pax_global_header00006660000000000000000000000064121223461250014510gustar00rootroot0000000000000052 comment=1fddd38fde3b846327d03c6eaaaab2651aa91259 ruby-rack-rewrite-1.3.3/000077500000000000000000000000001212234612500150725ustar00rootroot00000000000000ruby-rack-rewrite-1.3.3/Gemfile000066400000000000000000000001161212234612500163630ustar00rootroot00000000000000source "http://rubygems.org" gemspec group :development do gem 'rake' end ruby-rack-rewrite-1.3.3/History.rdoc000066400000000000000000000043721212234612500174120ustar00rootroot00000000000000=== 1.2.1 / 2011-09-20 * Maintenance * Use Rack::Request to match the host === 1.2.0 / 2011-09-20 * API * :headers option to send additional headers with the response === 1.1.0 / 2011-08-15 * API * :host and :method option to match SERVER_NAME and REQUEST_METHOD env params. * :not option to negative match against path. * Maintenance * Refactored internals a bit. === 1.0.2 / 2010-10-01 * Maintenance * :send_file rules return content in an Array for Ruby 1.9.2 compatibility === 1.0.1 / 2010-09-17 * Maintenance * Set Content-Type based on file extension of file/location being redirected to. Addresses GitHub Issue #8. === 1.0.0 / 2010-05-13 * API * Fix rack 1.1.0 / rails3 compatibility by eliminating reliance on REQUEST_URI env param. Paths are now constructed with PATH_INFO and QUERY_STRING * Follow rack directory/require convention: require 'rack/rewrite' instead of 'rack-rewrite' * Include an HTML anchor tag linked to where the URL being redirected to in the body of 301's and 302's === 0.2.1 / 2010-01-06 * API * Implement $& substitution pattern (thanks to {Ben Brinckerhoff}[http://github.com/bhb]) * Maintenance * Ignore empty captures instead of failing during subsitution (thanks to {Ben Brinckerhoff}[http://github.com/bhb]) * Play nice with Rack::Test requests which only set PATH_INFO and not REQUEST_URI (thanks to {@docunext}[http://github.com/docunext]) * Use QUERY_STRING instead of QUERYSTRING as per Rack spec. Closes Issue #1. === 0.2.0 / 2009-11-14 * API * Allow Proc's to be be passed as the 'to' argument to rule declarations * Introduce rule guard support using :if => Proc.new option. * :send_file and :x_send_file rules * proxy rack_env to rule guards for arbitrary rule writing * Documentation * Add example of writing capistrano maintenance page rewrite rules * Add examples of rule guards and arbitrary rewriting * Add examples of :send_file and :x_send_file rules === 0.1.3 / 2009-11-14 * Maintenance * Ensure Content-Type header is set for 301's and 302's (thanks to Sebastian Röbke) * Documentation * Add HISTORY.rdoc === 0.1.2 / 2009-10-13 * Initial Feature Set * :r301, :r302 and :redirect are supported in the rewrite DSL * Regex matching/substitution patterns supported in rules ruby-rack-rewrite-1.3.3/LICENSE000066400000000000000000000021101212234612500160710ustar00rootroot00000000000000(The MIT License) Copyright (c) 2012 — John Trupiano, Travis Jeffery Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-rack-rewrite-1.3.3/README.markdown000066400000000000000000000257571212234612500176130ustar00rootroot00000000000000# rack-rewrite A rack middleware for defining and applying rewrite rules. In many cases you can get away with rack-rewrite instead of writing Apache mod_rewrite rules. ## Usage Examples * [Rack::Rewrite for Site Maintenance and Downtime](http://blog.smartlogicsolutions.com/2009/11/16/rack-rewrite-for-site-maintenance-and-downtime/) * [Rack::Rewrite + Google Analytics Makes Site Transitions Seamless](http://blog.smartlogicsolutions.com/2009/11/24/rack-rewrite-google-analytics-makes-site-transitions-seamless/) ## Usage Details ### Sample rackup file ```ruby gem 'rack-rewrite', '~> 1.2.1' require 'rack/rewrite' use Rack::Rewrite do rewrite '/wiki/John_Trupiano', '/john' r301 '/wiki/Yair_Flicker', '/yair' r302 '/wiki/Greg_Jastrab', '/greg' r301 %r{/wiki/(\w+)_\w+}, '/$1' end ``` ### Sample usage in a rails app ```ruby config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do rewrite '/wiki/John_Trupiano', '/john' r301 '/wiki/Yair_Flicker', '/yair' r302 '/wiki/Greg_Jastrab', '/greg' r301 %r{/wiki/(\w+)_\w+}, '/$1' end ``` ## Redirection codes All redirect status codes from the [HTTP spec](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) are supported: * 301 moved permanently * 302 found * 303 see other * 307 temporary redirect These translate to the following methods inside the Rack::Rewrite block: ```ruby r301 '/wiki/John_Trupiano', '/john' moved_permanently '/wiki/John_Trupiano', '/john' p '/wiki/John_Trupiano', '/john' # shortcut alias r302 '/wiki/John_Trupiano', '/john' found '/wiki/John_Trupiano', '/john' r303 '/wiki/John_Trupiano', '/john' see_other '/wiki/John_Trupiano', '/john' r307 '/wiki/John_Trupiano', '/john' temporary_redirect '/wiki/John_Trupiano', '/john' t '/wiki/John_Trupiano', '/john' # shortcut alias ``` The 303 and 307 codes were added to the HTTP spec to make unambiguously clear what clients should do with the request method. 303 means that the new request should always be made via GET. 307 means that the new request should use the same method as the original request. Status code 302 was left as it is, since it was already in use by the time these issues came to light. In practice it behaves the same as 303. ## Use Cases ### Rebuild of existing site in a new technology It's very common for sites built in older technologies to be rebuilt with the latest and greatest. Let's consider a site that has already established quite a bit of "google juice." When we launch the new site, we don't want to lose that hard-earned reputation. By writing rewrite rules that issue 301's for old URL's, we can "transfer" that google ranking to the new site. An example rule might look like: ```ruby r301 '/contact-us.php', '/contact-us' r301 '/wiki/John_Trupiano', '/john' ``` ### Retiring old routes As a web application evolves you will undoubtedly reach a point where you need to change the name of something (a model, e.g.). This name change will typically require a similar change to your routing. The danger here is that any URL's previously generated (in a transactional email for instance) will have the URL hard-coded. In order for your rails app to continue to serve this URL, you'll need to add an extra entry to your routes file. Alternatively, you could use rack-rewrite to redirect or pass through requests to these routes and keep your routes.rb clean. ```ruby rewrite %r{/features(.*)}, '/facial_features$1' ``` ### CNAME alternative In the event that you do not control your DNS, you can leverage Rack::Rewrite to redirect to a canonical domain. In the following rule we utilize the $& substitution operator to capture the entire request URI. ```ruby r301 %r{.*}, 'http://mynewdomain.com$&', :if => Proc.new {|rack_env| rack_env['SERVER_NAME'] != 'mynewdomain.com' } ``` ### Site Maintenance Most capistrano users will be familiar with the following Apache rewrite rules: ``` RewriteCond %{REQUEST_URI} !\.(css|jpg|png)$ RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f RewriteCond %{SCRIPT_FILENAME} !maintenance.html RewriteRule ^.*$ /system/maintenance.html [L] ``` This rewrite rule says to render a maintenance page for all non-asset requests if the maintenance file exists. In capistrano, you can quickly upload a maintenance file using: `cap deploy:web:disable REASON=upgrade UNTIL=12:30PM` We can replace the mod_rewrite rules with the following Rack::Rewrite rule: ```ruby maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html') send_file /.*/, maintenance_file, :if => Proc.new { |rack_env| File.exists?(maintenance_file) && rack_env['PATH_INFO'] !~ /\.(css|jpg|png)/ } ``` If you're running Ruby 1.9, this rule is simplified: ```ruby maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html') send_file /(.*)$(? Proc.new { |rack_env| File.exists?(maintenance_file) } ``` For those using the oniguruma gem with their ruby 1.8 installation, you can get away with: ```ruby maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html') send_file Oniguruma::ORegexp.new("(.*)$(? Proc.new { |rack_env| File.exists?(maintenance_file) } ``` ## Rewrite Rules ### :rewrite Calls to #rewrite will simply update the PATH_INFO, QUERY_STRING and REQUEST_URI HTTP header values and pass the request onto the next chain in the Rack stack. The URL that a user's browser will show will not be changed. See these examples: ```ruby rewrite '/wiki/John_Trupiano', '/john' # [1] rewrite %r{/wiki/(\w+)_\w+}, '/$1' # [2] ``` For [1], the user's browser will continue to display /wiki/John_Trupiano, but the actual HTTP header values for PATH_INFO and REQUEST_URI in the request will be changed to /john for subsequent nodes in the Rack stack. Rails reads these headers to determine which routes will match. Rule [2] showcases the use of regular expressions and substitutions. [2] is a generalized version of [1] that will match any /wiki/FirstName_LastName URL's and rewrite them as the first name only. This is an actual catch-all rule we applied when we rebuilt our website in September 2009 ( http://www.smartlogicsolutions.com ). ### :r301, :r302, :r303, :r307 Calls to #r301 and #r302 have the same signature as #rewrite. The difference, however, is that these actually short-circuit the rack stack and send back their respective status codes. See these examples: ```ruby r301 '/wiki/John_Trupiano', '/john' # [1] r301 '/wiki/(.*)', 'http://www.google.com/?q=$1' # [2] ``` Recall that rules are interpreted from top to bottom. So you can install "default" rewrite rules if you like. [2] is a sample default rule that will redirect all other requests to the wiki to a google search. ### :send_file, :x_send_file Calls to #send_file and #x_send_file also have the same signature as #rewrite. If the rule matches, the 'to' parameter is interpreted as a path to a file to be rendered instead of passing the application call up the rack stack. ```ruby send_file /*/, 'public/spammers.htm', :if => Proc.new { |rack_env| rack_env['HTTP_REFERER'] =~ 'spammers.com' } x_send_file /^blog\/.*/, 'public/blog_offline.htm', :if => Proc.new { |rack_env| File.exists?('public/blog_offline.htm') } ``` ## Options Parameter Each rewrite rule takes an optional options parameter. The following options are supported. ### :host Using the :host option you can match requests to a specific hostname. ```ruby r301 "/features", "/facial_features", :host => "facerecognizer.com" ``` This rule will only match when the hostname is "facerecognizer.com" ### :headers Using the :headers option you can set custom response headers e.g. for HTTP caching instructions. ```ruby r301 "/features", "/facial_features", :headers => {'Cache-Control' => 'no-cache'} ``` Please be aware that the :headers value above is evaluated only once at app boot and shared amongst all matching requests. Use a Proc as the :headers option if you wish to determine the additional headers at request-time. For example: ```ruby # We want the Expires value to always be 1 year in the future from now. If # we didn't use a Proc here, then the Expires value would be set just once # at app startup. The Proc will be evaluated for each matching request. send_file /^.+\.(?:ico|jpg|jpeg|png|gif|)$/, 'public/$&', :headers => lambda { { 'Expires' => 1.year.from_now.httpdate } } ``` ### :method Using the :method option you can restrict the matching of a rule by the HTTP method of a given request. ```ruby # redirect GET's one way r301 "/players", "/current_players", :method => :get # and redirect POST's another way r302 "/players", "/no_longer_available.html?message=No&longer&supported", :method => :post ``` ### :if Using the :if option you can define arbitrary rule guards. Guards are any object responding to #call that return true or false indicating whether the rule matches. The following example demonstrates how the presence of a maintenance page on the filesystem can be utilized to take your site(s) offline. ```ruby maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html') x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env| File.exists?(maintenance_file) } ``` ### :not Using the :not option you can negatively match against the path. This can be useful when writing a regular expression match is difficult. ```ruby rewrite %r{^\/features}, '/facial_features', :not => '/features' ``` This will not match the relative URL /features but would match /features.xml. ## Tips ### Keeping your querystring When rewriting a URL, you may want to keep your querystring in tact (for example if you're tracking traffic sources). You will need to include a capture group and substitution pattern in your rewrite rule to achieve this. ```ruby rewrite %r{/wiki/John_Trupiano(\?.*)?}, '/john$1' ``` This rule will store the querystring in a capture group (via `(?.*)` ) and will substitute the querystring back into the rewritten URL (via `$1`). ### Arbitrary Rewriting All rules support passing a Proc as the second argument allowing you to perform arbitrary rewrites. The following rule will rewrite all requests received between 12AM and 8AM to an unavailable page. ```ruby rewrite %r{(.*)}, lambda { |match, rack_env| Time.now.hour < 8 ? "/unavailable.html" : match[1] } ``` ## Contribute rack-rewrite is maintained by [@travisjeffery](http://github.com/travisjeffery). Here's the most direct way to get your work merged into the project. - Fork the project - Clone down your fork - Create a feature branch - Hack away and add tests, not necessarily in that order - Make sure everything still passes by running tests - If necessary, rebase your commits into logical chunks without errors - Push the branch up to your fork - Send a pull request for your branch ## Copyright Copyright (c) 2012 — John Trupiano, Travis Jeffery. See LICENSE for details. ruby-rack-rewrite-1.3.3/Rakefile000066400000000000000000000015251212234612500165420ustar00rootroot00000000000000require 'rubygems' require 'rake' require 'rake/testtask' require 'rdoc/task' Rake::TestTask.new(:test) do |test| test.libs << 'lib' << 'test' << '.' test.pattern = 'test/**/*_test.rb' test.verbose = true end begin require 'rcov/rcovtask' Rcov::RcovTask.new do |test| test.libs << 'test' test.pattern = 'test/**/*_test.rb' test.verbose = true end rescue LoadError task :rcov do abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov" end end task :default => :test Rake::RDocTask.new do |rdoc| if File.exist?('VERSION') version = File.read('VERSION') else version = "" end rdoc.rdoc_dir = 'rdoc' rdoc.title = "rack-rewrite #{version}" rdoc.rdoc_files.include('README*') rdoc.rdoc_files.include('History.rdoc') rdoc.rdoc_files.include('lib/**/*.rb') end ruby-rack-rewrite-1.3.3/VERSION000066400000000000000000000000061212234612500161360ustar00rootroot000000000000001.3.3 ruby-rack-rewrite-1.3.3/lib/000077500000000000000000000000001212234612500156405ustar00rootroot00000000000000ruby-rack-rewrite-1.3.3/lib/rack-rewrite.rb000066400000000000000000000000261212234612500205620ustar00rootroot00000000000000require 'rack/rewrite'ruby-rack-rewrite-1.3.3/lib/rack/000077500000000000000000000000001212234612500165605ustar00rootroot00000000000000ruby-rack-rewrite-1.3.3/lib/rack/rewrite.rb000066400000000000000000000015661212234612500205760ustar00rootroot00000000000000module Rack autoload :RuleSet, 'rack/rewrite/rule' autoload :VERSION, 'rack/rewrite/version' # A rack middleware for defining and applying rewrite rules. In many cases you # can get away with rack-rewrite instead of writing Apache mod_rewrite rules. class Rewrite def initialize(app, &rule_block) @app = app @rule_set = RuleSet.new @rule_set.instance_eval(&rule_block) if block_given? end def call(env) if matched_rule = find_first_matching_rule(env) rack_response = matched_rule.apply!(env) # Don't invoke the app if applying the rule returns a rack response return rack_response unless rack_response === true end @app.call(env) end private def find_first_matching_rule(env) #:nodoc: @rule_set.rules.detect { |rule| rule.matches?(env) } end end end ruby-rack-rewrite-1.3.3/lib/rack/rewrite/000077500000000000000000000000001212234612500202415ustar00rootroot00000000000000ruby-rack-rewrite-1.3.3/lib/rack/rewrite/rule.rb000066400000000000000000000207461212234612500215460ustar00rootroot00000000000000require 'rack/mime' module Rack class Rewrite class RuleSet attr_reader :rules def initialize #:nodoc: @rules = [] end protected # We're explicitly defining private functions for our DSL rather than # using method_missing # Creates a rewrite rule that will simply rewrite the REQUEST_URI, # PATH_INFO, and QUERY_STRING headers of the Rack environment. The # user's browser will continue to show the initially requested URL. # # rewrite '/wiki/John_Trupiano', '/john' # rewrite %r{/wiki/(\w+)_\w+}, '/$1' # rewrite %r{(.*)}, '/maintenance.html', :if => lambda { File.exists?('maintenance.html') } def rewrite(*args) add_rule :rewrite, *args end # Creates a redirect rule that will send a 301 when matching. # # r301 '/wiki/John_Trupiano', '/john' # r301 '/contact-us.php', '/contact-us' # # You can use +moved_permanently+ or just +p+ instead of +r301+. def r301(*args) add_rule :r301, *args end alias :moved_permanently :r301 alias :p :r301 # Creates a redirect rule that will send a 302 when matching. # # r302 '/wiki/John_Trupiano', '/john' # r302 '/wiki/(.*)', 'http://www.google.com/?q=$1' # # You can use +found+ instead of +r302+. def r302(*args) add_rule :r302, *args end alias :found :r302 # Creates a redirect rule that will send a 303 when matching. # # r303 '/wiki/John_Trupiano', '/john' # r303 '/wiki/(.*)', 'http://www.google.com/?q=$1' # # You can use +see_other+ instead of +r303+. def r303(*args) add_rule :r303, *args end alias :see_other :r303 # Creates a redirect rule that will send a 307 when matching. # # r307 '/wiki/John_Trupiano', '/john' # r307 '/wiki/(.*)', 'http://www.google.com/?q=$1' # # You can use +temporary_redirect+ or +t+ instead of +r307+. def r307(*args) add_rule :r307, *args end alias :temporary_redirect :r307 alias :t :r307 # Creates a rule that will render a file if matched. # # send_file /*/, 'public/system/maintenance.html', # :if => Proc.new { File.exists?('public/system/maintenance.html') } def send_file(*args) add_rule :send_file, *args end # Creates a rule that will render a file using x-send-file # if matched. # # x_send_file /*/, 'public/system/maintenance.html', # :if => Proc.new { File.exists?('public/system/maintenance.html') } def x_send_file(*args) add_rule :x_send_file, *args end private def add_rule(method, from, to, options = {}) #:nodoc: @rules << Rule.new(method.to_sym, from, to, options) end end # TODO: Break rules into subclasses class Rule #:nodoc: attr_reader :rule_type, :from, :to, :options def initialize(rule_type, from, to, options={}) #:nodoc: @rule_type, @from, @to, @options = rule_type, from, to, normalize_options(options) end def matches?(rack_env) #:nodoc: return false if options[:if].respond_to?(:call) && !options[:if].call(rack_env) path = build_path_from_env(rack_env) self.match_options?(rack_env) && string_matches?(path, self.from) end # Either (a) return a Rack response (short-circuiting the Rack stack), or # (b) alter env as necessary and return true def apply!(env) #:nodoc: interpreted_to = self.interpret_to(env) additional_headers = {} if @options[:headers] if @options[:headers].respond_to?(:call) additional_headers = @options[:headers].call || {} else additional_headers = @options[:headers] || {} end end status = @options[:status] || 200 case self.rule_type when :r301 [301, {'Location' => interpreted_to, 'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to))}.merge!(additional_headers), [redirect_message(interpreted_to)]] when :r302 [302, {'Location' => interpreted_to, 'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to))}.merge!(additional_headers), [redirect_message(interpreted_to)]] when :r303 [303, {'Location' => interpreted_to, 'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to))}.merge!(additional_headers), [redirect_message(interpreted_to)]] when :r307 [307, {'Location' => interpreted_to, 'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to))}.merge!(additional_headers), [redirect_message(interpreted_to)]] when :rewrite # return [200, {}, {:content => env.inspect}] env['REQUEST_URI'] = interpreted_to if q_index = interpreted_to.index('?') env['PATH_INFO'] = interpreted_to[0..q_index-1] env['QUERY_STRING'] = interpreted_to[q_index+1..interpreted_to.size-1] else env['PATH_INFO'] = interpreted_to env['QUERY_STRING'] = '' end true when :send_file [status, { 'Content-Length' => ::File.size(interpreted_to).to_s, 'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to)) }.merge!(additional_headers), [::File.read(interpreted_to)]] when :x_send_file [status, { 'X-Sendfile' => interpreted_to, 'Content-Length' => ::File.size(interpreted_to).to_s, 'Content-Type' => Rack::Mime.mime_type(::File.extname(interpreted_to)) }.merge!(additional_headers), []] else raise Exception.new("Unsupported rule: #{self.rule_type}") end end protected def interpret_to(env) #:nodoc: path = build_path_from_env(env) return interpret_to_proc(path, env) if self.to.is_a?(Proc) return computed_to(path) if compute_to?(path) self.to end def is_a_regexp?(obj) obj.is_a?(Regexp) || (Object.const_defined?(:Oniguruma) && obj.is_a?(Oniguruma::ORegexp)) end def match_options?(env, path = build_path_from_env(env)) matches = [] request = Rack::Request.new(env) # negative matches matches << !string_matches?(path, options[:not]) if options[:not] # possitive matches matches << string_matches?(env['REQUEST_METHOD'], options[:method]) if options[:method] matches << string_matches?(request.host, options[:host]) if options[:host] matches << string_matches?(request.scheme, options[:scheme]) if options[:scheme] matches.all? end private def normalize_options(arg) options = arg.respond_to?(:call) ? {:if => arg} : arg options.symbolize_keys! if options.respond_to? :symbolize_keys! options.freeze end def interpret_to_proc(path, env) return self.to.call(match(path), env) if self.from.is_a?(Regexp) self.to.call(self.from, env) end def compute_to?(path) self.is_a_regexp?(from) && match(path) end def match(path) self.from.match(path) end def string_matches?(string, matcher) if self.is_a_regexp?(matcher) string =~ matcher elsif matcher.is_a?(String) string == matcher elsif matcher.is_a?(Symbol) string.downcase == matcher.to_s.downcase else false end end def computed_to(path) # is there a better way to do this? computed_to = self.to.dup computed_to.gsub!("$&",match(path).to_s) (match(path).size - 1).downto(1) do |num| computed_to.gsub!("$#{num}", match(path)[num].to_s) end return computed_to end # Construct the URL (without domain) from PATH_INFO and QUERY_STRING def build_path_from_env(env) path = env['PATH_INFO'] || '' path += "?#{env['QUERY_STRING']}" unless env['QUERY_STRING'].nil? || env['QUERY_STRING'].empty? path end def redirect_message(location) %Q(Redirecting to #{location}) end end end end ruby-rack-rewrite-1.3.3/lib/rack/rewrite/version.rb000066400000000000000000000002061212234612500222510ustar00rootroot00000000000000module Rack class Rewrite VERSION = File.read File.join(File.expand_path("..", __FILE__), "..", "..", "..", "VERSION") end endruby-rack-rewrite-1.3.3/metadata.yml000066400000000000000000000060511212234612500173770ustar00rootroot00000000000000--- !ruby/object:Gem::Specification name: rack-rewrite version: !ruby/object:Gem::Version version: 1.3.3 prerelease: platform: ruby authors: - Travis Jeffery - John Trupiano autorequire: bindir: bin cert_chain: [] date: 2013-01-06 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: bundler requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: shoulda requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 2.10.2 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 2.10.2 - !ruby/object:Gem::Dependency name: mocha requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 0.9.7 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 0.9.7 - !ruby/object:Gem::Dependency name: rack requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' description: A rack middleware for enforcing rewrite rules. In many cases you can get away with rack-rewrite instead of writing Apache mod_rewrite rules. email: travisjeffery@gmail.com executables: [] extensions: [] extra_rdoc_files: - LICENSE - History.rdoc files: - History.rdoc - LICENSE - README.markdown - Rakefile - VERSION - Gemfile - lib/rack-rewrite.rb - lib/rack/rewrite.rb - lib/rack/rewrite/rule.rb - lib/rack/rewrite/version.rb - rack-rewrite.gemspec - test/geminstaller.yml - test/rack-rewrite_test.rb - test/rule_test.rb - test/test_helper.rb homepage: http://github.com/jtrupiano/rack-rewrite licenses: [] post_install_message: rdoc_options: - --charset=UTF-8 require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: johntrupiano rubygems_version: 1.8.23 signing_key: specification_version: 3 summary: A rack middleware for enforcing rewrite rules test_files: - test/rack-rewrite_test.rb - test/geminstaller.yml - test/rule_test.rb - test/test_helper.rb ruby-rack-rewrite-1.3.3/rack-rewrite.gemspec000066400000000000000000000031501212234612500210350ustar00rootroot00000000000000Gem::Specification.new do |s| s.name = 'rack-rewrite' s.version = File.read('VERSION') s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Travis Jeffery", "John Trupiano"] s.date = Date.today.to_s 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.} s.email = %q{travisjeffery@gmail.com} s.extra_rdoc_files = [ "LICENSE", "History.rdoc", ] s.files = [ "History.rdoc", "LICENSE", "README.markdown", "Rakefile", "VERSION", "Gemfile", "lib/rack-rewrite.rb", "lib/rack/rewrite.rb", "lib/rack/rewrite/rule.rb", "lib/rack/rewrite/version.rb", "rack-rewrite.gemspec", "test/geminstaller.yml", "test/rack-rewrite_test.rb", "test/rule_test.rb", "test/test_helper.rb" ] s.homepage = %q{http://github.com/jtrupiano/rack-rewrite} s.rdoc_options = ["--charset=UTF-8"] s.require_paths = ["lib"] s.rubyforge_project = %q{johntrupiano} s.rubygems_version = %q{1.3.7} s.summary = %q{A rack middleware for enforcing rewrite rules} s.test_files = [ "test/rack-rewrite_test.rb", "test/geminstaller.yml", "test/rack-rewrite_test.rb", "test/rule_test.rb", "test/test_helper.rb" ] s.add_development_dependency 'bundler' s.add_development_dependency 'shoulda', '~> 2.10.2' s.add_development_dependency 'mocha', '~> 0.9.7' s.add_development_dependency 'rack' if s.respond_to? :specification_version then s.specification_version = 3 end end ruby-rack-rewrite-1.3.3/test/000077500000000000000000000000001212234612500160515ustar00rootroot00000000000000ruby-rack-rewrite-1.3.3/test/geminstaller.yml000066400000000000000000000002341212234612500212610ustar00rootroot00000000000000gems: - name: shoulda version: '= 2.10.3' - name: mocha version: '= 0.9.8' - name: rack version: '= 1.1.0' # - name: oniguruma # version: '= 1.1.0' ruby-rack-rewrite-1.3.3/test/rack-rewrite_test.rb000066400000000000000000000072411212234612500220400ustar00rootroot00000000000000require 'test_helper' class RackRewriteTest < Test::Unit::TestCase def call_args(overrides={}) {'REQUEST_URI' => '/wiki/Yair_Flicker', 'PATH_INFO' => '/wiki/Yair_Flicker', 'QUERY_STRING' => ''}.merge(overrides) end def call_args_no_req(overrides={}) {'PATH_INFO' => '/wiki/Yair_Flicker', 'QUERY_STRING' => ''}.merge(overrides) end def self.should_not_halt should "not halt the rack chain" do @app.expects(:call).once @rack.call(call_args) end end def self.should_be_a_rack_response should 'be a rack a response' do ret = @rack.call(call_args) assert ret.is_a?(Array), 'return value is not a valid rack response' assert_equal 3, ret.size, 'should have 3 arguments' end end def self.should_halt should "should halt the rack chain" do @app.expects(:call).never @rack.call(call_args) end should_be_a_rack_response end def self.should_location_redirect_to(location, code) should "respond with http status code #{code}" do ret = @rack.call(call_args) assert_equal code, ret[0] end should 'send a location header' do ret = @rack.call(call_args) assert_equal location, ret[1]['Location'], 'Location is incorrect' end end context 'Given an app' do setup do @app = Class.new { def call(app); true; end }.new end context 'when no rewrite rule matches' do setup { @rack = Rack::Rewrite.new(@app) } should_not_halt end [301, 302, 303, 307].each do |status| context "when a #{status} rule matches" do setup { @rack = Rack::Rewrite.new(@app) do send("r#{status}", '/wiki/Yair_Flicker', '/yair') end } should_halt should_location_redirect_to('/yair', status) end end [[:p, 301], [:moved_permanently, 301], [:found, 302], [:see_other, 303], [:t, 307], [:temporary_redirect, 307]].each do |rule| context "when a #{rule.first} rule matches" do setup { @rack = Rack::Rewrite.new(@app) do send(rule.first, '/wiki/Yair_Flicker', '/yair') end } should_halt should_location_redirect_to('/yair', rule.last) end end context 'when a rewrite rule matches' do setup { @rack = Rack::Rewrite.new(@app) do rewrite '/wiki/Yair_Flicker', '/john' end } should_not_halt context 'the env' do setup do @initial_args = call_args.dup @rack.call(@initial_args) end should "set PATH_INFO to '/john'" do assert_equal '/john', @initial_args['PATH_INFO'] end should "set REQUEST_URI to '/john'" do assert_equal '/john', @initial_args['REQUEST_URI'] end should "set QUERY_STRING to ''" do assert_equal '', @initial_args['QUERY_STRING'] end end end context 'when a rewrite rule matches but there is no REQUEST_URI set' do setup { @rack = Rack::Rewrite.new(@app) do rewrite '/wiki/Yair_Flicker', '/john' end } should_not_halt context 'the env' do setup do @initial_args = call_args_no_req.dup @rack.call(@initial_args) end should "set PATH_INFO to '/john'" do assert_equal '/john', @initial_args['PATH_INFO'] end should "set REQUEST_URI to '/john'" do assert_equal '/john', @initial_args['REQUEST_URI'] end should "set QUERY_STRING to ''" do assert_equal '', @initial_args['QUERY_STRING'] end end end end end ruby-rack-rewrite-1.3.3/test/rule_test.rb000066400000000000000000000410611212234612500204060ustar00rootroot00000000000000require 'test_helper' class RuleTest < Test::Unit::TestCase TEST_ROOT = File.dirname(__FILE__) def self.should_pass_maintenance_tests context 'and the maintenance file does in fact exist' do setup { File.stubs(:exists?).returns(true) } should('match for the root') { assert @rule.matches?(rack_env_for('/')) } should('match for a regular rails route') { assert @rule.matches?(rack_env_for('/users/1')) } should('match for an html page') { assert @rule.matches?(rack_env_for('/index.html')) } should('not match for a css file') { assert !@rule.matches?(rack_env_for('/stylesheets/style.css')) } should('not match for a jpg file') { assert !@rule.matches?(rack_env_for('/images/sls.jpg')) } should('not match for a png file') { assert !@rule.matches?(rack_env_for('/images/sls.png')) } end end def self.negative_lookahead_supported? begin require 'oniguruma' rescue LoadError; end RUBY_VERSION =~ /^1\.9/ || Object.const_defined?(:Oniguruma) end def negative_lookahead_regexp if RUBY_VERSION =~ /^1\.9/ # have to use the constructor instead of the literal syntax b/c load errors occur in Ruby 1.8 Regexp.new("(.*)$(? '/abc'} assert_equal rule.send(:interpret_to, '/abc'), rule.apply!(env)[1]['Location'] end end supported_status_codes.each do |rule_type| should "include a link to the result of #interpret_to for a #{rule_type}" do rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def') env = {'PATH_INFO' => '/abc'} assert_match /\/def/, rule.apply!(env)[2][0] end end should 'keep the QUERY_STRING when a 301 rule matches a URL with a querystring' do rule = Rack::Rewrite::Rule.new(:r301, %r{/john(.*)}, '/yair$1') env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'} assert_equal '/yair?show_bio=1', rule.apply!(env)[1]['Location'] end should 'keep the QUERY_STRING when a rewrite rule that requires a querystring matches a URL with a querystring' do rule = Rack::Rewrite::Rule.new(:rewrite, %r{/john(\?.*)}, '/yair$1') env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'} rule.apply!(env) assert_equal '/yair', env['PATH_INFO'] assert_equal 'show_bio=1', env['QUERY_STRING'] assert_equal '/yair?show_bio=1', env['REQUEST_URI'] end should 'update the QUERY_STRING when a rewrite rule changes its value' do rule = Rack::Rewrite::Rule.new(:rewrite, %r{/(\w+)\?show_bio=(\d)}, '/$1?bio=$2') env = {'PATH_INFO' => '/john', 'QUERY_STRING' => 'show_bio=1'} rule.apply!(env) assert_equal '/john', env['PATH_INFO'] assert_equal 'bio=1', env['QUERY_STRING'] assert_equal '/john?bio=1', env['REQUEST_URI'] end should 'set Content-Type header to text/html for a 301 and 302 request for a .html page' do supported_status_codes.each do |rule_type| rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def.html') env = {'PATH_INFO' => '/abc'} assert_equal 'text/html', rule.apply!(env)[1]['Content-Type'] end end should 'set Content-Type header to text/css for a 301 and 302 request for a .css page' do supported_status_codes.each do |rule_type| rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def.css') env = {'PATH_INFO' => '/abc'} assert_equal 'text/css', rule.apply!(env)[1]['Content-Type'] end end should 'set additional headers for a 301 and 302 request' do [:r301, :r302].each do |rule_type| rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def.css', {:headers => {'Cache-Control' => 'no-cache'}}) env = {'PATH_INFO' => '/abc'} assert_equal 'no-cache', rule.apply!(env)[1]['Cache-Control'] end end should 'evaluate additional headers block once per redirect request' do [:r301, :r302].each do |rule_type| header_val = 'foo' rule = Rack::Rewrite::Rule.new(rule_type, %r{/abc}, '/def.css', {:headers => lambda { {'X-Foobar' => header_val} } }) env = {'PATH_INFO' => '/abc'} assert_equal 'foo', rule.apply!(env)[1]['X-Foobar'] header_val = 'bar' assert_equal 'bar', rule.apply!(env)[1]['X-Foobar'] end end should 'evaluate additional headers block once per send file request' do [:send_file, :x_send_file].each do |rule_type| header_val = 'foo' rule = Rack::Rewrite::Rule.new(rule_type, /.*/, File.join(TEST_ROOT, 'geminstaller.yml'), {:headers => lambda { {'X-Foobar' => header_val} } }) env = {'PATH_INFO' => '/abc'} assert_equal 'foo', rule.apply!(env)[1]['X-Foobar'] header_val = 'bar' assert_equal 'bar', rule.apply!(env)[1]['X-Foobar'] end end context 'Given an :x_send_file rule that matches' do setup do @file = File.join(TEST_ROOT, 'geminstaller.yml') @rule = Rack::Rewrite::Rule.new(:x_send_file, /.*/, @file, :headers => {'Cache-Control' => 'no-cache'}) env = {'PATH_INFO' => '/abc'} @response = @rule.apply!(env) end should 'return 200' do assert_equal 200, @response[0] end should 'return an X-Sendfile header' do assert @response[1].has_key?('X-Sendfile') end should 'return a Content-Type of text/yaml' do assert_equal 'text/yaml', @response[1]['Content-Type'] end should 'return the proper Content-Length' do assert_equal File.size(@file).to_s, @response[1]['Content-Length'] end should 'return additional headers' do assert_equal 'no-cache', @response[1]['Cache-Control'] end should 'return empty content' do assert_equal [], @response[2] end end context 'Given a :send_file rule that matches' do setup do @file = File.join(TEST_ROOT, 'geminstaller.yml') @rule = Rack::Rewrite::Rule.new(:send_file, /.*/, @file, :headers => {'Cache-Control' => 'no-cache'}) env = {'PATH_INFO' => '/abc'} @response = @rule.apply!(env) end should 'return 200' do assert_equal 200, @response[0] end should 'not return an X-Sendfile header' do assert !@response[1].has_key?('X-Sendfile') end should 'return a Content-Type of text/yaml' do assert_equal 'text/yaml', @response[1]['Content-Type'] end should 'return the proper Content-Length' do assert_equal File.size(@file).to_s, @response[1]['Content-Length'] end should 'return additional headers' do assert_equal 'no-cache', @response[1]['Cache-Control'] end should 'return the contents of geminstaller.yml in an array for Ruby 1.9.2 compatibility' do assert_equal [File.read(@file)], @response[2] end end should 'return proper status for send_file or x_send_file if specified' do [:send_file, :x_send_file].each do |rule_type| file = File.join(TEST_ROOT, 'geminstaller.yml') rule = Rack::Rewrite::Rule.new(rule_type, /.*/, file, :status => 503) env = {'PATH_INFO' => '/abc'} assert_equal 503, rule.apply!(env)[0] end end end context 'Rule#matches' do context 'Given rule with :not option which matches "from" string' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, /^\/features/, '/facial_features', :not => '/features') end should 'not match PATH_INFO of /features' do assert !@rule.matches?(rack_env_for("/features")) end should 'match PATH_INFO of /features.xml' do assert @rule.matches?(rack_env_for("/features.xml")) end end context 'Given rule with :host option of testapp.com' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, /^\/features/, '/facial_features', :host => 'testapp.com') end should 'match PATH_INFO of /features and HOST of testapp.com' do assert @rule.matches?(rack_env_for("/features", 'SERVER_NAME' => 'testapp.com', "SERVER_PORT" => "8080")) end should 'not match PATH_INFO of /features and HOST of nottestapp.com' do assert ! @rule.matches?(rack_env_for("/features", 'SERVER_NAME' => 'nottestapp.com', "SERVER_PORT" => "8080")) end should 'match PATH_INFO of /features AND HTTP_X_FORWARDED_HOST of testapp.com and SERVER_NAME of 127.0.0.1' do assert @rule.matches?(rack_env_for("/features", "SERVER_NAME" => "127.0.0.1", "SERVER_PORT" => "8080", "HTTP_X_FORWARDED_HOST" => "testapp.com")) end should 'not match PATH_INFO of /features AND HTTP_X_FORWARDED_HOST of nottestapp.com and SERVER_NAME of 127.0.0.1' do assert !@rule.matches?(rack_env_for("/features", "SERVER_NAME" => "127.0.0.1", "SERVER_PORT" => "8080", "HTTP_X_FORWARDED_HOST" => "nottestapp.com")) end end context 'Given rule with :method option of POST' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, '/features', '/facial_features', :method => 'POST') end should 'match PATH_INFO of /features and REQUEST_METHOD of POST' do assert @rule.matches?(rack_env_for("/features", 'REQUEST_METHOD' => 'POST')) end should 'not match PATH_INFO of /features and REQUEST_METHOD of DELETE' do assert ! @rule.matches?(rack_env_for("/features", 'REQUEST_METHOD' => 'DELETE')) end end context 'Given any rule with a "from" string of /features' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, '/features', '/facial_features') end should 'match PATH_INFO of /features' do assert @rule.matches?(rack_env_for("/features")) end should 'not match PATH_INFO of /features.xml' do assert !@rule.matches?(rack_env_for("/features.xml")) end should 'not match PATH_INFO of /my_features' do assert !@rule.matches?(rack_env_for("/my_features")) end end context 'Given a rule with the ^ operator' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, %r{^/jason}, '/steve') end should 'match with the ^ operator if match is at the beginning of the path' do assert @rule.matches?(rack_env_for('/jason')) end should 'not match with the ^ operator when match is deeply nested' do assert !@rule.matches?(rack_env_for('/foo/bar/jason')) end end context 'Given any rule with a "from" regular expression of /features(.*)' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, %r{/features(.*)}, '/facial_features$1') end should 'match PATH_INFO of /features' do assert @rule.matches?(rack_env_for("/features")) end should 'match PATH_INFO of /features.xml' do assert @rule.matches?(rack_env_for('/features.xml')) end should 'match PATH_INFO of /features/1' do assert @rule.matches?(rack_env_for('/features/1')) end should 'match PATH_INFO of /features?filter_by=name' do assert @rule.matches?(rack_env_for('/features?filter_by_name=name')) end should 'match PATH_INFO of /features/1?hide_bio=1' do assert @rule.matches?(rack_env_for('/features/1?hide_bio=1')) end end context 'Given a rule with a guard that checks for the presence of a file' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, %r{(.)*}, '/maintenance.html', lambda { |rack_env| File.exists?('maintenance.html') }) end context 'when the file exists' do setup do File.stubs(:exists?).returns(true) end should 'match' do assert @rule.matches?(rack_env_for('/anything/should/match')) end end context 'when the file does not exist' do setup do File.stubs(:exists?).returns(false) end should 'not match' do assert !@rule.matches?(rack_env_for('/nothing/should/match')) end end end context 'Given the capistrano maintenance.html rewrite rule given in our README' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, /.*/, '/system/maintenance.html', lambda { |rack_env| maintenance_file = File.join('system', 'maintenance.html') File.exists?(maintenance_file) && rack_env['PATH_INFO'] !~ /\.(css|jpg|png)/ }) end should_pass_maintenance_tests end if negative_lookahead_supported? context 'Given the negative lookahead regular expression version of the capistrano maintenance.html rewrite rule given in our README' do setup do @rule = Rack::Rewrite::Rule.new(:rewrite, negative_lookahead_regexp, '/system/maintenance.html', lambda { |rack_env| File.exists?(File.join('public', 'system', 'maintenance.html')) }) end should_pass_maintenance_tests end end context 'Given the CNAME alternative rewrite rule in our README' do setup do @rule = Rack::Rewrite::Rule.new(:r301, %r{.*}, 'http://mynewdomain.com$&', lambda {|rack_env| rack_env['SERVER_NAME'] != 'mynewdomain.com' }) end should 'match requests for domain myolddomain.com and redirect to mynewdomain.com' do env = {'PATH_INFO' => '/anything', 'QUERY_STRING' => 'abc=1', 'SERVER_NAME' => 'myolddomain.com'} assert @rule.matches?(env) rack_response = @rule.apply!(env) assert_equal 'http://mynewdomain.com/anything?abc=1', rack_response[1]['Location'] end should 'not match requests for domain mynewdomain.com' do assert !@rule.matches?({'PATH_INFO' => '/anything', 'SERVER_NAME' => 'mynewdomain.com'}) end end end context 'Rule#interpret_to' do should 'return #to when #from is a string' do rule = Rack::Rewrite::Rule.new(:rewrite, '/abc', '/def') assert_equal '/def', rule.send(:interpret_to, rack_env_for('/abc')) end should 'replace $1 on a match' do rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)}, '/people/$1') assert_equal '/people/1', rule.send(:interpret_to, rack_env_for("/person_1")) end should 'be able to catch querystrings with a regexp match' do rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)(.*)}, '/people/$1$2') assert_equal '/people/1?show_bio=1', rule.send(:interpret_to, rack_env_for('/person_1?show_bio=1')) end should 'be able to make 10 replacements' do # regexp to reverse 10 characters 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') assert_equal 'jihgfedcba', rule.send(:interpret_to, rack_env_for("abcdefghij")) end should 'replace $& on a match' do rule = Rack::Rewrite::Rule.new(:rewrite, %r{.*}, 'http://example.org$&') assert_equal 'http://example.org/person/1', rule.send(:interpret_to, rack_env_for("/person/1")) end should 'ignore empty captures' do rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person(_\d+)?}, '/people/$1') assert_equal '/people/', rule.send(:interpret_to, rack_env_for("/person")) end should 'call to with from when it is a lambda' do rule = Rack::Rewrite::Rule.new(:rewrite, 'a', lambda { |from, env| from * 2 }) assert_equal 'aa', rule.send(:interpret_to, rack_env_for('a')) end should 'call to with from match data' do rule = Rack::Rewrite::Rule.new(:rewrite, %r{/person_(\d+)(.*)}, lambda {|match, env| "people-#{match[1].to_i * 3}#{match[2]}"}) assert_equal 'people-3?show_bio=1', rule.send(:interpret_to, rack_env_for('/person_1?show_bio=1')) end end context 'Mongel 1.2.0.pre2 edge case: root url with a query string' do should 'handle a nil PATH_INFO variable without errors' do rule = Rack::Rewrite::Rule.new(:r301, '/a', '/') assert_equal '?exists', rule.send(:build_path_from_env, {'QUERY_STRING' => 'exists'}) end end def rack_env_for(url, options = {}) components = url.split('?') {'PATH_INFO' => components[0], 'QUERY_STRING' => components[1] || ''}.merge(options) end end ruby-rack-rewrite-1.3.3/test/test_helper.rb000066400000000000000000000003061212234612500207130ustar00rootroot00000000000000require 'rubygems' require 'bundler/setup' Bundler.require :default, :development require 'test/unit' class Test::Unit::TestCase end def supported_status_codes [:r301, :r302, :r303, :r307] end