ianwhite / inherit_views

rails plugin that enables inheritance of views along a controller class heirachy

This URL has Read+Write access

inherit_views / lib / inherit_views.rb
287e1f8a » ianwhite 2009-02-06 Using thedarkone's implemen... 1 # Allow your controllers to inherit their views from parent controllers, or from
2 # specified view paths.
3 #
4 # === Example
5 #
6 # class FooController < ApplicationController
7 # inherit_views
8 # end
9 #
10 # class BarController < FooController
11 # ... # will look for views in 'views/bar' and 'views/foo'
12 # end
13 #
14 # In the example above, If BarController, or any of the views in views/bar, renders 'bar/view'
15 # and it is not found then 'foo/view' is rendered (if it can be found)
16 #
17 # You can also specify an inherit path other than the default (it does not have to be the default controller path)
18 # If your controller inherits from a controller with inherit_views then that controller
19 # gets the inherited view paths as well.
20 #
21 # class FooController < ApplicationController
22 # inherit_views 'far', 'faz' # will look for views in 'foo', then 'far', then 'faz'
23 # end
24 #
25 # class BarController < FooController
26 # # will look for views in 'bar', 'foo', 'far', 'faz'
27 # end
28 #
29 # If you want to turn off inherited views for a controller that has inherit_views in its
30 # ancestors use self.inherit_views=
31 #
32 # class BarController < FooController
33 # self.inherit_views = false
34 # end
35 #
36 # You can completely override the inherited view paths in a subclass controller using
37 # inherit_view_paths=
38 #
39 # class BarController < FooController
40 # self.inherit_view_paths = ['you_can_go', 'your_own_way']
41 # # will look for views in 'bar', 'you_can_go', and 'your_own_way'
42 # # (not 'far' or 'faz' from FooController)
43 # end
674331a9 » ianwhite 2009-02-05 Initial go at 2.3 inherit_v... 44 module InheritViews
a8f3979e » ianwhite 2009-02-07 Added ActionMailer support ... 45 # class extension which enables specification of inherit_views
46 module ActMethod
47 # Specify this to have your controller or mailer inherit its views from the specified path
48 # or the current controller/mailer's default path if no argument is given
287e1f8a » ianwhite 2009-02-06 Using thedarkone's implemen... 49 def inherit_views(*paths)
50 class_eval do
bdf78797 » ianwhite 2009-02-07 Extract InheritViews::Paths... 51 extend PathsContainer unless respond_to?(:inherit_views_paths)
287e1f8a » ianwhite 2009-02-06 Using thedarkone's implemen... 52 self.inherit_views = true
17993be3 » ianwhite 2009-02-07 Sanitize PatHSet#inherit_vi... 53 self.inherit_view_paths = paths if paths.any?
674331a9 » ianwhite 2009-02-05 Initial go at 2.3 inherit_v... 54 end
55 end
bdf78797 » ianwhite 2009-02-07 Extract InheritViews::Paths... 56 end
c260494b » ianwhite 2009-02-05 Got inherit_views container... 57
bdf78797 » ianwhite 2009-02-07 Extract InheritViews::Paths... 58 # class extension that enables inherit_view_paths to be calculated/set
59 #
a8f3979e » ianwhite 2009-02-07 Added ActionMailer support ... 60 # requires a class method called 'controller_path' (ActionController::Base & ActionMailer::Base have this)
bdf78797 » ianwhite 2009-02-07 Extract InheritViews::Paths... 61 module PathsContainer
62 def self.extended(base)
63 base.class_eval do
64 delegate :inherit_views?, :inherit_view_paths, :to => 'self.class'
674331a9 » ianwhite 2009-02-05 Initial go at 2.3 inherit_v... 65 end
66 end
bdf78797 » ianwhite 2009-02-07 Extract InheritViews::Paths... 67
68 # Return true if the class is inheriting views
69 def inherit_views?
70 read_inheritable_attribute('inherit_views') ? true : false
71 end
72
73 # Instruct the class that it is, or is not, inheriting views
74 def inherit_views=(bool)
75 write_inheritable_attribute('inherit_views', bool)
76 end
77
a8f3979e » ianwhite 2009-02-07 Added ActionMailer support ... 78 # Return the inherit view paths, in order of self to ancestor.
bdf78797 » ianwhite 2009-02-07 Extract InheritViews::Paths... 79 # Takes inherit_view_paths from the superclass when first read, and prepends the current controller_path
80 def inherit_view_paths
81 instance_variable_get('@inherit_view_paths') || instance_variable_set('@inherit_view_paths', [controller_path] + (superclass.inherit_view_paths rescue []))
82 end
15a0ee44 » ianwhite 2009-02-06 ControllerTrackingPathSet =... 83
bdf78797 » ianwhite 2009-02-07 Extract InheritViews::Paths... 84 # Set the inherit view paths, in order of self to ancestor.
85 # The controller_path for self is always prepended to the front, no matter what the arguments.
86 def inherit_view_paths=(new_paths)
87 new_paths -= [controller_path]
88 old_paths = inherit_view_paths - [controller_path] - new_paths
89 instance_variable_set('@inherit_view_paths', [controller_path] + new_paths + old_paths)
90 end
91 end
92
15a0ee44 » ianwhite 2009-02-06 ControllerTrackingPathSet =... 93 # just like a normal path set, but can have an optional array of inherit_view_paths
94 # which will be used to look for a matching template if the original template is missing
95 class PathSet < ::ActionView::PathSet
bdf78797 » ianwhite 2009-02-07 Extract InheritViews::Paths... 96 attr_accessor :inherit_view_paths
17993be3 » ianwhite 2009-02-07 Sanitize PatHSet#inherit_vi... 97
287e1f8a » ianwhite 2009-02-06 Using thedarkone's implemen... 98 alias_method :orig_find_template, :find_template
99
ad0976df » ianwhite 2009-02-09 InheritViews::PathSet now h... 100 # look for a parent template if a standard one can't be found
6bbd8e55 » ianwhite 2009-03-03 Update method signature of ... 101 def find_template(template_path, format = nil, html_fallback = true)
287e1f8a » ianwhite 2009-02-06 Using thedarkone's implemen... 102 super
ad0976df » ianwhite 2009-02-09 InheritViews::PathSet now h... 103 rescue ::ActionView::MissingTemplate
16954d7d » ianwhite 2009-02-24 Improve inline docs, and ma... 104 find_parent_template(template_path, format)
287e1f8a » ianwhite 2009-02-06 Using thedarkone's implemen... 105 end
ad0976df » ianwhite 2009-02-09 InheritViews::PathSet now h... 106
107 # given a template_path and format, returns a parent template, or raise ActionView::MissingTemplate
6bbd8e55 » ianwhite 2009-03-03 Update method signature of ... 108 def find_parent_template(template_path, format = nil, html_fallback = true)
15a0ee44 » ianwhite 2009-02-06 ControllerTrackingPathSet =... 109 # first, we grab the inherit view paths that are 'above' the given template_path
169c360b » ianwhite 2009-02-09 Added render parent functio... 110 if inherit_view_paths.present? && (starting_path = inherit_view_paths.detect {|path| template_path.starts_with?("#{path}/")})
ad0976df » ianwhite 2009-02-09 InheritViews::PathSet now h... 111 parent_paths = inherit_view_paths.slice(inherit_view_paths.index(starting_path)+1..-1)
15a0ee44 » ianwhite 2009-02-06 ControllerTrackingPathSet =... 112 # then, search through each path, substituting the inherit view path, returning the first found
ad0976df » ianwhite 2009-02-09 InheritViews::PathSet now h... 113 parent_paths.each do |path|
8199eb50 » ianwhite 2009-02-06 Simplify find_template_from... 114 begin
6bbd8e55 » ianwhite 2009-03-03 Update method signature of ... 115 return orig_find_template(template_path.sub(/^#{starting_path}/, path), format, html_fallback)
287e1f8a » ianwhite 2009-02-06 Using thedarkone's implemen... 116 rescue ::ActionView::MissingTemplate
8199eb50 » ianwhite 2009-02-06 Simplify find_template_from... 117 next
674331a9 » ianwhite 2009-02-05 Initial go at 2.3 inherit_v... 118 end
119 end
120 end
ad0976df » ianwhite 2009-02-09 InheritViews::PathSet now h... 121 raise ::ActionView::MissingTemplate.new(self, template_path, format)
7619b815 » ianwhite 2009-02-05 Setup for adding inherited ... 122 end
674331a9 » ianwhite 2009-02-05 Initial go at 2.3 inherit_v... 123 end
a8f3979e » ianwhite 2009-02-07 Added ActionMailer support ... 124
16954d7d » ianwhite 2009-02-24 Improve inline docs, and ma... 125 # Mixin for ActionView::Base to enable inherit views functionality. There are two
126 # enhancements
127 #
128 # * view_paths are set to an InheritViews::PathSet object, and any inherit_view_paths
129 # are passed from the view's controller to the view_paths
130 #
131 # * render is extended to include support for render :parent, see render_with_parent
a8f3979e » ianwhite 2009-02-07 Added ActionMailer support ... 132 module ActionView
133 def self.included(base)
134 base.class_eval do
22082ed0 » ianwhite 2009-02-23 Make sure that inherit_view... 135 def self.process_view_paths(value)
136 InheritViews::PathSet.new(Array(value))
a8f3979e » ianwhite 2009-02-07 Added ActionMailer support ... 137 end
169c360b » ianwhite 2009-02-09 Added render parent functio... 138
22082ed0 » ianwhite 2009-02-23 Make sure that inherit_view... 139 alias_method_chain :view_paths=, :inherit_views
169c360b » ianwhite 2009-02-09 Added render parent functio... 140 alias_method_chain :render, :parent
a8f3979e » ianwhite 2009-02-07 Added ActionMailer support ... 141 end
142 end
169c360b » ianwhite 2009-02-09 Added render parent functio... 143
16954d7d » ianwhite 2009-02-24 Improve inline docs, and ma... 144 # set the view_paths, and afterwards pass it my controller's inherit_view_paths
22082ed0 » ianwhite 2009-02-23 Make sure that inherit_view... 145 def view_paths_with_inherit_views=(value)
16954d7d » ianwhite 2009-02-24 Improve inline docs, and ma... 146 returning self.view_paths_without_inherit_views=(value) do
147 @view_paths.inherit_view_paths = controller.inherit_view_paths if (controller.inherit_views? rescue false)
148 end
22082ed0 » ianwhite 2009-02-23 Make sure that inherit_view... 149 end
150
16954d7d » ianwhite 2009-02-24 Improve inline docs, and ma... 151 # Extension for render which enables the following (in partials as well as top-level tenplates)
152 #
153 # <%= render :parent %>
154 # <%= render :parent, :locals => {:foo => @foo} %>
155 #
156 # These calls will render the template that is 'above' the current template according to the#
157 # current controller's inherit_view_paths.
169c360b » ianwhite 2009-02-09 Added render parent functio... 158 def render_with_parent(*args, &block)
159 if args.first == :parent
160 args.shift
161 args.first[:file] = view_paths.find_parent_template(template.to_s, template.format)
162 end
163 render_without_parent(*args, &block)
164 end
a8f3979e » ianwhite 2009-02-07 Added ActionMailer support ... 165 end
674331a9 » ianwhite 2009-02-05 Initial go at 2.3 inherit_v... 166 end