api-versions 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +14 -0
- data/Gemfile +1 -0
- data/README.md +18 -17
- data/Rakefile +8 -0
- data/api-versions.gemspec +1 -0
- data/lib/api-versions.rb +11 -17
- data/lib/api-versions/version.rb +1 -1
- data/spec/dummy/.rspec +1 -0
- data/spec/dummy/app/controllers/api/v1/bar_controller.rb +2 -0
- data/spec/dummy/app/controllers/api/v2/bar_controller.rb +5 -0
- data/spec/dummy/app/controllers/api/v2/foo_controller.rb +2 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +54 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/test.rb +29 -0
- data/spec/dummy/config/routes.rb +25 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/routing/routing_spec.rb +92 -0
- data/spec/spec_helper.rb +23 -0
- metadata +50 -5
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,29 +1,30 @@
|
|
1
|
-
API-Versions
|
2
|
-
|
1
|
+
API-Versions [![Build Status](https://secure.travis-ci.org/erichmenge/api-versions.png)](http://travis-ci.org/erichmenge/api-versions)
|
2
|
+
======================================================================================================================================
|
3
|
+
|
3
4
|
If you have multiple versions of an API in your Rails app, it is not very DRY to include the same resources over and over again.
|
4
5
|
In your Gemfile:
|
5
6
|
|
6
7
|
gem "api-versions", "~> 0.0.4"
|
7
|
-
|
8
|
+
|
8
9
|
In your routes.rb file:
|
9
10
|
|
10
11
|
namespace :api do
|
11
12
|
default_api_version 1 # If no API version is specified in the Accept header, this is what will be used.
|
12
13
|
api_vendor "myvendor" # For HTTP Accept Header application/vnd.myvendor+json;version=1
|
13
|
-
|
14
|
+
|
14
15
|
constraints api_version_check(:version => 1) do
|
15
|
-
scope :module => :v1 do
|
16
|
+
scope :module => :v1 do
|
16
17
|
cache_resources :as => :v1 do
|
17
|
-
resources :authorizations
|
18
|
+
resources :authorizations
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
21
|
-
|
22
|
+
|
22
23
|
constraints api_version_check(:version => 2) do
|
23
|
-
scope :module => :v2 do
|
24
|
+
scope :module => :v2 do
|
24
25
|
inherit_resources :from => :v1
|
25
26
|
end
|
26
|
-
end
|
27
|
+
end
|
27
28
|
end
|
28
29
|
|
29
30
|
rake routes outputs:
|
@@ -50,9 +51,9 @@ A more complicated example
|
|
50
51
|
namespace :api do
|
51
52
|
default_api_version 1
|
52
53
|
api_vendor "myvendor"
|
53
|
-
|
54
|
+
|
54
55
|
constraints api_version_check(:version => 1) do
|
55
|
-
scope :module => :v1 do
|
56
|
+
scope :module => :v1 do
|
56
57
|
cache_resources :as => :v1 do
|
57
58
|
resources :authorizations, :only => [ :create ]
|
58
59
|
resources :foo
|
@@ -60,24 +61,24 @@ A more complicated example
|
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
63
|
-
|
64
|
+
|
64
65
|
# Version 2 of the API has everything in Version 1, plus my_new_resource
|
65
66
|
# Version 2 will cache this entire package of resources
|
66
67
|
constraints api_version_check(:version => 2) do
|
67
|
-
scope :module => :v2 do
|
68
|
-
cache_resources :as => :v2 do
|
68
|
+
scope :module => :v2 do
|
69
|
+
cache_resources :as => :v2 do
|
69
70
|
resources :my_new_resource
|
70
71
|
inherit_resources :from => :v1
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|
74
|
-
|
75
|
+
|
75
76
|
# Version 3 of the API has everything in API Version 2, and by
|
76
77
|
# virtue of API Version 2 having everything in Version 1, Version 3
|
77
78
|
# also has everything in Version 1.
|
78
|
-
|
79
|
+
|
79
80
|
constraints api_version_check(:version => 3) do
|
80
|
-
scope :module => :v3 do
|
81
|
+
scope :module => :v3 do
|
81
82
|
inherit_resources :from => :v2
|
82
83
|
end
|
83
84
|
end
|
data/Rakefile
CHANGED
data/api-versions.gemspec
CHANGED
data/lib/api-versions.rb
CHANGED
@@ -1,42 +1,35 @@
|
|
1
1
|
require "api-versions/version"
|
2
2
|
|
3
|
-
class Engine < Rails::Engine
|
4
|
-
initializer "api_versions" do
|
5
|
-
config.to_prepare { ActionDispatch::Routing::Mapper.send :include, ApiVersions }
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
3
|
module ApiVersions
|
10
|
-
|
11
4
|
def inherit_resources(args)
|
12
5
|
[*args[:from]].each do |block|
|
13
6
|
@resource_cache[block].call
|
14
7
|
end
|
15
8
|
end
|
16
|
-
|
9
|
+
|
17
10
|
def cache_resources(args, &block)
|
18
11
|
@resource_cache ||= {}
|
19
12
|
@resource_cache.merge!(args[:as] => block)
|
20
13
|
block.call
|
21
14
|
end
|
22
|
-
|
15
|
+
|
23
16
|
def api_version=(version)
|
24
17
|
ApiVersions::ApiVersionCheck.api_version = version
|
25
18
|
end
|
26
19
|
alias_method :default_api_version, :api_version=
|
27
|
-
|
28
|
-
|
20
|
+
|
21
|
+
|
29
22
|
def vendor=(vendor)
|
30
23
|
ApiVersions::ApiVersionCheck.api_vendor = vendor
|
31
24
|
end
|
32
25
|
alias_method :api_vendor, :vendor=
|
33
|
-
|
26
|
+
|
34
27
|
def api_version_check(*args)
|
35
28
|
ApiVersions::ApiVersionCheck.new(*args)
|
36
29
|
end
|
37
|
-
|
30
|
+
|
38
31
|
class ApiVersionCheck
|
39
|
-
|
32
|
+
|
40
33
|
cattr_accessor :api_version, :api_vendor
|
41
34
|
|
42
35
|
def initialize(args = {})
|
@@ -46,11 +39,11 @@ module ApiVersions
|
|
46
39
|
def matches?(request)
|
47
40
|
accepts_proper_format?(request) && (matches_version?(request) || unversioned?(request))
|
48
41
|
end
|
49
|
-
|
42
|
+
|
50
43
|
private
|
51
44
|
|
52
45
|
def accepts_proper_format?(request)
|
53
|
-
!!(request.headers['Accept'] =~ /^application\/vnd\.#{self.class.api_vendor}
|
46
|
+
!!(request.headers['Accept'] =~ /^application\/vnd\.#{self.class.api_vendor}\+.+/)
|
54
47
|
end
|
55
48
|
|
56
49
|
def matches_version?(request)
|
@@ -60,6 +53,7 @@ module ApiVersions
|
|
60
53
|
def unversioned?(request)
|
61
54
|
@process_version == self.class.api_version && !(request.headers['Accept'] =~ /version\s*?=\s*?\d*\b/i)
|
62
55
|
end
|
63
|
-
|
64
56
|
end
|
65
57
|
end
|
58
|
+
|
59
|
+
ActionDispatch::Routing::Mapper.send :include, ApiVersions
|
data/lib/api-versions/version.rb
CHANGED
data/spec/dummy/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
# Pick the frameworks you want:
|
4
|
+
require "action_controller/railtie"
|
5
|
+
# require "rails/test_unit/railtie"
|
6
|
+
|
7
|
+
Bundler.require
|
8
|
+
require "api-versions"
|
9
|
+
|
10
|
+
module Dummy
|
11
|
+
class Application < Rails::Application
|
12
|
+
# Settings in config/environments/* take precedence over those specified here.
|
13
|
+
# Application configuration should go into files in config/initializers
|
14
|
+
# -- all .rb files in that directory are automatically loaded.
|
15
|
+
|
16
|
+
# Custom directories with classes and modules you want to be autoloadable.
|
17
|
+
# config.autoload_paths += %W(#{config.root}/extras)
|
18
|
+
|
19
|
+
# Only load the plugins named here, in the order given (default is alphabetical).
|
20
|
+
# :all can be used as a placeholder for all plugins not explicitly named.
|
21
|
+
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
|
22
|
+
|
23
|
+
# Activate observers that should always be running.
|
24
|
+
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
25
|
+
|
26
|
+
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
27
|
+
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
28
|
+
# config.time_zone = 'Central Time (US & Canada)'
|
29
|
+
|
30
|
+
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
31
|
+
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
32
|
+
# config.i18n.default_locale = :de
|
33
|
+
|
34
|
+
# Configure the default encoding used in templates for Ruby 1.9.
|
35
|
+
config.encoding = "utf-8"
|
36
|
+
|
37
|
+
# Configure sensitive parameters which will be filtered from the log file.
|
38
|
+
config.filter_parameters += [:password]
|
39
|
+
|
40
|
+
# Enable escaping HTML in JSON.
|
41
|
+
config.active_support.escape_html_entities_in_json = true
|
42
|
+
|
43
|
+
# Use SQL instead of Active Record's schema dumper when creating the database.
|
44
|
+
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
45
|
+
# like if you have constraints or database-specific column types
|
46
|
+
# config.active_record.schema_format = :sql
|
47
|
+
|
48
|
+
# Enforce whitelist mode for mass assignment.
|
49
|
+
# This will create an empty whitelist of attributes available for mass-assignment for all models
|
50
|
+
# in your app. As such, your models will need to explicitly whitelist or blacklist accessible
|
51
|
+
# parameters by using an attr_accessible or attr_protected declaration.
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Dummy::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# The test environment is used exclusively to run your application's
|
5
|
+
# test suite. You never need to work with it otherwise. Remember that
|
6
|
+
# your test database is "scratch space" for the test suite and is wiped
|
7
|
+
# and recreated between test runs. Don't rely on the data there!
|
8
|
+
config.cache_classes = true
|
9
|
+
|
10
|
+
# Configure static asset server for tests with Cache-Control for performance
|
11
|
+
config.serve_static_assets = true
|
12
|
+
config.static_cache_control = "public, max-age=3600"
|
13
|
+
|
14
|
+
# Log error messages when you accidentally call methods on nil
|
15
|
+
config.whiny_nils = true
|
16
|
+
|
17
|
+
# Show full error reports and disable caching
|
18
|
+
config.consider_all_requests_local = true
|
19
|
+
config.action_controller.perform_caching = false
|
20
|
+
|
21
|
+
# Raise exceptions instead of rendering exception templates
|
22
|
+
config.action_dispatch.show_exceptions = false
|
23
|
+
|
24
|
+
# Disable request forgery protection in test environment
|
25
|
+
config.action_controller.allow_forgery_protection = false
|
26
|
+
|
27
|
+
# Print deprecation notices to the stderr
|
28
|
+
config.active_support.deprecation = :stderr
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Dummy::Application.routes.draw do
|
2
|
+
namespace :api do
|
3
|
+
default_api_version 1
|
4
|
+
api_vendor "myvendor"
|
5
|
+
|
6
|
+
constraints api_version_check(:version => 1) do
|
7
|
+
scope :module => :v1 do
|
8
|
+
cache_resources :as => :v1 do
|
9
|
+
resources :bar
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Version 2 of the API has everything in Version 1, plus my_new_resource
|
15
|
+
# Version 2 will cache this entire package of resources
|
16
|
+
constraints api_version_check(:version => 2) do
|
17
|
+
scope :module => :v2 do
|
18
|
+
cache_resources :as => :v2 do
|
19
|
+
resources :foo
|
20
|
+
inherit_resources :from => :v1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
File without changes
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'API Routing' do
|
4
|
+
def merge_and_stub(path, method, hash)
|
5
|
+
env_hash = Rack::MockRequest.env_for(path, method: method).merge(hash)
|
6
|
+
Rack::MockRequest.stub(:env_for).and_return env_hash
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "V1" do
|
10
|
+
context "when no header is set" do
|
11
|
+
it "doesn't route" do
|
12
|
+
expect(get: new_api_bar_path).to_not be_routable
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when the header is set incorrectly" do
|
17
|
+
it "doesn't route" do
|
18
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.mybadvendor+json;version=1'
|
19
|
+
expect(get: '/api/bar/new').to_not be_routable
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when it is set correctly" do
|
24
|
+
it "should not route something from V2" do
|
25
|
+
merge_and_stub new_api_foo_path, 'get', 'Accept' => 'application/vnd.myvendor+json;version=1'
|
26
|
+
expect(get: new_api_foo_path).to_not be_routable
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should route" do
|
30
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.myvendor+json;version=1'
|
31
|
+
expect(get: new_api_bar_path).to route_to(controller: 'api/v1/bar', action: 'new')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should default" do
|
35
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.myvendor+json'
|
36
|
+
expect(get: new_api_bar_path).to route_to(controller: 'api/v1/bar', action: 'new')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should default with nothing after the semi-colon" do
|
40
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.myvendor+json; '
|
41
|
+
expect(get: new_api_bar_path).to route_to(controller: 'api/v1/bar', action: 'new')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "V2" do
|
47
|
+
it "should copy bar" do
|
48
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.myvendor+json;version=2'
|
49
|
+
expect(get: new_api_bar_path).to route_to(controller: 'api/v2/bar', action: 'new')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should add foo" do
|
53
|
+
merge_and_stub new_api_foo_path, 'get', 'Accept' => 'application/vnd.myvendor+json;version=2'
|
54
|
+
expect(get: new_api_foo_path).to route_to(controller: 'api/v2/foo', action: 'new')
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not default" do
|
58
|
+
merge_and_stub new_api_foo_path, 'get', 'Accept' => 'application/vnd.myvendor+json'
|
59
|
+
expect(get: new_api_foo_path).to_not be_routable
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should default" do
|
63
|
+
original_version = ApiVersions::ApiVersionCheck.api_version
|
64
|
+
ApiVersions::ApiVersionCheck.api_version = 2
|
65
|
+
merge_and_stub new_api_foo_path, 'get', 'Accept' => 'application/vnd.myvendor+json'
|
66
|
+
expect(get: new_api_foo_path).to route_to(controller: 'api/v2/foo', action: 'new')
|
67
|
+
ApiVersions::ApiVersionCheck.api_version = original_version
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "Header syntax" do
|
72
|
+
after(:each) do
|
73
|
+
expect(get: new_api_bar_path).to route_to(controller: 'api/v1/bar', action: 'new')
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should allow spaces after the semi-colon" do
|
77
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.myvendor+json; version=1'
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should allow other formats besides json" do
|
81
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.myvendor+xml; version=1'
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should allow spacing around the equal sign" do
|
85
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.myvendor+json; version = 1'
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should allow spacing around the plus" do
|
89
|
+
merge_and_stub new_api_bar_path, 'get', 'Accept' => 'application/vnd.myvendor+xml; version=1'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
3
|
+
require File.expand_path("../dummy/config/environment", __FILE__)
|
4
|
+
require 'rspec/rails'
|
5
|
+
require 'rspec/autorun'
|
6
|
+
|
7
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
8
|
+
# in spec/support/ and its subdirectories.
|
9
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
|
13
|
+
# If true, the base class of anonymous controllers will be inferred
|
14
|
+
# automatically. This will be the default behavior in future versions of
|
15
|
+
# rspec-rails.
|
16
|
+
config.infer_base_class_for_anonymous_controllers = true
|
17
|
+
|
18
|
+
# Run specs in random order to surface order dependencies. If you find an
|
19
|
+
# order dependency and want to debug it, you can fix the order by providing
|
20
|
+
# the seed, which is printed after each run.
|
21
|
+
# --seed 1234
|
22
|
+
config.order = "random"
|
23
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api-versions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
-
dependencies:
|
12
|
+
date: 2012-08-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec-rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
description: Useful for API versioning.
|
15
31
|
email:
|
16
32
|
- erich.menge@me.com
|
@@ -19,12 +35,27 @@ extensions: []
|
|
19
35
|
extra_rdoc_files: []
|
20
36
|
files:
|
21
37
|
- .gitignore
|
38
|
+
- .travis.yml
|
22
39
|
- Gemfile
|
23
40
|
- README.md
|
24
41
|
- Rakefile
|
25
42
|
- api-versions.gemspec
|
26
43
|
- lib/api-versions.rb
|
27
44
|
- lib/api-versions/version.rb
|
45
|
+
- spec/dummy/.rspec
|
46
|
+
- spec/dummy/app/controllers/api/v1/bar_controller.rb
|
47
|
+
- spec/dummy/app/controllers/api/v2/bar_controller.rb
|
48
|
+
- spec/dummy/app/controllers/api/v2/foo_controller.rb
|
49
|
+
- spec/dummy/app/controllers/application_controller.rb
|
50
|
+
- spec/dummy/config.ru
|
51
|
+
- spec/dummy/config/application.rb
|
52
|
+
- spec/dummy/config/boot.rb
|
53
|
+
- spec/dummy/config/environment.rb
|
54
|
+
- spec/dummy/config/environments/test.rb
|
55
|
+
- spec/dummy/config/routes.rb
|
56
|
+
- spec/dummy/log/.gitkeep
|
57
|
+
- spec/routing/routing_spec.rb
|
58
|
+
- spec/spec_helper.rb
|
28
59
|
homepage: https://github.com/erichmenge/api-versions
|
29
60
|
licenses: []
|
30
61
|
post_install_message:
|
@@ -45,8 +76,22 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
76
|
version: '0'
|
46
77
|
requirements: []
|
47
78
|
rubyforge_project: api-versions
|
48
|
-
rubygems_version: 1.8.
|
79
|
+
rubygems_version: 1.8.24
|
49
80
|
signing_key:
|
50
81
|
specification_version: 3
|
51
82
|
summary: Allows you to cache routing and then inherit it in other modules.
|
52
|
-
test_files:
|
83
|
+
test_files:
|
84
|
+
- spec/dummy/.rspec
|
85
|
+
- spec/dummy/app/controllers/api/v1/bar_controller.rb
|
86
|
+
- spec/dummy/app/controllers/api/v2/bar_controller.rb
|
87
|
+
- spec/dummy/app/controllers/api/v2/foo_controller.rb
|
88
|
+
- spec/dummy/app/controllers/application_controller.rb
|
89
|
+
- spec/dummy/config.ru
|
90
|
+
- spec/dummy/config/application.rb
|
91
|
+
- spec/dummy/config/boot.rb
|
92
|
+
- spec/dummy/config/environment.rb
|
93
|
+
- spec/dummy/config/environments/test.rb
|
94
|
+
- spec/dummy/config/routes.rb
|
95
|
+
- spec/dummy/log/.gitkeep
|
96
|
+
- spec/routing/routing_spec.rb
|
97
|
+
- spec/spec_helper.rb
|