versioncake 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.gitignore +4 -0
  2. data/.travis.yml +4 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +97 -0
  5. data/README.md +76 -0
  6. data/Rakefile +31 -0
  7. data/lib/versioncake/action_controller/versioning.rb +26 -0
  8. data/lib/versioncake/action_view/lookup_context.rb +10 -0
  9. data/lib/versioncake/action_view/railtie.rb +15 -0
  10. data/lib/versioncake/action_view/resolver.rb +13 -0
  11. data/lib/versioncake/action_view/template.rb +11 -0
  12. data/lib/versioncake/action_view/versions.rb +88 -0
  13. data/lib/versioncake/version.rb +3 -0
  14. data/lib/versioncake.rb +6 -0
  15. data/spec/app/controllers/renders_controller.rb +4 -0
  16. data/spec/app/views/renders/index.html.erb +1 -0
  17. data/spec/app/views/renders/index.v1.html.erb +1 -0
  18. data/spec/app/views/renders/index.v2.html.erb +1 -0
  19. data/spec/config/application.rb +13 -0
  20. data/spec/config/database.yml +4 -0
  21. data/spec/config/routes.rb +3 -0
  22. data/spec/config.ru +0 -0
  23. data/spec/db/test.sqlite3 +0 -0
  24. data/spec/fixtures/partials/_versioned.erb +1 -0
  25. data/spec/fixtures/partials/_versioned.v1.erb +1 -0
  26. data/spec/fixtures/partials/_versioned.v2.erb +1 -0
  27. data/spec/fixtures/partials/_versioned.v3.erb +1 -0
  28. data/spec/fixtures/partials/another_versioned_partial.erb +1 -0
  29. data/spec/fixtures/partials/another_versioned_partial.v1.erb +1 -0
  30. data/spec/fixtures/templates/unversioned.html.erb +1 -0
  31. data/spec/fixtures/templates/versioned.html.erb +1 -0
  32. data/spec/fixtures/templates/versioned.v1.html.erb +1 -0
  33. data/spec/fixtures/templates/versioned.v2.html.erb +1 -0
  34. data/spec/fixtures/templates/versioned.v3.html.erb +1 -0
  35. data/spec/script/rails +0 -0
  36. data/spec/spec_helper.rb +27 -0
  37. data/spec/template/render_spec.rb +34 -0
  38. data/spec/template/resolver_spec.rb +12 -0
  39. data/test/app/controllers/renders_controller.rb +7 -0
  40. data/test/app/views/renders/index.html.erb +1 -0
  41. data/test/app/views/renders/index.v1.html.erb +1 -0
  42. data/test/app/views/renders/index.v2.html.erb +1 -0
  43. data/test/config/application.rb +15 -0
  44. data/test/config/database.yml +4 -0
  45. data/test/config/routes.rb +3 -0
  46. data/test/config.ru +0 -0
  47. data/test/db/test.sqlite3 +0 -0
  48. data/test/functional/renders_controller_test.rb +145 -0
  49. data/test/script/rails +0 -0
  50. data/test/test_helper.rb +32 -0
  51. data/versioncake.gemspec +23 -0
  52. metadata +166 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .idea
2
+ .rvmrc
3
+ spec/log
4
+ log/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rack'
6
+ gem 'actionpack'
7
+ gem 'activerecord'
8
+ gem 'multi_json'
9
+ gem 'i18n', '0.6.1'
10
+ gem 'tzinfo'
11
+ gem 'sqlite3'
12
+
13
+ group :development do
14
+ # for travis-ci.org
15
+ gem "rake"
16
+ gem 'test-unit'
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,97 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ versioncake (0.1.0)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ actionpack (3.2.8)
10
+ activemodel (= 3.2.8)
11
+ activesupport (= 3.2.8)
12
+ builder (~> 3.0.0)
13
+ erubis (~> 2.7.0)
14
+ journey (~> 1.0.4)
15
+ rack (~> 1.4.0)
16
+ rack-cache (~> 1.2)
17
+ rack-test (~> 0.6.1)
18
+ sprockets (~> 2.1.3)
19
+ activemodel (3.2.8)
20
+ activesupport (= 3.2.8)
21
+ builder (~> 3.0.0)
22
+ activerecord (3.2.8)
23
+ activemodel (= 3.2.8)
24
+ activesupport (= 3.2.8)
25
+ arel (~> 3.0.2)
26
+ tzinfo (~> 0.3.29)
27
+ activesupport (3.2.8)
28
+ i18n (~> 0.6)
29
+ multi_json (~> 1.0)
30
+ arel (3.0.2)
31
+ builder (3.0.0)
32
+ diff-lcs (1.1.3)
33
+ erubis (2.7.0)
34
+ hike (1.2.1)
35
+ i18n (0.6.1)
36
+ journey (1.0.4)
37
+ json (1.7.5)
38
+ metaclass (0.0.1)
39
+ mocha (0.12.3)
40
+ metaclass (~> 0.0.1)
41
+ multi_json (1.3.6)
42
+ rack (1.4.1)
43
+ rack-cache (1.2)
44
+ rack (>= 0.4)
45
+ rack-ssl (1.3.2)
46
+ rack
47
+ rack-test (0.6.1)
48
+ rack (>= 1.0)
49
+ railties (3.2.8)
50
+ actionpack (= 3.2.8)
51
+ activesupport (= 3.2.8)
52
+ rack-ssl (~> 1.3.2)
53
+ rake (>= 0.8.7)
54
+ rdoc (~> 3.4)
55
+ thor (>= 0.14.6, < 2.0)
56
+ rake (0.9.2.2)
57
+ rdoc (3.12)
58
+ json (~> 1.4)
59
+ rspec (2.11.0)
60
+ rspec-core (~> 2.11.0)
61
+ rspec-expectations (~> 2.11.0)
62
+ rspec-mocks (~> 2.11.0)
63
+ rspec-core (2.11.1)
64
+ rspec-expectations (2.11.2)
65
+ diff-lcs (~> 1.1.3)
66
+ rspec-mocks (2.11.2)
67
+ rspec-rails (2.11.0)
68
+ actionpack (>= 3.0)
69
+ activesupport (>= 3.0)
70
+ railties (>= 3.0)
71
+ rspec (~> 2.11.0)
72
+ sprockets (2.1.3)
73
+ hike (~> 1.2)
74
+ rack (~> 1.0)
75
+ tilt (~> 1.1, != 1.3.0)
76
+ sqlite3 (1.3.6)
77
+ test-unit (2.5.2)
78
+ thor (0.16.0)
79
+ tilt (1.3.3)
80
+ tzinfo (0.3.33)
81
+
82
+ PLATFORMS
83
+ ruby
84
+
85
+ DEPENDENCIES
86
+ actionpack
87
+ activerecord
88
+ i18n (= 0.6.1)
89
+ mocha
90
+ multi_json
91
+ rack
92
+ rake
93
+ rspec-rails
94
+ sqlite3
95
+ test-unit
96
+ tzinfo
97
+ versioncake!
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Version Cake [![Build Status](https://secure.travis-ci.org/bwillis/versioncake.png?branch=master)](http://travis-ci.org/bwillis/versioncake)
2
+
3
+ Version Cake is a way to easily version views in your Rails app.
4
+
5
+ ## Install - not release yet
6
+
7
+ ```
8
+ gem install versioncake
9
+ ```
10
+
11
+ ## How to use
12
+
13
+ ### Configure
14
+
15
+ You need to define the supported versions in your Rails application.rb file as
16
+ ```view_versions```. Use this config to set the range of supported API
17
+ versions that can be served:
18
+
19
+ ```ruby
20
+ config.view_versions = [1,3,4,5] # or (1...5)
21
+ #config.view_version_extraction_strategy = :http_parameter # options = :http_header, :http_accept_parameter, :query_parameter, custom Proc
22
+ ```
23
+
24
+ ### Version your views
25
+
26
+ When a client makes a request to your controller the latest version of the
27
+ view will be rendered. The latest version is determined by naming the template
28
+ or partial with a version number that you configured to support.
29
+
30
+ ```
31
+ - app/views/posts
32
+ - index.html.erb
33
+ - edit.html.erb
34
+ - show.html.erb
35
+ - show.json.jbuilder
36
+ - show.v1.json.jbuilder
37
+ - show.v2.json.jbuilder
38
+ - new.html.erb
39
+ - _form.html.erb
40
+ ```
41
+
42
+ If you start supporting a newer version, v3 for instance, a request for the latest
43
+ version of posts/show will gracefully degrade to the latest support available
44
+ version, in this case posts/show.v2.json.jbuilder.
45
+
46
+ ### Client requests
47
+
48
+ When a client makes a request it will automatically receive the latest supported
49
+ version of the view. The client can also request for a specific version by one of three
50
+ strategies configured by ``view_version_extraction_strategy``:
51
+
52
+ - http_header: Api version HTTP header ie. ```API-Version: 1```
53
+ - http_accept_parameter: HTTP Accept header ie. ```Accept: application/xml; version=1```
54
+ - http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned
55
+ - query_parameter: version in the url query parameter ie. ```http://localhost:3000/posts.json?api_version=1```
56
+
57
+ A custom strategy is available by providing a proc to the ``view_version_extraction_strategy`` configuration. It
58
+ takes a single parameter of the current request and must return an integer.
59
+
60
+ ```ruby
61
+ Proc.new { |request| request.headers["HTTP_X_API_MAGIC"].to_i }
62
+ ```
63
+
64
+ ## Development Work
65
+
66
+ 1. Finish convertion of Rspec tests to TestUnit
67
+ 2. Syntatic sugar controller helpers to detect the version - interface discussion: https://github.com/bwillis/versioncake/commit/3dbdaf612ff99676c499a456f3e858e22382e76b#commitcomment-1847368
68
+ 3. Log the version requested in the logs
69
+
70
+ # Similar Libraries
71
+
72
+ - https://github.com/bploetz/versionist
73
+
74
+ # License
75
+
76
+ Version Cake is released under the MIT license: www.opensource.org/licenses/MIT
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/dsl_definition'
4
+ require "bundler"
5
+ Bundler.setup
6
+
7
+ require "rspec"
8
+ require "rspec/core/rake_task"
9
+ require 'rake/testtask'
10
+
11
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
12
+
13
+ Bundler::GemHelper.install_tasks
14
+
15
+ task :default => :spec
16
+
17
+ RSpec::Core::RakeTask.new(:spec) do |spec|
18
+ spec.pattern = 'spec/**/*_spec.rb'
19
+ end
20
+
21
+ $: << "."
22
+ $: << "./test"
23
+
24
+ Rake::TestTask.new do |i|
25
+ #i.libs << '.'
26
+ i.libs << 'test'
27
+ i.test_files = FileList['test/**/*_test.rb']
28
+ #i.test_files = FileList['test/test_*.rb']
29
+ #i.test_files = FileList.new('test/**/*_test.rb')
30
+ i.verbose = true
31
+ end
@@ -0,0 +1,26 @@
1
+ require 'action_controller'
2
+
3
+ module ActionController #:nodoc:
4
+ module Versioning
5
+ extend ActiveSupport::Concern
6
+
7
+ attr_accessor :requested_version, :is_latest_version
8
+
9
+ included do
10
+ prepend_before_filter :set_version
11
+ end
12
+
13
+ protected
14
+ def set_version
15
+ requested_version = ActionView::Template::Versions.extract_version request
16
+ if ActionView::Template::Versions.supports_version? requested_version
17
+ @requested_version = requested_version
18
+ @_lookup_context.versions = ActionView::Template::Versions.supported_versions(requested_version)
19
+ else
20
+ @requested_version = ActionView::Template::Versions.latest_version
21
+ end
22
+ @is_latest_version = @requested_version == ActionView::Template::Versions.latest_version
23
+ end
24
+ end
25
+ end
26
+ ActionController::Base.send(:include, ActionController::Versioning)
@@ -0,0 +1,10 @@
1
+ require 'action_view'
2
+
3
+ ActionView::LookupContext.class_eval do
4
+
5
+ # register an addition detail for the lookup context to understand,
6
+ # this will allow us to have the versions available upon lookup in
7
+ # the resolver.
8
+ register_detail(:versions){ ActionView::Template::Versions.supported_versions }
9
+
10
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails'
2
+
3
+ class ActionViewVersions < Rails::Railtie
4
+ initializer "view_versions" do |app|
5
+ ActiveSupport.on_load(:action_view) do
6
+ if app.config.respond_to?(:view_versions)
7
+ ActionView::Template::Versions.supported_version_numbers = app.config.view_versions
8
+ end
9
+
10
+ if app.config.respond_to?(:view_version_extraction_strategy)
11
+ ActionView::Template::Versions.extraction_strategy = app.config.view_version_extraction_strategy
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ require 'action_view'
2
+
3
+ ActionView::PathResolver.class_eval do
4
+
5
+ # not sure why we are doing this yet, but looks like a good idea
6
+ ActionView::PathResolver::EXTENSIONS.replace [:locale, :versions, :formats, :handlers]
7
+
8
+ # The query builder has the @details from the lookup_context and will
9
+ # match the detail name to the string in the pattern, so we must append
10
+ # it to the default pattern
11
+ ActionView::PathResolver::DEFAULT_PATTERN.replace ":prefix/:action{.:locale,}{.:versions,}{.:formats,}{.:handlers,}"
12
+
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'action_view'
2
+
3
+ ActionView::Template.class_eval do
4
+
5
+ # the identifier method name filters out numbers,
6
+ # but we want to preserve them for v1 etc.
7
+ def identifier_method_name #:nodoc:
8
+ inspect.gsub(/[^a-z0-9_]/, '_')
9
+ end
10
+
11
+ end
@@ -0,0 +1,88 @@
1
+ require 'active_support/core_ext/module/attribute_accessors.rb'
2
+
3
+ module ActionView
4
+ class Template
5
+ module Versions
6
+
7
+ VERSION_STRING = "api_version"
8
+
9
+ mattr_accessor :supported_version_numbers
10
+ self.supported_version_numbers = []
11
+
12
+ mattr_accessor :extraction_strategy
13
+ self.extraction_strategy = [:query_parameter]
14
+
15
+ EXTRACTION_STRATEGIES = {
16
+ :query_parameter => lambda { |request|
17
+ if request.query_parameters.has_key? VERSION_STRING.to_sym
18
+ request.query_parameters[VERSION_STRING.to_sym].to_i
19
+ end
20
+ },
21
+ :http_header => lambda { |request|
22
+ if request.headers.has_key? "HTTP_#{VERSION_STRING.upcase}"
23
+ request.headers["HTTP_#{VERSION_STRING.upcase}"].to_i
24
+ end
25
+ },
26
+ :http_accept_parameter => lambda { |request|
27
+ if request.headers.has_key?("HTTP_ACCEPT") &&
28
+ match = request.headers["HTTP_ACCEPT"].match(%{#{VERSION_STRING}=([0-9])})
29
+ match[1].to_i
30
+ end
31
+ }
32
+ }
33
+
34
+ def self.extract_version(request)
35
+ version = nil
36
+ extraction_strategy.each do |strategy|
37
+ version = if strategy.is_a? Proc
38
+ strategy.call(request)
39
+ elsif EXTRACTION_STRATEGIES.include? strategy
40
+ EXTRACTION_STRATEGIES[strategy].call(request)
41
+ else
42
+ raise "Unknown extraction strategy #{strategy}"
43
+ end
44
+ break unless version.nil?
45
+ end
46
+ version
47
+ end
48
+
49
+ def self.extraction_strategy=(val)
50
+ case val
51
+ when Array
52
+ @@extraction_strategy = val
53
+ else
54
+ @@extraction_strategy = Array.wrap(val)
55
+ end
56
+ end
57
+
58
+ def self.supported_version_numbers=(val)
59
+ case val
60
+ when Range
61
+ @@supported_version_numbers = val.to_a
62
+ when Array
63
+ @@supported_version_numbers = val
64
+ else
65
+ @@supported_version_numbers = Array.wrap(val)
66
+ end
67
+ @@supported_version_numbers.reverse!
68
+ end
69
+
70
+ def self.supported_versions(requested_version_number=nil)
71
+ supported_version_numbers.collect do |supported_version_number|
72
+ if requested_version_number.nil? || supported_version_number <= requested_version_number
73
+ :"v#{supported_version_number}"
74
+ end
75
+ end
76
+ end
77
+
78
+ def self.supports_version?(version)
79
+ supported_version_numbers.include? version
80
+ end
81
+
82
+ def self.latest_version
83
+ supported_version_numbers.first
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,3 @@
1
+ module VersionCake
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'versioncake/action_view/template'
2
+ require 'versioncake/action_view/versions'
3
+ require 'versioncake/action_view/lookup_context'
4
+ require 'versioncake/action_view/resolver'
5
+ require 'versioncake/action_controller/versioning'
6
+ require 'versioncake/action_view/railtie'
@@ -0,0 +1,4 @@
1
+ class RendersController < ActionController::Base
2
+ def index
3
+ end
4
+ end
@@ -0,0 +1 @@
1
+ index.html.erb
@@ -0,0 +1 @@
1
+ index.v1.html.erb
@@ -0,0 +1 @@
1
+ index.v2.html.erb
@@ -0,0 +1,13 @@
1
+ module RendersTest
2
+ class Application < Rails::Application
3
+ config.encoding = "utf-8"
4
+ config.filter_parameters += [:password]
5
+ config.active_support.escape_html_entities_in_json = true
6
+ config.active_record.whitelist_attributes = true
7
+ config.assets.enabled = true
8
+ config.assets.version = '1.0'
9
+ config.active_support.deprecation = :stderr
10
+ config.view_versions = (1..4)
11
+ config.view_version_extraction_strategy = :http_header
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/test.sqlite3
4
+ timeout: 5000
@@ -0,0 +1,3 @@
1
+ RendersTest::Application.routes.draw do
2
+ resources :renders
3
+ end
data/spec/config.ru ADDED
File without changes
File without changes
@@ -0,0 +1 @@
1
+ partial
@@ -0,0 +1 @@
1
+ partial version 1
@@ -0,0 +1 @@
1
+ partial base
@@ -0,0 +1 @@
1
+ partial version 3
@@ -0,0 +1 @@
1
+ another versioned partial
@@ -0,0 +1 @@
1
+ another versioned partial v1
@@ -0,0 +1 @@
1
+ unversioned template
@@ -0,0 +1 @@
1
+ template
@@ -0,0 +1 @@
1
+ template v1
@@ -0,0 +1 @@
1
+ template v2
@@ -0,0 +1 @@
1
+ template v3
data/spec/script/rails ADDED
File without changes
@@ -0,0 +1,27 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ require 'versioncake'
5
+ require 'rspec'
6
+ require 'rails/all'
7
+ require 'rspec/rails'
8
+ require 'config/application'
9
+
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
+
13
+ ENV["RAILS_ENV"] ||= 'test'
14
+
15
+ root = File.expand_path(File.dirname(__FILE__))
16
+
17
+ # Initialize the application
18
+ RendersTest::Application.initialize!
19
+
20
+ RSpec.configure do |config|
21
+ config.mock_with :mocha
22
+ end
23
+
24
+ FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
25
+ FIXTURES = Pathname.new(FIXTURE_LOAD_PATH)
26
+
27
+ Dir.glob(File.dirname(__FILE__) + "/app/controllers/**/*").each{|f| require(f) if File.file?(f)}
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+
3
+ describe "RenderTestCases" do
4
+
5
+ before do
6
+ path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
7
+ view_paths = ActionView::PathSet.new([path])
8
+ @view = ActionView::Base.new(view_paths,{})
9
+ end
10
+
11
+ it "renders the unversioned template (regression)" do
12
+ @view.lookup_context.versions = [:v0]
13
+ @view.render(:template => "templates/versioned").should == "template"
14
+ end
15
+
16
+ it "renders the latest version of the template" do
17
+ @view.render(:template => "templates/versioned").should == "template v3"
18
+ end
19
+
20
+ it "renders the overridden version of the template" do
21
+ @view.render(:template => "templates/versioned", :versions => :v1).should == "template v1"
22
+ end
23
+
24
+ it "renders the legacy version of the template" do
25
+ @view.lookup_context.versions = [:v2]
26
+ @view.render(:template => "templates/versioned").should == "template v2"
27
+ end
28
+
29
+ it "renders the latest available version of the requested template" do
30
+ @view.lookup_context.versions = [:v4,:v3,:v2,:v1]
31
+ @view.render(:template => "templates/versioned").should == "template v3"
32
+ end
33
+
34
+ end
@@ -0,0 +1,12 @@
1
+ require "spec_helper"
2
+
3
+ describe "Resolver" do
4
+
5
+ it "extracts the correct handler and format from a versioned template" do
6
+ resolver = ActionView::PathResolver.new
7
+ handler, format = resolver.send "extract_handler_and_format", "/some/path/to/app/views/index.v1.xml.builder", nil
8
+ handler.class.should == ActionView::Template::Handlers::Builder
9
+ format.should == "application/xml"
10
+ end
11
+
12
+ end
@@ -0,0 +1,7 @@
1
+ require "action_controller"
2
+ require "action_controller/base"
3
+
4
+ class RendersController < ActionController::Base
5
+ def index
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ index.html.erb
@@ -0,0 +1 @@
1
+ index.v1.html.erb
@@ -0,0 +1 @@
1
+ index.v2.html.erb
@@ -0,0 +1,15 @@
1
+ require 'rails/all'
2
+
3
+ module RendersTest
4
+ class Application < Rails::Application
5
+ config.encoding = "utf-8"
6
+ config.filter_parameters += [:password]
7
+ config.active_support.escape_html_entities_in_json = true
8
+ config.active_record.whitelist_attributes = true
9
+ config.assets.enabled = true
10
+ config.assets.version = '1.0'
11
+ config.active_support.deprecation = :stderr
12
+ config.view_versions = (1..3)
13
+ config.view_version_extraction_strategy = :http_header
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/test.sqlite3
4
+ timeout: 5000
@@ -0,0 +1,3 @@
1
+ RendersTest::Application.routes.draw do
2
+ resources :renders
3
+ end
data/test/config.ru ADDED
File without changes
File without changes
@@ -0,0 +1,145 @@
1
+ require 'test_helper'
2
+
3
+ require "action_controller"
4
+ require "action_controller/test_case"
5
+
6
+ class RendersControllerTest < ActionController::TestCase
7
+ test "render latest version of partial" do
8
+ get :index
9
+ assert_equal @response.body, "index.v2.html.erb"
10
+ end
11
+
12
+ test "exposes the requested version" do
13
+ get :index, "api_version" => "1"
14
+ assert_equal @controller.requested_version, 1
15
+ end
16
+
17
+ test "exposes latest version when requesting the latest" do
18
+ get :index, "api_version" => "4"
19
+ assert @controller.is_latest_version
20
+ end
21
+
22
+ test "reports not the latest version" do
23
+ get :index, "api_version" => "1"
24
+ assert !@controller.is_latest_version
25
+ end
26
+ end
27
+
28
+ class ParameterStragegyTest < ActionController::TestCase
29
+ tests RendersController
30
+
31
+ setup do
32
+ ActionView::Template::Versions.extraction_strategy = :query_parameter
33
+ end
34
+
35
+ test "render version 1 of the partial based on the parameter _api_version" do
36
+ get :index, "api_version" => "1"
37
+ assert_equal @response.body, "index.v1.html.erb"
38
+ end
39
+
40
+ test "render version 2 of the partial based on the parameter _api_version" do
41
+ get :index, "api_version" => "2"
42
+ assert_equal @response.body, "index.v2.html.erb"
43
+ end
44
+
45
+ test "render the latest available version (v2) of the partial based on the parameter _api_version" do
46
+ get :index, "api_version" => "3"
47
+ assert_equal @response.body, "index.v2.html.erb"
48
+ end
49
+ end
50
+
51
+ class CustomHeaderStrategyTest < ActionController::TestCase
52
+ tests RendersController
53
+
54
+ setup do
55
+ ActionView::Template::Versions.extraction_strategy = :http_header
56
+ end
57
+
58
+ test "renders version 1 of the partial based on the header API-Version" do
59
+ @controller.request.stubs(:headers).returns({"HTTP_API_VERSION" => "1"})
60
+ get :index
61
+ assert_equal @response.body, "index.v1.html.erb"
62
+ end
63
+
64
+ test "renders version 2 of the partial based on the header API-Version" do
65
+ @controller.request.stubs(:headers).returns({"HTTP_API_VERSION" => "2"})
66
+ get :index
67
+ assert_equal @response.body, "index.v2.html.erb"
68
+ end
69
+
70
+ test "renders the latest available version (v2) of the partial based on the header API-Version" do
71
+ @controller.request.stubs(:headers).returns({"HTTP_API_VERSION" => "3"})
72
+ get :index
73
+ assert_equal @response.body, "index.v2.html.erb"
74
+ end
75
+ end
76
+
77
+ class AcceptHeaderStrategyTest < ActionController::TestCase
78
+ tests RendersController
79
+
80
+ setup do
81
+ ActionView::Template::Versions.extraction_strategy = :http_accept_parameter
82
+ end
83
+
84
+ test "render version 1 of the partial based on the header Accept" do
85
+ @controller.request.stubs(:headers).returns({"HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;api_version=1"})
86
+ get :index
87
+ assert_equal @response.body, "index.v1.html.erb"
88
+ end
89
+
90
+ test "render version 2 of the partial based on the header Accept" do
91
+ @controller.request.stubs(:headers).returns({"HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;api_version=2"})
92
+ get :index
93
+ assert_equal @response.body, "index.v2.html.erb"
94
+ end
95
+
96
+ test "render the latest available version (v2) of the partial based on the header Accept" do
97
+ @controller.request.stubs(:headers).returns({"HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;api_version=3"})
98
+ get :index
99
+ assert_equal @response.body, "index.v2.html.erb"
100
+ end
101
+
102
+ test "render the latest version of the partial" do
103
+ @controller.request.stubs(:headers).returns({"HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;api_version=abc"})
104
+ get :index
105
+ assert_equal @response.body, "index.v2.html.erb"
106
+ end
107
+ end
108
+
109
+ class CustomStrategyTest < ActionController::TestCase
110
+ tests RendersController
111
+
112
+ setup do
113
+ ActionView::Template::Versions.extraction_strategy = lambda { |request| 2 }
114
+ end
115
+
116
+ test "renders version 2 of the partial based on the header Accept" do
117
+ get :index
118
+ assert_equal @response.body, "index.v2.html.erb"
119
+ end
120
+ end
121
+
122
+ class MultipleStrategyTest < ActionController::TestCase
123
+ tests RendersController
124
+
125
+ setup do
126
+ ActionView::Template::Versions.extraction_strategy = [:http_accept_parameter, :query_parameter]
127
+ end
128
+
129
+ test "renders version 1 of the partial based on the header Accept" do
130
+ @controller.request.stubs(:headers).returns({"HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;api_version=1"})
131
+ get :index
132
+ assert_equal @response.body, "index.v1.html.erb"
133
+ end
134
+
135
+ test "renders the query parameter when accept parameter isn't available" do
136
+ get :index, "api_version" => "1"
137
+ assert_equal @response.body, "index.v1.html.erb"
138
+ end
139
+
140
+ test "renders the higher priority accept parameter version" do
141
+ @controller.request.stubs(:headers).returns({"HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;api_version=2"})
142
+ get :index, "api_version" => "1"
143
+ assert_equal @response.body, "index.v2.html.erb"
144
+ end
145
+ end
data/test/script/rails ADDED
File without changes
@@ -0,0 +1,32 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ require 'versioncake'
5
+
6
+ ENV["RAILS_ENV"] = 'test'
7
+
8
+ require 'rails/all'
9
+ require 'rails/test_help'
10
+ require 'test/unit'
11
+
12
+
13
+ require File.expand_path('../config/application', __FILE__)
14
+
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
17
+
18
+ root = File.expand_path(File.dirname(__FILE__))
19
+
20
+ class ActiveSupport::TestCase
21
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
22
+ #
23
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
24
+ # -- they do not yet inherit this setting
25
+ fixtures :all
26
+
27
+ # Add more helper methods to be used by all tests here...
28
+ end
29
+
30
+ RendersTest::Application.initialize!
31
+
32
+ Dir.glob(File.dirname(__FILE__) + "/app/controllers/**/*").each{|f| require(f) if File.file?(f)}
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "versioncake/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "versioncake"
7
+ s.version = VersionCake::VERSION
8
+ s.authors = ["Jim Jones", "Ben Willis"]
9
+ s.email = ["jim.jones1@gmail.com", "benjamin.willis@gmail.com"]
10
+ s.homepage = "https://github.com/bwillis/versioncake"
11
+ s.summary = %q{Easily render versions of your rails views.}
12
+ s.description = %q{Render versioned views automagically based on the clients requested version.}
13
+
14
+ #s.rubyforge_project = ""
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rspec-rails"
22
+ s.add_development_dependency "mocha"
23
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: versioncake
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jim Jones
9
+ - Ben Willis
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-09-13 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec-rails
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: mocha
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ description: Render versioned views automagically based on the clients requested version.
48
+ email:
49
+ - jim.jones1@gmail.com
50
+ - benjamin.willis@gmail.com
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - .gitignore
56
+ - .travis.yml
57
+ - Gemfile
58
+ - Gemfile.lock
59
+ - README.md
60
+ - Rakefile
61
+ - lib/versioncake.rb
62
+ - lib/versioncake/action_controller/versioning.rb
63
+ - lib/versioncake/action_view/lookup_context.rb
64
+ - lib/versioncake/action_view/railtie.rb
65
+ - lib/versioncake/action_view/resolver.rb
66
+ - lib/versioncake/action_view/template.rb
67
+ - lib/versioncake/action_view/versions.rb
68
+ - lib/versioncake/version.rb
69
+ - spec/app/controllers/renders_controller.rb
70
+ - spec/app/views/renders/index.html.erb
71
+ - spec/app/views/renders/index.v1.html.erb
72
+ - spec/app/views/renders/index.v2.html.erb
73
+ - spec/config.ru
74
+ - spec/config/application.rb
75
+ - spec/config/database.yml
76
+ - spec/config/routes.rb
77
+ - spec/db/test.sqlite3
78
+ - spec/fixtures/partials/_versioned.erb
79
+ - spec/fixtures/partials/_versioned.v1.erb
80
+ - spec/fixtures/partials/_versioned.v2.erb
81
+ - spec/fixtures/partials/_versioned.v3.erb
82
+ - spec/fixtures/partials/another_versioned_partial.erb
83
+ - spec/fixtures/partials/another_versioned_partial.v1.erb
84
+ - spec/fixtures/templates/unversioned.html.erb
85
+ - spec/fixtures/templates/versioned.html.erb
86
+ - spec/fixtures/templates/versioned.v1.html.erb
87
+ - spec/fixtures/templates/versioned.v2.html.erb
88
+ - spec/fixtures/templates/versioned.v3.html.erb
89
+ - spec/script/rails
90
+ - spec/spec_helper.rb
91
+ - spec/template/render_spec.rb
92
+ - spec/template/resolver_spec.rb
93
+ - test/app/controllers/renders_controller.rb
94
+ - test/app/views/renders/index.html.erb
95
+ - test/app/views/renders/index.v1.html.erb
96
+ - test/app/views/renders/index.v2.html.erb
97
+ - test/config.ru
98
+ - test/config/application.rb
99
+ - test/config/database.yml
100
+ - test/config/routes.rb
101
+ - test/db/test.sqlite3
102
+ - test/functional/renders_controller_test.rb
103
+ - test/script/rails
104
+ - test/test_helper.rb
105
+ - versioncake.gemspec
106
+ homepage: https://github.com/bwillis/versioncake
107
+ licenses: []
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 1.8.19
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: Easily render versions of your rails views.
130
+ test_files:
131
+ - spec/app/controllers/renders_controller.rb
132
+ - spec/app/views/renders/index.html.erb
133
+ - spec/app/views/renders/index.v1.html.erb
134
+ - spec/app/views/renders/index.v2.html.erb
135
+ - spec/config.ru
136
+ - spec/config/application.rb
137
+ - spec/config/database.yml
138
+ - spec/config/routes.rb
139
+ - spec/db/test.sqlite3
140
+ - spec/fixtures/partials/_versioned.erb
141
+ - spec/fixtures/partials/_versioned.v1.erb
142
+ - spec/fixtures/partials/_versioned.v2.erb
143
+ - spec/fixtures/partials/_versioned.v3.erb
144
+ - spec/fixtures/partials/another_versioned_partial.erb
145
+ - spec/fixtures/partials/another_versioned_partial.v1.erb
146
+ - spec/fixtures/templates/unversioned.html.erb
147
+ - spec/fixtures/templates/versioned.html.erb
148
+ - spec/fixtures/templates/versioned.v1.html.erb
149
+ - spec/fixtures/templates/versioned.v2.html.erb
150
+ - spec/fixtures/templates/versioned.v3.html.erb
151
+ - spec/script/rails
152
+ - spec/spec_helper.rb
153
+ - spec/template/render_spec.rb
154
+ - spec/template/resolver_spec.rb
155
+ - test/app/controllers/renders_controller.rb
156
+ - test/app/views/renders/index.html.erb
157
+ - test/app/views/renders/index.v1.html.erb
158
+ - test/app/views/renders/index.v2.html.erb
159
+ - test/config.ru
160
+ - test/config/application.rb
161
+ - test/config/database.yml
162
+ - test/config/routes.rb
163
+ - test/db/test.sqlite3
164
+ - test/functional/renders_controller_test.rb
165
+ - test/script/rails
166
+ - test/test_helper.rb