restful_route_version 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/Gemfile +11 -0
  2. data/Gemfile.lock +81 -0
  3. data/LICENSE +3 -0
  4. data/MIT-LICENSE +19 -0
  5. data/README.md +53 -0
  6. data/Rakefile +40 -0
  7. data/VERSION +1 -0
  8. data/lib/restful_route_version.rb +2 -0
  9. data/lib/restful_route_version/dependency_ext.rb +15 -0
  10. data/lib/restful_route_version/inherited_view_resolver.rb +26 -0
  11. data/lib/restful_route_version/railtie.rb +22 -0
  12. data/lib/restful_route_version/version_mapper.rb +109 -0
  13. data/restful_route_version.gemspec +99 -0
  14. data/test/dependency_ext_test.rb +50 -0
  15. data/test/fixture_files/a.rb +2 -0
  16. data/test/fixture_files/b.rb +2 -0
  17. data/test/fixture_files/c.rb +2 -0
  18. data/test/rails_sandbox/app/controllers/api/v10/articles_controller.rb +10 -0
  19. data/test/rails_sandbox/app/controllers/api/v10/notes_controller.rb +6 -0
  20. data/test/rails_sandbox/app/controllers/api/v10/questions_controller.rb +10 -0
  21. data/test/rails_sandbox/app/controllers/api/v10/songs_controller.rb +26 -0
  22. data/test/rails_sandbox/app/controllers/api/v11/articles_controller.rb +9 -0
  23. data/test/rails_sandbox/app/controllers/api/v11/tags_controller.rb +9 -0
  24. data/test/rails_sandbox/app/views/api/v10/songs/_bar.erb +1 -0
  25. data/test/rails_sandbox/app/views/api/v10/songs/create.html.erb +1 -0
  26. data/test/rails_sandbox/app/views/api/v10/songs/foo.html.erb +1 -0
  27. data/test/rails_sandbox/app/views/api/v10/songs/index.html.erb +1 -0
  28. data/test/rails_sandbox/app/views/api/v10/songs/show.html.erb +1 -0
  29. data/test/rails_sandbox/app/views/api/v11/songs/_wow.html.erb +1 -0
  30. data/test/rails_sandbox/app/views/api/v11/songs/bar.html.erb +1 -0
  31. data/test/rails_sandbox/app/views/api/v11/songs/baz.html.erb +1 -0
  32. data/test/rails_sandbox/app/views/api/v11/songs/show.html.erb +1 -0
  33. data/test/test_helper.rb +60 -0
  34. data/test/version_mapper_test.rb +201 -0
  35. metadata +158 -0
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rails", "3.0.7"
4
+ gem "rake"
5
+
6
+ group :test do
7
+ gem "bundler", "~> 1.0.0"
8
+ gem "jeweler", "~> 1.5.2"
9
+ gem 'shoulda'
10
+ end
11
+
@@ -0,0 +1,81 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.7)
6
+ actionpack (= 3.0.7)
7
+ mail (~> 2.2.15)
8
+ actionpack (3.0.7)
9
+ activemodel (= 3.0.7)
10
+ activesupport (= 3.0.7)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.5.0)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.14)
16
+ rack-test (~> 0.5.7)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.7)
19
+ activesupport (= 3.0.7)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.5.0)
22
+ activerecord (3.0.7)
23
+ activemodel (= 3.0.7)
24
+ activesupport (= 3.0.7)
25
+ arel (~> 2.0.2)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.7)
28
+ activemodel (= 3.0.7)
29
+ activesupport (= 3.0.7)
30
+ activesupport (3.0.7)
31
+ arel (2.0.10)
32
+ builder (2.1.2)
33
+ erubis (2.6.6)
34
+ abstract (>= 1.0.0)
35
+ git (1.2.5)
36
+ i18n (0.5.0)
37
+ jeweler (1.5.2)
38
+ bundler (~> 1.0.0)
39
+ git (>= 1.2.5)
40
+ rake
41
+ mail (2.2.19)
42
+ activesupport (>= 2.3.6)
43
+ i18n (>= 0.4.0)
44
+ mime-types (~> 1.16)
45
+ treetop (~> 1.4.8)
46
+ mime-types (1.16)
47
+ polyglot (0.3.1)
48
+ rack (1.2.3)
49
+ rack-mount (0.6.14)
50
+ rack (>= 1.0.0)
51
+ rack-test (0.5.7)
52
+ rack (>= 1.0)
53
+ rails (3.0.7)
54
+ actionmailer (= 3.0.7)
55
+ actionpack (= 3.0.7)
56
+ activerecord (= 3.0.7)
57
+ activeresource (= 3.0.7)
58
+ activesupport (= 3.0.7)
59
+ bundler (~> 1.0)
60
+ railties (= 3.0.7)
61
+ railties (3.0.7)
62
+ actionpack (= 3.0.7)
63
+ activesupport (= 3.0.7)
64
+ rake (>= 0.8.7)
65
+ thor (~> 0.14.4)
66
+ rake (0.8.7)
67
+ shoulda (2.11.3)
68
+ thor (0.14.6)
69
+ treetop (1.4.9)
70
+ polyglot (>= 0.3.1)
71
+ tzinfo (0.3.27)
72
+
73
+ PLATFORMS
74
+ ruby
75
+
76
+ DEPENDENCIES
77
+ bundler (~> 1.0.0)
78
+ jeweler (~> 1.5.2)
79
+ rails (= 3.0.7)
80
+ rake
81
+ shoulda
data/LICENSE ADDED
@@ -0,0 +1,3 @@
1
+ Copyright (c) 2010 Hemant Kumar ( mail [at] gnufied [dot] org )
2
+
3
+ The Library is dual licensed under terms of Ruby License or MIT License.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Hemant Kumar ( mail [at] gnufied [dot] org )
2
+ Permission is hereby granted, free of charge, to any person obtaining
3
+ a copy of this software and associated documentation files (the
4
+ "Software"), to deal in the Software without restriction, including
5
+ without limitation the rights to use, copy, modify, merge, publish,
6
+ distribute, sublicense, and/or sell copies of the Software, and to
7
+ permit persons to whom the Software is furnished to do so, subject to
8
+ the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be
11
+ included in all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
17
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ # Restful Route Version #
2
+
3
+ ### Useful for creating inheritable routes and controllers ###
4
+
5
+ Features
6
+ ----------
7
+
8
+ 1. It extends routing API of rails, letting us inherit routes between versions:
9
+
10
+ ```ruby
11
+ version_namespace :api do
12
+ version_namespace(:v10,:cache_route => true) do
13
+ resources :articles
14
+ resources :comments
15
+ resources :notes
16
+ end
17
+
18
+ version_namespace(:v11, :cache_route => true) do
19
+ inherit_routes("/api/v10", :except => %w(articles))
20
+ resources :articles
21
+ resources :tags
22
+ end
23
+
24
+ version_namespace(:v12) do
25
+ inherit_routes("/api/v11",:except => %w(notes))
26
+ resources :lessons
27
+ end
28
+ end
29
+ ```
30
+
31
+ Important thing to remember is only routes which were cached via `cache_route => true` can be
32
+ reused for inheritance. Normal namespace blocks aren't cached.
33
+
34
+ 2. Dynamically defines controllers between versions. In other words if v11 inherits 'notes' route
35
+ from v10, and v11 doesn't have its own NotesController defined the, plugin will
36
+ automatically define `Api::V11::NotesController` which will inherit from `Api::V10::NotesController`.
37
+
38
+
39
+ 3. Inherits view files (such as index.xml.builder) between versions. For example if `V11::ArticlesController`
40
+ inherits `V10::ArticlesController` it will as well inherit all the view files of `v10/articles/`
41
+ and hence there won't be any need to copy the view files around when creating new version of the API.
42
+
43
+
44
+ Template inheritance will work out of box on Rails 3.1, but if you are still on 3.0.x series,
45
+ you can use it now :
46
+
47
+ ```ruby
48
+ class Api::V10::BaseController < ActionController::Base
49
+ restful_route_version
50
+ end
51
+ ```
52
+
53
+ 4. Works with Ruby 1.9.2 and Ruby 1.8.7
@@ -0,0 +1,40 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ desc "Run tests"
4
+ task :test do
5
+ test_files = Dir["test/*_test.rb"]
6
+ $:.unshift(File.dirname(__FILE__)) unless
7
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
8
+ test_files.each { |x| load(x) }
9
+ end
10
+
11
+
12
+ begin
13
+ gem 'jeweler', '~> 1.4'
14
+ require 'jeweler'
15
+
16
+ Jeweler::Tasks.new do |gem|
17
+ gem.name = 'restful_route_version'
18
+ gem.summary = 'Versioning your routes in Rails3'
19
+ gem.description = 'Versioning your routes in Rails3'
20
+ gem.email = 'gethemant@gmail.com'
21
+
22
+ gem.homepage = 'http://github.com/gnufied/%s' % gem.name
23
+
24
+ gem.authors = [ 'Hemant Kumar']
25
+
26
+ gem.rubyforge_project = 'restful_route_version'
27
+
28
+ gem.add_dependency 'activesupport', '~> 3.0.0'
29
+ gem.add_dependency 'actionpack', '~> 3.0.0'
30
+ gem.add_dependency 'railties', '~> 3.0.0'
31
+ end
32
+
33
+ Jeweler::GemcutterTasks.new
34
+
35
+ FileList['tasks/**/*.rake'].each { |task| import task }
36
+ rescue LoadError
37
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
38
+ end
39
+
40
+ task(:spec) {} # stub out the spec task for as long as we don't have any specs
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,2 @@
1
+ require 'restful_route_version/railtie'
2
+
@@ -0,0 +1,15 @@
1
+ module RestfulRouteVersion
2
+ module DependencyExt
3
+ mattr_accessor :dynamically_defined_constants
4
+ self.dynamically_defined_constants = Set.new()
5
+
6
+ def remove_unloadable_constants!
7
+ autoloaded_constants.each { |const|
8
+ remove_constant const unless dynamically_defined_constants.include?(const)
9
+ }
10
+ autoloaded_constants.clear
11
+ ActiveSupport::Dependencies::Reference.clear!
12
+ explicitly_unloadable_constants.each { |const| remove_constant const }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module RestfulRouteVersion
2
+
3
+ module ControllerExt
4
+ def restful_route_version
5
+ view_paths.each do |path|
6
+ append_view_path(InheritedViewResolver.new(path.to_s))
7
+ end
8
+ end
9
+ end
10
+
11
+ class InheritedViewResolver < ::ActionView::FileSystemResolver
12
+ def find_templates(name, prefix, partial, details)
13
+ klass = "#{prefix}_controller".camelize.constantize rescue nil
14
+
15
+ return [] if !klass || !(klass < ActionController::Base)
16
+
17
+ ancestor = klass.ancestors.second
18
+ ancestor_prefix = ancestor.name.gsub(/Controller$/, '').underscore
19
+
20
+ templates = super(name, ancestor_prefix, partial, details)
21
+ return templates if templates.present?
22
+ find_templates(name, ancestor_prefix, partial, details)
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ require "rails"
2
+
3
+ require "restful_route_version/dependency_ext"
4
+ require "restful_route_version/version_mapper"
5
+ require "restful_route_version/inherited_view_resolver"
6
+
7
+ module RestfulRouteVersion
8
+ VERSION = '0.0.2'
9
+ class Railtie < Rails::Railtie
10
+
11
+ initializer "restful_route_version.configure_rails_initialization" do
12
+ ActionDispatch::Routing::Mapper.send(:include, RestfulRouteVersion::VersionMapper)
13
+ ActiveSupport::Dependencies.send(:include, RestfulRouteVersion::DependencyExt)
14
+ ActiveSupport::Dependencies.extend(RestfulRouteVersion::DependencyExt)
15
+ ActionController::Base.extend(ControllerExt)
16
+ end
17
+ end
18
+ end
19
+
20
+
21
+
22
+
@@ -0,0 +1,109 @@
1
+ module RestfulRouteVersion
2
+ module VersionMapper
3
+ attr_accessor :cached_namespace_blocks
4
+ def version_namespace(path, options = {}, &block)
5
+ #puts "Calling version_namespace"
6
+ path = path.to_s
7
+ options = { :path => path, :as => path, :module => path,
8
+ :shallow_path => path, :shallow_prefix => path }.merge!(options)
9
+
10
+ @cached_namespace_blocks ||= {}
11
+
12
+
13
+ scope(options) {
14
+ create_controller_class(@scope[:module].to_s.camelize,Module.new)
15
+ @cached_namespace_blocks[@scope[:path]] = block if options[:cache_route]
16
+ block.call
17
+ }
18
+ end
19
+
20
+ def resources(*resources, &block)
21
+ except_options = @scope[:options][:except]
22
+ return if skip_resource?(resources,except_options)
23
+ super(*resources, &block)
24
+ end
25
+
26
+ def resource(*resources, &block)
27
+ except_options = @scope[:options][:except]
28
+ return if skip_resource?(resources,except_options)
29
+ super(*resources, &block)
30
+ end
31
+
32
+ def skip_resource?(resources, except_options)
33
+ #puts "********** incoming #{resources.inspect} and except_options #{except_options.inspect} and path #{@scope[:path]} **********"
34
+ return false if(resources.length > 1 || except_options.blank?)
35
+ return true if except_options.include?(resources.first.to_s)
36
+ false
37
+ end
38
+
39
+ def inherit_routes(*entities)
40
+ #puts "Current path #{@scope[:path]} and old one #{entities.first}"
41
+ options = entities.extract_options!
42
+ new_options = merge_except_options(options)
43
+ #puts "New options are #{new_options.inspect}"
44
+ new_options[:old_namespace] = @scope[:options][:old_namespace] || entities.dup.shift
45
+
46
+
47
+ entities.each { |entity|
48
+ inherited_route_block = @cached_namespace_blocks[entity]
49
+ inherited_route_block && scope(new_options) do
50
+ inherited_route_block.call()
51
+ end
52
+ }
53
+ create_derived_controllers(new_options[:old_namespace], new_options)
54
+ end
55
+
56
+ def merge_except_options(options)
57
+ options[:except] ||= []
58
+ options[:namespace] = @scope[:path]
59
+ if old_exception_option = @scope[:options][:except]
60
+ options[:except] += old_exception_option
61
+ end
62
+ options
63
+ end
64
+
65
+ def create_derived_controllers(old_namespace, options = {})
66
+ old_namespace.gsub!(/^\/?/,'')
67
+ current_namespace = options[:namespace].gsub(/^\/?/,'')
68
+ Dir["#{Rails.root}/app/controllers/#{old_namespace}/*.rb"].each do |controller_file_name|
69
+ require_or_load(controller_file_name)
70
+ end
71
+
72
+ exclude_constants = options[:except].blank? ? [] : options[:except]
73
+
74
+ controllers_to_exclude = exclude_constants.map { |x| (old_namespace + "/#{x}Controller").camelize }
75
+ #puts "Old namespace is #{old_namespace}"
76
+ old_namespace.camelize.constantize.constants.each do |constant_name|
77
+ #puts "Incoming constant #{constant_name}"
78
+ full_constant_name = old_namespace.camelize + "::" + constant_name.to_s
79
+ new_controller_name = "#{current_namespace.camelize}::#{constant_name}"
80
+ #puts "Defining constant #{new_controller_name} with parent #{full_constant_name}"
81
+ if create_controller_dynamically?(controllers_to_exclude, full_constant_name, new_controller_name)
82
+ create_controller_class(new_controller_name,Class.new(full_constant_name.constantize))
83
+ end
84
+ end
85
+ end
86
+
87
+ def create_controller_dynamically?(controllers_to_exclude, old_controller_name, new_controller_name)
88
+ !controllers_to_exclude.include?(old_controller_name) &&
89
+ old_controller_name =~ /Controller$/ &&
90
+ !File.exists?("#{Rails.root}/app/controllers/#{new_controller_name.underscore}.rb")
91
+ end
92
+
93
+
94
+ def create_controller_class(full_constant_name, klass_constant)
95
+ #puts "Full constant_name is #{full_constant_name}"
96
+ names = full_constant_name.split('::')
97
+ ActiveSupport::Dependencies.dynamically_defined_constants << full_constant_name
98
+ names.shift if names.empty? || names.first.empty?
99
+ constant = Object
100
+ names.each do |name|
101
+ if constant.const_defined?(name)
102
+ constant = constant.const_get(name)
103
+ else
104
+ constant = constant.const_set(name, klass_constant)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,99 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{restful_route_version}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Hemant Kumar"]
12
+ s.date = %q{2011-06-12}
13
+ s.description = %q{Versioning your routes in Rails3}
14
+ s.email = %q{gethemant@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "LICENSE",
23
+ "MIT-LICENSE",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/restful_route_version.rb",
28
+ "lib/restful_route_version/dependency_ext.rb",
29
+ "lib/restful_route_version/inherited_view_resolver.rb",
30
+ "lib/restful_route_version/railtie.rb",
31
+ "lib/restful_route_version/version_mapper.rb",
32
+ "restful_route_version.gemspec",
33
+ "test/dependency_ext_test.rb",
34
+ "test/fixture_files/a.rb",
35
+ "test/fixture_files/b.rb",
36
+ "test/fixture_files/c.rb",
37
+ "test/rails_sandbox/app/controllers/api/v10/articles_controller.rb",
38
+ "test/rails_sandbox/app/controllers/api/v10/notes_controller.rb",
39
+ "test/rails_sandbox/app/controllers/api/v10/questions_controller.rb",
40
+ "test/rails_sandbox/app/controllers/api/v10/songs_controller.rb",
41
+ "test/rails_sandbox/app/controllers/api/v11/articles_controller.rb",
42
+ "test/rails_sandbox/app/controllers/api/v11/tags_controller.rb",
43
+ "test/rails_sandbox/app/views/api/v10/songs/_bar.erb",
44
+ "test/rails_sandbox/app/views/api/v10/songs/create.html.erb",
45
+ "test/rails_sandbox/app/views/api/v10/songs/foo.html.erb",
46
+ "test/rails_sandbox/app/views/api/v10/songs/index.html.erb",
47
+ "test/rails_sandbox/app/views/api/v10/songs/show.html.erb",
48
+ "test/rails_sandbox/app/views/api/v11/songs/_wow.html.erb",
49
+ "test/rails_sandbox/app/views/api/v11/songs/bar.html.erb",
50
+ "test/rails_sandbox/app/views/api/v11/songs/baz.html.erb",
51
+ "test/rails_sandbox/app/views/api/v11/songs/show.html.erb",
52
+ "test/test_helper.rb",
53
+ "test/version_mapper_test.rb"
54
+ ]
55
+ s.homepage = %q{http://github.com/gnufied/restful_route_version}
56
+ s.require_paths = ["lib"]
57
+ s.rubyforge_project = %q{restful_route_version}
58
+ s.rubygems_version = %q{1.6.2}
59
+ s.summary = %q{Versioning your routes in Rails3}
60
+ s.test_files = [
61
+ "test/dependency_ext_test.rb",
62
+ "test/fixture_files/a.rb",
63
+ "test/fixture_files/b.rb",
64
+ "test/fixture_files/c.rb",
65
+ "test/rails_sandbox/app/controllers/api/v10/articles_controller.rb",
66
+ "test/rails_sandbox/app/controllers/api/v10/notes_controller.rb",
67
+ "test/rails_sandbox/app/controllers/api/v10/questions_controller.rb",
68
+ "test/rails_sandbox/app/controllers/api/v10/songs_controller.rb",
69
+ "test/rails_sandbox/app/controllers/api/v11/articles_controller.rb",
70
+ "test/rails_sandbox/app/controllers/api/v11/tags_controller.rb",
71
+ "test/test_helper.rb",
72
+ "test/version_mapper_test.rb"
73
+ ]
74
+
75
+ if s.respond_to? :specification_version then
76
+ s.specification_version = 3
77
+
78
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
79
+ s.add_runtime_dependency(%q<rails>, ["= 3.0.7"])
80
+ s.add_runtime_dependency(%q<rake>, [">= 0"])
81
+ s.add_runtime_dependency(%q<activesupport>, ["~> 3.0.0"])
82
+ s.add_runtime_dependency(%q<actionpack>, ["~> 3.0.0"])
83
+ s.add_runtime_dependency(%q<railties>, ["~> 3.0.0"])
84
+ else
85
+ s.add_dependency(%q<rails>, ["= 3.0.7"])
86
+ s.add_dependency(%q<rake>, [">= 0"])
87
+ s.add_dependency(%q<activesupport>, ["~> 3.0.0"])
88
+ s.add_dependency(%q<actionpack>, ["~> 3.0.0"])
89
+ s.add_dependency(%q<railties>, ["~> 3.0.0"])
90
+ end
91
+ else
92
+ s.add_dependency(%q<rails>, ["= 3.0.7"])
93
+ s.add_dependency(%q<rake>, [">= 0"])
94
+ s.add_dependency(%q<activesupport>, ["~> 3.0.0"])
95
+ s.add_dependency(%q<actionpack>, ["~> 3.0.0"])
96
+ s.add_dependency(%q<railties>, ["~> 3.0.0"])
97
+ end
98
+ end
99
+
@@ -0,0 +1,50 @@
1
+ require_relative "test_helper"
2
+
3
+ class RestfulRouteVersionDependenciesTest < Test::Unit::TestCase
4
+ context "For RestfulRouteVersionDependencies" do
5
+ setup do
6
+ ActiveSupport::Dependencies.dynamically_defined_constants << "Foo"
7
+ ActiveSupport::Dependencies.dynamically_defined_constants << "Bar"
8
+ ActiveSupport::Dependencies.dynamically_defined_constants << "C"
9
+ end
10
+
11
+ should "only remove constants which were not dynamically defined" do
12
+ with_autoloading_fixtures do
13
+ Object.const_set(:Foo,Class.new)
14
+ Object.const_set(:Bar,Class.new)
15
+ Object.const_get(:A)
16
+ Object.const_get(:B)
17
+ Object.const_get(:C)
18
+ ActiveSupport::Dependencies.clear
19
+ assert !Object.const_defined?(:A)
20
+ assert !Object.const_defined?(:B)
21
+ assert Object.const_defined?(:Foo)
22
+ assert Object.const_defined?(:Bar)
23
+ assert Object.const_defined?(:C)
24
+ end
25
+ end
26
+ end
27
+
28
+ def with_loading(*from)
29
+ old_mechanism, ActiveSupport::Dependencies.mechanism = ActiveSupport::Dependencies.mechanism, :load
30
+ this_dir = File.dirname(__FILE__)
31
+ parent_dir = File.dirname(this_dir)
32
+ path_copy = $LOAD_PATH.dup
33
+ $LOAD_PATH.unshift(parent_dir) unless $LOAD_PATH.include?(parent_dir)
34
+ prior_autoload_paths = ActiveSupport::Dependencies.autoload_paths
35
+ ActiveSupport::Dependencies.autoload_paths = from.collect { |f| "#{this_dir}/#{f}" }
36
+ yield
37
+ ensure
38
+ $LOAD_PATH.replace(path_copy)
39
+ ActiveSupport::Dependencies.autoload_paths = prior_autoload_paths
40
+ ActiveSupport::Dependencies.mechanism = old_mechanism
41
+ ActiveSupport::Dependencies.explicitly_unloadable_constants = []
42
+ end
43
+
44
+ def with_autoloading_fixtures(&block)
45
+ with_loading 'fixture_files', &block
46
+ end
47
+
48
+ end
49
+
50
+
@@ -0,0 +1,2 @@
1
+ class A
2
+ end
@@ -0,0 +1,2 @@
1
+ class B
2
+ end
@@ -0,0 +1,2 @@
1
+ class C
2
+ end
@@ -0,0 +1,10 @@
1
+ module Api
2
+ module V10
3
+ class ArticlesController < ActionController::Base
4
+ restful_route_version
5
+ def index
6
+ render :text => "Hello world from v10 ArticlesController"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ class Api::V10::NotesController < ActionController::Base
2
+ restful_route_version
3
+ def index
4
+ render :text => "Hello from V10 notes controller, lolz"
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ module Api
2
+ module V10
3
+ class QuestionsController < ActionController::Base
4
+ restful_route_version
5
+ def index
6
+ render :text => "Hello world from v10 QuestionsController"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ module Api
2
+ module V10
3
+ class SongsController < ActionController::Base
4
+ restful_route_version
5
+ def index
6
+ end
7
+
8
+ def show
9
+
10
+ end
11
+
12
+ def create
13
+ end
14
+
15
+ def foo
16
+ end
17
+
18
+ def bar
19
+
20
+ end
21
+
22
+ def baz
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ module Api
2
+ module V11
3
+ class ArticlesController < Api::V10::ArticlesController
4
+ def index
5
+ render :text => "Hello world from v11 ArticlesController"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Api
2
+ module V11
3
+ class TagsController < ActionController::Base
4
+ def index
5
+ render :text => "Hello world from v11 ArticlesController"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ Calling Songs#create from v10
@@ -0,0 +1 @@
1
+ Calling Foo from <%= render :partial => 'bar' -%>
@@ -0,0 +1 @@
1
+ Hello from v10 of Music#index
@@ -0,0 +1 @@
1
+ Calling Songs#show from v10
@@ -0,0 +1 @@
1
+ Dude this is <%= render :partial => 'bleh' -%>
@@ -0,0 +1 @@
1
+ Hello from <%= render :partial => 'wow' -%> dude
@@ -0,0 +1 @@
1
+ Calling Songs#show from v11
@@ -0,0 +1,60 @@
1
+ require "rubygems"
2
+ gem 'activesupport', '~> 3.0.7'
3
+ gem 'actionpack', '~> 3.0.7'
4
+ gem 'activerecord', '~> 3.0.7'
5
+ gem 'rails', '~> 3.0.7'
6
+
7
+ require "active_support"
8
+ require "active_support/dependencies"
9
+ require "active_support/core_ext/hash/slice"
10
+ require "action_controller"
11
+ require "action_view"
12
+ require "action_pack"
13
+
14
+ require "shoulda"
15
+
16
+ class MockLogger
17
+ attr_reader :logged
18
+
19
+ def initialize
20
+ @logged = []
21
+ end
22
+
23
+ def method_missing(method, *args)
24
+ @logged << args.first
25
+ end
26
+ end
27
+
28
+ class MockBacktraceCleaner < ActiveSupport::BacktraceCleaner
29
+ end
30
+
31
+ $:<< File.join(File.dirname(__FILE__), "..", "lib")
32
+ $:<< File.join(File.dirname(__FILE__), "rails_sandbox", "app", "controllers")
33
+
34
+ require "restful_route_version"
35
+ ActionDispatch::Routing::Mapper.send(:include, RestfulRouteVersion::VersionMapper)
36
+ ActiveSupport::Dependencies.send(:include, RestfulRouteVersion::DependencyExt)
37
+ ActiveSupport::Dependencies.extend(RestfulRouteVersion::DependencyExt)
38
+ ActionController::Base.extend(RestfulRouteVersion::ControllerExt)
39
+
40
+ module Rails
41
+ def self.root
42
+ File.expand_path(File.join(File.dirname(__FILE__), "rails_sandbox"))
43
+ end
44
+
45
+ def self.backtrace_cleaner
46
+ @@backtrace_cleaner ||= MockBacktraceCleaner.new()
47
+ end
48
+ def self.env
49
+ @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test")
50
+ end
51
+
52
+ def self.env_defaults
53
+ {}
54
+ end
55
+
56
+ def self.application
57
+ self
58
+ end
59
+ end
60
+
@@ -0,0 +1,201 @@
1
+ require_relative "test_helper"
2
+
3
+ class VersionMapperTest < Test::Unit::TestCase
4
+ context "Versioned routing extension" do
5
+ setup do
6
+ @route_set = ActionDispatch::Routing::RouteSet.new()
7
+ @mapper = ActionDispatch::Routing::Mapper.new(@route_set)
8
+ end
9
+
10
+ should "provide version_namespace routing method" do
11
+ assert @mapper.respond_to?(:version_namespace)
12
+ end
13
+
14
+ should "capture specified namespace when using version_namespace" do
15
+ route_block = lambda do
16
+ version_namespace("foo") do
17
+ resources :articles
18
+ end
19
+ end
20
+ @mapper.instance_exec(&route_block)
21
+ assert !ActiveSupport::Dependencies.dynamically_defined_constants.blank?
22
+ end
23
+
24
+ should "capture route block if cache_route is true when using version_namespace" do
25
+ route_block = lambda do
26
+ version_namespace("foo", :cache_route => true) do
27
+ resources :articles
28
+ end
29
+ end
30
+ @mapper.instance_exec(&route_block)
31
+ assert !@mapper.cached_namespace_blocks["/foo"].blank?
32
+ end
33
+
34
+ should "provide inherit_routes routing method" do
35
+ assert @mapper.respond_to?(:inherit_routes)
36
+ end
37
+ end
38
+
39
+ context "Restful route extension with inherit_routes" do
40
+ setup do
41
+ @route_set = ActionDispatch::Routing::RouteSet.new()
42
+ @mapper = ActionDispatch::Routing::Mapper.new(@route_set)
43
+
44
+ @route_block = lambda do
45
+ version_namespace :api do
46
+ version_namespace(:v10,:cache_route => true) do
47
+ resources :articles
48
+ resources :comments
49
+ resources :notes
50
+ end
51
+
52
+ version_namespace(:v11, :cache_route => true) do
53
+ inherit_routes("/api/v10", :except => %w(articles))
54
+ resources :articles
55
+ resources :tags
56
+ end
57
+
58
+ version_namespace(:v12) do
59
+ inherit_routes("/api/v11",:except => %w(notes))
60
+ resources :lessons
61
+ end
62
+ end #end of map.version_namespace(:api)
63
+ end #end of route_block
64
+
65
+ end #end of setup block
66
+
67
+ should "create derived routes when using inherit_routes" do
68
+ @mapper.instance_exec(&@route_block)
69
+ v12_tag_route = @route_set.named_routes.routes[:edit_api_v12_tag]
70
+ assert !v12_tag_route.blank?
71
+ assert_match /\/api\/v12\/tags\/\:id\/edit/, v12_tag_route.to_s
72
+ end
73
+
74
+ should "not create routes for except resources" do
75
+ @mapper.instance_exec(&@route_block)
76
+ article_route = @route_set.named_routes.routes[:new_api_v12_article]
77
+ assert !article_route.blank?
78
+
79
+ note_route = @route_set.named_routes.routes[:new_api_v12_note]
80
+ assert note_route.blank?
81
+ end
82
+ end
83
+
84
+ context "Restful route extension with inherit_routes and creating controllers dynamically" do
85
+ setup do
86
+ @route_set = ActionDispatch::Routing::RouteSet.new()
87
+ @mapper = ActionDispatch::Routing::Mapper.new(@route_set)
88
+
89
+ @route_block = lambda do
90
+ version_namespace :api do
91
+ version_namespace(:v10,:cache_route => true) do
92
+ resources :articles
93
+ resources :notes
94
+ end
95
+
96
+ version_namespace(:v11, :cache_route => true) do
97
+ inherit_routes("/api/v10", :except => %w(articles))
98
+ resources :tags
99
+ resources :articles
100
+ end
101
+
102
+ version_namespace(:v12) do
103
+ inherit_routes("/api/v11")
104
+ resources :lessons
105
+ end
106
+
107
+ end #end of map.version_namespace(:api)
108
+ end #end of route_block
109
+ end #end of setup block
110
+
111
+ should "automatically load classes which has to be loaded dynamically" do
112
+ @mapper.instance_exec(&@route_block)
113
+ assert defined?(Api::V11::NotesController)
114
+ t_superclass = Api::V11::NotesController.superclass.to_s
115
+ assert_equal "Api::V10::NotesController", t_superclass
116
+
117
+ assert defined?(Api::V12::NotesController)
118
+ assert_equal "Api::V11::NotesController", Api::V12::NotesController.superclass.to_s
119
+ end
120
+ end #end of context inherit_routes
121
+
122
+
123
+ context "Inherit controller with except" do
124
+ setup do
125
+ @route_set = ActionDispatch::Routing::RouteSet.new()
126
+ @mapper = ActionDispatch::Routing::Mapper.new(@route_set)
127
+
128
+ @route_block = lambda do
129
+ version_namespace :api do
130
+ version_namespace(:v10,:cache_route => true) do
131
+ resources :articles
132
+ resources :notes
133
+ end
134
+
135
+ version_namespace(:v11, :cache_route => true) do
136
+ inherit_routes("api/v10", :except => %w(articles))
137
+ resources :tags
138
+ resources :articles
139
+ end
140
+
141
+ version_namespace(:v12) do
142
+ inherit_routes("api/v11", :except => %w(tags))
143
+ resources :lessons
144
+ end
145
+
146
+ end #end of map.version_namespace(:api)
147
+ end #end of route_block
148
+ end #end of setup block
149
+
150
+ should "not create controllers in only specified namespace" do
151
+ @mapper.instance_exec(&@route_block)
152
+ ActiveSupport::Dependencies.remove_constant("Api::V12::TagsController")
153
+
154
+ assert defined?(Api::V11::ArticlesController)
155
+ assert defined?(Api::V12::ArticlesController)
156
+ assert (Api::V12::ArticlesController < Api::V11::ArticlesController)
157
+ assert (Api::V12::NotesController < Api::V11::NotesController)
158
+ assert (Api::V11::NotesController < Api::V10::NotesController)
159
+ assert !defined?(Api::V12::TagsController)
160
+ end
161
+ end
162
+
163
+ context "Inherit controller with except for non-existant" do
164
+ setup do
165
+ ActiveSupport::Dependencies.remove_constant("Api::V11::QuestionsController")
166
+ ActiveSupport::Dependencies.remove_constant("Api::V12::QuestionsController")
167
+ @route_set = ActionDispatch::Routing::RouteSet.new()
168
+ @mapper = ActionDispatch::Routing::Mapper.new(@route_set)
169
+
170
+ @route_block = lambda do
171
+ version_namespace :api do
172
+ version_namespace(:v10,:cache_route => true) do
173
+ resources :articles
174
+ resources :notes
175
+ resources :questions
176
+ end
177
+
178
+ version_namespace(:v11, :cache_route => true) do
179
+ inherit_routes("api/v10", :except => %w(articles questions))
180
+ resources :tags
181
+ resources :articles
182
+ end
183
+
184
+ version_namespace(:v12) do
185
+ inherit_routes("api/v11")
186
+ resources :lessons
187
+ end
188
+ end #end of map.version_namespace(:api)
189
+ end #end of route_block
190
+
191
+ end #end of setup block
192
+
193
+ should "not create controllers in only specified namespace" do
194
+ @mapper.instance_exec(&@route_block)
195
+ assert defined?(Api::V10::QuestionsController)
196
+ assert !defined?(Api::V11::QuestionsController)
197
+ assert !defined?(Api::V12::QuestionsController)
198
+ end
199
+ end
200
+
201
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: restful_route_version
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.2
6
+ platform: ruby
7
+ authors:
8
+ - Hemant Kumar
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-06-12 00:00:00 +05:30
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rails
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 3.0.7
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: activesupport
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 3.0.0
46
+ type: :runtime
47
+ prerelease: false
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: actionpack
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 3.0.0
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: railties
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 3.0.0
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: *id005
71
+ description: Versioning your routes in Rails3
72
+ email: gethemant@gmail.com
73
+ executables: []
74
+
75
+ extensions: []
76
+
77
+ extra_rdoc_files:
78
+ - LICENSE
79
+ - README.md
80
+ files:
81
+ - Gemfile
82
+ - Gemfile.lock
83
+ - LICENSE
84
+ - MIT-LICENSE
85
+ - README.md
86
+ - Rakefile
87
+ - VERSION
88
+ - lib/restful_route_version.rb
89
+ - lib/restful_route_version/dependency_ext.rb
90
+ - lib/restful_route_version/inherited_view_resolver.rb
91
+ - lib/restful_route_version/railtie.rb
92
+ - lib/restful_route_version/version_mapper.rb
93
+ - restful_route_version.gemspec
94
+ - test/dependency_ext_test.rb
95
+ - test/fixture_files/a.rb
96
+ - test/fixture_files/b.rb
97
+ - test/fixture_files/c.rb
98
+ - test/rails_sandbox/app/controllers/api/v10/articles_controller.rb
99
+ - test/rails_sandbox/app/controllers/api/v10/notes_controller.rb
100
+ - test/rails_sandbox/app/controllers/api/v10/questions_controller.rb
101
+ - test/rails_sandbox/app/controllers/api/v10/songs_controller.rb
102
+ - test/rails_sandbox/app/controllers/api/v11/articles_controller.rb
103
+ - test/rails_sandbox/app/controllers/api/v11/tags_controller.rb
104
+ - test/rails_sandbox/app/views/api/v10/songs/_bar.erb
105
+ - test/rails_sandbox/app/views/api/v10/songs/create.html.erb
106
+ - test/rails_sandbox/app/views/api/v10/songs/foo.html.erb
107
+ - test/rails_sandbox/app/views/api/v10/songs/index.html.erb
108
+ - test/rails_sandbox/app/views/api/v10/songs/show.html.erb
109
+ - test/rails_sandbox/app/views/api/v11/songs/_wow.html.erb
110
+ - test/rails_sandbox/app/views/api/v11/songs/bar.html.erb
111
+ - test/rails_sandbox/app/views/api/v11/songs/baz.html.erb
112
+ - test/rails_sandbox/app/views/api/v11/songs/show.html.erb
113
+ - test/test_helper.rb
114
+ - test/version_mapper_test.rb
115
+ has_rdoc: true
116
+ homepage: http://github.com/gnufied/restful_route_version
117
+ licenses: []
118
+
119
+ post_install_message:
120
+ rdoc_options: []
121
+
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: -2262431187530772954
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: "0"
139
+ requirements: []
140
+
141
+ rubyforge_project: restful_route_version
142
+ rubygems_version: 1.6.2
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: Versioning your routes in Rails3
146
+ test_files:
147
+ - test/dependency_ext_test.rb
148
+ - test/fixture_files/a.rb
149
+ - test/fixture_files/b.rb
150
+ - test/fixture_files/c.rb
151
+ - test/rails_sandbox/app/controllers/api/v10/articles_controller.rb
152
+ - test/rails_sandbox/app/controllers/api/v10/notes_controller.rb
153
+ - test/rails_sandbox/app/controllers/api/v10/questions_controller.rb
154
+ - test/rails_sandbox/app/controllers/api/v10/songs_controller.rb
155
+ - test/rails_sandbox/app/controllers/api/v11/articles_controller.rb
156
+ - test/rails_sandbox/app/controllers/api/v11/tags_controller.rb
157
+ - test/test_helper.rb
158
+ - test/version_mapper_test.rb