ianwhite / inherit_views
- Source
- Commits
- Network (3)
- Issues (0)
- Downloads (0)
- Wiki (1)
- Graphs
-
Tree:
cb020e3
inherit_views / lib / inherit_views.rb
| 287e1f8a » | ianwhite | 2009-02-06 | 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 | 44 | module InheritViews | |
| a8f3979e » | ianwhite | 2009-02-07 | 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 | 49 | def inherit_views(*paths) | |
| 50 | class_eval do | ||||
| bdf78797 » | ianwhite | 2009-02-07 | 51 | extend PathsContainer unless respond_to?(:inherit_views_paths) | |
| 287e1f8a » | ianwhite | 2009-02-06 | 52 | self.inherit_views = true | |
| 17993be3 » | ianwhite | 2009-02-07 | 53 | self.inherit_view_paths = paths if paths.any? | |
| 674331a9 » | ianwhite | 2009-02-05 | 54 | end | |
| 55 | end | ||||
| bdf78797 » | ianwhite | 2009-02-07 | 56 | end | |
| c260494b » | ianwhite | 2009-02-05 | 57 | ||
| bdf78797 » | ianwhite | 2009-02-07 | 58 | # class extension that enables inherit_view_paths to be calculated/set | |
| 59 | # | ||||
| a8f3979e » | ianwhite | 2009-02-07 | 60 | # requires a class method called 'controller_path' (ActionController::Base & ActionMailer::Base have this) | |
| bdf78797 » | ianwhite | 2009-02-07 | 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 | 65 | end | |
| 66 | end | ||||
| bdf78797 » | ianwhite | 2009-02-07 | 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 | 78 | # Return the inherit view paths, in order of self to ancestor. | |
| bdf78797 » | ianwhite | 2009-02-07 | 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 | 83 | ||
| bdf78797 » | ianwhite | 2009-02-07 | 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 | 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 | 96 | attr_accessor :inherit_view_paths | |
| 17993be3 » | ianwhite | 2009-02-07 | 97 | ||
| 287e1f8a » | ianwhite | 2009-02-06 | 98 | alias_method :orig_find_template, :find_template | |
| 99 | |||||
| ad0976df » | ianwhite | 2009-02-09 | 100 | # look for a parent template if a standard one can't be found | |
| 6bbd8e55 » | ianwhite | 2009-03-03 | 101 | def find_template(template_path, format = nil, html_fallback = true) | |
| 287e1f8a » | ianwhite | 2009-02-06 | 102 | super | |
| ad0976df » | ianwhite | 2009-02-09 | 103 | rescue ::ActionView::MissingTemplate | |
| 16954d7d » | ianwhite | 2009-02-24 | 104 | find_parent_template(template_path, format) | |
| 287e1f8a » | ianwhite | 2009-02-06 | 105 | end | |
| ad0976df » | ianwhite | 2009-02-09 | 106 | ||
| 107 | # given a template_path and format, returns a parent template, or raise ActionView::MissingTemplate | ||||
| 6bbd8e55 » | ianwhite | 2009-03-03 | 108 | def find_parent_template(template_path, format = nil, html_fallback = true) | |
| 15a0ee44 » | ianwhite | 2009-02-06 | 109 | # first, we grab the inherit view paths that are 'above' the given template_path | |
| 169c360b » | ianwhite | 2009-02-09 | 110 | if inherit_view_paths.present? && (starting_path = inherit_view_paths.detect {|path| template_path.starts_with?("#{path}/")}) | |
| ad0976df » | ianwhite | 2009-02-09 | 111 | parent_paths = inherit_view_paths.slice(inherit_view_paths.index(starting_path)+1..-1) | |
| 15a0ee44 » | ianwhite | 2009-02-06 | 112 | # then, search through each path, substituting the inherit view path, returning the first found | |
| ad0976df » | ianwhite | 2009-02-09 | 113 | parent_paths.each do |path| | |
| 8199eb50 » | ianwhite | 2009-02-06 | 114 | begin | |
| 6bbd8e55 » | ianwhite | 2009-03-03 | 115 | return orig_find_template(template_path.sub(/^#{starting_path}/, path), format, html_fallback) | |
| 287e1f8a » | ianwhite | 2009-02-06 | 116 | rescue ::ActionView::MissingTemplate | |
| 8199eb50 » | ianwhite | 2009-02-06 | 117 | next | |
| 674331a9 » | ianwhite | 2009-02-05 | 118 | end | |
| 119 | end | ||||
| 120 | end | ||||
| ad0976df » | ianwhite | 2009-02-09 | 121 | raise ::ActionView::MissingTemplate.new(self, template_path, format) | |
| 7619b815 » | ianwhite | 2009-02-05 | 122 | end | |
| 674331a9 » | ianwhite | 2009-02-05 | 123 | end | |
| a8f3979e » | ianwhite | 2009-02-07 | 124 | ||
| 16954d7d » | ianwhite | 2009-02-24 | 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 | 132 | module ActionView | |
| 133 | def self.included(base) | ||||
| 134 | base.class_eval do | ||||
| 22082ed0 » | ianwhite | 2009-02-23 | 135 | def self.process_view_paths(value) | |
| 136 | InheritViews::PathSet.new(Array(value)) | ||||
| a8f3979e » | ianwhite | 2009-02-07 | 137 | end | |
| 169c360b » | ianwhite | 2009-02-09 | 138 | ||
| 22082ed0 » | ianwhite | 2009-02-23 | 139 | alias_method_chain :view_paths=, :inherit_views | |
| 169c360b » | ianwhite | 2009-02-09 | 140 | alias_method_chain :render, :parent | |
| a8f3979e » | ianwhite | 2009-02-07 | 141 | end | |
| 142 | end | ||||
| 169c360b » | ianwhite | 2009-02-09 | 143 | ||
| 16954d7d » | ianwhite | 2009-02-24 | 144 | # set the view_paths, and afterwards pass it my controller's inherit_view_paths | |
| 22082ed0 » | ianwhite | 2009-02-23 | 145 | def view_paths_with_inherit_views=(value) | |
| 16954d7d » | ianwhite | 2009-02-24 | 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 | 149 | end | |
| 150 | |||||
| 16954d7d » | ianwhite | 2009-02-24 | 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 | 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 | 165 | end | |
| 674331a9 » | ianwhite | 2009-02-05 | 166 | end | |
