diff options
Diffstat (limited to 'actionmailer/lib')
-rw-r--r-- | actionmailer/lib/action_mailer.rb | 3 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/base.rb | 314 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/delivery_method.rb | 57 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/delivery_method/file.rb | 21 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/delivery_method/sendmail.rb | 22 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/delivery_method/smtp.rb | 31 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/delivery_method/test.rb | 12 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/deprecated_body.rb | 44 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/helpers.rb | 114 |
9 files changed, 273 insertions, 345 deletions
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index a427376579..23f04a11ba 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -32,8 +32,9 @@ module ActionMailer end autoload :AdvAttrAccessor, 'action_mailer/adv_attr_accessor' + autoload :DeprecatedBody, 'action_mailer/deprecated_body' autoload :Base, 'action_mailer/base' - autoload :Helpers, 'action_mailer/helpers' + autoload :DeliveryMethod, 'action_mailer/delivery_method' autoload :Part, 'action_mailer/part' autoload :PartContainer, 'action_mailer/part_container' autoload :Quoting, 'action_mailer/quoting' diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index c0c04af51c..293af01bbf 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -1,8 +1,4 @@ -require 'tmpdir' - -require "active_support/core_ext/class" -# Use the old layouts until actionmailer gets refactored -require "action_controller/legacy/layout" +require 'active_support/core_ext/class' module ActionMailer #:nodoc: # Action Mailer allows you to send email from your application using a mailer model and views. @@ -232,7 +228,7 @@ module ActionMailer #:nodoc: # * <tt>raise_delivery_errors</tt> - Whether or not errors should be raised if the email fails to be delivered. # # * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, <tt>:test</tt>, - # and <tt>:file</tt>. + # and <tt>:file</tt>. Or you may provide a custom delivery method object eg. MyOwnDeliveryMethodClass.new # # * <tt>perform_deliveries</tt> - Determines whether <tt>deliver_*</tt> methods are actually carried out. By default they are, # but this can be turned off to help functional testing. @@ -256,13 +252,20 @@ module ActionMailer #:nodoc: # +implicit_parts_order+. class Base include AdvAttrAccessor, PartContainer, Quoting, Utils - extend AbstractController::RenderingController + + include AbstractController::RenderingController + include AbstractController::LocalizedCache + include AbstractController::Layouts + + include AbstractController::Helpers + helper MailHelper if Object.const_defined?(:ActionController) include ActionController::UrlWriter - include ActionController::Layout end + include ActionMailer::DeprecatedBody + private_class_method :new #:nodoc: class_inheritable_accessor :view_paths @@ -270,35 +273,9 @@ module ActionMailer #:nodoc: cattr_accessor :logger - @@smtp_settings = { - :address => "localhost", - :port => 25, - :domain => 'localhost.localdomain', - :user_name => nil, - :password => nil, - :authentication => nil, - :enable_starttls_auto => true, - } - cattr_accessor :smtp_settings - - @@sendmail_settings = { - :location => '/usr/sbin/sendmail', - :arguments => '-i -t' - } - cattr_accessor :sendmail_settings - - @@file_settings = { - :location => defined?(Rails) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails" - } - - cattr_accessor :file_settings - @@raise_delivery_errors = true cattr_accessor :raise_delivery_errors - superclass_delegating_accessor :delivery_method - self.delivery_method = :smtp - @@perform_deliveries = true cattr_accessor :perform_deliveries @@ -317,17 +294,12 @@ module ActionMailer #:nodoc: @@default_implicit_parts_order = [ "text/html", "text/enriched", "text/plain" ] cattr_accessor :default_implicit_parts_order + @@protected_instance_variables = [] cattr_reader :protected_instance_variables - @@protected_instance_variables = %w(@body) # Specify the BCC addresses for the message adv_attr_accessor :bcc - # Define the body of the message. This is either a Hash (in which case it - # specifies the variables to pass to the template when it is rendered), - # or a string, in which case it specifies the actual text of the message. - adv_attr_accessor :body - # Specify the CC addresses for the message. adv_attr_accessor :cc @@ -372,43 +344,42 @@ module ActionMailer #:nodoc: # have multiple mailer methods share the same template. adv_attr_accessor :template + # The mail and action_name instances referenced by this mailer. + attr_reader :mail, :action_name + + # Where the response body is stored. + attr_internal :response_body + # Override the mailer name, which defaults to an inflected version of the # mailer's class name. If you want to use a template in a non-standard # location, you can use this to specify that location. + attr_writer :mailer_name + def mailer_name(value = nil) if value - self.mailer_name = value + @mailer_name = value else - self.class.mailer_name + @mailer_name || self.class.mailer_name end end - def mailer_name=(value) - self.class.mailer_name = value - end - - # The mail object instance referenced by this mailer. - attr_reader :mail - attr_reader :template_name, :default_template_name, :action_name - - def controller_path - self.class.controller_path - end - - def formats - @template.formats - end + # Alias controller_path to mailer_name so render :partial in views work. + alias :controller_path :mailer_name class << self attr_writer :mailer_name + delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::File, :prefix => :file + delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::Sendmail, :prefix => :sendmail + delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::Smtp, :prefix => :smtp + def mailer_name @mailer_name ||= name.underscore end - # for ActionView compatibility - alias_method :controller_name, :mailer_name - alias_method :controller_path, :mailer_name + def delivery_method=(method_name) + @delivery_method = ActionMailer::DeliveryMethod.lookup_method(method_name) + end def respond_to?(method_symbol, include_private = false) #:nodoc: matches_dynamic_method?(method_symbol) || super @@ -459,6 +430,7 @@ module ActionMailer #:nodoc: self.view_paths && self.view_paths.first end + # Should template root overwrite the whole view_paths? def template_root=(root) self.view_paths = ActionView::Base.process_view_paths(root) end @@ -470,6 +442,11 @@ module ActionMailer #:nodoc: end end + # Configure delivery method. Check ActionMailer::DeliveryMethod for more + # instructions. + superclass_delegating_reader :delivery_method + self.delivery_method = :smtp + # Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer # will be initialized according to the named method. If not, the mailer will # remain uninitialized (useful when you only need to invoke the "receive" @@ -481,62 +458,18 @@ module ActionMailer #:nodoc: # Initialize the mailer via the given +method_name+. The body will be # rendered and a new TMail::Mail object created. def create!(method_name, *parameters) #:nodoc: - ActiveSupport::Orchestra.instrument(:create_mail, :name => method_name) do - initialize_defaults(method_name) - __send__(method_name, *parameters) - - # If an explicit, textual body has not been set, we check assumptions. - unless String === @body - # First, we look to see if there are any likely templates that match, - # which include the content-type in their file name (i.e., - # "the_template_file.text.html.erb", etc.). Only do this if parts - # have not already been specified manually. - # if @parts.empty? - template_root.find_all(@template, {}, template_path).each do |template| - @parts << Part.new( - :content_type => template.mime_type ? template.mime_type.to_s : "text/plain", - :disposition => "inline", - :charset => charset, - :body => render_template(template, @body) - ) - end - - if @parts.size > 1 - @content_type = "multipart/alternative" if @content_type !~ /^multipart/ - @parts = sort_parts(@parts, @implicit_parts_order) - end - # end - - # Then, if there were such templates, we check to see if we ought to - # also render a "normal" template (without the content type). If a - # normal template exists (or if there were no implicit parts) we render - # it. - # ==== - # TODO: Revisit this - # template_exists = @parts.empty? - # template_exists ||= template_root.find("#{mailer_name}/#{@template}") - # @body = render_message(@template, @body) if template_exists - - # Finally, if there are other message parts and a textual body exists, - # we shift it onto the front of the parts and set the body to nil (so - # that create_mail doesn't try to render it in addition to the parts). - # ==== - # TODO: Revisit this - # if !@parts.empty? && String === @body - # @parts.unshift Part.new(:charset => charset, :body => @body) - # @body = nil - # end - end + initialize_defaults(method_name) + __send__(method_name, *parameters) - # If this is a multipart e-mail add the mime_version if it is not - # already set. - @mime_version ||= "1.0" if !@parts.empty? + # Create e-mail parts + create_parts - # build the mail object itself - @mail = create_mail - end + # Set the subject if not set yet + @subject ||= I18n.t(method_name, :scope => [:actionmailer, :subjects, mailer_name], + :default => method_name.humanize) - @mail + # build the mail object itself + @mail = create_mail end # Delivers a TMail::Mail object. By default, it delivers the cached mail @@ -545,14 +478,14 @@ module ActionMailer #:nodoc: def deliver!(mail = @mail) raise "no mail object available for delivery!" unless mail - unless logger.nil? + if logger logger.info "Sent mail to #{Array(recipients).join(', ')}" logger.debug "\n#{mail.encoded}" end - ActiveSupport::Orchestra.instrument(:deliver_mail, :mail => @mail) do + ActiveSupport::Notifications.instrument(:deliver_mail, :mail => @mail) do begin - __send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries + self.delivery_method.perform_delivery(mail) if perform_deliveries rescue Exception => e # Net::SMTP errors or sendmail pipe errors raise e if raise_delivery_errors end @@ -562,94 +495,61 @@ module ActionMailer #:nodoc: end private + # Set up the default values for the various instance variables of this # mailer. Subclasses may override this method to provide different # defaults. def initialize_defaults(method_name) - @charset ||= @@default_charset.dup - @content_type ||= @@default_content_type.dup + @charset ||= @@default_charset.dup + @content_type ||= @@default_content_type.dup @implicit_parts_order ||= @@default_implicit_parts_order.dup - @template ||= method_name - @default_template_name = @action_name = @template - @mailer_name ||= self.class.name.underscore - @parts ||= [] + @mime_version ||= @@default_mime_version.dup if @@default_mime_version + + @mailer_name ||= self.class.mailer_name + @template ||= method_name + @action_name = @template + + @parts ||= [] @headers ||= {} - @body ||= {} - @mime_version = @@default_mime_version.dup if @@default_mime_version @sent_on ||= Time.now - end - def render_template(template, body) - if template.respond_to?(:mime_type) - @current_template_content_type = template.mime_type && template.mime_type.to_sym.to_s - end - - @template = initialize_template_class(body) - layout = _pick_layout(layout, true) unless - ActionController::Base.exempt_from_layout.include?(template.handler) - @template._render_template(template, layout, {}) - ensure - @current_template_content_type = nil + super # Run deprecation hooks end - def render_message(method_name, body) - render :file => method_name, :body => body - ensure - @current_template_content_type = nil - end + def create_parts + super # Run deprecation hooks - def render(opts) - opts[:locals] ||= {} - layout, file = opts.delete(:layout), opts[:file] - - begin - @template = initialize_template_class(opts.delete(:body)) - - if file - prefix = mailer_name unless file =~ /\// - template = view_paths.find(file, {:formats => formats}, prefix) + if String === response_body + @parts.unshift Part.new( + :content_type => "text/plain", + :disposition => "inline", + :charset => charset, + :body => response_body + ) + else + self.class.template_root.find_all(@template, {}, mailer_name).each do |template| + @parts << Part.new( + :content_type => template.mime_type ? template.mime_type.to_s : "text/plain", + :disposition => "inline", + :charset => charset, + :body => render_to_body(:_template => template) + ) end - layout = _pick_layout(layout, - !template || ActionController::Base.exempt_from_layout.include?(template.handler)) - - if template - @template._render_template(template, layout, opts) - elsif inline = opts[:inline] - @template._render_inline(inline, layout, opts) + if @parts.size > 1 + @content_type = "multipart/alternative" if @content_type !~ /^multipart/ + @parts = sort_parts(@parts, @implicit_parts_order) end - end - end - def default_template_format - if @current_template_content_type - Mime::Type.lookup(@current_template_content_type).to_sym - else - :html + # If this is a multipart e-mail add the mime_version if it is not + # already set. + @mime_version ||= "1.0" if !@parts.empty? end end - def template_root - self.class.template_root - end - - def template_root=(root) - self.class.template_root = root - end - - def template_path - "#{mailer_name}" - end - - def initialize_template_class(assigns) - template = ActionView::Base.new(self.class.view_paths, assigns, self) - template.formats = [default_template_format] - template - end - def sort_parts(parts, order = []) order = order.collect { |s| s.downcase } - + parts = parts.sort do |a, b| a_ct = a.content_type.downcase b_ct = b.content_type.downcase @@ -698,14 +598,6 @@ module ActionMailer #:nodoc: m.set_content_type(real_content_type, nil, ctype_attrs) m.body = normalize_new_lines(@parts.first.body) else - if String === body - part = TMail::Mail.new - part.body = normalize_new_lines(body) - part.set_content_type(real_content_type, nil, ctype_attrs) - part.set_content_disposition "inline" - m.parts << part - end - @parts.each do |p| part = (TMail::Mail === p ? p : p.to_mail(self)) m.parts << part @@ -720,43 +612,5 @@ module ActionMailer #:nodoc: @mail = m end - def perform_delivery_smtp(mail) - destinations = mail.destinations - mail.ready_to_send - sender = (mail['return-path'] && mail['return-path'].spec) || mail['from'] - - smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port]) - smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto) - smtp.start(smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password], - smtp_settings[:authentication]) do |smtp| - smtp.sendmail(mail.encoded, sender, destinations) - end - end - - def perform_delivery_sendmail(mail) - sendmail_args = sendmail_settings[:arguments] - sendmail_args += " -f \"#{mail['return-path']}\"" if mail['return-path'] - IO.popen("#{sendmail_settings[:location]} #{sendmail_args}","w+") do |sm| - sm.print(mail.encoded.gsub(/\r/, '')) - sm.flush - end - end - - def perform_delivery_test(mail) - deliveries << mail - end - - def perform_delivery_file(mail) - FileUtils.mkdir_p file_settings[:location] - - (mail.to + mail.cc + mail.bcc).uniq.each do |to| - File.open(File.join(file_settings[:location], to), 'a') { |f| f.write(mail) } - end - end - end - - Base.class_eval do - include Helpers - helper MailHelper end end diff --git a/actionmailer/lib/action_mailer/delivery_method.rb b/actionmailer/lib/action_mailer/delivery_method.rb new file mode 100644 index 0000000000..29a51afdc3 --- /dev/null +++ b/actionmailer/lib/action_mailer/delivery_method.rb @@ -0,0 +1,57 @@ +require "active_support/core_ext/class" +module ActionMailer + module DeliveryMethod + + autoload :File, 'action_mailer/delivery_method/file' + autoload :Sendmail, 'action_mailer/delivery_method/sendmail' + autoload :Smtp, 'action_mailer/delivery_method/smtp' + autoload :Test, 'action_mailer/delivery_method/test' + + # Creates a new DeliveryMethod object according to the given options. + # + # If no arguments are passed to this method, then a new + # ActionMailer::DeliveryMethod::Stmp object will be returned. + # + # If you pass a Symbol as the first argument, then a corresponding + # delivery method class under the ActionMailer::DeliveryMethod namespace + # will be created. + # For example: + # + # ActionMailer::DeliveryMethod.lookup_method(:sendmail) + # # => returns a new ActionMailer::DeliveryMethod::Sendmail object + # + # If the first argument is not a Symbol, then it will simply be returned: + # + # ActionMailer::DeliveryMethod.lookup_method(MyOwnDeliveryMethod.new) + # # => returns MyOwnDeliveryMethod.new + def self.lookup_method(delivery_method) + case delivery_method + when Symbol + method_name = delivery_method.to_s.camelize + method_class = ActionMailer::DeliveryMethod.const_get(method_name) + method_class.new + when nil # default + Smtp.new + else + delivery_method + end + end + + # An abstract delivery method class. There are multiple delivery method classes. + # See the classes under the ActionMailer::DeliveryMethod, e.g. + # ActionMailer::DeliveryMethod::Smtp. + # Smtp is the default delivery method for production + # while Test is used in testing. + # + # each delivery method exposes just one method + # + # delivery_method = ActionMailer::DeliveryMethod::Smtp.new + # delivery_method.perform_delivery(mail) # send the mail via smtp + # + class Method + superclass_delegating_accessor :settings + self.settings = {} + end + + end +end diff --git a/actionmailer/lib/action_mailer/delivery_method/file.rb b/actionmailer/lib/action_mailer/delivery_method/file.rb new file mode 100644 index 0000000000..587ae37ffa --- /dev/null +++ b/actionmailer/lib/action_mailer/delivery_method/file.rb @@ -0,0 +1,21 @@ +require 'tmpdir' + +module ActionMailer + module DeliveryMethod + + # A delivery method implementation which writes all mails to a file. + class File < Method + self.settings = { + :location => defined?(Rails) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails" + } + + def perform_delivery(mail) + FileUtils.mkdir_p settings[:location] + + (mail.to + mail.cc + mail.bcc).uniq.each do |to| + ::File.open(::File.join(settings[:location], to), 'a') { |f| f.write(mail) } + end + end + end + end +end diff --git a/actionmailer/lib/action_mailer/delivery_method/sendmail.rb b/actionmailer/lib/action_mailer/delivery_method/sendmail.rb new file mode 100644 index 0000000000..db55af79f1 --- /dev/null +++ b/actionmailer/lib/action_mailer/delivery_method/sendmail.rb @@ -0,0 +1,22 @@ +module ActionMailer + module DeliveryMethod + + # A delivery method implementation which sends via sendmail. + class Sendmail < Method + self.settings = { + :location => '/usr/sbin/sendmail', + :arguments => '-i -t' + } + + def perform_delivery(mail) + sendmail_args = settings[:arguments] + sendmail_args += " -f \"#{mail['return-path']}\"" if mail['return-path'] + IO.popen("#{settings[:location]} #{sendmail_args}","w+") do |sm| + sm.print(mail.encoded.gsub(/\r/, '')) + sm.flush + end + end + end + + end +end diff --git a/actionmailer/lib/action_mailer/delivery_method/smtp.rb b/actionmailer/lib/action_mailer/delivery_method/smtp.rb new file mode 100644 index 0000000000..86b0ae8329 --- /dev/null +++ b/actionmailer/lib/action_mailer/delivery_method/smtp.rb @@ -0,0 +1,31 @@ +module ActionMailer + module DeliveryMethod + # A delivery method implementation which sends via smtp. + class Smtp < Method + + self.settings = { + :address => "localhost", + :port => 25, + :domain => 'localhost.localdomain', + :user_name => nil, + :password => nil, + :authentication => nil, + :enable_starttls_auto => true, + } + + def perform_delivery(mail) + destinations = mail.destinations + mail.ready_to_send + sender = (mail['return-path'] && mail['return-path'].spec) || mail['from'] + + smtp = Net::SMTP.new(settings[:address], settings[:port]) + smtp.enable_starttls_auto if settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto) + smtp.start(settings[:domain], settings[:user_name], settings[:password], + settings[:authentication]) do |smtp| + smtp.sendmail(mail.encoded, sender, destinations) + end + end + end + + end +end diff --git a/actionmailer/lib/action_mailer/delivery_method/test.rb b/actionmailer/lib/action_mailer/delivery_method/test.rb new file mode 100644 index 0000000000..6e3239d52a --- /dev/null +++ b/actionmailer/lib/action_mailer/delivery_method/test.rb @@ -0,0 +1,12 @@ +module ActionMailer + module DeliveryMethod + + # A delivery method implementation designed for testing, which just appends each record to the :deliveries array + class Test < Method + def perform_delivery(mail) + ActionMailer::Base.deliveries << mail + end + end + + end +end diff --git a/actionmailer/lib/action_mailer/deprecated_body.rb b/actionmailer/lib/action_mailer/deprecated_body.rb new file mode 100644 index 0000000000..50ff262432 --- /dev/null +++ b/actionmailer/lib/action_mailer/deprecated_body.rb @@ -0,0 +1,44 @@ +module ActionMailer + # TODO Remove this module all together in a next release. Ensure that super + # hooks in ActionMailer::Base are removed as well. + module DeprecatedBody + def self.included(base) + base.class_eval do + # Define the body of the message. This is either a Hash (in which case it + # specifies the variables to pass to the template when it is rendered), + # or a string, in which case it specifies the actual text of the message. + adv_attr_accessor :body + end + end + + def initialize_defaults(method_name) + @body ||= {} + end + + def create_parts + if String === @body + ActiveSupport::Deprecation.warn('body is deprecated. To set the body with a text ' << + 'call render(:text => "body").', caller[0,10]) + self.response_body = @body + elsif @body.is_a?(Hash) && !@body.empty? + ActiveSupport::Deprecation.warn('body is deprecated. To set assigns simply ' << + 'use instance variables', caller[0,10]) + @body.each { |k, v| instance_variable_set(:"@#{k}", v) } + end + end + + def render(*args) + options = args.last.is_a?(Hash) ? args.last : {} + if options[:body] + ActiveSupport::Deprecation.warn(':body is deprecated. To set assigns simply ' << + 'use instance variables', caller[0,1]) + + options.delete(:body).each do |k, v| + instance_variable_set(:"@#{k}", v) + end + end + + super + end + end +end diff --git a/actionmailer/lib/action_mailer/helpers.rb b/actionmailer/lib/action_mailer/helpers.rb deleted file mode 100644 index ecd8f0f5b6..0000000000 --- a/actionmailer/lib/action_mailer/helpers.rb +++ /dev/null @@ -1,114 +0,0 @@ -require 'active_support/dependencies' - -module ActionMailer - module Helpers #:nodoc: - def self.included(base) #:nodoc: - # Initialize the base module to aggregate its helpers. - base.class_inheritable_accessor :master_helper_module - base.master_helper_module = Module.new - - # Extend base with class methods to declare helpers. - base.extend(ClassMethods) - - base.class_eval do - # Wrap inherited to create a new master helper module for subclasses. - class << self - alias_method_chain :inherited, :helper - end - - # Wrap initialize_template_class to extend new template class - # instances with the master helper module. - alias_method_chain :initialize_template_class, :helper - end - end - - module ClassMethods - # Makes all the (instance) methods in the helper module available to templates rendered through this controller. - # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules - # available to the templates. - def add_template_helper(helper_module) #:nodoc: - master_helper_module.module_eval "include #{helper_module}" - end - - # Declare a helper: - # helper :foo - # requires 'foo_helper' and includes FooHelper in the template class. - # helper FooHelper - # includes FooHelper in the template class. - # helper { def foo() "#{bar} is the very best" end } - # evaluates the block in the template class, adding method +foo+. - # helper(:three, BlindHelper) { def mice() 'mice' end } - # does all three. - def helper(*args, &block) - args.flatten.each do |arg| - case arg - when Module - add_template_helper(arg) - when String, Symbol - file_name = arg.to_s.underscore + '_helper' - class_name = file_name.camelize - - require_dependency(file_name, "Missing helper file helpers/%s.rb") - # begin - # require_dependency(file_name) - # rescue LoadError => load_error - # requiree = / -- (.*?)(\.rb)?$/.match(load_error.message).to_a[1] - # msg = (requiree == file_name) ? "Missing helper file helpers/#{file_name}.rb" : "Can't load file: #{requiree}" - # raise LoadError.new(msg).copy_blame!(load_error) - # end - - add_template_helper(class_name.constantize) - else - raise ArgumentError, 'helper expects String, Symbol, or Module argument' - end - end - - # Evaluate block in template class if given. - master_helper_module.module_eval(&block) if block_given? - end - - # Declare a controller method as a helper. For example, - # helper_method :link_to - # def link_to(name, options) ... end - # makes the link_to controller method available in the view. - def helper_method(*methods) - methods.flatten.each do |method| - master_helper_module.module_eval <<-end_eval - def #{method}(*args, &block) - controller.__send__(%(#{method}), *args, &block) - end - end_eval - end - end - - # Declare a controller attribute as a helper. For example, - # helper_attr :name - # attr_accessor :name - # makes the name and name= controller methods available in the view. - # The is a convenience wrapper for helper_method. - def helper_attr(*attrs) - attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") } - end - - private - def inherited_with_helper(child) - inherited_without_helper(child) - begin - child.master_helper_module = Module.new - child.master_helper_module.__send__(:include, master_helper_module) - child.helper child.name.to_s.underscore - rescue MissingSourceFile => e - raise unless e.is_missing?("#{child.name.to_s.underscore}_helper") - end - end - end - - private - # Extend the template class instance with our controller's helper module. - def initialize_template_class_with_helper(assigns) - initialize_template_class_without_helper(assigns).tap do |template| - template.extend self.class.master_helper_module - end - end - end -end |