AndyObtiva / glimmer-dsl-web

Glimmer DSL for Web (Ruby-in-the-Browser Web Frontend Framework)
MIT License
88 stars 1 forks source link

[Question] is there a tetris code sample for this project? #4

Open zw963 opened 1 month ago

zw963 commented 1 month ago

As https://github.com/AndyObtiva/glimmer_tetris

But, because it use JRuby, it is hard to make it work on my laptop because of various issues related to JRuby.

I expect it can be port to gimmer-dsl-web, use standalone demo

Thanks.


BTW: i port standalone to use opal-browser instead of opal-jquery.

https://github.com/zw963/glimmer-dsl-web_example

AndyObtiva commented 1 month ago

I've never encountered any issues running JRuby though one of its dependencies is the JVM (Java Virtual Machine), and it has to be installed first before using JRuby. I'd be happy to troubleshoot your JRuby installation if needed. You oughta be able to run java --version successfully first before installing JRuby.

That said, Glimmer DSL for LibUI already ships with Tetris too as one of its Advanced examples, and it doesn't even need a web server like Glimmer DSL for Web, nor a JVM. It just runs on pure Ruby and it won a Fukuoka Ruby 2022 Special Award after getting presented to Matz the creator of Ruby.

tetris

Just install the gem in standard Ruby (MRI CRuby):

gem install glimmer-dsl-libui

And, then run this command to list all available samples:

glimmer examples

Meta Example

You will find Tetris under the Advanced examples tab.

Screenshot 2024-07-17 at 1 35 11 PM

You can select Tetris and click the Launch button to start Tetris from there.

tetris

Or, you can run this direct command to start Tetris right away:

ruby -r glimmer-dsl-libui -e "require 'examples/tetris'"

tetris

The version of Tetris above can be run much more easily without using a web browser. Desktop apps in general are way simpler than web apps. That's why I love them and prefer them over web app development when they are sufficient. People who try to build everything as a web app miss out on that advantage. It is better to use the simplest tool available for every job instead of trying to force everything into being a web app if not needed, which is a bad habit many developers suffer from recently, causing extreme over-engineering and writing a lot more code than needed that is unnecessary.

That said, if you want Tetris in Glimmer DSL for Web, you can implement/port it and submit a Pull Request. I am busy with other priorities at the moment, including some related to implementing features needed for version 1.0 of Glimmer DSL for Web.

BTW: i port standalone to use opal-browser instead of opal-jquery. https://github.com/zw963/glimmer-dsl-web_example

Thank you for providing that. I starred/forked it.

One thing to note is the last time I checked out opal-browser, it had limitations and issues that made it unreliable for my usage. That is why I rely on opal-jquery instead. I have not checked out the latest version of opal-browser though, so things might have changed since the last time I looked at it.

zw963 commented 1 month ago

Okay, thanks, let me try again.

I am current running Arch Linux.

╰─ $ java --version
java 22.0.1 2024-04-16
Java(TM) SE Runtime Environment (build 22.0.1+8-16)
Java HotSpot(TM) 64-Bit Server VM (build 22.0.1+8-16, mixed mode, sharing)

 ╰─ $ rvm current
jruby-9.2.19.0@glimmer_tetris

It get following error message when bundle install.

error report --- ERROR REPORT TEMPLATE ------------------------------------------------------- # Error Report ## Questions Please fill out answers to these questions, it'll help us figure out why things are going wrong. - **What did you do?** I ran the command `/home/zw963/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/bin/bundle install` - **What did you expect to happen?** I expected Bundler to... - **What happened instead?** Instead, what happened was... - **Have you tried any solutions posted on similar issues in our issue tracker, stack overflow, or google?** I tried... - **Have you read our issues document, https://github.com/rubygems/rubygems/blob/master/bundler/doc/contributing/ISSUES.md?** ... ## Backtrace ``` NameError: uninitialized constant Bundler::RubygemsIntegration::YamlLibrarySyntaxError Did you mean? Bundler::YamlSyntaxError org/jruby/RubyModule.java:3766:in `const_missing' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/rubygems_integration.rb:116:in `configuration' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/fetcher.rb:247:in `connection' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/fetcher.rb:89:in `initialize' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/source/rubygems.rb:291:in `block in fetchers' org/jruby/RubyArray.java:2588:in `map' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/source/rubygems.rb:289:in `fetchers' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/source/rubygems.rb:428:in `block in remote_specs' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/index.rb:9:in `build' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/source/rubygems.rb:427:in `remote_specs' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/source/rubygems.rb:127:in `specs' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/resolver.rb:168:in `index_for' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/resolver.rb:176:in `results_for' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/resolver.rb:114:in `search_for' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/resolver.rb:256:in `block in verify_gemfile_dependencies_are_found!' org/jruby/RubyArray.java:1820:in `each' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/resolver.rb:253:in `verify_gemfile_dependencies_are_found!' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/resolver.rb:50:in `start' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/resolver.rb:23:in `resolve' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/definition.rb:262:in `resolve' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/definition.rb:178:in `resolve_remotely!' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/installer.rb:283:in `resolve_if_needed' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/installer.rb:82:in `block in run' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/process_lock.rb:12:in `block in lock' org/jruby/RubyIO.java:1158:in `open' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/process_lock.rb:9:in `lock' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/installer.rb:71:in `run' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/installer.rb:23:in `install' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/cli/install.rb:60:in `run' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/cli.rb:252:in `block in install' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/settings.rb:131:in `temporary' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/cli.rb:251:in `install' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/cli.rb:31:in `dispatch' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/cli.rb:25:in `start' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/exe/bundle:49:in `block in
' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/lib/bundler/friendly_errors.rb:128:in `with_friendly_errors' /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/gems/bundler-2.2.27/exe/bundle:37:in `
' org/jruby/RubyKernel.java:1009:in `load' /home/zw963/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/bin/bundle:25:in `
' ``` ## Environment ``` Bundler 2.2.27 Platforms ruby, universal-java-22 Ruby 2.5.8p0 (2021-06-15 revision 67882) [java] Full Path /home/common/.rvm/rubies/jruby-9.2.19.0/bin/jruby Config Dir /home/common/.rvm/rubies/jruby-9.2.19.0/etc RubyGems 3.1.6 Gem Home /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris Gem Path /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris:/home/common/.rvm/rubies/jruby-9.2.19.0/lib/ruby/gems/shared User Home /home/zw963 User Path /home/zw963/.gem/jruby/2.5.0 Bin Dir /home/common/.rvm/gems/jruby-9.2.19.0@glimmer_tetris/bin OpenSSL Compiled JRuby-OpenSSL 0.14.3 Loaded JRuby-OpenSSL 0.14.3 Cert File /usr/lib/jvm/java-22-jdk/lib/security/cacerts Cert Dir /etc/ssl/certs Tools Git 2.45.2 RVM 1.29.12-next (master) rbenv not installed chruby not installed rubygems-bundler (1.4.5) ``` ## Bundler Build Metadata ``` Built At 2021-09-03 Git SHA b737e1c930 Released Version true ``` ## Bundler settings ``` # bundle_build.nokogiri You have not configured a value for `# bundle_build.nokogiri` # bundle_build.pg You have not configured a value for `# bundle_build.pg` # bundle_disable_multisource You have not configured a value for `# bundle_disable_multisource` # bundle_global_gem_cache You have not configured a value for `# bundle_global_gem_cache` # bundle_specific_platform You have not configured a value for `# bundle_specific_platform` default_install_use_path Set for the current user (/home/zw963/.bundle/config): "true" git.allow_insecure Set for the current user (/home/zw963/.bundle/config): true job Set for the current user (/home/zw963/.bundle/config): "4" mirror.https://rubygems.org/ Set for the current user (/home/zw963/.bundle/config): "https://gems.ruby-china.com" only_update_to_newer_versions Set for the current user (/home/zw963/.bundle/config): "true" retry Set for the current user (/home/zw963/.bundle/config): 2 source Set for the current user (/home/zw963/.bundle/config): "https:[REDACTED]" ``` ## Gemfile ### Gemfile ```ruby # frozen_string_literal: true source 'https://rubygems.org' git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem 'glimmer-dsl-swt', '~> 4.20.0.0' gem 'glimmer-cp-bevel', '~> 0.1.1' group :development do gem 'rspec', '~> 3.5.0' gem 'juwelier', '2.4.9' gem 'warbler', '2.0.5' gem 'simplecov', '>= 0' end ``` ### Gemfile.lock ``` GEM remote: https://rubygems.org/ specs: addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) array_include_methods (1.0.4) awesome_print (1.9.2) builder (3.2.4) concurrent-ruby (1.1.9) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.4.4) docile (1.4.0) facets (3.1.0) faraday (1.4.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) faraday-net_http (~> 1.0) faraday-net_http_persistent (~> 1.1) multipart-post (>= 1.2, < 3) ruby2_keywords (>= 0.0.4) faraday-em_http (1.0.0) faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-net_http (1.0.1) faraday-net_http_persistent (1.1.0) git (1.8.1) rchardet (~> 1.8) github_api (0.19.0) addressable (~> 2.4) descendants_tracker (~> 0.0.4) faraday (>= 0.8, < 2) hashie (~> 3.5, >= 3.5.2) oauth2 (~> 1.0) glimmer (1.3.1) array_include_methods (>= 1.0.4, < 2.0.0) concurrent-ruby (>= 1.1.7, < 2.0.0) facets (>= 3.1.0, < 4.0.0) glimmer-cp-bevel (0.1.1) glimmer-dsl-swt (>= 4.18.7.4, < 5.0.0.0) glimmer-dsl-swt (4.20.0.0) glimmer (~> 1.3.1) jruby-win32ole (>= 0.8.5, < 2.0.0) logging (>= 2.3.0, < 3.0.0) nested_inherited_jruby_include_package (>= 0.3.0, < 2.0.0) os (>= 1.0.0, < 2.0.0) puts_debuggerer (>= 0.12.0, < 2.0.0) rake (>= 13.0.0) rake-tui (>= 0.2.3, < 2.0.0) rouge (>= 3.26.0, < 4.0.0) super_module (>= 1.4.1, < 2.0.0) text-table (>= 1.2.4, < 2.0.0) hashie (3.6.0) highline (2.0.3) jar-dependencies (0.4.1) jruby-jars (9.2.19.0) jruby-rack (1.1.21) jruby-win32ole (0.8.5) juwelier (2.4.9) builder bundler git github_api highline kamelcase (~> 0) nokogiri psych rake rdoc semver2 jwt (2.2.3) kamelcase (0.0.2) semver2 (~> 3) little-plugger (1.1.4) logging (2.3.0) little-plugger (~> 1.1) multi_json (~> 1.14) method_source (1.0.0) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) nested_inherited_jruby_include_package (0.3.0) nokogiri (1.11.7-java) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) os (1.1.1) pastel (0.8.0) tty-color (~> 0.5) psych (4.0.1-java) jar-dependencies (>= 0.1.7) public_suffix (4.0.6) puts_debuggerer (0.12.0) awesome_print (~> 1.9.2) racc (1.5.2-java) rack (2.2.3) rake (13.0.6) rake-tui (0.2.3) tty-prompt rchardet (1.8.0) rdoc (6.3.1) rouge (3.26.0) rspec (3.5.0) rspec-core (~> 3.5.0) rspec-expectations (~> 3.5.0) rspec-mocks (~> 3.5.0) rspec-core (3.5.4) rspec-support (~> 3.5.0) rspec-expectations (3.5.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.5.0) rspec-mocks (3.5.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.5.0) rspec-support (3.5.0) ruby2_keywords (0.0.4) rubyzip (1.3.0) semver2 (3.4.2) simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.3) super_module (1.4.1) method_source (>= 0.8.2, < 1.1.0) text-table (1.2.4) thread_safe (0.3.6-java) tty-color (0.6.0) tty-cursor (0.7.1) tty-prompt (0.23.1) pastel (~> 0.8) tty-reader (~> 0.8) tty-reader (0.9.0) tty-cursor (~> 0.7) tty-screen (~> 0.8) wisper (~> 2.0) tty-screen (0.8.1) warbler (2.0.5) jruby-jars (>= 9.0.0.0) jruby-rack (>= 1.1.1, < 1.3) rake (>= 10.1.0) rubyzip (~> 1.0, < 1.4) wisper (2.0.1) PLATFORMS universal-java-1.8 DEPENDENCIES glimmer-cp-bevel (~> 0.1.1) glimmer-dsl-swt (~> 4.20.0.0) juwelier (= 2.4.9) rspec (~> 3.5.0) simplecov warbler (= 2.0.5) BUNDLED WITH 2.2.27 ``` --- TEMPLATE END ---------------------------------------------------------------- Unfortunately, an unexpected error occurred, and Bundler cannot continue. First, try this link to see if there are any existing issue reports for this error: https://github.com/rubygems/rubygems/search?q=uninitialized+constant+Bundler++RubygemsIntegration++YamlLibrarySyntaxError&type=Issues If there aren't any reports for this error yet, please copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at: https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md

Then, i switch to Ruby 3.3.4 with new rvmset ruby-3.3.4@glimmer-dsl-libui, and ran gem install glimmer-dsl-libui successful, but failed again when try to run glimmer examples.

install glimmer-dsl-libui logs ``` ╭─ 12:41 zw963 ⮀ ~/ruby/glimmer_tetris ⮀ ⭠ (77b25bd) master % u= ➦ ruby-3.3.4@glimmer-dsl-libui ╰─ $ gem install glimmer-dsl-libui Fetching text-table-1.2.4.gem Fetching method_source-1.0.0.gem Fetching super_module-1.4.1.gem Fetching rouge-3.30.0.gem Fetching wisper-2.0.1.gem Fetching tty-screen-0.8.2.gem Fetching tty-cursor-0.7.1.gem Fetching tty-reader-0.9.0.gem Fetching tty-color-0.6.0.gem Fetching pastel-0.8.0.gem Fetching tty-prompt-0.23.1.gem Fetching rake-tui-0.2.3.gem Fetching awesome_print-1.9.2.gem Fetching puts_debuggerer-1.0.1.gem Fetching equalizer-0.0.11.gem Fetching perfect-shape-1.0.8.gem Fetching glimmer-dsl-libui-0.12.2.gem Fetching os-1.1.4.gem Fetching libui-0.1.2.pre.gem Fetching facets-3.1.0.gem Fetching array_include_methods-1.5.1.gem Fetching glimmer-2.7.9.gem Fetching color-1.8.gem Fetching chunky_png-1.4.0.gem Successfully installed text-table-1.2.4 Successfully installed method_source-1.0.0 Successfully installed super_module-1.4.1 Successfully installed rouge-3.30.0 Successfully installed wisper-2.0.1 Successfully installed tty-screen-0.8.2 Successfully installed tty-cursor-0.7.1 Successfully installed tty-reader-0.9.0 Successfully installed tty-color-0.6.0 Successfully installed pastel-0.8.0 Successfully installed tty-prompt-0.23.1 Successfully installed rake-tui-0.2.3 Successfully installed awesome_print-1.9.2 Successfully installed puts_debuggerer-1.0.1 Successfully installed equalizer-0.0.11 Successfully installed perfect-shape-1.0.8 Successfully installed os-1.1.4 Successfully installed libui-0.1.2.pre Successfully installed facets-3.1.0 Successfully installed array_include_methods-1.5.1 Successfully installed glimmer-2.7.9 Successfully installed color-1.8 Successfully installed chunky_png-1.4.0 Successfully installed glimmer-dsl-libui-0.12.2 ╰─ $ 7 glimmer examples Resolving dependencies... Could not find glimmer-dsl-swt-4.20.0.0, glimmer-cp-bevel-0.1.1, rspec-3.5.0, juwelier-2.4.9, warbler-2.0.5, simplecov-0.21.2, glimmer-1.3.1, jruby-win32ole-0.8.5, logging-2.3.0, nested_inherited_jruby_include_package-0.3.0, os-1.1.1, puts_debuggerer-0.12.0, rake-13.0.6, rouge-3.26.0, rspec-core-3.5.4, rspec-expectations-3.5.0, rspec-mocks-3.5.0, builder-3.2.4, git-1.8.1, github_api-0.19.0, highline-2.0.3, kamelcase-0.0.2, rdoc-6.3.1, semver2-3.4.2, jruby-jars-9.2.19.0, jruby-rack-1.1.21, rubyzip-1.3.0, docile-1.4.0, simplecov-html-0.12.3, simplecov_json_formatter-0.1.3, array_include_methods-1.0.4, concurrent-ruby-1.1.9, little-plugger-1.1.4, multi_json-1.15.0, rspec-support-3.5.0, diff-lcs-1.4.4, rchardet-1.8.0, addressable-2.7.0, descendants_tracker-0.0.4, faraday-1.4.3, hashie-3.6.0, oauth2-1.4.7, public_suffix-4.0.6, faraday-em_http-1.0.0, faraday-em_synchrony-1.0.0, faraday-excon-1.1.0, faraday-net_http-1.0.1, faraday-net_http_persistent-1.1.0, multipart-post-2.1.1, ruby2_keywords-0.0.4, jwt-2.2.3, multi_xml-0.6.0, rack-2.2.3, tty-screen-0.8.1 in locally installed gems Run `bundle install` to install missing gems ```

Anyway, I think JRuby is a niche thing in the Ruby world, in my decade of working with Ruby, I haven't even seen anyone use it, if we could run Tetris on a very small web server (e.g. Roda, Sinatra, even webrick), it would actually be easier to reproduce.

zw963 commented 1 month ago

One thing to note is the last time I checked out opal-browser, it had limitations and issues that made it unreliable for my usage. That is why I rely on opal-jquery instead. I have not checked out the latest version of opal-browser though, so things might have changed since the last time I looked at it.

I don't know if this reason, when i run the data-binding example code in README, i get following error.

 ╰─ $ ruby app.rb
./script.js.rb:4:16: error: unexpected token tRCURLY
./script.js.rb:4:   STATES = {...} # contains US States
./script.js.rb:4:                ^
./script.js.rb:4:in `  STATES = {...} # contains US States': unexpected token tRCURLY (Opal::SyntaxError)
        from /home/zw963/Dropbox/linux/utils/ruby_tools/app/gems/parser-3.3.0.5/lib/parser/diagnostic/engine.rb:72:in `process'
        from /home/zw963/Dropbox/linux/utils/ruby_tools/app/gems/parser-3.3.0.5/lib/parser/base.rb:286:in `on_error'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/racc-1.8.0/lib/racc/parser.rb:263:in `_racc_do_parse_c'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/racc-1.8.0/lib/racc/parser.rb:263:in `do_parse'
        from /home/zw963/Dropbox/linux/utils/ruby_tools/app/gems/parser-3.3.0.5/lib/parser/base.rb:190:in `parse'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/parser/default_config.rb:32:in `parse'
        from /home/zw963/Dropbox/linux/utils/ruby_tools/app/gems/parser-3.3.0.5/lib/parser/base.rb:238:in `tokenize'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/compiler.rb:312:in `block in parse'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/compiler.rb:393:in `re_raise_with_location'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/compiler.rb:312:in `parse'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/compiler.rb:298:in `compile'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder_processors.rb:88:in `block in compiled'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/cache.rb:43:in `fetch'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder_processors.rb:86:in `compiled'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder_processors.rb:102:in `requires'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder.rb:105:in `build_str'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder.rb:92:in `build'
        from app.rb:11:in `<main>'
./script.js.rb:4:in `  STATES = {...} # contains US States': unexpected token tRCURLY (Parser::SyntaxError)
        from /home/zw963/Dropbox/linux/utils/ruby_tools/app/gems/parser-3.3.0.5/lib/parser/diagnostic/engine.rb:72:in `process'
        from /home/zw963/Dropbox/linux/utils/ruby_tools/app/gems/parser-3.3.0.5/lib/parser/base.rb:286:in `on_error'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/racc-1.8.0/lib/racc/parser.rb:263:in `_racc_do_parse_c'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/racc-1.8.0/lib/racc/parser.rb:263:in `do_parse'
        from /home/zw963/Dropbox/linux/utils/ruby_tools/app/gems/parser-3.3.0.5/lib/parser/base.rb:190:in `parse'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/parser/default_config.rb:32:in `parse'
        from /home/zw963/Dropbox/linux/utils/ruby_tools/app/gems/parser-3.3.0.5/lib/parser/base.rb:238:in `tokenize'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/compiler.rb:312:in `block in parse'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/compiler.rb:393:in `re_raise_with_location'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/compiler.rb:312:in `parse'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/compiler.rb:298:in `compile'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder_processors.rb:88:in `block in compiled'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/cache.rb:43:in `fetch'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder_processors.rb:86:in `compiled'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder_processors.rb:102:in `requires'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder.rb:105:in `build_str'
        from /home/common/.rvm/gems/ruby-3.3.0@glimmer-dsl-web_example/gems/opal-1.8.2/lib/opal/builder.rb:92:in `build'
        from app.rb:11:in `<main>'

I don't know if it caused by opal-browser, you can check data-binding branch of my standalone example repo to reproduce.

AndyObtiva commented 1 month ago

It might be caused by opal-browser. I don't recommend using opal-browser. Everything works for me without opal-browser.

AndyObtiva commented 1 month ago

One thing to improve in your example is to make it use a Glimmer::Web::Component. For serious app usage, web UI should always be built using Glimmer::Web::Component (and embedded using the glimmer_component helper in a Rails view).

(Update: I found the issue (below). Try to fix the issue as per my solution below first. You can upgrade the code to use Glimmer::Web::Component and the glimmer_component helper separately in a different example if desired)

AndyObtiva commented 1 month ago

Actually, your main problem though is you copied code from the GitHub page that is intentionally shortened (to avoid distracting readers with unimportant details) by not putting all states in:

  STATES = {...} # contains US States

You need to copy the actual full version of it in the project files (with the STATES filled in): https://github.com/AndyObtiva/glimmer-dsl-web/blob/master/lib/glimmer-dsl-web/samples/hello/hello_data_binding.rb

# Copyright (c) 2023-2024 Andy Maleh
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

require 'glimmer-dsl-web'

Address = Struct.new(:street, :street2, :city, :state, :zip_code, :billing_and_shipping, keyword_init: true) do
  STATES = {
    "AK"=>"Alaska",
    "AL"=>"Alabama",
    "AR"=>"Arkansas",
    "AS"=>"American Samoa",
    "AZ"=>"Arizona",
    "CA"=>"California",
    "CO"=>"Colorado",
    "CT"=>"Connecticut",
    "DC"=>"District of Columbia",
    "DE"=>"Delaware",
    "FL"=>"Florida",
    "GA"=>"Georgia",
    "GU"=>"Guam",
    "HI"=>"Hawaii",
    "IA"=>"Iowa",
    "ID"=>"Idaho",
    "IL"=>"Illinois",
    "IN"=>"Indiana",
    "KS"=>"Kansas",
    "KY"=>"Kentucky",
    "LA"=>"Louisiana",
    "MA"=>"Massachusetts",
    "MD"=>"Maryland",
    "ME"=>"Maine",
    "MI"=>"Michigan",
    "MN"=>"Minnesota",
    "MO"=>"Missouri",
    "MS"=>"Mississippi",
    "MT"=>"Montana",
    "NC"=>"North Carolina",
    "ND"=>"North Dakota",
    "NE"=>"Nebraska",
    "NH"=>"New Hampshire",
    "NJ"=>"New Jersey",
    "NM"=>"New Mexico",
    "NV"=>"Nevada",
    "NY"=>"New York",
    "OH"=>"Ohio",
    "OK"=>"Oklahoma",
    "OR"=>"Oregon",
    "PA"=>"Pennsylvania",
    "PR"=>"Puerto Rico",
    "RI"=>"Rhode Island",
    "SC"=>"South Carolina",
    "SD"=>"South Dakota",
    "TN"=>"Tennessee",
    "TX"=>"Texas",
    "UT"=>"Utah",
    "VA"=>"Virginia",
    "VI"=>"Virgin Islands",
    "VT"=>"Vermont",
    "WA"=>"Washington",
    "WI"=>"Wisconsin",
    "WV"=>"West Virginia",
    "WY"=>"Wyoming"
  }

  def state_code
    STATES.invert[state]
  end

  def state_code=(value)
    self.state = STATES[value]
  end

  def summary
    string_attributes = to_h.except(:billing_and_shipping)
    summary = string_attributes.values.map(&:to_s).reject(&:empty?).join(', ')
    summary += " (Billing & Shipping)" if billing_and_shipping
    summary
  end
end

@address = Address.new(
  street: '123 Main St',
  street2: 'Apartment 3C, 2nd door to the right',
  city: 'San Diego',
  state: 'California',
  zip_code: '91911',
  billing_and_shipping: true,
)

include Glimmer

Document.ready? do
  div {
    div(style: 'display: grid; grid-auto-columns: 80px 260px;') { |address_div|
      label('Street: ', for: 'street-field')
      input(id: 'street-field') {
        # Bidirectional Data-Binding with <=> ensures input.value and @address.street
        # automatically stay in sync when either side changes
        value <=> [@address, :street]
      }

      label('Street 2: ', for: 'street2-field')
      textarea(id: 'street2-field') {
        value <=> [@address, :street2]
      }

      label('City: ', for: 'city-field')
      input(id: 'city-field') {
        value <=> [@address, :city]
      }

      label('State: ', for: 'state-field')
      select(id: 'state-field') {
        Address::STATES.each do |state_code, state|
          option(value: state_code) { state }
        end

        value <=> [@address, :state_code]
      }

      label('Zip Code: ', for: 'zip-code-field')
      input(id: 'zip-code-field', type: 'number', min: '0', max: '99999') {
        # Bidirectional Data-Binding with <=> ensures input.value and @address.zip_code
        # automatically stay in sync when either side changes
        # on_write option specifies :to_s method to invoke on value before writing to model attribute
        # to ensure the numeric zip code value is stored as a String
        value <=> [@address, :zip_code,
                    on_write: :to_s,
                  ]
      }

      div(style: 'grid-column: 1 / span 2') {
        input(id: 'billing-and-shipping-field', type: 'checkbox') {
          checked <=> [@address, :billing_and_shipping]
        }
        label(for: 'billing-and-shipping-field') {
          'Use this address for both Billing & Shipping'
        }
      }

      # Programmable CSS using Glimmer DSL for CSS
      style {
        # `r` is an alias for `rule`, generating a CSS rule
        r("#{address_div.selector} *") {
          margin '5px'
        }
        r("#{address_div.selector} input, #{address_div.selector} select") {
          grid_column '2'
        }
      }
    }

    div(style: 'margin: 5px') {
      # Unidirectional Data-Binding is done with <= to ensure @address.summary changes
      # automatically update div.inner_text
      # (computed by changes to address attributes, meaning if street changes,
      # @address.summary is automatically recomputed.)
      inner_text <= [@address, :summary,
                      computed_by: @address.members + ['state_code'],
                    ]
    }
  }
end

I just put the STATES back in the main README to avoid confusing users who miss this detail.

zw963 commented 1 month ago

It might be caused by opal-browser. I don't recommend using opal-browser. Everything works for me without opal-browser.

Hi, i test on the full version new data-binding code, although ruby app.rb work now without any error whatever use opal-jquery or opal-browser, but still get error when open index.html.

image

i test on both Firefox/Chrome browser.

One thing to improve in your example is to make it use a Glimmer::Web::Component. For serious app usage, web UI should always be built using Glimmer::Web::Component (and embedded using the glimmer_component helper in a Rails view).

Thanks, I will discover how to use it latter. in fact, what i expected is to use glimmer-dsl-web with lucky, it write web view use Crystal code instead traditional template for speed and safety and support component too.

AndyObtiva commented 1 month ago

II told you to go to the source: https://github.com/AndyObtiva/glimmer-dsl-web/blob/master/lib/glimmer-dsl-web/samples/hello/hello_data_binding.rb

The README version which I shared with you still has issues apparently (I forgot to add the billing_and_shipping attribute given I added it to the source). I need to fix it. Ignore it please given I gave you the source.

The source works 100% in the original Rails Sample App: https://github.com/AndyObtiva/sample-glimmer-dsl-web-rails7-app

When in doubt, go to that sample app and try its code.

Also, in general, do not try extra libraries like opal-browser until you mastered all the basic samples first and got comfortable with Glimmer DSL for Web as is. It is not a good software engineering technique to add more moving pieces until you mastered the basics or else you would be confusing yourself every time an issue occurs as you would not know if it's the extra moving piece (opal-browser) causing the issue or something else. Use good software engineering techniques by starting small and adding extra things only after mastering the basics.

And, if you want my opinion about opal-browser, you do not need opal-browser. I don't recommend it whether it works or not whatsoever. I don't believe it offers any important benefits at all on top of Glimmer DSL for Web.

I understand you would like to use glimmer-dsl-web with Crystal and Lucky, but you would be defeating part of the point of using a Ruby library in the Frontend if you do that, which is matching the language of the backend, assuming Ruby on Rails.

Although I do like Crystal for the purpose of performance optimization of some algorithms only and some large scale processing of data, I do not think Crystal is a good software engineering decision in general in 80-90% of business apps. I would generally use Ruby because it's a lot simpler due to dynamic typing. The compilation benefits of Crystal are overblown and are over-engineering for most business apps. Many new developers fall for the trap of statically typed languages like TypeScript among others. I actually have work experience with statically typed languages for 5-6 years and about 15 years of Ruby on Rails and I know for a fact most business apps don't need the benefits of compilation. Developers would be more productive without the heavy weight of a compiler that adds extra an extra step to building software that is not needed most of the time.

I would only use Crystal for performance optimizations in 1-10% of use cases.

Otherwise, Glimmer DSL for Web eventually is going to do server-side rendering of components in Rails so that you can write your components once and they run on both the backend and frontend. If you use Crystal in the backend, you won't have that benefit, let alone Crystal is over-engineering that slows people down over Ruby in productivity as mentioned above. It is only useful in 1-10% of the performance optimization cases. That said, I know for sure my current employer wouldn't need Crystal at all in 100% of our use-cases.

zw963 commented 1 month ago

Also, in general, do not try extra libraries like opal-browser until you mastered all the basic samples first and got comfortable with Glimmer DSL for Web as is. It is not a good software engineering technique to add more moving pieces until you mastered the basics or else you would be confusing yourself every time an issue occurs as you would not know if it's the extra moving piece (opal-browser) causing the issue or something else. Use good software engineering techniques by starting small and adding extra things only after mastering the basics.

Can't agree more, i revert to use Jquery.

but you would be defeating part of the point of using a Ruby library in the Frontend if you do that, which is matching the language of the backend, assuming Ruby on Rails.

This is acceptable anyway.

After switch to Crystal 2 years, I really don't want to use Ruby to write web server code anymore. you mentioned performance improvement, but on the contrary, although it was the reason attracted me, but it became the least important factor when I started using it, it fixed many design errors in Matz's eyes, the most important reason let me can't leave is type safety, if you have ever used a language like Dart, you know what I am talking about. I used to do very very well in using TDD with Ruby (Or DDD, Data Driven development), but now I write tests lesser, because I am very happy with compiler driven development, no error, robust.

Following is some highlight in Crystal:

Null Safety (as Dart, Swift, Kotlin) make code sound,

Union Type + with the type_inference, make write Crystal almost like write Ruby.

Multiple dispatch allows you to have different versions of a method with the same name,

Concurrent Fiber as golang's goroutine/channel,

Plus the most wonderful compile time macro feature(which possible stolen from lisp), which make many of feature in ruby (method missing, Module.included etc) is possible in Crystal.

The compilation benefits of Crystal are overblown and are over-engineering for most business apps.

This is the first time I have heard this viewpoint, I actually think Ruby made some mistakes at the beginning and has been patching up now, but Crystal fixed most of those issues perfectly from the beginning.

BTW: Like you, @jgaskins is also a senior development in the Opal/Ruby area, but very active in the Crystal community nowadays, maybe we can hear something from him.


EDIT:

I am current write web use htmx, a server-side rendering tech i guess similar to hotwire and Turbo in Rails, but not tightly bound to Rails, this project can as a replacement if need write page more dynamically, e.g. SPA.

AndyObtiva commented 1 month ago

I don't buy the "type safety" benefits either. I worked in type safe languages for 6 years without using Ruby, and after I got used to Ruby on Rails and writing automated tests, I found there is no big need for type safety. After all, even while using type safe languages like Java in the past, I found I still had to write automated tests to ensure business requirement correctness, and those tests always caught type safety issues anyways, including when I write them in Ruby, so it would be more productive to avoid an extra compilation step in software development. That is not just my opinion. I worked for a US company in the past with 55 people who all believed that the benefits of "type safety" are overblown. That's why DHH abandoned TypeScript in favor of JavaScript recently. It's the opinion of other people too not just me.

I appreciate and respect other people's opinions on the matter, but my opinion comes from my deep experience with both type safe and dynamically typed languages. Someone else's opinion won't change mine on this matter given my deep experience with it. What I recommended above (using 99% Ruby and 1% type safe languages for performance optimization only) is what I believe yields the most productiveness in software development.

zw963 commented 1 month ago

I found I still had to write automated tests to ensure business requirement correctness,

Yes, this is true, but write Crystal spec just like old fashion RSpec (???.should ??), it did not lose efficiency (compare to Ruby), on the contrary, many spec don't need anymore because compiler help us a lot.

I worked for a US company in the past with 55 people who all believed that the benefits of "type safety" are overblown. That's why DHH abandoned TypeScript in favor of JavaScript recently. It's the opinion of other people too not just me.

I don't know why DHH make this decision, From my point of view, introduce type in typescript is great idea, maybe other reasons? so i checked a blog, it seem like involved with writing types was creating a bad developer experience for him and his team. but this is not true for Crystal, TS is a dynamic language disguised as a static language, but Crystal is a static language disguised to a dynamic language, you don't need write any type in Crystal if you prefer this(just like Ruby), But beneath the surface, the hidden union types are ten times better than TS. Although I only have a basic understanding of TS, I believe the union types in TypeScripts's is quite primitive ,Crystal's type inference is TOO powerful compare to TS, this is the guarantee of experience, just not like JAVA types is everywhere and I hate it! type safety in JAVA and Crystal is totally different, AFAIK, There are some similar concepts present in Dart, Swift, Kotlin, and Julia, if you have used one of them, of course, TS should be in this list, but as I mentioned before, its very primitive,

Anyway, just like DHH abandoned the Mac and use Ubuntu instead in recent days, i use Linux years, never used a Mac for more than six months, but i still think MBP may be one of the best development laptop ever. It just personal preferences, I never heard of him use Opal either.

Anyway, I don't know if you have used Crystal formally, i feel try it out is a good choice, considering that you are a Ruby expert and expressed your love for Ruby on Twitter, as well as used static language before. :smile: