|
1 | | -require 'opal' |
2 | | -require 'opal/full' |
3 | | -require 'opal-parser' |
4 | | -require 'native' |
5 | | -require 'promise/v2' |
6 | | -require 'browser/setup/full' |
7 | | -require 'browser/cookies' |
8 | | -require 'browser/form_data' |
9 | | - |
10 | | -# Container for individual lessons |
11 | | -class TryRubyItem |
12 | | - attr_reader :lang, :step, :title, :chapter, :answer, :ok, :error, :text, :saved_editor, :saved_output |
13 | | - attr_accessor :load_code |
14 | | - |
15 | | - def initialize(key, values) |
16 | | - @lang = values["lang"] |
17 | | - @step = key.to_i |
18 | | - @title = values["title"] |
19 | | - @chapter = values["chapter"] |
20 | | - answer = values["answer"] |
21 | | - @answer = answer && !answer.empty? ? Regexp.new(answer, 'mi') : nil |
22 | | - @ok = values["ok"].split('<br/>') |
23 | | - @error = values["error"].split('<br/>') |
24 | | - @text = values["text"] |
25 | | - load_code = values["load_code"] |
26 | | - @load_code = load_code && !load_code.empty? ? load_code : nil |
27 | | - @saved_editor = '' |
28 | | - @saved_output = '' |
29 | | - end |
30 | | - |
31 | | - def update_current_edit(current_editor_value, current_output_value) |
32 | | - @saved_editor = current_editor_value |
33 | | - @saved_output = current_output_value |
34 | | - end |
35 | | -end |
36 | | - |
37 | | -# Wrapper for CodeMirror objects |
38 | | -class Editor |
39 | | - def initialize(dom_id, options) |
40 | | - @native = `CodeMirror(document.getElementById(dom_id), #{options.to_n})` |
41 | | - end |
42 | | - |
43 | | - def value=(str) |
44 | | - `#@native.setValue(str)` |
45 | | - end |
46 | | - |
47 | | - def value |
48 | | - `#@native.getValue()` |
49 | | - end |
50 | | - |
51 | | - def focus |
52 | | - `#@native.focus()` |
53 | | - end |
54 | | - |
55 | | - def mark_ok(line_from, line_to) |
56 | | - `#@native.markText({line: line_from, ch: 0}, {line: line_to, ch: 99}, {className: "tryruby-output-green"})` |
57 | | - end |
58 | | - |
59 | | - def mark_error(line_from, line_to) |
60 | | - `#@native.markText({line: line_from, ch: 0}, {line: line_to, ch: 99}, {className: "tryruby-output-red"})` |
61 | | - end |
62 | | - |
63 | | - def on(event, &block) |
64 | | - `#@native.on(#{event}, #{block})` |
65 | | - end |
66 | | -end |
67 | | - |
68 | | -class RubyEngine |
69 | | - def run(source, instance) |
70 | | - end |
71 | | - |
72 | | - class OpalEngine < RubyEngine |
73 | | - def name |
74 | | - "Opal #{Opal::VERSION}" |
75 | | - end |
76 | | - |
77 | | - def engine_id |
78 | | - "opal" |
79 | | - end |
80 | | - |
81 | | - def run(source, writer) |
82 | | - # Compile |
83 | | - js_code = Opal.compile(source) |
84 | | - |
85 | | - # Bind puts and print methods. |
86 | | - $stdout.write_proc = $stderr.write_proc = ->(str) do |
87 | | - writer.print_to_output str, "" |
88 | | - end |
89 | | - |
90 | | - # Run |
91 | | - retval = nil |
92 | | - error = nil |
93 | | - |
94 | | - retval = `eval(js_code)` |
95 | | - yield(retval ? retval.to_s : '') |
96 | | - $stdout.write_proc = $stderr.write_proc = nil |
97 | | - end |
98 | | - end |
99 | | - |
100 | | - class CRubyEngine < RubyEngine |
101 | | - |
102 | | - def initialize(ruby_wasm_url, version) |
103 | | - @ruby_wasm_url = ruby_wasm_url |
104 | | - @version = version |
105 | | - end |
106 | | - |
107 | | - def name |
108 | | - "CRuby #{@version}" |
109 | | - end |
110 | | - |
111 | | - def engine_id |
112 | | - "cruby-#{@version}" |
113 | | - end |
114 | | - |
115 | | - def wasm_module |
116 | | - return @module if @module |
117 | | - %x{ |
118 | | - #{@module} = (async function() { |
119 | | - const response = await fetch(#{@ruby_wasm_url}); |
120 | | - const buffer = await response.arrayBuffer(); |
121 | | - return await WebAssembly.compile(buffer); |
122 | | - })(); |
123 | | - } |
124 | | - @module |
125 | | - end |
126 | | - |
127 | | - def run(source, writer) |
128 | | - %x{ |
129 | | - async function instantiateVM() { |
130 | | - const $WASI = window["WASI"].WASI; |
131 | | - const $WasmFs = window["WasmFs"].WasmFs; |
132 | | - const $RubyVM = window["ruby-wasm-wasi"].RubyVM; |
133 | | -
|
134 | | - const wasmFs = new $WasmFs(); |
135 | | - const originalWriteSync = wasmFs.fs.writeSync.bind(wasmFs.fs); |
136 | | - const textDecoder = new TextDecoder("utf-8"); |
137 | | - wasmFs.fs.writeSync = (fd, buffer, offset, length, position) => { |
138 | | - const text = textDecoder.decode(buffer); |
139 | | - if (fd == 1 || fd == 2) { |
140 | | - #{writer.print_to_output(`text`, "")}; |
141 | | - } |
142 | | - return originalWriteSync(fd, buffer, offset, length, position); |
143 | | - }; |
144 | | -
|
145 | | - const vm = new $RubyVM(); |
146 | | - const wasi = new $WASI({ |
147 | | - bindings: { ...$WASI.defaultBindings, fs: wasmFs.fs }, |
148 | | - }); |
149 | | - const imports = { wasi_snapshot_preview1: wasi.wasiImport }; |
150 | | - vm.addToImports(imports); |
151 | | - const wasmInstance = await WebAssembly.instantiate(await #{wasm_module}, imports); |
152 | | - await vm.setInstance(wasmInstance); |
153 | | - wasi.setMemory(wasmInstance.exports.memory); |
154 | | - vm.initialize(); |
155 | | - return vm; |
156 | | - } |
157 | | -
|
158 | | - instantiateVM() |
159 | | - .then((vm) => { #{yield `vm.eval(source).toString()`} }) |
160 | | - .catch((err) => { #{writer.log_error(`err`)} }) |
161 | | - } |
162 | | - end |
163 | | - end |
164 | | - |
165 | | - ENGINES = [ |
166 | | - OpalEngine.new, |
167 | | - CRubyEngine.new( |
168 | | - "https://cdn.jsdelivr.net/npm/ruby-wasm-wasi@0.1.2/dist/ruby.wasm", |
169 | | - "3.2.0dev" |
170 | | - ), |
171 | | - ].each_with_object({}) do |engine, hash| |
172 | | - hash[engine.engine_id] = engine |
173 | | - end |
174 | | -end |
175 | | - |
| 1 | +require 'dependencies' |
| 2 | +require 'editor' |
| 3 | +require 'lesson' |
| 4 | +require 'ruby_engine' |
176 | 5 |
|
177 | 6 | # The TryRuby application |
178 | 7 | class TryRuby |
@@ -318,7 +147,7 @@ def get_content_from_server(language) |
318 | 147 | def update_json(items) |
319 | 148 | @items = {} |
320 | 149 | items.each do |k, v| |
321 | | - @items[k.to_i] = TryRubyItem.new(k, v) |
| 150 | + @items[k.to_i] = Lesson.new(k, v) |
322 | 151 | end |
323 | 152 | @loaded = true |
324 | 153 |
|
@@ -601,4 +430,4 @@ def print_to_output(str, term = "\n") |
601 | 430 | end |
602 | 431 | end |
603 | 432 |
|
604 | | -TryRuby.start |
| 433 | +$window.on("dom:load") { TryRuby.start } |
0 commit comments