render_inheritable 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Pascal Zumkehr
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,77 @@
1
+ = RENDER INHERITABLE
2
+
3
+ A Rails 3 plugin that allows one to inherit or override single templates for controller hierarchies. Finally, also views and partials remain DRY!
4
+
5
+ In the default case, a template is searched in the current controller's view folder. If it is not found there, the template with the same name in the view folder of the superclass controller is used. Have a look at the examples for more clarification.
6
+
7
+ Install the gem with
8
+ gem install render_inheritable
9
+
10
+ In your Rails application's +Gemfile+, add
11
+ gem 'render_inheritable'
12
+
13
+ To use inheritable templates in a certain controller hierarchy, add this declaration to the respective base controller:
14
+ render_inheritable
15
+
16
+ That's it, no more duplications in your views and partials.
17
+
18
+ == Example
19
+
20
+ Suppose we have the following files in our Rails app:
21
+
22
+ # controllers/crud_controller.rb:
23
+ class CrudController < ApplicationController
24
+ # use render inheritable for this controller hierarchy
25
+ render_inheritable
26
+
27
+ def index
28
+ # set @entries in subclasses
29
+ end
30
+ ...
31
+ end
32
+
33
+ # controllers/messages_controller.rb:
34
+ class MessagesController < CrudController
35
+ def index
36
+ @entries = Message.all
37
+ end
38
+ ...
39
+ end
40
+
41
+ # views/crud/index.html.erb:
42
+ <h1>Listing</h1>
43
+
44
+ <%= render :partial => 'list' %>
45
+
46
+ <%= link_to 'New Entry', :url => {:action => 'new'} %>
47
+
48
+ # views/crud/_list.html.erb:
49
+ <ul>
50
+ <% @entries.each do |entry| %>
51
+ <li><%= render :partial => 'entry', :object => 'entry' %></li>
52
+ <% end %>
53
+ </ul>
54
+
55
+ # views/crud/_entry.html.erb
56
+ <%= entry.to_s %>
57
+
58
+ Nothing sophisticated, but it will do to explain our little gem. With the call to _render_inheritable_ in the CrudController, we tell all +render+ calls in this controller, its subclasses and their corresponding views to perform a template lookup. What does this mean? When we call the index action of our MessagesController, no corresponding template is found in <i>views/messages/index.html.erb</i>. The lookup proceeds to the superclass controller, where it finds the template in <i>views/crud/index.html.erb</i>. The same holds for the two partials <i>views/crud/_list.html.erb</i> and <i>views/crud/_entry.html.erb</i>.
59
+
60
+ With this mechanism, we are able to define generic templates that are *inherited* to various subclass controllers. There is no need to duplicate templates when they basically look the same.
61
+
62
+ If we need to customize a certain part, it is possible to *override* a single template or partial. Say we would like to present a custom entry for messages. Just introduce the corresponding partial:
63
+
64
+ # views/messages/_entry.html.erb
65
+ <%= entry.title %>: <%= truncate(entry.body, :length => 20) %>
66
+
67
+
68
+ Now, the <code>render :partial => 'entry'</code> call in <i>views/crud/_list.html.erb</i> will find the partial in the <i>views/messages</i> folder and render it. The other two templates do not have to be touched and are still inherited form the <i>views/crud</i> folder. So it's possible to customize certain snippets by specifically overriding partials. For this example, you could also create a partial <i>views/messages/_list.html.erb</i> to display a table instead of a list for messages.
69
+
70
+ Of course, the lookup not only works for HTML templates and partials, but for any format. Even <code>page.replace 'element_id', :partial => 'element'</code> calls in RJS templates benefit from this gem.
71
+
72
+
73
+ == Custom Lookup Paths
74
+
75
+ To support more advanced lookups, it is possible to customize the used lookup path. You may override the method <code>self.template_lookup_path(param = nil)</code> in the controller where you defined +render_inheritable+. This method is expected to return an ordered list of controller_paths where the templates are searched in.
76
+
77
+ With the optional parameter +param+, definable in the controller instance method +template_lookup_param+, lookup paths may even be dynamic. This would allow you, for example, to perform a template lookup based on a type attribute from your model instance. Each type would get an own _views_ subfolder, where specific views or partials might be overriden. These subfolders then would not need to match an existing controller.
data/Rakefile ADDED
@@ -0,0 +1,92 @@
1
+ require 'rubygems'
2
+ require "rake/testtask"
3
+ require 'rake/gempackagetask'
4
+ require 'rake/rdoctask'
5
+ sdoc = (require 'sdoc' || true) rescue false
6
+
7
+ load 'render_inheritable.gemspec'
8
+
9
+ TEST_APP_ROOT = File.join(File.dirname(__FILE__), 'test', 'test_app')
10
+
11
+ task :default => :test
12
+
13
+ desc "Run all tests"
14
+ task :test => ['test:app:init'] do
15
+ Rake::TestTask.new do |test|
16
+ test.libs << "#{TEST_APP_ROOT}/test"
17
+ test.test_files = Dir[ "#{TEST_APP_ROOT}/test/**/*_test.rb" ]
18
+ test.verbose = true
19
+ end
20
+ end
21
+
22
+ namespace :test do
23
+ namespace :app do
24
+ desc "Create a rails test application"
25
+ task :create do
26
+ unless File.exist?(TEST_APP_ROOT)
27
+ sh "rails _3.0.0.beta4_ new #{TEST_APP_ROOT}"
28
+ end
29
+ end
30
+
31
+ desc "Initializes the test application with a couple of classes"
32
+ task :init => :create do
33
+ FileUtils.cp_r(File.join(File.dirname(__FILE__), 'test', 'templates', '.'), TEST_APP_ROOT)
34
+ FileUtils.cd(TEST_APP_ROOT) do
35
+ sh "rake db:migrate db:test:prepare"
36
+ end
37
+ end
38
+
39
+ task :environment => :init do
40
+ ::RAILS_ROOT = TEST_APP_ROOT
41
+ ::RAILS_ENV = 'test'
42
+
43
+ require(File.join(TEST_APP_ROOT, 'config', 'environment'))
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ desc "Clean up all generated resources"
50
+ task :clobber do
51
+ FileUtils.rm_rf(TEST_APP_ROOT)
52
+ end
53
+
54
+ desc "Install render_inheritable as a local gem."
55
+ task :install => [:package] do
56
+ sudo = RUBY_PLATFORM =~ /win32/ ? '' : 'sudo'
57
+ gem = RUBY_PLATFORM =~ /java/ ? 'jgem' : 'gem'
58
+ sh %{#{sudo} #{gem} install --no-ri pkg/render_inheritable-#{File.read('VERSION').strip}}
59
+ end
60
+
61
+ desc "Deploy rdoc to website"
62
+ task :site => :rdoc do
63
+ sh "rsync -rzv rdoc/ #{ENV['DEST']}"
64
+ end
65
+
66
+ # :package task
67
+ Rake::GemPackageTask.new(RENDER_INHERITABLE_GEMSPEC) do |pkg|
68
+ if Rake.application.top_level_tasks.include?('release')
69
+ pkg.need_tar_gz = true
70
+ pkg.need_tar_bz2 = true
71
+ pkg.need_zip = true
72
+ end
73
+ end
74
+
75
+ # :rdoc task
76
+ Rake::RDocTask.new do |rdoc|
77
+ rdoc.title = 'Render Inheritable'
78
+ rdoc.options << '--line-numbers' << '--inline-source'
79
+ if sdoc
80
+ rdoc.options << '--fmt' << 'shtml'
81
+ rdoc.template = 'direct'
82
+ end
83
+ rdoc.rdoc_files.include(*FileList.new('*') do |list|
84
+ list.exclude(/(^|[^.a-z])[a-z]+/)
85
+ list.exclude('TODO')
86
+ end.to_a)
87
+ rdoc.rdoc_files.include('lib/**/*.rb')
88
+ rdoc.rdoc_files.exclude('TODO')
89
+
90
+ rdoc.rdoc_dir = 'rdoc'
91
+ rdoc.main = 'README.rdoc'
92
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0
@@ -0,0 +1,11 @@
1
+ module AbstractController
2
+ # Add a simple render_inheritable method to AbstractController
3
+ # to define that rendering should perform a lookup.
4
+ class Base
5
+ # Tell the controller, its subclasses and views to use inheritable rendering.
6
+ def self.render_inheritable
7
+ include RenderInheritable
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,153 @@
1
+ require File.join(File.dirname(__FILE__), 'rails_integration')
2
+
3
+ # Allows one to render inheritable views and partials.
4
+ # If no view file is found for the current controller, the corresponding file
5
+ # is looked up in its superclass hierarchy. This module must only be
6
+ # included in the root controller of the desired lookup hierarchy.
7
+ #
8
+ # By default, this module only supports direct inheritance over one level. By overriding
9
+ # the method lookup_path, you may define a custom lookup path. By providing an object
10
+ # for the 'with' parameter, this path may even be dynamic.
11
+ module RenderInheritable
12
+
13
+ # Add inheritable_root_path method to including controller.
14
+ def self.included(controller_class)
15
+ controller_class.send(:extend, ClassMethods)
16
+
17
+ controller_class.send(:class_variable_set, :@@inheritable_root_controller, controller_class)
18
+ controller_class.cattr_reader :inheritable_root_controller
19
+ end
20
+
21
+ # Performs a lookup for the given filename and returns the most specific
22
+ # folder that contains the file.
23
+ def find_inheritable_template_folder(name, partial = false)
24
+ self.class.find_inheritable_template_folder(view_context, name, partial, formats, template_lookup_param)
25
+ end
26
+
27
+ # Override this method to specify a dynamic parameter used in the lookup path.
28
+ # For the default inheritance lookup, this parameter is not needed.
29
+ def template_lookup_param
30
+ nil
31
+ end
32
+
33
+ module ClassMethods
34
+ # Performs a lookup for the given filename and returns the most specific
35
+ # folder that contains the file.
36
+ def find_inheritable_template_folder(view_context, name, partial, formats, param = nil)
37
+ find_inheritable_template_folder_cached(view_context, name, partial, formats, param) do
38
+ find_inheritable_artifact(param) do |folder|
39
+ view_context.template_exists?(name, folder, partial)
40
+ end
41
+ end
42
+ end
43
+
44
+ # Performs a lookup for a controller and returns the name of the most specific one found.
45
+ # This method is primarly usefull when given a 'param' argument that is used
46
+ # in a custom #template_lookup_path. In this case, no controller class would need to
47
+ # exist to render templates from corresponding view folders.
48
+ def inheritable_controller(param = nil)
49
+ c = find_inheritable_artifact(param) do |folder|
50
+ ActionController::Base.subclasses.any? { |c| c.constantize.controller_path == folder }
51
+ end
52
+ c || inheritable_root_controller.controller_path
53
+ end
54
+
55
+ # Runs through the lookup path and yields each folder to the passed block.
56
+ # If the block returns true, this folder is returned and no further lookup
57
+ # happens. If no folder is found, the nil is returned.
58
+ def find_inheritable_artifact(param = nil)
59
+ template_lookup_path(param).each { |folder| return folder if yield(folder) }
60
+ nil
61
+ end
62
+
63
+ # An array of controller names / folders, ordered from most specific to most general.
64
+ # May be dynamic dependening on the passed 'param' argument.
65
+ # You may override this method in an own controller to customize the lookup path.
66
+ def template_lookup_path(param = nil)
67
+ inheritance_lookup_path
68
+ end
69
+
70
+ # The inheritance path of controllers that is used as default lookup path.
71
+ def inheritance_lookup_path
72
+ path = [self]
73
+ until path.last == inheritable_root_controller
74
+ path << path.last.superclass
75
+ end
76
+ path.collect(&:controller_path)
77
+ end
78
+
79
+ # Override view context class to includes the render inheritable modules.
80
+ def view_context_class
81
+ @view_context_class ||= begin
82
+ Class.new(super) do
83
+ include RenderInheritable::View
84
+ end
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ # Performs a lookup for a template folder using the cache.
91
+ def find_inheritable_template_folder_cached(view_context, name, partial, formats, param = nil)
92
+ prefix = inheritable_cache_get(formats, name, partial, param)
93
+ return prefix if prefix
94
+
95
+ prefix = yield
96
+
97
+ if prefix
98
+ template = view_context.find_template_without_lookup(name, prefix, partial)
99
+ inheritable_cache_set(template.formats, name, partial, param, prefix)
100
+ end
101
+ prefix
102
+ end
103
+
104
+ # A simple template lookup cache for each controller.
105
+ def inheritable_cache #:nodoc:
106
+ # do not store keys on each access, only return default structure
107
+ @inheritable_cache ||= Hash.new do |h1, k1|
108
+ Hash.new do |h2, k2|
109
+ Hash.new do |h3, k3|
110
+ Hash.new
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ # Gets the prefix from the cache. Returns nil if it's not there yet.
117
+ def inheritable_cache_get(formats, name, partial, param)
118
+ prefixes = formats.collect { |format| inheritable_cache[format.to_sym][partial][name][param] }
119
+ prefixes.compact!
120
+ prefixes.empty? ? nil : prefixes.first
121
+ end
122
+
123
+ # Stores the found prefix in the cache.
124
+ def inheritable_cache_set(formats, name, partial, param, prefix)
125
+ formats.each do |format|
126
+ # assign hash default values to respective key
127
+ inheritable_cache[format.to_sym] = hf = inheritable_cache[format.to_sym]
128
+ hf[partial] = hp = hf[partial]
129
+ hp[name] = hn = hp[name]
130
+ # finally store prefix in the deepest hash
131
+ hn[param] = prefix
132
+ end
133
+ end
134
+
135
+ end
136
+
137
+ # Extend ActionView so templates are looked up on a find_template call.
138
+ module View
139
+ def self.included(base)
140
+ base.send :alias_method_chain, :find_template, :lookup
141
+ end
142
+
143
+ # Perform a template lookup if the prefix corresponds to the current controller's path.
144
+ def find_template_with_lookup(name, prefix = nil, partial = false)
145
+ if prefix == controller_path
146
+ folder = controller.find_inheritable_template_folder(name, partial)
147
+ prefix = folder if folder
148
+ end
149
+ find_template_without_lookup(name, prefix, partial)
150
+ end
151
+ end
152
+
153
+ end
@@ -0,0 +1,10 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rails', '3.0.0.beta4'
4
+
5
+ # Bundle edge Rails instead:
6
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
+
8
+ gem 'sqlite3-ruby', :require => 'sqlite3'
9
+
10
+ gem 'render_inheritable', :path => '../../../render_inheritable'
@@ -0,0 +1,58 @@
1
+ TestApp::Application.routes.draw do |map|
2
+ # The priority is based upon order of creation:
3
+ # first created -> highest priority.
4
+
5
+ # Sample of regular route:
6
+ # match 'products/:id' => 'catalog#view'
7
+ # Keep in mind you can assign values other than :controller and :action
8
+
9
+ # Sample of named route:
10
+ # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
11
+ # This route can be invoked with purchase_url(:id => product.id)
12
+
13
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
14
+ # resources :products
15
+
16
+ # Sample resource route with options:
17
+ # resources :products do
18
+ # member do
19
+ # get :short
20
+ # post :toggle
21
+ # end
22
+ #
23
+ # collection do
24
+ # get :sold
25
+ # end
26
+ # end
27
+
28
+ # Sample resource route with sub-resources:
29
+ # resources :products do
30
+ # resources :comments, :sales
31
+ # resource :seller
32
+ # end
33
+
34
+ # Sample resource route with more complex sub-resources
35
+ # resources :products do
36
+ # resources :comments
37
+ # resources :sales do
38
+ # get :recent, :on => :collection
39
+ # end
40
+ # end
41
+
42
+ # Sample resource route within a namespace:
43
+ # namespace :admin do
44
+ # # Directs /admin/products/* to Admin::ProductsController
45
+ # # (app/controllers/admin/products_controller.rb)
46
+ # resources :products
47
+ # end
48
+
49
+ # You can have the root of your site routed with "root"
50
+ # just remember to delete public/index.html.
51
+ # root :to => "welcome#index"
52
+
53
+ # See how all your routes lay out with "rake routes"
54
+
55
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
56
+ # Note: This route will make all actions in every controller accessible via GET requests.
57
+ match ':controller(/:action(/:id(.:format)))'
58
+ end
@@ -0,0 +1,23 @@
1
+ class BaseController < ApplicationController
2
+
3
+ render_inheritable
4
+
5
+ def inherited
6
+ respond_to do |format|
7
+ format.html
8
+ format.js
9
+ format.xml
10
+ end
11
+ end
12
+
13
+
14
+ def overriden
15
+ respond_to do |format|
16
+ format.html
17
+ format.js
18
+ format.xml
19
+ end
20
+ end
21
+
22
+
23
+ end
@@ -0,0 +1,6 @@
1
+ class ChildController < BaseController
2
+
3
+ def overriden
4
+ end
5
+
6
+ end
@@ -0,0 +1 @@
1
+ Inherited Partial Base
@@ -0,0 +1 @@
1
+ Overriden Partial Base
@@ -0,0 +1,11 @@
1
+ Inherited Base
2
+
3
+ <%= render :partial => 'inh_partial' %>
4
+
5
+ <%= render :partial => 'over_partial' %>
6
+
7
+
8
+
9
+
10
+
11
+
@@ -0,0 +1,3 @@
1
+ page << "/* Inherited Base JS */"
2
+ page.replace 'element_id', :partial => 'inh_partial'
3
+ page.replace 'other_id', :partial => 'over_partial'
@@ -0,0 +1,5 @@
1
+ Overriden Base
2
+
3
+ <%= render :partial => 'inh_partial' %>
4
+
5
+ <%= render :partial => 'over_partial' %>
@@ -0,0 +1,3 @@
1
+ page << "/* Overriden Base JS */"
2
+ page.replace 'element_id', :partial => 'inh_partial'
3
+ page.replace 'other_id', :partial => 'over_partial'
@@ -0,0 +1 @@
1
+ Overriden Partial Child
@@ -0,0 +1,5 @@
1
+ Overriden Child
2
+
3
+ <%= render :partial => 'inh_partial' %>
4
+
5
+ <%= render :partial => 'over_partial' %>
@@ -0,0 +1,3 @@
1
+ page << "/* Overriden Child JS */"
2
+ page.replace 'element_id', :partial => 'inh_partial'
3
+ page.replace 'other_id', :partial => 'over_partial'
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class BaseControllerTest < ActionController::TestCase
4
+
5
+ test "base template and partials are rendered for inherited" do
6
+ get :inherited
7
+ assert_match /^inherited base$/i, @response.body
8
+ assert_match /^inherited partial base$/i, @response.body
9
+ assert_match /^overriden partial base$/i, @response.body
10
+ end
11
+
12
+ test "base template and partials are rendered for override" do
13
+ get :overriden
14
+ assert_match /^overriden base$/i, @response.body
15
+ assert_match /^inherited partial base$/i, @response.body
16
+ assert_match /^overriden partial base$/i, @response.body
17
+ end
18
+
19
+ test "base template and partials are rendered for inherited format js" do
20
+ get :inherited, :format => :js
21
+ assert_match /inherited base js/i, @response.body
22
+ assert_match /inherited partial base/i, @response.body
23
+ assert_match /overriden partial base/i, @response.body
24
+ end
25
+
26
+ test "base template and partials are rendered for override format js" do
27
+ get :overriden, :format => :js
28
+ assert_match /overriden base js/i, @response.body
29
+ assert_match /inherited partial base/i, @response.body
30
+ assert_match /overriden partial base/i, @response.body
31
+ end
32
+
33
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class ChildControllerTest < ActionController::TestCase
4
+
5
+ test "base template and partials are rendered for inherited" do
6
+ get :inherited
7
+ assert_match /^inherited base$/i, @response.body
8
+ assert_match /^inherited partial base$/i, @response.body
9
+ assert_match /^overriden partial child$/i, @response.body
10
+ end
11
+
12
+ test "child template and partials are rendered for override" do
13
+ get :overriden
14
+ assert_match /^overriden child$/i, @response.body
15
+ assert_match /^inherited partial base$/i, @response.body
16
+ assert_match /^overriden partial child$/i, @response.body
17
+ end
18
+
19
+ test "base template and partials are rendered for inherited format js" do
20
+ get :inherited, :format => :js
21
+ assert_match /inherited base js/i, @response.body
22
+ assert_match /inherited partial base/i, @response.body
23
+ assert_match /overriden partial child/i, @response.body
24
+ end
25
+
26
+ test "child template and partials are rendered for override format js" do
27
+ get :overriden, :format => :js
28
+ assert_match /overriden child js/i, @response.body
29
+ assert_match /inherited partial base/i, @response.body
30
+ assert_match /overriden partial child/i, @response.body
31
+ end
32
+
33
+ end
@@ -0,0 +1,154 @@
1
+ require 'rails'
2
+ require 'test_helper'
3
+
4
+ TEST_VIEW_PATH = File.join(Rails.root, 'test', 'test_views')
5
+
6
+ class RootController < ActionController::Base
7
+ render_inheritable
8
+
9
+ attr_accessor :default_template_format
10
+
11
+ append_view_path(TEST_VIEW_PATH)
12
+
13
+ def initialize(*args)
14
+ super(*args)
15
+ self.default_template_format = :html
16
+ end
17
+
18
+ def view_paths
19
+ self.class.view_paths
20
+ end
21
+
22
+ end
23
+
24
+ class ChildrenController < RootController
25
+
26
+ end
27
+
28
+ class GrandChildrenController < ChildrenController
29
+
30
+ end
31
+
32
+ # mock File ojbect
33
+ class File
34
+ class << self
35
+ def touched
36
+ @touched ||= []
37
+ end
38
+
39
+ alias_method :orig_exists?, :exists?
40
+ def exists?(filename, *args)
41
+ touched.include?(filename) || orig_exists?(filename, *args)
42
+ end
43
+
44
+ def touch_template(file)
45
+ touched << File.join(ActionController::Base.view_paths.first, "#{file}.html.erb")
46
+ end
47
+ end
48
+ end
49
+
50
+ class RenderInheritableTest < ActiveSupport::TestCase
51
+
52
+ attr_reader :controller, :grand_controller
53
+
54
+ def setup
55
+ teardown
56
+ @controller = ChildrenController.new
57
+ @grand_controller = GrandChildrenController.new
58
+ ChildrenController.send(:inheritable_cache).clear
59
+ GrandChildrenController.send(:inheritable_cache).clear
60
+ end
61
+
62
+ def teardown
63
+ FileUtils.rm_rf(TEST_VIEW_PATH)
64
+ end
65
+
66
+ test "inheritable_root_controller" do
67
+ assert_equal RootController, RootController.inheritable_root_controller
68
+ assert_equal RootController, ChildrenController.inheritable_root_controller
69
+ assert_equal RootController, GrandChildrenController.inheritable_root_controller
70
+ end
71
+
72
+ test "lookup path" do
73
+ assert_equal ['children', 'root'], ChildrenController.send(:inheritance_lookup_path)
74
+ assert_equal ['grand_children', 'children', 'root'], GrandChildrenController.send(:inheritance_lookup_path)
75
+ end
76
+
77
+ test "inheritable controller finds controller instance" do
78
+ assert_equal 'children', ChildrenController.send(:inheritable_controller)
79
+ assert_equal 'grand_children', GrandChildrenController.send(:inheritable_controller)
80
+ end
81
+
82
+ test "find non-existing inheritable file" do
83
+ assert_nil @controller.send(:find_inheritable_template_folder, 'foo')
84
+ end
85
+
86
+ test "find inheritable file not overwritten" do
87
+ touch("root/root.html.erb")
88
+
89
+ assert_equal 'root', @controller.send(:find_inheritable_template_folder, 'root')
90
+ assert_equal 'root', @grand_controller.send(:find_inheritable_template_folder, 'root')
91
+ end
92
+
93
+ test "find inheritable file partially overwritten" do
94
+ touch("root/child.html.erb")
95
+ touch("children/child.html.erb")
96
+
97
+ assert_equal 'children', @controller.send(:find_inheritable_template_folder, 'child')
98
+ assert_equal 'children', @grand_controller.send(:find_inheritable_template_folder, 'child')
99
+ end
100
+
101
+ test "find inheritable file partially overwritten with gaps" do
102
+ touch("root/grandchild.html.erb")
103
+ touch("grand_children/grandchild.rhtml")
104
+
105
+ assert_equal 'root', @controller.send(:find_inheritable_template_folder, 'grandchild')
106
+ assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'grandchild')
107
+ end
108
+
109
+ test "find inheritable file for js format" do
110
+ touch("root/_grandchild.js.rjs")
111
+ touch("grand_children/_grandchild.js.rjs")
112
+
113
+ assert_equal 'root', @controller.send(:find_inheritable_template_folder, 'grandchild', true)
114
+ assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'grandchild', true)
115
+
116
+ assert_equal({:js => { true => {'grandchild' => {nil => 'root'}}}}, ChildrenController.send(:inheritable_cache))
117
+ assert_equal({:js => { true => {'grandchild' => {nil => 'grand_children'}}}}, GrandChildrenController.send(:inheritable_cache))
118
+ end
119
+
120
+ test "find inheritable file for xml format" do
121
+ touch("root/_grandchild.xml.builder")
122
+ touch("grand_children/_grandchild.xml.builder")
123
+
124
+ assert_equal 'root', @controller.send(:find_inheritable_template_folder, 'grandchild', true)
125
+ assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'grandchild', true)
126
+ end
127
+
128
+ test "find inheritable file all overwritten" do
129
+ touch("root/all.html.erb")
130
+ touch("children/all.rhtml")
131
+ touch("grand_children/all.html.erb")
132
+
133
+ assert_equal 'children', @controller.send(:find_inheritable_template_folder, 'all')
134
+ assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'all')
135
+
136
+ assert_equal({:html => { false => { 'all' => {nil => 'children'}}}}, ChildrenController.send(:inheritable_cache))
137
+ assert_equal({:html => { false => { 'all' => {nil => 'grand_children'}}}}, GrandChildrenController.send(:inheritable_cache))
138
+
139
+ assert_equal 'children', @controller.send(:find_inheritable_template_folder, 'all')
140
+ assert_equal 'grand_children', @grand_controller.send(:find_inheritable_template_folder, 'all')
141
+
142
+ assert_equal({:html => { false => { 'all' => {nil => 'children'}}}}, ChildrenController.send(:inheritable_cache))
143
+ assert_equal({:html => { false => { 'all' => {nil => 'grand_children'}}}}, GrandChildrenController.send(:inheritable_cache))
144
+ end
145
+
146
+ private
147
+
148
+ def touch(file)
149
+ f = File.join(TEST_VIEW_PATH, file)
150
+ FileUtils.mkdir_p(File.dirname(f))
151
+ FileUtils.touch(f)
152
+ end
153
+
154
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: render_inheritable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 11
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
11
+ platform: ruby
12
+ authors:
13
+ - Pascal Zumkehr
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-23 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rails
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: -1848230024
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ - beta4
35
+ version: 3.0.0.beta4
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ description: |
39
+ With this gem, a template is searched in the current controller's view folder (as usual).
40
+ If it is not found there, the template with the same name in the view folder of the
41
+ superclass controller is used. Finally, also views and partials remain DRY!
42
+
43
+ email: spam@codez.ch
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ extra_rdoc_files:
49
+ - MIT-LICENSE
50
+ - README.rdoc
51
+ - VERSION
52
+ files:
53
+ - lib/rails_integration.rb
54
+ - lib/render_inheritable.rb
55
+ - test/templates/app/config/routes.rb
56
+ - test/templates/app/controllers/base_controller.rb
57
+ - test/templates/app/controllers/child_controller.rb
58
+ - test/templates/app/views/base/_inh_partial.html.erb
59
+ - test/templates/app/views/base/_over_partial.html.erb
60
+ - test/templates/app/views/base/inherited.html.erb
61
+ - test/templates/app/views/base/inherited.js.rjs
62
+ - test/templates/app/views/base/overriden.html.erb
63
+ - test/templates/app/views/base/overriden.js.rjs
64
+ - test/templates/app/views/child/_over_partial.html.erb
65
+ - test/templates/app/views/child/overriden.html.erb
66
+ - test/templates/app/views/child/overriden.js.rjs
67
+ - test/templates/Gemfile
68
+ - test/templates/test/functional/base_controller_test.rb
69
+ - test/templates/test/functional/child_controller_test.rb
70
+ - test/templates/test/unit/render_inheritable_test.rb
71
+ - Rakefile
72
+ - MIT-LICENSE
73
+ - README.rdoc
74
+ - VERSION
75
+ has_rdoc: true
76
+ homepage: http://codez.ch/render_inheritable
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --title
82
+ - Render Inheritable
83
+ - --main
84
+ - README.rdoc
85
+ - --line-numbers
86
+ - --inline-source
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ requirements: []
108
+
109
+ rubyforge_project:
110
+ rubygems_version: 1.3.7
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: A Rails 3 plugin that allows one to inherit or override single templates for controller hierarchies.
114
+ test_files: []
115
+