roda-sprockets 1.0.0 → 1.1.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
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 +33 -7
  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 +22 -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 +53 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e60bfe5e2c8adb6d2276d1c3ca69eb489201fda460d32cf9a93987603afcfcea
4
- data.tar.gz: 9d0201eb062793f1c1de05661cb4db699153cb11e8de5ec01b897fcad4928cce
3
+ metadata.gz: 044c710248511deccca6f7742043b0b6d8f292485ae2ad4739c4bd5d2db0cd4e
4
+ data.tar.gz: 6eedd2832e892adcd7d4bd8f9812f1a6c2fa51dad4f7b2fe9088c9c07c572c9b
5
5
  SHA512:
6
- metadata.gz: 8f0ab041fbc6da153ef2b61dcf215daf104e4029059090dfde0f64b760a9f542f7d3ddb244d89d0aa359e4bea3d82cc6dfa7cdc3acf6456aa13beb3244285ce7
7
- data.tar.gz: df03c4d605741ae5163803a542cf3f4b6a2ae8fa6505ead89a5277a0dd902038e96198868fd15200a2756a1f1d4f82b0adc27cc928dc6cb9db41475ed03601ff
6
+ metadata.gz: eac44b966b14b05b7d50b91d4806082c626a9207353fbf9e4bbc2a4d0f58a5603d22a2d67c15ca789f01b1753fea3fddfc39fd4d1e135729bc7a1559d54d7305
7
+ data.tar.gz: e69db382d5d988dab102855baa77fdf211e5efa4ac328fbb3019f4e622cfc852153865e1f5fc5d103c56ec509f5afe251f159d76af588fe1cd8365bdaa6a1b08
@@ -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,7 +29,7 @@ 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
 
@@ -40,9 +39,11 @@ end
40
39
  * `prefix` (relative to the `root`, which is `app.opts[:root]` by default,
41
40
  but also supports absolute paths) - an array of directories where your
42
41
  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)
42
+ * `root` - a filesystem root directory of your app. By default, same as
43
+ `app.opts[:root]`, that is: `Dir.pwd`.
44
+ * `public_path` - filesystem path to a place, where precompiled assets will be
45
+ stored, by default: `public/assets` (it should be a directory from which `:public`
46
+ plugin takes files + `path_prefix`)
46
47
  * `path_prefix` - a Roda prefix of your assets directory. By default: `/assets`
47
48
  * `protocol` - either :http (default) or :https.
48
49
  * `css_compressor`, `js_compressor` - pick a compressor of your choice.
@@ -50,6 +51,7 @@ end
50
51
  * `digest` (bool) - digest your assets for unique filenames, default: true
51
52
  * `opal` (bool) - Opal support, default: false
52
53
  * `debug` (bool) - debug mode, default: false
54
+ * `cache` - a `Sprockets::Cache` instance, default: nil (no cache)
53
55
 
54
56
  ### Templates:
55
57
 
@@ -87,15 +89,39 @@ $document.body << DOM {
87
89
  ```
88
90
 
89
91
  You will need to tell Opal to load this file. Add this in your template
90
- after everything has been loaded or somewhere else:
92
+ after everything has been loaded (after your `javascript_tag` call, it is
93
+ needed too!):
91
94
 
92
- ```html
95
+ ```erb
93
96
  <%= opal_require 'site' %>
94
97
  ```
95
98
 
96
99
  Note that it won't be needed for plain Javascript use, only Opal needs that
97
100
  line.
98
101
 
102
+ ### Caching:
103
+
104
+ To speed up page loads during development, you can enable cache. Be warned,
105
+ there are some caveats with how Sprockets cache works. This will improve your
106
+ experience, but be prepared for some rough edges.
107
+
108
+ To enable memory cache, add an argument to your plugin config:
109
+
110
+ ```ruby
111
+ cache: Sprockets::Cache::MemoryStore.new(65536)
112
+ ```
113
+
114
+ To enable filesystem cache, for it to persist across application restarts,
115
+ add an argument to your plugin config:
116
+
117
+ ```ruby
118
+ cache: Sprockets::Cache::FileStore.new("var/cache/")
119
+ ```
120
+
121
+ Remember: with filesystem cache problems may happen if you, for instance,
122
+ update your Gems. You will then have to remove the cache for it to get
123
+ repopulated.
124
+
99
125
  ### Rake precompilation tasks:
100
126
 
101
127
  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,
@@ -19,12 +19,9 @@ class Roda
19
19
  digest: true,
20
20
  opal: false,
21
21
  debug: false,
22
+ cache: nil,
22
23
  }.freeze
23
24
 
24
- def self.load_dependencies(app, _opts = nil)
25
- app.plugin :environments
26
- end
27
-
28
25
  def self.configure(app, plugin_options = {})
29
26
  if app.opts[:sprockets]
30
27
  app.opts[:sprockets].merge!(plugin_options)
@@ -34,9 +31,9 @@ class Roda
34
31
  options = app.opts[:sprockets].merge! plugin_options
35
32
  DEFAULTS.each { |k, v| options[k] = v unless options.key?(k) }
36
33
 
37
- options[:root] = app.opts[:root] if !options[:root]
38
-
39
- %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
40
37
 
41
38
  # opal-sprockets registers engines when required, but if we create Sprockets::Environment before
42
39
  # requiring that, they don't get registered
@@ -71,6 +68,10 @@ class Roda
71
68
  end
72
69
  end
73
70
 
71
+ if options[:cache]
72
+ options[:sprockets].cache = options[:cache]
73
+ end
74
+
74
75
  options[:sprockets_helpers] = ::Sprockets::Helpers::Settings.new
75
76
 
76
77
  options[:sprockets_helpers].environment = options[:sprockets]
@@ -78,7 +79,7 @@ class Roda
78
79
  options[:sprockets_helpers].prefix = options[:path_prefix] unless options[:path_prefix].nil?
79
80
  options[:sprockets_helpers].debug = options[:debug]
80
81
 
81
- app.configure :staging, :production do
82
+ unless options[:debug]
82
83
  options[:sprockets].css_compressor = options[:css_compressor] unless options[:css_compressor].nil?
83
84
  options[:sprockets].js_compressor = options[:js_compressor] unless options[:js_compressor].nil?
84
85
 
@@ -118,7 +119,7 @@ class Roda
118
119
  Opal.require(#{file.to_json});
119
120
  </script>
120
121
  END
121
- .gsub(/\s+/, ' ')
122
+ .gsub(/\s+/, ' ').chop
122
123
  end
123
124
  end
124
125
 
@@ -131,15 +132,20 @@ class Roda
131
132
 
132
133
  status, headers, response = options[:sprockets].call env_sprockets
133
134
 
134
- # Appease Rack::Lint
135
- if (300..399).include? status
136
- headers.delete("Content-type")
137
- end
138
-
139
135
  scope.response.status = status
140
136
  scope.response.headers.merge! headers
141
137
 
142
- 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
143
149
  end
144
150
  end
145
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.0'
7
+ spec.version = '1.1.0.rc2'
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.0
4
+ version: 1.1.0.rc2
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-01 00:00:00.000000000 Z
12
+ date: 2021-08-22 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
@@ -112,12 +144,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
112
144
  version: '0'
113
145
  required_rubygems_version: !ruby/object:Gem::Requirement
114
146
  requirements:
115
- - - ">="
147
+ - - ">"
116
148
  - !ruby/object:Gem::Version
117
- version: '0'
149
+ version: 1.3.1
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