New Upstream Snapshot - ruby-versionist

Ready changes

Summary

Merged new upstream version: 2.0.1+git20210211.1.80b09ce (was: 2.0.1).

Resulting package

Built on 2023-01-11T04:27 (took 2m44s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots ruby-versionist

Lintian Result

Diff

diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..7438fbe
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,2 @@
+--colour
+--format documentation
diff --git a/.rvmrc b/.rvmrc
new file mode 100644
index 0000000..8dfc6c5
--- /dev/null
+++ b/.rvmrc
@@ -0,0 +1 @@
+rvm use ruby-2.2.2@versionist --create
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..1cfe518
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,42 @@
+language: ruby
+rvm:
+  - 1.9.3
+  - 2.0.0
+  - 2.2.2
+  - 2.3.4
+  - 2.4.1
+  - jruby-18mode
+  - jruby-19mode
+  - jruby-head
+before_install: # https://github.com/travis-ci/travis-ci/issues/5861
+  - gem install bundler
+  - gem update bundler
+jdk:
+  - oraclejdk7
+matrix:
+  exclude:
+    - gemfile: gemfiles/Rails-5.0
+      rvm: 1.9.3
+    - gemfile: gemfiles/Rails-5.0
+      rvm: 2.0.0
+    - gemfile: gemfiles/Rails-5.0
+      rvm: jruby-18mode
+    - gemfile: gemfiles/Rails-5.0
+      rvm: jruby-19mode
+    - gemfile: gemfiles/Rails-5.1
+      rvm: 1.9.3
+    - gemfile: gemfiles/Rails-5.1
+      rvm: 2.0.0
+    - gemfile: gemfiles/Rails-5.1
+      rvm: jruby-18mode
+    - gemfile: gemfiles/Rails-5.1
+      rvm: jruby-19mode
+
+gemfile:
+  - gemfiles/Rails-3.0
+  - gemfiles/Rails-3.1
+  - gemfiles/Rails-3.2
+  - gemfiles/Rails-4.0
+  - gemfiles/Rails-5.0
+  - gemfiles/Rails-5.1
+  - gemfiles/RailsAPI-0.0
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ac3b0b6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012 Brian Ploetz (bploetz@gmail.com)
+
+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.
diff --git a/README.markdown b/README.markdown
new file mode 100644
index 0000000..3b9e93a
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,363 @@
+# versionist
+
+[![Build Status](https://travis-ci.org/bploetz/versionist.svg?branch=master)](https://travis-ci.org/bploetz/versionist)
+
+A plugin for versioning Rails based RESTful APIs. Versionist supports three versioning strategies out of the box:
+
+- Specifying version via an HTTP header
+- Specifying version by prepending paths with a version slug
+- Specifying version via a request parameter
+
+A version of your API consists of:
+
+- Namespaced controllers/routes
+- Namespaced presenters
+- Namespaced tests
+- Documentation
+
+Versionist includes Rails generators for generating new versions of your API as well as new components within an existing version.
+
+
+## Installation
+
+Add the following dependency to your Rails application's `Gemfile` file and run `bundle install`:
+
+    gem 'versionist'
+
+
+## Configuration
+
+Versionist provides the method `api_version` that you use in your Rails application's `config/routes.rb` file to constrain a collection of routes to a specific version of your API.
+The versioning strategies used by the collection of routes constrained by `api_version` is set by specifying `:header`, `:path`, and/or `:parameter` (and their supporting values)
+in the configuration Hash passed to `api_version`. You configure the module namespace for your API version by specifying `:module` in the configuration Hash passed to `api_version`.
+
+### Upgrading from Versionist 0.x to 1.x+
+
+A backwards incompatible change was made to the format of the configuration hash passed to `api_version` starting in Versionist 1.0.
+Prior to 1.0, `api_version` expected hashes with the following structure:
+
+```ruby
+api_version(:module => "V1", :header => "Accept", :value => "application/vnd.mycompany.com; version=1") do
+  ...
+end
+```
+
+In order to support multiple concurrent versioning strategies per api version, `api_version` expects that the `:header`, `:parameter`, and `:path`
+keys point to hashes and contain the required keys.
+
+```ruby
+api_version(:module => "V1", :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}) do
+  ...
+end
+
+api_version(:module => "V1", :parameter => {:name => "version", :value => "1"}) do
+  ...
+end
+
+api_version(:module => "V1", :path => {:value => "v1"}) do
+  ...
+end
+```
+
+An error will be thrown at startup if your `config/routes.rb` file contains 0.x style `api_version` entries when running with Versionist 1.x+.
+
+## Versioning Strategies
+
+### HTTP Header
+
+This strategy uses an HTTP header to request a specific version of your API.
+
+    Accept: application/vnd.mycompany.com; version=1,application/json
+    GET /foos
+
+You configure the header to be inspected and the header value specifying the version in the configuration Hash passed to `api_version`.
+
+Examples:
+
+##### Content negotiation via the `Accept` header:
+
+```ruby
+MyApi::Application.routes.draw do
+  api_version(:module => "V1", :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}) do
+    match '/foos.(:format)' => 'foos#index', :via => :get
+    match '/foos_no_format' => 'foos#index', :via => :get
+    resources :bars
+  end
+end
+```
+
+`Accept` Header Gotcha
+
+Please note: when your routes do not include an explicit format in the URL (i.e. `match 'foos.(:format)' => foos#index`), Rails inspects the `Accept` header to determine the requested format. Since
+an `Accept` header can have multiple values, Rails uses the *first* one present to determine the format. If your custom version header happens to be the first value in the `Accept` header, Rails would 
+incorrectly try to interpret it as the format. If you use the `Accept` header, Versionist will move your custom version header (if found) to the end of the `Accept` header so as to not interfere with
+Rails' format resolution logic. This is the only case where Versionist will alter the incoming request.
+
+
+##### Custom header:
+
+```ruby
+MyApi::Application.routes.draw do
+  api_version(:module => "V20120317", :header => {:name => "Api-Version", :value => "v20120317"}) do
+    match '/foos.(:format)' => 'foos#index', :via => :get
+    match '/foos_no_format' => 'foos#index', :via => :get
+    resources :bars
+  end
+end
+```
+
+### Path
+
+This strategy uses a URL path prefix to request a specific version of your API.
+
+    GET /v3/foos
+
+You configure the path version prefix to be applied to the routes.
+
+Example:
+
+```ruby
+MyApi::Application.routes.draw do
+  api_version(:module => "V3", :path => {:value => "v3"}) do
+    match '/foos.(:format)' => 'foos#index', :via => :get
+    match '/foos_no_format' => 'foos#index', :via => :get
+    resources :bars
+  end
+end
+```
+
+### Request Parameter
+
+This strategy uses a request parameter to request a specific version of your API.
+
+    GET /foos?version=v2
+
+You configure the parameter name and value to be applied to the routes.
+
+Example:
+
+```ruby
+MyApi::Application.routes.draw do
+  api_version(:module => "V2", :parameter => {:name => "version", :value => "v2"}) do
+    match '/foos.(:format)' => 'foos#index', :via => :get
+    match '/foos_no_format' => 'foos#index', :via => :get
+    resources :bars
+  end
+end
+```
+
+### Default Version
+
+If a request is made to your API without specifying a specific version, by default a RoutingError (i.e. 404) will occur. You can optionally configure Versionist to
+return a specific version by default when none is specified. To specify that a version should be used as the default, include `:default => true` in the config hash
+passed to the `api_version` method.
+
+Example.
+
+```ruby
+MyApi::Application.routes.draw do
+  api_version(:module => "V20120317", :header => {:name => "Api-Version", :value => "v20120317"}, :default => true) do
+    match '/foos.(:format)' => 'foos#index', :via => :get
+    match '/foos_no_format' => 'foos#index', :via => :get
+    resources :bars
+  end
+end
+```
+
+If you attempt to specify more than one default version, an error will be thrown at startup.
+
+Note that when you configure a default API version, you will see the routes under your default version show up twice when running `rake routes`. This is due to the fact that Versionist adds another `scope` to your routes to handle the default case. Unfortunately `rake routes` does not show you enough contextual information to be able to differentiate the two, but this is the expected behavior.
+
+
+### Rails Route :defaults Hash
+
+The `api_version` method also supports Rails' [`:defaults`](http://guides.rubyonrails.org/routing.html#defining-defaults) hash (note that this is different than
+the `:default` key which controls the default API version described above). If a `:defaults` hash is passed to `api_version`, it will be applied to the collection
+of routes constrainted by `api_version`.
+
+Example.
+
+```ruby
+MyApi::Application.routes.draw do
+  api_version(:module => "V20120317", :header => {:name => "Api-Version", :value => "v20120317"}, :defaults => {:format => :json}, :default => true) do
+    match '/foos.(:format)' => 'foos#index', :via => :get
+    match '/foos_no_format' => 'foos#index', :via => :get
+    resources :bars
+  end
+end
+```
+
+## Multiple Versioning Strategies Per API Version
+
+An API version may optionally support multiple concurrent versioning strategies.
+
+Example.
+```ruby
+MyApi::Application.routes.draw do
+  api_version(:module => "V1", :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}, :path => {:value => "v1"}) do
+    match '/foos.(:format)' => 'foos#index', :via => :get
+    match '/foos_no_format' => 'foos#index', :via => :get
+    resources :bars
+  end
+end
+```
+
+## A Note About Testing
+
+Rails functional tests (ActionController::TestCase) and RSpec Controller specs are for testing controller action methods in isolation.
+They do not go through the full Rails stack, specifically the Rails dispatcher code path, which is where versionist hooks in to do its thing.
+
+In order to test your versioned API routes, use integration tests (ActionDispatch::IntegrationTest) if you're using Test::Unit, or Request specs if you're using RSpec.
+
+Test::Unit Example:
+```ruby
+# test/integration/v1/test_controller_test.rb
+require 'test_helper'
+
+class V1::TestControllerTest < ActionDispatch::IntegrationTest
+  test "should get v1" do
+    get '/test', {}, {'Accept' => 'application/vnd.mycompany.com; version=1'}
+    assert_response 200
+    assert_equal "v1", @response.body
+  end
+end
+```
+
+RSpec Example:
+```ruby
+# spec/requests/v1/test_controller_spec.rb
+require 'spec_helper'
+
+describe V1::TestController do
+  it "should get v1" do
+    get '/test', {}, {'Accept' => 'application/vnd.mycompany.com; version=1'}
+    assert_response 200
+    assert_equal "v1", response.body
+  end
+end
+```
+
+## Generators
+
+Versionist comes with generators to facilitate managing the versions of your API. To see the available generators, simply run
+`rails generate`, and you will see the versionist generators under the `versionist` namespace.
+
+The following generators are available:
+
+### `versionist:new_api_version`
+
+creates the infrastructure for a new API version. This will create:
+
+- A new controller namespace, base controller and test
+- A new presenters namespace, base presenter and test
+- A new documentation directory and base files
+
+Usage
+
+    rails generate versionist:new_api_version <version> <module namespace> [options]
+
+Examples:
+
+    # HTTP header versioning strategy
+    rails generate versionist:new_api_version v2 V2 --header=name:Accept value:"application/vnd.mycompany.com; version=2"
+
+    # request parameter versioning strategy
+    rails generate versionist:new_api_version v2 V2 --parameter=name:version value:2
+
+    # path versioning strategy
+    rails generate versionist:new_api_version v2 V2 --path=value:v2
+
+    # multiple versioning strategies
+    rails generate versionist:new_api_version v2 V2 --header=name:Accept value:"application/vnd.mycompany.com; version=2" --parameter=name:version value:2
+
+    # default version
+    rails generate versionist:new_api_version v2 V2 --path=value:v2 --default
+
+    # route :defaults hash
+    rails generate versionist:new_api_version v2 V2 --path=value:v2 --defaults=format:json
+
+
+    rails generate versionist:new_api_version v2 V2 --header=name:Accept value:"application/vnd.mycompany.com; version=2"
+      route  api_version(:module => "V2", :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=2"}) do
+      end
+      create  app/controllers/v2
+      create  app/controllers/v2/base_controller.rb
+      create  spec/controllers/v2
+      create  spec/controllers/v2/base_controller_spec.rb
+      create  spec/requests/v2
+      create  spec/requests/v2/base_controller_spec.rb
+      create  app/presenters/v2
+      create  app/presenters/v2/base_presenter.rb
+      create  spec/presenters/v2
+      create  spec/presenters/v2/base_presenter_spec.rb
+      create  app/helpers/v2
+      create  spec/helpers/v2
+      create  public/docs/v2
+      create  public/docs/v2/index.html
+      create  public/docs/v2/style.css
+
+
+### `versionist:new_controller`
+
+creates a new controller class with the given name under the given version module.
+
+Usage
+
+    rails generate versionist:new_controller <name> <module namespace>
+
+Example:
+
+    rails generate versionist:new_controller foos V2
+      create  app/controllers/v2/foos_controller.rb
+      create  spec/controllers/v2/foos_controller_spec.rb
+      create  spec/requests/v2/foos_controller_spec.rb
+
+
+### `versionist:new_presenter`
+
+creates a new presenter class with the given name under the given version module.
+
+Usage
+
+    rails generate versionist:new_presenter <name> <module namespace>
+
+Example:
+
+    rails generate versionist:new_presenter foos V2
+      create  app/presenters/v2/foos_presenter.rb
+      create  spec/presenters/v2/foos_presenter_spec.rb
+
+
+### `versionist:copy_api_version`
+
+copies an existing API version to a new API version. This will do the following:
+
+- Copy all existing routes in config/routes.rb from the old API version to routes for the new API version in config/routes.rb (**see note below**)
+- Copy all existing controllers and tests from the old API version to the new API version
+- Copy all existing presenters and tests from the old API version to the new API version
+- Copy all existing helpers and tests from the old API version to the new API version
+- Copy all documentation from the old API version to the new API version
+
+**Note**: routes can only be copied with MRI Ruby 1.9 and above, as this feature relies on Ripper which is only available 
+in stdlib in MRI Ruby 1.9 and above. Outside of routes copying, the other copy steps will work just fine in Ruby 1.8 and other
+non-MRI Ruby implementations.
+
+Usage
+
+    rails generate versionist:copy_api_version <old version> <old module namespace> <new version> <new module namespace>
+
+Example:
+
+    rails generate versionist:copy_api_version v2 V2 v3 V3
+      route  api_version(:module => "V3", :header=>"Accept", :value=>"application/vnd.mycompany.com; version=3") do
+      end
+      Copying all files from app/controllers/v2 to app/controllers/v3
+      Copying all files from spec/controllers/v2 to spec/controllers/v3
+      Copying all files from app/presenters/v2 to app/presenters/v3
+      Copying all files from spec/presenters/v2 to spec/presenters/v3
+      Copying all files from app/helpers/v2 to app/helpers/v3
+      Copying all files from spec/helpers/v2 to spec/helpers/v3
+      Copying all files from public/docs/v2 to public/docs/v3
+
+## Additional Resources
+- [API Versioning using Versionist](http://www.multunus.com/blog/2014/04/api-versioning-using-versionist/)
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..0691006
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,33 @@
+GEMFILE_MAP = {"gemfiles/Rails-3.0" => "Rails 3.0", "gemfiles/Rails-3.1" => "Rails 3.1", "gemfiles/Rails-3.2" => "Rails 3.2", "gemfiles/RailsAPI-0.0" => "Rails API 0.0", "gemfiles/Rails-4.0" => "Rails 4.0", "gemfiles/Rails-4.0-RSpec3" => "RSpec 3", "gemfiles/Rails-5.0" => "Rails 5.0", "gemfiles/Rails-5.1" => "Rails 5.1"}
+
+# To run the tests locally:
+#   gem install bundler
+#   rake test:all
+namespace :test do
+  desc "Installs all dependencies"
+  task :setup do
+    GEMFILE_MAP.each do |gemfile, name|
+      puts "Installing gems for testing with #{name} ..."
+      sh "env BUNDLE_GEMFILE=#{File.dirname(__FILE__) + '/' + gemfile} bundle install"
+    end
+  end
+
+  GEMFILE_MAP.each do |gemfile, name|
+    desc "Run all tests against #{name}"
+    task gemfile.downcase.gsub(/\./, "_") do
+      sh "env BUNDLE_GEMFILE=#{gemfile} bundle exec rake"
+    end
+  end
+  task :all=> [:setup] + GEMFILE_MAP.map {|gemfile, name| "test:#{gemfile.downcase.gsub(/\./, "_")}"}
+end
+
+require 'rspec/core/rake_task'
+
+desc "Run all specs"
+RSpec::Core::RakeTask.new
+task :default => [:spec]
+
+task :build do
+  system "gem build versionist.gemspec"
+end
+
diff --git a/debian/changelog b/debian/changelog
index b1f5552..abf8b3e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-ruby-versionist (2.0.1-3) UNRELEASED; urgency=medium
+ruby-versionist (2.0.1+git20210211.1.80b09ce-1) UNRELEASED; urgency=medium
 
   * Update watch file format version to 4.
   * Bump debhelper from old 12 to 13.
@@ -9,8 +9,9 @@ ruby-versionist (2.0.1-3) UNRELEASED; urgency=medium
     + ruby-versionist: Drop versioned constraint on ruby-activesupport and
       ruby-railties in Depends.
   * Update standards version to 4.6.2, no changes needed.
+  * New upstream snapshot.
 
- -- Debian Janitor <janitor@jelmer.uk>  Fri, 10 Sep 2021 13:56:58 -0000
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 11 Jan 2023 04:25:48 -0000
 
 ruby-versionist (2.0.1-2) unstable; urgency=medium
 
diff --git a/gemfiles/Rails-3.0 b/gemfiles/Rails-3.0
new file mode 100644
index 0000000..2dbfa51
--- /dev/null
+++ b/gemfiles/Rails-3.0
@@ -0,0 +1,14 @@
+source "http://rubygems.org"
+
+gem "rails", "~> 3.0.0"
+
+gemspec :path => "../"
+
+group :development, :test do
+  gem 'rake', '>= 0.9.2', '< 10.5.0'
+  gem 'rspec', '2.8.0'
+  gem 'rspec-rails', '2.8.0'
+  gem 'generator_spec', '0.8.5'
+  gem 'simplecov', '0.5.4'
+  gem 'test-unit'
+end
diff --git a/gemfiles/Rails-3.1 b/gemfiles/Rails-3.1
new file mode 100644
index 0000000..20c79df
--- /dev/null
+++ b/gemfiles/Rails-3.1
@@ -0,0 +1,14 @@
+source "http://rubygems.org"
+
+gem "rails", "~> 3.1.0"
+
+gemspec :path => "../"
+
+group :development, :test do
+  gem 'rake', '>= 0.9.2', '< 10.5.0'
+  gem 'rspec', '2.8.0'
+  gem 'rspec-rails', '2.8.0'
+  gem 'generator_spec', '0.8.5'
+  gem 'simplecov', '0.5.4'
+  gem 'test-unit'
+end
diff --git a/gemfiles/Rails-3.2 b/gemfiles/Rails-3.2
new file mode 100644
index 0000000..2280c5f
--- /dev/null
+++ b/gemfiles/Rails-3.2
@@ -0,0 +1,14 @@
+source "http://rubygems.org"
+
+gem "rails", "~> 3.2.0"
+
+gemspec :path => "../"
+
+group :development, :test do
+  gem 'rake', '>= 0.9.2', '< 10.5.0'
+  gem 'rspec', '2.8.0'
+  gem 'rspec-rails', '2.8.0'
+  gem 'generator_spec', '0.8.5'
+  gem 'simplecov', '0.5.4'
+  gem 'test-unit'
+end
diff --git a/gemfiles/Rails-4.0 b/gemfiles/Rails-4.0
new file mode 100644
index 0000000..7ce4090
--- /dev/null
+++ b/gemfiles/Rails-4.0
@@ -0,0 +1,13 @@
+source "http://rubygems.org"
+
+gem "rails", "4.0.0"
+
+gemspec :path => "../"
+
+group :development, :test do
+  gem 'rake'
+  gem 'rspec', '>= 2.13.0'
+  gem 'rspec-rails', '>= 2.13.0'
+  gem 'generator_spec', '0.9.0'
+  gem 'simplecov'
+end
diff --git a/gemfiles/Rails-4.0-RSpec3 b/gemfiles/Rails-4.0-RSpec3
new file mode 100644
index 0000000..d08a92c
--- /dev/null
+++ b/gemfiles/Rails-4.0-RSpec3
@@ -0,0 +1,13 @@
+source "http://rubygems.org"
+
+gem "rails", "4.0.0"
+
+gemspec :path => "../"
+
+group :development, :test do
+  gem 'rake'
+  gem 'rspec', '>= 3'
+  gem 'rspec-rails', '>= 3'
+  gem 'generator_spec', '0.9.0'
+  gem 'simplecov'
+end
diff --git a/gemfiles/Rails-5.0 b/gemfiles/Rails-5.0
new file mode 100644
index 0000000..ce093d4
--- /dev/null
+++ b/gemfiles/Rails-5.0
@@ -0,0 +1,13 @@
+source "http://rubygems.org"
+
+gem "rails", "5.0.0"
+
+gemspec :path => "../"
+
+group :development, :test do
+  gem 'rake'
+  gem 'rspec', '>= 2.13.0'
+  gem 'rspec-rails', '>= 2.13.0'
+  gem 'generator_spec'
+  gem 'simplecov'
+end
diff --git a/gemfiles/Rails-5.1 b/gemfiles/Rails-5.1
new file mode 100644
index 0000000..ac104b9
--- /dev/null
+++ b/gemfiles/Rails-5.1
@@ -0,0 +1,13 @@
+source "http://rubygems.org"
+
+gem "rails", "5.1.0"
+
+gemspec :path => "../"
+
+group :development, :test do
+  gem 'rake'
+  gem 'rspec', '>= 2.13.0'
+  gem 'rspec-rails', '>= 2.13.0'
+  gem 'generator_spec'
+  gem 'simplecov'
+end
diff --git a/gemfiles/RailsAPI-0.0 b/gemfiles/RailsAPI-0.0
new file mode 100644
index 0000000..122c674
--- /dev/null
+++ b/gemfiles/RailsAPI-0.0
@@ -0,0 +1,14 @@
+source "http://rubygems.org"
+
+gem "rails-api", "~> 0.0"
+
+gemspec :path => "../"
+
+group :development, :test do
+  gem 'rake', '>= 0.9.2', '< 10.5.0'
+  gem 'rspec', '2.8.0'
+  gem 'rspec-rails', '2.8.0'
+  gem 'generator_spec', '0.8.5'
+  gem 'simplecov', '0.5.4'
+  gem 'test-unit'
+end
diff --git a/spec/api_routing_spec.rb b/spec/api_routing_spec.rb
new file mode 100644
index 0000000..946607c
--- /dev/null
+++ b/spec/api_routing_spec.rb
@@ -0,0 +1,1037 @@
+require 'spec_helper'
+require 'rspec/rails'
+
+describe Versionist::Routing do
+  include RSpec::Rails::RequestExampleGroup
+
+  before :all do
+    ENV["RAILS_ENV"] = 'test'
+    require File.expand_path("../test-api/config/application", __FILE__)
+    TestApi::Application.initialize!
+  end
+
+  context "#api_version" do
+    before :each do
+      Versionist.configuration.clear!
+      TestApi::Application.routes.clear!
+    end
+
+    it "should raise an error when config nil" do
+      lambda {
+        TestApi::Application.routes.draw do
+          api_version(nil)
+        end
+      }.should raise_error(ArgumentError, /you must pass a configuration Hash to api_version/)
+    end
+
+    it "should raise an error when config is not a Hash" do
+      lambda {
+        TestApi::Application.routes.draw do
+          api_version(1)
+        end
+      }.should raise_error(ArgumentError, /you must pass a configuration Hash to api_version/)
+    end
+
+    it "should raise an error when config doesn't contain any supported strategies" do
+      lambda {
+        TestApi::Application.routes.draw do
+          api_version({})
+        end
+      }.should raise_error(ArgumentError, /you must specify :header, :path, or :parameter in configuration Hash passed to api_version/)
+    end
+
+    it "should raise an error when strategy key doesn't point to a Hash" do
+      [:header, :path, :parameter].each do |s|
+        lambda {
+          TestApi::Application.routes.draw do
+            api_version({s => 1})
+          end
+        }.should raise_error(ArgumentError, /#{s} key in configuration Hash passed to api_version must point to a Hash/)
+      end
+    end
+
+    it "should raise an error when config doesn't contain :module" do
+      lambda {
+        TestApi::Application.routes.draw do
+          api_version({:path => {:value => "v1"}})
+        end
+      }.should raise_error(ArgumentError, /you must specify :module in configuration Hash passed to api_version/)
+    end
+
+    it "should raise an error when config contains a :defaults key which isn't a Hash" do
+      lambda {
+        TestApi::Application.routes.draw do
+          api_version({:module => "V1", :path => {:value => "v1"}, :defaults => 1})
+        end
+      }.should raise_error(ArgumentError, /:defaults must be a Hash/)
+    end
+
+    it "should add the middleware" do
+      TestApi::Application.routes.draw do
+        api_version({:module => "v1", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-v1"}}) do
+          match '/foos.(:format)' => 'foos#index', :via => :get
+          match '/foos_no_format' => 'foos#index', :via => :get
+          resources :bars
+        end
+        match '/foos(:format)' => 'foos#index', :via => :get
+      end
+      TestApi::Application.config.middleware.should include(Versionist::Middleware)
+    end
+
+    {"v1" => "v1", "v1" => "V1", "v2" => "v2", "v2" => "V2", "v2.1" => "v2__1", "v2.1" => "V2__1", "v3" => "Api::V3", "v3" => "api/v3"}.each do |ver, mod|
+      # Skip module names with underscores in Rails 3.2+
+      # https://github.com/rails/rails/issues/5849
+      next if ((Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR == 2) || (Rails::VERSION::MAJOR >= 4)) && mod.include?('_')
+      context ver do
+        before :each do
+          @headers = Hash.new
+        end
+
+        context ":header" do
+          context "Accept" do
+            before :each do
+              TestApi::Application.routes.draw do
+                api_version({:module => mod, :header => {:name => "Accept", :value => "application/vnd.mycompany.com-#{ver}"}}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                  match '/foos_no_format' => 'foos#index', :via => :get
+                  resources :bars
+                end
+                match '*a', :to => 'application#not_found', :via => :get
+              end
+            end
+
+            it "should not route when header isn't present" do
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 404
+            end
+
+            it "should not route when header doesn't match" do
+              @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-v4"
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 404
+            end
+
+            it "should route to the correct controller when header matches" do
+              @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-#{ver}"
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              if older_than_rails_5?
+                get "/foos.xml", nil, @headers
+              else
+                get "/foos.xml", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+            end
+
+            it "should route to the correct controller when format specified via accept header" do
+              @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-#{ver},application/json"
+              if older_than_rails_5?
+                get "/foos_no_format", nil, @headers
+              else
+                get "/foos_no_format", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              @headers["HTTP_ACCEPT"] = "application/xml, application/vnd.mycompany.com-#{ver}"
+              if older_than_rails_5?
+                get "/foos_no_format", nil, @headers
+              else
+                get "/foos_no_format", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+
+              @headers["HTTP_ACCEPT"] = "application/xml, application/vnd.mycompany.com-#{ver}, application/json"
+              if older_than_rails_5?
+                get "/foos_no_format", nil, @headers
+              else
+                get "/foos_no_format", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+            end
+
+            context ":default => true" do
+              before :each do
+                TestApi::Application.routes.draw do
+                  api_version({:module => mod, :header => {:name => "Accept", :value => "application/vnd.mycompany.com-#{ver}"}, :default => true}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                  end
+                  api_version({:module => "not_default", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-not_default"}}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                  end
+                end
+              end
+
+              it "should route to the default when no version given" do
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal ver, response.body
+
+                @headers["HTTP_ACCEPT"] = ""
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal ver, response.body
+
+                @headers["HTTP_ACCEPT"] = "   "
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal ver, response.body
+              end
+
+              it "should not route to the default when another configured version is given" do
+                @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-not_default"
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal "not_default", response.body
+              end
+            end
+
+            context ":defaults" do
+              it "should pass the :defaults hash on to the scope() call" do
+                ActionDispatch::Routing::Mapper.any_instance.should_receive(:scope).with(hash_including(:defaults => {:format => :json}))
+                TestApi::Application.routes.draw do
+                  api_version({:module => mod, :header => {:name => "Accept", :value => "application/vnd.mycompany.com-#{ver}"}, :defaults => {:format => :json}}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                    match '/foos_no_format' => 'foos#index', :via => :get
+                    resources :bars
+                  end
+                end
+              end
+            end
+          end
+
+          context "Accept with parameters" do
+            before :each do
+              TestApi::Application.routes.draw do
+                api_version({:module => mod, :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=#{ver}"}}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                  match '/foos_no_format' => 'foos#index', :via => :get
+                  resources :bars
+                end
+                match '*a', :to => 'application#not_found', :via => :get
+              end
+            end
+
+            it "should not route when header isn't present" do
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 404
+            end
+
+            it "should not route when header doesn't match" do
+              @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com; version=v4"
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 404
+            end
+
+            it "should route to the correct controller when header matches" do
+              @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com; version=#{ver}"
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              if older_than_rails_5?
+                get "/foos.xml", nil, @headers
+              else
+                get "/foos.xml", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+            end
+
+            it "should route to the correct controller when format specified via accept header" do
+              @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com; version=#{ver},application/json"
+              if older_than_rails_5?
+                get "/foos_no_format", nil, @headers
+              else
+                get "/foos_no_format", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              @headers["HTTP_ACCEPT"] = "application/xml, application/vnd.mycompany.com; version=#{ver}"
+              if older_than_rails_5?
+                get "/foos_no_format", nil, @headers
+              else
+                get "/foos_no_format", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+
+              @headers["HTTP_ACCEPT"] = "application/xml, application/vnd.mycompany.com; version=#{ver}, application/json"
+              if older_than_rails_5?
+                get "/foos_no_format", nil, @headers
+              else
+                get "/foos_no_format", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+            end
+
+            context ":default => true" do
+              before :each do
+                TestApi::Application.routes.draw do
+                  api_version({:module => mod, :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=#{ver}"}, :default => true}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                  end
+                  api_version({:module => "not_default", :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=not_default"}}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                  end
+                end
+              end
+
+              it "should route to the default when no version given" do
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal ver, response.body
+
+                @headers["HTTP_ACCEPT"] = ""
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal ver, response.body
+
+                @headers["HTTP_ACCEPT"] = "   "
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal ver, response.body
+              end
+
+              it "should not route to the default when another configured version is given" do
+                @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com; version=not_default"
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal "not_default", response.body
+              end
+            end
+
+            context ":defaults" do
+              it "should pass the :defaults hash on to the scope() call" do
+                ActionDispatch::Routing::Mapper.any_instance.should_receive(:scope).with(hash_including(:defaults => {:format => :json}))
+                TestApi::Application.routes.draw do
+                  api_version({:module => mod, :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=#{ver}"}, :defaults => {:format => :json}}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                    match '/foos_no_format' => 'foos#index', :via => :get
+                    resources :bars
+                  end
+                end
+              end
+            end
+          end
+
+          context "custom header" do
+            before :each do
+              TestApi::Application.routes.draw do
+                api_version({:module => mod, :header => {:name => "API-VERSION", :value => ver}}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                  match '/foos_no_format' => 'foos#index', :via => :get
+                  resources :bars
+                end
+                match '*a', :to => 'application#not_found', :via => :get
+              end
+            end
+
+            it "should not route when header isn't present" do
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 404
+            end
+
+            it "should not route when header doesn't match" do
+              @headers["API_VERSION"] = "v3"
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 404
+            end
+
+            it "should route to the correct controller when header matches" do
+              @headers["HTTP_API_VERSION"] = ver
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              if older_than_rails_5?
+                get "/foos.xml", nil, @headers
+              else
+                get "/foos.xml", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+            end
+
+            it "should route to the correct controller when format specified via accept header" do
+              @headers["HTTP_ACCEPT"] = "application/json,application/xml"
+              @headers["HTTP_API_VERSION"] = ver
+              if older_than_rails_5?
+                get "/foos_no_format", nil, @headers
+              else
+                get "/foos_no_format", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              @headers["HTTP_ACCEPT"] = "application/xml,application/json"
+              @headers["HTTP_API_VERSION"] = ver
+              if older_than_rails_5?
+                get "/foos_no_format", nil, @headers
+              else
+                get "/foos_no_format", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+            end
+
+            context ":default => true" do
+              before :each do
+                TestApi::Application.routes.draw do
+                  api_version({:module => mod, :header => {:name => "API-VERSION", :value => ver}, :default => true}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                  end
+                  api_version({:module => "not_default", :header => {:name => "API-VERSION", :value => "not_default"}}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                  end
+                end
+              end
+
+              it "should route to the default when no version given" do
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal ver, response.body
+
+                @headers["HTTP_API_VERSION"] = ""
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal ver, response.body
+
+                @headers["HTTP_API_VERSION"] = "    "
+                if older_than_rails_5?
+                  get "/foos.xml", nil, @headers
+                else
+                  get "/foos.xml", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/xml', response.content_type
+                assert_equal ver, response.body
+              end
+
+              it "should not route to the default when another configured version is given" do
+                @headers["HTTP_API_VERSION"] = "not_default"
+                if older_than_rails_5?
+                  get "/foos.json", nil, @headers
+                else
+                  get "/foos.json", :params => nil, :headers => @headers
+                end
+                assert_response 200
+                assert_equal 'application/json', response.content_type
+                assert_equal "not_default", response.body
+              end
+            end
+
+            context ":defaults" do
+              it "should pass the :defaults hash on to the scope() call" do
+                ActionDispatch::Routing::Mapper.any_instance.should_receive(:scope).with(hash_including(:defaults => {:format => :json}))
+                TestApi::Application.routes.draw do
+                  api_version({:module => mod, :header => {:name => "API-VERSION", :value => ver}, :defaults => {:format => :json}}) do
+                    match '/foos.(:format)' => 'foos#index', :via => :get
+                    match '/foos_no_format' => 'foos#index', :via => :get
+                    resources :bars
+                  end
+                end
+              end
+            end
+          end
+        end
+
+        context ":path" do
+          before :each do
+            TestApi::Application.routes.draw do
+              api_version({:module => mod, :path => {:value => "/#{ver}"}}) do
+                match '/foos.(:format)' => 'foos#index', :via => :get
+                match '/foos_no_format' => 'foos#index', :via => :get
+                resources :bars
+              end
+              match '*a', :to => 'application#not_found', :via => :get
+            end
+          end
+
+          it "should not route when path isn't present" do
+            if older_than_rails_5?
+              get "/foos.json", nil, @headers
+            else
+              get "/foos.json", :params => nil, :headers => @headers
+            end
+            assert_response 404
+          end
+
+          it "should not route when path doesn't match" do
+            if older_than_rails_5?
+              get "/bogu/foos.json", nil, @headers
+            else
+              get "/bogus/foos.json", :params => nil, :headers => @headers
+            end
+            assert_response 404
+          end
+
+          it "should route to the correct controller when path matches" do
+            if older_than_rails_5?
+              get "/#{ver}/foos.json", nil, @headers
+            else
+              get "/#{ver}/foos.json", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal ver, response.body
+
+            if older_than_rails_5?
+              get "/#{ver}/bars.json", nil, @headers
+            else
+              get "/#{ver}/bars.json", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal ver, response.body
+
+            if older_than_rails_5?
+              get "/#{ver}/foos.xml", nil, @headers
+            else
+              get "/#{ver}/foos.xml", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/xml', response.content_type
+            assert_equal ver, response.body
+
+            if older_than_rails_5?
+              get "/#{ver}/bars.xml", nil, @headers
+            else
+              get "/#{ver}/bars.xml", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/xml', response.content_type
+            assert_equal ver, response.body
+          end
+
+          it "should route to the correct controller when path matches and format specified via accept header" do
+            @headers["HTTP_ACCEPT"] = "application/json,application/xml"
+            if older_than_rails_5?
+              get "/#{ver}/foos_no_format", nil, @headers
+            else
+              get "/#{ver}/foos_no_format", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal ver, response.body
+
+            @headers["HTTP_ACCEPT"] = "application/xml,application/json"
+            if older_than_rails_5?
+              get "/#{ver}/foos_no_format", nil, @headers
+            else
+              get "/#{ver}/foos_no_format", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/xml', response.content_type
+            assert_equal ver, response.body
+          end
+
+          context ":default => true" do
+            before :each do
+              TestApi::Application.routes.draw do
+                api_version({:module => mod, :path => {:value => "/#{ver}"}, :default => true}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                  resources :bars
+                end
+                api_version({:module => "not_default", :path => {:value => "/not_default"}}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                  resources :bars
+                end
+              end
+            end
+
+            it "should route to the default when no version given" do
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              if older_than_rails_5?
+                get "/#{ver}/bars.json", nil, @headers
+              else
+                get "/#{ver}/bars.json", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              if older_than_rails_5?
+                get "/foos.xml", nil, @headers
+              else
+                get "/foos.xml", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+
+              if older_than_rails_5?
+                get "/#{ver}/bars.xml", nil, @headers
+              else
+                get "/#{ver}/bars.xml", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/xml', response.content_type
+              assert_equal ver, response.body
+            end
+
+            it "should not route to the default when another configured version is given" do
+              if older_than_rails_5?
+                get "/not_default/foos.json", nil, @headers
+              else
+                get "/not_default/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal "not_default", response.body
+            end
+          end
+
+          context ":defaults" do
+            it "should pass the :defaults hash on to the namespace() call" do
+              ActionDispatch::Routing::Mapper.any_instance.should_receive(:namespace).with("#{ver}", hash_including(:defaults => {:format => :json}))
+              TestApi::Application.routes.draw do
+                api_version({:module => mod, :path => {:value => "/#{ver}"}, :defaults => {:format => :json}}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                  match '/foos_no_format' => 'foos#index', :via => :get
+                  resources :bars
+                end
+              end
+            end
+
+            it "should pass the :defaults hash on to the namespace() call and the scope() call when :default is present" do
+              ActionDispatch::Routing::Mapper.any_instance.should_receive(:namespace).with("#{ver}", hash_including(:defaults => {:format => :json}))
+              ActionDispatch::Routing::Mapper.any_instance.should_receive(:scope).with(hash_including(:defaults => {:format => :json}))
+              TestApi::Application.routes.draw do
+                api_version({:module => mod, :path => {:value => "/#{ver}"}, :default => true, :defaults => {:format => :json}}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                  match '/foos_no_format' => 'foos#index', :via => :get
+                  resources :bars
+                end
+              end
+            end
+          end
+        end
+
+        context ":parameter" do
+          before :each do
+            TestApi::Application.routes.draw do
+              api_version({:module => mod, :parameter => {:name => "version", :value => ver}}) do
+                match '/foos.(:format)' => 'foos#index', :via => :get
+                match '/foos_no_format' => 'foos#index', :via => :get
+                resources :bars
+              end
+              match '*a', :to => 'application#not_found', :via => :get
+            end
+          end
+
+          it "should not route when parameter isn't present" do
+            if older_than_rails_5?
+              get "/foos.json", nil, @headers
+            else
+              get "/foos.json", :params => nil, :headers => @headers
+            end
+            assert_response 404
+          end
+
+          it "should not route when parameter doesn't match" do
+            if older_than_rails_5?
+              get "/foos.json?version=3", nil, @headers
+            else
+              get "/foos.json?version=3", :params => nil, :headers => @headers
+            end
+            assert_response 404
+          end
+
+          it "should route to the correct controller when parameter matches" do
+            if older_than_rails_5?
+              get "/foos.json?version=#{ver}", nil, @headers
+            else
+              get "/foos.json?version=#{ver}", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal ver, response.body
+
+            if older_than_rails_5?
+              get "/foos.xml?version=#{ver}", nil, @headers
+            else
+              get "/foos.xml?version=#{ver}", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/xml', response.content_type
+            assert_equal ver, response.body
+          end
+
+          it "should route to the correct controller when parameter matches and format specified via accept header" do
+            @headers["HTTP_ACCEPT"] = "application/json,application/xml"
+            if older_than_rails_5?
+              get "/foos_no_format?version=#{ver}", nil, @headers
+            else
+              get "/foos_no_format?version=#{ver}", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal ver, response.body
+
+            @headers["HTTP_ACCEPT"] = "application/xml,application/json"
+            if older_than_rails_5?
+              get "/foos_no_format?version=#{ver}", nil, @headers
+            else
+              get "/foos_no_format?version=#{ver}", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/xml', response.content_type
+            assert_equal ver, response.body
+          end
+
+          context ":default => true" do
+            before :each do
+              TestApi::Application.routes.draw do
+                api_version({:module => mod, :parameter => {:name => "version", :value => ver}, :default => true}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                end
+                api_version({:module => "not_default", :parameter => {:name => "version", :value => "not_default"}}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                end
+              end
+            end
+
+            it "should route to the default when no version given" do
+              if older_than_rails_5?
+                get "/foos.json", nil, @headers
+              else
+                get "/foos.json", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+
+              if older_than_rails_5?
+                get "/foos.json?version=", nil, @headers
+              else
+                get "/foos.json?version=", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal ver, response.body
+            end
+
+            it "should not route to the default when another configured version is given" do
+              if older_than_rails_5?
+                get "/foos.json?version=not_default", nil, @headers
+              else
+                get "/foos.json?version=not_default", :params => nil, :headers => @headers
+              end
+              assert_response 200
+              assert_equal 'application/json', response.content_type
+              assert_equal "not_default", response.body
+            end
+          end
+
+          context ":defaults" do
+            it "should pass the :defaults hash on to the scope() call" do
+              ActionDispatch::Routing::Mapper.any_instance.should_receive(:scope).with(hash_including(:defaults => {:format => :json}))
+              TestApi::Application.routes.draw do
+                api_version({:module => mod, :parameter => {:name => "version", :value => ver}, :defaults => {:format => :json}}) do
+                  match '/foos.(:format)' => 'foos#index', :via => :get
+                  match '/foos_no_format' => 'foos#index', :via => :get
+                  resources :bars
+                end
+              end
+            end
+          end
+        end
+
+        context "multi-strategy :default => true" do
+          before :each do
+            TestApi::Application.routes.draw do
+              api_version({:module => mod, :header => {:name => "Accept", :value => "application/vnd.mycompany.com-#{ver}"}, :parameter => {:name => "version", :value => "#{ver}"}, :default => true}) do
+                match '/foos.(:format)' => 'foos#index', :via => :get
+              end
+              api_version({:module => "not_default", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-not_default"}}) do
+                match '/foos.(:format)' => 'foos#index', :via => :get
+              end
+            end
+          end
+
+          it "should route to the default when no version given" do
+            if older_than_rails_5?
+              get "/foos.json", nil, @headers
+            else
+              get "/foos.json", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal ver, response.body
+
+            @headers["HTTP_ACCEPT"] = ""
+            if older_than_rails_5?
+              get "/foos.json", nil, @headers
+            else
+              get "/foos.json", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal ver, response.body
+
+            @headers["HTTP_ACCEPT"] = "   "
+            if older_than_rails_5?
+              get "/foos.json", nil, @headers
+            else
+              get "/foos.json", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal ver, response.body
+          end
+
+          it "should not route to the default when another configured version is given" do
+            @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-not_default"
+            if older_than_rails_5?
+              get "/foos.json", nil, @headers
+            else
+              get "/foos.json", :params => nil, :headers => @headers
+            end
+            assert_response 200
+            assert_equal 'application/json', response.content_type
+            assert_equal "not_default", response.body
+          end
+        end
+      end
+    end
+
+    context "Accept header version substring matches" do
+      before :each do
+        @headers = Hash.new
+
+        TestApi::Application.routes.draw do
+          api_version({:module => "v1", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-v1"}, :default => true}) do
+            match '/foos.(:format)' => 'foos#index', :via => :get
+            match '/foos_no_format' => 'foos#index', :via => :get
+            resources :bars
+          end
+
+          api_version({:module => "v11", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-v11"}}) do
+            match '/foos.(:format)' => 'foos#index', :via => :get
+            match '/foos_no_format' => 'foos#index', :via => :get
+            resources :bars
+          end
+        end
+      end
+
+      it "should route to the correct controller" do
+        @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-v1"
+        if older_than_rails_5?
+          get "/foos.json", nil, @headers
+        else
+          get "/foos.json", :params => nil, :headers => @headers
+        end
+        assert_response 200
+        assert_equal 'application/json', response.content_type
+        assert_equal "v1", response.body
+
+        @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-v1"
+        if older_than_rails_5?
+          get "/foos.json", nil, @headers
+        else
+          get "/foos.json", :params => nil, :headers => @headers
+        end
+        assert_response 200
+        assert_equal 'application/json', response.content_type
+        assert_equal "v1", response.body
+
+        # default routing
+        if older_than_rails_5?
+          get "/foos.json", nil, {}
+        else
+          get "/foos.json", :params => nil, :headers => {}
+        end
+        assert_response 200
+        assert_equal 'application/json', response.content_type
+        assert_equal "v1", response.body
+      end
+
+      it "should route to the correct controller when format specified via accept header" do
+        @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-v1,application/json"
+        if older_than_rails_5?
+          get "/foos_no_format", nil, @headers
+        else
+          get "/foos_no_format", :params => nil, :headers => @headers
+        end
+        assert_response 200
+        assert_equal 'application/json', response.content_type
+        assert_equal "v1", response.body
+
+        @headers["HTTP_ACCEPT"] = "application/xml, application/vnd.mycompany.com-v1"
+        if older_than_rails_5?
+          get "/foos_no_format", nil, @headers
+        else
+          get "/foos_no_format", :params => nil, :headers => @headers
+        end
+        assert_response 200
+        assert_equal 'application/xml', response.content_type
+        assert_equal "v1", response.body
+
+        @headers["HTTP_ACCEPT"] = "application/xml, application/vnd.mycompany.com-v1, application/json"
+        if older_than_rails_5?
+          get "/foos_no_format", nil, @headers
+        else
+          get "/foos_no_format", :params => nil, :headers => @headers
+        end
+        assert_response 200
+        assert_equal 'application/xml', response.content_type
+        assert_equal "v1", response.body
+
+        @headers["HTTP_ACCEPT"] = "application/vnd.mycompany.com-v11,application/json"
+        if older_than_rails_5?
+          get "/foos_no_format", nil, @headers
+        else
+          get "/foos_no_format", :params => nil, :headers => @headers
+        end
+        assert_response 200
+        assert_equal 'application/json', response.content_type
+        assert_equal "v11", response.body
+
+        @headers["HTTP_ACCEPT"] = "application/xml, application/vnd.mycompany.com-v11"
+        if older_than_rails_5?
+          get "/foos_no_format", nil, @headers
+        else
+          get "/foos_no_format", :params => nil, :headers => @headers
+        end
+        assert_response 200
+        assert_equal 'application/xml', response.content_type
+        assert_equal "v11", response.body
+
+        @headers["HTTP_ACCEPT"] = "application/xml, application/vnd.mycompany.com-v11, application/json"
+        if older_than_rails_5?
+          get "/foos_no_format", nil, @headers
+        else
+          get "/foos_no_format", :params => nil, :headers => @headers
+        end
+        assert_response 200
+        assert_equal 'application/xml', response.content_type
+        assert_equal "v11", response.body
+      end
+    end
+  end
+
+  context "route reloading" do
+    it "should handle Rails.application.reload_routes!" do
+      lambda {
+        Rails.application.reload_routes!
+        Rails.application.reload_routes!
+      }.should_not raise_error
+    end
+  end
+end
diff --git a/spec/generators/copy_api_version_generator_spec.rb b/spec/generators/copy_api_version_generator_spec.rb
new file mode 100644
index 0000000..7c882c1
--- /dev/null
+++ b/spec/generators/copy_api_version_generator_spec.rb
@@ -0,0 +1,451 @@
+require 'spec_helper'
+require 'generator_spec/test_case'
+
+describe Versionist::CopyApiVersionGenerator do
+  include GeneratorSpec::TestCase
+  include Versionist::InflectorFixes
+
+  destination File.expand_path("../../tmp", __FILE__)
+
+  before :each do
+    prepare_destination
+    ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers", __FILE__))
+    ::Dir.mkdir(::File.expand_path("../../tmp/config", __FILE__))
+    ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+  end
+
+  {"v1" => "V1", "v2" => "V2", "v2.1" => "V2_1", "v20120119" => "Api::V20120119"}.each do |ver, mod|
+    context "#{ver} => #{mod}" do
+      context "api version doesn't exist" do
+        before :each do
+          ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\nend"}
+        end
+
+        after :each do
+          if older_than_rails_5?
+            ::FileUtils.rm_rf(::File.expand_path("../../tmp/test/integration/#{module_name_for_path(mod)}", __FILE__))
+          end
+          ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          ::FileUtils.rm_rf(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.rm_rf(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.rm_rf(::File.expand_path("../../tmp/app/helpers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.rm_rf(::File.expand_path("../../tmp/#{test_path}/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.rm_rf(::File.expand_path("../../tmp/spec/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.rm_rf(::File.expand_path("../../tmp/spec/requests/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = nil
+        end
+
+        it "should not raise an error if old version not found config/routes.rb" do
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version module not found in app/controllers" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version module not found in test path when Test::Unit is the test framework" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = :test_unit
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version module not found in test/integration when Test::Unit is the test framework" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = :test_unit
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version module not found in spec/controllers when rspec is the test framework" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = :rspec
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version module not found in spec/requests when rspec is the test framework" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = :rspec
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version module not found in app/presenters" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/controllers/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = :rspec
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version module not found in test/presenters when Test::Unit is the test framework" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/#{test_path}/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = :test_unit
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version module not found in spec/presenters when rspec is the test framework" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = :rspec
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+
+        it "should not raise an error if old version not found in public/docs" do
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/presenters/#{module_name_for_path(mod)}", __FILE__))
+          Versionist.configuration.configured_test_framework = :rspec
+          lambda {
+            run_generator [ver, mod, "x", "X", {}]
+          }.should_not raise_error
+        end
+      end
+
+      context "api version exists" do
+        before :each do
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/presenters/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/helpers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/helpers/#{module_name_for_path(mod)}", __FILE__))
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/public/docs/#{ver}", __FILE__))
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do\n  end\nend"}
+          ::File.open(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}/base_controller.rb", __FILE__), "w") {|f| f.write "class #{mod}::BaseController < ApplicationController\nend"}
+          ::File.open(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}/foos_controller.rb", __FILE__), "w") {|f| f.write "class #{mod}::FoosController < #{mod}::BaseController\nend"}
+          ::File.open(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}/base_presenter.rb", __FILE__), "w") {|f| f.write "class #{mod}::BasePresenter\n\n  def initialize(#{ver})\n    @#{ver} = #{ver}\n  end\n\n  def as_json(options={})\n    # fill me in...\n  end\n\n  def to_xml(options={}, &block)\n    xml = options[:builder] ||= Builder::XmlMarkup.new\n    # fill me in...\n  end\nend"}
+          ::File.open(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}/foo_presenter.rb", __FILE__), "w") {|f| f.write "class #{mod}::FooPresenter < #{mod}::BasePresenter\n\n  def initialize(#{ver})\n    @#{ver} = #{ver}\n  end\n\n  def as_json(options={})\n    # fill me in...\n  end\n\n  def to_xml(options={}, &block)\n    xml = options[:builder] ||= Builder::XmlMarkup.new\n    # fill me in...\n  end\nend"}
+          ::File.open(::File.expand_path("../../tmp/app/helpers/#{module_name_for_path(mod)}/foos_helper.rb", __FILE__), "w") {|f| f.write "module #{mod}::FoosHelper\n\n  def help\n  end\nend"}
+          ::File.open(::File.expand_path("../../tmp/public/docs/#{ver}/style.css", __FILE__), "w") {|f| f.write "body {margin: 0; background-color: #fff; color: #000; font-family: Arial,sans-serif;}\ncontent {margin-left: 200px;}\ncontent h1 {text-align: center;}\noperations {float: left; width: 200px; border-right: 1px solid #ccc;}\noperations h3 {text-align: center;}"}
+          ::File.open(::File.expand_path("../../tmp/public/docs/#{ver}/index.html", __FILE__), "w") {|f| f.write "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <title>Documentation for #{ver}</title>\n    <link href=\"#{ver}/style.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\">\n  </head>\n  <body>\n    <div id=\"container\">\n      <div id=\"operations\">\n        <h3>API Operations</h3>\n      </div>\n      <div id=\"content\">\n        <h1>Documentation for #{ver}</h1>\n      </div>\n    </div>\n  </body>\n</html>"}
+          Versionist.configuration.configured_test_framework = nil
+          run_generator [ver, mod, "x", "X"]
+        end
+
+        it "should copy correct api_version to config/routes.rb" do
+          if RUBY_VERSION =~ /1.9/ && defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby"
+            assert_file "config/routes.rb"
+            expected = <<-CONTENTS
+Test::Application.routes.draw do
+  api_version(:module => \"X\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-x\") do
+  end
+
+  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-#{ver}\") do
+  end
+end
+            CONTENTS
+
+            # Rails 4 removed the trailing newline from the 'route' generator
+            # https://github.com/rails/rails/commit/7cdb12286639b38db2eb1e9fd0c8b2e6bc3b39dc
+            if Rails::VERSION::MAJOR < 4
+              assert_file "config/routes.rb", expected.chop
+            elsif Rails::VERSION::MAJOR == 4
+              assert_file "config/routes.rb", expected.gsub(/^$\n/, '').chop
+            end
+          end
+        end
+
+        it "should copy old controllers to new controllers" do
+          expected_base_controller = <<-BASE
+class X::BaseController < ApplicationController
+end
+          BASE
+
+          expected_foos_controller = <<-FOOS
+class X::FoosController < X::BaseController
+end
+          FOOS
+
+          assert_file "app/controllers/#{module_name_for_path("X")}/base_controller.rb", expected_base_controller.chop
+          assert_file "app/controllers/#{module_name_for_path("X")}/foos_controller.rb", expected_foos_controller.chop
+        end
+
+        it "should copy old presenters to new presenters" do
+          expected_base_presenter = <<-BASE
+class X::BasePresenter
+
+  def initialize(#{ver})
+    @#{ver} = #{ver}
+  end
+
+  def as_json(options={})
+    # fill me in...
+  end
+
+  def to_xml(options={}, &block)
+    xml = options[:builder] ||= Builder::XmlMarkup.new
+    # fill me in...
+  end
+end
+          BASE
+
+          expected_foo_presenter = <<-FOOS
+class X::FooPresenter < X::BasePresenter
+
+  def initialize(#{ver})
+    @#{ver} = #{ver}
+  end
+
+  def as_json(options={})
+    # fill me in...
+  end
+
+  def to_xml(options={}, &block)
+    xml = options[:builder] ||= Builder::XmlMarkup.new
+    # fill me in...
+  end
+end
+          FOOS
+
+          assert_file "app/presenters/#{module_name_for_path("X")}/base_presenter.rb", expected_base_presenter.chop
+          assert_file "app/presenters/#{module_name_for_path("X")}/foo_presenter.rb", expected_foo_presenter.chop
+        end
+
+        it "should copy old helpers to new helpers" do
+          expected_foos_helper = <<-DOC
+module X::FoosHelper
+
+  def help
+  end
+end
+          DOC
+
+          assert_file "app/helpers/#{module_name_for_path("X")}/foos_helper.rb", expected_foos_helper.chop
+        end
+
+        it "should copy documentation" do
+          assert_file "public/docs/x/style.css"
+          assert_file "public/docs/x/index.html"
+        end
+
+        context "test_framework: test_unit" do
+          before :each do
+            if older_than_rails_5?
+              ::FileUtils.mkdir_p(::File.expand_path("../../tmp/test/integration/#{module_name_for_path(mod)}", __FILE__))
+              ::File.open(::File.expand_path("../../tmp/test/integration/#{module_name_for_path(mod)}/base_controller_test.rb", __FILE__), "w") {|f| f.write "require 'test_helper'\n\nclass #{mod}::BaseControllerTest < ActionDispatch::IntegrationTest\n  # Replace this with your real tests.\n  test \"the truth\" do\n    assert true\n  end\nend"}
+              ::File.open(::File.expand_path("../../tmp/test/integration/#{module_name_for_path(mod)}/foos_controller_test.rb", __FILE__), "w") {|f| f.write "require 'test_helper'\n\nclass #{mod}::FoosControllerTest < ActionDispatch::IntegrationTest\n  # Replace this with your real tests.\n  test \"the truth\" do\n    assert true\n  end\nend"}
+            end
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/#{test_path}/#{module_name_for_path(mod)}", __FILE__))
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/test/presenters/#{module_name_for_path(mod)}", __FILE__))
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/test/helpers/#{module_name_for_path(mod)}", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/#{test_path}/#{module_name_for_path(mod)}/base_controller_test.rb", __FILE__), "w") {|f| f.write "require 'test_helper'\n\nclass #{mod}::BaseControllerTest < ActionController::TestCase\n  # Replace this with your real tests.\n  test \"the truth\" do\n    assert true\n  end\nend"}
+            ::File.open(::File.expand_path("../../tmp/#{test_path}/#{module_name_for_path(mod)}/foos_controller_test.rb", __FILE__), "w") {|f| f.write "require 'test_helper'\n\nclass #{mod}::FoosControllerTest < ActionController::TestCase\n  # Replace this with your real tests.\n  test \"the truth\" do\n    assert true\n  end\nend"}
+            ::File.open(::File.expand_path("../../tmp/test/presenters/#{module_name_for_path(mod)}/base_presenter_test.rb", __FILE__), "w") {|f| f.write "require 'test_helper'\n\nclass #{mod}::BasePresenterTest < Test::Unit::TestCase\n  # Replace this with your real tests.\n  test \"the truth\" do\n    assert true\n  end\nend"}
+            ::File.open(::File.expand_path("../../tmp/test/presenters/#{module_name_for_path(mod)}/foo_presenter_test.rb", __FILE__), "w") {|f| f.write "require 'test_helper'\n\nclass #{mod}::FooPresenterTest < Test::Unit::TestCase\n  # Replace this with your real tests.\n  test \"the truth\" do\n    assert true\n  end\nend"}
+            ::File.open(::File.expand_path("../../tmp/test/helpers/#{module_name_for_path(mod)}/foos_helper_test.rb", __FILE__), "w") {|f| f.write "require 'test_helper'\n\nclass #{mod}::FoosHelperTest < Test::Unit::TestCase\n  # Replace this with your real tests.\n  test \"the truth\" do\n    assert true\n  end\nend"}
+            Versionist.configuration.configured_test_framework = :test_unit
+            run_generator [ver, mod, "x", "X"]
+          end
+
+          it "should copy old controller tests to new controller tests" do
+            expected_base_controller_functional_test = <<-BASE
+require 'test_helper'
+
+class X::BaseControllerTest < ActionController::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+            BASE
+
+            if older_than_rails_5?
+              expected_base_controller_integration_test = <<-BASE
+require 'test_helper'
+
+class X::BaseControllerTest < ActionDispatch::IntegrationTest
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              BASE
+            end
+
+            expected_foos_controller_functional_test = <<-FOOS
+require 'test_helper'
+
+class X::FoosControllerTest < ActionController::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+            FOOS
+
+            if older_than_rails_5?
+              expected_foos_controller_integration_test = <<-FOOS
+require 'test_helper'
+
+class X::FoosControllerTest < ActionDispatch::IntegrationTest
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              FOOS
+            end
+
+
+            assert_file "#{test_path}/#{module_name_for_path("X")}/base_controller_test.rb", expected_base_controller_functional_test.chop
+            assert_file "#{test_path}/#{module_name_for_path("X")}/foos_controller_test.rb", expected_foos_controller_functional_test.chop
+            if older_than_rails_5?
+              assert_file "test/integration/#{module_name_for_path("X")}/base_controller_test.rb", expected_base_controller_integration_test.chop
+              assert_file "test/integration/#{module_name_for_path("X")}/foos_controller_test.rb", expected_foos_controller_integration_test.chop
+            end
+          end
+
+          it "should copy old presenter tests to new presenter tests" do
+            expected_base_presenter_test = <<-BASE
+require 'test_helper'
+
+class X::BasePresenterTest < Test::Unit::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+            BASE
+
+            expected_foo_presenter_test = <<-FOOS
+require 'test_helper'
+
+class X::FooPresenterTest < Test::Unit::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+            FOOS
+
+            assert_file "test/presenters/#{module_name_for_path("X")}/base_presenter_test.rb", expected_base_presenter_test.chop
+            assert_file "test/presenters/#{module_name_for_path("X")}/foo_presenter_test.rb", expected_foo_presenter_test.chop
+          end
+
+          it "should copy old helper tests to new helper tests" do
+            expected_foos_helper_test = <<-DOC
+require 'test_helper'
+
+class X::FoosHelperTest < Test::Unit::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+            DOC
+
+            assert_file "test/helpers/#{module_name_for_path("X")}/foos_helper_test.rb", expected_foos_helper_test.chop
+          end
+        end
+
+        context "test_framework: rspec" do
+          before :each do
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/controllers/#{module_name_for_path(mod)}", __FILE__))
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/requests/#{module_name_for_path(mod)}", __FILE__))
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/presenters/#{module_name_for_path(mod)}", __FILE__))
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec/helpers/#{module_name_for_path(mod)}", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/spec/controllers/#{module_name_for_path(mod)}/base_controller_spec.rb", __FILE__), "w") {|f| f.write "require 'spec_helper'\n\ndescribe #{mod}::BaseController do\n\nend"}
+            ::File.open(::File.expand_path("../../tmp/spec/controllers/#{module_name_for_path(mod)}/foos_controller_spec.rb", __FILE__), "w") {|f| f.write "require 'spec_helper'\n\ndescribe #{mod}::FoosController do\n\nend"}
+            ::File.open(::File.expand_path("../../tmp/spec/requests/#{module_name_for_path(mod)}/base_controller_spec.rb", __FILE__), "w") {|f| f.write "require 'spec_helper'\n\ndescribe #{mod}::BaseController do\n\nend"}
+            ::File.open(::File.expand_path("../../tmp/spec/requests/#{module_name_for_path(mod)}/foos_controller_spec.rb", __FILE__), "w") {|f| f.write "require 'spec_helper'\n\ndescribe #{mod}::FoosController do\n\nend"}
+            ::File.open(::File.expand_path("../../tmp/spec/presenters/#{module_name_for_path(mod)}/base_presenter_spec.rb", __FILE__), "w") {|f| f.write "require 'spec_helper'\n\ndescribe #{mod}::BasePresenter do\n\nend"}
+            ::File.open(::File.expand_path("../../tmp/spec/presenters/#{module_name_for_path(mod)}/foo_presenter_spec.rb", __FILE__), "w") {|f| f.write "require 'spec_helper'\n\ndescribe #{mod}::FooPresenter do\n\nend"}
+            ::File.open(::File.expand_path("../../tmp/spec/helpers/#{module_name_for_path(mod)}/foos_helper_spec.rb", __FILE__), "w") {|f| f.write "require 'spec_helper'\n\ndescribe #{mod}::FoosHelper do\n\nend"}
+            Versionist.configuration.configured_test_framework = :rspec
+            run_generator [ver, mod, "x", "X"]
+          end
+
+          it "should copy old controller specs to new controller specs" do
+            expected_base_controller_spec = <<-BASE
+require 'spec_helper'
+
+describe X::BaseController do
+
+end
+            BASE
+
+            expected_foos_controller_spec = <<-FOOS
+require 'spec_helper'
+
+describe X::FoosController do
+
+end
+            FOOS
+
+            assert_file "spec/controllers/#{module_name_for_path("X")}/base_controller_spec.rb", expected_base_controller_spec.chop
+            assert_file "spec/controllers/#{module_name_for_path("X")}/foos_controller_spec.rb", expected_foos_controller_spec.chop
+            assert_file "spec/requests/#{module_name_for_path("X")}/base_controller_spec.rb", expected_base_controller_spec.chop
+            assert_file "spec/requests/#{module_name_for_path("X")}/foos_controller_spec.rb", expected_foos_controller_spec.chop
+          end
+
+          it "should copy old presenter specs to new presenter specs" do
+            expected_base_presenter_spec = <<-BASE
+require 'spec_helper'
+
+describe X::BasePresenter do
+
+end
+            BASE
+
+            expected_foo_presenter_spec = <<-FOOS
+require 'spec_helper'
+
+describe X::FooPresenter do
+
+end
+            FOOS
+
+            assert_file "spec/presenters/#{module_name_for_path("X")}/base_presenter_spec.rb", expected_base_presenter_spec.chop
+            assert_file "spec/presenters/#{module_name_for_path("X")}/foo_presenter_spec.rb", expected_foo_presenter_spec.chop
+          end
+
+          it "should copy old helper specs to new helper specs" do
+            expected_foos_helper_spec = <<-DOC
+require 'spec_helper'
+
+describe X::FoosHelper do
+
+end
+            DOC
+
+            assert_file "spec/helpers/#{module_name_for_path("X")}/foos_helper_spec.rb", expected_foos_helper_spec.chop
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/spec/generators/inflector_fixes_spec.rb b/spec/generators/inflector_fixes_spec.rb
new file mode 100644
index 0000000..5e2bca3
--- /dev/null
+++ b/spec/generators/inflector_fixes_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Versionist::InflectorFixes do
+  before :each do
+    @object = Object.new
+    @object.extend(Versionist::InflectorFixes)
+  end
+
+  context "#module_name_for_route" do
+    it "should transform" do
+      @object.module_name_for_route("V2_1_3").should == "V2__1__3"
+    end
+  end
+
+  context "#module_name_for_path" do
+    it "should transform" do
+      @object.module_name_for_path("V2_1_3").should == "v2_1_3"
+    end
+  end
+end
diff --git a/spec/generators/new_api_version_generator_spec.rb b/spec/generators/new_api_version_generator_spec.rb
new file mode 100644
index 0000000..ddbbf20
--- /dev/null
+++ b/spec/generators/new_api_version_generator_spec.rb
@@ -0,0 +1,476 @@
+require 'spec_helper'
+require 'generator_spec/test_case'
+
+describe Versionist::NewApiVersionGenerator do
+  include GeneratorSpec::TestCase
+  include Versionist::InflectorFixes
+
+  destination File.expand_path("../../tmp", __FILE__)
+
+  before :each do
+    prepare_destination
+    ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers", __FILE__))
+    ::Dir.mkdir(::File.expand_path("../../tmp/config", __FILE__))
+    ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+  end
+
+  {"v1" => "V1", "v2" => "V2", "v2.1" => "V2_1", "v20120119" => "Api::V20120119"}.each do |ver, mod|
+    context "#{ver} => #{mod}" do
+      context "verify_options" do
+        it "should raise an error if no versioning strategies are specified" do
+          lambda {
+            run_generator %W(#{ver} #{mod})
+          }.should raise_error(RuntimeError, /Must specify at least one versioning strategy option/)
+        end
+
+        it "should raise an error if header hash doesn't contain name and value keys" do
+          lambda {
+            run_generator %W(#{ver} #{mod} --header=name:Accept)
+          }.should raise_error(RuntimeError, /Must specify name and value for header versioning strategy/)
+
+          lambda {
+            run_generator %W(#{ver} #{mod} --header=value:v1)
+          }.should raise_error(RuntimeError, /Must specify name and value for header versioning strategy/)
+        end
+
+        it "should not raise an error if header hash has both name and value keys" do
+          lambda {
+            run_generator %W(#{ver} #{mod} --header=name:Accept value:"application/vnd.mycompany.com; version=2")
+          }.should_not raise_error
+        end
+
+        it "should raise an error if parameter hash doesn't contain name and value keys" do
+          lambda {
+            run_generator %W(#{ver} #{mod} --parameter=name:Accept)
+          }.should raise_error(RuntimeError, /Must specify name and value for parameter versioning strategy/)
+
+          lambda {
+            run_generator %W(#{ver} #{mod} --parameter=value:1)
+          }.should raise_error(RuntimeError, /Must specify name and value for parameter versioning strategy/)
+        end
+
+        it "should not raise an error if parameter hash has both name and value keys" do
+          lambda {
+            run_generator %W(#{ver} #{mod} --parameter=name:version value:1)
+          }.should_not raise_error
+        end
+
+        it "should raise an error if path hash doesn't contain value key" do
+          lambda {
+            run_generator %W(#{ver} #{mod} --path=foo:bar)
+          }.should raise_error(RuntimeError, /Must specify value for path versioning strategy/)
+        end
+
+        it "should not raise an error if path hash has value key" do
+          lambda {
+            run_generator %W(#{ver} #{mod} --path=value:v1)
+          }.should_not raise_error
+        end
+      end
+
+      context "api version exists" do
+        before :each do
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => {:name => \"Accept\", :value => \"application/vnd.mycompany.com-v1\"}) do\n  end\nend"}
+        end
+
+        after :each do
+          ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+        end
+
+        it "should raise an error" do
+          lambda {
+            run_generator %W(#{ver} #{mod} --header=name:Accept value:"application/vnd.mycompany.com-v1")
+          }.should raise_error(RuntimeError, /API version already exists in config\/routes.rb/)
+        end
+      end
+
+      context "api version doesn't exist" do
+        before :each do
+          ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\nend"}
+          Versionist.configuration.configured_test_framework = nil
+          run_generator %W(#{ver} #{mod} --header=name:Accept value:application/vnd.mycompany.com-#{ver})
+        end
+
+        after :each do
+          ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+        end
+
+        it "should add correct api_version to config/routes.rb" do
+          assert_file "config/routes.rb"
+          expected = <<-CONTENTS
+Test::Application.routes.draw do
+  api_version(:module => "#{module_name_for_route(mod)}", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-#{ver}"}) do
+  end
+
+end
+          CONTENTS
+          # Rails 4 removed the trailing newline from the 'route' generator
+          # https://github.com/rails/rails/commit/7cdb12286639b38db2eb1e9fd0c8b2e6bc3b39dc
+          if Rails::VERSION::MAJOR < 4
+            assert_file "config/routes.rb", expected.chop
+          elsif Rails::VERSION::MAJOR == 4
+            assert_file "config/routes.rb", expected.gsub(/^$\n/, '').chop
+          end
+        end
+
+        it "should create a namespaced controller directory" do
+          assert_directory "app/controllers/#{module_name_for_path(mod)}"
+        end
+
+        it "should create a namespaced base controller" do
+          assert_file "app/controllers/#{module_name_for_path(mod)}/base_controller.rb", <<-CONTENTS
+class #{mod}::BaseController < ApplicationController
+end
+          CONTENTS
+        end
+
+        it "should create a namespaced presenters directory" do
+          assert_directory "app/presenters/#{module_name_for_path(mod)}"
+        end
+
+        it "should create a namespaced base presenter" do
+          assert_file "app/presenters/#{module_name_for_path(mod)}/base_presenter.rb", <<-CONTENTS
+class #{mod}::BasePresenter
+end
+          CONTENTS
+        end
+
+        it "should create a namespaced helpers directory" do
+          assert_directory "app/helpers/#{module_name_for_path(mod)}"
+        end
+
+        it "should create a documentation directory" do
+          assert_directory "public/docs/#{ver}"
+        end
+
+        it "should create a documentation index.html" do
+          assert_file "public/docs/#{ver}/index.html", <<-CONTENTS
+<!DOCTYPE html>
+<html lang="en-US">
+  <head>
+    <title>Documentation for #{ver}</title>
+    <link href="#{ver}/style.css" media="screen" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="container">
+      <div id="operations">
+        <h3>API Operations</h3>
+      </div>
+      <div id="content">
+        <h1>Documentation for #{ver}</h1>
+      </div>
+    </div>
+  </body>
+</html>
+          CONTENTS
+        end
+
+        it "should create a documentation style.css" do
+          assert_file "public/docs/#{ver}/style.css", <<-CONTENTS
+body {margin: 0; background-color: #fff; color: #000; font-family: Arial,sans-serif;}
+content {margin-left: 200px;}
+content h1 {text-align: center;}
+operations {float: left; width: 200px; border-right: 1px solid #ccc;}
+operations h3 {text-align: center;}
+          CONTENTS
+        end
+
+        context "multiple versioning strategies" do
+          before :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\nend"}
+            Versionist.configuration.configured_test_framework = nil
+            run_generator %W(#{ver} #{mod} --header=name:Accept value:application/vnd.mycompany.com-#{ver} --parameter=name:version value:#{ver} --path=value:/#{ver})
+          end
+
+          after :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          end
+
+          it "should add all versioning strategies to api_version to config/routes.rb" do
+            assert_file "config/routes.rb"
+            expected = <<-CONTENTS
+Test::Application.routes.draw do
+  api_version(:module => "#{module_name_for_route(mod)}", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-#{ver}"}, :parameter => {:name => "version", :value => "#{ver}"}, :path => {:value => "/#{ver}"}) do
+  end
+
+end
+            CONTENTS
+            # Rails 4 removed the trailing newline from the 'route' generator
+            # https://github.com/rails/rails/commit/7cdb12286639b38db2eb1e9fd0c8b2e6bc3b39dc
+            if Rails::VERSION::MAJOR < 4
+              assert_file "config/routes.rb", expected.chop
+            elsif Rails::VERSION::MAJOR == 4
+              assert_file "config/routes.rb", expected.gsub(/^$\n/, '').chop
+            end
+          end
+        end
+
+        context ":defaults hash" do
+          before :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\nend"}
+            Versionist.configuration.configured_test_framework = nil
+            run_generator %W(#{ver} #{mod} --header=name:Accept value:application/vnd.mycompany.com-#{ver} --defaults=format:json)
+          end
+
+          after :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          end
+
+          it "should add :defaults hash to api_version to config/routes.rb" do
+            assert_file "config/routes.rb"
+            expected = <<-CONTENTS
+Test::Application.routes.draw do
+  api_version(:module => "#{module_name_for_route(mod)}", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-#{ver}"}, :defaults => {:format => "json"}) do
+  end
+
+end
+            CONTENTS
+            # Rails 4 removed the trailing newline from the 'route' generator
+            # https://github.com/rails/rails/commit/7cdb12286639b38db2eb1e9fd0c8b2e6bc3b39dc
+            if Rails::VERSION::MAJOR < 4
+              assert_file "config/routes.rb", expected.chop
+            elsif Rails::VERSION::MAJOR == 4
+              assert_file "config/routes.rb", expected.gsub(/^$\n/, '').chop
+            end
+          end
+        end
+
+        context ":default" do
+          before :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\nend"}
+            Versionist.configuration.configured_test_framework = nil
+            run_generator %W(#{ver} #{mod} --header=name:Accept value:application/vnd.mycompany.com-#{ver} --default)
+          end
+
+          after :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+          end
+
+          it "should add :default to api_version to config/routes.rb" do
+            assert_file "config/routes.rb"
+            expected = <<-CONTENTS
+Test::Application.routes.draw do
+  api_version(:module => "#{module_name_for_route(mod)}", :header => {:name => "Accept", :value => "application/vnd.mycompany.com-#{ver}"}, :default => true) do
+  end
+
+end
+            CONTENTS
+            # Rails 4 removed the trailing newline from the 'route' generator
+            # https://github.com/rails/rails/commit/7cdb12286639b38db2eb1e9fd0c8b2e6bc3b39dc
+            if Rails::VERSION::MAJOR < 4
+              assert_file "config/routes.rb", expected.chop
+            elsif Rails::VERSION::MAJOR == 4
+              assert_file "config/routes.rb", expected.gsub(/^$\n/, '').chop
+            end
+          end
+        end
+
+        context "test_framework: test_unit" do
+          before :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            Versionist.configuration.configured_test_framework = :test_unit
+            run_generator %W(#{ver} #{mod} --header=name:Accept value:application/vnd.mycompany.com-#{ver})
+          end
+
+          it "should create a namespaced test directory" do
+            assert_directory "test/#{test_path}/#{module_name_for_path(mod)}"
+          end
+
+          if older_than_rails_5?
+            it "should create a namespaced base controller test" do
+              assert_file "test/#{test_path}/#{module_name_for_path(mod)}/base_controller_test.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::BaseControllerTest < ActionController::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              CONTENTS
+            end
+          else
+            it "should create a namespaced base controller test" do
+              assert_file "test/#{test_path}/#{module_name_for_path(mod)}/base_controller_test_rails_5.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::BaseControllerTest < ActionDispatch::IntegrationTest
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              CONTENTS
+            end
+          end
+
+          if older_than_rails_5?
+            it "should create a namespaced base controller integration test" do
+              assert_file "test/integration/#{module_name_for_path(mod)}/base_controller_test.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::BaseControllerTest < ActionDispatch::IntegrationTest
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              CONTENTS
+            end
+          end
+
+          it "should create a namespaced test/presenters directory" do
+            assert_directory "test/presenters/#{module_name_for_path(mod)}"
+          end
+
+          if older_than_rails_5?
+            it "should create a namespaced base presenter test" do
+              assert_file "test/presenters/#{module_name_for_path(mod)}/base_presenter_test.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::BasePresenterTest < Test::Unit::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              CONTENTS
+            end
+          else
+            it "should create a namespaced base presenter test" do
+              assert_file "test/presenters/#{module_name_for_path(mod)}/base_presenter_test_rails_5.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::BasePresenterTest < ActiveSupport::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              CONTENTS
+            end
+          end
+
+          it "should create a namespaced test/helpers directory" do
+            assert_directory "test/helpers/#{module_name_for_path(mod)}"
+          end
+        end
+
+        context "test_framework: rspec" do
+          before :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            Versionist.configuration.configured_test_framework = :rspec
+          end
+
+          context "directories" do
+            before :each do
+              run_generator %W(#{ver} #{mod} --header=name:Accept value:application/vnd.mycompany.com-#{ver})
+            end
+
+            it "should create a namespaced spec/controllers directory" do
+              assert_directory "spec/controllers/#{module_name_for_path(mod)}"
+            end
+
+            it "should create a namespaced spec/presenters directory" do
+              assert_directory "spec/presenters/#{module_name_for_path(mod)}"
+            end
+
+            it "should create a namespaced spec/helpers directory" do
+              assert_directory "spec/helpers/#{module_name_for_path(mod)}"
+            end
+          end
+
+          context "rspec < 3" do
+            before :each do
+              run_generator %W(#{ver} #{mod} --header=name:Accept value:application/vnd.mycompany.com-#{ver})
+            end
+
+            it "should create a namespaced base request spec" do
+              assert_file "spec/requests/#{module_name_for_path(mod)}/base_controller_spec.rb", <<-CONTENTS
+require 'spec_helper'
+
+describe #{mod}::BaseController do
+
+end
+              CONTENTS
+            end
+
+            it "should create a namespaced base controller spec" do
+              assert_file "spec/controllers/#{module_name_for_path(mod)}/base_controller_spec.rb", <<-CONTENTS
+require 'spec_helper'
+
+describe #{mod}::BaseController do
+
+end
+              CONTENTS
+            end
+
+            it "should create a namespaced base presenter spec" do
+              assert_file "spec/presenters/#{module_name_for_path(mod)}/base_presenter_spec.rb", <<-CONTENTS
+require 'spec_helper'
+
+describe #{mod}::BasePresenter do
+
+end
+              CONTENTS
+            end
+          end
+
+          context "rspec >= 3" do
+            before :each do
+              ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec", __FILE__))
+              ::FileUtils.touch(::File.expand_path("../../tmp/spec/rails_helper.rb", __FILE__))
+              run_generator %W(#{ver} #{mod} --header=name:Accept value:application/vnd.mycompany.com-#{ver})
+            end
+
+            after :each do
+              ::FileUtils.rm(::File.expand_path("../../tmp/spec/rails_helper.rb", __FILE__))
+            end
+
+            it "should create a namespaced base request spec" do
+              assert_file "spec/requests/#{module_name_for_path(mod)}/base_controller_spec.rb", <<-CONTENTS
+require 'rails_helper'
+
+describe #{mod}::BaseController do
+
+end
+              CONTENTS
+            end
+
+            it "should create a namespaced base controller spec" do
+              assert_file "spec/controllers/#{module_name_for_path(mod)}/base_controller_spec.rb", <<-CONTENTS
+require 'rails_helper'
+
+describe #{mod}::BaseController do
+
+end
+              CONTENTS
+            end
+
+            it "should create a namespaced base presenter spec" do
+              assert_file "spec/presenters/#{module_name_for_path(mod)}/base_presenter_spec.rb", <<-CONTENTS
+require 'rails_helper'
+
+describe #{mod}::BasePresenter do
+
+end
+              CONTENTS
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/spec/generators/new_controller_generator_spec.rb b/spec/generators/new_controller_generator_spec.rb
new file mode 100644
index 0000000..c7b7b59
--- /dev/null
+++ b/spec/generators/new_controller_generator_spec.rb
@@ -0,0 +1,265 @@
+require 'spec_helper'
+require 'generator_spec/test_case'
+
+describe Versionist::NewControllerGenerator do
+  include GeneratorSpec::TestCase
+  include Versionist::InflectorFixes
+
+  destination File.expand_path("../../tmp", __FILE__)
+
+  before :each do
+    prepare_destination
+    ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers", __FILE__))
+    ::Dir.mkdir(::File.expand_path("../../tmp/config", __FILE__))
+    ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+  end
+
+  context "controller" do
+    context "api version doesn't exist" do
+      it "should raise an error if the api version doesn't exist yet" do
+        lambda {
+          run_generator %w(v1 V1)
+        }.should raise_error(RuntimeError, /API module namespace V1 doesn't exist. Please run \'rails generate versionist:new_api_version\' generator first/)
+      end
+    end
+
+    context "ruby hash syntaxes" do
+      context "< 1.9" do
+        it "should not raise an error if api version exists" do
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path("V1")}", __FILE__))
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route("V1")}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+          Versionist.configuration.configured_test_framework = nil
+          lambda {
+            run_generator ["foo", "V1"]
+          }.should_not raise_error#(RuntimeError, /API version doesn't exist in config\/routes.rb. Please run \'rails generate versionist:new_api_version\' generator first/)
+        end
+      end
+
+      context ">= 1.9" do
+        it "should not raise an error if api version exists" do
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path("V1")}", __FILE__))
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(module: \"#{module_name_for_route("V1")}\", header: \"Accept\", value: \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+          Versionist.configuration.configured_test_framework = nil
+          lambda {
+            run_generator ["foo", "V1"]
+          }.should_not raise_error#(RuntimeError, /API version doesn't exist in config\/routes.rb. Please run \'rails generate versionist:new_api_version\' generator first/)
+        end
+      end
+    end
+
+    context "api version exists" do
+      {"foo" => "V1", "bar" => "V2", "foos" => "V2_1", "bazs" => "Api::V3"}.each do |name, mod|
+        context "#{name} => #{mod}" do
+          before :each do
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+            Versionist.configuration.configured_test_framework = nil
+            run_generator [name, mod]
+          end
+
+          it "should create a namespaced controller" do
+            assert_directory "app/controllers/#{module_name_for_path(mod)}"
+            assert_file "app/controllers/#{module_name_for_path(mod)}/#{name.underscore}_controller.rb", "class #{mod}::#{name.camelize}Controller < #{mod}::BaseController\nend\n"
+          end
+
+          context "test_framework: test_unit" do
+            before :each do
+              ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+              ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+              ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+              Versionist.configuration.configured_test_framework = :test_unit
+              run_generator [name, mod]
+            end
+
+            it "should create a namespaced test directory" do
+              assert_directory "test/#{test_path}/#{module_name_for_path(mod)}"
+            end
+
+            if older_than_rails_5?
+              it "should create a namespaced controller test" do
+                assert_file "test/#{test_path}/#{module_name_for_path(mod)}/#{name.underscore}_controller_test.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::#{name.camelize}ControllerTest < ActionController::TestCase
+
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+                CONTENTS
+              end
+            else
+              it "should create a namespaced controller test" do
+                assert_file "test/#{test_path}/#{module_name_for_path(mod)}/#{name.underscore}_controller_test_rails_5.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::#{name.camelize}ControllerTest < ActionDispatch::IntegrationTest
+
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+                CONTENTS
+              end
+            end
+
+            if older_than_rails_5?
+              it "should create a namespaced test/integration directory" do
+                assert_directory "test/integration/#{module_name_for_path(mod)}"
+              end
+
+              it "should create a namespaced controller integration test" do
+                assert_file "test/integration/#{module_name_for_path(mod)}/#{name.underscore}_controller_test.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::#{name.camelize}ControllerTest < ActionDispatch::IntegrationTest
+
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+                CONTENTS
+              end
+            end
+          end
+
+          context "test_framework: rspec" do
+            before :each do
+              ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+              ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+              ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+              Versionist.configuration.configured_test_framework = :rspec
+            end
+
+            context "directories" do
+              before :each do
+                run_generator [name, mod]
+              end
+
+              it "should create a namespaced spec/controllers directory" do
+                assert_directory "spec/controllers/#{module_name_for_path(mod)}"
+              end
+
+              it "should create a namespaced spec/requests directory" do
+                assert_directory "spec/requests/#{module_name_for_path(mod)}"
+              end
+            end
+
+            context "rspec < 3" do
+              before :each do
+                run_generator [name, mod]
+              end
+
+              it "should create a namespaced controller spec" do
+                assert_file "spec/controllers/#{module_name_for_path(mod)}/#{name.underscore}_controller_spec.rb", <<-CONTENTS
+require 'spec_helper'
+
+describe #{mod}::#{name.camelize}Controller do
+
+end
+                CONTENTS
+              end
+
+              it "should create a namespaced request spec" do
+                assert_file "spec/requests/#{module_name_for_path(mod)}/#{name.underscore}_controller_spec.rb", <<-CONTENTS
+require 'spec_helper'
+
+describe #{mod}::#{name.camelize}Controller do
+
+end
+                CONTENTS
+              end
+            end
+
+            context "rspec >= 3" do
+              before :each do
+                ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec", __FILE__))
+                ::FileUtils.touch(::File.expand_path("../../tmp/spec/rails_helper.rb", __FILE__))
+                run_generator [name, mod]
+              end
+
+              after :each do
+                ::FileUtils.rm(::File.expand_path("../../tmp/spec/rails_helper.rb", __FILE__))
+              end
+
+              it "should create a namespaced controller spec" do
+                assert_file "spec/controllers/#{module_name_for_path(mod)}/#{name.underscore}_controller_spec.rb", <<-CONTENTS
+require 'rails_helper'
+
+describe #{mod}::#{name.camelize}Controller do
+
+end
+                CONTENTS
+              end
+
+              it "should create a namespaced request spec" do
+                assert_file "spec/requests/#{module_name_for_path(mod)}/#{name.underscore}_controller_spec.rb", <<-CONTENTS
+require 'rails_helper'
+
+describe #{mod}::#{name.camelize}Controller do
+
+end
+                CONTENTS
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+
+  context "routes" do
+    context "api version doesn't exist in config/routes.rb" do
+      before :each do
+        ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/v1", __FILE__))
+        ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\nend"}
+      end
+
+      it "should raise an error" do
+        lambda {
+          run_generator %w(v1 V1)
+        }.should raise_error(RuntimeError, /API version doesn't exist in config\/routes.rb. Please run \'rails generate versionist:new_api_version\' generator first/)
+      end
+    end
+
+    context "api version duplicated in config/routes.rb" do
+      before :each do
+        ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/v1", __FILE__))
+        ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"V1\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\n\n  api_version(:module => \"V1\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+      end
+
+      it "should raise an error" do
+        lambda {
+          run_generator %w(v1 V1)
+        }.should raise_error(RuntimeError, /API version is duplicated in config\/routes.rb/)
+      end
+    end
+
+    context "api version exists" do
+      {"foo" => "V1", "bar" => "V2", "foos" => "V2_1", "bazs" => "Api::V3"}.each do |name, mod|
+        context "#{name} => #{mod}" do
+          before :each do
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/controllers/#{module_name_for_path(mod)}", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+            run_generator [name, mod]
+          end
+
+          it "should add the new resource to the existing scope in routes.rb" do
+            assert_file "config/routes.rb"
+            expected = <<-CONTENTS
+Test::Application.routes.draw do
+  api_version(:module => "#{module_name_for_route(mod)}", :header => "Accept", :value => "application/vnd.mycompany.com-v1") do
+    resources :#{name}
+  end
+end
+            CONTENTS
+            assert_file "config/routes.rb", expected.chop
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/spec/generators/new_presenter_generator_spec.rb b/spec/generators/new_presenter_generator_spec.rb
new file mode 100644
index 0000000..3ac891e
--- /dev/null
+++ b/spec/generators/new_presenter_generator_spec.rb
@@ -0,0 +1,157 @@
+require 'spec_helper'
+require 'generator_spec/test_case'
+
+describe Versionist::NewPresenterGenerator do
+  include GeneratorSpec::TestCase
+  include Versionist::InflectorFixes
+
+  destination File.expand_path("../../tmp", __FILE__)
+
+  before :each do
+    prepare_destination
+    ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters", __FILE__))
+    ::Dir.mkdir(::File.expand_path("../../tmp/config", __FILE__))
+    ::FileUtils.touch(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+  end
+
+  context "api version doesn't exist" do
+    it "should raise an error if the api version doesn't exist yet" do
+      lambda {
+        run_generator %w(v1 V1)
+      }.should raise_error(RuntimeError, /API module namespace V1 doesn't exist. Please run \'rails generate versionist:new_api_version\' generator first/)
+    end
+  end
+
+  context "api version exists" do
+    {"foo" => "V1", "bar" => "V2", "foos" => "V2_1", "bazs" => "Api::V3"}.each do |name, mod|
+      context "#{name} => #{mod}" do
+        before :each do
+          ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+          ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+          Versionist.configuration.configured_test_framework = nil
+          run_generator [name, mod]
+        end
+
+        it "should create a namespaced presenter" do
+          assert_directory "app/presenters/#{module_name_for_path(mod)}"
+          assert_file "app/presenters/#{module_name_for_path(mod)}/#{name.underscore}_presenter.rb", <<-CONTENTS
+class #{mod}::#{name.camelize}Presenter < #{mod}::BasePresenter
+
+  def initialize(#{name})
+    @#{name} = #{name}
+  end
+
+  def as_json(options={})
+    # fill me in...
+  end
+
+  def to_xml(options={}, &block)
+    xml = options[:builder] ||= Builder::XmlMarkup.new
+    # fill me in...
+  end
+end
+          CONTENTS
+        end
+
+        context "test_framework: test_unit" do
+          before :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+            Versionist.configuration.configured_test_framework = :test_unit
+            run_generator [name, mod]
+          end
+
+          it "should create a namespaced test/presenters directory" do
+            assert_directory "test/presenters/#{module_name_for_path(mod)}"
+          end
+
+          if older_than_rails_5?
+            it "should create a namespaced presenter test" do
+              assert_file "test/presenters/#{module_name_for_path(mod)}/#{name.underscore}_presenter_test.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::#{name.camelize}PresenterTest < Test::Unit::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              CONTENTS
+            end
+          else
+            it "should create a namespaced presenter test" do
+              assert_file "test/presenters/#{module_name_for_path(mod)}/#{name.underscore}_presenter_test_rails_5.rb", <<-CONTENTS
+require 'test_helper'
+
+class #{mod}::#{name.camelize}PresenterTest < ActiveSupport::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end
+              CONTENTS
+            end
+          end
+        end
+
+        context "test_framework: rspec" do
+          before :each do
+            ::FileUtils.rm(::File.expand_path("../../tmp/config/routes.rb", __FILE__))
+            ::FileUtils.mkdir_p(::File.expand_path("../../tmp/app/presenters/#{module_name_for_path(mod)}", __FILE__))
+            ::File.open(::File.expand_path("../../tmp/config/routes.rb", __FILE__), "w") {|f| f.write "Test::Application.routes.draw do\n  api_version(:module => \"#{module_name_for_route(mod)}\", :header => \"Accept\", :value => \"application/vnd.mycompany.com-v1\") do\n  end\nend"}
+            Versionist.configuration.configured_test_framework = :rspec
+          end
+
+          context "directories" do
+            before :each do
+              run_generator [name, mod]
+            end
+
+            it "should create a namespaced spec/presenters directory" do
+              assert_directory "spec/presenters/#{module_name_for_path(mod)}"
+            end
+          end
+
+          context "rspec < 3" do
+            before :each do
+              run_generator [name, mod]
+            end
+
+            it "should create a namespaced presenter spec" do
+              assert_file "spec/presenters/#{module_name_for_path(mod)}/#{name.underscore}_presenter_spec.rb", <<-CONTENTS
+require 'spec_helper'
+
+describe #{mod}::#{name.camelize}Presenter do
+
+end
+              CONTENTS
+            end
+          end
+
+          context "rspec >= 3" do
+            before :each do
+              ::FileUtils.mkdir_p(::File.expand_path("../../tmp/spec", __FILE__))
+              ::FileUtils.touch(::File.expand_path("../../tmp/spec/rails_helper.rb", __FILE__))
+              run_generator [name, mod]
+            end
+
+            after :each do
+              ::FileUtils.rm(::File.expand_path("../../tmp/spec/rails_helper.rb", __FILE__))
+            end
+
+            it "should create a namespaced presenter spec" do
+              assert_file "spec/presenters/#{module_name_for_path(mod)}/#{name.underscore}_presenter_spec.rb", <<-CONTENTS
+require 'rails_helper'
+
+describe #{mod}::#{name.camelize}Presenter do
+
+end
+              CONTENTS
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/spec/middleware_spec.rb b/spec/middleware_spec.rb
new file mode 100644
index 0000000..40277be
--- /dev/null
+++ b/spec/middleware_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+require 'rack/test'
+
+describe Versionist::Middleware do
+  before :each do
+    Versionist.configuration.clear!
+    Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com-v2.3.0"}})
+    @app = lambda {|env| [200, {"Content-Type" => "text/plain"}, [env["HTTP_ACCEPT"]]]}
+  end
+
+  after :each do
+    Versionist.configuration.clear!
+  end
+
+  context "Accept header" do
+    it "should not alter the header if the version is not present" do
+      request = Rack::MockRequest.env_for("/foos", "HTTP_ACCEPT" => "application/json", :lint => true, :fatal => true)
+      status, headers, response = described_class.new(@app).call(request)
+      response[0].should == "application/json"
+    end
+
+    it "should not alter the header if an unconfigured version is present" do
+      request = Rack::MockRequest.env_for("/foos", "HTTP_ACCEPT" => "application/vnd.mycompany.com-v1,application/json", :lint => true, :fatal => true)
+      status, headers, response = described_class.new(@app).call(request)
+      response[0].should == "application/vnd.mycompany.com-v1,application/json"
+    end
+
+    it "should move the version to the end" do
+      request = Rack::MockRequest.env_for("/foos", "HTTP_ACCEPT" => "application/vnd.mycompany.com-v2.3.0,application/json", :lint => true, :fatal => true)
+      status, headers, response = described_class.new(@app).call(request)
+      response[0].should == "application/json, application/vnd.mycompany.com-v2.3.0"
+    end
+
+    it "should move the version to the end and retain accept params" do
+      request = Rack::MockRequest.env_for("/foos", "HTTP_ACCEPT" => "audio/*; q=0.2, audio/basic, application/vnd.mycompany.com-v2.3.0, application/json", :lint => true, :fatal => true)
+      status, headers, response = described_class.new(@app).call(request)
+      response[0].should == "audio/*; q=0.2, audio/basic, application/json, application/vnd.mycompany.com-v2.3.0"
+    end
+
+    it "should not alter the header if the accept header is not present" do
+      request = Rack::MockRequest.env_for("/foos", :lint => true, :fatal => true)
+      status, headers, response = described_class.new(@app).call(request)
+      response[0].should be_nil
+    end
+  end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..8b2a267
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,31 @@
+require 'rubygems'
+require 'bundler/setup'
+Bundler.setup(:default, :development) if defined?(Bundler)
+require "action_controller/railtie"
+require 'rspec'
+require 'rspec-rails'
+require 'simplecov'
+SimpleCov.start do
+  add_filter "spec"
+end
+require 'versionist'
+require 'fileutils'
+
+RSpec.configure do |config|
+  config.mock_with :rspec
+
+  config.after :each do
+    # delete spec/tmp/
+    tmp_dir = ::File.expand_path('../tmp', __FILE__)
+    ::FileUtils.rm_rf(tmp_dir)
+  end
+end
+
+def older_than_rails_5?
+  defined?(Rails) && Rails.version.to_i < 5
+end
+
+def test_path
+  return "test/functional" if older_than_rails_5?
+  "test/controllers"
+end
diff --git a/spec/test-api/app/controllers/api/v3/bars_controller.rb b/spec/test-api/app/controllers/api/v3/bars_controller.rb
new file mode 100644
index 0000000..63fb124
--- /dev/null
+++ b/spec/test-api/app/controllers/api/v3/bars_controller.rb
@@ -0,0 +1,9 @@
+class Api::V3::BarsController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v3" }
+      format.json { render :json => "v3" }
+      format.xml { render :xml => "v3" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/api/v3/foos_controller.rb b/spec/test-api/app/controllers/api/v3/foos_controller.rb
new file mode 100644
index 0000000..a36b6a7
--- /dev/null
+++ b/spec/test-api/app/controllers/api/v3/foos_controller.rb
@@ -0,0 +1,9 @@
+class Api::V3::FoosController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v3" }
+      format.json { render :json => "v3" }
+      format.xml { render :xml => "v3" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/application_controller.rb b/spec/test-api/app/controllers/application_controller.rb
new file mode 100644
index 0000000..3a8681f
--- /dev/null
+++ b/spec/test-api/app/controllers/application_controller.rb
@@ -0,0 +1,6 @@
+class ApplicationController < ActionController::Base
+  def not_found
+    # just silence it
+    head :not_found
+  end
+end
diff --git a/spec/test-api/app/controllers/not_default/foos_controller.rb b/spec/test-api/app/controllers/not_default/foos_controller.rb
new file mode 100644
index 0000000..c4e27db
--- /dev/null
+++ b/spec/test-api/app/controllers/not_default/foos_controller.rb
@@ -0,0 +1,9 @@
+class NotDefault::FoosController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "not_default" }
+      format.json { render :json => "not_default" }
+      format.xml { render :xml => "not_default" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/v1/bars_controller.rb b/spec/test-api/app/controllers/v1/bars_controller.rb
new file mode 100644
index 0000000..b8effa7
--- /dev/null
+++ b/spec/test-api/app/controllers/v1/bars_controller.rb
@@ -0,0 +1,9 @@
+class V1::BarsController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v1" }
+      format.json { render :json => "v1" }
+      format.xml { render :xml => "v1" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/v1/foos_controller.rb b/spec/test-api/app/controllers/v1/foos_controller.rb
new file mode 100644
index 0000000..547f7e1
--- /dev/null
+++ b/spec/test-api/app/controllers/v1/foos_controller.rb
@@ -0,0 +1,9 @@
+class V1::FoosController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v1" }
+      format.json { render :json => "v1" }
+      format.xml { render :xml => "v1" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/v11/bars_controller.rb b/spec/test-api/app/controllers/v11/bars_controller.rb
new file mode 100644
index 0000000..b1e6e1c
--- /dev/null
+++ b/spec/test-api/app/controllers/v11/bars_controller.rb
@@ -0,0 +1,5 @@
+class V11::BarsController < ApplicationController
+  def index
+    render :text => "v11"
+  end
+end
diff --git a/spec/test-api/app/controllers/v11/foos_controller.rb b/spec/test-api/app/controllers/v11/foos_controller.rb
new file mode 100644
index 0000000..e5f3ab6
--- /dev/null
+++ b/spec/test-api/app/controllers/v11/foos_controller.rb
@@ -0,0 +1,9 @@
+class V11::FoosController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v11" }
+      format.json { render :json => "v11" }
+      format.xml { render :xml => "v11" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/v2/bars_controller.rb b/spec/test-api/app/controllers/v2/bars_controller.rb
new file mode 100644
index 0000000..e4178e1
--- /dev/null
+++ b/spec/test-api/app/controllers/v2/bars_controller.rb
@@ -0,0 +1,9 @@
+class V2::BarsController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v2" }
+      format.json { render :json => "v2" }
+      format.xml { render :xml => "v2" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/v2/foos_controller.rb b/spec/test-api/app/controllers/v2/foos_controller.rb
new file mode 100644
index 0000000..1bbc2ad
--- /dev/null
+++ b/spec/test-api/app/controllers/v2/foos_controller.rb
@@ -0,0 +1,9 @@
+class V2::FoosController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v2" }
+      format.json { render :json => "v2" }
+      format.xml { render :xml => "v2" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/v2_1/bars_controller.rb b/spec/test-api/app/controllers/v2_1/bars_controller.rb
new file mode 100644
index 0000000..4b32337
--- /dev/null
+++ b/spec/test-api/app/controllers/v2_1/bars_controller.rb
@@ -0,0 +1,9 @@
+class V2_1::BarsController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v2.1" }
+      format.json { render :json => "v2.1" }
+      format.xml { render :xml => "v2.1" }
+    end
+  end
+end
diff --git a/spec/test-api/app/controllers/v2_1/foos_controller.rb b/spec/test-api/app/controllers/v2_1/foos_controller.rb
new file mode 100644
index 0000000..6713fd2
--- /dev/null
+++ b/spec/test-api/app/controllers/v2_1/foos_controller.rb
@@ -0,0 +1,9 @@
+class V2_1::FoosController < ApplicationController
+  def index
+    respond_to do |format|
+      format.text { render :text => "v2.1" }
+      format.json { render :json => "v2.1" }
+      format.xml { render :xml => "v2.1" }
+    end
+  end
+end
diff --git a/spec/test-api/config/application.rb b/spec/test-api/config/application.rb
new file mode 100644
index 0000000..0e6ada3
--- /dev/null
+++ b/spec/test-api/config/application.rb
@@ -0,0 +1,18 @@
+require "action_controller/railtie"
+require 'versionist/railtie'
+
+module TestApi
+  class Application < Rails::Application
+    config.secret_token = "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!hi mom!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+    config.secret_key_base = "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!hi mom!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+    config.eager_load = true
+    config.root = File.expand_path("../../", __FILE__)
+    config.active_support.deprecation = :log
+    config.action_controller.logger = nil
+    config.logger = Logger.new(STDOUT)
+    config.log_level = :info
+    config.action_controller.logger = nil
+    config.middleware.delete Rails::Rack::Logger
+    config.action_dispatch.show_exceptions = false
+  end
+end
diff --git a/spec/versioning_strategy/base_spec.rb b/spec/versioning_strategy/base_spec.rb
new file mode 100644
index 0000000..1600e10
--- /dev/null
+++ b/spec/versioning_strategy/base_spec.rb
@@ -0,0 +1,77 @@
+require 'spec_helper'
+
+describe Versionist::VersioningStrategy::Base do
+  after :each do
+    Versionist.configuration.clear!
+  end
+  
+  it "should raise an error when config nil" do
+    lambda {
+      Versionist::VersioningStrategy::Base.new(nil)
+    }.should raise_error(ArgumentError, /you must pass a configuration Hash/)
+  end
+
+  it "should raise an error when config is not a Hash" do
+    lambda {
+      Versionist::VersioningStrategy::Base.new(1)
+    }.should raise_error(ArgumentError, /you must pass a configuration Hash/)
+  end
+
+  it "should set attributes" do
+    @base = Versionist::VersioningStrategy::Base.new({})
+    @base.config.should == {}
+
+    @base2 = Versionist::VersioningStrategy::Base.new({"module" => "V1"})
+    # symbolize_keys! should be called
+    @base2.config.should_not == {"module" => "V1"}
+    @base2.config.should == {:module => "V1"}
+  end
+
+  it "should add self to Versionist::Configuration.versioning_strategies" do
+    Versionist.configuration.versioning_strategies.should be_empty
+    Versionist::VersioningStrategy::Base.new({})
+    Versionist.configuration.versioning_strategies.should_not be_empty
+    Versionist.configuration.versioning_strategies.size.should == 1
+  end
+
+  it "should not add self to Versionist::Configuration.versioning_strategies more than once" do
+    Versionist.configuration.versioning_strategies.should be_empty
+    Versionist::VersioningStrategy::Base.new({})
+    Versionist.configuration.versioning_strategies.should_not be_empty
+    Versionist.configuration.versioning_strategies.size.should == 1
+    Versionist::VersioningStrategy::Base.new({})
+    Versionist.configuration.versioning_strategies.should_not be_empty
+    Versionist.configuration.versioning_strategies.size.should == 1
+  end
+
+  context "==" do
+    before :each do
+      @base = Versionist::VersioningStrategy::Base.new({:default => false})
+      @equal_base = Versionist::VersioningStrategy::Base.new({:default => false})
+    end
+
+    it "should return true if passed an equal object" do
+      (@base == @equal_base).should == true
+    end
+
+    it "should return false if passed nil" do
+      (@base == nil).should == false
+    end
+
+    it "should return false if passed an object that's not a Versionist::VersioningStrategy::Base" do
+      (@base == Array.new).should == false
+    end
+
+    it "should return false if passed an object that's not equal" do
+      @unequal_base = Versionist::VersioningStrategy::Base.new({})
+      (@base == @unequal_base).should == false
+    end
+
+    it "should find equal versioning strategies via Array.include?" do
+      @array = Array.new
+      @array << @base
+      @array.include?(@base).should == true
+      @array.include?(@equal_base).should == true
+    end
+  end
+end
diff --git a/spec/versioning_strategy/default_spec.rb b/spec/versioning_strategy/default_spec.rb
new file mode 100644
index 0000000..63459e1
--- /dev/null
+++ b/spec/versioning_strategy/default_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+describe Versionist::VersioningStrategy::Default do
+  before :each do
+    Versionist.configuration.clear!
+  end
+
+  after :each do
+    Versionist.configuration.clear!
+  end
+
+  it "should set attributes" do
+    @default = Versionist::VersioningStrategy::Default.new({:module => "V1", :header => {:name => "Accept", :value => "v1"}})
+    @default.module.should == "V1"
+    Versionist.configuration.default_version.should_not be_nil
+    Versionist.configuration.default_version.should == @default
+  end
+
+  it "should raise an error when attempting to set more than one :default version" do
+    Versionist.configuration.default_version.should be_nil
+    Versionist::VersioningStrategy::Default.new({:module => "V1", :default => true, :path => "foo"})
+    Versionist.configuration.default_version.should_not be_nil
+    lambda {
+      Versionist::VersioningStrategy::Default.new({:module => "V2", :default => true, :path => "bar"})
+    }.should raise_error(ArgumentError, /attempt to set more than one default api version/)
+  end
+
+  context "==" do
+    before :each do
+      @header = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}})
+      @equal_header = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}})
+    end
+
+    it "should return true if passed an equal object" do
+      (@header == @equal_header).should == true
+    end
+
+    it "should return false if passed an object that's not a Versionist::VersioningStrategy::Header" do
+      (@header == Array.new).should == false
+    end
+
+    it "should return false if passed an object that's not equal" do
+      @unequal_header = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=2"}})
+      (@header == @unequal_header).should == false
+    end
+
+    it "should find equal versioning strategies via Array.include?" do
+      @array = Array.new
+      @array << @header
+      @array.include?(@header).should == true
+      @array.include?(@equal_header).should == true
+    end
+  end
+end
diff --git a/spec/versioning_strategy/header_spec.rb b/spec/versioning_strategy/header_spec.rb
new file mode 100644
index 0000000..4c11517
--- /dev/null
+++ b/spec/versioning_strategy/header_spec.rb
@@ -0,0 +1,73 @@
+require 'spec_helper'
+
+describe Versionist::VersioningStrategy::Header do
+  before :each do
+    Versionist.configuration.clear!
+  end
+
+  after :each do
+    Versionist.configuration.clear!
+  end
+
+  it "should raise an ArgumentError if :name is not specified" do
+    lambda {
+      Versionist::VersioningStrategy::Header.new({:header => {:foo => "foo"}})
+    }.should raise_error(ArgumentError, /you must specify :name in the :header configuration Hash/)
+  end
+ 
+  it "should raise an ArgumentError if :value is not specified" do
+    lambda {
+      Versionist::VersioningStrategy::Header.new({:header => {:name => "foo"}})
+    }.should raise_error(ArgumentError, /you must specify :value in the :header configuration Hash/)
+  end
+
+  it "should raise an ArgumentError if :name is version" do
+    lambda {
+      Versionist::VersioningStrategy::Header.new({:header => {:name => "version", :value => "1"}})
+    }.should raise_error(ArgumentError, /a header :name of 'version' will clash with the built in rack header "HTTP_VERSION". You must use a different header name/)
+  end
+
+  it "should add the version to Versionist::Configuration.header_versions" do
+    Versionist.configuration.header_versions.should be_empty
+    header_version = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com-v2"}})
+    Versionist.configuration.header_versions.include?(header_version).should == true
+  end
+
+  it "should not add self to Versionist::Configuration.header_versions more than once" do
+    Versionist.configuration.header_versions.should be_empty
+    header_version = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com-v2"}})
+    Versionist.configuration.header_versions.should_not be_empty
+    Versionist.configuration.header_versions.size.should == 1
+
+    header_version2 = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com-v2"}})
+    Versionist.configuration.header_versions.should_not be_empty
+    Versionist.configuration.header_versions.size.should == 1
+  end
+
+  context "==" do
+    before :each do
+      @header = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}})
+      @equal_header = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}})
+    end
+
+    it "should return true if passed an equal object" do
+      (@header == @equal_header).should == true
+    end
+
+    it "should return false if passed an object that's not a Versionist::VersioningStrategy::Header" do
+      (@header == Array.new).should == false
+    end
+
+    it "should return false if passed an object that's not equal" do
+      @unequal_header = Versionist::VersioningStrategy::Header.new({:header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=2"}})
+      (@header == @unequal_header).should == false
+    end
+
+    it "should find equal versioning strategies via Array.include?" do
+      @array = Array.new
+      @array << @header
+      @array.include?(@header).should == true
+      @array.include?(@equal_header).should == true
+    end
+  end
+end
diff --git a/spec/versioning_strategy/parameter_spec.rb b/spec/versioning_strategy/parameter_spec.rb
new file mode 100644
index 0000000..5900b73
--- /dev/null
+++ b/spec/versioning_strategy/parameter_spec.rb
@@ -0,0 +1,67 @@
+require 'spec_helper'
+
+describe Versionist::VersioningStrategy::Parameter do
+  before :each do
+    Versionist.configuration.clear!
+  end
+
+  after :each do
+    Versionist.configuration.clear!
+  end
+
+  it "should raise an ArgumentError if :name is not specified" do
+    lambda {
+      Versionist::VersioningStrategy::Parameter.new({:parameter => {:value => "v1"}})
+    }.should raise_error(ArgumentError, /you must specify :name in the :parameter configuration Hash/)
+  end
+
+  it "should raise an ArgumentError if :value is not specified" do
+    lambda {
+      Versionist::VersioningStrategy::Parameter.new({:parameter => {:name => "version"}})
+    }.should raise_error(ArgumentError, /you must specify :value in the :parameter configuration Hash/)
+  end
+
+  it "should add the version to Versionist::Configuration.parameter_versions" do
+    Versionist.configuration.parameter_versions.should be_empty
+    parmeter_version = Versionist::VersioningStrategy::Parameter.new({:parameter => {:name => "version", :value => "3"}})
+    Versionist.configuration.parameter_versions.include?(parmeter_version).should == true
+  end
+
+  it "should not add self to Versionist::Configuration.parameter_versions more than once" do
+    Versionist.configuration.parameter_versions.should be_empty
+    parameter_version = Versionist::VersioningStrategy::Parameter.new({:parameter => {:name => "version", :value => "v2"}})
+    Versionist.configuration.parameter_versions.should_not be_empty
+    Versionist.configuration.parameter_versions.size.should == 1
+
+    parameter_version2 = Versionist::VersioningStrategy::Parameter.new({:parameter => {:name => "version", :value => "v2"}})
+    Versionist.configuration.parameter_versions.should_not be_empty
+    Versionist.configuration.parameter_versions.size.should == 1
+  end
+
+  context "==" do
+    before :each do
+      @parameter = Versionist::VersioningStrategy::Parameter.new({:parameter => {:name => "version", :value => "1"}})
+      @equal_parameter = Versionist::VersioningStrategy::Parameter.new({:parameter => {:name => "version", :value => "1"}})
+    end
+
+    it "should return true if passed an equal object" do
+      (@parameter == @equal_parameter).should == true
+    end
+
+    it "should return false if passed an object that's not a Versionist::VersioningStrategy::Parameter" do
+      (@parameter == Array.new).should == false
+    end
+
+    it "should return false if passed an object that's not equal" do
+      @unequal_parameter = Versionist::VersioningStrategy::Parameter.new({:parameter => {:name => "ver", :value => "1"}})
+      (@parameter == @unequal_parameter).should == false
+    end
+
+    it "should find equal versioning strategies via Array.include?" do
+      @array = Array.new
+      @array << @parameter
+      @array.include?(@parameter).should == true
+      @array.include?(@equal_parameter).should == true
+    end
+  end
+end
diff --git a/spec/versioning_strategy/path_spec.rb b/spec/versioning_strategy/path_spec.rb
new file mode 100644
index 0000000..02dd1b8
--- /dev/null
+++ b/spec/versioning_strategy/path_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Versionist::VersioningStrategy::Path do
+  before :each do
+    Versionist.configuration.clear!
+  end
+
+  after :each do
+    Versionist.configuration.clear!
+  end
+
+  it "should raise an ArgumentError if :value is not specified" do
+    lambda {
+      Versionist::VersioningStrategy::Path.new({:path => {}})
+    }.should raise_error(ArgumentError, /you must specify :value in the :path configuration Hash/)
+  end
+
+  it "should add the version to Versionist::Configuration.path_versions" do
+    Versionist.configuration.path_versions.should be_empty
+    path_version = Versionist::VersioningStrategy::Path.new({:path => {:value => "v1"}})
+    Versionist.configuration.path_versions.include?(path_version).should == true
+  end
+
+  context "==" do
+    before :each do
+      @path = Versionist::VersioningStrategy::Path.new({:path => {:value => "/v1"}})
+      @equal_path = Versionist::VersioningStrategy::Path.new({:path => {:value => "/v1"}})
+    end
+
+    it "should return true if passed an equal object" do
+      (@path == @equal_path).should == true
+    end
+
+    it "should return false if passed an object that's not a Versionist::VersioningStrategy::Path" do
+      (@path == Array.new).should == false
+    end
+
+    it "should return false if passed an object that's not equal" do
+      @unequal_path = Versionist::VersioningStrategy::Path.new({:path => {:value => "v2"}})
+      (@path == @unequal_path).should == false
+    end
+
+    it "should find equal versioning strategies via Array.include?" do
+      @array = Array.new
+      @array << @path
+      @array.include?(@path).should == true
+      @array.include?(@equal_path).should == true
+    end
+  end
+end
diff --git a/versionist.gemspec b/versionist.gemspec
index 364d409..866ec00 100644
--- a/versionist.gemspec
+++ b/versionist.gemspec
@@ -1,40 +1,26 @@
-#########################################################
-# This file has been automatically generated by gem2tgz #
-#########################################################
 # -*- encoding: utf-8 -*-
-# stub: versionist 2.0.1 ruby lib
 
-Gem::Specification.new do |s|
-  s.name = "versionist".freeze
-  s.version = "2.0.1"
+lib = File.expand_path('../lib/', __FILE__)
+$:.unshift lib unless $:.include?(lib)
+
+require 'versionist/version'
 
-  s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6".freeze) if s.respond_to? :required_rubygems_version=
-  s.require_paths = ["lib".freeze]
-  s.authors = ["Brian Ploetz".freeze]
-  s.date = "2019-07-22"
-  s.description = "A plugin for versioning Rails based RESTful APIs.".freeze
-  s.files = ["lib/generators/versionist/copy_api_version/USAGE".freeze, "lib/generators/versionist/copy_api_version/copy_api_version_generator.rb".freeze, "lib/generators/versionist/inflector_fixes.rb".freeze, "lib/generators/versionist/new_api_version/USAGE".freeze, "lib/generators/versionist/new_api_version/new_api_version_generator.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller_functional_test.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller_functional_test_rails_5.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller_integration_test.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller_spec.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_presenter.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_presenter_spec.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_presenter_test.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_presenter_test_rails_5.rb".freeze, "lib/generators/versionist/new_api_version/templates/docs_index.rb".freeze, "lib/generators/versionist/new_api_version/templates/docs_style.rb".freeze, "lib/generators/versionist/new_controller/USAGE".freeze, "lib/generators/versionist/new_controller/new_controller_generator.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller_functional_test.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller_functional_test_rails_5.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller_integration_test.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller_spec.rb".freeze, "lib/generators/versionist/new_presenter/USAGE".freeze, "lib/generators/versionist/new_presenter/new_presenter_generator.rb".freeze, "lib/generators/versionist/new_presenter/templates/new_presenter.rb".freeze, "lib/generators/versionist/new_presenter/templates/new_presenter_spec.rb".freeze, "lib/generators/versionist/new_presenter/templates/new_presenter_test.rb".freeze, "lib/generators/versionist/new_presenter/templates/new_presenter_test_rails_5.rb".freeze, "lib/generators/versionist/rspec_helper.rb".freeze, "lib/versionist.rb".freeze, "lib/versionist/configuration.rb".freeze, "lib/versionist/middleware.rb".freeze, "lib/versionist/railtie.rb".freeze, "lib/versionist/routing.rb".freeze, "lib/versionist/version.rb".freeze, "lib/versionist/versioning_strategy.rb".freeze, "lib/versionist/versioning_strategy/base.rb".freeze, "lib/versionist/versioning_strategy/default.rb".freeze, "lib/versionist/versioning_strategy/header.rb".freeze, "lib/versionist/versioning_strategy/parameter.rb".freeze, "lib/versionist/versioning_strategy/path.rb".freeze]
-  s.homepage = "https://github.com/bploetz/versionist".freeze
-  s.licenses = ["MIT".freeze]
-  s.rdoc_options = ["--charset=UTF-8".freeze]
-  s.rubygems_version = "2.5.2.1".freeze
-  s.summary = "versionist-2.0.1".freeze
+Gem::Specification.new do |s|
+  s.name = 'versionist'
+  s.homepage = 'https://github.com/bploetz/versionist'
+  s.version = Versionist::VERSION
+  s.platform = Gem::Platform::RUBY
+  s.authors = ['Brian Ploetz']
+  s.summary = "versionist-#{Versionist::VERSION}"
+  s.description = 'A plugin for versioning Rails based RESTful APIs.'
+  s.license = 'MIT'
+  s.files = Dir['lib/**/*']
+  s.rdoc_options = ['--charset=UTF-8']
+  s.require_paths = ['lib']
+  s.required_rubygems_version = '>= 1.3.6'
 
-  if s.respond_to? :specification_version then
-    s.specification_version = 4
+  s.add_dependency 'railties', '>= 3'
+  s.add_dependency 'activesupport', '>= 3'
 
-    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
-      s.add_runtime_dependency(%q<activesupport>.freeze, [">= 3"])
-      s.add_runtime_dependency(%q<railties>.freeze, [">= 3"])
-      s.add_runtime_dependency(%q<yard>.freeze, ["~> 0.9.20"])
-    else
-      s.add_dependency(%q<activesupport>.freeze, [">= 3"])
-      s.add_dependency(%q<railties>.freeze, [">= 3"])
-      s.add_dependency(%q<yard>.freeze, ["~> 0.9.20"])
-    end
-  else
-    s.add_dependency(%q<activesupport>.freeze, [">= 3"])
-    s.add_dependency(%q<railties>.freeze, [">= 3"])
-    s.add_dependency(%q<yard>.freeze, ["~> 0.9.20"])
-  end
+  s.add_dependency('yard', "~> 0.9.20")
 end

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details