versioncake 2.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. checksums.yaml +6 -14
  2. data/.rspec +2 -0
  3. data/.travis.yml +4 -0
  4. data/Appraisals +12 -0
  5. data/CHANGELOG.md +18 -1
  6. data/CONTRIBUTING.md +2 -2
  7. data/Gemfile.lock +96 -44
  8. data/README.md +79 -29
  9. data/RELEASE.md +1 -1
  10. data/Rakefile +3 -7
  11. data/gemfiles/rails3.2.gemfile +2 -1
  12. data/gemfiles/rails3.2.gemfile.lock +34 -10
  13. data/gemfiles/rails4.0.gemfile +2 -1
  14. data/gemfiles/rails4.0.gemfile.lock +31 -7
  15. data/gemfiles/rails4.1.gemfile +1 -1
  16. data/gemfiles/rails4.1.gemfile.lock +28 -8
  17. data/gemfiles/rails4.2.gemfile +9 -0
  18. data/gemfiles/rails4.2.gemfile.lock +133 -0
  19. data/lib/generators/templates/versioncake.rb +40 -0
  20. data/lib/generators/versioncake/install_generator.rb +12 -0
  21. data/lib/versioncake.rb +24 -3
  22. data/lib/versioncake/configuration.rb +19 -2
  23. data/lib/versioncake/controller_additions.rb +35 -23
  24. data/lib/versioncake/engine.rb +7 -0
  25. data/lib/versioncake/exceptions.rb +4 -0
  26. data/lib/versioncake/rack/middleware.rb +20 -0
  27. data/lib/versioncake/strategies/extraction_strategy.rb +8 -3
  28. data/lib/versioncake/strategies/http_accept_parameter_strategy.rb +2 -2
  29. data/lib/versioncake/strategies/http_header_strategy.rb +2 -2
  30. data/lib/versioncake/strategies/path_parameter_strategy.rb +6 -2
  31. data/lib/versioncake/strategies/query_parameter_strategy.rb +2 -2
  32. data/lib/versioncake/strategies/request_parameter_strategy.rb +2 -2
  33. data/lib/versioncake/test_helpers.rb +14 -0
  34. data/lib/versioncake/version.rb +1 -1
  35. data/lib/versioncake/version_checker.rb +28 -0
  36. data/lib/versioncake/version_context.rb +20 -0
  37. data/lib/versioncake/version_context_service.rb +47 -0
  38. data/lib/versioncake/versioned_request.rb +22 -33
  39. data/lib/versioncake/versioned_resource.rb +14 -0
  40. data/lib/versioncake/view_additions.rb +7 -7
  41. data/{test → spec}/fixtures/partials/_versioned.erb +0 -0
  42. data/{test → spec}/fixtures/partials/_versioned.v1.erb +0 -0
  43. data/{test → spec}/fixtures/partials/_versioned.v2.erb +0 -0
  44. data/{test → spec}/fixtures/partials/_versioned.v3.erb +0 -0
  45. data/{test → spec}/fixtures/partials/another_versioned_partial.erb +0 -0
  46. data/{test → spec}/fixtures/partials/another_versioned_partial.v1.erb +0 -0
  47. data/{test → spec}/fixtures/templates/unversioned.html.erb +0 -0
  48. data/{test → spec}/fixtures/templates/v1_extension_scheme.v3.html.erb +0 -0
  49. data/{test → spec}/fixtures/templates/v1_extension_scheme.v6.json +0 -0
  50. data/{test → spec}/fixtures/templates/versioned.html.erb +0 -0
  51. data/{test → spec}/fixtures/templates/versioned.html.v1.erb +0 -0
  52. data/{test → spec}/fixtures/templates/versioned.html.v2.erb +0 -0
  53. data/{test → spec}/fixtures/templates/versioned.html.v3.erb +0 -0
  54. data/spec/fixtures/test_cases.yml +45 -0
  55. data/spec/integration/controller/renders_controller_spec.rb +73 -0
  56. data/spec/integration/controller/unversioned_controller_spec.rb +12 -0
  57. data/spec/integration/rack/middleware_regression_spec.rb +41 -0
  58. data/spec/integration/view/render_spec.rb +33 -0
  59. data/spec/integration/view/view_additions_spec.rb +51 -0
  60. data/spec/rails_helper.rb +41 -0
  61. data/spec/spec_helper.rb +25 -0
  62. data/spec/test_app/Rakefile +7 -0
  63. data/{test → spec/test_app}/app/controllers/renders_controller.rb +0 -0
  64. data/spec/test_app/app/controllers/unversioned_controller.rb +6 -0
  65. data/spec/test_app/app/views/renders/index.html.erb +1 -0
  66. data/{test → spec/test_app}/app/views/renders/index.html.v1.erb +0 -0
  67. data/{test → spec/test_app}/app/views/renders/index.html.v2.erb +0 -0
  68. data/spec/test_app/app/views/unversioned/index.html.erb +1 -0
  69. data/spec/test_app/config.ru +4 -0
  70. data/{test → spec/test_app}/config/application.rb +4 -6
  71. data/spec/test_app/config/boot.rb +5 -0
  72. data/spec/test_app/config/environment.rb +5 -0
  73. data/spec/test_app/config/initializers/versioncake.rb +45 -0
  74. data/spec/test_app/config/routes.rb +4 -0
  75. data/spec/test_app/script/rails +4 -0
  76. data/spec/unit/cli_spec.rb +36 -0
  77. data/spec/unit/configuration_spec.rb +61 -0
  78. data/spec/unit/strategies/extraction_strategy_spec.rb +71 -0
  79. data/spec/unit/strategies/http_accept_parameter_strategy_spec.rb +20 -0
  80. data/spec/unit/strategies/http_header_strategy_spec.rb +19 -0
  81. data/spec/unit/strategies/path_parameter_strategy_spec.rb +18 -0
  82. data/spec/unit/strategies/query_parameter_strategy_spec.rb +24 -0
  83. data/spec/unit/strategies/request_parameter_strategy_spec.rb +19 -0
  84. data/spec/unit/version_checker_spec.rb +60 -0
  85. data/spec/unit/version_context_service_spec.rb +84 -0
  86. data/spec/unit/version_context_spec.rb +46 -0
  87. data/spec/unit/versioned_request_spec.rb +35 -0
  88. data/spec/unit/versioned_resource_spec.rb +12 -0
  89. data/versioncake.gemspec +5 -2
  90. metadata +91 -70
  91. data/lib/versioncake/railtie.rb +0 -7
  92. data/test/app/views/renders/index.html.erb +0 -1
  93. data/test/config.ru +0 -0
  94. data/test/config/routes.rb +0 -3
  95. data/test/fixtures/test_cases.yml +0 -70
  96. data/test/functional/custom_strategy_controller_test.rb +0 -16
  97. data/test/functional/multiple_strategy_controller_test.rb +0 -24
  98. data/test/functional/renders_controller_test.rb +0 -71
  99. data/test/functional/strategy_controller_test.rb +0 -38
  100. data/test/script/rails +0 -0
  101. data/test/template/render_test.rb +0 -34
  102. data/test/test_helper.rb +0 -21
  103. data/test/unit/cli_test.rb +0 -48
  104. data/test/unit/configuration_test.rb +0 -45
  105. data/test/unit/strategies/extraction_strategy_test.rb +0 -70
  106. data/test/unit/strategies/http_accept_parameter_strategy_test.rb +0 -17
  107. data/test/unit/strategies/http_header_strategy_test.rb +0 -17
  108. data/test/unit/strategies/path_parameter_strategy_test.rb +0 -17
  109. data/test/unit/strategies/query_parameter_strategy_test.rb +0 -22
  110. data/test/unit/strategies/request_parameter_strategy_test.rb +0 -17
  111. data/test/unit/versioned_request_test.rb +0 -44
  112. data/test/unit/view_additions_test.rb +0 -35
@@ -0,0 +1,14 @@
1
+ module VersionCake
2
+ class VersionedResource
3
+ attr_reader :uri, :supported_versions, :deprecated_versions, :obsolete_versions
4
+
5
+ def initialize(uri, obsolete_versions, deprecated_versions, supported_versions)
6
+ @uri, @supported_versions, @deprecated_versions, @obsolete_versions =
7
+ uri, supported_versions, deprecated_versions, obsolete_versions
8
+ end
9
+
10
+ def latest_version
11
+ @supported_versions.last
12
+ end
13
+ end
14
+ end
@@ -3,17 +3,17 @@ require 'action_view'
3
3
  # register an addition detail for the lookup context to understand,
4
4
  # this will allow us to have the versions available upon lookup in
5
5
  # the resolver.
6
- ActionView::LookupContext.register_detail(:versions){ VersionCake::Railtie.config.versioncake.supported_versions }
6
+ ActionView::LookupContext.register_detail(:versions){ [] }
7
7
 
8
8
  ActionView::PathResolver.class_eval do
9
9
  # not sure why we are doing this yet, but looks like a good idea
10
- if ActionPack::VERSION::MAJOR >= 4 && ActionPack::VERSION::MINOR >= 1
10
+ if ActionPack::VERSION::MAJOR >= 4 && ActionPack::VERSION::MINOR >= 1 || ActionPack::VERSION::MAJOR >= 5
11
11
  ActionView::PathResolver::EXTENSIONS.replace({
12
- :locale => ".",
13
- :formats => ".",
14
- :versions => ".",
15
- :variants => "+",
16
- :handlers => "."
12
+ locale: ".",
13
+ formats: ".",
14
+ versions: ".",
15
+ variants: "+",
16
+ handlers: "."
17
17
  })
18
18
 
19
19
  ActionView::PathResolver::DEFAULT_PATTERN.replace ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:versions,}{.:handlers,}"
@@ -0,0 +1,45 @@
1
+ # http_header_strategy
2
+ - request:
3
+ headers:
4
+ HTTP_ACCEPT: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;api_version=1"
5
+ response: "1"
6
+
7
+ - request:
8
+ headers:
9
+ HTTP_ACCEPT: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;api_version=2"
10
+ response: "2"
11
+
12
+ # request_parameter_strategy
13
+ - request:
14
+ method: post
15
+ params:
16
+ api_version: "1"
17
+ response: "1"
18
+
19
+ - request:
20
+ method: post
21
+ params:
22
+ api_version: "2"
23
+ response: "2"
24
+
25
+ # query_parameter_strategy
26
+ - request:
27
+ params:
28
+ api_version: "1"
29
+ response: "1"
30
+
31
+ - request:
32
+ params:
33
+ api_version: "2"
34
+ response: "2"
35
+
36
+ # http_header_strategy
37
+ - request:
38
+ headers:
39
+ HTTP_API_VERSION: "1"
40
+ response: "1"
41
+
42
+ - request:
43
+ headers:
44
+ HTTP_API_VERSION: "2"
45
+ response: "2"
@@ -0,0 +1,73 @@
1
+ require './spec/rails_helper'
2
+
3
+ describe RendersController, type: :controller do
4
+ let(:request_options) { {} }
5
+ subject(:response_body) { get :index, request_options; response.body }
6
+
7
+ context '#index' do
8
+ render_views
9
+ before { set_request_version 'renders', request_version }
10
+ before { response_body }
11
+
12
+ context 'when requesting the non latest version' do
13
+ let(:request_version) { 1 }
14
+
15
+ it { expect(controller.request_version).to eq 1 }
16
+ it { expect(controller.is_latest_version?).to be_falsey }
17
+ it { expect(controller.is_deprecated_version?).to be_falsey }
18
+ it { expect(response_body).to eq 'template v1' }
19
+ end
20
+
21
+ context 'with explicity requesting the latest version' do
22
+ let(:request_version) { 5 }
23
+
24
+ it { expect(controller.request_version).to eq 5 }
25
+ it { expect(controller.is_latest_version?).to be_truthy }
26
+ it { expect(controller.is_deprecated_version?).to be_falsey }
27
+ it { expect(response_body).to eq 'template v2' }
28
+ end
29
+
30
+ context 'when requesting a deprecated version' do
31
+ let(:request_version) { 4 }
32
+
33
+ it { expect(controller.request_version).to eq 4 }
34
+ it { expect(controller.is_latest_version?).to be_falsey }
35
+ it { expect(controller.is_deprecated_version?).to be_truthy }
36
+ it { expect(response_body).to eq 'template v2' }
37
+ end
38
+
39
+ context '#set_version' do
40
+ let(:request_options) { { 'override_version' => 2 } }
41
+ let(:request_version) { 3 }
42
+
43
+ it { expect(controller.request_version).to eq 2 }
44
+ it { expect(response_body).to eq 'template v2' }
45
+ end
46
+ end
47
+
48
+ context 'errors' do
49
+ context 'with a version larger than the supported versions' do
50
+ before { set_version_context :version_too_high }
51
+
52
+ it { expect { response_body }.to raise_error VersionCake::UnsupportedVersionError }
53
+ end
54
+
55
+ context 'with a version lower than the supported versions' do
56
+ before { set_version_context :version_too_low }
57
+
58
+ it { expect { response_body }.to raise_error VersionCake::UnsupportedVersionError }
59
+ end
60
+
61
+ context 'with an invalid version' do
62
+ before { set_version_context :version_invalid }
63
+
64
+ it { expect { response_body }.to raise_error VersionCake::UnsupportedVersionError }
65
+ end
66
+
67
+ context 'with an obsolete version' do
68
+ before { set_version_context :obsolete }
69
+
70
+ it { expect { response_body }.to raise_error VersionCake::ObsoleteVersionError }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,12 @@
1
+ require './spec/rails_helper'
2
+
3
+ describe UnversionedController, type: :controller do
4
+ subject(:response) { get :index }
5
+
6
+ context '#index' do
7
+ render_views
8
+
9
+ it { expect(response).to be_success }
10
+ it { expect(response.body).to eq 'unversioned index' }
11
+ end
12
+ end
@@ -0,0 +1,41 @@
1
+ require './spec/rails_helper'
2
+ require 'yaml'
3
+
4
+ describe VersionCake::Rack::Middleware do
5
+ let(:app) do
6
+ rack = Rack::Builder.new do
7
+ use VersionCake::Rack::Middleware
8
+ run lambda { |env| [ 200, {}, [ env['versioncake.context'].version ] ] }
9
+ end
10
+ Rack::MockRequest.new(rack)
11
+ end
12
+
13
+ test_cases = YAML.load(File.open('./spec/fixtures/test_cases.yml'))
14
+ test_cases.each do |test_case|
15
+ context 'for a test case' do
16
+
17
+
18
+ let(:data) { test_case['request'] || {} }
19
+ let(:method) { (data['method'] || 'get').to_sym }
20
+ let(:headers) { data['headers'] || {} }
21
+ let(:params) { data['params'] || {} }
22
+ let(:test_response) { test_case['response'] }
23
+
24
+ it "test yml test cases" do
25
+ begin
26
+ response = app.request(method, '/renders', headers.merge(params: params))
27
+ expect(response.body).to(eq(test_response), custom_message(headers, params, method, response.body, test_response))
28
+ rescue => e
29
+ raise custom_message(headers, params, method, response.body, test_response) + ", but it failed with an exception '#{e.message}'"
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def custom_message(headers, params, method, actual_response, expected_response)
36
+ data = []
37
+ data << "headers:#{headers}" if headers
38
+ data << "params:#{params}" if params
39
+ "Expected #{data.join(',')} with method #{method} to yield '#{expected_response}', but got '#{actual_response}'"
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ require './spec/rails_helper'
2
+
3
+ describe ActionView::Base do
4
+ let(:path) { ActionView::FileSystemResolver.new('./spec/fixtures') }
5
+ let(:view_paths) { ActionView::PathSet.new([path]) }
6
+ let(:view) { ActionView::Base.new(view_paths) }
7
+ let(:version_override) { nil }
8
+ subject { view.render(template: 'templates/versioned', versions: version_override) }
9
+
10
+ context 'with a 0 version' do
11
+ before { view.lookup_context.versions = [:v0] }
12
+
13
+ it { is_expected.to eq 'template' }
14
+ end
15
+
16
+ context 'with the version override set' do
17
+ let(:version_override) { :v1 }
18
+
19
+ it { is_expected.to eq 'template v1' }
20
+ end
21
+
22
+ context 'with an older version in the lookup context' do
23
+ before { view.lookup_context.versions = [:v2] }
24
+
25
+ it { is_expected.to eq 'template v2' }
26
+ end
27
+
28
+ context 'with a v4 requested, but only highest templates is v3' do
29
+ before { view.lookup_context.versions = [:v4,:v3,:v2,:v1] }
30
+
31
+ it { is_expected.to eq 'template v3' }
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ require './spec/rails_helper'
2
+
3
+ describe ActionView::PathResolver do
4
+ let(:resolver) { ActionView::PathResolver.new }
5
+
6
+ context '#extract_handler_and_format' do
7
+ subject(:template_format) do
8
+ _, format = resolver.extract_handler_and_format("application.#{template_extension}", nil)
9
+ format.to_s
10
+ end
11
+
12
+ context 'when only handler and format are present' do
13
+ let(:template_extension) { 'html.erb' }
14
+
15
+ it { expect(template_format).to eq 'text/html' }
16
+ end
17
+
18
+ context 'when handler, format and version are present' do
19
+ let(:template_extension) { 'json.v1.jbuilder' }
20
+
21
+ it { expect(template_format).to eq 'application/json' }
22
+ end
23
+
24
+ context 'when handler, format and locale are present' do
25
+ let(:template_extension) { 'en.json.jbuilder' }
26
+
27
+ it { expect(template_format).to eq 'application/json' }
28
+ end
29
+
30
+ context 'when handler, format, locale and version are present' do
31
+ let(:template_extension) { 'en.json.v1.jbuilder' }
32
+
33
+ it { expect(template_format).to eq 'application/json' }
34
+ end
35
+
36
+ context 'when in Rails >=4.1' do
37
+ before do
38
+ unless (ActionPack::VERSION::MAJOR == 4 && ActionPack::VERSION::MINOR >= 1) ||
39
+ ActionPack::VERSION::MAJOR > 5
40
+ skip('Template variants are only available in Rails >=4.1')
41
+ end
42
+ end
43
+
44
+ context 'when handler, format, variant and version are present' do
45
+ let(:template_extension) { 'application.json+tablet.v1.jbuilder' }
46
+
47
+ it { expect(template_format).to eq 'application/json' }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,41 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV['RAILS_ENV'] ||= 'test'
3
+ require File.expand_path('../test_app/config/environment.rb', __FILE__)
4
+ require 'rails/all'
5
+
6
+ require 'rspec/rails'
7
+
8
+ # Requires supporting ruby files with custom matchers and macros, etc,
9
+ # in spec/support/ and its subdirectories.
10
+ # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
11
+
12
+ RSpec.configure do |config|
13
+ # ## Mock Framework
14
+ #
15
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
16
+ #
17
+ # config.mock_with :mocha
18
+ # config.mock_with :flexmock
19
+ # config.mock_with :rr
20
+
21
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
22
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
23
+
24
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
25
+ # examples within a transaction, remove the following line or assign false
26
+ # instead of true.
27
+ config.use_transactional_fixtures = false # false - no active record
28
+
29
+ # If true, the base class of anonymous controllers will be inferred
30
+ # automatically. This will be the default behavior in future versions of
31
+ # rspec-rails.
32
+ config.infer_base_class_for_anonymous_controllers = false
33
+
34
+ # Run specs in random order to surface order dependencies. If you find an
35
+ # order dependency and want to debug it, you can fix the order by providing
36
+ # the seed, which is printed after each run.
37
+ # --seed 1234
38
+ config.order = "random"
39
+
40
+ config.include VersionCake::TestHelpers, type: :controller
41
+ end
@@ -0,0 +1,25 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+ require 'versioncake'
4
+
5
+ # We have to occasionally require test-unit because it was removed as a core
6
+ # dependency, so have to explicitly disable it from running automatically
7
+ Test::Unit::AutoRunner.need_auto_run = false if defined?(Test::Unit::AutoRunner)
8
+
9
+ def capture_stdout(flag=true)
10
+ if flag
11
+ out = StringIO.new
12
+ $stdout = out
13
+ else
14
+ $stdout = STDOUT
15
+ end
16
+ end
17
+
18
+ # Turn off stdout for all specs
19
+ def quiet_stdout
20
+ around(:example) do |example|
21
+ capture_stdout true
22
+ example.run
23
+ capture_stdout false
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
3
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ RendersTest::Application.load_tasks
@@ -0,0 +1,6 @@
1
+ require "action_controller"
2
+ require "action_controller/base"
3
+
4
+ class UnversionedController < ActionController::Base
5
+ def index;end
6
+ end
@@ -0,0 +1 @@
1
+ base template
@@ -0,0 +1 @@
1
+ unversioned index
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run RendersTest::Application
@@ -1,6 +1,4 @@
1
- require "action_controller/railtie"
2
- require "active_support/railtie"
3
-
1
+ require 'rails/all'
4
2
  # Auto-require default libraries and those for the current Rails environment.
5
3
  Bundler.require :default, Rails.env
6
4
 
@@ -11,8 +9,8 @@ module RendersTest
11
9
  config.eager_load = false
12
10
 
13
11
  config.active_support.deprecation = :stderr
14
-
15
- config.versioncake.supported_version_numbers = (1..3)
16
- config.versioncake.extraction_strategy = [:http_header, :http_accept_parameter, :query_parameter, :request_parameter]
12
+ config.generators do |g|
13
+ g.test_framework :rspec
14
+ end
17
15
  end
18
16
  end