ruby_wasm_ui 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +0 -2
  3. data/Makefile +53 -0
  4. data/README.md +22 -4
  5. data/examples/.gitignore +3 -0
  6. data/examples/Gemfile.lock +15 -17
  7. data/examples/src/index.html +21 -0
  8. data/examples/src/index.rb +26 -0
  9. data/exe/ruby-wasm-ui +6 -0
  10. data/lib/ruby_wasm_ui/cli/command/base.rb +174 -0
  11. data/lib/ruby_wasm_ui/cli/command/dev.rb +206 -0
  12. data/lib/ruby_wasm_ui/cli/command/pack.rb +36 -0
  13. data/lib/ruby_wasm_ui/cli/command/rebuild.rb +38 -0
  14. data/lib/ruby_wasm_ui/cli/command/setup.rb +130 -0
  15. data/lib/ruby_wasm_ui/cli/command.rb +48 -0
  16. data/lib/ruby_wasm_ui/version.rb +1 -1
  17. data/lib/ruby_wasm_ui.rb +8 -8
  18. data/package-lock.json +2 -2
  19. data/package.json +1 -1
  20. data/packages/npm-packages/runtime/package-lock.json +2 -2
  21. data/packages/npm-packages/runtime/package.json +3 -3
  22. data/packages/npm-packages/runtime/rollup.config.mjs +68 -10
  23. data/spec/ruby_wasm_ui/cli/command/base_spec.rb +358 -0
  24. data/spec/ruby_wasm_ui/cli/command/dev_spec.rb +412 -0
  25. data/spec/ruby_wasm_ui/cli/command/pack_spec.rb +127 -0
  26. data/spec/ruby_wasm_ui/cli/command/rebuild_spec.rb +95 -0
  27. data/spec/ruby_wasm_ui/cli/command/setup_spec.rb +186 -0
  28. data/spec/ruby_wasm_ui/cli/command_spec.rb +118 -0
  29. data/{packages/npm-packages/runtime/spec → spec}/spec_helper.rb +1 -1
  30. metadata +96 -38
  31. data/packages/npm-packages/runtime/Gemfile +0 -3
  32. data/packages/npm-packages/runtime/Gemfile.lock +0 -26
  33. /data/lib/ruby_wasm_ui/{app.rb → runtime/app.rb} +0 -0
  34. /data/lib/ruby_wasm_ui/{component.rb → runtime/component.rb} +0 -0
  35. /data/lib/ruby_wasm_ui/{dispatcher.rb → runtime/dispatcher.rb} +0 -0
  36. /data/lib/ruby_wasm_ui/{dom → runtime/dom}/attributes.rb +0 -0
  37. /data/lib/ruby_wasm_ui/{dom → runtime/dom}/destroy_dom.rb +0 -0
  38. /data/lib/ruby_wasm_ui/{dom → runtime/dom}/events.rb +0 -0
  39. /data/lib/ruby_wasm_ui/{dom → runtime/dom}/mount_dom.rb +0 -0
  40. /data/lib/ruby_wasm_ui/{dom → runtime/dom}/patch_dom.rb +0 -0
  41. /data/lib/ruby_wasm_ui/{dom → runtime/dom}/scheduler.rb +0 -0
  42. /data/lib/ruby_wasm_ui/{dom.rb → runtime/dom.rb} +0 -0
  43. /data/lib/ruby_wasm_ui/{nodes_equal.rb → runtime/nodes_equal.rb} +0 -0
  44. /data/lib/ruby_wasm_ui/{template → runtime/template}/build_conditional_group.rb +0 -0
  45. /data/lib/ruby_wasm_ui/{template → runtime/template}/build_for_group.rb +0 -0
  46. /data/lib/ruby_wasm_ui/{template → runtime/template}/build_vdom.rb +0 -0
  47. /data/lib/ruby_wasm_ui/{template → runtime/template}/parser.rb +0 -0
  48. /data/lib/ruby_wasm_ui/{template.rb → runtime/template.rb} +0 -0
  49. /data/lib/ruby_wasm_ui/{utils → runtime/utils}/arrays.rb +0 -0
  50. /data/lib/ruby_wasm_ui/{utils → runtime/utils}/objects.rb +0 -0
  51. /data/lib/ruby_wasm_ui/{utils → runtime/utils}/props.rb +0 -0
  52. /data/lib/ruby_wasm_ui/{utils → runtime/utils}/strings.rb +0 -0
  53. /data/lib/ruby_wasm_ui/{utils.rb → runtime/utils.rb} +0 -0
  54. /data/lib/ruby_wasm_ui/{vdom.rb → runtime/vdom.rb} +0 -0
  55. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/component_spec.rb +0 -0
  56. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/dom/scheduler_spec.rb +0 -0
  57. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/nodes_equal_spec.rb +0 -0
  58. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/template/build_conditional_group_spec.rb +0 -0
  59. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/template/build_for_group_spec.rb +0 -0
  60. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/template/build_vdom_spec.rb +0 -0
  61. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/template/parser_spec.rb +0 -0
  62. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/utils/arrays_spec.rb +0 -0
  63. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/utils/objects_spec.rb +0 -0
  64. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/utils/props_spec.rb +0 -0
  65. /data/{packages/npm-packages/runtime/spec/ruby_wasm_ui → spec/ruby_wasm_ui/runtime}/utils/strings_spec.rb +0 -0
@@ -0,0 +1,358 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fileutils'
5
+ require 'tmpdir'
6
+
7
+ RSpec.describe RubyWasmUi::Cli::Command::Base do
8
+ let(:base_instance) { described_class.new }
9
+
10
+ describe '#run' do
11
+ it 'raises NotImplementedError' do
12
+ expect { base_instance.run([]) }.to raise_error(NotImplementedError, /Subclasses must implement #run/)
13
+ end
14
+ end
15
+
16
+ describe '#update_gitignore' do
17
+ let(:temp_dir) { Dir.mktmpdir }
18
+ let(:original_dir) { Dir.pwd }
19
+
20
+ around do |example|
21
+ Dir.chdir(temp_dir) do
22
+ example.run
23
+ end
24
+ ensure
25
+ FileUtils.rm_rf(temp_dir) if Dir.exist?(temp_dir)
26
+ end
27
+
28
+ context 'when .gitignore does not exist' do
29
+ it 'creates .gitignore with new entries' do
30
+ base_instance.send(:update_gitignore, ['*.wasm', '/rubies'])
31
+ content = File.read('.gitignore')
32
+ expect(content).to include('*.wasm')
33
+ expect(content).to include('/rubies')
34
+ end
35
+ end
36
+
37
+ context 'when .gitignore exists' do
38
+ before do
39
+ File.write('.gitignore', "node_modules/\n*.log\n")
40
+ end
41
+
42
+ it 'adds new entries to existing .gitignore' do
43
+ base_instance.send(:update_gitignore, ['*.wasm', '/rubies'])
44
+ content = File.read('.gitignore')
45
+ expect(content).to include('node_modules/')
46
+ expect(content).to include('*.log')
47
+ expect(content).to include('*.wasm')
48
+ expect(content).to include('/rubies')
49
+ end
50
+
51
+ it 'does not add duplicate entries' do
52
+ File.write('.gitignore', "*.wasm\n")
53
+ base_instance.send(:update_gitignore, ['*.wasm', '/rubies'])
54
+ content = File.read('.gitignore')
55
+ expect(content.scan(/^\*\.wasm$/).count).to eq(1)
56
+ end
57
+
58
+ it 'outputs message when entries are added' do
59
+ expect { base_instance.send(:update_gitignore, ['*.wasm']) }.to output(
60
+ /Added to .gitignore: \*\.wasm/
61
+ ).to_stdout
62
+ end
63
+
64
+ it 'outputs message when no entries are added' do
65
+ File.write('.gitignore', "*.wasm\n")
66
+ expect { base_instance.send(:update_gitignore, ['*.wasm']) }.to output(
67
+ /No new entries added to .gitignore/
68
+ ).to_stdout
69
+ end
70
+ end
71
+ end
72
+
73
+ describe '#run_command' do
74
+ context 'when command succeeds' do
75
+ it 'executes the command and outputs stdout' do
76
+ expect { base_instance.send(:run_command, 'echo "test output"') }.to output(
77
+ /test output/
78
+ ).to_stdout
79
+ end
80
+
81
+ it 'does not raise error' do
82
+ expect { base_instance.send(:run_command, 'echo "test"') }.not_to raise_error
83
+ end
84
+
85
+ it 'returns true' do
86
+ result = base_instance.send(:run_command, 'echo "test"')
87
+ expect(result).to be true
88
+ end
89
+ end
90
+
91
+ context 'when command fails' do
92
+ it 'outputs error message and exits by default' do
93
+ expect { base_instance.send(:run_command, 'false') }.to output(
94
+ /Command failed: false/
95
+ ).to_stdout.and raise_error(SystemExit)
96
+ end
97
+
98
+ it 'exits with correct status code' do
99
+ expect { base_instance.send(:run_command, 'false') }.to raise_error(SystemExit) do |error|
100
+ expect(error.status).to eq(1)
101
+ end
102
+ end
103
+
104
+ context 'when exit_on_error is false' do
105
+ it 'outputs error message but does not exit' do
106
+ expect { base_instance.send(:run_command, 'false', exit_on_error: false) }.to output(
107
+ /Command failed: false/
108
+ ).to_stdout
109
+ expect { base_instance.send(:run_command, 'false', exit_on_error: false) }.not_to raise_error
110
+ end
111
+
112
+ it 'returns false' do
113
+ result = base_instance.send(:run_command, 'false', exit_on_error: false)
114
+ expect(result).to be false
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ describe '#ensure_src_directory' do
121
+ let(:temp_dir) { Dir.mktmpdir }
122
+ let(:original_dir) { Dir.pwd }
123
+
124
+ around do |example|
125
+ Dir.chdir(temp_dir) do
126
+ example.run
127
+ end
128
+ ensure
129
+ FileUtils.rm_rf(temp_dir) if Dir.exist?(temp_dir)
130
+ end
131
+
132
+ context 'when src directory does not exist' do
133
+ it 'outputs error message and exits' do
134
+ expect { base_instance.send(:ensure_src_directory) }.to output(
135
+ /src directory not found. Please run 'ruby-wasm-ui setup' first./
136
+ ).to_stdout.and raise_error(SystemExit)
137
+ end
138
+
139
+ it 'exits with status 1' do
140
+ expect { base_instance.send(:ensure_src_directory) }.to raise_error(SystemExit) do |error|
141
+ expect(error.status).to eq(1)
142
+ end
143
+ end
144
+ end
145
+
146
+ context 'when src directory exists' do
147
+ before do
148
+ FileUtils.mkdir_p('src')
149
+ end
150
+
151
+ it 'does not raise error' do
152
+ expect { base_instance.send(:ensure_src_directory) }.not_to raise_error
153
+ end
154
+
155
+ it 'does not output error message' do
156
+ expect { base_instance.send(:ensure_src_directory) }.not_to output(
157
+ /src directory not found/
158
+ ).to_stdout
159
+ end
160
+ end
161
+ end
162
+
163
+ describe '#ensure_ruby_wasm' do
164
+ let(:temp_dir) { Dir.mktmpdir }
165
+ let(:original_dir) { Dir.pwd }
166
+
167
+ around do |example|
168
+ Dir.chdir(temp_dir) do
169
+ example.run
170
+ end
171
+ ensure
172
+ FileUtils.rm_rf(temp_dir) if Dir.exist?(temp_dir)
173
+ end
174
+
175
+ context 'when ruby.wasm does not exist' do
176
+ it 'outputs error message and exits' do
177
+ expect { base_instance.send(:ensure_ruby_wasm) }.to output(
178
+ /ruby.wasm not found. Please run 'ruby-wasm-ui setup' first./
179
+ ).to_stdout.and raise_error(SystemExit)
180
+ end
181
+
182
+ it 'exits with status 1' do
183
+ expect { base_instance.send(:ensure_ruby_wasm) }.to raise_error(SystemExit) do |error|
184
+ expect(error.status).to eq(1)
185
+ end
186
+ end
187
+ end
188
+
189
+ context 'when ruby.wasm exists' do
190
+ before do
191
+ FileUtils.touch('ruby.wasm')
192
+ end
193
+
194
+ it 'does not raise error' do
195
+ expect { base_instance.send(:ensure_ruby_wasm) }.not_to raise_error
196
+ end
197
+
198
+ it 'does not output error message' do
199
+ expect { base_instance.send(:ensure_ruby_wasm) }.not_to output(
200
+ /ruby.wasm not found/
201
+ ).to_stdout
202
+ end
203
+ end
204
+ end
205
+
206
+ describe '#check_ruby_version' do
207
+ context 'when Ruby version is 3.2 or higher' do
208
+ before do
209
+ stub_const('RUBY_VERSION', '3.2.0')
210
+ end
211
+
212
+ it 'returns the version string' do
213
+ result = base_instance.send(:check_ruby_version)
214
+ expect(result).to eq('3.2')
215
+ end
216
+
217
+ it 'does not exit' do
218
+ expect { base_instance.send(:check_ruby_version) }.not_to raise_error
219
+ end
220
+ end
221
+
222
+ context 'when Ruby version is 3.4' do
223
+ before do
224
+ stub_const('RUBY_VERSION', '3.4.0')
225
+ end
226
+
227
+ it 'returns the version string' do
228
+ result = base_instance.send(:check_ruby_version)
229
+ expect(result).to eq('3.4')
230
+ end
231
+ end
232
+
233
+ context 'when Ruby version is less than 3.2' do
234
+ context 'when Ruby version is 3.1' do
235
+ before do
236
+ stub_const('RUBY_VERSION', '3.1.5')
237
+ end
238
+
239
+ it 'outputs error message and exits' do
240
+ expect { base_instance.send(:check_ruby_version) }.to output(
241
+ /\[ERROR\] Ruby WASM requires Ruby 3.2 or higher. Current version: 3.1.5/
242
+ ).to_stdout.and raise_error(SystemExit) do |error|
243
+ expect(error.status).to eq(1)
244
+ end
245
+ end
246
+ end
247
+
248
+ context 'when Ruby version is 2.7' do
249
+ before do
250
+ stub_const('RUBY_VERSION', '2.7.8')
251
+ end
252
+
253
+ it 'outputs error message and exits' do
254
+ expect { base_instance.send(:check_ruby_version) }.to output(
255
+ /\[ERROR\] Ruby WASM requires Ruby 3.2 or higher. Current version: 2.7.8/
256
+ ).to_stdout.and raise_error(SystemExit) do |error|
257
+ expect(error.status).to eq(1)
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ describe '#configure_excluded_gems' do
265
+ before do
266
+ # Clear EXCLUDED_GEMS before each test
267
+ RubyWasm::Packager::EXCLUDED_GEMS.clear if defined?(RubyWasm::Packager::EXCLUDED_GEMS)
268
+ end
269
+
270
+ it 'excludes rack, puma, nio4r, listen, and ffi gems' do
271
+ allow(Bundler).to receive(:definition).and_return(
272
+ double(
273
+ resolve: double(
274
+ materialize: [
275
+ double(name: 'rack'),
276
+ double(name: 'puma'),
277
+ double(name: 'nio4r'),
278
+ double(name: 'listen'),
279
+ double(name: 'ffi'),
280
+ double(name: 'js'),
281
+ double(name: 'ruby_wasm')
282
+ ]
283
+ ),
284
+ requested_dependencies: []
285
+ )
286
+ )
287
+
288
+ base_instance.send(:configure_excluded_gems)
289
+
290
+ expect(RubyWasm::Packager::EXCLUDED_GEMS).to include('rack', 'puma', 'nio4r', 'listen', 'ffi')
291
+ expect(RubyWasm::Packager::EXCLUDED_GEMS).not_to include('js', 'ruby_wasm')
292
+ end
293
+
294
+ it 'always excludes nio4r, puma, rack, listen, and ffi even if not in dependencies' do
295
+ allow(Bundler).to receive(:definition).and_return(
296
+ double(
297
+ resolve: double(
298
+ materialize: [
299
+ double(name: 'js'),
300
+ double(name: 'ruby_wasm')
301
+ ]
302
+ ),
303
+ requested_dependencies: []
304
+ )
305
+ )
306
+
307
+ base_instance.send(:configure_excluded_gems)
308
+
309
+ # Always excluded gems should be in the list even if not in dependencies
310
+ expect(RubyWasm::Packager::EXCLUDED_GEMS).to include('nio4r', 'puma', 'rack', 'listen', 'ffi')
311
+ expect(RubyWasm::Packager::EXCLUDED_GEMS).not_to include('js', 'ruby_wasm')
312
+ end
313
+
314
+ it 'excludes development/test gems' do
315
+ allow(Bundler).to receive(:definition).and_return(
316
+ double(
317
+ resolve: double(
318
+ materialize: [
319
+ double(name: 'rspec'),
320
+ double(name: 'rubocop'),
321
+ double(name: 'rake'),
322
+ double(name: 'js')
323
+ ]
324
+ ),
325
+ requested_dependencies: []
326
+ )
327
+ )
328
+
329
+ base_instance.send(:configure_excluded_gems)
330
+
331
+ expect(RubyWasm::Packager::EXCLUDED_GEMS).to include('rspec', 'rubocop', 'rake')
332
+ expect(RubyWasm::Packager::EXCLUDED_GEMS).not_to include('js')
333
+ end
334
+ end
335
+
336
+ describe '#build_ruby_wasm' do
337
+ let(:cli_instance) { instance_double(RubyWasm::CLI) }
338
+
339
+ before do
340
+ allow(RubyWasm::CLI).to receive(:new).and_return(cli_instance)
341
+ allow(cli_instance).to receive(:run)
342
+ end
343
+
344
+ it 'executes rbwasm build command with correct arguments' do
345
+ expect(RubyWasm::CLI).to receive(:new).with(stdout: $stdout, stderr: $stderr).and_return(cli_instance)
346
+ expect(cli_instance).to receive(:run).with(['build', '--ruby-version', '3.2', '-o', 'ruby.wasm'])
347
+
348
+ base_instance.send(:build_ruby_wasm, '3.2')
349
+ end
350
+
351
+ it 'executes rbwasm build command with different version' do
352
+ expect(RubyWasm::CLI).to receive(:new).with(stdout: $stdout, stderr: $stderr).and_return(cli_instance)
353
+ expect(cli_instance).to receive(:run).with(['build', '--ruby-version', '3.4', '-o', 'ruby.wasm'])
354
+
355
+ base_instance.send(:build_ruby_wasm, '3.4')
356
+ end
357
+ end
358
+ end