ruact 0.0.8 → 0.0.10

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -1
  3. data/LICENSE.txt +21 -0
  4. data/README.md +124 -18
  5. data/SECURITY.md +1 -1
  6. data/lib/generators/ruact/install/install_generator.rb +264 -5
  7. data/lib/generators/ruact/install/templates/Procfile.dev.tt +3 -0
  8. data/lib/generators/ruact/install/templates/globals.css.tt +20 -0
  9. data/lib/generators/ruact/install/templates/initializer.rb.tt +9 -0
  10. data/lib/generators/ruact/install/templates/package.json.tt +7 -1
  11. data/lib/generators/ruact/install/templates/tsconfig.json.tt +18 -0
  12. data/lib/generators/ruact/scaffold/scaffold_shadcn_preflight.rb +10 -0
  13. data/lib/ruact/configuration.rb +73 -0
  14. data/lib/ruact/controller/document_rendering.rb +210 -0
  15. data/lib/ruact/controller.rb +5 -46
  16. data/lib/ruact/doctor.rb +37 -5
  17. data/lib/ruact/layout_source.rb +59 -0
  18. data/lib/ruact/version.rb +1 -1
  19. data/lib/ruact/view_helper.rb +10 -1
  20. data/lib/ruact.rb +1 -0
  21. data/spec/fixtures/readme/children-error.html.erb +3 -0
  22. data/spec/fixtures/readme/children-error.txt +1 -0
  23. data/spec/fixtures/story_7_9_views/controller_request_spec_support/exploding_layout_demo/show.html.erb +3 -0
  24. data/spec/fixtures/story_7_9_views/controller_request_spec_support/ghost_layout_demo/show.html.erb +3 -0
  25. data/spec/fixtures/story_7_9_views/controller_request_spec_support/layout_demo/show.html.erb +3 -0
  26. data/spec/fixtures/story_7_9_views/controller_request_spec_support/rootless_layout_demo/show.html.erb +3 -0
  27. data/spec/fixtures/story_7_9_views/controller_request_spec_support/unwired_layout_demo/show.html.erb +3 -0
  28. data/spec/fixtures/story_7_9_views/layouts/bare_host.html.erb +16 -0
  29. data/spec/fixtures/story_7_9_views/layouts/exploding_host.html.erb +24 -0
  30. data/spec/fixtures/story_7_9_views/layouts/rootless_host.html.erb +15 -0
  31. data/spec/fixtures/story_7_9_views/layouts/ruact_host.html.erb +17 -0
  32. data/spec/readme_demo_message_spec.rb +67 -0
  33. data/spec/readme_spec.rb +282 -0
  34. data/spec/ruact/controller_request_spec.rb +203 -0
  35. data/spec/ruact/doctor_spec.rb +81 -6
  36. data/spec/ruact/install_generator_spec.rb +442 -70
  37. data/spec/ruact/layout_source_spec.rb +108 -0
  38. data/spec/ruact/scaffold_generator_spec.rb +14 -0
  39. metadata +30 -5
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "ruact"
5
+
6
+ # The single definition of "is this layout migrated?", shared by the runtime and
7
+ # by `ruact:install`. Every example here is a shape that fooled an earlier,
8
+ # looser check — a NAME where only a CALL counts, or a substring where only an
9
+ # attribute counts.
10
+ RSpec.describe Ruact::LayoutSource do
11
+ describe ".wired?" do
12
+ it "accepts a plain output tag" do
13
+ expect(described_class.wired?("<%= ruact_js_assets %>")).to be true
14
+ end
15
+
16
+ it "accepts the raw-output form and tight whitespace" do
17
+ expect(described_class.wired?("<%==ruact_js_assets%>")).to be true
18
+ end
19
+
20
+ it "accepts a call with an argument" do
21
+ expect(described_class.wired?("<%= ruact_js_assets(payload) %>")).to be true
22
+ end
23
+
24
+ # Round-1 finding: a mention in prose read as wired.
25
+ it "rejects a mention inside an ERB comment" do
26
+ expect(described_class.wired?("<%# remember to add ruact_js_assets here %>")).to be false
27
+ end
28
+
29
+ # Round-2 finding, and the sharper version of the same mistake: a genuinely
30
+ # COMMENTED-OUT call. ERB comments do not nest, so this emits nothing — but
31
+ # a regex looking only for `<%=` sees a call and reports the layout ready,
32
+ # which sends the runtime off to render an unmigrated layout.
33
+ it "rejects a commented-out call" do
34
+ expect(described_class.wired?("<%# <%= ruact_js_assets %> %>")).to be false
35
+ end
36
+
37
+ it "rejects a multi-line comment that wraps a call" do
38
+ source = <<~ERB
39
+ <%#
40
+ disabled for now:
41
+ <%= ruact_js_assets %>
42
+ %>
43
+ ERB
44
+ expect(described_class.wired?(source)).to be false
45
+ end
46
+
47
+ it "still sees a real call that follows a comment mentioning it" do
48
+ expect(described_class.wired?("<%# ruact_js_assets %>\n<%= ruact_js_assets %>")).to be true
49
+ end
50
+
51
+ # Round-3 finding: ERB's trim-mode comment (`<%-# ... -%>`) is a comment in
52
+ # Erubi too — verified by compiling it — but the stripper only knew `<%#`,
53
+ # so a call disabled this way read as wired.
54
+ it "rejects a call disabled with a trim-mode comment" do
55
+ expect(described_class.wired?("<%-# <%= ruact_js_assets %> -%>")).to be false
56
+ end
57
+
58
+ # Round-3 finding, the other direction: forbidding `%` before the name to
59
+ # avoid crossing tag boundaries also rejected legitimate calls. A false
60
+ # "unwired" is safer than a false "wired", but it is still a wrong answer —
61
+ # the app would silently keep ruact's CSS-less shell.
62
+ it "accepts a call whose expression contains a percent sign" do
63
+ expect(described_class.wired?(%(<%= raw("100%") + ruact_js_assets %>))).to be true
64
+ expect(described_class.wired?("<%= ruact_js_assets if 50 % 2 == 0 %>")).to be true
65
+ end
66
+
67
+ it "still refuses to match across a tag boundary" do
68
+ expect(described_class.wired?("<%= something %> then a bare ruact_js_assets mention")).to be false
69
+ end
70
+
71
+ it "rejects a layout that never names it" do
72
+ expect(described_class.wired?("<html><body><%= yield %></body></html>")).to be false
73
+ end
74
+ end
75
+
76
+ describe ".root?" do
77
+ it "accepts the emitted form" do
78
+ expect(described_class.root?(%(<div id="root"></div>))).to be true
79
+ end
80
+
81
+ it "accepts single quotes, extra attributes and unquoted values" do
82
+ expect(described_class.root?(%(<div id='root'></div>))).to be true
83
+ expect(described_class.root?(%(<div class="a" id="root" data-x="1"></div>))).to be true
84
+ expect(described_class.root?(%(<div id=root></div>))).to be true
85
+ end
86
+
87
+ # Round-2 finding: `data-id="root"` is not a mount point, and a document
88
+ # carrying one but no real root gives React nothing to mount into.
89
+ it "rejects a look-alike attribute" do
90
+ expect(described_class.root?(%(<body data-id="root"></body>))).to be false
91
+ end
92
+
93
+ it "rejects a different id that merely starts with root" do
94
+ expect(described_class.root?(%(<div id="rootish"></div>))).to be false
95
+ end
96
+ end
97
+
98
+ # The anchor `ruact:install` injects after.
99
+ describe "::ROOT_ELEMENT" do
100
+ it "anchors on a whole empty root div" do
101
+ expect(described_class::ROOT_ELEMENT).to match(%(<div id="root"></div>))
102
+ end
103
+
104
+ it "does not anchor on a look-alike attribute" do
105
+ expect(described_class::ROOT_ELEMENT).not_to match(%(<div data-id="root"></div>))
106
+ end
107
+ end
108
+ end
@@ -1136,6 +1136,20 @@ RSpec.describe Ruact::Generators::ScaffoldGenerator, :story_10_1 do # rubocop:di
1136
1136
  expect(minimal).to eq(%w[button input label badge table alert-dialog dropdown-menu])
1137
1137
  end
1138
1138
 
1139
+ # `ruact:install --shadcn` runs before any resource exists, so it prints
1140
+ # the SUPERSET constant instead of this per-resource list. If a template
1141
+ # ever imports a primitive the constant does not carry, the printed
1142
+ # `npx shadcn add` line would be short one component and the scaffold
1143
+ # would fail its own pre-flight — so pin the relationship.
1144
+ it "keeps the per-resource list a subset of the superset install prints" do
1145
+ superset = described_class::ShadcnPreflight::ALL_SHADCN_COMPONENTS
1146
+ richest = build(%w[Post title:string body:text published:boolean author:references])
1147
+ .required_shadcn_components
1148
+
1149
+ expect(richest).to all(be_in(superset))
1150
+ expect(superset).to match_array(richest)
1151
+ end
1152
+
1139
1153
  it "maps each component to its app/javascript/components/ui/<name>.tsx file" do
1140
1154
  gen = build(default_args)
1141
1155
  expect(gen.shadcn_component_file("table").to_s)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruact
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luiz Garcia
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-11 00:00:00.000000000 Z
11
+ date: 2026-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -24,7 +24,12 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.15'
27
- description:
27
+ description: |
28
+ ruact renders React components straight from your ERB views: write a PascalCase
29
+ tag, pass a Ruby value as a prop, and React hydrates it in the browser over the
30
+ Flight wire format. Server functions and queries are drawn from your existing
31
+ route table, so there is no hand-written JSON layer to keep in sync and no Node
32
+ process in production.
28
33
  email:
29
34
  - luizcg@gmail.com
30
35
  executables: []
@@ -37,6 +42,7 @@ files:
37
42
  - ".rubocop.yml"
38
43
  - ".rubocop_todo.yml"
39
44
  - CHANGELOG.md
45
+ - LICENSE.txt
40
46
  - README.md
41
47
  - RELEASING.md
42
48
  - Rakefile
@@ -49,8 +55,10 @@ files:
49
55
  - lib/generators/ruact/install/templates/AGENTS.md.tt
50
56
  - lib/generators/ruact/install/templates/Procfile.dev.tt
51
57
  - lib/generators/ruact/install/templates/dev.tt
58
+ - lib/generators/ruact/install/templates/globals.css.tt
52
59
  - lib/generators/ruact/install/templates/initializer.rb.tt
53
60
  - lib/generators/ruact/install/templates/package.json.tt
61
+ - lib/generators/ruact/install/templates/tsconfig.json.tt
54
62
  - lib/generators/ruact/install/templates/vite.config.js.tt
55
63
  - lib/generators/ruact/scaffold/scaffold_attribute.rb
56
64
  - lib/generators/ruact/scaffold/scaffold_form_helpers.rb
@@ -75,6 +83,7 @@ files:
75
83
  - lib/ruact/component_contract.rb
76
84
  - lib/ruact/configuration.rb
77
85
  - lib/ruact/controller.rb
86
+ - lib/ruact/controller/document_rendering.rb
78
87
  - lib/ruact/doctor.rb
79
88
  - lib/ruact/erb_preprocessor.rb
80
89
  - lib/ruact/erb_preprocessor_hook.rb
@@ -86,6 +95,7 @@ files:
86
95
  - lib/ruact/flight/row_emitter.rb
87
96
  - lib/ruact/flight/serializer.rb
88
97
  - lib/ruact/html_converter.rb
98
+ - lib/ruact/layout_source.rb
89
99
  - lib/ruact/manifest_resolver.rb
90
100
  - lib/ruact/query.rb
91
101
  - lib/ruact/railtie.rb
@@ -152,8 +162,21 @@ files:
152
162
  - spec/fixtures/flight/string_basic.txt
153
163
  - spec/fixtures/flight/string_dollar_escape.txt
154
164
  - spec/fixtures/flight/undefined.txt
165
+ - spec/fixtures/readme/children-error.html.erb
166
+ - spec/fixtures/readme/children-error.txt
155
167
  - spec/fixtures/story_7_9_views/controller_request_spec_support/demo/show.html.erb
156
168
  - spec/fixtures/story_7_9_views/controller_request_spec_support/errors_demo/new.html.erb
169
+ - spec/fixtures/story_7_9_views/controller_request_spec_support/exploding_layout_demo/show.html.erb
170
+ - spec/fixtures/story_7_9_views/controller_request_spec_support/ghost_layout_demo/show.html.erb
171
+ - spec/fixtures/story_7_9_views/controller_request_spec_support/layout_demo/show.html.erb
172
+ - spec/fixtures/story_7_9_views/controller_request_spec_support/rootless_layout_demo/show.html.erb
173
+ - spec/fixtures/story_7_9_views/controller_request_spec_support/unwired_layout_demo/show.html.erb
174
+ - spec/fixtures/story_7_9_views/layouts/bare_host.html.erb
175
+ - spec/fixtures/story_7_9_views/layouts/exploding_host.html.erb
176
+ - spec/fixtures/story_7_9_views/layouts/rootless_host.html.erb
177
+ - spec/fixtures/story_7_9_views/layouts/ruact_host.html.erb
178
+ - spec/readme_demo_message_spec.rb
179
+ - spec/readme_spec.rb
157
180
  - spec/ruact/client_manifest_spec.rb
158
181
  - spec/ruact/component_contract_spec.rb
159
182
  - spec/ruact/configuration_spec.rb
@@ -167,6 +190,7 @@ files:
167
190
  - spec/ruact/flight/serializer_spec.rb
168
191
  - spec/ruact/html_converter_spec.rb
169
192
  - spec/ruact/install_generator_spec.rb
193
+ - spec/ruact/layout_source_spec.rb
170
194
  - spec/ruact/manifest_resolver_spec.rb
171
195
  - spec/ruact/query_request_spec.rb
172
196
  - spec/ruact/query_spec.rb
@@ -242,15 +266,16 @@ files:
242
266
  - vendor/javascript/vite-plugin-ruact/type-tests/typed-query.test-d.ts
243
267
  - vendor/javascript/vite-plugin-ruact/type-tests/usequery.test-d.ts
244
268
  - vendor/javascript/vite-plugin-ruact/vitest.config.mjs
245
- homepage: https://luizcg.github.io/ruact/
269
+ homepage: https://ruact.dev/
246
270
  licenses:
247
271
  - MIT
248
272
  metadata:
249
273
  allowed_push_host: https://rubygems.org
250
- homepage_uri: https://luizcg.github.io/ruact/
274
+ homepage_uri: https://ruact.dev/
251
275
  source_code_uri: https://github.com/luizcg/ruact
252
276
  changelog_uri: https://github.com/luizcg/ruact/blob/main/CHANGELOG.md
253
277
  bug_tracker_uri: https://github.com/luizcg/ruact/issues
278
+ documentation_uri: https://ruact.dev
254
279
  rubygems_mfa_required: 'true'
255
280
  post_install_message:
256
281
  rdoc_options: []