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 +19 -0
- data/README.rdoc +77 -0
- data/Rakefile +92 -0
- data/VERSION +1 -0
- data/lib/rails_integration.rb +11 -0
- data/lib/render_inheritable.rb +153 -0
- data/test/templates/Gemfile +10 -0
- data/test/templates/app/config/routes.rb +58 -0
- data/test/templates/app/controllers/base_controller.rb +23 -0
- data/test/templates/app/controllers/child_controller.rb +6 -0
- data/test/templates/app/views/base/_inh_partial.html.erb +1 -0
- data/test/templates/app/views/base/_over_partial.html.erb +1 -0
- data/test/templates/app/views/base/inherited.html.erb +11 -0
- data/test/templates/app/views/base/inherited.js.rjs +3 -0
- data/test/templates/app/views/base/overriden.html.erb +5 -0
- data/test/templates/app/views/base/overriden.js.rjs +3 -0
- data/test/templates/app/views/child/_over_partial.html.erb +1 -0
- data/test/templates/app/views/child/overriden.html.erb +5 -0
- data/test/templates/app/views/child/overriden.js.rjs +3 -0
- data/test/templates/test/functional/base_controller_test.rb +33 -0
- data/test/templates/test/functional/child_controller_test.rb +33 -0
- data/test/templates/test/unit/render_inheritable_test.rb +154 -0
- metadata +115 -0
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 @@
|
|
1
|
+
Inherited Partial Base
|
@@ -0,0 +1 @@
|
|
1
|
+
Overriden Partial Base
|
@@ -0,0 +1 @@
|
|
1
|
+
Overriden Partial Child
|
@@ -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
|
+
|