root/branches/1-2-stable/actionpack/lib/action_controller/helpers.rb
| Revision 4952, 5.2 kB (checked in by david, 2 years ago) |
|---|
| Line | |
|---|---|
| 1 | module ActionController #:nodoc: |
| 2 | module Helpers #:nodoc: |
| 3 | def self.included(base) |
| 4 | # Initialize the base module to aggregate its helpers. |
| 5 | base.class_inheritable_accessor :master_helper_module |
| 6 | base.master_helper_module = Module.new |
| 7 | |
| 8 | # Extend base with class methods to declare helpers. |
| 9 | base.extend(ClassMethods) |
| 10 | |
| 11 | base.class_eval do |
| 12 | # Wrap inherited to create a new master helper module for subclasses. |
| 13 | class << self |
| 14 | alias_method_chain :inherited, :helper |
| 15 | end |
| 16 | end |
| 17 | end |
| 18 | |
| 19 | # The template helpers serve to relieve the templates from including the same inline code again and again. It's a |
| 20 | # set of standardized methods for working with forms (FormHelper), dates (DateHelper), texts (TextHelper), and |
| 21 | # Active Records (ActiveRecordHelper) that's available to all templates by default. |
| 22 | # |
| 23 | # It's also really easy to make your own helpers and it's much encouraged to keep the template files free |
| 24 | # from complicated logic. It's even encouraged to bundle common compositions of methods from other helpers |
| 25 | # (often the common helpers) as they're used by the specific application. |
| 26 | # |
| 27 | # module MyHelper |
| 28 | # def hello_world() "hello world" end |
| 29 | # end |
| 30 | # |
| 31 | # MyHelper can now be included in a controller, like this: |
| 32 | # |
| 33 | # class MyController < ActionController::Base |
| 34 | # helper :my_helper |
| 35 | # end |
| 36 | # |
| 37 | # ...and, same as above, used in any template rendered from MyController, like this: |
| 38 | # |
| 39 | # Let's hear what the helper has to say: <tt><%= hello_world %></tt> |
| 40 | module ClassMethods |
| 41 | # Makes all the (instance) methods in the helper module available to templates rendered through this controller. |
| 42 | # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules |
| 43 | # available to the templates. |
| 44 | def add_template_helper(helper_module) #:nodoc: |
| 45 | master_helper_module.send(:include, helper_module) |
| 46 | end |
| 47 | |
| 48 | # Declare a helper: |
| 49 | # helper :foo |
| 50 | # requires 'foo_helper' and includes FooHelper in the template class. |
| 51 | # helper FooHelper |
| 52 | # includes FooHelper in the template class. |
| 53 | # helper { def foo() "#{bar} is the very best" end } |
| 54 | # evaluates the block in the template class, adding method #foo. |
| 55 | # helper(:three, BlindHelper) { def mice() 'mice' end } |
| 56 | # does all three. |
| 57 | def helper(*args, &block) |
| 58 | args.flatten.each do |arg| |
| 59 | case arg |
| 60 | when Module |
| 61 | add_template_helper(arg) |
| 62 | when String, Symbol |
| 63 | file_name = arg.to_s.underscore + '_helper' |
| 64 | class_name = file_name.camelize |
| 65 | |
| 66 | begin |
| 67 | require_dependency(file_name) |
| 68 | rescue LoadError => load_error |
| 69 | requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1] |
| 70 | msg = (requiree == file_name) ? "Missing helper file helpers/#{file_name}.rb" : "Can't load file: #{requiree}" |
| 71 | raise LoadError.new(msg).copy_blame!(load_error) |
| 72 | end |
| 73 | |
| 74 | add_template_helper(class_name.constantize) |
| 75 | else |
| 76 | raise ArgumentError, 'helper expects String, Symbol, or Module argument' |
| 77 | end |
| 78 | end |
| 79 | |
| 80 | # Evaluate block in template class if given. |
| 81 | master_helper_module.module_eval(&block) if block_given? |
| 82 | end |
| 83 | |
| 84 | # Declare a controller method as a helper. For example, |
| 85 | # helper_method :link_to |
| 86 | # def link_to(name, options) ... end |
| 87 | # makes the link_to controller method available in the view. |
| 88 | def helper_method(*methods) |
| 89 | methods.flatten.each do |method| |
| 90 | master_helper_module.module_eval <<-end_eval |
| 91 | def #{method}(*args, &block) |
| 92 | controller.send(%(#{method}), *args, &block) |
| 93 | end |
| 94 | end_eval |
| 95 | end |
| 96 | end |
| 97 | |
| 98 | # Declare a controller attribute as a helper. For example, |
| 99 | # helper_attr :name |
| 100 | # attr_accessor :name |
| 101 | # makes the name and name= controller methods available in the view. |
| 102 | # The is a convenience wrapper for helper_method. |
| 103 | def helper_attr(*attrs) |
| 104 | attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") } |
| 105 | end |
| 106 | |
| 107 | private |
| 108 | def default_helper_module! |
| 109 | module_name = name.sub(/Controller$|$/, 'Helper') |
| 110 | module_path = module_name.split('::').map { |m| m.underscore }.join('/') |
| 111 | require_dependency module_path |
| 112 | helper module_name.constantize |
| 113 | rescue LoadError |
| 114 | logger.debug("#{name}: missing default helper path #{module_path}") if logger |
| 115 | rescue NameError |
| 116 | logger.debug("#{name}: missing default helper module #{module_name}") if logger |
| 117 | end |
| 118 | |
| 119 | def inherited_with_helper(child) |
| 120 | inherited_without_helper(child) |
| 121 | begin |
| 122 | child.master_helper_module = Module.new |
| 123 | child.master_helper_module.send :include, master_helper_module |
| 124 | child.send :default_helper_module! |
| 125 | rescue MissingSourceFile => e |
| 126 | raise unless e.is_missing?("helpers/#{child.controller_path}_helper") |
| 127 | end |
| 128 | end |
| 129 | end |
| 130 | end |
| 131 | end |
Note: See TracBrowser for help on using the browser.