ruby2js 4.0.1 → 4.1.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -1
  3. data/lib/ruby2js.rb +13 -2
  4. data/lib/ruby2js/converter.rb +31 -0
  5. data/lib/ruby2js/converter/args.rb +1 -1
  6. data/lib/ruby2js/converter/class.rb +6 -4
  7. data/lib/ruby2js/converter/class2.rb +4 -4
  8. data/lib/ruby2js/converter/def.rb +7 -1
  9. data/lib/ruby2js/converter/dstr.rb +3 -1
  10. data/lib/ruby2js/converter/for.rb +1 -1
  11. data/lib/ruby2js/converter/next.rb +10 -2
  12. data/lib/ruby2js/converter/redo.rb +14 -0
  13. data/lib/ruby2js/converter/return.rb +1 -1
  14. data/lib/ruby2js/converter/send.rb +1 -0
  15. data/lib/ruby2js/converter/taglit.rb +9 -2
  16. data/lib/ruby2js/converter/while.rb +1 -1
  17. data/lib/ruby2js/converter/whilepost.rb +1 -1
  18. data/lib/ruby2js/filter/functions.rb +44 -9
  19. data/lib/ruby2js/filter/lit-element.rb +202 -0
  20. data/lib/ruby2js/filter/react.rb +155 -91
  21. data/lib/ruby2js/filter/stimulus.rb +4 -2
  22. data/lib/ruby2js/filter/tagged_templates.rb +4 -2
  23. data/lib/ruby2js/rails.rb +6 -59
  24. data/lib/ruby2js/serializer.rb +16 -11
  25. data/lib/ruby2js/sprockets.rb +40 -0
  26. data/lib/ruby2js/version.rb +2 -2
  27. data/lib/tasks/README.md +4 -0
  28. data/lib/tasks/install/app/javascript/elements/index.js +2 -0
  29. data/lib/tasks/install/config/webpack/loaders/ruby2js.js +20 -0
  30. data/lib/tasks/install/litelement.rb +9 -0
  31. data/lib/tasks/install/preact.rb +3 -0
  32. data/lib/tasks/install/react.rb +2 -0
  33. data/lib/tasks/install/stimulus-sprockets.rb +32 -0
  34. data/lib/tasks/install/stimulus-webpacker.rb +5 -0
  35. data/lib/tasks/install/webpacker.rb +80 -0
  36. data/lib/tasks/nodetest.js +47 -0
  37. data/lib/tasks/ruby2js_tasks.rake +47 -0
  38. data/ruby2js.gemspec +1 -1
  39. metadata +18 -4
@@ -51,8 +51,10 @@ module Ruby2JS
51
51
  @stim_classes = Set.new
52
52
  stim_walk(node)
53
53
 
54
- prepend_list << (@options[:import_from_skypack] ?
55
- STIMULUS_IMPORT_SKYPACK : STIMULUS_IMPORT)
54
+ if modules_enabled?
55
+ prepend_list << (@options[:import_from_skypack] ?
56
+ STIMULUS_IMPORT_SKYPACK : STIMULUS_IMPORT)
57
+ end
56
58
 
57
59
  nodes = body
58
60
  if nodes.length == 1 and nodes.first&.type == :begin
@@ -15,17 +15,19 @@ module Ruby2JS
15
15
 
16
16
  tagged_methods = @options[:template_literal_tags] || [:html, :css]
17
17
 
18
- if tagged_methods.include?(method) && !args.empty?
18
+ if tagged_methods.include?(method) && args.length == 1
19
19
  strnode = process args.first
20
20
  if strnode.type == :str
21
21
  # convert regular strings to literal strings
22
22
  strnode = strnode.updated(:dstr, [s(:str, strnode.children.first.chomp("\n"))])
23
- else
23
+ elsif strnode.type == :dstr
24
24
  # for literal strings, chomp a newline off the end
25
25
  if strnode.children.last.type == :str && strnode.children.last.children[0].end_with?("\n")
26
26
  children = [*strnode.children.take(strnode.children.length - 1), s(:str, strnode.children.last.children[0].chomp)]
27
27
  strnode = s(:dstr, *children)
28
28
  end
29
+ else
30
+ return super
29
31
  end
30
32
 
31
33
  S(:taglit, s(:sym, method), strnode)
data/lib/ruby2js/rails.rb CHANGED
@@ -1,63 +1,10 @@
1
- # Example usage:
2
- #
3
- # $ echo "gem 'ruby2js', require: 'ruby2js/rails'" >> Gemfile
4
- # $ bundle update
5
- # $ rails generate controller Say hello
6
- # $ echo 'alert "Hello world!"' > app/views/say/hello.js.rb
7
- # $ rails server
8
- # $ curl http://localhost:3000/say/hello.js
9
- #
10
- # Using an optional filter:
11
- #
12
- # $ echo 'require "ruby2js/filter/functions"' > config/initializers/ruby2js.rb
13
- #
14
- # Asset Pipeline:
15
- #
16
- # Ruby2JS registers ".rb.js" extension.
17
- # You can add "ruby_thing.js.rb" to your app/javascript folder
18
- # and '= require ruby_thing' from other js sources.
19
- #
20
- # (options are not yet supported, but by requiring the appropriate files
21
- # as shown above, you can configure proejct wide.)
22
- require 'ruby2js'
1
+ require 'rails'
2
+ require_relative './sprockets'
23
3
 
24
- module Ruby2JS
25
- module Rails
26
- class Template
27
- cattr_accessor :default_format
28
- self.default_format = Mime[:js]
29
- def self.call(template, source)
30
- "Ruby2JS.convert(#{template.source.inspect}, file: source).to_s"
31
- end
4
+ class Ruby2JSRailtie < Rails::Railtie
5
+ rake_tasks do
6
+ Dir[File.expand_path('../tasks/*.rake', __dir__)].each do |file|
7
+ load file
32
8
  end
33
-
34
- ActiveSupport.on_load(:action_view) do
35
- ActionView::Template.register_template_handler :rb, Template
36
- end
37
-
38
- class SprocketProcessor
39
- def initialize(file = nil)
40
- @file = file
41
- end
42
- def render(context , _)
43
- context = context.instance_eval { binding } unless context.is_a? Binding
44
- Ruby2JS.convert(File.read(@file), binding: context).to_s
45
- end
46
- end
47
-
48
- class Engine < ::Rails::Engine
49
- engine_name "ruby2js"
50
-
51
- config.app_generators.javascripts true
52
- config.app_generators.javascript_engine :rb
53
-
54
- config.assets.configure do |env|
55
- env.register_mime_type 'text/ruby', extensions: ['.js.rb', '.rb']
56
- env.register_transformer 'text/ruby', 'text/javascript', SprocketProcessor
57
- env.register_preprocessor 'text/javascript', SprocketProcessor
58
- end
59
- end
60
-
61
9
  end
62
-
63
10
  end
@@ -303,11 +303,11 @@ module Ruby2JS
303
303
  def vlq(*mark)
304
304
  if @mark[0] == mark[0]
305
305
  return if @mark[-3..-1] == mark[-3..-1]
306
- @mappings << ',' unless @mappings == ''
306
+ @mappings += ',' unless @mappings == ''
307
307
  end
308
308
 
309
309
  while @mark[0] < mark[0]
310
- @mappings << ';'
310
+ @mappings += ';'
311
311
  @mark[0] += 1
312
312
  @mark[1] = 0
313
313
  end
@@ -322,16 +322,21 @@ module Ruby2JS
322
322
  data = diff << 1
323
323
  end
324
324
 
325
- encoded = ''
326
-
327
- begin
328
- digit = data & 0b11111
329
- data >>= 5
330
- digit |= 0b100000 if data > 0
331
- encoded << BASE64[digit]
332
- end while data > 0
325
+ if data <= 0b11111
326
+ # workaround https://github.com/opal/opal/issues/575
327
+ encoded = BASE64[data]
328
+ else
329
+ encoded = ''
330
+
331
+ begin
332
+ digit = data & 0b11111
333
+ data >>= 5
334
+ digit |= 0b100000 if data > 0
335
+ encoded += BASE64[digit]
336
+ end while data > 0
337
+ end
333
338
 
334
- @mappings << encoded
339
+ @mappings += encoded
335
340
  end
336
341
  end
337
342
 
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/source_map_utils'
3
+ require 'ruby2js'
4
+ require 'ruby2js/version'
5
+
6
+ module Ruby2JS
7
+ module SprocketsTransformer
8
+ include Sprockets
9
+ VERSION = '1'
10
+
11
+ @@options = {}
12
+
13
+ def self.options=(options)
14
+ @@options = options
15
+ end
16
+
17
+ def self.cache_key
18
+ @cache_key ||= "#{name}:#{Ruby2JS::VERSION::STRING}:#{VERSION}".freeze
19
+ end
20
+
21
+ def self.call(input)
22
+ data = input[:data]
23
+
24
+ js, map = input[:cache].fetch([self.cache_key, data]) do
25
+ result = Ruby2JS.convert(data, {**@@options, file: input[:filename]})
26
+ [result.to_s, result.sourcemap.transform_keys {|key| key.to_s}]
27
+ end
28
+
29
+ map = SourceMapUtils.format_source_map(map, input)
30
+ map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
31
+
32
+ { data: js, map: map }
33
+ end
34
+ end
35
+ end
36
+
37
+ Sprockets.register_mime_type 'application/ruby', extensions: ['.rb', '.js.rb']
38
+
39
+ Sprockets.register_transformer 'application/ruby', 'application/javascript',
40
+ Ruby2JS::SprocketsTransformer
@@ -1,8 +1,8 @@
1
1
  module Ruby2JS
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 4
4
- MINOR = 0
5
- TINY = 1
4
+ MINOR = 1
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -0,0 +1,4 @@
1
+ This directory contains rails install tasks and a test program which will run
2
+ the rails examples from the docs/src/_examples/rails directory.
3
+
4
+ run `./testrails.rb` for usage instructions.
@@ -0,0 +1,2 @@
1
+ function importAll(r) { r.keys().forEach(r) }
2
+ importAll(require.context("elements", true, /_elements?\.js(\.rb)?$/))
@@ -0,0 +1,20 @@
1
+ const { environment } = require('@rails/webpacker')
2
+
3
+ module.exports = {
4
+ test: /\.js\.rb$/,
5
+ use: [
6
+ {
7
+ loader: "babel-loader",
8
+ options: environment.loaders.get('babel').use[0].options
9
+ },
10
+
11
+ {
12
+ loader: "@ruby2js/webpack-loader",
13
+ options: {
14
+ autoexports: "default",
15
+ eslevel: 2021,
16
+ filters: ["esm", "functions"]
17
+ }
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,9 @@
1
+ @ruby2js_options = {filters: ['lit-element']}
2
+ @yarn_add='lit-element'
3
+ eval IO.read "#{__dir__}/webpacker.rb"
4
+
5
+ directory File.expand_path("app/javascript/elements", __dir__),
6
+ Rails.root.join('app/javascript/elements').to_s
7
+
8
+ append_to_file Rails.root.join('app/javascript/packs/application.js').to_s,
9
+ "\nimport 'elements'\n"
@@ -0,0 +1,3 @@
1
+ @ruby2js_options = {filters: ['react']}
2
+ @yarn_add='preact'
3
+ eval IO.read "#{__dir__}/webpacker.rb"
@@ -0,0 +1,2 @@
1
+ @ruby2js_options = {filters: ['react']}
2
+ eval IO.read "#{__dir__}/webpacker.rb"
@@ -0,0 +1,32 @@
1
+ create_file Rails.root.join('config/initializers/ruby2js.rb').to_s,
2
+ <<~CONFIG
3
+ require 'ruby2js/filter/esm'
4
+ require 'ruby2js/filter/functions'
5
+ require 'ruby2js/filter/stimulus'
6
+
7
+ Ruby2JS::SprocketsTransformer.options = {
8
+ autoexports: :default,
9
+ eslevel: 2020
10
+ }
11
+
12
+ require 'stimulus/importmap_helper'
13
+
14
+ module Stimulus::ImportmapHelper
15
+ def find_javascript_files_in_tree(path)
16
+ exts = {'.js' => '.js', '.jsm' => '.jsm'}.merge(
17
+ Sprockets.mime_exts.map {|key, value|
18
+ next unless Sprockets.transformers[value]["application/javascript"]
19
+ [key, '.js']
20
+ }.compact.to_h)
21
+
22
+ Dir[path.join('**/*')].map {|file|
23
+ file_ext, web_ext = Sprockets::PathUtils.match_path_extname(file, exts)
24
+ next unless file_ext
25
+
26
+ next unless File.file? file
27
+
28
+ Pathname.new(file.chomp(file_ext) + web_ext)
29
+ }.compact
30
+ end
31
+ end
32
+ CONFIG
@@ -0,0 +1,5 @@
1
+ @ruby2js_options = {filters: ['stimulus'], eslevel: 2022}
2
+ eval IO.read "#{__dir__}/webpacker.rb"
3
+
4
+ insert_into_file Rails.root.join("app/javascript/controllers/index.js").to_s,
5
+ '(\\.rb)?', after: '_controller\\.js'
@@ -0,0 +1,80 @@
1
+ #
2
+ # These instructions can be used standalone or in combination with other
3
+ # instructions.
4
+ #
5
+ # If used standalone on a repository which did not previously have the Ruby2JS
6
+ # webpack loader configured, it will add the '.js.rb' extension to
7
+ # `config/webpacker.yml`, install the Ruby2JS webpack-loader and add a minimal
8
+ # configuration which runs the Ruby2JS webpack loader then the babel loader to
9
+ # `config/webpacker.yml`.
10
+ #
11
+ # Other instructions can require these instructions. If they set the
12
+ # @ruby2js_options instance variable before they do so, the options provided
13
+ # will be merged and/or override the ones in the base configuration.
14
+ #
15
+ # If these instructions are run against a Rails application that was
16
+ # previously configured, the @ruby2js_options provided, if any, will be merged
17
+ # with the options found in the configuration.
18
+ #
19
+
20
+ # default options
21
+ options = @ruby2js_options || {}
22
+
23
+ # define .js.rb as a extension to webpacker
24
+ insert_into_file Rails.root.join("config/webpacker.yml").to_s,
25
+ " - .js.rb\n", after: "\n - .js\n"
26
+
27
+ # install webpack loader
28
+ run "yarn add @ruby2js/webpack-loader #{@yarn_add}"
29
+
30
+ target = Rails.root.join("config/webpack/loaders/ruby2js.js").to_s
31
+
32
+ # default config
33
+ if not File.exist? target
34
+ # may be called via eval, or directly. Resolve source either way.
35
+ source_paths.unshift __dir__
36
+ source_paths.unshift File.dirname(caller.first)
37
+ directory "config/webpack/loaders", File.dirname(target)
38
+ end
39
+
40
+ # load config
41
+ insert_into_file Rails.root.join("config/webpack/environment.js").to_s,
42
+ "environment.loaders.prepend('ruby2js', require('./loaders/ruby2js'))\n"
43
+
44
+ # read current configuration
45
+ before = IO.read(target)
46
+
47
+ # extract indentation and options
48
+ match = /^(\s*)options: (\{.*?\n\1\})/m.match(before)
49
+
50
+ # evaluate base options. Here it is handy that Ruby's syntax for hashes is
51
+ # fairly close to JavaScript's object literals. May run into problems in the
52
+ # future if there ever is a need for {"x": y} as that would need to be
53
+ # {"x" => y} in Ruby.
54
+ base = eval(match[2])
55
+
56
+ # Merge the options, initially having the new options override the original
57
+ # options.
58
+ merged = base.merge(options)
59
+
60
+ # Intelligently combine options if they are the same type.
61
+ options.keys.each do |key|
62
+ next unless base[key]
63
+
64
+ if options[key].is_a? Array and base[key].is_a? Array
65
+ merged[key] = (base[key] + options[key]).uniq
66
+ elsif options[key].is_a? Numeric and base[key].is_a? Numeric
67
+ merged[key] = [base[key], options[key]].max
68
+ elsif options[key].is_a? Hash and base[key].is_a? Hash
69
+ merged[key] = base[key].merge(options[key])
70
+ end
71
+ end
72
+
73
+ # Serialize options as JavaScript, matching original indentation.
74
+ replacement = Ruby2JS.convert(merged.inspect + "\n").to_s.
75
+ gsub(/^/, match[1]).strip
76
+
77
+ # Update configuration
78
+ unless before.include? replacement
79
+ gsub_file target, match[2].to_s, replacement
80
+ end
@@ -0,0 +1,47 @@
1
+ // minimal sanity test to verify usage of Ruby2JS under Node
2
+
3
+ const assert = require('assert');
4
+
5
+ const Ruby2JS = require('@ruby2js/ruby2js');
6
+ // const Ruby2JS =
7
+ // require('/home/rubys/git/ruby2js/docs/src/demo/ruby2js.js');
8
+
9
+ function to_js(string, options={}) {
10
+ return Ruby2JS.convert(string, options).toString()
11
+ }
12
+
13
+ assert.strictEqual(
14
+ to_js('foo = 1'),
15
+ 'var foo = 1');
16
+
17
+ assert.strictEqual(
18
+ to_js('foo = 1', {eslevel: 2015}),
19
+ 'let foo = 1');
20
+
21
+ assert.strictEqual(
22
+ to_js('foo.empty?', {filters: ['functions']}),
23
+ 'foo.length == 0');
24
+
25
+ let ast = Ruby2JS.convert('String', {file: 'a.rb'}).ast
26
+ assert.strictEqual(ast.constructor, Ruby2JS.AST.Node)
27
+ assert.strictEqual(ast.type, "const")
28
+ assert.strictEqual(ast.children.length, 2)
29
+ assert.strictEqual(ast.children[0], Ruby2JS.nil)
30
+ assert.strictEqual(ast.children[1], "String")
31
+
32
+ let sourcemap = Ruby2JS.convert('a=1', {file: 'a.rb'}).sourcemap
33
+ assert.strictEqual(sourcemap.version, 3)
34
+ assert.strictEqual(sourcemap.file, 'a.rb')
35
+ assert.strictEqual(sourcemap.sources.length, 1)
36
+ assert.strictEqual(sourcemap.sources[0], 'a.rb')
37
+ assert.strictEqual(sourcemap.mappings, 'QAAE')
38
+
39
+ console.log(to_js(`
40
+ class C < LitElement
41
+ def render
42
+ x.empty?
43
+ '<h1>title</h1>'
44
+ end
45
+ end
46
+
47
+ `, {eslevel: 2020, filters: ['lit-element', 'esm', 'functions']}))
@@ -0,0 +1,47 @@
1
+ Thor::Actions::WARNINGS[:unchanged_no_flag] = 'unchanged'
2
+
3
+ def template(location)
4
+ system "#{RbConfig.ruby} #{Rails.root.join("bin")}/rails app:template " +
5
+ "LOCATION=#{File.expand_path(location, __dir__)}"
6
+ end
7
+
8
+ namespace :ruby2js do
9
+ namespace :install do
10
+ desc "Install Ruby2JS with LitElement support"
11
+ task :litelement do
12
+ template 'install/litelement.rb'
13
+ end
14
+
15
+ desc "Install Ruby2JS with Preact support"
16
+ task :preact do
17
+ template 'install/preact.rb'
18
+ end
19
+
20
+ desc "Install Ruby2JS with React support"
21
+ task :react do
22
+ template 'install/react.rb'
23
+ Rake::Task['webpacker:install:react'].invoke
24
+ end
25
+
26
+ namespace :stimulus do
27
+ desc "Install Ruby2JS with Stimulus Sprockets support"
28
+ task :sprockets => :"stimulus:install:asset_pipeline" do
29
+ template 'install/stimulus-sprockets.rb'
30
+ end
31
+
32
+ desc "Install Ruby2JS with Stimulus Webpacker support"
33
+ task :webpacker => :"stimulus:install" do
34
+ template 'install/stimulus-webpacker.rb'
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ namespace :webpacker do
41
+ namespace :install do
42
+ desc "Install everything needed for Ruby2JS"
43
+ task :ruby2js do
44
+ template 'install/webpacker.rb'
45
+ end
46
+ end
47
+ end