Permalink
Browse files

Issue #5: Support for Rails' :defaults hash

  • Loading branch information...
1 parent b092a80 commit a66773a2c407aceddcbe8ed931b91ce7876727de Brian Ploetz committed Apr 24, 2012
Showing with 103 additions and 4 deletions.
  1. +19 −0 README.markdown
  2. +11 −4 lib/versionist/routing.rb
  3. +73 −0 spec/api_routing_spec.rb
View
@@ -138,6 +138,25 @@ end
If you attempt to specify more than one default version, an error will be thrown at startup.
+### 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 => "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
+```
+
+
## Version/Module Naming Convention Gotcha
Note that if your public facing version naming convention uses dots (i.e. v1.2.3), your module names cannot use dots, as you obviously cannot use dots in module names in Ruby.
View
@@ -12,6 +12,7 @@ def api_version(config, &block)
raise ArgumentError, "you must pass a configuration Hash to api_version" if config.nil? || !config.is_a?(Hash)
raise ArgumentError, "you must specify :module in configuration Hash passed to api_version" if !config.has_key?(:module)
raise ArgumentError, "you must specify :header, :path, or :parameter in configuration Hash passed to api_version" if !config.has_key?(:header) && !config.has_key?(:path) && !config.has_key?(:parameter)
+ raise ArgumentError, ":defaults must be a Hash" if config.has_key?(:defaults) && !config[:defaults].is_a?(Hash)
if config.has_key?(:header)
return configure_header(config, &block)
elsif config.has_key?(:path)
@@ -26,22 +27,28 @@ def api_version(config, &block)
def configure_header(config, &block)
header = Versionist::VersioningStrategy::Header.new(config)
- scope({:module => config[:module], :constraints => header}, &block)
+ route_hash = {:module => config[:module], :constraints => header}
+ route_hash.merge!({:defaults => config[:defaults]}) if config.has_key?(:defaults)
+ scope(route_hash, &block)
end
def configure_path(config, &block)
path = Versionist::VersioningStrategy::Path.new(config)
# Use the :as option and strip out non-word characters from the path to avoid this:
# https://github.com/rails/rails/issues/3224
- namespace(config[:path], {:module => config[:module], :as => config[:path].gsub(/\W/, '_')}, &block)
+ route_hash = {:module => config[:module], :as => config[:path].gsub(/\W/, '_')}
+ route_hash.merge!({:defaults => config[:defaults]}) if config.has_key?(:defaults)
+ namespace(config[:path], route_hash, &block)
if path.default?
- scope({:module => config[:module], :as => config[:path].gsub(/\W/, '_')}, &block)
+ scope(route_hash, &block)
end
end
def configure_parameter(config, &block)
parameter = Versionist::VersioningStrategy::Parameter.new(config)
- scope({:module => config[:module], :constraints => parameter}, &block)
+ route_hash = {:module => config[:module], :constraints => parameter}
+ route_hash.merge!({:defaults => config[:defaults]}) if config.has_key?(:defaults)
+ scope(route_hash, &block)
end
end
end
View
@@ -48,6 +48,15 @@
}.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 config contains a :defaults key which isn't a Hash" do
+ lambda {
+ TestApi::Application.routes.draw do
+ api_version({:module => "v1", :header => "Accept", :value => "application/vnd.mycompany.com-v1", :defaults => 1}) do
+ end
+ 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 => "Accept", :value => "application/vnd.mycompany.com-v1"}) do
@@ -166,6 +175,19 @@
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 => "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 "custom header" do
@@ -260,6 +282,19 @@
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 => "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
@@ -343,6 +378,31 @@
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 => "/#{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 => "/#{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
@@ -425,6 +485,19 @@
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 => "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
end

0 comments on commit a66773a

Please sign in to comment.