diff options
Diffstat (limited to 'actionmailer')
-rw-r--r-- | actionmailer/Rakefile | 11 | ||||
-rw-r--r-- | actionmailer/actionmailer.gemspec | 12 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer.rb | 1 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/base.rb | 83 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/old_api.rb | 4 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/quoting.rb | 2 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/railtie.rb | 14 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/railties/log_subscriber.rb (renamed from actionmailer/lib/action_mailer/railties/subscriber.rb) | 2 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/version.rb | 5 | ||||
-rw-r--r-- | actionmailer/test/abstract_unit.rb | 5 | ||||
-rw-r--r-- | actionmailer/test/base_test.rb | 83 | ||||
-rw-r--r-- | actionmailer/test/log_subscriber_test.rb (renamed from actionmailer/test/subscriber_test.rb) | 14 | ||||
-rw-r--r-- | actionmailer/test/old_base/asset_host_test.rb | 9 | ||||
-rw-r--r-- | actionmailer/test/old_base/url_test.rb | 10 |
14 files changed, 170 insertions, 85 deletions
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index baea591b97..5b72843f5e 100644 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -4,17 +4,6 @@ require 'rake/testtask' require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require File.join(File.dirname(__FILE__), 'lib', 'action_mailer', 'version') - -PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' -PKG_NAME = 'actionmailer' -PKG_VERSION = ActionMailer::VERSION::STRING + PKG_BUILD -PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" - -RELEASE_NAME = "REL #{PKG_VERSION}" - -RUBY_FORGE_PROJECT = "actionmailer" -RUBY_FORGE_USER = "webster132" desc "Default Task" task :default => [ :test ] diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 31d8efc7bf..a7a2599105 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -1,9 +1,11 @@ +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip + Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY s.name = 'actionmailer' - s.version = '3.0.0.beta1' - s.summary = 'Email composition, delivery, and recieval framework (part of Rails).' - s.description = 'Email composition, delivery, and recieval framework (part of Rails).' + s.version = version + s.summary = 'Email composition, delivery, and receiving framework (part of Rails).' + s.description = 'Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.' s.required_ruby_version = '>= 1.8.7' s.author = 'David Heinemeier Hansson' @@ -17,7 +19,7 @@ Gem::Specification.new do |s| s.has_rdoc = true - s.add_dependency('actionpack', '= 3.0.0.beta1') - s.add_dependency('mail', '~> 2.1.2') + s.add_dependency('actionpack', version) + s.add_dependency('mail', '~> 2.1.3') s.add_dependency('text-format', '~> 1.0.0') end diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index 7f5bcad922..43d73e71b9 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -34,6 +34,7 @@ require 'active_support/core_ext/array/uniq_by' require 'active_support/core_ext/module/attr_internal' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/string/inflections' +require 'active_support/lazy_load_hooks' module ActionMailer extend ::ActiveSupport::Autoload diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 4e89c1ea0c..ef3820ad67 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -181,6 +181,18 @@ module ActionMailer #:nodoc: # and the second being a <tt>application/pdf</tt> with a Base64 encoded copy of the file.pdf book # with the filename +free_book.pdf+. # + # = Observing and Intercepting Mails + # + # ActionMailer provides hooks into the Mail observer and interceptor methods. These allow you to + # register objects that are called during the mail delivery life cycle. + # + # An observer object must implement the <tt>:delivered_email(message)</tt> method which will be + # called once for every email sent after the email has been sent. + # + # An interceptor object must implement the <tt>:delivering_email(message)</tt> method which will be + # called before the email is sent, allowing you to make modifications to the email before it hits + # the delivery agents. Your object should make and needed modifications directly to the passed + # in Mail::Message instance. # # = Configuration options # @@ -255,16 +267,17 @@ module ActionMailer #:nodoc: include AbstractController::Logger include AbstractController::Rendering - include AbstractController::LocalizedCache include AbstractController::Layouts include AbstractController::Helpers include AbstractController::Translation - include AbstractController::Compatibility helper ActionMailer::MailHelper include ActionMailer::OldApi include ActionMailer::DeprecatedApi + + delegate :register_observer, :to => Mail + delegate :register_interceptor, :to => Mail private_class_method :new #:nodoc: @@ -276,6 +289,8 @@ module ActionMailer #:nodoc: :parts_order => [ "text/plain", "text/enriched", "text/html" ] }.freeze + ActionMailer.run_base_hooks(self) + class << self def mailer_name @@ -452,10 +467,27 @@ module ActionMailer #:nodoc: # field for the 'envelope from' value. # # If you do not pass a block to the +mail+ method, it will find all templates in the - # template path that match the method name that it is being called from, it will then - # create parts for each of these templates intelligently, making educated guesses - # on correct content type and sequence, and return a fully prepared Mail::Message - # ready to call <tt>:deliver</tt> on to send. + # view paths using by default the mailer name and the method name that it is being + # called from, it will then create parts for each of these templates intelligently, + # making educated guesses on correct content type and sequence, and return a fully + # prepared Mail::Message ready to call <tt>:deliver</tt> on to send. + # + # For example: + # + # class Notifier < ActionMailer::Base + # default :from => 'no-reply@test.lindsaar.net', + # + # def welcome + # mail(:to => 'mikel@test.lindsaar.net') + # end + # end + # + # Will look for all templates at "app/views/notifier" with name "welcome". However, those + # can be customized: + # + # mail(:template_path => 'notifications', :template_name => 'another') + # + # And now it will look for all templates at "app/views/notifications" with name "another". # # If you do pass a block, you can render specific templates of your choice: # @@ -493,7 +525,7 @@ module ActionMailer #:nodoc: # Merge defaults from class headers = headers.reverse_merge(self.class.default) - charset = headers[:charset] + charset = headers.delete(:charset) # Quote fields headers[:subject] ||= default_i18n_subject @@ -514,13 +546,11 @@ module ActionMailer #:nodoc: end # Set configure delivery behavior - wrap_delivery_behavior!(headers[:delivery_method]) + wrap_delivery_behavior!(headers.delete(:delivery_method)) - # Remove headers already treated and assign all others - headers.except!(:subject, :to, :from, :cc, :bcc, :reply_to) - headers.except!(:body, :parts_order, :content_type, :charset, :delivery_method) + # Remove any missing configuration header and assign all others + headers.except!(:parts_order, :content_type) headers.each { |k, v| m[k] = v } - m end @@ -548,12 +578,12 @@ module ActionMailer #:nodoc: # TODO: Move this into Mail def quote_fields!(headers, charset) #:nodoc: m = @_message - m.subject ||= quote_if_necessary(headers[:subject], charset) if headers[:subject] - m.to ||= quote_address_if_necessary(headers[:to], charset) if headers[:to] - m.from ||= quote_address_if_necessary(headers[:from], charset) if headers[:from] - m.cc ||= quote_address_if_necessary(headers[:cc], charset) if headers[:cc] - m.bcc ||= quote_address_if_necessary(headers[:bcc], charset) if headers[:bcc] - m.reply_to ||= quote_address_if_necessary(headers[:reply_to], charset) if headers[:reply_to] + m.subject ||= quote_if_necessary(headers.delete(:subject), charset) if headers[:subject] + m.to ||= quote_address_if_necessary(headers.delete(:to), charset) if headers[:to] + m.from ||= quote_address_if_necessary(headers.delete(:from), charset) if headers[:from] + m.cc ||= quote_address_if_necessary(headers.delete(:cc), charset) if headers[:cc] + m.bcc ||= quote_address_if_necessary(headers.delete(:bcc), charset) if headers[:bcc] + m.reply_to ||= quote_address_if_necessary(headers.delete(:reply_to), charset) if headers[:reply_to] end def collect_responses_and_parts_order(headers) #:nodoc: @@ -566,13 +596,16 @@ module ActionMailer #:nodoc: responses = collector.responses elsif headers[:body] responses << { - :body => headers[:body], + :body => headers.delete(:body), :content_type => self.class.default[:content_type] || "text/plain" } else - each_template do |template| + templates_path = headers.delete(:template_path) || self.class.mailer_name + templates_name = headers.delete(:template_name) || action_name + + each_template(templates_path, templates_name) do |template| responses << { - :body => render_to_body(:_template => template), + :body => render(:_template => template), :content_type => template.mime_type.to_s } end @@ -581,10 +614,10 @@ module ActionMailer #:nodoc: [responses, parts_order] end - def each_template(&block) #:nodoc: - self.class.view_paths.each do |load_paths| - templates = load_paths.find_all(action_name, {}, self.class.mailer_name) - templates = templates.uniq_by { |t| t.details[:formats] } + def each_template(paths, name, &block) #:nodoc: + Array(paths).each do |path| + templates = lookup_context.find_all(name, path) + templates = templates.uniq_by { |t| t.formats } unless templates.empty? templates.each(&block) diff --git a/actionmailer/lib/action_mailer/old_api.rb b/actionmailer/lib/action_mailer/old_api.rb index 936ceb0dd6..aeb653c5db 100644 --- a/actionmailer/lib/action_mailer/old_api.rb +++ b/actionmailer/lib/action_mailer/old_api.rb @@ -206,8 +206,8 @@ module ActionMailer if String === @body @parts.unshift create_inline_part(@body) elsif @parts.empty? || @parts.all? { |p| p.content_disposition =~ /^attachment/ } - self.class.view_paths.first.find_all(@template, {}, @mailer_name).each do |template| - @parts << create_inline_part(render_to_body(:_template => template), template.mime_type) + lookup_context.find_all(@template, @mailer_name).each do |template| + @parts << create_inline_part(render(:_template => template), template.mime_type) end if @parts.size > 1 diff --git a/actionmailer/lib/action_mailer/quoting.rb b/actionmailer/lib/action_mailer/quoting.rb index 70f636bf69..2b55c0f0ab 100644 --- a/actionmailer/lib/action_mailer/quoting.rb +++ b/actionmailer/lib/action_mailer/quoting.rb @@ -22,7 +22,7 @@ module ActionMailer # A quick-and-dirty regexp for determining whether a string contains any # characters that need escaping. if !defined?(CHARS_NEEDING_QUOTING) - CHARS_NEEDING_QUOTING = /[\000-\011\013\014\016-\037\177-\377]/ + CHARS_NEEDING_QUOTING = Regexp.new('[\000-\011\013\014\016-\037\177-\377]', nil, 'n') end # Quote the given text if it contains any "illegal" characters diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index a3afc23e6a..0182e48425 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -6,19 +6,21 @@ module ActionMailer railtie_name :action_mailer initializer "action_mailer.url_for", :before => :load_environment_config do |app| - ActionMailer::Base.send(:include, ActionController::UrlFor) if defined?(ActionController) + ActionMailer.base_hook { include app.routes.url_helpers } end - require "action_mailer/railties/subscriber" - subscriber ActionMailer::Railties::Subscriber.new + require "action_mailer/railties/log_subscriber" + log_subscriber ActionMailer::Railties::LogSubscriber.new initializer "action_mailer.logger" do - ActionMailer::Base.logger ||= Rails.logger + ActionMailer.base_hook { self.logger ||= Rails.logger } end initializer "action_mailer.set_configs" do |app| - app.config.action_mailer.each do |k,v| - ActionMailer::Base.send "#{k}=", v + ActionMailer.base_hook do + app.config.action_mailer.each do |k,v| + send "#{k}=", v + end end end end diff --git a/actionmailer/lib/action_mailer/railties/subscriber.rb b/actionmailer/lib/action_mailer/railties/log_subscriber.rb index cff852055c..d1b3dd33af 100644 --- a/actionmailer/lib/action_mailer/railties/subscriber.rb +++ b/actionmailer/lib/action_mailer/railties/log_subscriber.rb @@ -1,6 +1,6 @@ module ActionMailer module Railties - class Subscriber < Rails::Subscriber + class LogSubscriber < Rails::LogSubscriber def deliver(event) recipients = Array(event.payload[:to]).join(', ') info("\nSent mail to #{recipients} (%1.fms)" % event.duration) diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb index 56af531d01..7328a7dc80 100644 --- a/actionmailer/lib/action_mailer/version.rb +++ b/actionmailer/lib/action_mailer/version.rb @@ -2,8 +2,9 @@ module ActionMailer module VERSION #:nodoc: MAJOR = 3 MINOR = 0 - TINY = "0.beta1" + TINY = 0 + BUILD = "beta1" - STRING = [MAJOR, MINOR, TINY].join('.') + STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end end diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index f6baa4a9e8..16fef3a9a4 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -1,5 +1,8 @@ require File.expand_path('../../../load_paths', __FILE__) +lib = File.expand_path("#{File.dirname(__FILE__)}/../lib") +$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) + require 'test/unit' require 'action_mailer' require 'action_mailer/test_case' @@ -14,7 +17,7 @@ ActionView::Template.register_template_handler :bak, lambda { |template| "Lame b FIXTURE_LOAD_PATH = File.expand_path('fixtures', File.dirname(__FILE__)) ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH -class MockSMTP +class MockSMTP def self.deliveries @@deliveries end diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index 222db66aaa..c1cf1f0157 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -14,8 +14,13 @@ class BaseTest < ActiveSupport::TestCase mail({:subject => "The first email on new API!"}.merge!(hash)) end - def simple(hash = {}) - mail(hash) + def welcome_with_headers(hash = {}) + headers hash + mail + end + + def welcome_from_another_path(path) + mail(:template_name => "welcome", :template_path => path) end def html_only(hash = {}) @@ -25,11 +30,6 @@ class BaseTest < ActiveSupport::TestCase def plain_text_only(hash = {}) mail(hash) end - - def simple_with_headers(hash = {}) - headers hash - mail - end def attachment_with_content(hash = {}) attachments['invoice.pdf'] = 'This is test File content' @@ -78,8 +78,12 @@ class BaseTest < ActiveSupport::TestCase format.html{ render "welcome" } if include_html end end - - def different_template(template_name='') + + def implicit_different_template(template_name='') + mail(:template_name => template_name) + end + + def explicit_different_template(template_name='') mail do |format| format.text { render :template => "#{mailer_name}/#{template_name}" } format.html { render :template => "#{mailer_name}/#{template_name}" } @@ -88,13 +92,10 @@ class BaseTest < ActiveSupport::TestCase def different_layout(layout_name='') mail do |format| - format.text { - render :layout => layout_name - } + format.text { render :layout => layout_name } format.html { render :layout => layout_name } end end - end test "method call to mail does not raise error" do @@ -154,7 +155,7 @@ class BaseTest < ActiveSupport::TestCase test "can pass random headers in as a hash to mail" do hash = {'X-Special-Domain-Specific-Header' => "SecretValue", 'In-Reply-To' => '1234@mikel.me.com' } - mail = BaseMailer.simple(hash) + mail = BaseMailer.welcome(hash) assert_equal('SecretValue', mail['X-Special-Domain-Specific-Header'].decoded) assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded) end @@ -162,7 +163,7 @@ class BaseTest < ActiveSupport::TestCase test "can pass random headers in as a hash" do hash = {'X-Special-Domain-Specific-Header' => "SecretValue", 'In-Reply-To' => '1234@mikel.me.com' } - mail = BaseMailer.simple_with_headers(hash) + mail = BaseMailer.welcome_with_headers(hash) assert_equal('SecretValue', mail['X-Special-Domain-Specific-Header'].decoded) assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded) end @@ -247,9 +248,9 @@ class BaseTest < ActiveSupport::TestCase end test "uses random default headers from class" do - with_default BaseMailer, "X-SPAM" => "Not spam" do - email = BaseMailer.simple - assert_equal("Not spam", email["X-SPAM"].decoded) + with_default BaseMailer, "X-Custom" => "Custom" do + email = BaseMailer.welcome + assert_equal("Custom", email["X-Custom"].decoded) end end @@ -476,18 +477,58 @@ class BaseTest < ActiveSupport::TestCase end # Rendering - test "that you can specify a different template" do - mail = BaseMailer.different_template('explicit_multipart_templates') + test "you can specify a different template for implicit render" do + mail = BaseMailer.implicit_different_template('implicit_multipart') + assert_equal("HTML Implicit Multipart", mail.html_part.body.decoded) + assert_equal("TEXT Implicit Multipart", mail.text_part.body.decoded) + end + + test "you can specify a different template for explicit render" do + mail = BaseMailer.explicit_different_template('explicit_multipart_templates') assert_equal("HTML Explicit Multipart Templates", mail.html_part.body.decoded) assert_equal("TEXT Explicit Multipart Templates", mail.text_part.body.decoded) end - test "that you can specify a different layout" do + test "you can specify a different layout" do mail = BaseMailer.different_layout('different_layout') assert_equal("HTML -- HTML", mail.html_part.body.decoded) assert_equal("PLAIN -- PLAIN", mail.text_part.body.decoded) end + test "you can specify the template path for implicit lookup" do + mail = BaseMailer.welcome_from_another_path('another.path/base_mailer') + assert_equal("Welcome from another path", mail.body.encoded) + + mail = BaseMailer.welcome_from_another_path(['unknown/invalid', 'another.path/base_mailer']) + assert_equal("Welcome from another path", mail.body.encoded) + end + + # Before and After hooks + + class MyObserver + def self.delivered_email(mail) + end + end + + test "you can register an observer to the mail object that gets informed on email delivery" do + ActionMailer::Base.register_observer(MyObserver) + mail = BaseMailer.welcome + MyObserver.expects(:delivered_email).with(mail) + mail.deliver + end + + class MyInterceptor + def self.delivering_email(mail) + end + end + + test "you can register an interceptor to the mail object that gets passed the mail object before delivery" do + ActionMailer::Base.register_interceptor(MyInterceptor) + mail = BaseMailer.welcome + MyInterceptor.expects(:delivering_email).with(mail) + mail.deliver + end + protected # Execute the block setting the given values and restoring old values after diff --git a/actionmailer/test/subscriber_test.rb b/actionmailer/test/log_subscriber_test.rb index 3d1736d64f..c08c34b4a2 100644 --- a/actionmailer/test/subscriber_test.rb +++ b/actionmailer/test/log_subscriber_test.rb @@ -1,10 +1,14 @@ require "abstract_unit" -require "rails/subscriber/test_helper" -require "action_mailer/railties/subscriber" +require "rails/log_subscriber/test_helper" +require "action_mailer/railties/log_subscriber" -class AMSubscriberTest < ActionMailer::TestCase - include Rails::Subscriber::TestHelper - Rails::Subscriber.add(:action_mailer, ActionMailer::Railties::Subscriber.new) +class AMLogSubscriberTest < ActionMailer::TestCase + include Rails::LogSubscriber::TestHelper + + def setup + super + Rails::LogSubscriber.add(:action_mailer, ActionMailer::Railties::LogSubscriber.new) + end class TestMailer < ActionMailer::Base def basic diff --git a/actionmailer/test/old_base/asset_host_test.rb b/actionmailer/test/old_base/asset_host_test.rb index aa9cfd88dd..0ec0242f55 100644 --- a/actionmailer/test/old_base/asset_host_test.rb +++ b/actionmailer/test/old_base/asset_host_test.rb @@ -14,6 +14,10 @@ class AssetHostTest < Test::Unit::TestCase set_delivery_method :test ActionMailer::Base.perform_deliveries = true ActionMailer::Base.deliveries.clear + AssetHostMailer.configure do |c| + c.asset_host = "http://www.example.com" + c.assets_dir = '' + end end def teardown @@ -21,13 +25,12 @@ class AssetHostTest < Test::Unit::TestCase end def test_asset_host_as_string - ActionController::Base.asset_host = "http://www.example.com" mail = AssetHostMailer.email_with_asset assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.to_s.strip end def test_asset_host_as_one_arguement_proc - ActionController::Base.asset_host = Proc.new { |source| + AssetHostMailer.config.asset_host = Proc.new { |source| if source.starts_with?('/images') "http://images.example.com" else @@ -39,7 +42,7 @@ class AssetHostTest < Test::Unit::TestCase end def test_asset_host_as_two_arguement_proc - ActionController::Base.asset_host = Proc.new {|source,request| + ActionController::Base.config.asset_host = Proc.new {|source,request| if request && request.ssl? "https://www.example.com" else diff --git a/actionmailer/test/old_base/url_test.rb b/actionmailer/test/old_base/url_test.rb index d851431c7a..60740d6b0b 100644 --- a/actionmailer/test/old_base/url_test.rb +++ b/actionmailer/test/old_base/url_test.rb @@ -4,13 +4,19 @@ require 'action_controller' class WelcomeController < ActionController::Base end +AppRoutes = ActionDispatch::Routing::RouteSet.new + class ActionMailer::Base - include ActionController::UrlFor + include AppRoutes.url_helpers end class TestMailer < ActionMailer::Base default_url_options[:host] = 'www.basecamphq.com' + configure do |c| + c.assets_dir = '' # To get the tests to pass + end + def signed_up_with_url(recipient) @recipients = recipient @subject = "[Signed up] Welcome #{recipient}" @@ -61,7 +67,7 @@ class ActionMailerUrlTest < Test::Unit::TestCase def test_signed_up_with_url TestMailer.delivery_method = :test - ActionController::Routing::Routes.draw do |map| + AppRoutes.draw do |map| map.connect ':controller/:action/:id' map.welcome 'welcome', :controller=>"foo", :action=>"bar" end |