rack-rewrite 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.rdoc ADDED
@@ -0,0 +1,23 @@
1
+ === 0.2.0 / 2009-11-14
2
+ * API
3
+ * Allow Proc's to be be passed as the 'to' argument to rule declarations
4
+ * Introduce rule guard support using :if => Proc.new option.
5
+ * :send_file and :x_send_file rules
6
+ * proxy rack_env to rule guards for arbitrary rule writing
7
+
8
+ * Documentation
9
+ * Add example of writing capistrano maintenance page rewrite rules
10
+ * Add examples of rule guards and arbitrary rewriting
11
+ * Add examples of :send_file and :x_send_file rules
12
+
13
+ === 0.1.3 / 2009-11-14
14
+ * Maintenance
15
+ * Ensure Content-Type header is set for 301's and 302's (thanks to Sebastian Röbke)
16
+ * Documentation
17
+ * Add HISTORY.rdoc
18
+
19
+ === 0.1.2 / 2009-10-13
20
+
21
+ * Initial Feature Set
22
+ * :r301, :r302 and :redirect are supported in the rewrite DSL
23
+ * Regex matching/substitution patterns supported in rules
data/README.rdoc CHANGED
@@ -3,6 +3,29 @@
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
+ == Usage
7
+
8
+ === Sample rackup file
9
+
10
+ gem 'rack-rewrite', '~> 0.1.3'
11
+ require 'rack-rewrite
12
+ use Rack::Rewrite do
13
+ rewrite '/wiki/John_Trupiano', '/john'
14
+ r301 '/wiki/Yair_Flicker', '/yair'
15
+ r302 '/wiki/Greg_Jastrab', '/greg'
16
+ r301 %r{/wiki/(\w+)_\w+}, '/$1'
17
+ end
18
+
19
+ === Sample usage in a rails app
20
+ config.gem 'rack-rewrite', '~> 0.1.3'
21
+ require 'rack-rewrite
22
+ config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
23
+ rewrite '/wiki/John_Trupiano', '/john'
24
+ r301 '/wiki/Yair_Flicker', '/yair'
25
+ r302 '/wiki/Greg_Jastrab', '/greg'
26
+ r301 %r{/wiki/(\w+)_\w+}, '/$1'
27
+ end
28
+
6
29
  == Use Cases
7
30
 
8
31
  === Rebuild of existing site in a new technology
@@ -30,27 +53,49 @@ to these routes and keep your routes.rb clean.
30
53
 
31
54
  rewrite %r{/features(.*)}, '/facial_features$1'
32
55
 
33
- == Sample rackup file
34
-
35
- gem 'rack-rewrite', '~> 0.1.2'
36
- require 'rack-rewrite
37
- use Rack::Rewrite do
38
- rewrite '/wiki/John_Trupiano', '/john'
39
- r301 '/wiki/Yair_Flicker', '/yair'
40
- r302 '/wiki/Greg_Jastrab', '/greg'
41
- r301 %r{/wiki/(\w+)_\w+}, '/$1'
42
- end
56
+ === Site Maintenance
43
57
 
44
- == Sample usage in a rails app
45
- config.gem 'rack-rewrite', '~> 0.1.2'
46
- require 'rack-rewrite
47
- config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
48
- rewrite '/wiki/John_Trupiano', '/john'
49
- r301 '/wiki/Yair_Flicker', '/yair'
50
- r302 '/wiki/Greg_Jastrab', '/greg'
51
- r301 %r{/wiki/(\w+)_\w+}, '/$1'
52
- end
58
+ Most capistrano users will be familiar with the following Apache rewrite rules:
59
+
60
+ RewriteCond %{REQUEST_URI} !\.(css|jpg|png)$
61
+ RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
62
+ RewriteCond %{SCRIPT_FILENAME} !maintenance.html
63
+ RewriteRule ^.*$ /system/maintenance.html [L]
64
+
65
+ This rewrite rule says to render a maintenance page for all non-asset requests
66
+ if the maintenance file exists. In capistrano, you can quickly upload a
67
+ maintenance file using:
68
+
69
+ cap deploy:web:disable REASON=upgrade UNTIL=12:30PM
53
70
 
71
+ We can replace the mod_rewrite rules with the following Rack::Rewrite rule:
72
+
73
+ maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
74
+ 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}$")}
76
+ }
77
+
78
+ If you're running Ruby 1.9, this rule is highly simplified:
79
+
80
+ maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
81
+ send_file /(.*)$(?<!css|png|jpg)/, maintenance_file, :if => Proc.new { |rack_env|
82
+ File.exists?(maintenance_file)
83
+ }
84
+
85
+ For those using the oniguruma gem with their ruby 1.8 installation, you can
86
+ get away with this:
87
+
88
+ 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|
90
+ File.exists?(maintenance_file)
91
+ }
92
+
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
+
54
99
  == Rewrite Rules
55
100
 
56
101
  === :rewrite
@@ -86,6 +131,19 @@ Recall that rules are interpreted from top to bottom. So you can install
86
131
  "default" rewrite rules if you like. [2] is a sample default rule that
87
132
  will redirect all other requests to the wiki to a google search.
88
133
 
134
+ === :send_file, :x_send_file
135
+
136
+ Calls to #send_file and #x_send_file also have the same signature as #rewrite.
137
+ If the rule matches, the 'to' parameter is interpreted as a path to a file
138
+ to be rendered instead of passing the application call up the rack stack.
139
+
140
+ send_file /*/, 'public/spammers.htm', :if => Proc.new { |rack_env|
141
+ rack_env['HTTP_REFERER'] =~ 'spammers.com'
142
+ }
143
+ x_send_file /^blog\/.*/, 'public/blog_offline.htm', :if => Proc.new { |rack_env|
144
+ File.exists?('public/blog_offline.htm')
145
+ }
146
+
89
147
  == Tips
90
148
 
91
149
  === Keeping your querystring
@@ -99,6 +157,39 @@ capture group and substitution pattern in your rewrite rule to achieve this.
99
157
  This rule will store the querystring in a capture group (via '(?.*)' ) and
100
158
  will substitute the querystring back into the rewritten URL (via $1).
101
159
 
160
+ === Rule Guards
161
+
162
+ All rules support passing guards as Procs/lambdas. Guards simply return
163
+ true or false indicating whether the rule declaration is a match. The
164
+ following example demonstrates how the presence of a maintenance page
165
+ on the filesystem can be utilized to take your site(s) offline.
166
+
167
+ maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
168
+ x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
169
+ File.exists?(maintenance_file)
170
+ }
171
+
172
+ === Arbitrary Rewriting
173
+
174
+ All rules support passing a Proc as the second argument allowing you to
175
+ perform arbitrary rewrites. The following rule will rewrite all requests
176
+ received between 12AM and 8AM to an unavailable page.
177
+
178
+ rewrite %r{(.*)}, lambda { |match, rack_env|
179
+ Time.now.hour < 8 ? "/unavailable.html" : match[1]
180
+ }
181
+
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
+
102
193
  == Copyright
103
194
 
104
195
  Copyright (c) 2009 John Trupiano. See LICENSE for details.
data/TODO CHANGED
@@ -1,4 +1,9 @@
1
- * Add :host support to restrict which URL's a rewrite rule matches [10/15/09]
2
- * Add :if => lambda support for arbitrary conditional rule application (this will allow us to do the capistrano maintenance page w/o apache's mod_rewrite)
3
- * Add support for specifying a config file instead of passing a block (e.g. config/rewrite.rb)
4
- * Better message than "Redirecting..." -- how about html that says where it's being redirected to?
1
+ * OUTSTANDING
2
+ * Add :host support to restrict which URL's a rewrite rule matches [10/15/09]
3
+ * Add support for specifying a config file instead of passing a block (e.g. config/rewrite.rb) [10/15/09]
4
+ * Better message than "Redirecting..." -- how about html that says where it's being redirected to? [10/16/09]
5
+ * Provide testing helpers (e.g. should_rewrite) to facilitate straightforward testing. [10/25/09]
6
+ * Allow rules to return arbitrary html (e.g. the contents of the maintenance page) [10/25/09]
7
+
8
+ * COMPLETED
9
+ * Add :if => lambda support for arbitrary conditional rule application (this will allow us to do the capistrano maintenance page w/o apache's mod_rewrite) [10/15/09]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.2.0
data/lib/rack-rewrite.rb CHANGED
@@ -23,7 +23,7 @@ module Rack
23
23
 
24
24
  private
25
25
  def find_first_matching_rule(env) #:nodoc:
26
- @rule_set.rules.detect { |rule| rule.matches?(env['REQUEST_URI']) }
26
+ @rule_set.rules.detect { |rule| rule.matches?(env) }
27
27
  end
28
28
  end
29
29
  end
@@ -1,3 +1,5 @@
1
+ require 'rack/mime'
2
+
1
3
  module Rack
2
4
  class Rewrite
3
5
  class RuleSet
@@ -15,40 +17,64 @@ module Rack
15
17
  # user's browser will continue to show the initially requested URL.
16
18
  #
17
19
  # rewrite '/wiki/John_Trupiano', '/john'
18
- # rewrite %r{/wiki/(\w+)_\w+}, '/$1'
19
- def rewrite(from, to)
20
- @rules << Rule.new(:rewrite, from, to)
20
+ # rewrite %r{/wiki/(\w+)_\w+}, '/$1'
21
+ # rewrite %r{(.*)}, '/maintenance.html', :if => lambda { File.exists?('maintenance.html') }
22
+ def rewrite(from, to, *args)
23
+ options = args.last.is_a?(Hash) ? args.last : {}
24
+ @rules << Rule.new(:rewrite, from, to, options[:if])
21
25
  end
22
26
 
23
27
  # Creates a redirect rule that will send a 301 when matching.
24
28
  #
25
29
  # r301 '/wiki/John_Trupiano', '/john'
26
30
  # r301 '/contact-us.php', '/contact-us'
27
- def r301(from, to)
28
- @rules << Rule.new(:r301, from, to)
31
+ def r301(from, to, *args)
32
+ options = args.last.is_a?(Hash) ? args.last : {}
33
+ @rules << Rule.new(:r301, from, to, options[:if])
29
34
  end
30
35
 
31
36
  # Creates a redirect rule that will send a 302 when matching.
32
37
  #
33
38
  # r302 '/wiki/John_Trupiano', '/john'
34
39
  # r302 '/wiki/(.*)', 'http://www.google.com/?q=$1'
35
- def r302(from, to)
36
- @rules << Rule.new(:r302, from, to)
40
+ def r302(from, to, *args)
41
+ options = args.last.is_a?(Hash) ? args.last : {}
42
+ @rules << Rule.new(:r302, from, to, options[:if])
37
43
  end
44
+
45
+ # Creates a rule that will render a file if matched.
46
+ #
47
+ # send_file /*/, 'public/system/maintenance.html',
48
+ # :if => { File.exists?('public/system/maintenance.html') }
49
+ def send_file(from, to, *args)
50
+ options = args.last.is_a?(Hash) ? args.last : {}
51
+ @rules << Rule.new(:send_file, from, to, options[:if])
52
+ end
53
+
54
+ # Creates a rule that will render a file using x-send-file
55
+ # if matched.
56
+ #
57
+ # x_send_file /*/, 'public/system/maintenance.html',
58
+ # :if => { File.exists?('public/system/maintenance.html') }
59
+ def x_send_file(from, to, *args)
60
+ options = args.last.is_a?(Hash) ? args.last : {}
61
+ @rules << Rule.new(:x_send_file, from, to, options[:if])
62
+ end
38
63
  end
39
64
 
40
65
  # TODO: Break rules into subclasses
41
66
  class Rule #:nodoc:
42
- attr_reader :rule_type, :from, :to
43
- def initialize(rule_type, from, to) #:nodoc:
44
- @rule_type, @from, @to = rule_type, from, to
67
+ attr_reader :rule_type, :from, :to, :guard
68
+ def initialize(rule_type, from, to, guard=nil) #:nodoc:
69
+ @rule_type, @from, @to, @guard = rule_type, from, to, guard
45
70
  end
46
71
 
47
- def matches?(path) #:nodoc:
48
- case self.from
49
- when Regexp
72
+ def matches?(rack_env) #:nodoc:
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))
50
76
  path =~ self.from
51
- when String
77
+ elsif self.from.is_a?(String)
52
78
  path == self.from
53
79
  else
54
80
  false
@@ -58,7 +84,7 @@ module Rack
58
84
  # Either (a) return a Rack response (short-circuiting the Rack stack), or
59
85
  # (b) alter env as necessary and return true
60
86
  def apply!(env) #:nodoc:
61
- interpreted_to = self.send(:interpret_to, env['REQUEST_URI'])
87
+ interpreted_to = self.send(:interpret_to, env['REQUEST_URI'], env)
62
88
  case self.rule_type
63
89
  when :r301
64
90
  [301, {'Location' => interpreted_to, 'Content-Type' => 'text/html'}, ['Redirecting...']]
@@ -75,25 +101,50 @@ module Rack
75
101
  env['QUERYSTRING'] = ''
76
102
  end
77
103
  true
104
+ when :send_file
105
+ [200, {
106
+ 'Content-Length' => ::File.size(interpreted_to).to_s,
107
+ 'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to))
108
+ }, ::File.read(interpreted_to)]
109
+ when :x_send_file
110
+ [200, {
111
+ 'X-Sendfile' => interpreted_to,
112
+ 'Content-Length' => ::File.size(interpreted_to).to_s,
113
+ 'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to))
114
+ }, []]
78
115
  else
79
116
  raise Exception.new("Unsupported rule: #{self.rule_type}")
80
117
  end
81
118
  end
82
119
 
83
120
  private
84
- # is there a better way to do this?
85
- def interpret_to(path) #:nodoc:
86
- if self.from.is_a?(Regexp)
87
- if from_match_data = self.from.match(path)
88
- computed_to = self.to.dup
89
- (from_match_data.size - 1).downto(1) do |num|
90
- computed_to.gsub!("$#{num}", from_match_data[num])
91
- end
92
- return computed_to
93
- end
94
- end
121
+ def interpret_to(path, env={}) #:nodoc:
122
+ return interpret_to_proc(path, env) if self.to.is_a?(Proc)
123
+ return computed_to(path) if compute_to?(path)
95
124
  self.to
96
125
  end
97
- end
126
+
127
+ def interpret_to_proc(path, env)
128
+ return self.to.call(match(path), env) if self.from.is_a?(Regexp)
129
+ self.to.call(self.from, env)
130
+ end
131
+
132
+ def compute_to?(path)
133
+ self.from.is_a?(Regexp) && match(path)
134
+ end
135
+
136
+ def match(path)
137
+ self.from.match(path)
138
+ end
139
+
140
+ def computed_to(path)
141
+ # is there a better way to do this?
142
+ computed_to = self.to.dup
143
+ (match(path).size - 1).downto(1) do |num|
144
+ computed_to.gsub!("$#{num}", match(path)[num])
145
+ end
146
+ return computed_to
147
+ end
148
+ end
98
149
  end
99
- end
150
+ end
data/rack-rewrite.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rack-rewrite}
8
- s.version = "0.1.3"
8
+ s.version = "0.2.0"
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"]
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.files = [
20
20
  ".document",
21
21
  ".gitignore",
22
- "HISTORY.rdoc",
22
+ "History.rdoc",
23
23
  "LICENSE",
24
24
  "README.rdoc",
25
25
  "Rakefile",
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
28
28
  "lib/rack-rewrite.rb",
29
29
  "lib/rack-rewrite/rule.rb",
30
30
  "rack-rewrite.gemspec",
31
+ "test/geminstaller.yml",
31
32
  "test/rack-rewrite_test.rb",
32
33
  "test/rule_test.rb",
33
34
  "test/test_helper.rb"
@@ -0,0 +1,9 @@
1
+ gems:
2
+ - name: jeweler
3
+ version: '~> 1.3.0'
4
+ - name: shoulda
5
+ version: '~> 2.10.2'
6
+ - name: mocha
7
+ version: '~> 0.9.7'
8
+ - name: oniguruma
9
+ version: '~> 1.1.0'
data/test/rule_test.rb CHANGED
@@ -1,7 +1,36 @@
1
- require 'test_helper'
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
3
  class RuleTest < Test::Unit::TestCase
4
+
5
+ def self.should_pass_maintenance_tests
6
+ context 'and the maintenance file does in fact exist' do
7
+ setup { File.stubs(:exists?).returns(true) }
4
8
 
9
+ should('match for the root') { assert @rule.matches?({'REQUEST_URI' => '/'}) }
10
+ should('match for a regular rails route') { assert @rule.matches?({'REQUEST_URI' => '/users/1'}) }
11
+ should('match for an html page') { assert @rule.matches?({'REQUEST_URI' => '/index.html'}) }
12
+ should('not match for a css file') { assert !@rule.matches?({'REQUEST_URI' => '/stylesheets/style.css'}) }
13
+ should('not match for a jpg file') { assert !@rule.matches?({'REQUEST_URI' => '/images/sls.jpg'}) }
14
+ should('not match for a png file') { assert !@rule.matches?({'REQUEST_URI' => '/images/sls.png'}) }
15
+ end
16
+ end
17
+
18
+ def self.negative_lookahead_supported?
19
+ begin
20
+ require 'oniguruma'
21
+ rescue LoadError; end
22
+ RUBY_VERSION =~ /^1\.9/ || Object.const_defined?(:Oniguruma)
23
+ end
24
+
25
+ def negative_lookahead_regexp
26
+ if RUBY_VERSION =~ /^1\.9/
27
+ # have to use the constructor instead of the literal syntax b/c load errors occur in Ruby 1.8
28
+ Regexp.new("(.*)$(?<!css|png|jpg)")
29
+ else
30
+ Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)")
31
+ end
32
+ end
33
+
5
34
  context '#Rule#apply' do
6
35
  should 'set Location header to result of #interpret_to for a 301' do
7
36
  rule = Rack::Rewrite::Rule.new(:r301, %r{/abc}, '/def')
@@ -40,6 +69,64 @@ class RuleTest < Test::Unit::TestCase
40
69
  assert_equal 'text/html', rule.apply!(env)[1]['Content-Type']
41
70
  end
42
71
  end
72
+
73
+ context 'Given an :x_send_file rule that matches' do
74
+ setup do
75
+ @file = File.join(TEST_ROOT, 'geminstaller.yml')
76
+ @rule = Rack::Rewrite::Rule.new(:x_send_file, /.*/, @file)
77
+ env = {'PATH_INFO' => '/abc'}
78
+ @response = @rule.apply!(env)
79
+ end
80
+
81
+ should 'return 200' do
82
+ assert_equal 200, @response[0]
83
+ end
84
+
85
+ should 'return an X-Sendfile header' do
86
+ assert @response[1].has_key?('X-Sendfile')
87
+ end
88
+
89
+ should 'return a Content-Type of text/yaml' do
90
+ assert_equal 'text/yaml', @response[1]['Content-Type']
91
+ end
92
+
93
+ should 'return the proper Content-Length' do
94
+ assert_equal File.size(@file).to_s, @response[1]['Content-Length']
95
+ end
96
+
97
+ should 'return empty content' do
98
+ assert_equal [], @response[2]
99
+ end
100
+ end
101
+
102
+ context 'Given a :send_file rule that matches' do
103
+ setup do
104
+ @file = File.join(TEST_ROOT, 'geminstaller.yml')
105
+ @rule = Rack::Rewrite::Rule.new(:send_file, /.*/, @file)
106
+ env = {'PATH_INFO' => '/abc'}
107
+ @response = @rule.apply!(env)
108
+ end
109
+
110
+ should 'return 200' do
111
+ assert_equal 200, @response[0]
112
+ end
113
+
114
+ should 'not return an X-Sendfile header' do
115
+ assert !@response[1].has_key?('X-Sendfile')
116
+ end
117
+
118
+ should 'return a Content-Type of text/yaml' do
119
+ assert_equal 'text/yaml', @response[1]['Content-Type']
120
+ end
121
+
122
+ should 'return the proper Content-Length' do
123
+ assert_equal File.size(@file).to_s, @response[1]['Content-Length']
124
+ end
125
+
126
+ should 'return the contents of geminstaller.yml' do
127
+ assert_equal File.read(@file), @response[2]
128
+ end
129
+ end
43
130
  end
44
131
 
45
132
  context 'Rule#matches' do
@@ -49,15 +136,15 @@ class RuleTest < Test::Unit::TestCase
49
136
  end
50
137
 
51
138
  should 'match PATH_INFO of /features' do
52
- assert @rule.matches?("/features")
139
+ assert @rule.matches?({'REQUEST_URI' => "/features"})
53
140
  end
54
141
 
55
142
  should 'not match PATH_INFO of /features.xml' do
56
- assert !@rule.matches?("/features.xml")
143
+ assert !@rule.matches?({'REQUEST_URI' => "/features.xml"})
57
144
  end
58
145
 
59
146
  should 'not match PATH_INFO of /my_features' do
60
- assert !@rule.matches?("/my_features")
147
+ assert !@rule.matches?({'REQUEST_URI' => "/my_features"})
61
148
  end
62
149
  end
63
150
 
@@ -67,23 +154,72 @@ class RuleTest < Test::Unit::TestCase
67
154
  end
68
155
 
69
156
  should 'match PATH_INFO of /features' do
70
- assert @rule.matches?("/features")
157
+ assert @rule.matches?({'REQUEST_URI' => "/features"})
71
158
  end
72
159
 
73
160
  should 'match PATH_INFO of /features.xml' do
74
- assert @rule.matches?('/features.xml')
161
+ assert @rule.matches?({'REQUEST_URI' => '/features.xml'})
75
162
  end
76
163
 
77
164
  should 'match PATH_INFO of /features/1' do
78
- assert @rule.matches?('/features/1')
165
+ assert @rule.matches?({'REQUEST_URI' => '/features/1'})
79
166
  end
80
167
 
81
168
  should 'match PATH_INFO of /features?filter_by=name' do
82
- assert @rule.matches?('/features?filter_by_name=name')
169
+ assert @rule.matches?({'REQUEST_URI' => '/features?filter_by_name=name'})
83
170
  end
84
171
 
85
172
  should 'match PATH_INFO of /features/1?hide_bio=1' do
86
- assert @rule.matches?('/features/1?hide_bio=1')
173
+ assert @rule.matches?({'REQUEST_URI' => '/features/1?hide_bio=1'})
174
+ end
175
+ end
176
+
177
+ context 'Given a rule with a guard that checks for the presence of a file' do
178
+ setup do
179
+ @rule = Rack::Rewrite::Rule.new(:rewrite, %r{(.)*}, '/maintenance.html', lambda { |rack_env|
180
+ File.exists?('maintenance.html')
181
+ })
182
+ end
183
+
184
+ context 'when the file exists' do
185
+ setup do
186
+ File.stubs(:exists?).returns(true)
187
+ end
188
+
189
+ should 'match' do
190
+ assert @rule.matches?({'REQUEST_URI' => '/anything/should/match'})
191
+ end
192
+ end
193
+
194
+ context 'when the file does not exist' do
195
+ setup do
196
+ File.stubs(:exists?).returns(false)
197
+ end
198
+
199
+ should 'not match' do
200
+ assert !@rule.matches?({'REQUEST_URI' => '/nothing/should/match'})
201
+ end
202
+ end
203
+ end
204
+
205
+ context 'Given the capistrano maintenance.html rewrite rule given in our README' do
206
+ setup do
207
+ @rule = Rack::Rewrite::Rule.new(:rewrite, /.*/, '/system/maintenance.html', lambda { |rack_env|
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}$")}
210
+ })
211
+ end
212
+ should_pass_maintenance_tests
213
+ end
214
+
215
+ if negative_lookahead_supported?
216
+ context 'Given the negative lookahead regular expression version of the capistrano maintenance.html rewrite rule given in our README' do
217
+ setup do
218
+ @rule = Rack::Rewrite::Rule.new(:rewrite, negative_lookahead_regexp, '/system/maintenance.html', lambda { |rack_env|
219
+ File.exists?(File.join('public', 'system', 'maintenance.html'))
220
+ })
221
+ end
222
+ should_pass_maintenance_tests
87
223
  end
88
224
  end
89
225
  end
@@ -109,5 +245,16 @@ class RuleTest < Test::Unit::TestCase
109
245
  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')
110
246
  assert_equal 'jihgfedcba', rule.send(:interpret_to, "abcdefghij")
111
247
  end
248
+
249
+ should 'call to with from when it is a lambda' do
250
+ rule = Rack::Rewrite::Rule.new(:rewrite, 'a', lambda { |from, env| from * 2 })
251
+ assert_equal 'aa', rule.send(:interpret_to, 'a')
252
+ end
253
+
254
+ should 'call to with from match data' do
255
+ rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)(.*)}, lambda {|match, env| "people-#{match[1].to_i * 3}#{match[2]}"})
256
+ assert_equal 'people-3?show_bio=1', rule.send(:interpret_to, '/person_1?show_bio=1')
257
+ end
112
258
  end
259
+
113
260
  end
data/test/test_helper.rb CHANGED
@@ -11,3 +11,5 @@ require 'rack-rewrite'
11
11
 
12
12
  class Test::Unit::TestCase
13
13
  end
14
+
15
+ TEST_ROOT = File.dirname(__FILE__)
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.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Trupiano
@@ -34,7 +34,7 @@ extra_rdoc_files:
34
34
  files:
35
35
  - .document
36
36
  - .gitignore
37
- - HISTORY.rdoc
37
+ - History.rdoc
38
38
  - LICENSE
39
39
  - README.rdoc
40
40
  - Rakefile
@@ -43,6 +43,7 @@ files:
43
43
  - lib/rack-rewrite.rb
44
44
  - lib/rack-rewrite/rule.rb
45
45
  - rack-rewrite.gemspec
46
+ - test/geminstaller.yml
46
47
  - test/rack-rewrite_test.rb
47
48
  - test/rule_test.rb
48
49
  - test/test_helper.rb
data/HISTORY.rdoc DELETED
@@ -1,10 +0,0 @@
1
- === 0.1.3 / 2009-11-14
2
- * Maintenance
3
- * Ensure Content-Type header is set for 301's and 302's (thanks to Sebastian Röbke)
4
- * Documentation
5
- * Add HISTORY.rdoc
6
-
7
- === 0.1.2 / 2009-10-15
8
- * API
9
- * rewrite, r301 and r302 rules
10
- * regular expression matching and substitution rules