From 4aee5e06fe692b1183868752ccc78dd8f6b7fd1d Mon Sep 17 00:00:00 2001 From: AdamMusa Date: Fri, 31 Jul 2026 00:44:41 -0400 Subject: [PATCH 01/30] Ship the HTML DSL in ruflet_rails Rails ERB views compile into real native controls, so a Rails app can drive a native UI without a Ruflet app file or a WebView. The feature previously lived only in an uncommitted worktree; this lands it in the package. html_dsl/parser, styles, transformer markup -> control tree html_dsl/html_app screens, navigation, services html_dsl/rack_fetcher in-process Rails dispatch, no socket html_dsl/view_helpers 112 ERB helpers Two fixes for how an in-place re-render costs: control_diff patch only the props that changed instead of replacing the body. A counter tap went from 653 bytes and 11 controls to 53 bytes and one prop, and the client no longer rebuilds the subtree (which was losing scroll position). render_native Post/Redirect/Get is for browsers with a reload button. The native client has neither, so the redirect doubled the work. Actions now answer the native session directly: two Rails cycles per tap became one. Service calls that wait on a person -- permission prompts, file pickers, save sheets -- no longer use the 10s default, which expired while the dialog was still on screen ("execution expired"). 30s covers answering a dialog without turning a broken call into a long hang. save_file's src-bytes arrives from an HTML attribute as text; force it to binary so msgpack sends it as bin and it lands as the Uint8List the client declares, instead of raising a String/Uint8List cast error. Mounting services no longer swallows its own errors: a failed mount used to surface later as an unexplained invoke timeout. Also removes the duplicated WireCodec and WebSocketConnection now provided by ruflet_server, and adds a Gemfile/Rakefile so the package resolves against the local sibling gems and runs its own suite. 282 runs, 1863 assertions, 0 failures. --- packages/ruflet_rails/Gemfile | 19 + packages/ruflet_rails/Gemfile.lock | 338 +++++ packages/ruflet_rails/README.md | 213 ++- packages/ruflet_rails/Rakefile | 12 + .../ruflet/install/install_generator.rb | 5 +- packages/ruflet_rails/lib/ruflet/rails.rb | 45 +- .../lib/ruflet/rails/controller_helpers.rb | 55 + .../ruflet_rails/lib/ruflet/rails/html_dsl.rb | 38 + .../lib/ruflet/rails/html_dsl/control_diff.rb | 109 ++ .../lib/ruflet/rails/html_dsl/html_app.rb | 1169 +++++++++++++++++ .../lib/ruflet/rails/html_dsl/parser.rb | 208 +++ .../lib/ruflet/rails/html_dsl/rack_fetcher.rb | 153 +++ .../lib/ruflet/rails/html_dsl/styles.rb | 433 ++++++ .../lib/ruflet/rails/html_dsl/transformer.rb | 1149 ++++++++++++++++ .../lib/ruflet/rails/html_dsl/view_helpers.rb | 306 +++++ .../lib/ruflet/rails/install_support.rb | 6 +- .../lib/ruflet/rails/native_app.rb | 6 +- .../lib/ruflet/rails/protocol/web_app.rb | 6 +- .../rails/protocol/web_socket_connection.rb | 126 -- .../lib/ruflet/rails/protocol/wire_codec.rb | 268 ---- .../ruflet_rails/lib/ruflet/rails/railtie.rb | 27 +- .../lib/ruflet/rails/view_helpers.rb | 4 +- .../lib/ruflet/rails/web_installer.rb | 2 +- packages/ruflet_rails/lib/ruflet_rails.rb | 2 + packages/ruflet_rails/ruflet_rails.gemspec | 6 +- .../test/controller_helpers_test.rb | 61 + .../test/endpoint_declaration_test.rb | 10 +- packages/ruflet_rails/test/html_app_test.rb | 676 ++++++++++ .../test/html_dsl_helpers_test.rb | 251 ++++ packages/ruflet_rails/test/html_dsl_test.rb | 824 ++++++++++++ .../test/install_generator_test.rb | 6 +- .../ruflet_rails/test/install_support_test.rb | 4 +- packages/ruflet_rails/test/native_app_test.rb | 4 +- .../ruflet_rails/test/ruflet_rails_test.rb | 4 +- packages/ruflet_rails/test/web_app_test.rb | 10 +- 35 files changed, 6077 insertions(+), 478 deletions(-) create mode 100644 packages/ruflet_rails/Gemfile create mode 100644 packages/ruflet_rails/Gemfile.lock create mode 100644 packages/ruflet_rails/Rakefile create mode 100644 packages/ruflet_rails/lib/ruflet/rails/controller_helpers.rb create mode 100644 packages/ruflet_rails/lib/ruflet/rails/html_dsl.rb create mode 100644 packages/ruflet_rails/lib/ruflet/rails/html_dsl/control_diff.rb create mode 100644 packages/ruflet_rails/lib/ruflet/rails/html_dsl/html_app.rb create mode 100644 packages/ruflet_rails/lib/ruflet/rails/html_dsl/parser.rb create mode 100644 packages/ruflet_rails/lib/ruflet/rails/html_dsl/rack_fetcher.rb create mode 100644 packages/ruflet_rails/lib/ruflet/rails/html_dsl/styles.rb create mode 100644 packages/ruflet_rails/lib/ruflet/rails/html_dsl/transformer.rb create mode 100644 packages/ruflet_rails/lib/ruflet/rails/html_dsl/view_helpers.rb delete mode 100644 packages/ruflet_rails/lib/ruflet/rails/protocol/web_socket_connection.rb delete mode 100644 packages/ruflet_rails/lib/ruflet/rails/protocol/wire_codec.rb create mode 100644 packages/ruflet_rails/test/controller_helpers_test.rb create mode 100644 packages/ruflet_rails/test/html_app_test.rb create mode 100644 packages/ruflet_rails/test/html_dsl_helpers_test.rb create mode 100644 packages/ruflet_rails/test/html_dsl_test.rb diff --git a/packages/ruflet_rails/Gemfile b/packages/ruflet_rails/Gemfile new file mode 100644 index 00000000..9398fdbd --- /dev/null +++ b/packages/ruflet_rails/Gemfile @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec + +# Develop against the sibling packages in this repo, not the released gems. +# The HTML DSL leans on current ruflet_core (ControlFactory, the control +# registry the transformer builds every tag from) and on ruflet_server's +# WireCodec, so resolving those to a published version would test the gem +# against code it is not actually shipping with. +gem "ruflet", path: "../ruflet" +gem "ruflet_core", path: "../ruflet_core" +gem "ruflet_server", path: "../ruflet_server" + +group :development, :test do + gem "minitest", "~> 5.0" + gem "rake", "~> 13.0" +end diff --git a/packages/ruflet_rails/Gemfile.lock b/packages/ruflet_rails/Gemfile.lock new file mode 100644 index 00000000..81032e49 --- /dev/null +++ b/packages/ruflet_rails/Gemfile.lock @@ -0,0 +1,338 @@ +PATH + remote: ../ruflet_core + specs: + ruflet_core (0.0.21) + +PATH + remote: ../ruflet_server + specs: + ruflet_server (0.0.21) + ruflet_core (= 0.0.21) + +PATH + remote: ../ruflet + specs: + ruflet (0.0.21) + rqrcode (~> 2.2) + +PATH + remote: . + specs: + ruflet_rails (0.0.16) + rails (>= 7.0) + ruflet (>= 0.0.21) + ruflet_core (>= 0.0.21) + ruflet_server (>= 0.0.21) + +GEM + remote: https://rubygems.org/ + specs: + action_text-trix (2.1.19) + railties + actioncable (8.1.3.1) + actionpack (= 8.1.3.1) + activesupport (= 8.1.3.1) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + zeitwerk (~> 2.6) + actionmailbox (8.1.3.1) + actionpack (= 8.1.3.1) + activejob (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) + mail (>= 2.8.0) + actionmailer (8.1.3.1) + actionpack (= 8.1.3.1) + actionview (= 8.1.3.1) + activejob (= 8.1.3.1) + activesupport (= 8.1.3.1) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (8.1.3.1) + actionview (= 8.1.3.1) + activesupport (= 8.1.3.1) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (8.1.3.1) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (8.1.3.1) + activesupport (= 8.1.3.1) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (8.1.3.1) + activesupport (= 8.1.3.1) + globalid (>= 0.3.6) + activemodel (8.1.3.1) + activesupport (= 8.1.3.1) + activerecord (8.1.3.1) + activemodel (= 8.1.3.1) + activesupport (= 8.1.3.1) + timeout (>= 0.4.0) + activestorage (8.1.3.1) + actionpack (= 8.1.3.1) + activejob (= 8.1.3.1) + activerecord (= 8.1.3.1) + activesupport (= 8.1.3.1) + marcel (~> 1.0) + activesupport (8.1.3.1) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + json + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + base64 (0.3.0) + bigdecimal (4.1.2) + builder (3.3.0) + chunky_png (1.4.0) + concurrent-ruby (1.3.8) + connection_pool (3.0.2) + crass (1.0.7) + date (3.5.1) + drb (2.2.3) + erb (6.0.6) + erubi (1.13.1) + globalid (1.4.0) + activesupport (>= 6.1) + i18n (1.15.2) + concurrent-ruby (~> 1.0) + io-console (0.8.2) + irb (1.18.0) + pp (>= 0.6.0) + prism (>= 1.3.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + json (2.21.1) + logger (1.7.0) + loofah (2.25.2) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mail (2.9.1) + logger + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.2.1) + mini_mime (1.1.5) + minitest (5.27.0) + net-imap (0.6.6) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.5.1) + net-protocol + nio4r (2.7.5) + nokogiri (1.19.4-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-aarch64-linux-musl) + racc (~> 1.4) + nokogiri (1.19.4-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-arm-linux-musl) + racc (~> 1.4) + nokogiri (1.19.4-arm64-darwin) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-musl) + racc (~> 1.4) + pp (0.6.4) + prettyprint + prettyprint (0.2.0) + prism (1.9.0) + racc (1.8.1) + rack (3.2.6) + rack-session (2.1.2) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rackup (2.3.1) + rack (>= 3) + rails (8.1.3.1) + actioncable (= 8.1.3.1) + actionmailbox (= 8.1.3.1) + actionmailer (= 8.1.3.1) + actionpack (= 8.1.3.1) + actiontext (= 8.1.3.1) + actionview (= 8.1.3.1) + activejob (= 8.1.3.1) + activemodel (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) + bundler (>= 1.15.0) + railties (= 8.1.3.1) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.7.1) + loofah (~> 2.25, >= 2.25.2) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (8.1.3.1) + actionpack (= 8.1.3.1) + activesupport (= 8.1.3.1) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) + rake (13.4.2) + rbs (4.1.1) + logger + prism (>= 1.6.0) + tsort + rdoc (8.0.0) + erb + prism (>= 1.6.0) + rbs (>= 4.0.0) + tsort + reline (0.6.3) + io-console (~> 0.5) + rqrcode (2.2.0) + chunky_png (~> 1.0) + rqrcode_core (~> 1.0) + rqrcode_core (1.2.0) + securerandom (0.4.1) + thor (1.5.0) + timeout (0.6.1) + tsort (0.2.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uri (1.1.1) + useragent (0.16.11) + websocket-driver (0.8.2) + base64 + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.8.2) + +PLATFORMS + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + minitest (~> 5.0) + rake (~> 13.0) + ruflet! + ruflet_core! + ruflet_rails! + ruflet_server! + +CHECKSUMS + action_text-trix (2.1.19) sha256=7012f59421009cf284aa651294896414d653a61a2417c9b8714c8476d2f74009 + actioncable (8.1.3.1) sha256=e318528295c878a3efdfe25f0f2267c80cb7a76eba41bb5f64d44aa380a3d91b + actionmailbox (8.1.3.1) sha256=5f704972097d843ade8e435e93694a1dac732b926df1717aceba1f3840082b1c + actionmailer (8.1.3.1) sha256=88ea441b28ff02a0c6c006468892642a3d9942affce9d294e81a74504aa5c43c + actionpack (8.1.3.1) sha256=974cb7154548e81f470b1b0f247b99cb38e87825899dca58610596e2817723d0 + actiontext (8.1.3.1) sha256=5da729d833d1a29cddb1eee938878e55e503d2613e00e735f5daf58c2ba98af2 + actionview (8.1.3.1) sha256=2da68b8414c47b43bfbed1ce69c5afe1c04f78c267aacb5660a4cab5ca12cfb6 + activejob (8.1.3.1) sha256=1c8dd275df930df40deecffec63d913a550a33fd94bd298f69721dd96939954a + activemodel (8.1.3.1) sha256=99cc02ce2faec371d14440949d85787ebd23a907c9baef0a9d4bcd4d21888f88 + activerecord (8.1.3.1) sha256=0a2fb6c28f4938f6b013a3a549bec0a7e37d535f3dc8990e804bcc3258c0403b + activestorage (8.1.3.1) sha256=f555254f387b1cffa499d2fd3115d12635eadc5b15206a8534316a67036163ef + activesupport (8.1.3.1) sha256=85458765f25ea48b9019c46b6bb3fa5683197bf4280d9f06710a6e8d7a831376 + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd + builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f + chunky_png (1.4.0) sha256=89d5b31b55c0cf4da3cf89a2b4ebc3178d8abe8cbaf116a1dba95668502fdcfe + concurrent-ruby (1.3.8) sha256=b2f1be836e968ccc78ccfce277ea79c72a88633f22306782c16ff23fb415d1e1 + connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a + crass (1.0.7) sha256=94868719948664c89ddcaf0a37c65048413dfcb1c869470a5f7a7ceb5390b295 + date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0 + drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 + erb (6.0.6) sha256=a9b24986700f5bf127c4f297c5403c3ca41b83b0a316c0cd09a096b56e644ae5 + erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 + globalid (1.4.0) sha256=037f12fbf1d9d7a014d501c2d5c77356fd4ddd96d7a7991d6700bba96706f427 + i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5 + io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc + irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3 + json (2.21.1) sha256=13a43df75d95641443f5702dff350f237164a9d811ff0f2c2800d4d980220583 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + loofah (2.25.2) sha256=2007f746959ac65552456e04b433e83deb22759ab38c838b4445c70e43425918 + mail (2.9.1) sha256=06574eca475253d6c18145dd70af80d0eb970182d55053497c5f4d797ea160e8 + marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f + mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef + minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5 + net-imap (0.6.6) sha256=96aa4ee50df3060203e649efc341f53480b791d49e150f2fdebf68beb141a8df + net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 + net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 + net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736 + nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 + nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f + nokogiri (1.19.4-aarch64-linux-musl) sha256=35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af + nokogiri (1.19.4-arm-linux-gnu) sha256=a301313e38bb065d68239e79734bcd6f56fb6efaacebde29e9abf2a4735340ca + nokogiri (1.19.4-arm-linux-musl) sha256=588923c101bcfa78869734d247d25b598674323e7f22474fc468f6e5647311eb + nokogiri (1.19.4-arm64-darwin) sha256=a46db9853286e6597b36ebc6953817d15acf3a299583eb3f89fdc6f91dd63527 + nokogiri (1.19.4-x86_64-darwin) sha256=7fd17057d3e1f00e9954a74b3cd76595d3d4a5ef233b7ed9599047c204f70551 + nokogiri (1.19.4-x86_64-linux-gnu) sha256=379fae440b28915e3f19d752ce2dcf8465ed2b2fbefd2a7ca0dd497bc981a06a + nokogiri (1.19.4-x86_64-linux-musl) sha256=17dfb7c1fa194ae02fbf7c51a7afc8d278045ab3fdacfd86f91d02d7b274470b + pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570 + prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 + prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85 + racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f + rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2 + rack-session (2.1.2) sha256=595434f8c0c3473ae7d7ac56ecda6cc6dfd9d37c0b2b5255330aa1576967ffe8 + rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463 + rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868 + rails (8.1.3.1) sha256=ccd11a36bfc171bf9c66d585d14c0ece91c0c9dde840aae60c0118d6f5c9c52a + rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d + rails-html-sanitizer (1.7.1) sha256=e797a7c9b01e567307e317c576b49ab4168017e63eea4dba9ce3cb587e2f22c2 + railties (8.1.3.1) sha256=2388a232579a00cefea4487de66c8553c3408c1300abdc6cf1799d86ffb04487 + rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701 + rbs (4.1.1) sha256=1bf118f2f95d1cd3956357645d495152b661e0257e57781d18ceecd461622b9e + rdoc (8.0.0) sha256=03bf8c08a9639658855a0cfd77c0abca8325c227693f7f33f82957811348c469 + reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835 + rqrcode (2.2.0) sha256=23eea88bb44c7ee6d6cab9354d08c287f7ebcdc6112e1fe7bcc2d010d1ffefc1 + rqrcode_core (1.2.0) sha256=cf4989dc82d24e2877984738c4ee569308625fed2a810960f1b02d68d0308d1a + ruflet (0.0.21) + ruflet_core (0.0.21) + ruflet_rails (0.0.16) + ruflet_server (0.0.21) + securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 + thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 + timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb + tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f + tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b + uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6 + useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844 + websocket-driver (0.8.2) sha256=97c556b019bf3410b4961002ac501621e9322d3f8a7bc02161a09301cc4c4146 + websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241 + zeitwerk (2.8.2) sha256=7212a61311083c604184b1ea2574b9aa05cd14f855a0841c06985cabe9181d12 + +BUNDLED WITH + 4.0.11 diff --git a/packages/ruflet_rails/README.md b/packages/ruflet_rails/README.md index d6b4f4c8..52ae9322 100644 --- a/packages/ruflet_rails/README.md +++ b/packages/ruflet_rails/README.md @@ -60,7 +60,7 @@ bundle exec rake ruflet:web Mount the installed client and a developer-owned Ruflet entrypoint: ```ruby -mount Ruflet::Rails.web_app(app_file: Rails.root.join("app/views/ruflet/main.rb")), at: "/app" +mount Ruflet::Rails.native(app_file: Rails.root.join("app/views/ruflet/main.rb")), at: "/app" ``` The install generator adds the same mount at `/ruflet` when `--web` is used. @@ -120,11 +120,214 @@ bundle exec rake ruflet:install bundle exec rake ruflet:install[DEVICE_ID] ``` +## HTML as the UI DSL (no WebView) + +Beyond the WebView shell, Ruflet can treat HTML itself as the UI language: +Rails views describe screens with markup, and `Ruflet::Rails.html_to_native` +compiles each page into **real native Ruflet controls** — no WebView anywhere. +This is HTML-over-the-wire for native UI: state lives in Rails, every +interaction is a request, and the response markup re-renders the screen. + +```ruby +# app/views/ruflet/main.rb +Ruflet.run do |page| + Ruflet::Rails.html_to_native(page, start_url: "#{Ruflet::Rails.backend_url}/native") +end +``` + +Screens are ordinary Rails views (ERB, controllers, sessions, and redirects +all work — requests carry the Rails session cookie and CSRF token, plus an +`X-Ruflet-Native: 1` header so a controller can render native markup and a +browser page from the same action): + +```erb +<%# app/views/counters/show.html.erb %> + + + + <%= @count %> + + + + + Settings + +``` + +- **Layout** — ``, ``, ``, `
`/`
` (container), + ``, `
`, ``, ``, ``. +- **Content** — ``, `

`–`

`, `

`, ``, ``, ``, + `


`, `