rack-rewrite 0.2.0 → 0.2.1

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.
@@ -1,3 +1,12 @@
1
+ === 0.2.1 / 2010-01-06
2
+ * API
3
+ * Implement $& substitution pattern (thanks to {Ben Brinckerhoff}[http://github.com/bhb])
4
+
5
+ * Maintenance
6
+ * Ignore empty captures instead of failing during subsitution (thanks to {Ben Brinckerhoff}[http://github.com/bhb])
7
+ * Play nice with Rack::Test requests which only set PATH_INFO and not REQUEST_URI (thanks to {@docunext}[http://github.com/docunext])
8
+ * Use QUERY_STRING instead of QUERYSTRING as per Rack spec. Closes Issue #1.
9
+
1
10
  === 0.2.0 / 2009-11-14
2
11
  * API
3
12
  * Allow Proc's to be be passed as the 'to' argument to rule declarations
@@ -3,11 +3,18 @@
3
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
+ == References
7
+
8
+ * Source[http://github.com/jtrupiano/rack-rewrite]
9
+ * Documentation[http://johntrupiano.rubyforge.org/rack-rewrite]
10
+ * {Rack::Rewrite for Site Maintenance and Downtime}[http://blog.smartlogicsolutions.com/2009/11/16/rack-rewrite-for-site-maintenance-and-downtime/]
11
+ * {Rack::Rewrite + Google Analytics Makes Site Transitions Seamless}[http://blog.smartlogicsolutions.com/2009/11/24/rack-rewrite-google-analytics-makes-site-transitions-seamless/]
12
+
6
13
  == Usage
7
14
 
8
15
  === Sample rackup file
9
16
 
10
- gem 'rack-rewrite', '~> 0.1.3'
17
+ gem 'rack-rewrite', '~> 0.2.1'
11
18
  require 'rack-rewrite
12
19
  use Rack::Rewrite do
13
20
  rewrite '/wiki/John_Trupiano', '/john'
@@ -17,7 +24,7 @@ can get away with rack-rewrite instead of writing Apache mod_rewrite rules.
17
24
  end
18
25
 
19
26
  === Sample usage in a rails app
20
- config.gem 'rack-rewrite', '~> 0.1.3'
27
+ config.gem 'rack-rewrite', '~> 0.2.1'
21
28
  require 'rack-rewrite
22
29
  config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
23
30
  rewrite '/wiki/John_Trupiano', '/john'
@@ -53,6 +60,16 @@ to these routes and keep your routes.rb clean.
53
60
 
54
61
  rewrite %r{/features(.*)}, '/facial_features$1'
55
62
 
63
+ === CNAME alternative
64
+
65
+ In the event that you do not control your DNS, you can leverage Rack::Rewrite
66
+ to redirect to a canonical domain. In the following rule we utilize the
67
+ $& substitution operator to capture the entire request URI.
68
+
69
+ r301 %r{.*}, 'http://mynewdomain.com$&', :if => Proc.new {|rack_env|
70
+ rack_env['SERVER_NAME'] != 'mynewdomain.com'
71
+ }
72
+
56
73
  === Site Maintenance
57
74
 
58
75
  Most capistrano users will be familiar with the following Apache rewrite rules:
@@ -72,10 +89,10 @@ We can replace the mod_rewrite rules with the following Rack::Rewrite rule:
72
89
 
73
90
  maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
74
91
  send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
75
- File.exists?(maintenance_file) && !%w(css jpg png).any? {|ext| maintenance_file =~ Regexp.new("\.#{ext}$")}
92
+ File.exists?(maintenance_file) && rack_env['REQUEST_URI'] !~ /\.(css|jpg|png)/
76
93
  }
77
94
 
78
- If you're running Ruby 1.9, this rule is highly simplified:
95
+ If you're running Ruby 1.9, this rule is simplified:
79
96
 
80
97
  maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
81
98
  send_file /(.*)$(?<!css|png|jpg)/, maintenance_file, :if => Proc.new { |rack_env|
@@ -83,19 +100,13 @@ If you're running Ruby 1.9, this rule is highly simplified:
83
100
  }
84
101
 
85
102
  For those using the oniguruma gem with their ruby 1.8 installation, you can
86
- get away with this:
103
+ get away with:
87
104
 
88
105
  maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
89
- send_file Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)"), maintenace_file, :if => Proc.new { |rack_env|
106
+ send_file Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)"), maintenance_file, :if => Proc.new { |rack_env|
90
107
  File.exists?(maintenance_file)
91
108
  }
92
109
 
93
- NOTE: These replacement rules actually issue redirects. The apache config
94
- snippet referenced above actually performs a rewrite. With Rack::Rewrite
95
- we currently have to issue a redirect because rails will not recognize the
96
- maintenance route. If you have any ideas on how to fix this, I would love
97
- to discuss it with you.
98
-
99
110
  == Rewrite Rules
100
111
 
101
112
  === :rewrite
@@ -179,17 +190,6 @@ received between 12AM and 8AM to an unavailable page.
179
190
  Time.now.hour < 8 ? "/unavailable.html" : match[1]
180
191
  }
181
192
 
182
- Note also that the rack environment is yielded to the lambda. The
183
- following redirect rule will send all visitors coming from a
184
-
185
- rewrite %r{(.*)}, lambda { |match, rack_env|
186
- if rack_env['HTTP_REFERER'] =~ /microsoft\.com/
187
-
188
- Time.now.hour < 8 ? "/unavailable.html" : match[1]
189
- }
190
-
191
-
192
-
193
193
  == Copyright
194
194
 
195
- Copyright (c) 2009 John Trupiano. See LICENSE for details.
195
+ Copyright (c) 2009-2010 John Trupiano. See LICENSE for details.
data/Rakefile CHANGED
@@ -57,5 +57,6 @@ Rake::RDocTask.new do |rdoc|
57
57
  rdoc.rdoc_dir = 'rdoc'
58
58
  rdoc.title = "rack-rewrite #{version}"
59
59
  rdoc.rdoc_files.include('README*')
60
+ rdoc.rdoc_files.include('History.rdoc')
60
61
  rdoc.rdoc_files.include('lib/**/*.rb')
61
62
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
@@ -13,7 +13,7 @@ module Rack
13
13
  # using method_missing
14
14
 
15
15
  # Creates a rewrite rule that will simply rewrite the REQUEST_URI,
16
- # PATH_INFO, and QUERYSTRING headers of the Rack environment. The
16
+ # PATH_INFO, and QUERY_STRING headers of the Rack environment. The
17
17
  # user's browser will continue to show the initially requested URL.
18
18
  #
19
19
  # rewrite '/wiki/John_Trupiano', '/john'
@@ -45,7 +45,7 @@ module Rack
45
45
  # Creates a rule that will render a file if matched.
46
46
  #
47
47
  # send_file /*/, 'public/system/maintenance.html',
48
- # :if => { File.exists?('public/system/maintenance.html') }
48
+ # :if => Proc.new { File.exists?('public/system/maintenance.html') }
49
49
  def send_file(from, to, *args)
50
50
  options = args.last.is_a?(Hash) ? args.last : {}
51
51
  @rules << Rule.new(:send_file, from, to, options[:if])
@@ -55,7 +55,7 @@ module Rack
55
55
  # if matched.
56
56
  #
57
57
  # x_send_file /*/, 'public/system/maintenance.html',
58
- # :if => { File.exists?('public/system/maintenance.html') }
58
+ # :if => Proc.new { File.exists?('public/system/maintenance.html') }
59
59
  def x_send_file(from, to, *args)
60
60
  options = args.last.is_a?(Hash) ? args.last : {}
61
61
  @rules << Rule.new(:x_send_file, from, to, options[:if])
@@ -71,8 +71,8 @@ module Rack
71
71
 
72
72
  def matches?(rack_env) #:nodoc:
73
73
  return false if !guard.nil? && !guard.call(rack_env)
74
- path = rack_env['REQUEST_URI']
75
- if self.from.is_a?(Regexp) || (Object.const_defined?(:Oniguruma) && self.from.is_a?(Oniguruma::ORegexp))
74
+ path = rack_env['REQUEST_URI'].nil? ? rack_env['PATH_INFO'] : rack_env['REQUEST_URI']
75
+ if self.is_a_regexp?(self.from)
76
76
  path =~ self.from
77
77
  elsif self.from.is_a?(String)
78
78
  path == self.from
@@ -84,7 +84,7 @@ module Rack
84
84
  # Either (a) return a Rack response (short-circuiting the Rack stack), or
85
85
  # (b) alter env as necessary and return true
86
86
  def apply!(env) #:nodoc:
87
- interpreted_to = self.send(:interpret_to, env['REQUEST_URI'], env)
87
+ interpreted_to = self.interpret_to(env['REQUEST_URI'], env)
88
88
  case self.rule_type
89
89
  when :r301
90
90
  [301, {'Location' => interpreted_to, 'Content-Type' => 'text/html'}, ['Redirecting...']]
@@ -95,10 +95,10 @@ module Rack
95
95
  env['REQUEST_URI'] = interpreted_to
96
96
  if q_index = interpreted_to.index('?')
97
97
  env['PATH_INFO'] = interpreted_to[0..q_index-1]
98
- env['QUERYSTRING'] = interpreted_to[q_index+1..interpreted_to.size-1]
98
+ env['QUERY_STRING'] = interpreted_to[q_index+1..interpreted_to.size-1]
99
99
  else
100
100
  env['PATH_INFO'] = interpreted_to
101
- env['QUERYSTRING'] = ''
101
+ env['QUERY_STRING'] = ''
102
102
  end
103
103
  true
104
104
  when :send_file
@@ -117,20 +117,25 @@ module Rack
117
117
  end
118
118
  end
119
119
 
120
- private
120
+ protected
121
121
  def interpret_to(path, env={}) #:nodoc:
122
122
  return interpret_to_proc(path, env) if self.to.is_a?(Proc)
123
123
  return computed_to(path) if compute_to?(path)
124
124
  self.to
125
125
  end
126
+
127
+ def is_a_regexp?(obj)
128
+ obj.is_a?(Regexp) || (Object.const_defined?(:Oniguruma) && obj.is_a?(Oniguruma::ORegexp))
129
+ end
126
130
 
131
+ private
127
132
  def interpret_to_proc(path, env)
128
133
  return self.to.call(match(path), env) if self.from.is_a?(Regexp)
129
134
  self.to.call(self.from, env)
130
135
  end
131
136
 
132
137
  def compute_to?(path)
133
- self.from.is_a?(Regexp) && match(path)
138
+ self.is_a_regexp?(from) && match(path)
134
139
  end
135
140
 
136
141
  def match(path)
@@ -140,11 +145,12 @@ module Rack
140
145
  def computed_to(path)
141
146
  # is there a better way to do this?
142
147
  computed_to = self.to.dup
148
+ computed_to.gsub!("$&",match(path).to_s)
143
149
  (match(path).size - 1).downto(1) do |num|
144
- computed_to.gsub!("$#{num}", match(path)[num])
150
+ computed_to.gsub!("$#{num}", match(path)[num].to_s)
145
151
  end
146
152
  return computed_to
147
- end
153
+ end
148
154
  end
149
155
  end
150
156
  end
@@ -5,16 +5,17 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rack-rewrite}
8
- s.version = "0.2.0"
8
+ s.version = "0.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["John Trupiano"]
12
- s.date = %q{2009-11-14}
12
+ s.date = %q{2010-01-06}
13
13
  s.description = %q{A rack middleware for enforcing rewrite rules. In many cases you can get away with rack-rewrite instead of writing Apache mod_rewrite rules.}
14
14
  s.email = %q{jtrupiano@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.rdoc",
18
+ "TODO"
18
19
  ]
19
20
  s.files = [
20
21
  ".document",
@@ -3,7 +3,11 @@ require 'test_helper'
3
3
  class RackRewriteTest < Test::Unit::TestCase
4
4
 
5
5
  def call_args(overrides={})
6
- {'REQUEST_URI' => '/wiki/Yair_Flicker', 'PATH_INFO' => '/wiki/Yair_Flicker', 'QUERYSTRING' => ''}.merge(overrides)
6
+ {'REQUEST_URI' => '/wiki/Yair_Flicker', 'PATH_INFO' => '/wiki/Yair_Flicker', 'QUERY_STRING' => ''}.merge(overrides)
7
+ end
8
+
9
+ def call_args_no_req(overrides={})
10
+ {'PATH_INFO' => '/wiki/Yair_Flicker', 'QUERY_STRING' => ''}.merge(overrides)
7
11
  end
8
12
 
9
13
  def self.should_not_halt
@@ -90,10 +94,36 @@ class RackRewriteTest < Test::Unit::TestCase
90
94
  assert_equal '/john', @initial_args['PATH_INFO']
91
95
  end
92
96
  should "set REQUEST_URI to '/john'" do
93
- assert_equal '/john', @initial_args['REQUEST_URI']
97
+ assert_equal '/john', @initial_args['REQUEST_URI']
98
+ end
99
+ should "set QUERY_STRING to ''" do
100
+ assert_equal '', @initial_args['QUERY_STRING']
101
+ end
102
+ end
103
+ end
104
+
105
+ context 'when a rewrite rule matches but there is no REQUEST_URI set' do
106
+ setup {
107
+ @rack = Rack::Rewrite.new(@app) do
108
+ rewrite '/wiki/Yair_Flicker', '/john'
109
+ end
110
+ }
111
+ should_not_halt
112
+
113
+ context 'the env' do
114
+ setup do
115
+ @initial_args = call_args_no_req.dup
116
+ @rack.call(@initial_args)
117
+ end
118
+
119
+ should "set PATH_INFO to '/john'" do
120
+ assert_equal '/john', @initial_args['PATH_INFO']
121
+ end
122
+ should "set REQUEST_URI to '/john'" do
123
+ assert_equal '/john', @initial_args['REQUEST_URI']
94
124
  end
95
- should "set QUERYSTRING to ''" do
96
- assert_equal '', @initial_args['QUERYSTRING']
125
+ should "set QUERY_STRING to ''" do
126
+ assert_equal '', @initial_args['QUERY_STRING']
97
127
  end
98
128
  end
99
129
  end
@@ -38,27 +38,27 @@ class RuleTest < Test::Unit::TestCase
38
38
  assert_equal rule.send(:interpret_to, '/abc'), rule.apply!(env)[1]['Location']
39
39
  end
40
40
 
41
- should 'keep the QUERYSTRING when a 301 rule matches a URL with a querystring' do
41
+ should 'keep the QUERY_STRING when a 301 rule matches a URL with a querystring' do
42
42
  rule = Rack::Rewrite::Rule.new(:r301, %r{/john(.*)}, '/yair$1')
43
- env = {'REQUEST_URI' => '/john?show_bio=1', 'PATH_INFO' => '/john', 'QUERYSTRING' => 'show_bio=1'}
43
+ env = {'REQUEST_URI' => '/john?show_bio=1', 'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
44
44
  assert_equal '/yair?show_bio=1', rule.apply!(env)[1]['Location']
45
45
  end
46
46
 
47
- should 'keep the QUERYSTRING when a rewrite rule that requires a querystring matches a URL with a querystring' do
47
+ should 'keep the QUERY_STRING when a rewrite rule that requires a querystring matches a URL with a querystring' do
48
48
  rule = Rack::Rewrite::Rule.new(:rewrite, %r{/john(\?.*)}, '/yair$1')
49
- env = {'REQUEST_URI' => '/john?show_bio=1', 'PATH_INFO' => '/john', 'QUERYSTRING' => 'show_bio=1'}
49
+ env = {'REQUEST_URI' => '/john?show_bio=1', 'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
50
50
  rule.apply!(env)
51
51
  assert_equal '/yair', env['PATH_INFO']
52
- assert_equal 'show_bio=1', env['QUERYSTRING']
52
+ assert_equal 'show_bio=1', env['QUERY_STRING']
53
53
  assert_equal '/yair?show_bio=1', env['REQUEST_URI']
54
54
  end
55
55
 
56
- should 'update the QUERYSTRING when a rewrite rule changes its value' do
56
+ should 'update the QUERY_STRING when a rewrite rule changes its value' do
57
57
  rule = Rack::Rewrite::Rule.new(:rewrite, %r{/(\w+)\?show_bio=(\d)}, '/$1?bio=$2')
58
- env = {'REQUEST_URI' => '/john?show_bio=1', 'PATH_INFO' => '/john', 'QUERYSTRING' => 'show_bio=1'}
58
+ env = {'REQUEST_URI' => '/john?show_bio=1', 'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'}
59
59
  rule.apply!(env)
60
60
  assert_equal '/john', env['PATH_INFO']
61
- assert_equal 'bio=1', env['QUERYSTRING']
61
+ assert_equal 'bio=1', env['QUERY_STRING']
62
62
  assert_equal '/john?bio=1', env['REQUEST_URI']
63
63
  end
64
64
 
@@ -206,7 +206,7 @@ class RuleTest < Test::Unit::TestCase
206
206
  setup do
207
207
  @rule = Rack::Rewrite::Rule.new(:rewrite, /.*/, '/system/maintenance.html', lambda { |rack_env|
208
208
  maintenance_file = File.join('system', 'maintenance.html')
209
- File.exists?(maintenance_file) && !%w(css jpg png).any? {|ext| rack_env['REQUEST_URI'] =~ Regexp.new("\.#{ext}$")}
209
+ File.exists?(maintenance_file) && rack_env['REQUEST_URI'] !~ /\.(css|jpg|png)/
210
210
  })
211
211
  end
212
212
  should_pass_maintenance_tests
@@ -222,6 +222,25 @@ class RuleTest < Test::Unit::TestCase
222
222
  should_pass_maintenance_tests
223
223
  end
224
224
  end
225
+
226
+ context 'Given the CNAME alternative rewrite rule in our README' do
227
+ setup do
228
+ @rule = Rack::Rewrite::Rule.new(:r301, %r{.*}, 'http://mynewdomain.com$&', lambda {|rack_env|
229
+ rack_env['SERVER_NAME'] != 'mynewdomain.com'
230
+ })
231
+ end
232
+
233
+ should 'match requests for domain myolddomain.com and redirect to mynewdomain.com' do
234
+ env = {'REQUEST_URI' => '/anything?abc=1', 'PATH_INFO' => '/anything', 'QUERY_STRING' => 'abc=1', 'SERVER_NAME' => 'myolddomain.com'}
235
+ assert @rule.matches?(env)
236
+ rack_response = @rule.apply!(env)
237
+ assert_equal 'http://mynewdomain.com/anything?abc=1', rack_response[1]['Location']
238
+ end
239
+
240
+ should 'not match requests for domain mynewdomain.com' do
241
+ assert !@rule.matches?({'REQUEST_URI' => '/anything', 'SERVER_NAME' => 'mynewdomain.com'})
242
+ end
243
+ end
225
244
  end
226
245
 
227
246
  context 'Rule#interpret_to' do
@@ -246,6 +265,16 @@ class RuleTest < Test::Unit::TestCase
246
265
  assert_equal 'jihgfedcba', rule.send(:interpret_to, "abcdefghij")
247
266
  end
248
267
 
268
+ should 'replace $& on a match' do
269
+ rule = Rack::Rewrite::Rule.new(:rewrite, %r{.*}, 'http://example.org$&')
270
+ assert_equal 'http://example.org/person/1', rule.send(:interpret_to, "/person/1")
271
+ end
272
+
273
+ should 'ignore empty captures' do
274
+ rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person(_\d+)?}, '/people/$1')
275
+ assert_equal '/people/', rule.send(:interpret_to, "/person")
276
+ end
277
+
249
278
  should 'call to with from when it is a lambda' do
250
279
  rule = Rack::Rewrite::Rule.new(:rewrite, 'a', lambda { |from, env| from * 2 })
251
280
  assert_equal 'aa', rule.send(:interpret_to, 'a')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-rewrite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Trupiano
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-14 00:00:00 -05:00
12
+ date: 2010-01-06 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -31,6 +31,7 @@ extensions: []
31
31
  extra_rdoc_files:
32
32
  - LICENSE
33
33
  - README.rdoc
34
+ - TODO
34
35
  files:
35
36
  - .document
36
37
  - .gitignore