ruact 0.0.11 → 0.0.13

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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +147 -48
  3. data/CONTRIBUTING.md +233 -0
  4. data/README.md +18 -8
  5. data/RELEASING.md +125 -139
  6. data/lib/generators/ruact/install/install_generator.rb +305 -126
  7. data/lib/generators/ruact/install/templates/AGENTS.md.tt +14 -13
  8. data/lib/generators/ruact/install/templates/initializer.rb.tt +29 -7
  9. data/lib/generators/ruact/install/templates/tsconfig.json.tt +3 -0
  10. data/lib/generators/ruact/layout/layout_generator.rb +52 -0
  11. data/lib/generators/ruact/scaffold/templates/controller.rb.tt +5 -3
  12. data/lib/ruact/configuration.rb +65 -13
  13. data/lib/ruact/controller/document_rendering.rb +72 -16
  14. data/lib/ruact/controller/page_rendering.rb +134 -0
  15. data/lib/ruact/controller/pages.rb +116 -0
  16. data/lib/ruact/controller.rb +78 -11
  17. data/lib/ruact/doctor.rb +233 -25
  18. data/lib/ruact/layout_source.rb +29 -7
  19. data/lib/ruact/navigation_boundary.rb +240 -0
  20. data/lib/ruact/packaging.rb +68 -0
  21. data/lib/ruact/railtie.rb +30 -0
  22. data/lib/ruact/server.rb +10 -1
  23. data/lib/ruact/version.rb +1 -1
  24. data/lib/ruact/view_helper.rb +158 -1
  25. data/lib/ruact/views/layouts/ruact.html.erb +32 -0
  26. data/lib/ruact.rb +29 -0
  27. data/vendor/javascript/vite-plugin-ruact/flight-client.test.mjs +321 -0
  28. data/vendor/javascript/vite-plugin-ruact/package-lock.json +11 -0
  29. data/vendor/javascript/vite-plugin-ruact/package.json +1 -0
  30. data/vendor/javascript/vite-plugin-ruact/ruact-router.test.mjs +433 -0
  31. data/vendor/javascript/vite-plugin-ruact/runtime/flight-client.js +14 -3
  32. data/vendor/javascript/vite-plugin-ruact/runtime/ruact-router.js +170 -7
  33. metadata +12 -107
  34. data/.codecov.yml +0 -31
  35. data/.github/workflows/ci.yml +0 -284
  36. data/.github/workflows/server-functions-bench.yml +0 -54
  37. data/.rubocop.yml +0 -107
  38. data/.rubocop_todo.yml +0 -63
  39. data/Rakefile +0 -10
  40. data/bench/server_functions_dispatch_bench.rb +0 -276
  41. data/bench/server_functions_dispatch_bench.results.md +0 -150
  42. data/docs/internal/README.md +0 -9
  43. data/docs/internal/decisions/server-functions-api.md +0 -2236
  44. data/spec/benchmarks/baseline.json +0 -12
  45. data/spec/benchmarks/render_pipeline_benchmark_spec.rb +0 -109
  46. data/spec/fixtures/flight/README.md +0 -136
  47. data/spec/fixtures/flight/array.txt +0 -1
  48. data/spec/fixtures/flight/as_json_object.txt +0 -2
  49. data/spec/fixtures/flight/bigint.txt +0 -1
  50. data/spec/fixtures/flight/boolean_false.txt +0 -1
  51. data/spec/fixtures/flight/boolean_true.txt +0 -1
  52. data/spec/fixtures/flight/client_component_with_props.txt +0 -2
  53. data/spec/fixtures/flight/client_reference.txt +0 -2
  54. data/spec/fixtures/flight/hash.txt +0 -1
  55. data/spec/fixtures/flight/infinity.txt +0 -1
  56. data/spec/fixtures/flight/nan.txt +0 -1
  57. data/spec/fixtures/flight/negative_infinity.txt +0 -1
  58. data/spec/fixtures/flight/nil.txt +0 -1
  59. data/spec/fixtures/flight/number_float.txt +0 -1
  60. data/spec/fixtures/flight/number_integer.txt +0 -1
  61. data/spec/fixtures/flight/react_element_no_props.txt +0 -1
  62. data/spec/fixtures/flight/redirect_row.txt +0 -1
  63. data/spec/fixtures/flight/serializable_object.txt +0 -2
  64. data/spec/fixtures/flight/string_basic.txt +0 -1
  65. data/spec/fixtures/flight/string_dollar_escape.txt +0 -1
  66. data/spec/fixtures/flight/undefined.txt +0 -1
  67. data/spec/fixtures/readme/children-error.html.erb +0 -3
  68. data/spec/fixtures/readme/children-error.txt +0 -1
  69. data/spec/fixtures/story_7_9_views/controller_request_spec_support/demo/show.html.erb +0 -3
  70. data/spec/fixtures/story_7_9_views/controller_request_spec_support/errors_demo/new.html.erb +0 -3
  71. data/spec/fixtures/story_7_9_views/controller_request_spec_support/exploding_layout_demo/show.html.erb +0 -3
  72. data/spec/fixtures/story_7_9_views/controller_request_spec_support/ghost_layout_demo/show.html.erb +0 -3
  73. data/spec/fixtures/story_7_9_views/controller_request_spec_support/layout_demo/show.html.erb +0 -3
  74. data/spec/fixtures/story_7_9_views/controller_request_spec_support/rootless_layout_demo/show.html.erb +0 -3
  75. data/spec/fixtures/story_7_9_views/controller_request_spec_support/unwired_layout_demo/show.html.erb +0 -3
  76. data/spec/fixtures/story_7_9_views/layouts/bare_host.html.erb +0 -16
  77. data/spec/fixtures/story_7_9_views/layouts/exploding_host.html.erb +0 -24
  78. data/spec/fixtures/story_7_9_views/layouts/rootless_host.html.erb +0 -15
  79. data/spec/fixtures/story_7_9_views/layouts/ruact_host.html.erb +0 -17
  80. data/spec/readme_demo_message_spec.rb +0 -67
  81. data/spec/readme_spec.rb +0 -282
  82. data/spec/ruact/client_manifest_spec.rb +0 -270
  83. data/spec/ruact/component_contract_spec.rb +0 -119
  84. data/spec/ruact/configuration_spec.rb +0 -518
  85. data/spec/ruact/controller_request_spec.rb +0 -671
  86. data/spec/ruact/controller_spec.rb +0 -343
  87. data/spec/ruact/doctor_spec.rb +0 -769
  88. data/spec/ruact/erb_preprocessor_hook_spec.rb +0 -55
  89. data/spec/ruact/erb_preprocessor_spec.rb +0 -361
  90. data/spec/ruact/errors_spec.rb +0 -93
  91. data/spec/ruact/flight/renderer_spec.rb +0 -133
  92. data/spec/ruact/flight/serializer_spec.rb +0 -494
  93. data/spec/ruact/html_converter_spec.rb +0 -375
  94. data/spec/ruact/install_generator_spec.rb +0 -1549
  95. data/spec/ruact/layout_source_spec.rb +0 -108
  96. data/spec/ruact/manifest_resolver_spec.rb +0 -174
  97. data/spec/ruact/query_request_spec.rb +0 -706
  98. data/spec/ruact/query_spec.rb +0 -105
  99. data/spec/ruact/railtie_spec.rb +0 -155
  100. data/spec/ruact/render_context_spec.rb +0 -58
  101. data/spec/ruact/render_pipeline_concurrency_spec.rb +0 -78
  102. data/spec/ruact/render_pipeline_spec.rb +0 -928
  103. data/spec/ruact/scaffold_generator_spec.rb +0 -1849
  104. data/spec/ruact/serializable_spec.rb +0 -179
  105. data/spec/ruact/server_bucket_request_spec.rb +0 -785
  106. data/spec/ruact/server_function_name_spec.rb +0 -53
  107. data/spec/ruact/server_functions/backtrace_cleaner_spec.rb +0 -63
  108. data/spec/ruact/server_functions/bucket_two_payload_spec.rb +0 -200
  109. data/spec/ruact/server_functions/codegen_spec.rb +0 -397
  110. data/spec/ruact/server_functions/error_payload_spec.rb +0 -222
  111. data/spec/ruact/server_functions/error_suggestion_spec.rb +0 -79
  112. data/spec/ruact/server_functions/introspection_spec.rb +0 -135
  113. data/spec/ruact/server_functions/name_bridge_spec.rb +0 -212
  114. data/spec/ruact/server_functions/query_context_spec.rb +0 -72
  115. data/spec/ruact/server_functions/query_source_spec.rb +0 -193
  116. data/spec/ruact/server_functions/railtie_integration_spec.rb +0 -215
  117. data/spec/ruact/server_functions/rake_spec.rb +0 -86
  118. data/spec/ruact/server_functions/route_source_spec.rb +0 -202
  119. data/spec/ruact/server_functions/snapshot_spec.rb +0 -96
  120. data/spec/ruact/server_functions/snapshot_writer_spec.rb +0 -71
  121. data/spec/ruact/server_rescue_request_spec.rb +0 -416
  122. data/spec/ruact/server_spec.rb +0 -179
  123. data/spec/ruact/server_upload_request_spec.rb +0 -311
  124. data/spec/ruact/signed_references_spec.rb +0 -164
  125. data/spec/ruact/string_distance_spec.rb +0 -38
  126. data/spec/ruact/tasks_json_introspection_spec.rb +0 -141
  127. data/spec/ruact/testing/have_ruact_component_spec.rb +0 -170
  128. data/spec/ruact/testing/no_production_load_spec.rb +0 -41
  129. data/spec/ruact/validation_errors_spec.rb +0 -116
  130. data/spec/ruact/view_helper_spec.rb +0 -131
  131. data/spec/spec_helper.rb +0 -77
  132. data/spec/support/fixtures/pixel.png +0 -0
  133. data/spec/support/flight_wire_parser.rb +0 -21
  134. data/spec/support/flight_wire_parser_spec.rb +0 -93
  135. data/spec/support/matchers/flight_fixture_matcher.rb +0 -130
  136. data/spec/support/matchers/flight_fixture_matcher_spec.rb +0 -250
  137. data/spec/support/rails_stub.rb +0 -115
@@ -1,179 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- module Ruact
6
- RSpec.describe Serializable do
7
- let(:serializable_class) do
8
- Class.new do
9
- include Ruact::Serializable
10
-
11
- attr_reader :id, :title, :secret
12
-
13
- def initialize
14
- @id = 1
15
- @title = "Hello"
16
- @secret = "top-secret"
17
- end
18
-
19
- ruact_props :id, :title
20
- end
21
- end
22
-
23
- describe "ruact_props (AC#2)" do
24
- it "raises ArgumentError for undefined method at class load time" do
25
- expect do
26
- Class.new do
27
- include Ruact::Serializable
28
-
29
- ruact_props :nonexistent
30
- end
31
- end.to raise_error(ArgumentError, /nonexistent/)
32
- end
33
- end
34
-
35
- # Story 13.7 — `ruact_props` on ActiveRecord models.
36
- #
37
- # ActiveRecord defines its attribute reader methods LAZILY (on first
38
- # instance access), so at the moment the `ruact_props :title` macro runs,
39
- # `method_defined?(:title)` is `false` even for a real column. The eager
40
- # boot check used to raise there, so an AR model that included
41
- # `Ruact::Serializable` crashed at class-load. Story 13.7 makes the check
42
- # HYBRID: POROs are still checked eagerly at class-load (byte-identical, see
43
- # the block above), while for a lazy-attribute (AR) class the loud check is
44
- # DEFERRED to the first `ruact_serialize` — where the DB is up and the reader
45
- # exists. Loudness is preserved: a bogus prop still raises a clean
46
- # `ArgumentError`, just at first render of that model instead of at boot.
47
- #
48
- # Zero suite-boot DB footprint: the connection + table are built INSIDE the
49
- # example (direct connection DDL, NOT `Schema.define`, so we touch nothing
50
- # global — no `schema_migrations` / `ar_internal_metadata`), and only a
51
- # connection we ourselves opened is torn down.
52
- describe "ActiveRecord models (Story 13.7)", :story_13_7 do
53
- before do
54
- require "active_record"
55
- @already_connected =
56
- ActiveRecord::Base.respond_to?(:connected?) && ActiveRecord::Base.connected?
57
- ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") unless @already_connected
58
- ActiveRecord::Base.connection.create_table(:ruact_props_probe_posts, force: true) do |t|
59
- t.string :title
60
- t.string :secret
61
- end
62
- end
63
-
64
- after do
65
- if defined?(ActiveRecord::Base) && ActiveRecord::Base.connected?
66
- ActiveRecord::Base.connection.drop_table(:ruact_props_probe_posts, if_exists: true)
67
- end
68
- ActiveRecord::Base.remove_connection unless @already_connected
69
- end
70
-
71
- let(:ar_model) do
72
- Class.new(ActiveRecord::Base) do
73
- self.table_name = "ruact_props_probe_posts"
74
- include Ruact::Serializable
75
-
76
- ruact_props :id, :title
77
- end
78
- end
79
-
80
- it "loads without raising even though readers are lazy at class-load (AC#1)" do
81
- expect { ar_model }.not_to raise_error
82
- end
83
-
84
- it "ruact_serialize returns only the declared allowlist (AC#1)" do
85
- row = ar_model.create!(title: "Hello", secret: "top-secret")
86
-
87
- expect(row.ruact_serialize).to eq({ "id" => row.id, "title" => "Hello" })
88
- expect(row.ruact_serialize.keys).not_to include("secret")
89
- end
90
-
91
- it "defers the loud check to first serialize for a bogus prop (AC#2)" do
92
- model = nil
93
-
94
- # Declaring a bogus prop on an AR model does NOT raise at class-load —
95
- # the reader might still be defined lazily, so the check is deferred.
96
- expect do
97
- model = Class.new(ActiveRecord::Base) do
98
- self.table_name = "ruact_props_probe_posts"
99
- include Ruact::Serializable
100
-
101
- ruact_props :ttile # typo — neither a column nor a method
102
- end
103
- end.not_to raise_error
104
-
105
- # …but it fails LOUDLY (same clean ArgumentError) on first serialize.
106
- expect { model.new.ruact_serialize }
107
- .to raise_error(ArgumentError, /ttile.*not defined/)
108
- end
109
-
110
- it "re-validates loudly when props are re-declared after a first serialize (AC#2)" do
111
- model = Class.new(ActiveRecord::Base) do
112
- self.table_name = "ruact_props_probe_posts"
113
- include Ruact::Serializable
114
-
115
- ruact_props :id, :title
116
- end
117
-
118
- # First serialize succeeds and memoizes "validated"…
119
- model.create!(title: "Hello").ruact_serialize
120
-
121
- # …a re-declaration with a bogus prop must NOT be masked by the stale
122
- # memo: the next serialize still raises the clean ArgumentError.
123
- model.ruact_props :id, :ttile
124
- expect { model.new.ruact_serialize }
125
- .to raise_error(ArgumentError, /ttile.*not defined/)
126
- end
127
-
128
- it "re-validates an inherited declaration re-declared on the parent after a subclass serialize (AC#2)" do
129
- parent = Class.new(ActiveRecord::Base) do
130
- self.table_name = "ruact_props_probe_posts"
131
- include Ruact::Serializable
132
-
133
- ruact_props :id, :title
134
- end
135
- child = Class.new(parent)
136
-
137
- # The subclass serializes first, memoizing the inherited (valid) list…
138
- parent.create!(title: "Hello")
139
- child.first.ruact_serialize
140
-
141
- # …then the PARENT re-declares with a bogus prop. The subclass must not
142
- # keep serving its stale memo: its next serialize re-validates loudly.
143
- parent.ruact_props :id, :ttile
144
- expect { child.first.ruact_serialize }
145
- .to raise_error(ArgumentError, /ttile.*not defined/)
146
- end
147
-
148
- it "dispatches through serialize_serializable under strict true AND false (AC#4)" do
149
- row = ar_model.create!(title: "Hello", secret: "top-secret")
150
-
151
- [true, false].each do |strict|
152
- output = Ruact::Flight::Renderer.render(
153
- row, Ruact::ClientManifest.from_hash({}), strict_serialization: strict
154
- )
155
- expect(output).to include("Hello")
156
- expect(output).not_to include("top-secret")
157
- end
158
- end
159
- end
160
-
161
- describe "ruact_serialize (AC#1)" do
162
- it "returns only declared props" do
163
- obj = serializable_class.new
164
- expect(obj.ruact_serialize).to eq({ "id" => 1, "title" => "Hello" })
165
- end
166
-
167
- it "excludes undeclared attributes" do
168
- obj = serializable_class.new
169
- expect(obj.ruact_serialize.keys).not_to include("secret")
170
- end
171
- end
172
-
173
- describe "ruact_props_list" do
174
- it "returns the declared prop names as symbols" do
175
- expect(serializable_class.ruact_props_list).to eq(%i[id title])
176
- end
177
- end
178
- end
179
- end