rack-rewrite 1.3.3 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1d85860482ab49561638787391c367e8144173e8
4
+ data.tar.gz: 93e9dcb2b6c38c85e38dc0bd07938929fb010a5c
5
+ SHA512:
6
+ metadata.gz: e5532f91f14dcfb454f4392ff15bf482a7f0e129695183579498c545aa8a89bcad7facc38ce81e3de9eed2e9954e62d2b3413e631784c04924e178a274374ef5
7
+ data.tar.gz: 20faa15a94a838718c64702436b030885b1b8595753e430958a9ca86176f77313b37383ec4ee4bc220a141b3e695dfa0a123529f9f61630a62d2f432322a17ac
@@ -1,3 +1,13 @@
1
+ == 1.4.1 / 2013-11-07
2
+ * API
3
+ * Add support for external loaders (#50)
4
+
5
+ === 1.4.01 / 2013-09-13
6
+ * API
7
+ * Add support for lambda matchers
8
+ * Maintenance
9
+ * Update README for usage with Rails 4 and threading, :scheme option
10
+
1
11
  === 1.2.1 / 2011-09-20
2
12
  * Maintenance
3
13
  * Use Rack::Request to match the host
@@ -30,7 +40,7 @@
30
40
  === 0.2.1 / 2010-01-06
31
41
  * API
32
42
  * Implement $& substitution pattern (thanks to {Ben Brinckerhoff}[http://github.com/bhb])
33
-
43
+
34
44
  * Maintenance
35
45
  * Ignore empty captures instead of failing during subsitution (thanks to {Ben Brinckerhoff}[http://github.com/bhb])
36
46
  * Play nice with Rack::Test requests which only set PATH_INFO and not REQUEST_URI (thanks to {@docunext}[http://github.com/docunext])
@@ -46,14 +56,14 @@
46
56
  * Documentation
47
57
  * Add example of writing capistrano maintenance page rewrite rules
48
58
  * Add examples of rule guards and arbitrary rewriting
49
- * Add examples of :send_file and :x_send_file rules
59
+ * Add examples of :send_file and :x_send_file rules
50
60
 
51
61
  === 0.1.3 / 2009-11-14
52
62
  * Maintenance
53
63
  * Ensure Content-Type header is set for 301's and 302's (thanks to Sebastian Röbke)
54
64
  * Documentation
55
65
  * Add HISTORY.rdoc
56
-
66
+
57
67
  === 0.1.2 / 2009-10-13
58
68
 
59
69
  * Initial Feature Set
@@ -1,17 +1,18 @@
1
1
  # rack-rewrite
2
2
 
3
- A rack middleware for defining and applying rewrite rules. In many cases you
3
+ A rack middleware for defining and applying rewrite rules. In many cases you
4
4
  can get away with rack-rewrite instead of writing Apache mod_rewrite rules.
5
5
 
6
6
  ## Usage Examples
7
7
 
8
8
  * [Rack::Rewrite for Site Maintenance and Downtime](http://blog.smartlogicsolutions.com/2009/11/16/rack-rewrite-for-site-maintenance-and-downtime/)
9
9
  * [Rack::Rewrite + Google Analytics Makes Site Transitions Seamless](http://blog.smartlogicsolutions.com/2009/11/24/rack-rewrite-google-analytics-makes-site-transitions-seamless/)
10
+ * [Rack::Rewrite for serving gzipped pipeline assets on Heroku](https://gist.github.com/eliotsykes/6049536)
10
11
 
11
12
  ## Usage Details
12
13
 
13
14
  ### Sample rackup file
14
-
15
+
15
16
  ```ruby
16
17
  gem 'rack-rewrite', '~> 1.2.1'
17
18
  require 'rack/rewrite'
@@ -34,6 +35,24 @@ config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
34
35
  end
35
36
  ```
36
37
 
38
+ If you use `config.threadsafe`, you'll need to `insert_before(Rack::Runtime, Rack::Rewrite)` as `Rack::Lock` does
39
+ not exist when `config.allow_concurrency == true`:
40
+
41
+ ```ruby
42
+ config.middleware.insert_before(Rack::Runtime, Rack::Rewrite) do
43
+ rewrite '/wiki/John_Trupiano', '/john'
44
+ r301 '/wiki/Yair_Flicker', '/yair'
45
+ r302 '/wiki/Greg_Jastrab', '/greg'
46
+ r301 %r{/wiki/(\w+)_\w+}, '/$1'
47
+ end
48
+ ```
49
+
50
+ Or insert Rack::Rewrite to the top of the stack:
51
+
52
+ ``` ruby
53
+ config.middleware.insert 0, 'Rack::Rewrite' {}
54
+ ```
55
+
37
56
  ## Redirection codes
38
57
 
39
58
  All redirect status codes from the [HTTP spec](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) are supported:
@@ -72,7 +91,7 @@ behaves the same as 303.
72
91
 
73
92
  ### Rebuild of existing site in a new technology
74
93
 
75
- It's very common for sites built in older technologies to be rebuilt with the
94
+ It's very common for sites built in older technologies to be rebuilt with the
76
95
  latest and greatest. Let's consider a site that has already established quite
77
96
  a bit of "google juice." When we launch the new site, we don't want to lose
78
97
  that hard-earned reputation. By writing rewrite rules that issue 301's for
@@ -123,11 +142,11 @@ RewriteRule ^.*$ /system/maintenance.html [L]
123
142
  ```
124
143
 
125
144
  This rewrite rule says to render a maintenance page for all non-asset requests
126
- if the maintenance file exists. In capistrano, you can quickly upload a
145
+ if the maintenance file exists. In capistrano, you can quickly upload a
127
146
  maintenance file using:
128
147
 
129
148
  `cap deploy:web:disable REASON=upgrade UNTIL=12:30PM`
130
-
149
+
131
150
  We can replace the mod_rewrite rules with the following Rack::Rewrite rule:
132
151
 
133
152
  ```ruby
@@ -146,7 +165,7 @@ send_file /(.*)$(?<!css|png|jpg)/, maintenance_file, :if => Proc.new { |rack_env
146
165
  }
147
166
  ```
148
167
 
149
- For those using the oniguruma gem with their ruby 1.8 installation, you can
168
+ For those using the oniguruma gem with their ruby 1.8 installation, you can
150
169
  get away with:
151
170
 
152
171
  ```ruby
@@ -160,9 +179,9 @@ send_file Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)"), maintenance_file, :if
160
179
 
161
180
  ### :rewrite
162
181
 
163
- Calls to #rewrite will simply update the PATH_INFO, QUERY_STRING and
164
- REQUEST_URI HTTP header values and pass the request onto the next chain in
165
- the Rack stack. The URL that a user's browser will show will not be changed.
182
+ Calls to #rewrite will simply update the PATH_INFO, QUERY_STRING and
183
+ REQUEST_URI HTTP header values and pass the request onto the next chain in
184
+ the Rack stack. The URL that a user's browser will show will not be changed.
166
185
  See these examples:
167
186
 
168
187
  ```ruby
@@ -171,14 +190,14 @@ rewrite %r{/wiki/(\w+)_\w+}, '/$1' # [2]
171
190
  ```
172
191
 
173
192
  For [1], the user's browser will continue to display /wiki/John_Trupiano, but
174
- the actual HTTP header values for PATH_INFO and REQUEST_URI in the request
193
+ the actual HTTP header values for PATH_INFO and REQUEST_URI in the request
175
194
  will be changed to /john for subsequent nodes in the Rack stack. Rails
176
195
  reads these headers to determine which routes will match.
177
196
 
178
- Rule [2] showcases the use of regular expressions and substitutions. [2] is a
197
+ Rule [2] showcases the use of regular expressions and substitutions. [2] is a
179
198
  generalized version of [1] that will match any /wiki/FirstName_LastName URL's
180
- and rewrite them as the first name only. This is an actual catch-all rule we
181
- applied when we rebuilt our website in September 2009
199
+ and rewrite them as the first name only. This is an actual catch-all rule we
200
+ applied when we rebuilt our website in September 2009
182
201
  ( http://www.smartlogicsolutions.com ).
183
202
 
184
203
  ### :r301, :r302, :r303, :r307
@@ -189,10 +208,10 @@ their respective status codes. See these examples:
189
208
 
190
209
  ```ruby
191
210
  r301 '/wiki/John_Trupiano', '/john' # [1]
192
- r301 '/wiki/(.*)', 'http://www.google.com/?q=$1' # [2]
211
+ r301 %r{/wiki/(.*)}, 'http://www.google.com/?q=$1' # [2]
193
212
  ```
194
213
 
195
- Recall that rules are interpreted from top to bottom. So you can install
214
+ Recall that rules are interpreted from top to bottom. So you can install
196
215
  "default" rewrite rules if you like. [2] is a sample default rule that
197
216
  will redirect all other requests to the wiki to a google search.
198
217
 
@@ -223,11 +242,13 @@ Using the :host option you can match requests to a specific hostname.
223
242
  ```ruby
224
243
  r301 "/features", "/facial_features", :host => "facerecognizer.com"
225
244
  ```
226
- This rule will only match when the hostname is "facerecognizer.com"
245
+ This rule will only match when the hostname is "facerecognizer.com".
246
+
247
+ The :host option accepts a symbol, string, or regexp.
227
248
 
228
249
  ### :headers
229
250
 
230
- Using the :headers option you can set custom response headers e.g. for HTTP
251
+ Using the :headers option you can set custom response headers e.g. for HTTP
231
252
  caching instructions.
232
253
 
233
254
  ```ruby
@@ -247,9 +268,20 @@ send_file /^.+\.(?:ico|jpg|jpeg|png|gif|)$/,
247
268
  :headers => lambda { { 'Expires' => 1.year.from_now.httpdate } }
248
269
  ```
249
270
 
271
+ ### :scheme
272
+
273
+ Using the :scheme option you can restrict the matching of a rule by the protocol of a given request.
274
+
275
+ ```ruby
276
+ # Redirect all http traffic to https
277
+ r301 %r{.*}, 'https://www.example.tld$&', :scheme => 'http'
278
+ ```
279
+
280
+ The :scheme option accepts a symbol, string, or regexp.
281
+
250
282
  ### :method
251
283
 
252
- Using the :method option you can restrict the matching of a rule by the HTTP
284
+ Using the :method option you can restrict the matching of a rule by the HTTP
253
285
  method of a given request.
254
286
 
255
287
  ```ruby
@@ -260,16 +292,18 @@ r301 "/players", "/current_players", :method => :get
260
292
  r302 "/players", "/no_longer_available.html?message=No&longer&supported", :method => :post
261
293
  ```
262
294
 
295
+ The :method option accepts a symbol, string, or regexp.
296
+
263
297
  ### :if
264
298
 
265
299
  Using the :if option you can define arbitrary rule guards. Guards are any
266
- object responding to #call that return true or false indicating whether the
267
- rule matches. The following example demonstrates how the presence of a
300
+ object responding to #call that return true or false indicating whether the
301
+ rule matches. The following example demonstrates how the presence of a
268
302
  maintenance page on the filesystem can be utilized to take your site(s) offline.
269
303
 
270
304
  ```ruby
271
305
  maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
272
- x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
306
+ x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
273
307
  File.exists?(maintenance_file)
274
308
  }
275
309
  ```
@@ -289,7 +323,7 @@ This will not match the relative URL /features but would match /features.xml.
289
323
 
290
324
  ### Keeping your querystring
291
325
 
292
- When rewriting a URL, you may want to keep your querystring in tact (for
326
+ When rewriting a URL, you may want to keep your querystring intact (for
293
327
  example if you're tracking traffic sources). You will need to include a
294
328
  capture group and substitution pattern in your rewrite rule to achieve this.
295
329
 
@@ -302,7 +336,7 @@ will substitute the querystring back into the rewritten URL (via `$1`).
302
336
 
303
337
  ### Arbitrary Rewriting
304
338
 
305
- All rules support passing a Proc as the second argument allowing you to
339
+ All rules support passing a Proc as the first or second argument allowing you to
306
340
  perform arbitrary rewrites. The following rule will rewrite all requests
307
341
  received between 12AM and 8AM to an unavailable page.
308
342
 
@@ -312,6 +346,40 @@ received between 12AM and 8AM to an unavailable page.
312
346
  }
313
347
  ```
314
348
 
349
+ This rule will redirect all requests paths starting with a current date
350
+ string to /today.html
351
+
352
+ ```ruby
353
+ r301 lambda { "/#{Time.current.strftime(%m%d%Y)}.html" }, '/today.html'
354
+ ```
355
+
356
+
357
+ ##Alternative loaders
358
+
359
+ rack-rewrite can also be driven by external loaders. Bundled with this library is a loader for YAML files.
360
+
361
+ ```
362
+ config.middleware.insert_before(Rack::Lock, Rack::Rewrite,
363
+ :klass => Rack::Rewrite::YamlRuleSet,
364
+ :options => {:file_name => @file_name})
365
+ ```
366
+
367
+ Using syntax like
368
+
369
+ ```
370
+ -
371
+ method: r301
372
+ from: !ruby/regexp '/(.*)/print'
373
+ to : '$1/printer_friendly'
374
+ options :
375
+ host : 'example.com'
376
+ ```
377
+
378
+ Any class can be used here as long as:
379
+
380
+ - the class take an options hash
381
+ - `#rules` returns an array of `Rack::Rewrite::Rule` instances
382
+
315
383
  ## Contribute
316
384
 
317
385
  rack-rewrite is maintained by [@travisjeffery](http://github.com/travisjeffery).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.3
1
+ 1.4.1
@@ -5,9 +5,13 @@ module Rack
5
5
  # A rack middleware for defining and applying rewrite rules. In many cases you
6
6
  # can get away with rack-rewrite instead of writing Apache mod_rewrite rules.
7
7
  class Rewrite
8
- def initialize(app, &rule_block)
8
+ def initialize(app, given_options = {}, &rule_block)
9
+ options = {
10
+ :klass => RuleSet,
11
+ :options => {}
12
+ }.merge(given_options)
9
13
  @app = app
10
- @rule_set = RuleSet.new
14
+ @rule_set = options[:klass].new(options[:options])
11
15
  @rule_set.instance_eval(&rule_block) if block_given?
12
16
  end
13
17
 
@@ -4,7 +4,7 @@ module Rack
4
4
  class Rewrite
5
5
  class RuleSet
6
6
  attr_reader :rules
7
- def initialize #:nodoc:
7
+ def initialize(options = {})#:nodoc:
8
8
  @rules = []
9
9
  end
10
10
 
@@ -99,7 +99,7 @@ module Rack
99
99
 
100
100
  # TODO: Break rules into subclasses
101
101
  class Rule #:nodoc:
102
- attr_reader :rule_type, :from, :to, :options
102
+ attr_reader :rule_type, :to, :options
103
103
  def initialize(rule_type, from, to, options={}) #:nodoc:
104
104
  @rule_type, @from, @to, @options = rule_type, from, to, normalize_options(options)
105
105
  end
@@ -111,6 +111,11 @@ module Rack
111
111
  self.match_options?(rack_env) && string_matches?(path, self.from)
112
112
  end
113
113
 
114
+ def from
115
+ return @static_from if @static_from
116
+ @from.respond_to?(:call) ? @from.call : @static_from = @from
117
+ end
118
+
114
119
  # Either (a) return a Rack response (short-circuiting the Rack stack), or
115
120
  # (b) alter env as necessary and return true
116
121
  def apply!(env) #:nodoc:
@@ -1,3 +1,5 @@
1
+ require 'date'
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = 'rack-rewrite'
3
5
  s.version = File.read('VERSION')
@@ -41,12 +43,12 @@ Gem::Specification.new do |s|
41
43
  "test/rule_test.rb",
42
44
  "test/test_helper.rb"
43
45
  ]
44
-
46
+
45
47
  s.add_development_dependency 'bundler'
46
48
  s.add_development_dependency 'shoulda', '~> 2.10.2'
47
49
  s.add_development_dependency 'mocha', '~> 0.9.7'
48
50
  s.add_development_dependency 'rack'
49
-
51
+
50
52
  if s.respond_to? :specification_version then
51
53
  s.specification_version = 3
52
54
  end
@@ -1,9 +1,9 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class RuleTest < Test::Unit::TestCase
4
-
4
+
5
5
  TEST_ROOT = File.dirname(__FILE__)
6
-
6
+
7
7
  def self.should_pass_maintenance_tests
8
8
  context 'and the maintenance file does in fact exist' do
9
9
  setup { File.stubs(:exists?).returns(true) }
@@ -16,14 +16,14 @@ class RuleTest < Test::Unit::TestCase
16
16
  should('not match for a png file') { assert !@rule.matches?(rack_env_for('/images/sls.png')) }
17
17
  end
18
18
  end
19
-
19
+
20
20
  def self.negative_lookahead_supported?
21
21
  begin
22
22
  require 'oniguruma'
23
23
  rescue LoadError; end
24
24
  RUBY_VERSION =~ /^1\.9/ || Object.const_defined?(:Oniguruma)
25
25
  end
26
-
26
+
27
27
  def negative_lookahead_regexp
28
28
  if RUBY_VERSION =~ /^1\.9/
29
29
  # have to use the constructor instead of the literal syntax b/c load errors occur in Ruby 1.8
@@ -32,7 +32,7 @@ class RuleTest < Test::Unit::TestCase
32
32
  Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)")
33
33
  end
34
34
  end
35
-
35
+
36
36
  context '#Rule#apply' do
37
37
  supported_status_codes.each do |rule_type|
38
38
  should "set Location header to result of #interpret_to for a #{rule_type}" do
@@ -41,7 +41,7 @@ class RuleTest < Test::Unit::TestCase
41
41
  assert_equal rule.send(:interpret_to, '/abc'), rule.apply!(env)[1]['Location']
42
42
  end
43
43
  end
44
-
44
+
45
45
  supported_status_codes.each do |rule_type|
46
46
  should "include a link to the result of #interpret_to for a #{rule_type}" do
47
47
  rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def')
@@ -49,13 +49,13 @@ class RuleTest < Test::Unit::TestCase
49
49
  assert_match /\/def/, rule.apply!(env)[2][0]
50
50
  end
51
51
  end
52
-
52
+
53
53
  should 'keep the QUERY_STRING when a 301 rule matches a URL with a querystring' do
54
54
  rule = Rack::Rewrite::Rule.new(:r301, %r{/john(.*)}, '/yair$1')
55
55
  env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
56
56
  assert_equal '/yair?show_bio=1', rule.apply!(env)[1]['Location']
57
57
  end
58
-
58
+
59
59
  should 'keep the QUERY_STRING when a rewrite rule that requires a querystring matches a URL with a querystring' do
60
60
  rule = Rack::Rewrite::Rule.new(:rewrite, %r{/john(\?.*)}, '/yair$1')
61
61
  env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
@@ -64,7 +64,7 @@ class RuleTest < Test::Unit::TestCase
64
64
  assert_equal 'show_bio=1', env['QUERY_STRING']
65
65
  assert_equal '/yair?show_bio=1', env['REQUEST_URI']
66
66
  end
67
-
67
+
68
68
  should 'update the QUERY_STRING when a rewrite rule changes its value' do
69
69
  rule = Rack::Rewrite::Rule.new(:rewrite, %r{/(\w+)\?show_bio=(\d)}, '/$1?bio=$2')
70
70
  env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
@@ -81,21 +81,21 @@ class RuleTest < Test::Unit::TestCase
81
81
  assert_equal 'text/html', rule.apply!(env)[1]['Content-Type']
82
82
  end
83
83
  end
84
-
84
+
85
85
  should 'set Content-Type header to text/css for a 301 and 302 request for a .css page' do
86
86
  supported_status_codes.each do |rule_type|
87
87
  rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def.css')
88
88
  env = {'PATH_INFO' => '/abc'}
89
89
  assert_equal 'text/css', rule.apply!(env)[1]['Content-Type']
90
- end
90
+ end
91
91
  end
92
-
92
+
93
93
  should 'set additional headers for a 301 and 302 request' do
94
94
  [:r301, :r302].each do |rule_type|
95
95
  rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def.css', {:headers => {'Cache-Control' => 'no-cache'}})
96
96
  env = {'PATH_INFO' => '/abc'}
97
97
  assert_equal 'no-cache', rule.apply!(env)[1]['Cache-Control']
98
- end
98
+ end
99
99
  end
100
100
 
101
101
  should 'evaluate additional headers block once per redirect request' do
@@ -119,7 +119,7 @@ class RuleTest < Test::Unit::TestCase
119
119
  assert_equal 'bar', rule.apply!(env)[1]['X-Foobar']
120
120
  end
121
121
  end
122
-
122
+
123
123
  context 'Given an :x_send_file rule that matches' do
124
124
  setup do
125
125
  @file = File.join(TEST_ROOT, 'geminstaller.yml')
@@ -127,23 +127,23 @@ class RuleTest < Test::Unit::TestCase
127
127
  env = {'PATH_INFO' => '/abc'}
128
128
  @response = @rule.apply!(env)
129
129
  end
130
-
130
+
131
131
  should 'return 200' do
132
132
  assert_equal 200, @response[0]
133
133
  end
134
-
134
+
135
135
  should 'return an X-Sendfile header' do
136
136
  assert @response[1].has_key?('X-Sendfile')
137
137
  end
138
-
138
+
139
139
  should 'return a Content-Type of text/yaml' do
140
140
  assert_equal 'text/yaml', @response[1]['Content-Type']
141
141
  end
142
-
142
+
143
143
  should 'return the proper Content-Length' do
144
144
  assert_equal File.size(@file).to_s, @response[1]['Content-Length']
145
145
  end
146
-
146
+
147
147
  should 'return additional headers' do
148
148
  assert_equal 'no-cache', @response[1]['Cache-Control']
149
149
  end
@@ -152,7 +152,7 @@ class RuleTest < Test::Unit::TestCase
152
152
  assert_equal [], @response[2]
153
153
  end
154
154
  end
155
-
155
+
156
156
  context 'Given a :send_file rule that matches' do
157
157
  setup do
158
158
  @file = File.join(TEST_ROOT, 'geminstaller.yml')
@@ -160,27 +160,27 @@ class RuleTest < Test::Unit::TestCase
160
160
  env = {'PATH_INFO' => '/abc'}
161
161
  @response = @rule.apply!(env)
162
162
  end
163
-
163
+
164
164
  should 'return 200' do
165
165
  assert_equal 200, @response[0]
166
166
  end
167
-
167
+
168
168
  should 'not return an X-Sendfile header' do
169
169
  assert !@response[1].has_key?('X-Sendfile')
170
170
  end
171
-
171
+
172
172
  should 'return a Content-Type of text/yaml' do
173
173
  assert_equal 'text/yaml', @response[1]['Content-Type']
174
174
  end
175
-
175
+
176
176
  should 'return the proper Content-Length' do
177
177
  assert_equal File.size(@file).to_s, @response[1]['Content-Length']
178
178
  end
179
-
179
+
180
180
  should 'return additional headers' do
181
181
  assert_equal 'no-cache', @response[1]['Cache-Control']
182
182
  end
183
-
183
+
184
184
  should 'return the contents of geminstaller.yml in an array for Ruby 1.9.2 compatibility' do
185
185
  assert_equal [File.read(@file)], @response[2]
186
186
  end
@@ -196,7 +196,7 @@ class RuleTest < Test::Unit::TestCase
196
196
  end
197
197
 
198
198
  end
199
-
199
+
200
200
  context 'Rule#matches' do
201
201
  context 'Given rule with :not option which matches "from" string' do
202
202
  setup do
@@ -209,16 +209,16 @@ class RuleTest < Test::Unit::TestCase
209
209
  assert @rule.matches?(rack_env_for("/features.xml"))
210
210
  end
211
211
  end
212
-
212
+
213
213
  context 'Given rule with :host option of testapp.com' do
214
214
  setup do
215
215
  @rule = Rack::Rewrite::Rule.new(:rewrite, /^\/features/, '/facial_features', :host => 'testapp.com')
216
216
  end
217
-
217
+
218
218
  should 'match PATH_INFO of /features and HOST of testapp.com' do
219
219
  assert @rule.matches?(rack_env_for("/features", 'SERVER_NAME' => 'testapp.com', "SERVER_PORT" => "8080"))
220
220
  end
221
-
221
+
222
222
  should 'not match PATH_INFO of /features and HOST of nottestapp.com' do
223
223
  assert ! @rule.matches?(rack_env_for("/features", 'SERVER_NAME' => 'nottestapp.com', "SERVER_PORT" => "8080"))
224
224
  end
@@ -231,39 +231,39 @@ class RuleTest < Test::Unit::TestCase
231
231
  assert !@rule.matches?(rack_env_for("/features", "SERVER_NAME" => "127.0.0.1", "SERVER_PORT" => "8080", "HTTP_X_FORWARDED_HOST" => "nottestapp.com"))
232
232
  end
233
233
  end
234
-
234
+
235
235
  context 'Given rule with :method option of POST' do
236
236
  setup do
237
237
  @rule = Rack::Rewrite::Rule.new(:rewrite, '/features', '/facial_features', :method => 'POST')
238
238
  end
239
-
239
+
240
240
  should 'match PATH_INFO of /features and REQUEST_METHOD of POST' do
241
241
  assert @rule.matches?(rack_env_for("/features", 'REQUEST_METHOD' => 'POST'))
242
242
  end
243
-
243
+
244
244
  should 'not match PATH_INFO of /features and REQUEST_METHOD of DELETE' do
245
245
  assert ! @rule.matches?(rack_env_for("/features", 'REQUEST_METHOD' => 'DELETE'))
246
246
  end
247
247
  end
248
-
248
+
249
249
  context 'Given any rule with a "from" string of /features' do
250
250
  setup do
251
251
  @rule = Rack::Rewrite::Rule.new(:rewrite, '/features', '/facial_features')
252
252
  end
253
-
253
+
254
254
  should 'match PATH_INFO of /features' do
255
255
  assert @rule.matches?(rack_env_for("/features"))
256
256
  end
257
-
257
+
258
258
  should 'not match PATH_INFO of /features.xml' do
259
259
  assert !@rule.matches?(rack_env_for("/features.xml"))
260
260
  end
261
-
261
+
262
262
  should 'not match PATH_INFO of /my_features' do
263
263
  assert !@rule.matches?(rack_env_for("/my_features"))
264
264
  end
265
265
  end
266
-
266
+
267
267
  context 'Given a rule with the ^ operator' do
268
268
  setup do
269
269
  @rule = Rack::Rewrite::Rule.new(:rewrite, %r{^/jason}, '/steve')
@@ -271,66 +271,66 @@ class RuleTest < Test::Unit::TestCase
271
271
  should 'match with the ^ operator if match is at the beginning of the path' do
272
272
  assert @rule.matches?(rack_env_for('/jason'))
273
273
  end
274
-
274
+
275
275
  should 'not match with the ^ operator when match is deeply nested' do
276
276
  assert !@rule.matches?(rack_env_for('/foo/bar/jason'))
277
277
  end
278
278
  end
279
-
279
+
280
280
  context 'Given any rule with a "from" regular expression of /features(.*)' do
281
281
  setup do
282
282
  @rule = Rack::Rewrite::Rule.new(:rewrite, %r{/features(.*)}, '/facial_features$1')
283
283
  end
284
-
284
+
285
285
  should 'match PATH_INFO of /features' do
286
286
  assert @rule.matches?(rack_env_for("/features"))
287
287
  end
288
-
288
+
289
289
  should 'match PATH_INFO of /features.xml' do
290
290
  assert @rule.matches?(rack_env_for('/features.xml'))
291
291
  end
292
-
292
+
293
293
  should 'match PATH_INFO of /features/1' do
294
294
  assert @rule.matches?(rack_env_for('/features/1'))
295
295
  end
296
-
296
+
297
297
  should 'match PATH_INFO of /features?filter_by=name' do
298
298
  assert @rule.matches?(rack_env_for('/features?filter_by_name=name'))
299
299
  end
300
-
300
+
301
301
  should 'match PATH_INFO of /features/1?hide_bio=1' do
302
302
  assert @rule.matches?(rack_env_for('/features/1?hide_bio=1'))
303
303
  end
304
304
  end
305
-
305
+
306
306
  context 'Given a rule with a guard that checks for the presence of a file' do
307
307
  setup do
308
308
  @rule = Rack::Rewrite::Rule.new(:rewrite, %r{(.)*}, '/maintenance.html', lambda { |rack_env|
309
309
  File.exists?('maintenance.html')
310
310
  })
311
311
  end
312
-
312
+
313
313
  context 'when the file exists' do
314
314
  setup do
315
315
  File.stubs(:exists?).returns(true)
316
316
  end
317
-
317
+
318
318
  should 'match' do
319
319
  assert @rule.matches?(rack_env_for('/anything/should/match'))
320
320
  end
321
321
  end
322
-
322
+
323
323
  context 'when the file does not exist' do
324
324
  setup do
325
325
  File.stubs(:exists?).returns(false)
326
326
  end
327
-
327
+
328
328
  should 'not match' do
329
329
  assert !@rule.matches?(rack_env_for('/nothing/should/match'))
330
330
  end
331
331
  end
332
332
  end
333
-
333
+
334
334
  context 'Given the capistrano maintenance.html rewrite rule given in our README' do
335
335
  setup do
336
336
  @rule = Rack::Rewrite::Rule.new(:rewrite, /.*/, '/system/maintenance.html', lambda { |rack_env|
@@ -340,7 +340,7 @@ class RuleTest < Test::Unit::TestCase
340
340
  end
341
341
  should_pass_maintenance_tests
342
342
  end
343
-
343
+
344
344
  if negative_lookahead_supported?
345
345
  context 'Given the negative lookahead regular expression version of the capistrano maintenance.html rewrite rule given in our README' do
346
346
  setup do
@@ -351,43 +351,57 @@ class RuleTest < Test::Unit::TestCase
351
351
  should_pass_maintenance_tests
352
352
  end
353
353
  end
354
-
354
+
355
355
  context 'Given the CNAME alternative rewrite rule in our README' do
356
356
  setup do
357
357
  @rule = Rack::Rewrite::Rule.new(:r301, %r{.*}, 'http://mynewdomain.com$&', lambda {|rack_env|
358
358
  rack_env['SERVER_NAME'] != 'mynewdomain.com'
359
359
  })
360
360
  end
361
-
361
+
362
362
  should 'match requests for domain myolddomain.com and redirect to mynewdomain.com' do
363
363
  env = {'PATH_INFO' => '/anything', 'QUERY_STRING' => 'abc=1', 'SERVER_NAME' => 'myolddomain.com'}
364
364
  assert @rule.matches?(env)
365
365
  rack_response = @rule.apply!(env)
366
366
  assert_equal 'http://mynewdomain.com/anything?abc=1', rack_response[1]['Location']
367
367
  end
368
-
368
+
369
369
  should 'not match requests for domain mynewdomain.com' do
370
370
  assert !@rule.matches?({'PATH_INFO' => '/anything', 'SERVER_NAME' => 'mynewdomain.com'})
371
371
  end
372
372
  end
373
+
374
+ context 'Given a lambda matcher' do
375
+ setup do
376
+ @rule = Rack::Rewrite::Rule.new(:r302, ->{ Thread.current[:test_matcher] }, '/today' )
377
+ end
378
+ should 'call the lambda and match appropriately' do
379
+ Thread.current[:test_matcher] = '/abcd'
380
+ assert @rule.matches?(rack_env_for("/abcd"))
381
+ assert !@rule.matches?(rack_env_for("/DEFG"))
382
+ Thread.current[:test_matcher] = /DEFG$/
383
+ assert !@rule.matches?(rack_env_for("/abcd"))
384
+ assert @rule.matches?(rack_env_for("/DEFG"))
385
+ end
386
+ end
373
387
  end
374
-
388
+
375
389
  context 'Rule#interpret_to' do
376
390
  should 'return #to when #from is a string' do
377
391
  rule = Rack::Rewrite::Rule.new(:rewrite, '/abc', '/def')
378
392
  assert_equal '/def', rule.send(:interpret_to, rack_env_for('/abc'))
379
393
  end
380
-
394
+
381
395
  should 'replace $1 on a match' do
382
396
  rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)}, '/people/$1')
383
397
  assert_equal '/people/1', rule.send(:interpret_to, rack_env_for("/person_1"))
384
398
  end
385
-
399
+
386
400
  should 'be able to catch querystrings with a regexp match' do
387
401
  rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)(.*)}, '/people/$1$2')
388
402
  assert_equal '/people/1?show_bio=1', rule.send(:interpret_to, rack_env_for('/person_1?show_bio=1'))
389
403
  end
390
-
404
+
391
405
  should 'be able to make 10 replacements' do
392
406
  # regexp to reverse 10 characters
393
407
  rule = Rack::Rewrite::Rule.new(:rewrite, %r{(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)}, '$10$9$8$7$6$5$4$3$2$1')
@@ -413,15 +427,23 @@ class RuleTest < Test::Unit::TestCase
413
427
  rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)(.*)}, lambda {|match, env| "people-#{match[1].to_i * 3}#{match[2]}"})
414
428
  assert_equal 'people-3?show_bio=1', rule.send(:interpret_to, rack_env_for('/person_1?show_bio=1'))
415
429
  end
430
+
431
+ should 'call to with from lambda match data' do
432
+ rule = Rack::Rewrite::Rule.new(:rewrite, ->{ Thread.current[:test_matcher]}, ->(match, env){ match[1][0] })
433
+ Thread.current[:test_matcher] = /^\/(alpha|beta|gamma)$/
434
+ assert_equal 'b', rule.send(:interpret_to, rack_env_for('/beta'))
435
+ Thread.current[:test_matcher] = /^\/(zulu)/
436
+ assert_equal 'z', rule.send(:interpret_to, rack_env_for('/zulu'))
437
+ end
416
438
  end
417
-
439
+
418
440
  context 'Mongel 1.2.0.pre2 edge case: root url with a query string' do
419
441
  should 'handle a nil PATH_INFO variable without errors' do
420
442
  rule = Rack::Rewrite::Rule.new(:r301, '/a', '/')
421
443
  assert_equal '?exists', rule.send(:build_path_from_env, {'QUERY_STRING' => 'exists'})
422
444
  end
423
445
  end
424
-
446
+
425
447
  def rack_env_for(url, options = {})
426
448
  components = url.split('?')
427
449
  {'PATH_INFO' => components[0], 'QUERY_STRING' => components[1] || ''}.merge(options)
@@ -8,6 +8,11 @@ require 'test/unit'
8
8
  class Test::Unit::TestCase
9
9
  end
10
10
 
11
+ def rack_env_for(url, options = {})
12
+ components = url.split('?')
13
+ {'PATH_INFO' => components[0], 'QUERY_STRING' => components[1] || ''}.merge(options)
14
+ end
15
+
11
16
  def supported_status_codes
12
17
  [:r301, :r302, :r303, :r307]
13
18
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-rewrite
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
5
- prerelease:
4
+ version: 1.4.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Travis Jeffery
@@ -10,28 +9,25 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-01-06 00:00:00.000000000 Z
12
+ date: 2013-11-07 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: bundler
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
- - - ! '>='
18
+ - - '>='
21
19
  - !ruby/object:Gem::Version
22
20
  version: '0'
23
21
  type: :development
24
22
  prerelease: false
25
23
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
24
  requirements:
28
- - - ! '>='
25
+ - - '>='
29
26
  - !ruby/object:Gem::Version
30
27
  version: '0'
31
28
  - !ruby/object:Gem::Dependency
32
29
  name: shoulda
33
30
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
31
  requirements:
36
32
  - - ~>
37
33
  - !ruby/object:Gem::Version
@@ -39,7 +35,6 @@ dependencies:
39
35
  type: :development
40
36
  prerelease: false
41
37
  version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
38
  requirements:
44
39
  - - ~>
45
40
  - !ruby/object:Gem::Version
@@ -47,7 +42,6 @@ dependencies:
47
42
  - !ruby/object:Gem::Dependency
48
43
  name: mocha
49
44
  requirement: !ruby/object:Gem::Requirement
50
- none: false
51
45
  requirements:
52
46
  - - ~>
53
47
  - !ruby/object:Gem::Version
@@ -55,7 +49,6 @@ dependencies:
55
49
  type: :development
56
50
  prerelease: false
57
51
  version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
52
  requirements:
60
53
  - - ~>
61
54
  - !ruby/object:Gem::Version
@@ -63,17 +56,15 @@ dependencies:
63
56
  - !ruby/object:Gem::Dependency
64
57
  name: rack
65
58
  requirement: !ruby/object:Gem::Requirement
66
- none: false
67
59
  requirements:
68
- - - ! '>='
60
+ - - '>='
69
61
  - !ruby/object:Gem::Version
70
62
  version: '0'
71
63
  type: :development
72
64
  prerelease: false
73
65
  version_requirements: !ruby/object:Gem::Requirement
74
- none: false
75
66
  requirements:
76
- - - ! '>='
67
+ - - '>='
77
68
  - !ruby/object:Gem::Version
78
69
  version: '0'
79
70
  description: A rack middleware for enforcing rewrite rules. In many cases you can
@@ -102,26 +93,25 @@ files:
102
93
  - test/test_helper.rb
103
94
  homepage: http://github.com/jtrupiano/rack-rewrite
104
95
  licenses: []
96
+ metadata: {}
105
97
  post_install_message:
106
98
  rdoc_options:
107
99
  - --charset=UTF-8
108
100
  require_paths:
109
101
  - lib
110
102
  required_ruby_version: !ruby/object:Gem::Requirement
111
- none: false
112
103
  requirements:
113
- - - ! '>='
104
+ - - '>='
114
105
  - !ruby/object:Gem::Version
115
106
  version: '0'
116
107
  required_rubygems_version: !ruby/object:Gem::Requirement
117
- none: false
118
108
  requirements:
119
- - - ! '>='
109
+ - - '>='
120
110
  - !ruby/object:Gem::Version
121
111
  version: '0'
122
112
  requirements: []
123
113
  rubyforge_project: johntrupiano
124
- rubygems_version: 1.8.23
114
+ rubygems_version: 2.0.3
125
115
  signing_key:
126
116
  specification_version: 3
127
117
  summary: A rack middleware for enforcing rewrite rules