rack-zippy 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 2.0.1 / 2014-12-15
2
+ - New `:max_age_fallback` (in seconds) option
3
+
1
4
  ## 2.0.0 / 2014-12-07
2
5
  - Rack Zippy now works cleanly with all Rack apps, including Rails apps ([#23](https://github.com/eliotsykes/rack-zippy/issues/23))
3
6
  - Decomposed AssetServer into AssetServer, ServeableFile, and AssetCompiler classes
data/README.md CHANGED
@@ -66,6 +66,24 @@ In `config.ru`:
66
66
  Follow the installation instructions above and rack-zippy will serve any static assets, including gzipped assets, from your
67
67
  application's public/ directory and will respond with sensible caching headers.
68
68
 
69
+ ### Options
70
+
71
+ #### max_age_fallback
72
+
73
+ `max_age_fallback`, is an integer value in seconds that should be used as the max_age fallback for files served by rack-zippy that live **outside** the `/assets` subdirectory *and* aren't `/favicon.ico`.
74
+
75
+ A typical use for `max_age_fallback` is to define how long the cache lifetime for static HTML files served by rack-zippy should be. For one of my sites I have this set to 10 minutes:
76
+
77
+ ```ruby
78
+ max_age_in_secs = 10*60 # 10 mins = 600 secs
79
+ use Rack::Zippy::AssetServer, asset_root, max_age_fallback: max_age_in_secs
80
+ ```
81
+
82
+ Any files given the `max_age_fallback` would have the following `Cache-Control` header:
83
+
84
+ ```
85
+ Cache-Control: public, max-age=600
86
+ ```
69
87
 
70
88
  ## Troubleshooting
71
89
 
@@ -75,6 +93,12 @@ Check your environment (in config/environments/) does not have `serve_static_ass
75
93
 
76
94
  config.serve_static_assets = false # Oops! Should be set to true for rack-zippy
77
95
 
96
+ ##### NameError: uninitialized constant Rack::Zippy
97
+
98
+ - Check `Gemfile` doesn't limit rack-zippy to a subset of environment groups
99
+ - Run `bundle install`
100
+ - Check `Gemfile.lock` contains an entry for rack-zippy
101
+
78
102
 
79
103
  ## Contributing
80
104
 
@@ -112,18 +136,19 @@ Cleanup time! When you’re finished testing, delete the local override and set
112
136
 
113
137
  ## Contributors
114
138
 
115
- - [Eliot Sykes](https://github.com/eliotsykes)
116
- - [Kieran Topping](https://github.com/ktopping)
117
- - [Luke Wendling](https://github.com/lukewendling)
139
+ - Eliot Sykes https://eliotsykes.com
140
+ - Kieran Topping https://github.com/ktopping
141
+ - Luke Wendling https://github.com/lukewendling
118
142
 
119
143
 
120
144
  ## Releasing a new gem
121
145
 
122
- 1. Update pre-release version to the release version in lib/rack-zippy/version.rb, e.g. '1.0.1.pre' becomes '1.0.1'
123
- 2. Update CHANGELOG.md and Contributors in README.md
146
+ 1. Update pre-release version to the release version in `lib/rack-zippy/version.rb`, e.g. `1.0.1.pre` becomes `1.0.1`
147
+ 2. Update `CHANGELOG.md` version and date. Update Contributors in `README.md`.
124
148
  3. Tests pass? (`rake test`)
125
149
  4. Build the gem (`rake build`)
126
150
  5. Release on rubygems.org (`rake release`)
127
- 6. Update version to the next pre-release version in lib/rack-zippy/version.rb, e.g. '1.0.1' becomes '1.0.2.pre'.
128
- 7. Commit and push the updated lib/rack-zippy/version.rb.
151
+ 6. Update version to the next pre-release version in `lib/rack-zippy/version.rb`, e.g. `1.0.1` becomes `1.0.2.pre`.
152
+ 7. Add new heading to `CHANGELOG` for the next pre-release
153
+ 8. Commit and push the updated `lib/rack-zippy/version.rb` and `CHANGELOG` files.
129
154
 
data/bin/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
data/lib/rack-zippy.rb CHANGED
@@ -14,7 +14,7 @@ module Rack
14
14
 
15
15
  HTTP_STATUS_CODE_OK = 200
16
16
 
17
- def initialize(app, asset_root=nil)
17
+ def initialize(app, asset_root=nil, options={})
18
18
  if asset_root.nil?
19
19
  if RailsAssetCompiler.rails_env?
20
20
  asset_root = ::Rails.public_path
@@ -24,8 +24,11 @@ module Rack
24
24
  end
25
25
  end
26
26
  @app = app
27
- @asset_root = asset_root
28
- @asset_compiler = resolve_asset_compiler
27
+
28
+ @options = {
29
+ :asset_compiler => resolve_asset_compiler,
30
+ :asset_root => asset_root
31
+ }.merge(options)
29
32
  end
30
33
 
31
34
  def call(env)
@@ -33,12 +36,15 @@ module Rack
33
36
 
34
37
  return not_found_response if path_info =~ ILLEGAL_PATH_REGEX
35
38
 
36
- serveable_file = ServeableFile.find_first(
39
+ serveable_file_options = {
37
40
  :path_info => path_info,
38
- :asset_root => @asset_root,
39
- :asset_compiler => @asset_compiler,
40
- :include_gzipped => client_accepts_gzip?(env)
41
- )
41
+ :asset_root => asset_root,
42
+ :asset_compiler => asset_compiler,
43
+ :include_gzipped => client_accepts_gzip?(env),
44
+ :max_age_fallback => @options[:max_age_fallback]
45
+ }
46
+
47
+ serveable_file = ServeableFile.find_first(serveable_file_options)
42
48
 
43
49
  if serveable_file
44
50
  return [HTTP_STATUS_CODE_OK, serveable_file.headers, serveable_file.response_body]
@@ -47,6 +53,10 @@ module Rack
47
53
  @app.call(env)
48
54
  end
49
55
 
56
+ def asset_root
57
+ @options[:asset_root]
58
+ end
59
+
50
60
  private
51
61
 
52
62
  ACCEPTS_GZIP_REGEX = /\bgzip\b/
@@ -62,6 +72,10 @@ module Rack
62
72
  return asset_compiler_class.new
63
73
  end
64
74
 
75
+ def asset_compiler
76
+ @options[:asset_compiler]
77
+ end
78
+
65
79
  def not_found_response
66
80
  [404, {}, ['Not Found']]
67
81
  end
@@ -11,6 +11,7 @@ module Rack
11
11
  @full_path_info = options[:full_path_info]
12
12
  @has_encoding_variants = options[:has_encoding_variants]
13
13
  @is_gzipped = options[:is_gzipped]
14
+ @max_age_fallback = options[:max_age_fallback] || SECONDS_IN[:day]
14
15
  end
15
16
 
16
17
  def headers
@@ -26,17 +27,17 @@ module Rack
26
27
 
27
28
  def cache_headers
28
29
  case full_path_info
29
- when PRECOMPILED_ASSETS_SUBDIR_REGEX
30
- lifetime = :year
31
- last_modified = CACHE_FRIENDLY_LAST_MODIFIED
32
- when '/favicon.ico'
33
- lifetime = :month
34
- last_modified = CACHE_FRIENDLY_LAST_MODIFIED
35
- else
36
- lifetime = :day
30
+ when PRECOMPILED_ASSETS_SUBDIR_REGEX
31
+ lifetime_in_secs = SECONDS_IN[:year]
32
+ last_modified = CACHE_FRIENDLY_LAST_MODIFIED
33
+ when '/favicon.ico'
34
+ lifetime_in_secs = SECONDS_IN[:month]
35
+ last_modified = CACHE_FRIENDLY_LAST_MODIFIED
36
+ else
37
+ lifetime_in_secs = @max_age_fallback
37
38
  end
38
39
 
39
- headers = { 'Cache-Control' => "public, max-age=#{SECONDS_IN[lifetime]}" }
40
+ headers = { 'Cache-Control' => "public, max-age=#{lifetime_in_secs}" }
40
41
  headers['Last-Modified'] = last_modified if last_modified
41
42
 
42
43
  return headers
@@ -49,7 +50,7 @@ module Rack
49
50
  def self.find_first(options)
50
51
  asset_compiler = options[:asset_compiler]
51
52
  path_info = options[:path_info].chomp('/')
52
-
53
+
53
54
  return nil if asset_compiler.compiles?(path_info)
54
55
 
55
56
  asset_root = options[:asset_root]
@@ -77,20 +78,19 @@ module Rack
77
78
 
78
79
  has_encoding_variants = gzipped_file_present
79
80
 
81
+ init_options = {
82
+ :path => file_path,
83
+ :full_path_info => full_path_info,
84
+ :has_encoding_variants => has_encoding_variants,
85
+ :max_age_fallback => options[:max_age_fallback]
86
+ }
87
+
80
88
  if include_gzipped && gzipped_file_present
81
- return ServeableFile.new(
82
- :path => gzipped_file_path,
83
- :full_path_info => full_path_info,
84
- :has_encoding_variants => has_encoding_variants,
85
- :is_gzipped => true
86
- )
89
+ init_options[:path] = gzipped_file_path
90
+ init_options[:is_gzipped] = true
87
91
  end
88
92
 
89
- return ServeableFile.new(
90
- :path => file_path,
91
- :full_path_info => full_path_info,
92
- :has_encoding_variants => has_encoding_variants
93
- )
93
+ return ServeableFile.new(init_options)
94
94
  end
95
95
 
96
96
  def self.has_static_extension?(path)
@@ -116,15 +116,15 @@ module Rack
116
116
  end
117
117
  alias_method :eql?, :==
118
118
 
119
- private
119
+ private
120
120
 
121
121
  # Old last-modified headers encourage caching via browser heuristics. Use it for year-long cached assets.
122
122
  CACHE_FRIENDLY_LAST_MODIFIED = 'Mon, 10 Jan 2005 10:00:00 GMT'
123
123
 
124
124
  SECONDS_IN = {
125
- :day => 24*60*60,
126
- :month => 31*(24*60*60),
127
- :year => 365*(24*60*60)
125
+ :day => 24*60*60,
126
+ :month => 31*(24*60*60),
127
+ :year => 365*(24*60*60)
128
128
  }.freeze
129
129
 
130
130
  DEFAULT_STATIC_EXTENSION = '.html'.freeze
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  module Zippy
3
- VERSION = '2.0.0'
3
+ VERSION = '2.0.1'
4
4
  end
5
5
  end
@@ -14,6 +14,7 @@ module Rack
14
14
 
15
15
  def teardown
16
16
  revert_to_original_working_directory
17
+ @app = nil
17
18
  end
18
19
 
19
20
  def test_serves_static_file_as_directory
@@ -43,14 +44,12 @@ module Rack
43
44
  end
44
45
 
45
46
  def test_rails_asset_compiler_set_when_rails_environment_detected
46
- asset_compiler = app.instance_variable_get('@asset_compiler')
47
- assert_equal RailsAssetCompiler, asset_compiler.class
47
+ assert_equal RailsAssetCompiler, app.send(:asset_compiler).class
48
48
  end
49
49
 
50
50
  def test_null_asset_compiler_set_when_no_rails_environment_detected
51
51
  exit_rails_env
52
- asset_compiler = app.instance_variable_get('@asset_compiler')
53
- assert_equal NullAssetCompiler, asset_compiler.class
52
+ assert_equal NullAssetCompiler, app.send(:asset_compiler).class
54
53
  end
55
54
 
56
55
  def test_request_for_non_asset_path_beginning_with_assets_dir_name_bypasses_middleware
@@ -255,23 +254,36 @@ module Rack
255
254
 
256
255
  def test_asset_root_constructor_arg_accepts_string
257
256
  asset_server = AssetServer.new(create_rack_app, '/custom/asset/root')
258
- assert_equal '/custom/asset/root', asset_server.instance_variable_get('@asset_root')
257
+ assert_equal '/custom/asset/root', asset_server.asset_root
259
258
  end
260
259
 
261
260
  def test_default_asset_root_is_rails_public_path
262
261
  Rails.public_path = '/unexpected/absolute/path/to/public'
263
262
  asset_server = AssetServer.new(create_rack_app)
264
- assert_equal '/unexpected/absolute/path/to/public', asset_server.instance_variable_get('@asset_root')
263
+ assert_equal '/unexpected/absolute/path/to/public', asset_server.asset_root
264
+ end
265
+
266
+ def test_asset_server_accepts_max_age_fallback_option
267
+ fallback_in_secs = 1234
268
+ @app = AssetServer.new(
269
+ create_rack_app, asset_root, max_age_fallback: fallback_in_secs
270
+ )
271
+
272
+ get '/thanks.html'
273
+ assert_equal "public, max-age=1234", last_response.headers['cache-control']
265
274
  end
266
275
 
267
276
  private
268
277
 
269
278
  def app
279
+ return @app if @app
270
280
  if in_rails_env?
271
- return AssetServer.new(create_rack_app)
281
+ @app = AssetServer.new(create_rack_app)
282
+ else
283
+ # In a pure rack app, non-Rails env
284
+ @app = AssetServer.new(create_rack_app, asset_root)
272
285
  end
273
- # In a pure rack app, non-Rails env
274
- return AssetServer.new(create_rack_app, asset_root)
286
+ return @app
275
287
  end
276
288
 
277
289
  def create_rack_app
@@ -30,6 +30,24 @@ module Rack
30
30
  assert_last_modified cache_headers, nil
31
31
  end
32
32
 
33
+ def test_max_age_fallback_used_for_cache_headers
34
+
35
+ ten_mins_in_secs = 10*60
36
+
37
+ serveable_file = ServeableFile.new(
38
+ :full_path_info => "/thanks.html",
39
+ :path => "#{asset_root}/thanks.html",
40
+ :has_encoding_variants => false,
41
+ :is_gzipped => false,
42
+ :max_age_fallback => ten_mins_in_secs
43
+ )
44
+
45
+ cache_headers = serveable_file.cache_headers
46
+
47
+ assert_cache_max_age cache_headers, ten_mins_in_secs
48
+ assert_last_modified cache_headers, nil
49
+ end
50
+
33
51
  def test_cache_max_age_is_month_for_root_favicon
34
52
  serveable_file = ServeableFile.new(
35
53
  :full_path_info => "/favicon.ico",
@@ -460,7 +478,8 @@ module Rack
460
478
  end
461
479
 
462
480
  def assert_cache_max_age(headers, expected_duration)
463
- assert_equal "public, max-age=#{DURATIONS_IN_SECS[expected_duration]}", headers['Cache-Control']
481
+ duration_in_secs = DURATIONS_IN_SECS[expected_duration] || expected_duration
482
+ assert_equal "public, max-age=#{duration_in_secs}", headers['Cache-Control']
464
483
  end
465
484
 
466
485
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-zippy
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,13 +9,14 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-12-07 00:00:00.000000000 Z
12
+ date: 2014-12-15 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Rack middleware for serving static gzipped assets generated by the Rails
15
15
  asset pipeline
16
16
  email:
17
17
  - e@jetbootlabs.com
18
- executables: []
18
+ executables:
19
+ - rake
19
20
  extensions: []
20
21
  extra_rdoc_files: []
21
22
  files:
@@ -26,6 +27,7 @@ files:
26
27
  - LICENSE
27
28
  - README.md
28
29
  - Rakefile
30
+ - bin/rake
29
31
  - lib/rack-zippy.rb
30
32
  - lib/rack-zippy/asset_compiler.rb
31
33
  - lib/rack-zippy/serveable_file.rb
@@ -63,12 +65,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
63
65
  - - ! '>='
64
66
  - !ruby/object:Gem::Version
65
67
  version: '0'
68
+ segments:
69
+ - 0
70
+ hash: -1213525352478824492
66
71
  required_rubygems_version: !ruby/object:Gem::Requirement
67
72
  none: false
68
73
  requirements:
69
74
  - - ! '>='
70
75
  - !ruby/object:Gem::Version
71
76
  version: '0'
77
+ segments:
78
+ - 0
79
+ hash: -1213525352478824492
72
80
  requirements: []
73
81
  rubyforge_project:
74
82
  rubygems_version: 1.8.23.2