serviceworker-rails 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/Gemfile +7 -3
- data/README.md +11 -13
- data/lib/serviceworker/middleware.rb +13 -12
- data/lib/serviceworker/rails/handler.rb +3 -1
- data/lib/serviceworker/rails/version.rb +1 -1
- data/lib/serviceworker/route.rb +106 -28
- data/lib/serviceworker/router.rb +20 -5
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c1a7fe0cb0777d62d399186270fd11a4965ed77
|
4
|
+
data.tar.gz: 24f12fd53135a6dc7a5ebbfaa8b73a39af9b5e1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a38f837ac9dab05e34edbee772b98ca12959bed7851ad0ca7f8537eabc768cc5f5cac5a053c00605a3d72ace70c7520bd5bc0b1cda7a5dcd765f16193c5e65d6
|
7
|
+
data.tar.gz: 5db0e5eaf38682d447786a4950cc1e65b893052e5fe52b76016f4a5dc464ea82e059896df07f2144e79dbd13c023e2c13ccf4ce63bd1bb0254869e9ccfa2539a
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -3,6 +3,10 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in serviceworker-rails.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
gem "
|
6
|
+
group :development, :test do
|
7
|
+
unless ENV["TRAVIS"]
|
8
|
+
gem "pry-byebug", platforms: [:ruby_23]
|
9
|
+
gem "guard"
|
10
|
+
gem "guard-minitest"
|
11
|
+
end
|
12
|
+
end
|
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# ServiceWorker::Rails
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/rossta/serviceworker-rails)
|
4
|
+
|
5
|
+
Use [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) with the Rails asset pipeline.
|
4
6
|
|
5
7
|
## Features
|
6
8
|
|
7
|
-
*
|
8
|
-
* Adds appropriate response headers to service
|
9
|
+
* Maps service worker endpoints to Rails assets
|
10
|
+
* Adds appropriate response headers to service workers
|
9
11
|
* Renders compiled source in production and development
|
10
12
|
|
11
13
|
## Installation
|
@@ -35,24 +37,20 @@ Sprockets JavaScript assets, like the example below, in `application.rb`.
|
|
35
37
|
# application.rb
|
36
38
|
|
37
39
|
config.serviceworker.routes.draw do
|
38
|
-
|
40
|
+
match "/basic-serviceworker.js"
|
39
41
|
|
40
|
-
|
41
|
-
asset: "nested/asset/serviceworker.js"
|
42
|
+
match "/proxied-serviceworker.js" => "nested/asset/serviceworker.js"
|
42
43
|
|
43
|
-
|
44
|
-
asset: "another/serviceworker.js"
|
44
|
+
match "/nested/serviceworker.js" => "another/serviceworker.js"
|
45
45
|
|
46
|
-
|
47
|
-
asset: "another/serviceworker.js",
|
46
|
+
match "/header-serviceworker.js" => "another/serviceworker.js",
|
48
47
|
headers: { "X-Resource-Header" => "A resource" }
|
49
48
|
|
50
|
-
|
51
|
-
asset: "serviceworker.js"
|
49
|
+
match "/*/serviceworker.js" => "serviceworker.js"
|
52
50
|
end
|
53
51
|
```
|
54
52
|
|
55
|
-
`Serviceworker
|
53
|
+
`Serviceworker::Rails` with insert a `Cache-Control` header to instruct browsers
|
56
54
|
not to cache your serviceworkers by default. You can customize the headers for all service worker routes if you'd like,
|
57
55
|
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.
|
58
56
|
|
@@ -1,5 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ServiceWorker
|
2
3
|
class Middleware
|
4
|
+
REQUEST_METHOD = "REQUEST_METHOD".freeze
|
5
|
+
GET = "GET".freeze
|
6
|
+
HEAD = "HEAD".freeze
|
7
|
+
|
3
8
|
def initialize(app, opts = {})
|
4
9
|
@app = app
|
5
10
|
@opts = opts
|
@@ -8,12 +13,10 @@ module ServiceWorker
|
|
8
13
|
end
|
9
14
|
|
10
15
|
def call(env)
|
11
|
-
case env[
|
12
|
-
when
|
13
|
-
|
14
|
-
|
15
|
-
route = @router.match_route(path)
|
16
|
-
return respond_to_route(route, env) if route
|
16
|
+
case env[REQUEST_METHOD]
|
17
|
+
when GET, HEAD
|
18
|
+
route_match = @router.match_route(env)
|
19
|
+
return respond_to_match(route_match, env) if route_match
|
17
20
|
end
|
18
21
|
|
19
22
|
@app.call(env)
|
@@ -27,14 +30,12 @@ module ServiceWorker
|
|
27
30
|
}
|
28
31
|
end
|
29
32
|
|
30
|
-
def
|
31
|
-
|
33
|
+
def respond_to_match(route_match, env)
|
34
|
+
env = env.merge("serviceworker.asset_name" => route_match.asset_name)
|
32
35
|
|
33
|
-
|
34
|
-
end
|
36
|
+
status, headers, body = handler.call(env)
|
35
37
|
|
36
|
-
|
37
|
-
handler.call(env.merge("serviceworker.asset_name" => route.asset_name))
|
38
|
+
[status, headers.merge(@headers).merge(route_match.headers), body]
|
38
39
|
end
|
39
40
|
|
40
41
|
def info(msg)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "rack/file"
|
2
|
+
|
1
3
|
module ServiceWorker
|
2
4
|
module Rails
|
3
5
|
class Handler
|
@@ -18,7 +20,7 @@ module ServiceWorker
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def file_server
|
21
|
-
@file_server ||= ::Rack::File.new(::Rails.
|
23
|
+
@file_server ||= ::Rack::File.new(::Rails.public_path)
|
22
24
|
end
|
23
25
|
|
24
26
|
def config
|
data/lib/serviceworker/route.rb
CHANGED
@@ -1,22 +1,32 @@
|
|
1
1
|
module ServiceWorker
|
2
2
|
class Route
|
3
|
-
attr_reader :
|
3
|
+
attr_reader :path_pattern, :asset_pattern, :options
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@pattern = compile(path)
|
5
|
+
RouteMatch = Struct.new(:path, :asset_name, :headers) do
|
6
|
+
def to_s
|
7
|
+
asset_name
|
8
|
+
end
|
10
9
|
end
|
11
10
|
|
12
|
-
def
|
13
|
-
|
11
|
+
def initialize(path_pattern, asset_pattern = nil, options = {})
|
12
|
+
if asset_pattern.is_a?(Hash)
|
13
|
+
options = asset_pattern
|
14
|
+
asset_pattern = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
@path_pattern = path_pattern
|
18
|
+
@asset_pattern = asset_pattern || options[:asset] || path_pattern
|
19
|
+
@options = options
|
14
20
|
end
|
15
21
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
def match(path)
|
23
|
+
if path.to_s.strip.empty?
|
24
|
+
raise ArgumentError.new("path is required")
|
25
|
+
end
|
26
|
+
|
27
|
+
asset = resolver.call(path) or return nil
|
28
|
+
|
29
|
+
RouteMatch.new(path, asset, headers)
|
20
30
|
end
|
21
31
|
|
22
32
|
def headers
|
@@ -25,24 +35,92 @@ module ServiceWorker
|
|
25
35
|
|
26
36
|
private
|
27
37
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
def resolver
|
39
|
+
@resolver ||= AssetResolver.new(path_pattern, asset_pattern)
|
40
|
+
end
|
41
|
+
|
42
|
+
class AssetResolver
|
43
|
+
PATH_INFO = 'PATH_INFO'.freeze
|
44
|
+
DEFAULT_WILDCARD_NAME = :paths
|
45
|
+
WILDCARD_PATTERN = /\/\*([^\/]*)/.freeze
|
46
|
+
NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([^:$\/]+)/.freeze
|
47
|
+
LEADING_SLASH_PATTERN = /^\//
|
48
|
+
INTERPOLATION_PATTERN = Regexp.union(
|
49
|
+
/%%/,
|
50
|
+
/%\{(\w+)\}/, # matches placeholders like "%{foo}"
|
51
|
+
)
|
52
|
+
|
53
|
+
attr_reader :path_pattern, :asset_pattern
|
54
|
+
|
55
|
+
def initialize(path_pattern, asset_pattern)
|
56
|
+
@path_pattern = path_pattern
|
57
|
+
@asset_pattern = asset_pattern
|
58
|
+
end
|
59
|
+
|
60
|
+
def call(path)
|
61
|
+
if path.to_s.strip.empty?
|
62
|
+
raise ArgumentError.new("path is required")
|
63
|
+
end
|
64
|
+
|
65
|
+
captures = path_captures(regexp, path) or return nil
|
66
|
+
|
67
|
+
interpolate_captures(asset_pattern, captures)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def regexp
|
73
|
+
@regexp ||= compile_regexp(path_pattern)
|
74
|
+
end
|
75
|
+
|
76
|
+
def compile_regexp(pattern)
|
77
|
+
Regexp.new("\\A#{compiled_source(pattern)}\\Z")
|
78
|
+
end
|
79
|
+
|
80
|
+
def compiled_source(pattern)
|
81
|
+
if pattern_match = pattern.match(WILDCARD_PATTERN)
|
82
|
+
@wildcard_name = if pattern_match[1].to_s.strip.empty?
|
83
|
+
DEFAULT_WILDCARD_NAME
|
84
|
+
else
|
85
|
+
pattern_match[1].to_sym
|
86
|
+
end
|
87
|
+
pattern.gsub(WILDCARD_PATTERN,'(?:/(.*)|)')
|
88
|
+
else
|
89
|
+
p = if pattern_match = pattern.match(NAMED_SEGMENTS_PATTERN)
|
90
|
+
pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^.$/]+)')
|
91
|
+
else
|
92
|
+
pattern
|
93
|
+
end
|
94
|
+
p + '(?:\.(?<format>.*))?'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def path_captures(regexp, path)
|
99
|
+
return nil unless path_match = path.match(regexp)
|
100
|
+
params = if @wildcard_name
|
101
|
+
{ @wildcard_name => path_match[1].to_s.split('/') }
|
102
|
+
else
|
103
|
+
Hash[path_match.names.map(&:to_sym).zip(path_match.captures)]
|
104
|
+
end
|
105
|
+
params.delete(:format) if params.has_key?(:format) && params[:format].nil?
|
106
|
+
params
|
107
|
+
end
|
108
|
+
|
109
|
+
def interpolate_captures(string, captures)
|
110
|
+
string.gsub(INTERPOLATION_PATTERN) do |match|
|
111
|
+
if match == '%%'
|
112
|
+
'%'
|
37
113
|
else
|
38
|
-
|
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
|
120
|
+
value = value.call(captures) if value.respond_to?(:call)
|
121
|
+
$3 ? sprintf("%#{$3}", value) : value
|
39
122
|
end
|
40
|
-
end
|
41
|
-
/^#{pattern}$/
|
42
|
-
elsif path.respond_to?(:match)
|
43
|
-
path
|
44
|
-
else
|
45
|
-
raise TypeError, path
|
123
|
+
end.gsub(LEADING_SLASH_PATTERN, "")
|
46
124
|
end
|
47
125
|
end
|
48
126
|
end
|
data/lib/serviceworker/router.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ServiceWorker
|
2
3
|
class Router
|
4
|
+
PATH_INFO = "PATH_INFO".freeze
|
5
|
+
|
3
6
|
def self.default
|
4
7
|
new.draw_default
|
5
8
|
end
|
@@ -28,19 +31,31 @@ module ServiceWorker
|
|
28
31
|
draw { get "/serviceworker.js" }
|
29
32
|
end
|
30
33
|
|
31
|
-
def
|
32
|
-
|
34
|
+
def match(path, *args)
|
35
|
+
if path.is_a?(Hash)
|
36
|
+
opts = path.to_a
|
37
|
+
path, asset = opts.shift
|
38
|
+
args = [asset, opts.to_h]
|
39
|
+
end
|
40
|
+
|
41
|
+
Route.new(path, *args).tap do |route|
|
33
42
|
@routes << route
|
34
43
|
end
|
35
44
|
end
|
45
|
+
alias get match
|
36
46
|
|
37
47
|
def any?
|
38
48
|
@routes.any?
|
39
49
|
end
|
40
50
|
|
41
|
-
def match_route(
|
42
|
-
|
51
|
+
def match_route(env)
|
52
|
+
path = env[PATH_INFO]
|
53
|
+
@routes.each do |route|
|
54
|
+
if match = route.match(path)
|
55
|
+
return match
|
56
|
+
end
|
57
|
+
end
|
58
|
+
nil
|
43
59
|
end
|
44
60
|
end
|
45
|
-
|
46
61
|
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.
|
4
|
+
version: 0.3.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-
|
11
|
+
date: 2016-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -145,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
145
|
version: '0'
|
146
146
|
requirements: []
|
147
147
|
rubyforge_project:
|
148
|
-
rubygems_version: 2.
|
148
|
+
rubygems_version: 2.2.3
|
149
149
|
signing_key:
|
150
150
|
specification_version: 4
|
151
151
|
summary: ServiceWorker for Rails 3+
|