serviceworker-rails 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d025ce1cde7d307ac23919e459e703f06702b9ad
4
- data.tar.gz: 9d0239c076fcae84235b78ce35398cb8fe26a808
3
+ metadata.gz: 3752a3b8e5aab69a95949bf282791c5871a1297d
4
+ data.tar.gz: 22de311f4ed1728871bb3032673f03e3bac57e4e
5
5
  SHA512:
6
- metadata.gz: 5b0e0c3e6599dd4f74efe555dc4271b5d51c1d0b1a07a0079e095055ff53d2cb57befa0f048a9e7d44ab1bad2108fcca3b975fb0e38d98d0456eebc6d43a6c4c
7
- data.tar.gz: db588993939e6b722c3f5e968e1cbcd816cdd5100b6a553bab9252a2d67e7b38d2f536bc394ae2fe9e04babf59de8858b56d3f4ca6f38afa58ff692eb83fa07f
6
+ metadata.gz: e14a4a092b558e85a68d3dbef7f61d2fdf185d3510d9def1480a45d8abd7a96202f00da5ce2debe3a05fe2bd408d7a8ec26a801f19427fb6a8bd25aaae4c6c70
7
+ data.tar.gz: b439353ce2aa25da2df120f902b59ed431b873cf077cb48e3d3a612c71f6ae474f12cf57b5e4900ad70f66d220c82297b4e71dac0885178eda6aeb7bbbc920a8
data/.rubocop.yml ADDED
@@ -0,0 +1,87 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "test/tmp/**/*"
4
+
5
+ Metrics/LineLength:
6
+ Max: 120
7
+
8
+ Metrics/ClassLength:
9
+ Max: 300
10
+
11
+ Metrics/ModuleLength:
12
+ Max: 300
13
+
14
+ Metrics/MethodLength:
15
+ Max: 100
16
+
17
+ Metrics/ParameterLists:
18
+ Max: 8
19
+
20
+ Metrics/AbcSize:
21
+ Enabled: false
22
+
23
+ Metrics/CyclomaticComplexity:
24
+ Enabled: false
25
+
26
+ Metrics/PerceivedComplexity:
27
+ Enabled: false
28
+
29
+ Style/AlignParameters:
30
+ EnforcedStyle: with_fixed_indentation
31
+
32
+ Style/StringLiterals:
33
+ EnforcedStyle: double_quotes
34
+
35
+ Style/StringLiteralsInInterpolation:
36
+ EnforcedStyle: double_quotes
37
+
38
+ Style/ClosingParenthesisIndentation:
39
+ Enabled: false
40
+
41
+ Style/OneLineConditional:
42
+ Enabled: false
43
+
44
+ Style/AndOr:
45
+ Enabled: false
46
+
47
+ Style/Not:
48
+ Enabled: false
49
+
50
+ Documentation:
51
+ Enabled: false # TODO: Enable again once we have more docs
52
+
53
+ Style/CaseIndentation:
54
+ IndentWhenRelativeTo: case
55
+ SupportedStyles:
56
+ - case
57
+ - end
58
+ IndentOneStep: true
59
+
60
+ Style/PercentLiteralDelimiters:
61
+ PreferredDelimiters:
62
+ '%w': "[]"
63
+ '%W': "[]"
64
+
65
+ Style/AccessModifierIndentation:
66
+ Enabled: false
67
+
68
+ Style/SignalException:
69
+ Enabled: false
70
+
71
+ Style/IndentationWidth:
72
+ Enabled: false
73
+
74
+ Style/TrivialAccessors:
75
+ ExactNameMatch: true
76
+
77
+ Lint/DefEndAlignment:
78
+ Enabled: false
79
+
80
+ Lint/HandleExceptions:
81
+ Enabled: false
82
+
83
+ Style/SpecialGlobalVars:
84
+ Enabled: false
85
+
86
+ Style/TrivialAccessors:
87
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.8
4
3
  - 2.2.5
5
4
  - 2.3.0
6
5
  before_install: gem install bundler -v 1.11.2
data/Gemfile CHANGED
@@ -1,11 +1,14 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in serviceworker-rails.gemspec
4
4
  gemspec
5
5
 
6
6
  group :development, :test do
7
+ gem "rubocop", "0.39.0"
8
+
7
9
  unless ENV["TRAVIS"]
8
- gem "pry-byebug", platforms: [:ruby_23]
10
+ gem "pry"
11
+ gem "pry-byebug", platforms: [:mri]
9
12
  gem "guard"
10
13
  gem "guard-minitest"
11
14
  end
data/Guardfile CHANGED
@@ -19,7 +19,7 @@ guard :minitest do
19
19
  # with Minitest::Unit
20
20
  watch(%r{^test/(.*)\/?(.*)_test\.rb$})
21
21
  watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
22
- watch(%r{^test/test_helper\.rb$}) { 'test' }
22
+ watch(%r{^test/test_helper\.rb$}) { "test" }
23
23
 
24
24
  # with Minitest::Spec
25
25
  # watch(%r{^spec/(.*)_spec\.rb$})
data/README.md CHANGED
@@ -2,7 +2,29 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/rossta/serviceworker-rails.svg?branch=master)](https://travis-ci.org/rossta/serviceworker-rails)
4
4
 
5
- Use [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) with the Rails asset pipeline.
5
+ Turn your Rails app into a Progressive Web App. Use [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) with the Rails asset pipeline.
6
+
7
+ ## Why?
8
+
9
+ The Rails asset pipeline makes a number of assumptions about what's best for deploying JavaScript, including asset digest fingerprints and long-lived cache headers - mostly to increase "cacheability". Rails also assumes a single parent directory, `/public/assets`, to make it easier to look up the file path for a given asset.
10
+
11
+ Service worker assets must play by different rules. Consider these behaviors:
12
+
13
+ * Service workers may only be active from within the scope from which they are
14
+ served. So if you try to register a service worker from a Rails asset pipeline
15
+ path, like `/assets/serviceworker-abcd1234.js`, it will only be able to interact
16
+ with requests and responses within `/assets/`<em>**</em>. This is not what we want.
17
+
18
+ * [MDN states](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API#Download_install_and_activate) browsers check for updated service worker scripts in the background every 24 hours (possibly less). Rails developers wouldn't be able to take advantage of this feature since the fingerprint strategy means assets at a given url are immutable. Beside fingerprintings, the `Cache-Control` headers used for static files served from Rails also work against browser's treatment of service workers.
19
+
20
+ We want Sprockets to compile service worker JavaScript from ES6/7, CoffeeScript, ERB, etc. but must remove the caching and scoping mechanisms offered by Rails asset pipeline defaults. This is where `serviceworker-rails` comes in.
21
+
22
+ *Check out the [blog post](https://rossta.net/blog/service-worker-on-rails.html)
23
+ for more background.*
24
+
25
+ ### Demo
26
+
27
+ See various examples of using Service Workers in the demo Rails app, [Service Worker Rails Sandbox](https://serviceworker-rails.herokuapp.com/). The [source code](https://github.com/rossta/serviceworker-rails-sandbox) is also on GitHub.
6
28
 
7
29
  ## Features
8
30
 
@@ -26,31 +48,169 @@ Or install it yourself as:
26
48
 
27
49
  $ gem install serviceworker-rails
28
50
 
29
- ## Usage
51
+ To set up your Rails project for use with a Service Worker, you either use the
52
+ Rails generator and edit the generated files as needed, or you can follow the
53
+ manual installation steps.
54
+
55
+ ### Automated setup
56
+
57
+ After bundling the gem in your Rails project, run the generator from the root of
58
+ your Rails project.
59
+
60
+ ```
61
+ $ rails g serviceworker:install
62
+ ```
63
+
64
+ ### Manual setup
65
+
66
+ Let's add a `ServiceWorker` to cache some of your JavaScript and CSS assets. We'll assume you already have a Rails application using the asset pipeline built on Sprockets.
67
+
68
+ #### Add a service worker script
69
+
70
+ Create a JavaScript file called `app/assets/javascripts/serviceworker.js.erb`:
71
+
72
+ ```javascript
73
+ // app/assets/javascripts/serviceworker.js.erb
74
+ console.log('[Service Worker] Hello world!');
75
+
76
+ function onInstall(event) {
77
+ event.waitUntil(
78
+ caches.open('cached-assets').then(function prefill(cache) {
79
+ return cache.addAll([
80
+ '<%= asset_path "application.js" %>',
81
+ '<%= asset_path "application.css" %>',
82
+ '<%= asset_path "admin.css" %>',
83
+ // you get the idea ...
84
+ ]);
85
+ })
86
+ );
87
+ }
88
+
89
+ self.addEventListener('install', onInstall)
90
+ ```
91
+
92
+ For use in production, instruct Sprockets to precompile service worker scripts separately from `application.js`, as in the following example:
93
+
94
+ #### Precompile the asset
95
+
96
+ ```ruby
97
+ # config/initializers/assets.rb
98
+
99
+ Rails.application.configure do
100
+ config.assets.precompile += %w[
101
+ serviceworker.js
102
+ ]
103
+ end
104
+ ```
105
+
106
+ #### Register the service worker
107
+
108
+ You'll need to register the service worker with a companion script in your main page JavaScript, like `application.js`. You can use the following:
109
+
110
+ ```javascript
111
+ // app/assets/javascripts/serviceworker-companion.js
30
112
 
31
- To use `serviceworker-rails` in a Rails app, install the gem as above. When
32
- `serviceworker-rails` is required, it will insert a middleware into the Rails
113
+ if (navigator.serviceWorker) {
114
+ navigator.serviceWorker.register('/serviceworker.js', { scope: './' })
115
+ .then(function(reg) {
116
+ console.log('[Page] Service worker registered!');
117
+ });
118
+ }
119
+
120
+ // app/assets/javascripts/application.js
121
+
122
+ // ...
123
+ //= require serviceworker-companion
124
+ ```
125
+
126
+ #### Add a manifest
127
+
128
+ You may also want to create a `manifest.json` file to make your web app installable.
129
+
130
+ ```
131
+ // manifest.json
132
+ {
133
+ "name": "My Rails App"
134
+ "name": "My Progressive Rails App",
135
+ "short_name": "Progressive",
136
+ "start_url": "/"
137
+ }
138
+ ```
139
+
140
+ You'd then link to your manifest from the application layout:
141
+
142
+ ```html
143
+ <link rel="manifest" href="/manifest.json" />
144
+ ```
145
+
146
+ #### Configure the middleware
147
+
148
+ Next, add a new initializer as show below to instruct the `serviceworker-rails`
149
+ middleware how to route requests for assets by canonical url.
150
+
151
+ ```ruby
152
+ # config/initializers/serviceworker.rb
153
+
154
+ Rails.application.configure do
155
+ config.serviceworker.routes.draw do
156
+ match "/serviceworker.js"
157
+ match "/manifest.json"
158
+ end
159
+ end
160
+ ```
161
+
162
+ #### Test the setup
163
+
164
+ At this point, restart your Rails app and reload a page in your app in Chrome or Firefox. Using dev tools, you should be able to determine.
165
+
166
+ 1. The page requests a service worker at `/serviceworker.js`
167
+ 2. The Rails app responds to the request by compiling and rendering the file in `app/assets/javascripts/serviceworker.js.erb`.
168
+ 3. The console displays messages from the page and the service worker
169
+ 4. The application JavaScript and CSS assets are added to the browser's request/response [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache).
170
+
171
+ #### Using the cache
172
+
173
+ So far so good? At this point, all we've done is pre-fetched assets and added them to the cache, but we're not doing anything with them yet.
174
+
175
+ Now, we can use the service worker to intercept requests and either serve them from the cache if they exist there or fallback to the network response otherwise. In most cases, we can expect responses coming from the local cache to be much faster than those coming from the network.
176
+
177
+ (...more coming soon, WIP)
178
+
179
+ ## Configuration
180
+
181
+ When `serviceworker-rails` is required in your Gemfile, it will insert a middleware into the Rails
33
182
  middleware stack. You'll want to configure it by mapping serviceworker routes to
34
- Sprockets JavaScript assets, like the example below, in `application.rb`.
183
+ Sprockets JavaScript assets in an initializer, like the example below.
35
184
 
36
185
  ```ruby
37
- # application.rb
186
+ # config/initializers/serviceworker.rb
187
+
188
+ Rails.application.configure do
189
+ config.serviceworker.routes.draw do
190
+ # maps to asset named 'serviceworker.js' implicitly
191
+ match "/serviceworker.js"
38
192
 
39
- config.serviceworker.routes.draw do
40
- match "/basic-serviceworker.js"
193
+ # map to a named asset explicitly
194
+ match "/proxied-serviceworker.js" => "nested/asset/serviceworker.js"
195
+ match "/nested/serviceworker.js" => "another/serviceworker.js"
41
196
 
42
- match "/proxied-serviceworker.js" => "nested/asset/serviceworker.js"
197
+ # capture named path segments and interpolate to asset name
198
+ match "/captures/*segments/serviceworker.js" => "%{segments}/serviceworker.js"
43
199
 
44
- match "/nested/serviceworker.js" => "another/serviceworker.js"
200
+ # capture named parameter and interpolate to asset name
201
+ match "/parameter/:id/serviceworker.js" => "project/%{id}/serviceworker.js"
45
202
 
46
- match "/header-serviceworker.js" => "another/serviceworker.js",
47
- headers: { "X-Resource-Header" => "A resource" }
203
+ # insert custom headers
204
+ match "/header-serviceworker.js" => "another/serviceworker.js",
205
+ headers: { "X-Resource-Header" => "A resource" }
48
206
 
49
- match "/*/serviceworker.js" => "serviceworker.js"
207
+ # anonymous glob exposes `paths` variable for interpolation
208
+ match "/*/serviceworker.js" => "%{paths}/serviceworker.js"
209
+ end
50
210
  end
51
211
  ```
52
212
 
53
- `Serviceworker::Rails` with insert a `Cache-Control` header to instruct browsers
213
+ `Serviceworker::Rails` will insert a `Cache-Control` header to instruct browsers
54
214
  not to cache your serviceworkers by default. You can customize the headers for all service worker routes if you'd like,
55
215
  such as adding the experimental [`Service-Worker-Allowed`](https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-allowed) header to set the allowed scope.
56
216
 
@@ -59,15 +219,9 @@ config.serviceworker.headers["Service-Worker-Allowed"] = "/"
59
219
  config.serviceworker.headers["X-Custom-Header"] = "foobar"
60
220
  ```
61
221
 
62
- ### Demo
63
-
64
- Check out the demo application, [Service Worker on Rails](https://serviceworker-rails.herokuapp.com/), to see various examples of using Service Workers in a Rails app.
65
-
66
222
  ## Development
67
223
 
68
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
69
-
70
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
224
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rake` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
71
225
 
72
226
  ## Contributing
73
227
 
data/Rakefile CHANGED
@@ -1,15 +1,16 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
+ require "rubocop/rake_task"
3
4
 
4
5
  APP_RAKEFILE = File.expand_path("../test/sample/Rakefile", __FILE__)
5
6
  load "rails/tasks/engine.rake"
6
7
 
7
- Bundler::GemHelper.install_tasks
8
+ RuboCop::RakeTask.new
8
9
 
9
10
  Rake::TestTask.new(:test) do |t|
10
11
  t.libs << "test"
11
12
  t.libs << "lib"
12
- t.test_files = FileList['test/**/*_test.rb']
13
+ t.test_files = FileList["test/**/*_test.rb"]
13
14
  end
14
15
 
15
- task :default => :test
16
+ task default: [:test, :rubocop]
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # This file was generated by Bundler.
4
4
  #
5
- # The application 'rspec' is installed as part of a gem, and
5
+ # The application 'rubocop' is installed as part of a gem, and
6
6
  # this file is here to facilitate running it.
7
7
  #
8
8
 
@@ -13,4 +13,4 @@ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
13
  require "rubygems"
14
14
  require "bundler/setup"
15
15
 
16
- load Gem.bin_path("rspec-core", "rspec")
16
+ load Gem.bin_path("rubocop", "rubocop")
@@ -0,0 +1,73 @@
1
+ require "rails/generators"
2
+
3
+ module Serviceworker
4
+ module Generators
5
+ class InstallGenerator < ::Rails::Generators::Base
6
+ desc "Make your Rails app a progressive web app"
7
+ source_root File.join(File.dirname(__FILE__), "templates")
8
+
9
+ def create_assets
10
+ template "serviceworker.js",
11
+ File.join(javascripts_base_dir, "serviceworker.js")
12
+ template "serviceworker-companion.js",
13
+ File.join(javascripts_base_dir, "serviceworker-companion.js")
14
+ template "manifest.json",
15
+ File.join(javascripts_base_dir, "manifest.json")
16
+ end
17
+
18
+ def create_initializer
19
+ template "serviceworker.rb",
20
+ File.join(initializers_dir, "serviceworker.rb")
21
+ end
22
+
23
+ def update_application_js
24
+ ext, directive = detect_js_format
25
+ append_to_file application_js_path(ext), "#{directive} require serviceworker-companion\n"
26
+ end
27
+
28
+ def update_precompiled_assets
29
+ append_to_file File.join(initializers_dir, "assets.rb"),
30
+ "Rails.configuration.assets.precompile += %w[serviceworker.js]\n"
31
+ end
32
+
33
+ def update_application_layout
34
+ insert_into_file detect_layout,
35
+ %(<link rel="manifest" href="/manifest.json" />),
36
+ before: "</head>\n"
37
+ end
38
+
39
+ private
40
+
41
+ def application_js_path(ext)
42
+ File.join(javascripts_base_dir, "application#{ext}")
43
+ end
44
+
45
+ def detect_js_format
46
+ %w[.coffee .coffee.erb .js.coffee .js.coffee.erb .js .js.erb].each do |ext|
47
+ next unless File.exist?(File.join(javascripts_base_dir, "application#{ext}"))
48
+ return [ext, "#="] if ext.include?(".coffee")
49
+ return [ext, "//="]
50
+ end
51
+ end
52
+
53
+ def detect_layout
54
+ layouts = %w[.html.erb .html.haml .html.slim].map do |ext|
55
+ File.join(layouts_base_dir, "application#{ext}")
56
+ end
57
+ layouts.find { |layout| File.exist?(layout) }
58
+ end
59
+
60
+ def javascripts_base_dir
61
+ File.join("app", "assets", "javascripts")
62
+ end
63
+
64
+ def initializers_dir
65
+ File.join("config", "initializers")
66
+ end
67
+
68
+ def layouts_base_dir
69
+ File.join("app", "views", "layouts")
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "My Progressive Rails App",
3
+ "short_name": "Progressive",
4
+ "start_url": "/",
5
+ "icons": [
6
+ {
7
+ "src": "/icons/icon36.png",
8
+ "sizes": "36x36",
9
+ "type": "image/png"
10
+ },
11
+ {
12
+ "src": "/icons/icon48.png",
13
+ "sizes": "48x48",
14
+ "type": "image/png"
15
+ },
16
+ {
17
+ "src": "/icons/icon60.png",
18
+ "sizes": "60x60",
19
+ "type": "image/png"
20
+ },
21
+ {
22
+ "src": "/icons/icon72.png",
23
+ "sizes": "72x72",
24
+ "type": "image/png"
25
+ },
26
+ {
27
+ "src": "/icons/icon76.png",
28
+ "sizes": "76x76",
29
+ "type": "image/png"
30
+ },
31
+ {
32
+ "src": "/icons/icon96.png",
33
+ "sizes": "96x96",
34
+ "type": "image/png"
35
+ },
36
+ {
37
+ "src": "/icons/icon120.png",
38
+ "sizes": "120x120",
39
+ "type": "image/png"
40
+ },
41
+ {
42
+ "src": "/icons/icon152.png",
43
+ "sizes": "152x152",
44
+ "type": "image/png"
45
+ },
46
+ {
47
+ "src": "/icons/icon180.png",
48
+ "sizes": "180x180",
49
+ "type": "image/png"
50
+ },
51
+ {
52
+ "src": "/icons/icon192.png",
53
+ "sizes": "192x192",
54
+ "type": "image/png"
55
+ },
56
+ {
57
+ "src": "/icons/icon512.png",
58
+ "sizes": "512x512",
59
+ "type": "image/png"
60
+ }
61
+ ],
62
+ "theme_color": "#000000",
63
+ "background_color": "#FFFFFF",
64
+ "display": "fullscreen",
65
+ "orientation": "portrait"
66
+ }
@@ -0,0 +1,6 @@
1
+ if (navigator.serviceWorker) {
2
+ navigator.serviceWorker.register('/serviceworker.js', { scope: './' })
3
+ .then(function(reg) {
4
+ console.log('[Companion]', 'Service worker registered!');
5
+ });
6
+ }
@@ -0,0 +1,14 @@
1
+ function onInstall() {
2
+ console.log('[Serviceworker]', "Installing!");
3
+ }
4
+
5
+ function onActivate() {
6
+ console.log('[Serviceworker]', "Activating!");
7
+ }
8
+
9
+ function onFetch() {
10
+ }
11
+
12
+ self.addEventListener('install', onInstall);
13
+ self.addEventListener('activate', onActivate);
14
+ self.addEventListener('fetch', onFetch);
@@ -0,0 +1,26 @@
1
+ Rails.application.configure do
2
+ config.serviceworker.routes.draw do
3
+ # map to assets implicitly
4
+ match "/serviceworker.js"
5
+ match "/manifest.json"
6
+
7
+ # Examples
8
+ #
9
+ # map to a named asset explicitly
10
+ # match "/proxied-serviceworker.js" => "nested/asset/serviceworker.js"
11
+ # match "/nested/serviceworker.js" => "another/serviceworker.js"
12
+ #
13
+ # capture named path segments and interpolate to asset name
14
+ # match "/captures/*segments/serviceworker.js" => "%{segments}/serviceworker.js"
15
+ #
16
+ # capture named parameter and interpolate to asset name
17
+ # match "/parameter/:id/serviceworker.js" => "project/%{id}/serviceworker.js"
18
+ #
19
+ # insert custom headers
20
+ # match "/header-serviceworker.js" => "another/serviceworker.js",
21
+ # headers: { "X-Resource-Header" => "A resource" }
22
+ #
23
+ # anonymous glob exposes `paths` variable for interpolation
24
+ # match "/*/serviceworker.js" => "%{paths}/serviceworker.js"
25
+ end
26
+ end
@@ -0,0 +1 @@
1
+ require "serviceworker"
@@ -1,2 +1,3 @@
1
+ # rubocop:disable Style/FileName
1
2
  require "serviceworker"
2
3
  require "serviceworker/rails"
@@ -0,0 +1,21 @@
1
+ module ServiceWorker
2
+ class Handler
3
+ def initialize(root = Dir.getwd)
4
+ @root = root
5
+ end
6
+
7
+ def call(env)
8
+ path_info = env.fetch("serviceworker.asset_name")
9
+
10
+ file_server.call(env.merge("PATH_INFO" => path_info))
11
+ end
12
+
13
+ def file_path(path_info)
14
+ @root.join(path_info)
15
+ end
16
+
17
+ def file_server
18
+ @file_server ||= ::Rack::File.new(@root)
19
+ end
20
+ end
21
+ end
@@ -5,16 +5,26 @@ module ServiceWorker
5
5
  GET = "GET".freeze
6
6
  HEAD = "HEAD".freeze
7
7
 
8
+ # Initialize the Rack middleware for responding to serviceworker asset
9
+ # requests
10
+ #
11
+ # @app [#call] middleware stack
12
+ # @opts [Hash] options to inject
13
+ # @param opts [#match_route] :routes matches routes on PATH_INFO
14
+ # @param opts [Hash] :headers default headers to use for matched routes
15
+ # @param opts [#call] :handler resolves response from matched asset name
16
+ # @param opts [#info] :logger logs requests
8
17
  def initialize(app, opts = {})
9
18
  @app = app
10
19
  @opts = opts
11
20
  @headers = opts.fetch(:headers, {}).merge(default_headers)
12
21
  @router = opts.fetch(:routes, ServiceWorker::Router.new)
22
+ @handler = @opts.fetch(:handler, default_handler)
13
23
  end
14
24
 
15
25
  def call(env)
16
26
  case env[REQUEST_METHOD]
17
- when GET, HEAD
27
+ when GET, HEAD
18
28
  route_match = @router.match_route(env)
19
29
  return respond_to_match(route_match, env) if route_match
20
30
  end
@@ -22,7 +32,7 @@ module ServiceWorker
22
32
  @app.call(env)
23
33
  end
24
34
 
25
- private
35
+ private
26
36
 
27
37
  def default_headers
28
38
  {
@@ -33,7 +43,7 @@ module ServiceWorker
33
43
  def respond_to_match(route_match, env)
34
44
  env = env.merge("serviceworker.asset_name" => route_match.asset_name)
35
45
 
36
- status, headers, body = handler.call(env)
46
+ status, headers, body = @handler.call(env)
37
47
 
38
48
  [status, headers.merge(@headers).merge(route_match.headers), body]
39
49
  end
@@ -42,14 +52,13 @@ module ServiceWorker
42
52
  logger.info "[#{self.class}] - #{msg}"
43
53
  end
44
54
 
45
- # TODO
46
- # provide non-rails handler as default
47
- def handler
48
- @handler ||= @opts.fetch(:handler)
49
- end
50
-
51
55
  def logger
52
56
  @logger ||= @opts.fetch(:logger, Logger.new(STDOUT))
53
57
  end
58
+
59
+ def default_handler
60
+ require "serviceworker/handler"
61
+ ServiceWorker::Handler.new
62
+ end
54
63
  end
55
64
  end
@@ -13,7 +13,7 @@ module ServiceWorker
13
13
  end
14
14
  end
15
15
 
16
- private
16
+ private
17
17
 
18
18
  def sprockets_server
19
19
  ::Rails.application.assets
@@ -1,5 +1,5 @@
1
1
  module ServiceWorker
2
2
  module Rails
3
- VERSION = "0.3.1"
3
+ VERSION = "0.4.0".freeze
4
4
  end
5
5
  end
@@ -20,9 +20,7 @@ module ServiceWorker
20
20
  end
21
21
 
22
22
  def match(path)
23
- if path.to_s.strip.empty?
24
- raise ArgumentError.new("path is required")
25
- end
23
+ raise ArgumentError, "path is required" if path.to_s.strip.empty?
26
24
 
27
25
  asset = resolver.call(path) or return nil
28
26
 
@@ -40,11 +38,11 @@ module ServiceWorker
40
38
  end
41
39
 
42
40
  class AssetResolver
43
- PATH_INFO = 'PATH_INFO'.freeze
41
+ PATH_INFO = "PATH_INFO".freeze
44
42
  DEFAULT_WILDCARD_NAME = :paths
45
- WILDCARD_PATTERN = /\/\*([^\/]*)/.freeze
46
- NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([^:$\/]+)/.freeze
47
- LEADING_SLASH_PATTERN = /^\//
43
+ WILDCARD_PATTERN = %r{\/\*([^\/]*)}
44
+ NAMED_SEGMENTS_PATTERN = %r{\/([^\/]*):([^:$\/]+)}
45
+ LEADING_SLASH_PATTERN = %r{^\/}
48
46
  INTERPOLATION_PATTERN = Regexp.union(
49
47
  /%%/,
50
48
  /%\{(\w+)\}/, # matches placeholders like "%{foo}"
@@ -58,9 +56,7 @@ module ServiceWorker
58
56
  end
59
57
 
60
58
  def call(path)
61
- if path.to_s.strip.empty?
62
- raise ArgumentError.new("path is required")
63
- end
59
+ raise ArgumentError, "path is required" if path.to_s.strip.empty?
64
60
 
65
61
  captures = path_captures(regexp, path) or return nil
66
62
 
@@ -78,15 +74,16 @@ module ServiceWorker
78
74
  end
79
75
 
80
76
  def compiled_source(pattern)
81
- if pattern_match = pattern.match(WILDCARD_PATTERN)
77
+ pattern_match = pattern.match(WILDCARD_PATTERN)
78
+ if pattern_match
82
79
  @wildcard_name = if pattern_match[1].to_s.strip.empty?
83
80
  DEFAULT_WILDCARD_NAME
84
81
  else
85
82
  pattern_match[1].to_sym
86
83
  end
87
- pattern.gsub(WILDCARD_PATTERN,'(?:/(.*)|)')
84
+ pattern.gsub(WILDCARD_PATTERN, "(?:/(.*)|)")
88
85
  else
89
- p = if pattern_match = pattern.match(NAMED_SEGMENTS_PATTERN)
86
+ p = if pattern.match(NAMED_SEGMENTS_PATTERN)
90
87
  pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^.$/]+)')
91
88
  else
92
89
  pattern
@@ -96,29 +93,25 @@ module ServiceWorker
96
93
  end
97
94
 
98
95
  def path_captures(regexp, path)
99
- return nil unless path_match = path.match(regexp)
96
+ path_match = path.match(regexp) or return nil
100
97
  params = if @wildcard_name
101
- { @wildcard_name => path_match[1].to_s.split('/') }
98
+ { @wildcard_name => path_match[1].to_s.split("/") }
102
99
  else
103
100
  Hash[path_match.names.map(&:to_sym).zip(path_match.captures)]
104
101
  end
105
- params.delete(:format) if params.has_key?(:format) && params[:format].nil?
102
+ params.delete(:format) if params.key?(:format) && params[:format].nil?
106
103
  params
107
104
  end
108
105
 
109
106
  def interpolate_captures(string, captures)
110
107
  string.gsub(INTERPOLATION_PATTERN) do |match|
111
- if match == '%%'
112
- '%'
108
+ if match == "%%"
109
+ "%"
113
110
  else
114
- key = ($1 || $2).to_sym
115
- value = if captures.key?(key)
116
- Array(captures[key]).join("/")
117
- else
118
- raise "Interpolation error: #{key} not captured in #{captures.inspect}"
119
- end
111
+ key = (Regexp.last_match(1) || Regexp.last_match(2)).to_sym
112
+ value = captures.key?(key) ? Array(captures[key]).join("/") : key
120
113
  value = value.call(captures) if value.respond_to?(:call)
121
- $3 ? sprintf("%#{$3}", value) : value
114
+ Regexp.last_match(3) ? format("%#{Regexp.last_match(3)}", value) : value
122
115
  end
123
116
  end.gsub(LEADING_SLASH_PATTERN, "")
124
117
  end
@@ -19,7 +19,7 @@ module ServiceWorker
19
19
  return self unless block_given?
20
20
 
21
21
  if block.arity == 1
22
- block.call(self)
22
+ yield(self)
23
23
  else
24
24
  instance_eval(&block)
25
25
  end
@@ -51,9 +51,7 @@ module ServiceWorker
51
51
  def match_route(env)
52
52
  path = env[PATH_INFO]
53
53
  @routes.each do |route|
54
- if match = route.match(path)
55
- return match
56
- end
54
+ match = route.match(path) and return match
57
55
  end
58
56
  nil
59
57
  end
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
2
+ lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'serviceworker/rails/version'
4
+ require "serviceworker/rails/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "serviceworker-rails"
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Ross Kaffenberger"]
10
10
  spec.email = ["rosskaff@gmail.com"]
11
11
 
12
- spec.summary = %q{ServiceWorker for Rails 3+}
13
- spec.description = %q{Integrates ServiceWorker into the Rails asset pipeline.}
12
+ spec.summary = "ServiceWorker for Rails 3+"
13
+ spec.description = "Integrates ServiceWorker into the Rails asset pipeline."
14
14
  spec.homepage = "https://github.com/rossta/serviceworker-rails"
15
15
  spec.license = "MIT"
16
16
 
@@ -26,4 +26,5 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "rake", "~> 10.0"
27
27
  spec.add_development_dependency "minitest", "~> 5.0"
28
28
  spec.add_development_dependency "rack-test"
29
+ spec.add_development_dependency "rails"
29
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serviceworker-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ross Kaffenberger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-05-03 00:00:00.000000000 Z
11
+ date: 2016-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  description: Integrates ServiceWorker into the Rails asset pipeline.
98
112
  email:
99
113
  - rosskaff@gmail.com
@@ -102,6 +116,7 @@ extensions: []
102
116
  extra_rdoc_files: []
103
117
  files:
104
118
  - ".gitignore"
119
+ - ".rubocop.yml"
105
120
  - ".travis.yml"
106
121
  - CHANGELOG.md
107
122
  - CODE_OF_CONDUCT.md
@@ -114,10 +129,17 @@ files:
114
129
  - bin/console
115
130
  - bin/guard
116
131
  - bin/rake
117
- - bin/rspec
132
+ - bin/rubocop
118
133
  - bin/setup
134
+ - lib/generators/serviceworker/install_generator.rb
135
+ - lib/generators/serviceworker/templates/manifest.json
136
+ - lib/generators/serviceworker/templates/serviceworker-companion.js
137
+ - lib/generators/serviceworker/templates/serviceworker.js
138
+ - lib/generators/serviceworker/templates/serviceworker.rb
139
+ - lib/service_worker.rb
119
140
  - lib/serviceworker-rails.rb
120
141
  - lib/serviceworker.rb
142
+ - lib/serviceworker/handler.rb
121
143
  - lib/serviceworker/middleware.rb
122
144
  - lib/serviceworker/rails.rb
123
145
  - lib/serviceworker/rails/handler.rb
@@ -146,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
168
  version: '0'
147
169
  requirements: []
148
170
  rubyforge_project:
149
- rubygems_version: 2.5.1
171
+ rubygems_version: 2.4.5.1
150
172
  signing_key:
151
173
  specification_version: 4
152
174
  summary: ServiceWorker for Rails 3+