opal-rails 1.0.1 → 2.0.1
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.
- checksums.yaml +4 -4
- data/.github/workflows/{main.yml → build.yml} +12 -5
- data/.gitignore +1 -0
- data/Appraisals +8 -17
- data/CHANGELOG.md +66 -0
- data/Gemfile +7 -4
- data/README.md +55 -13
- data/app/helpers/opal_helper.rb +6 -5
- data/bin/rackup +29 -0
- data/bin/rails +8 -0
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +18 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/sandbox +39 -0
- data/bin/sandbox-setup +14 -0
- data/bin/setup +8 -0
- data/gemfiles/rails_6_0_opal_1_0.gemfile +0 -3
- data/gemfiles/rails_6_0_opal_1_1.gemfile +9 -0
- data/gemfiles/rails_6_1_opal_1_0.gemfile +9 -0
- data/gemfiles/rails_6_1_opal_1_1.gemfile +9 -0
- data/lib/assets/javascripts/opal_ujs.js.rb +1 -4
- data/lib/generators/opal/assets/assets_generator.rb +7 -0
- data/lib/{rails/generators → generators}/opal/assets/templates/javascript.js.rb +0 -0
- data/lib/generators/opal/install/USAGE +8 -0
- data/lib/generators/opal/install/install_generator.rb +14 -0
- data/lib/generators/opal/install/templates/application.js.rb +12 -0
- data/lib/generators/opal/install/templates/initializer.rb +22 -0
- data/lib/opal/rails.rb +0 -4
- data/lib/opal/rails/engine.rb +9 -2
- data/lib/opal/rails/template_handler.rb +16 -7
- data/lib/opal/rails/version.rb +1 -1
- data/opal-rails.gemspec +45 -40
- data/spec/helpers/opal_helper_spec.rb +23 -9
- data/spec/integration/assigns_spec.rb +58 -2
- data/spec/integration/source_map_spec.rb +9 -5
- data/test_apps/{application_controller.rb → app/application_controller.rb} +1 -1
- data/test_apps/app/assets/config/manifest.js +1 -0
- data/test_apps/{assets → app/assets}/javascripts/application.js.rb +1 -0
- data/test_apps/{assets → app/assets}/javascripts/bar.rb +0 -0
- data/test_apps/{assets → app/assets}/javascripts/foo.js.rb +0 -0
- data/test_apps/{assets → app/assets}/javascripts/source_map_example.js.rb +0 -0
- data/test_apps/{assets → app/assets}/javascripts/with_assignments.js.rb +0 -0
- data/test_apps/rails6.rb +1 -3
- metadata +48 -84
- data/gemfiles/rails_5_1_opal_1_0.gemfile +0 -12
- data/gemfiles/rails_5_1_opal_master.gemfile +0 -11
- data/gemfiles/rails_5_2_opal_1_0.gemfile +0 -12
- data/gemfiles/rails_5_2_opal_master.gemfile +0 -11
- data/gemfiles/rails_6_0_opal_master.gemfile +0 -11
- data/lib/rails/generators/opal/assets/assets_generator.rb +0 -12
- data/spec/integration/template_spec.rb +0 -9
- data/test_apps/rails5.rb +0 -50
data/bin/sandbox
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
gem_name="$(ruby -rpathname -e"puts Pathname(ARGV.first).join('../..').expand_path.glob('*.gemspec').first.basename('.gemspec')" -- $0)"
|
4
|
+
|
5
|
+
# Stay away from the bundler env of the containing extension.
|
6
|
+
function unbundled {
|
7
|
+
ruby -rbundler -e'b = proc {system *ARGV}; Bundler.respond_to?(:with_unbundled_env) ? Bundler.with_unbundled_env(&b) : Bundler.with_clean_env(&b)' -- $@
|
8
|
+
}
|
9
|
+
|
10
|
+
rm -rf ./sandbox
|
11
|
+
unbundled bundle exec rails new sandbox \
|
12
|
+
--skip-bundle \
|
13
|
+
--skip-git \
|
14
|
+
--skip-keeps \
|
15
|
+
--skip-rc \
|
16
|
+
--skip-spring \
|
17
|
+
--skip-test \
|
18
|
+
$@
|
19
|
+
|
20
|
+
if [ ! -d "sandbox" ]; then
|
21
|
+
echo 'sandbox rails application failed'
|
22
|
+
exit 1
|
23
|
+
fi
|
24
|
+
|
25
|
+
cd ./sandbox
|
26
|
+
cat <<RUBY >> Gemfile
|
27
|
+
gem '$gem_name', path: '..'
|
28
|
+
RUBY
|
29
|
+
|
30
|
+
unbundled bundle install --gemfile Gemfile
|
31
|
+
unbundled bin/rails webpacker:install
|
32
|
+
|
33
|
+
|
34
|
+
cd .. # Back to the project root.
|
35
|
+
bin/sandbox-setup # Run any custom setup.
|
36
|
+
|
37
|
+
echo
|
38
|
+
echo "🚀 Sandbox app successfully created for $gem_name!"
|
39
|
+
|
data/bin/sandbox-setup
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
root = Pathname('sandbox')
|
6
|
+
|
7
|
+
system 'bin/rails g opal:install'
|
8
|
+
system 'bin/rails g controller home index -f'
|
9
|
+
|
10
|
+
root.join('config/routes.rb').write <<~RUBY
|
11
|
+
Rails.application.routes.draw do
|
12
|
+
root to: "home#index"
|
13
|
+
end
|
14
|
+
RUBY
|
data/bin/setup
ADDED
@@ -2,11 +2,8 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "c_lexer"
|
6
5
|
gem "rails", "~> 6.0.0"
|
7
6
|
gem "opal", "~> 1.0.0"
|
8
|
-
gem "opal-rspec", git: "https://github.com/opal/opal-rspec.git", branch: :master
|
9
|
-
gem "opal-jquery", git: "https://github.com/opal/opal-jquery.git", branch: :master
|
10
7
|
gem "opal-sprockets"
|
11
8
|
|
12
9
|
gemspec path: "../"
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Opal::InstallGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path('templates', __dir__)
|
3
|
+
|
4
|
+
def configure_sprockets
|
5
|
+
append_to_file 'app/assets/config/manifest.js', '//= link_directory ../javascript .js'
|
6
|
+
template "application.js.rb", "app/assets/javascript/application.js.rb"
|
7
|
+
template "initializer.rb", "config/initializers/opal.rb"
|
8
|
+
|
9
|
+
# Add the javascript tag to the application head tag
|
10
|
+
gsub_file 'app/views/layouts/application.html.erb', %r{(\n *)</head>},
|
11
|
+
'\1 <%= javascript_include_tag "application", "data-turbolinks-track": "reload" %>' \
|
12
|
+
'\1</head>'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "opal"
|
2
|
+
|
3
|
+
# Uncomment the following to print out you're hello-world with Opal:
|
4
|
+
#
|
5
|
+
# puts "hello world!"
|
6
|
+
#
|
7
|
+
# The following will append a hello-world to your <body> element:
|
8
|
+
#
|
9
|
+
# require "native"
|
10
|
+
# $$[:document].addEventListener :DOMContentLoaded do
|
11
|
+
# $$[:document][:body][:innerHTML] += '<h2>Hello World!</h2>'
|
12
|
+
# end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Check out the full list of the available configuration options at
|
2
|
+
# https://github.com/opal/opal/blob/master/lib/opal/config.rb
|
3
|
+
|
4
|
+
Rails.application.configure do
|
5
|
+
# We suggest keeping the configuration above as default for all environments,
|
6
|
+
# disabling some of them might slightly reduce the bundle size or reduce performance
|
7
|
+
# by degrading some ruby features.
|
8
|
+
config.opal.method_missing_enabled = true
|
9
|
+
config.opal.const_missing_enabled = true
|
10
|
+
config.opal.arity_check_enabled = true
|
11
|
+
config.opal.freezing_stubs_enabled = true
|
12
|
+
config.opal.dynamic_require_severity = :ignore
|
13
|
+
|
14
|
+
# To enable passing assigns from the controller to the opal template handler
|
15
|
+
# change the following configuration to one of these values:
|
16
|
+
#
|
17
|
+
# - true # both locals and instance variables
|
18
|
+
# - :locals # only locals
|
19
|
+
# - :ivars # only instance variables
|
20
|
+
#
|
21
|
+
config.opal.assigns_in_templates = false
|
22
|
+
end
|
data/lib/opal/rails.rb
CHANGED
data/lib/opal/rails/engine.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'rails'
|
2
|
-
require 'opal/sprockets
|
3
|
-
require 'opal/sprockets/processor'
|
2
|
+
require 'opal/sprockets'
|
4
3
|
|
5
4
|
module Opal
|
6
5
|
module Rails
|
@@ -12,6 +11,14 @@ module Opal
|
|
12
11
|
config.opal.dynamic_require_severity = :ignore
|
13
12
|
config.opal.assigns_in_templates = true
|
14
13
|
|
14
|
+
def (config.opal).assign_locals_in_templates?
|
15
|
+
assigns_in_templates == true || assigns_in_templates == :locals
|
16
|
+
end
|
17
|
+
|
18
|
+
def (config.opal).assign_instance_variables_in_templates?
|
19
|
+
assigns_in_templates == true || assigns_in_templates == :ivars
|
20
|
+
end
|
21
|
+
|
15
22
|
# Cache eager_load_paths now, otherwise the assets dir is added
|
16
23
|
# and its .rb files are eagerly loaded.
|
17
24
|
config.eager_load_paths
|
@@ -1,22 +1,31 @@
|
|
1
|
+
require 'active_support/json'
|
2
|
+
|
1
3
|
module Opal
|
2
4
|
module Rails
|
3
5
|
class TemplateHandler
|
4
6
|
|
5
|
-
def self.call(template)
|
6
|
-
new.call(template)
|
7
|
+
def self.call(template, source = template.source)
|
8
|
+
new.call(template, source)
|
7
9
|
end
|
8
10
|
|
9
|
-
def call(template)
|
10
|
-
escaped =
|
11
|
+
def call(template, source = template.source)
|
12
|
+
escaped = source.gsub(':', '\:')
|
11
13
|
string = '%q:' + escaped + ':'
|
12
14
|
|
13
15
|
<<-RUBY
|
16
|
+
config = ::Rails.application.config.opal
|
17
|
+
|
14
18
|
code = []
|
15
19
|
code << 'Object.new.instance_eval {'
|
16
|
-
|
17
|
-
|
18
|
-
code << JSON.
|
20
|
+
|
21
|
+
if config.assign_locals_in_templates?
|
22
|
+
code << ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(local_assigns)).map { |key, val| "\#{key} = \#{val.inspect};" }.join
|
19
23
|
end
|
24
|
+
|
25
|
+
if config.assign_instance_variables_in_templates?
|
26
|
+
code << ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(@_assigns)).map { |key, val| "@\#{key} = \#{val.inspect};" }.join
|
27
|
+
end
|
28
|
+
|
20
29
|
code << #{string}
|
21
30
|
code << '}'
|
22
31
|
Opal.compile(code.join("\n"))
|
data/lib/opal/rails/version.rb
CHANGED
data/opal-rails.gemspec
CHANGED
@@ -1,41 +1,46 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
Gem::Specification.new do |
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/opal/rails/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'opal-rails'
|
7
|
+
spec.version = Opal::Rails::VERSION
|
8
|
+
spec.authors = ['Elia Schito']
|
9
|
+
spec.email = ['elia@schito.me']
|
10
|
+
|
11
|
+
spec.summary = %q{Rails bindings for opal JS engine}
|
12
|
+
spec.description = %q{Rails bindings for opal JS engine}
|
13
|
+
spec.homepage = 'https://github.com/opal/opal-rails#readme'
|
14
|
+
spec.license = 'MIT-LICENSE'
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/opal/opal-rails#readme'
|
18
|
+
spec.metadata['changelog_uri'] = 'https://github.com/opal/opal-rails/blob/master/CHANGELOG.md'
|
19
|
+
|
20
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.5')
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
files = Dir.chdir(__dir__) { `git ls-files -z`.split("\x0") }
|
25
|
+
|
26
|
+
spec.files = files.grep_v(%r{^(test|spec|features)/})
|
27
|
+
spec.test_files = files.grep(%r{^(test|spec|features)/})
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
spec.add_dependency 'rails', '>= 6.0', '< 7'
|
33
|
+
spec.add_dependency 'sprockets-rails', '>= 3.0'
|
34
|
+
|
35
|
+
spec.add_dependency 'opal', '~> 1.0'
|
36
|
+
spec.add_dependency 'opal-sprockets', '~> 1.0'
|
37
|
+
|
38
|
+
spec.add_development_dependency 'execjs'
|
39
|
+
spec.add_development_dependency 'launchy'
|
40
|
+
spec.add_development_dependency 'capybara', '~> 3.25'
|
41
|
+
spec.add_development_dependency 'apparition'
|
42
|
+
spec.add_development_dependency 'rspec-rails'
|
43
|
+
spec.add_development_dependency 'appraisal', '~> 2.1'
|
44
|
+
spec.add_development_dependency 'sqlite3'
|
45
|
+
spec.add_development_dependency 'puma'
|
41
46
|
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
# We need the view type because helpers specs are to are too minimalistic
|
4
|
+
# and are missing some initialization stuff.
|
5
|
+
describe OpalHelper, :js, type: :view do
|
6
|
+
let(:helper) { view }
|
5
7
|
|
6
8
|
describe '#opal_tag' do
|
7
9
|
it 'compiles to js' do
|
@@ -20,17 +22,29 @@ describe OpalHelper, type: :helper do
|
|
20
22
|
# sprockets-rails v3 sets Rails.application.assets to nil in production mode
|
21
23
|
allow(Rails.application).to receive(:assets).and_return(nil)
|
22
24
|
|
23
|
-
loading_code =
|
25
|
+
loading_code = [
|
26
|
+
%<if(window.Opal && Opal.modules["application"]){Opal.loaded(typeof(OpalLoaded) === "undefined" ? [] : OpalLoaded);>,
|
27
|
+
%<Opal.require("application");}>,
|
28
|
+
].join("\n")
|
29
|
+
|
24
30
|
escaped_loading_code = ERB::Util.h loading_code
|
31
|
+
loading_code_in_script_tag = [
|
32
|
+
%(<script>), %(//<![CDATA[), loading_code, %(//]]>), %(</script>),
|
33
|
+
].join("\n")
|
34
|
+
|
35
|
+
expect(helper.javascript_include_tag('application', debug: true)).to include(loading_code_in_script_tag)
|
36
|
+
expect(helper.javascript_include_tag('application', debug: true)).not_to include(escaped_loading_code)
|
25
37
|
|
26
|
-
expect(helper.javascript_include_tag('application', debug: true)).to include(escaped_loading_code)
|
27
38
|
expect(helper.javascript_include_tag('application', debug: false)).to include(escaped_loading_code)
|
39
|
+
expect(helper.javascript_include_tag('application', debug: false)).not_to include(loading_code_in_script_tag)
|
40
|
+
|
28
41
|
expect(helper.javascript_include_tag('application', skip_opal_loader: true)).not_to include(escaped_loading_code)
|
29
|
-
expect(helper.javascript_include_tag('application', skip_opal_loader:
|
42
|
+
expect(helper.javascript_include_tag('application', skip_opal_loader: false)).to include(loading_code_in_script_tag)
|
43
|
+
|
44
|
+
expect(helper.javascript_include_tag('application', force_opal_loader_tag: true, debug: true)).to include(loading_code_in_script_tag)
|
45
|
+
expect(helper.javascript_include_tag('application', force_opal_loader_tag: true, debug: false)).to include(loading_code_in_script_tag)
|
30
46
|
|
31
|
-
expect(helper.javascript_include_tag('application', force_opal_loader_tag: true,
|
32
|
-
expect(helper.javascript_include_tag('application', force_opal_loader_tag: true,
|
33
|
-
expect(helper.javascript_include_tag('application', force_opal_loader_tag: true, skip_opal_loader: true)).not_to include(loading_code)
|
34
|
-
expect(helper.javascript_include_tag('application', force_opal_loader_tag: true, skip_opal_loader: true)).not_to include(loading_code)
|
47
|
+
expect(helper.javascript_include_tag('application', force_opal_loader_tag: true, skip_opal_loader: true)).not_to include(escaped_loading_code)
|
48
|
+
expect(helper.javascript_include_tag('application', force_opal_loader_tag: true, skip_opal_loader: true)).to include(loading_code_in_script_tag)
|
35
49
|
end
|
36
50
|
end
|
@@ -7,7 +7,7 @@ describe 'controller assignments' do
|
|
7
7
|
Rails.application.config.opal.assigns_in_templates = true
|
8
8
|
end
|
9
9
|
|
10
|
-
it '
|
10
|
+
it 'has them in the template' do
|
11
11
|
source = get_source_of '/application/with_assignments.js'
|
12
12
|
assignments = opal_eval(source)
|
13
13
|
|
@@ -29,7 +29,7 @@ describe 'controller assignments' do
|
|
29
29
|
Rails.application.config.opal.assigns_in_templates = false
|
30
30
|
end
|
31
31
|
|
32
|
-
it '
|
32
|
+
it 'has not them in the template' do
|
33
33
|
source = get_source_of '/application/with_assignments.js'
|
34
34
|
assignments = opal_eval(source)
|
35
35
|
{
|
@@ -45,6 +45,62 @@ describe 'controller assignments' do
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
context 'when :locals' do
|
49
|
+
before do
|
50
|
+
Rails.application.config.opal.assigns_in_templates = :locals
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'has only locals in the template' do
|
54
|
+
source = get_source_of '/application/with_assignments.js'
|
55
|
+
assignments = opal_eval(source)
|
56
|
+
{
|
57
|
+
:number_var => 1234,
|
58
|
+
:string_var => 'hello',
|
59
|
+
:array_var => [1,'a'],
|
60
|
+
:hash_var => {:a => 1, :b => 2},
|
61
|
+
:object_var => {:contents => 'json representation'},
|
62
|
+
}.each_pair do |ivar, assignment|
|
63
|
+
expect(assignments[ivar]).not_to eq(assignment)
|
64
|
+
end
|
65
|
+
{
|
66
|
+
:local_var => 'i am local',
|
67
|
+
}.each_pair do |ivar, assignment|
|
68
|
+
expect(assignments[ivar]).to eq(assignment)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when :ivars' do
|
74
|
+
before do
|
75
|
+
Rails.application.config.opal.assigns_in_templates = :ivars
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'has only ivars in the template' do
|
79
|
+
source = get_source_of '/application/with_assignments.js'
|
80
|
+
assignments = opal_eval(source)
|
81
|
+
{
|
82
|
+
:number_var => 1234,
|
83
|
+
:string_var => 'hello',
|
84
|
+
:array_var => [1,'a'],
|
85
|
+
:hash_var => {:a => 1, :b => 2},
|
86
|
+
:object_var => {:contents => 'json representation'},
|
87
|
+
}.each_pair do |ivar, assignment|
|
88
|
+
expect(assignments[ivar]).to eq(assignment)
|
89
|
+
end
|
90
|
+
{
|
91
|
+
:local_var => 'i am local',
|
92
|
+
}.each_pair do |ivar, assignment|
|
93
|
+
expect(assignments[ivar]).not_to eq(assignment)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'has the correct content type' do
|
99
|
+
get '/application/with_assignments.js'
|
100
|
+
expect(response).to be_successful
|
101
|
+
expect(response.headers['Content-Type']).to eq('text/javascript; charset=utf-8')
|
102
|
+
end
|
103
|
+
|
48
104
|
def get_source_of path
|
49
105
|
get path
|
50
106
|
response.should be_successful
|