roda-sprockets 1.0.1 → 1.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +32 -0
  3. data/.gitignore +2 -1
  4. data/.rspec +1 -0
  5. data/CHANGELOG.md +22 -0
  6. data/Gemfile +13 -0
  7. data/LICENSE.txt +1 -1
  8. data/README.md +43 -11
  9. data/Rakefile +4 -0
  10. data/examples/opal-doc/Gemfile +6 -0
  11. data/examples/opal-doc/README.md +4 -0
  12. data/examples/opal-doc/Rakefile +6 -0
  13. data/examples/opal-doc/app.rb +26 -0
  14. data/examples/opal-doc/app/application.rb +3 -0
  15. data/examples/opal-doc/config.ru +3 -0
  16. data/examples/opal-exception/Gemfile +7 -0
  17. data/examples/opal-exception/README.md +1 -0
  18. data/examples/opal-exception/Rakefile +6 -0
  19. data/examples/opal-exception/app.rb +26 -0
  20. data/examples/opal-exception/app/application.rb +16 -0
  21. data/examples/opal-exception/config.ru +3 -0
  22. data/examples/sass/Gemfile +6 -0
  23. data/examples/sass/Rakefile +6 -0
  24. data/examples/sass/app.rb +24 -0
  25. data/examples/sass/assets/css/application.scss +3 -0
  26. data/examples/sass/config.ru +3 -0
  27. data/lib/roda/plugins/sprockets.rb +17 -16
  28. data/lib/roda/plugins/sprockets_task.rb +34 -6
  29. data/roda-sprockets.gemspec +1 -1
  30. data/spec/assets/css/scss_css.scss +7 -0
  31. data/spec/assets/css/scss_css_with_erb.scss.erb +13 -0
  32. data/spec/assets/css/scss_css_with_imports.scss +1 -0
  33. data/spec/assets/css/simple_css.css +1 -0
  34. data/spec/assets/js/opal_js.rb +4 -0
  35. data/spec/assets/js/opal_js_with_erb.rb.erb +10 -0
  36. data/spec/assets/js/opal_js_with_requires.rb +1 -0
  37. data/spec/assets/js/simple_js.js +1 -0
  38. data/spec/examples_spec.rb +132 -0
  39. data/spec/plugin_spec.rb +237 -0
  40. data/spec/server_helper.rb +68 -0
  41. data/spec/spec_helper.rb +59 -0
  42. metadata +51 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 206ac0ccb23a8c14334933207d7b4c05d9d1800cdfdfa60363baad72475eda25
4
- data.tar.gz: 611361f41adbc1ede9f5bed7745d4ba279be8752ec5d5e3ef6334ba1ab61c4a2
3
+ metadata.gz: 3c5624471b78bed45e3ad30586950ddd71710008d5f2b7831d418d08eea65390
4
+ data.tar.gz: d231ec5e75c74f884cfef8cb37f565480b982bb6a3cd7249269b4e2a81618425
5
5
  SHA512:
6
- metadata.gz: fc69e2766b243deda0b241d7370b92eb1060b42fc9b5b1f9c21743ec67e2bcb658ee1b25835f02b0d0798bd2c6c77094f38ba049ce1bfeca9f0f26b7d37deab0
7
- data.tar.gz: 3ce5844c80721baee05d8642a4a1bc4eedcf0241ab3537061f1d7e7297d356335fa0a3d9d02472c7b56a119ef442c8d94d579faed04aba4e589990c0ea898f56
6
+ metadata.gz: 49f8d649e83eca62de5464f7be4ce388284204fb9a1664ed44efdb9e91f7b97185cfc590369e0cc9e8aaa3a7056bc6c0439754303511f206e0db75821ab95d66
7
+ data.tar.gz: 4fd782e737b76b53aa090c6d5ade85028d83c662a420ed201f4ab0a81bed75ac64186af9f7ce62af9ea0d92cdb8f6454fee4cde25cce5b167646be54f3a3e936
@@ -0,0 +1,32 @@
1
+ name: rake
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ - "*-stable"
8
+ - "*/ci-check"
9
+ pull_request: {}
10
+
11
+ jobs:
12
+ rspec:
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby-version: ['2.6', '2.7', '3.0']
17
+ os: ['ubuntu-latest', 'windows-latest', 'macos-latest']
18
+
19
+ runs-on: ${{ matrix.os }}
20
+
21
+ env:
22
+ CI: 'true'
23
+
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31
+ - name: Run tests
32
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -1,12 +1,13 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
- /Gemfile.lock
3
+ Gemfile.lock
4
4
  /_yardoc/
5
5
  /coverage/
6
6
  /doc/
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ /vendor/
10
11
  *.bundle
11
12
  *.so
12
13
  *.o
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ v1.1.0
2
+
3
+ - Fix the Rack::Lint issue (#1)
4
+ - :public_path argument to receive a default value (#7)
5
+ - Roda::RodaPlugins::Sprockets::Task to superclass SprocketsTask (#6)
6
+ - The debug logic now depends on :debug argument, not environment (#4)
7
+
8
+ v1.0.2
9
+
10
+ - :root argument to select a default argument more robustly (#2)
11
+
12
+ v1.0.1
13
+
14
+ - New :cache argument to plugin configuration
15
+
16
+ v1.0.0
17
+
18
+ - Sprockets 4.0 support
19
+
20
+ v0.0.11
21
+
22
+ - Support polyinstantiation, improve Opal support
data/Gemfile CHANGED
@@ -2,3 +2,16 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in roda-sprocket_assets.gemspec
4
4
  gemspec
5
+
6
+ # For rspec:
7
+ gem "rspec"
8
+ gem "opal"
9
+ gem "opal-sprockets"
10
+ gem "sassc"
11
+ gem "uglifier"
12
+ # Until janbiedermann's Windows paths patch is released, we are using git ref:
13
+ # https://github.com/rubycdp/ferrum/commit/5beca76588d1544026eb8b8ee841f305803c67e5
14
+ # Also, my patch that captures stacktraces should be merged:
15
+ # https://github.com/hmdne/ferrum/commit/fbc74b7ca7b670d29cc53a2d779470a05c60ef9d
16
+ gem "ferrum", github: "hmdne/ferrum", ref: "capture-stacktrace"
17
+ gem "puma"
data/LICENSE.txt CHANGED
@@ -1,5 +1,5 @@
1
1
  Copyright (c) 2015 cj
2
- Copyright (c) 2020 hmdne
2
+ Copyright (c) 2020-2021 hmdne and opal-sprockets contributors
3
3
 
4
4
  MIT License
5
5
 
data/README.md CHANGED
@@ -22,7 +22,6 @@ And then execute:
22
22
  ```ruby
23
23
  class App < Roda
24
24
  plugin :sprockets, precompile: %w(site.js site.css),
25
- public_path: 'public/',
26
25
  opal: true,
27
26
  debug: true
28
27
  plugin :public
@@ -30,19 +29,28 @@ class App < Roda
30
29
  route do |r|
31
30
  r.public
32
31
  r.sprockets
33
- end
32
+ end
34
33
  end
35
34
  ```
36
35
 
37
36
  ### Parameters for the plugin:
38
37
 
39
38
  * `precompile` - an array of files that you want to precompile
40
- * `prefix` (relative to the `root`, which is `app.opts[:root]` by default,
41
- but also supports absolute paths) - an array of directories where your
42
- assets are located, by default: `%w(assets vendor/assets)`.
43
- * `root` - a filesystem root directory of your app. By default, `app.opts[:root]`.
44
- * `public_path` - filesystem path to your `public` directory, for all your
45
- precompilation needs. (REQUIRED)
39
+ * `prefix` (relative to the `root`, which is `app.opts[:root]` by default) -
40
+ an array of directories where your assets are located, by default:
41
+ `%w(assets vendor/assets)`.
42
+ * Here, an element of the array can be an absolute path instead of relative.
43
+ * If an element ends with `/`, it will use assets directly in a given
44
+ subdirectory.
45
+ * If it doesn't end with `/` (which is by default) if will be equivalent to
46
+ `value/*`, which means, that assets will be loaded for instance from
47
+ `assets/javascripts` and `assets/stylesheets`, but not directly from `assets`.
48
+ * An element can contain glob characters.
49
+ * `root` - a filesystem root directory of your app. By default, same as
50
+ `app.opts[:root]`, that is: `Dir.pwd`.
51
+ * `public_path` - filesystem path to a place, where precompiled assets will be
52
+ stored, by default: `public/assets` (it should be a directory from which `:public`
53
+ plugin takes files + `path_prefix`)
46
54
  * `path_prefix` - a Roda prefix of your assets directory. By default: `/assets`
47
55
  * `protocol` - either :http (default) or :https.
48
56
  * `css_compressor`, `js_compressor` - pick a compressor of your choice.
@@ -50,7 +58,7 @@ end
50
58
  * `digest` (bool) - digest your assets for unique filenames, default: true
51
59
  * `opal` (bool) - Opal support, default: false
52
60
  * `debug` (bool) - debug mode, default: false
53
- * `cache` - a `Sprockets::Cache` instance
61
+ * `cache` - a `Sprockets::Cache` instance, default: nil (no cache)
54
62
 
55
63
  ### Templates:
56
64
 
@@ -88,15 +96,39 @@ $document.body << DOM {
88
96
  ```
89
97
 
90
98
  You will need to tell Opal to load this file. Add this in your template
91
- after everything has been loaded or somewhere else:
99
+ after everything has been loaded (after your `javascript_tag` call, it is
100
+ needed too!):
92
101
 
93
- ```html
102
+ ```erb
94
103
  <%= opal_require 'site' %>
95
104
  ```
96
105
 
97
106
  Note that it won't be needed for plain Javascript use, only Opal needs that
98
107
  line.
99
108
 
109
+ ### Caching:
110
+
111
+ To speed up page loads during development, you can enable cache. Be warned,
112
+ there are some caveats with how Sprockets cache works. This will improve your
113
+ experience, but be prepared for some rough edges.
114
+
115
+ To enable memory cache, add an argument to your plugin config:
116
+
117
+ ```ruby
118
+ cache: Sprockets::Cache::MemoryStore.new(65536)
119
+ ```
120
+
121
+ To enable filesystem cache, for it to persist across application restarts,
122
+ add an argument to your plugin config:
123
+
124
+ ```ruby
125
+ cache: Sprockets::Cache::FileStore.new("var/cache/")
126
+ ```
127
+
128
+ Remember: with filesystem cache problems may happen if you, for instance,
129
+ update your Gems. You will then have to remove the cache for it to get
130
+ repopulated.
131
+
100
132
  ### Rake precompilation tasks:
101
133
 
102
134
  In your Rakefile:
data/Rakefile CHANGED
@@ -1,2 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
2
3
 
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "roda-sprockets", path: "../.."
4
+ gem "opal-sprockets"
5
+ gem "puma"
6
+ gem "rake"
@@ -0,0 +1,4 @@
1
+ This is an example found in `opal` repository in `docs/roda-sprockets.md`.
2
+
3
+ It describes how to create the simplest application with roda, roda-sprockets
4
+ and opal.
@@ -0,0 +1,6 @@
1
+ require "bundler/setup"
2
+ require "roda/plugins/sprockets_task"
3
+
4
+ require_relative "app"
5
+
6
+ Roda::RodaPlugins::Sprockets::Task.define!(App)
@@ -0,0 +1,26 @@
1
+ require 'roda'
2
+
3
+ class App < Roda
4
+ plugin :sprockets, precompile: %w(application.js),
5
+ prefix: %w(app/),
6
+ opal: true,
7
+ debug: ENV['RACK_ENV'] != 'production'
8
+ plugin :public
9
+
10
+ route do |r|
11
+ r.public
12
+ r.sprockets if ENV['RACK_ENV'] != 'production'
13
+
14
+ r.root do
15
+ <<~END
16
+ <!doctype html>
17
+ <html>
18
+ <head>
19
+ #{ javascript_tag 'application' }
20
+ #{ opal_require 'application' }
21
+ </head>
22
+ </html>
23
+ END
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ require 'opal'
2
+
3
+ puts "wow, running ruby!"
@@ -0,0 +1,3 @@
1
+ require_relative "app"
2
+
3
+ run App.app
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "roda-sprockets", path: "../.."
4
+ gem "opal", github: "opal/opal"
5
+ gem "opal-sprockets"
6
+ gem "puma"
7
+ gem "rake"
@@ -0,0 +1 @@
1
+ This example drops an exception. It's for a test of source maps.
@@ -0,0 +1,6 @@
1
+ require "bundler/setup"
2
+ require "roda/plugins/sprockets_task"
3
+
4
+ require_relative "app"
5
+
6
+ Roda::RodaPlugins::Sprockets::Task.define!(App)
@@ -0,0 +1,26 @@
1
+ require 'roda'
2
+
3
+ class App < Roda
4
+ plugin :sprockets, precompile: %w(application.js),
5
+ prefix: %w(app/),
6
+ opal: true,
7
+ debug: ENV['RACK_ENV'] != 'production'
8
+ plugin :public
9
+
10
+ route do |r|
11
+ r.public
12
+ r.sprockets if ENV['RACK_ENV'] != 'production'
13
+
14
+ r.root do
15
+ <<~END
16
+ <!doctype html>
17
+ <html>
18
+ <head>
19
+ #{ javascript_tag 'application' }
20
+ #{ opal_require 'application' }
21
+ </head>
22
+ </html>
23
+ END
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ require 'opal'
2
+
3
+ def a
4
+ b
5
+ end
6
+
7
+ def b
8
+ 2 + 2 == 5
9
+ c
10
+ end
11
+
12
+ def c
13
+ nomethoderror
14
+ end
15
+
16
+ a
@@ -0,0 +1,3 @@
1
+ require_relative "app"
2
+
3
+ run App.app
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "roda-sprockets", path: "../.."
4
+ gem "sassc"
5
+ gem "puma"
6
+ gem "rake"
@@ -0,0 +1,6 @@
1
+ require "bundler/setup"
2
+ require "roda/plugins/sprockets_task"
3
+
4
+ require_relative "app"
5
+
6
+ Roda::RodaPlugins::Sprockets::Task.define!(App)
@@ -0,0 +1,24 @@
1
+ require 'roda'
2
+
3
+ class App < Roda
4
+ plugin :sprockets, precompile: %w(application.css),
5
+ debug: ENV['RACK_ENV'] != 'production'
6
+ plugin :public
7
+
8
+ route do |r|
9
+ r.public
10
+ r.sprockets if ENV['RACK_ENV'] != 'production'
11
+
12
+ r.root do
13
+ <<~END
14
+ <!doctype html>
15
+ <html>
16
+ <head>
17
+ #{ stylesheet_tag 'application' }
18
+ </head>
19
+ </html>
20
+ END
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,3 @@
1
+ html, body {
2
+ background-color: green;
3
+ }
@@ -0,0 +1,3 @@
1
+ require_relative "app"
2
+
3
+ run App.app
@@ -10,7 +10,7 @@ class Roda
10
10
  precompile: %w(app.js app.css *.png *.jpg *.svg *.eot *.ttf *.woff *.woff2),
11
11
  prefix: %w(assets vendor/assets),
12
12
  root: false,
13
- public_path: false,
13
+ public_path: "public/assets/",
14
14
  path_prefix: "/assets",
15
15
  protocol: :http,
16
16
  css_compressor: nil,
@@ -22,10 +22,6 @@ class Roda
22
22
  cache: nil,
23
23
  }.freeze
24
24
 
25
- def self.load_dependencies(app, _opts = nil)
26
- app.plugin :environments
27
- end
28
-
29
25
  def self.configure(app, plugin_options = {})
30
26
  if app.opts[:sprockets]
31
27
  app.opts[:sprockets].merge!(plugin_options)
@@ -35,9 +31,9 @@ class Roda
35
31
  options = app.opts[:sprockets].merge! plugin_options
36
32
  DEFAULTS.each { |k, v| options[k] = v unless options.key?(k) }
37
33
 
38
- options[:root] = app.opts[:root] if !options[:root]
39
-
40
- %i(root public_path).each { |type| raise "#{type} needs to be set." unless options[type] }
34
+ if !options[:root]
35
+ options[:root] = app.opts[:root] || Dir.pwd
36
+ end
41
37
 
42
38
  # opal-sprockets registers engines when required, but if we create Sprockets::Environment before
43
39
  # requiring that, they don't get registered
@@ -83,7 +79,7 @@ class Roda
83
79
  options[:sprockets_helpers].prefix = options[:path_prefix] unless options[:path_prefix].nil?
84
80
  options[:sprockets_helpers].debug = options[:debug]
85
81
 
86
- app.configure :staging, :production do
82
+ unless options[:debug]
87
83
  options[:sprockets].css_compressor = options[:css_compressor] unless options[:css_compressor].nil?
88
84
  options[:sprockets].js_compressor = options[:js_compressor] unless options[:js_compressor].nil?
89
85
 
@@ -123,7 +119,7 @@ class Roda
123
119
  Opal.require(#{file.to_json});
124
120
  </script>
125
121
  END
126
- .gsub(/\s+/, ' ')
122
+ .gsub(/\s+/, ' ').chop
127
123
  end
128
124
  end
129
125
 
@@ -136,15 +132,20 @@ class Roda
136
132
 
137
133
  status, headers, response = options[:sprockets].call env_sprockets
138
134
 
139
- # Appease Rack::Lint
140
- if (300..399).include? status
141
- headers.delete("Content-type")
142
- end
143
-
144
135
  scope.response.status = status
145
136
  scope.response.headers.merge! headers
146
137
 
147
- response.is_a?(Array) ? response.join('\n') : response.to_s
138
+ case response
139
+ when nil, []
140
+ # Empty response happens for example when 304 Not Modified happens.
141
+ # We want to return nil in this case.
142
+ # (See: https://github.com/hmdne/roda-sprockets/issues/1)
143
+ nil
144
+ when Array
145
+ response.join
146
+ else
147
+ response.to_s
148
+ end
148
149
  end
149
150
  end
150
151
  end
@@ -5,20 +5,48 @@ require 'rake/sprocketstask'
5
5
  class Roda
6
6
  module RodaPlugins
7
7
  module Sprockets
8
- class Task < Rake::TaskLib
8
+ class Task < Rake::SprocketsTask
9
9
  def initialize(app_klass)
10
+ if app_klass.class != Class
11
+ raise "#{app_klass} is not a Class"
12
+ elsif !app_klass.ancestors.map(&:name).include? "Roda"
13
+ raise "#{app_klass} doesn't inherit Roda"
14
+ elsif !app_klass.respond_to? :sprockets_options
15
+ raise "#{app_klass} doesn't load 'plugin :sprockets` - we can build nothing from it"
16
+ end
17
+
18
+ @app_klass = app_klass
19
+ super() { update_values }
20
+ end
21
+
22
+ def update_values
23
+ @environment = sprockets_options[:sprockets]
24
+ @output = sprockets_options[:public_path]
25
+ @assets = sprockets_options[:precompile]
26
+ end
27
+
28
+ def sprockets_options
29
+ @opts ||= begin
30
+ opts = @app_klass.sprockets_options.dup
31
+ opts[:debug] = false
32
+ opts
33
+ end
34
+ end
35
+
36
+ def define
10
37
  namespace :assets do
11
38
  desc "Precompile assets"
12
39
  task :precompile do
13
- options = app_klass.sprockets_options
14
- environment = options[:sprockets]
15
- manifest = ::Sprockets::Manifest.new(environment.index, options[:public_path])
16
- manifest.compile(options[:precompile])
40
+ with_logger do
41
+ manifest.compile(assets)
42
+ end
17
43
  end
18
44
 
19
45
  desc "Clean assets"
20
46
  task :clean do
21
- FileUtils.rm_rf(app_klass.sprockets_options[:public_path])
47
+ with_logger do
48
+ manifest.clobber
49
+ end
22
50
  end
23
51
  end
24
52
  end
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "roda-sprockets"
7
- spec.version = '1.0.1'
7
+ spec.version = '1.1.0'
8
8
  spec.authors = ["cj", "hmdne"]
9
9
  spec.email = ["cjlazell@gmail.com"]
10
10
  spec.summary = %q{Use sprockets to serve assets in roda.}
@@ -0,0 +1,7 @@
1
+ @mixin scss($this, $is, $scss) {
2
+ content: "#{$this} #{$is} #{$scss}"
3
+ }
4
+
5
+ body {
6
+ @include scss(This, is, SCSS);
7
+ }
@@ -0,0 +1,13 @@
1
+ <%=
2
+ mixin = "@mixin"
3
+ incl = "@include"
4
+ <<~EOF
5
+ #{mixin} scss($this, $is, $scss) {
6
+ content: "\#{$this} \#{$is} \#{$scss}"
7
+ }
8
+
9
+ body {
10
+ #{incl} scss(This, is, ERBSCSS);
11
+ }
12
+ EOF
13
+ %>
@@ -0,0 +1 @@
1
+ @import "scss_css";
@@ -0,0 +1 @@
1
+ body { content: "Simple CSS"; }
@@ -0,0 +1,4 @@
1
+ class Test
2
+ end
3
+
4
+ Test.new
@@ -0,0 +1,10 @@
1
+ <%=
2
+ classname = "TestERB"
3
+
4
+ <<~EOF
5
+ class #{classname}
6
+ end
7
+
8
+ #{classname}.new
9
+ EOF
10
+ %>
@@ -0,0 +1 @@
1
+ require "opal_js"
@@ -0,0 +1 @@
1
+ alert("Simple JS");
@@ -0,0 +1,132 @@
1
+ require "ferrum"
2
+
3
+ def sigterm(pid)
4
+ if Gem.win_platform?
5
+ system("taskkill /F /pid #{pid}")
6
+ else
7
+ Process.kill("TERM", pid)
8
+ Process.wait(pid)
9
+ end
10
+ rescue Errno::ECHILD
11
+ # Ignore
12
+ end
13
+
14
+ def free_port
15
+ $free_port ||= 19900
16
+ $free_port += 1
17
+ $free_port
18
+ end
19
+
20
+ browser_options = {
21
+ timeout: 15,
22
+ process_timeout: 20,
23
+ js_errors: true,
24
+ browser_options: {
25
+ 'no-sandbox': nil,
26
+ 'auto-open-devtools-for-tabs': nil
27
+ }
28
+ }
29
+
30
+ RSpec.describe "Example" do
31
+ Dir[__dir__+"/../examples/*"].each do |example|
32
+ example_name = File.basename(example)
33
+
34
+ example_specific = proc do |browser, debug, error|
35
+ case example_name
36
+ when "opal-doc"
37
+ browser.evaluate("typeof(Opal.Kernel.$puts)").should be == "function"
38
+ when "opal-exception"
39
+ error.should_not be_nil
40
+ functions = error.stack_trace["callFrames"].map { |i| i["functionName"] }
41
+ functions.should include "$$a"
42
+ functions.should include "$$b"
43
+ functions.should include "$$c"
44
+ # How can we now test that source maps work? The browser doesn't help us...
45
+ when "sass"
46
+ browser.evaluate("window.getComputedStyle(document.body).backgroundColor").should be == "rgb(0, 128, 0)"
47
+ end
48
+ end
49
+
50
+ context example_name do
51
+ it "works in development mode" do
52
+ Dir.chdir example do
53
+ Bundler.with_unbundled_env do
54
+ if ENV.key? 'CI'
55
+ # Ensure we will reuse the cached gems
56
+ system("bundle config --local path #{__dir__+"/../vendor/bundle"}")
57
+ end
58
+
59
+ system("bundle install").should be true
60
+
61
+ begin
62
+ port = free_port
63
+ pid = spawn("bundle exec rackup -p#{port}")
64
+ sleep 1
65
+
66
+ begin
67
+ browser = Ferrum::Browser.new(**browser_options)
68
+ browser.go_to("http://localhost:#{port}/")
69
+ browser.network.wait_for_idle
70
+
71
+ # Sometimes we need to wait a little bit longer for the exception to appear.
72
+ sleep 3 if example_name == "opal-exception"
73
+
74
+ instance_exec(browser, true, nil, &example_specific)
75
+ rescue Ferrum::JavaScriptError => e
76
+ instance_exec(browser, true, e, &example_specific)
77
+ ensure
78
+ browser.quit
79
+ end
80
+ ensure
81
+ sigterm(pid)
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ it "works in production mode" do
88
+ Dir.chdir example do
89
+ Bundler.with_unbundled_env do
90
+ ENV['RACK_ENV'] = 'production'
91
+
92
+ if ENV.key? 'CI'
93
+ system("bundle config --local path #{__dir__+"/../vendor/bundle"}")
94
+ end
95
+
96
+ system("bundle install").should be true
97
+
98
+ system("bundle exec rake assets:clean").should be true
99
+ -> { Dir.children(example + "/public/assets") }.should raise_error Errno::ENOENT
100
+ system("bundle exec rake assets:precompile").should be true
101
+ Dir.children(example + "/public/assets").length.should be == 3
102
+
103
+ begin
104
+ port = free_port
105
+ pid = spawn("bundle exec rackup -p#{port}")
106
+ sleep 1
107
+
108
+ begin
109
+ browser = Ferrum::Browser.new(**browser_options)
110
+ browser.go_to("http://localhost:#{port}/")
111
+ browser.network.wait_for_idle
112
+
113
+ instance_exec(browser, false, nil, &example_specific)
114
+ rescue Ferrum::JavaScriptError => e
115
+ instance_exec(browser, true, e, &example_specific)
116
+ ensure
117
+ browser.quit
118
+ end
119
+ ensure
120
+ system("bundle exec rake assets:clean").should be true
121
+ -> { Dir.children(example + "/public/assets") }.should raise_error Errno::ENOENT
122
+
123
+ sigterm(pid)
124
+ end
125
+ ensure
126
+ ENV.delete('RACK_ENV')
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,237 @@
1
+ require "time"
2
+ require "roda/plugins/sprockets"
3
+
4
+ RSpec.shared_examples("basic checks") do
5
+ it "returns a OK result" do
6
+ req = app.req
7
+ req.should be_ok
8
+ end
9
+
10
+ it "generates the necessary tags" do
11
+ req = app.req
12
+ if debug
13
+ req.body.should include %'<script src="/assets/#{js_name}.debug.js" type="text/javascript"'
14
+ req.body.should include %'<link rel="stylesheet" type="text/css" href="/assets/#{css_name}.debug.css">'
15
+ else
16
+ req.body.should include %'<script src="/assets/#{js_name}-'
17
+ req.body.should include %'<link rel="stylesheet" type="text/css" href="/assets/#{css_name}-'
18
+ end
19
+ end
20
+
21
+ it "generates the necessary files" do
22
+ req = app.req
23
+ req_css = app.req(req.css_path)
24
+ req_js = app.req(req.js_path)
25
+
26
+ req_css.should be_ok
27
+ req_css.body.should include css_value
28
+
29
+ req_js.should be_ok
30
+ req_js.body.should include js_value
31
+ end
32
+
33
+ it "returns a not modified status if the assets haven't been modified" do
34
+ req = app.req
35
+
36
+ etag_css = app.req(req.css_path).headers["ETag"]
37
+ etag_js = app.req(req.js_path).headers["ETag"]
38
+
39
+ req_css = app.req(req.css_path, "HTTP_IF_NONE_MATCH" => etag_css)
40
+ req_js = app.req(req.js_path, "HTTP_IF_NONE_MATCH" => etag_js)
41
+
42
+ req_css.should be_not_modified
43
+ req_js.should be_not_modified
44
+ end
45
+
46
+ it "appropriately includes source maps or not" do
47
+ req = app.req
48
+ req_css = app.req(req.css_path)
49
+ req_js = app.req(req.js_path)
50
+
51
+ if debug
52
+ req_css.body.should include "/*# sourceMappingURL="
53
+ req_js.body.should include "//# sourceMappingURL="
54
+ else
55
+ req_css.body.should_not include "/*# sourceMappingURL="
56
+ req_js.body.should_not include "//# sourceMappingURL="
57
+ end
58
+ end
59
+ end
60
+
61
+ RSpec.describe Roda::RodaPlugins::Sprockets do
62
+ context "simple app" do
63
+ let(:css_name) { "simple_css" }
64
+ let(:js_name) { "simple_js" }
65
+ let(:css_value) { "Simple CSS" }
66
+ let(:js_value) { "Simple JS" }
67
+
68
+ context "in debug mode" do
69
+ simple_debug_app = Server.gen("simple_css", "simple_js", debug: true)
70
+
71
+ let(:app) { simple_debug_app }
72
+ let(:debug) { true }
73
+
74
+ include_examples "basic checks"
75
+ end
76
+
77
+ context "in production mode" do
78
+ simple_prod_app = Server.gen("simple_css", "simple_js", debug: false)
79
+
80
+ let(:app) { simple_prod_app }
81
+ let(:debug) { false }
82
+
83
+ include_examples "basic checks"
84
+ end
85
+ end
86
+
87
+ context "opal + scss app" do
88
+ let(:css_name) { "scss_css" }
89
+ let(:js_name) { "opal_js" }
90
+ let(:css_value) { "This is SCSS" }
91
+ let(:js_value) { "$$($nesting, 'Test').$new();" }
92
+
93
+ context "in debug mode" do
94
+ opalscss_debug_app = Server.gen("scss_css", "opal_js", opal: true, debug: true)
95
+
96
+ let(:app) { opalscss_debug_app }
97
+ let(:debug) { true }
98
+
99
+ include_examples "basic checks"
100
+ end
101
+
102
+ context "in production mode" do
103
+ opalscss_prod_app = Server.gen("scss_css", "opal_js", opal: true, debug: false)
104
+
105
+ let(:app) { opalscss_prod_app }
106
+ let(:debug) { false }
107
+
108
+ include_examples "basic checks"
109
+ end
110
+ end
111
+
112
+ context "opal with requires + scss with imports app" do
113
+ let(:css_name) { "scss_css_with_imports" }
114
+ let(:js_name) { "opal_js_with_requires" }
115
+ let(:css_value) { "This is SCSS" }
116
+ let(:js_value) { "$$($nesting, 'Test').$new();" }
117
+
118
+ context "in debug mode" do
119
+ opalscssreq_debug_app = Server.gen("scss_css_with_imports", "opal_js_with_requires", opal: true, debug: true)
120
+
121
+ let(:app) { opalscssreq_debug_app }
122
+ let(:debug) { true }
123
+
124
+ include_examples "basic checks"
125
+ end
126
+
127
+ context "in production mode" do
128
+ opalscssreq_prod_app = Server.gen("scss_css_with_imports", "opal_js_with_requires", opal: true, debug: false)
129
+
130
+ let(:app) { opalscssreq_prod_app }
131
+ let(:debug) { false }
132
+
133
+ include_examples "basic checks"
134
+ end
135
+ end
136
+
137
+ context "opal with erb + scss with erb app" do
138
+ let(:css_name) { "scss_css_with_erb" }
139
+ let(:js_name) { "opal_js_with_erb" }
140
+ let(:css_value) { "This is ERBSCSS" }
141
+ let(:js_value) { "$$($nesting, 'TestERB').$new();" }
142
+
143
+ context "in debug mode" do
144
+ opalscsserb_debug_app = Server.gen("scss_css_with_erb", "opal_js_with_erb", opal: true, debug: true)
145
+
146
+ let(:app) { opalscsserb_debug_app }
147
+ let(:debug) { true }
148
+
149
+ include_examples "basic checks"
150
+ end
151
+
152
+ context "in production mode" do
153
+ opalscsserb_prod_app = Server.gen("scss_css_with_erb", "opal_js_with_erb", opal: true, debug: false)
154
+
155
+ let(:app) { opalscsserb_prod_app }
156
+ let(:debug) { false }
157
+
158
+ include_examples "basic checks"
159
+ end
160
+ end
161
+
162
+ context "opal + scss app with compressor" do
163
+ let(:css_name) { "scss_css" }
164
+ let(:js_name) { "opal_js" }
165
+ let(:css_value) { "This is SCSS" }
166
+ let(:js_value) { "Test" }
167
+
168
+ context "in debug mode" do
169
+ opalscsscomp_debug_app = Server.gen("scss_css", "opal_js",
170
+ css_compressor: :sassc, js_compressor: :uglify,
171
+ opal: true, debug: true
172
+ )
173
+
174
+ let(:app) { opalscsscomp_debug_app }
175
+ let(:debug) { true }
176
+
177
+ include_examples "basic checks"
178
+
179
+ it "should run uglifier" do
180
+ req = app.req
181
+ req_js = app.req(req.js_path)
182
+
183
+ req_js.body.should include "$$($nesting, 'Test').$new();"
184
+ end
185
+ end
186
+
187
+ context "in production mode" do
188
+ opalscsscomp_prod_app = Server.gen("scss_css", "opal_js",
189
+ css_compressor: :sassc, js_compressor: :uglify,
190
+ opal: true, debug: false
191
+ )
192
+
193
+ let(:app) { opalscsscomp_prod_app }
194
+ let(:debug) { false }
195
+
196
+ include_examples "basic checks"
197
+
198
+ it "should not run uglifier" do
199
+ req = app.req
200
+ req_js = app.req(req.js_path)
201
+
202
+ req_js.body.should_not include "$$($nesting, 'Test').$new();"
203
+ end
204
+ end
205
+ end
206
+
207
+ context "opal + scss app with cache" do
208
+ let(:css_name) { "scss_css" }
209
+ let(:js_name) { "opal_js" }
210
+ let(:css_value) { "This is SCSS" }
211
+ let(:js_value) { "$$($nesting, 'Test').$new();" }
212
+
213
+ context "in debug mode" do
214
+ opalscsscache_debug_app = Server.gen("scss_css", "opal_js",
215
+ opal: true, debug: true,
216
+ cache: Sprockets::Cache::MemoryStore.new(65536)
217
+ )
218
+
219
+ let(:app) { opalscsscache_debug_app }
220
+ let(:debug) { true }
221
+
222
+ include_examples "basic checks"
223
+ end
224
+
225
+ context "in production mode" do
226
+ opalscsscache_prod_app = Server.gen("scss_css", "opal_js",
227
+ opal: true, debug: false,
228
+ cache: Sprockets::Cache::MemoryStore.new(65536)
229
+ )
230
+
231
+ let(:app) { opalscsscache_prod_app }
232
+ let(:debug) { false }
233
+
234
+ include_examples "basic checks"
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,68 @@
1
+ require "roda"
2
+
3
+ class Server < Roda
4
+ class << self
5
+ def gen(css=nil, js=nil, **kwargs, &block)
6
+ Class.new Server do |c|
7
+ unless kwargs.empty?
8
+ c.plugin :sprockets, root: __dir__, **kwargs
9
+ end
10
+
11
+ if css || js
12
+ c.route do |r|
13
+ r.sprockets
14
+
15
+ r.root do
16
+ out = ""
17
+ out += stylesheet_tag(css) if css
18
+ out += javascript_tag(js) if js
19
+ out
20
+ end
21
+ end
22
+ end
23
+
24
+ yield(c) if block_given?
25
+ end
26
+ end
27
+
28
+ # Slightly adapted from https://github.com/jeremyevans/roda/blob/master/spec/spec_helper.rb
29
+ def req(path = '/', env = {})
30
+ env['PATH_INFO'] = path.dup
31
+ env = {"REQUEST_METHOD" => "GET", "PATH_INFO" => "/", "SCRIPT_NAME" => ""}.merge(env)
32
+ Response.new(*self.call(env))
33
+ end
34
+ end
35
+
36
+ class Response
37
+ def initialize(status, headers, body)
38
+ @status, @headers, @body = status, headers, body
39
+ end
40
+
41
+ def ok?
42
+ status == 200
43
+ end
44
+
45
+ attr_reader :status, :headers
46
+
47
+ def body
48
+ @body&.join
49
+ end
50
+
51
+ def js_path
52
+ body =~ /<script src="(.*?)"/
53
+ $1
54
+ end
55
+
56
+ def css_path
57
+ body =~ /<link rel="stylesheet" type="text\/css" href="(.*?)"/
58
+ $1
59
+ end
60
+
61
+ def not_modified?
62
+ status == 304 &&
63
+ (body.nil? || body.empty?) &&
64
+ !headers.key?("Content-Length") &&
65
+ !headers.key?("Content-Type")
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,59 @@
1
+ RSpec.configure do |config|
2
+ config.expect_with :rspec do |expectations|
3
+ # This option will default to `true` in RSpec 4. It makes the `description`
4
+ # and `failure_message` of custom matchers include text for helper methods
5
+ # defined using `chain`, e.g.:
6
+ # be_bigger_than(2).and_smaller_than(4).description
7
+ # # => "be bigger than 2 and smaller than 4"
8
+ # ...rather than:
9
+ # # => "be bigger than 2"
10
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
11
+ expectations.syntax = :should
12
+ end
13
+
14
+ config.mock_with :rspec do |mocks|
15
+ # Prevents you from mocking or stubbing a method that does not exist on
16
+ # a real object. This is generally recommended, and will default to
17
+ # `true` in RSpec 4.
18
+ mocks.verify_partial_doubles = true
19
+ end
20
+
21
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
22
+ # have no way to turn it off -- the option exists only for backwards
23
+ # compatibility in RSpec 3). It causes shared context metadata to be
24
+ # inherited by the metadata hash of host groups and examples, rather than
25
+ # triggering implicit auto-inclusion in groups with matching metadata.
26
+ config.shared_context_metadata_behavior = :apply_to_host_groups
27
+
28
+ # This allows you to limit a spec run to individual examples or groups
29
+ # you care about by tagging them with `:focus` metadata. When nothing
30
+ # is tagged with `:focus`, all examples get run. RSpec also provides
31
+ # aliases for `it`, `describe`, and `context` that include `:focus`
32
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
33
+ config.filter_run_when_matching :focus
34
+
35
+ # This setting enables warnings. It's recommended, but in some cases may
36
+ # be too noisy due to issues in dependencies.
37
+ config.warnings = true
38
+
39
+ # Print the 10 slowest examples and example groups at the
40
+ # end of the spec run, to help surface which specs are running
41
+ # particularly slow.
42
+ config.profile_examples = 10
43
+
44
+ # Run specs in random order to surface order dependencies. If you find an
45
+ # order dependency and want to debug it, you can fix the order by providing
46
+ # the seed, which is printed after each run.
47
+ # --seed 1234
48
+ config.order = :random
49
+
50
+ # Seed global randomization in this process using the `--seed` CLI option.
51
+ # Setting this allows you to use `--seed` to deterministically reproduce
52
+ # test failures related to randomization by passing the same `--seed` value
53
+ # as the one that triggered the failure.
54
+ Kernel.srand config.seed
55
+ end
56
+
57
+ require "bundler/setup"
58
+
59
+ require_relative "server_helper"
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda-sprockets
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - cj
8
8
  - hmdne
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-09-16 00:00:00.000000000 Z
12
+ date: 2021-08-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: roda
@@ -88,20 +88,52 @@ executables: []
88
88
  extensions: []
89
89
  extra_rdoc_files: []
90
90
  files:
91
+ - ".github/workflows/rake.yml"
91
92
  - ".gitignore"
93
+ - ".rspec"
94
+ - CHANGELOG.md
92
95
  - Gemfile
93
96
  - LICENSE.txt
94
97
  - README.md
95
98
  - Rakefile
99
+ - examples/opal-doc/Gemfile
100
+ - examples/opal-doc/README.md
101
+ - examples/opal-doc/Rakefile
102
+ - examples/opal-doc/app.rb
103
+ - examples/opal-doc/app/application.rb
104
+ - examples/opal-doc/config.ru
105
+ - examples/opal-exception/Gemfile
106
+ - examples/opal-exception/README.md
107
+ - examples/opal-exception/Rakefile
108
+ - examples/opal-exception/app.rb
109
+ - examples/opal-exception/app/application.rb
110
+ - examples/opal-exception/config.ru
111
+ - examples/sass/Gemfile
112
+ - examples/sass/Rakefile
113
+ - examples/sass/app.rb
114
+ - examples/sass/assets/css/application.scss
115
+ - examples/sass/config.ru
96
116
  - lib/roda/plugins/sprockets.rb
97
117
  - lib/roda/plugins/sprockets_task.rb
98
118
  - lib/roda/sprockets.rb
99
119
  - roda-sprockets.gemspec
120
+ - spec/assets/css/scss_css.scss
121
+ - spec/assets/css/scss_css_with_erb.scss.erb
122
+ - spec/assets/css/scss_css_with_imports.scss
123
+ - spec/assets/css/simple_css.css
124
+ - spec/assets/js/opal_js.rb
125
+ - spec/assets/js/opal_js_with_erb.rb.erb
126
+ - spec/assets/js/opal_js_with_requires.rb
127
+ - spec/assets/js/simple_js.js
128
+ - spec/examples_spec.rb
129
+ - spec/plugin_spec.rb
130
+ - spec/server_helper.rb
131
+ - spec/spec_helper.rb
100
132
  homepage: https://github.com/hmdne/roda-sprockets
101
133
  licenses:
102
134
  - MIT
103
135
  metadata: {}
104
- post_install_message:
136
+ post_install_message:
105
137
  rdoc_options: []
106
138
  require_paths:
107
139
  - lib
@@ -116,8 +148,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
148
  - !ruby/object:Gem::Version
117
149
  version: '0'
118
150
  requirements: []
119
- rubygems_version: 3.1.2
120
- signing_key:
151
+ rubygems_version: 3.2.22
152
+ signing_key:
121
153
  specification_version: 4
122
154
  summary: Use sprockets to serve assets in roda.
123
- test_files: []
155
+ test_files:
156
+ - spec/assets/css/scss_css.scss
157
+ - spec/assets/css/scss_css_with_erb.scss.erb
158
+ - spec/assets/css/scss_css_with_imports.scss
159
+ - spec/assets/css/simple_css.css
160
+ - spec/assets/js/opal_js.rb
161
+ - spec/assets/js/opal_js_with_erb.rb.erb
162
+ - spec/assets/js/opal_js_with_requires.rb
163
+ - spec/assets/js/simple_js.js
164
+ - spec/examples_spec.rb
165
+ - spec/plugin_spec.rb
166
+ - spec/server_helper.rb
167
+ - spec/spec_helper.rb