提交 abad0970 编写于 作者: J José Valim

Merge remote branch 'mikel/master'

*Rails 3.0 (pending)*
* Whole new API added with tests. See base.rb for full details. Old API is deprecated.
* The Mail::Message class has helped methods for all the field types that return 'common' defaults for the common use case, so to get the subject, mail.subject will give you a string, mail.date will give you a DateTime object, mail.from will give you an array of address specs (mikel@test.lindsaar.net) etc. If you want to access the field object itself, call mail[:field_name] which will return the field object you want, which you can then chain, like mail[:from].formatted
* Mail#content_type now returns the content_type field as a string. If you want the mime type of a mail, then you call Mail#mime_type (eg, text/plain), if you want the parameters of the content type field, you call Mail#content_type_parameters which gives you a hash, eg {'format' => 'flowed', 'charset' => 'utf-8'}
......
......@@ -5,51 +5,72 @@ are used to consolidate code for sending out forgotten passwords, welcome
wishes on signup, invoices for billing, and any other use case that requires
a written notification to either a person or another system.
Action Mailer is in essence a wrapper around Action Controller and the
Mail gem. It provides a way to make emails using templates in the same
way that Action Controller renders views using templates.
Additionally, an Action Mailer class can be used to process incoming email,
such as allowing a weblog to accept new posts from an email (which could even
have been sent from a phone).
== Sending emails
The framework works by setting up all the email details, except the body,
in methods on the service layer. Subject, recipients, sender, and timestamp
are all set up this way. An example of such a method:
The framework works by initializing any instance variables you want to be
available in the email template, followed by a call to +mail+ to deliver
the email.
This can be as simple as:
def signed_up(recipient)
recipients recipient
subject "[Signed up] Welcome #{recipient}"
from "system@loudthinking.com"
body :recipient => recipient
class Notifier < ActionMailer::Base
delivers_from 'system@loudthinking.com'
def welcome(recipient)
@recipient = recipient
mail(:to => recipient,
:subject => "[Signed up] Welcome #{recipient}")
end
end
The body of the email is created by using an Action View template (regular
ERb) that has the content of the body hash parameter available as instance variables.
ERb) that has the instance variables that are declared in the mailer action.
So the corresponding body template for the method above could look like this:
Hello there,
Mr. <%= @recipient %>
Thank you for signing up!
And if the recipient was given as "david@loudthinking.com", the email
generated would look like this:
Date: Sun, 12 Dec 2004 00:00:00 +0100
Date: Mon, 25 Jan 2010 22:48:09 +1100
From: system@loudthinking.com
To: david@loudthinking.com
Message-ID: <4b5d84f9dd6a5_7380800b81ac29578@void.loudthinking.com.mail>
Subject: [Signed up] Welcome david@loudthinking.com
Mime-Version: 1.0
Content-Type: text/plain;
charset="US-ASCII";
Content-Transfer-Encoding: 7bit
Hello there,
Mr. david@loudthinking.com
You never actually call the instance methods like signed_up directly. Instead,
you call class methods like deliver_* and create_* that are automatically
created for each instance method. So if the signed_up method sat on
ApplicationMailer, it would look like this:
In previous version of rails you would call <tt>create_method_name</tt> and
<tt>deliver_method_name</tt>. Rails 3.0 has a much simpler interface, you
simply call the method and optionally call +deliver+ on the return value.
ApplicationMailer.create_signed_up("david@loudthinking.com") # => tmail object for testing
ApplicationMailer.deliver_signed_up("david@loudthinking.com") # sends the email
ApplicationMailer.new.signed_up("david@loudthinking.com") # won't work!
Calling the method returns a Mail Message object:
message = Notifier.welcome #=> Returns a Mail::Message object
message.deliver #=> delivers the email
Or you can just chain the methods together like:
Notifier.welcome.deliver # Creates the email and sends it immediately
== Receiving emails
......@@ -103,16 +124,13 @@ The Base class has the full list of configuration options. Here's an example:
Action Mailer requires that the Action Pack is either available to be required immediately
or is accessible as a GEM.
Additionally, Action Mailer requires the Mail gem, http://github.com/mikel/mail
== Bundled software
* tmail 0.10.8 by Minero Aoki released under LGPL
Read more on http://i.loveruby.net/en/prog/tmail.html
* Text::Format 0.63 by Austin Ziegler released under OpenSource
Read more on http://www.halostatue.ca/ruby/Text__Format.html
== Download
The latest version of Action Mailer can be found at
......
......@@ -22,14 +22,14 @@ task :default => [ :test ]
# Run the unit tests
Rake::TestTask.new { |t|
t.libs << "test"
t.pattern = 'test/*_test.rb'
t.pattern = 'test/**/*_test.rb'
t.warning = true
}
namespace :test do
task :isolated do
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir.glob("test/*_test.rb").all? do |file|
Dir.glob("test/**/*_test.rb").all? do |file|
system(ruby, '-Ilib:test', file)
end or raise "Failures"
end
......
......@@ -11,7 +11,7 @@
s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 3.0.pre')
s.add_dependency('mail', '~> 1.6.0')
s.add_dependency('mail', '~> 2.1.1')
s.files = Dir['CHANGELOG', 'README', 'MIT-LICENSE', 'lib/**/*']
s.has_rdoc = true
......
......@@ -31,10 +31,12 @@ module ActionMailer
extend ::ActiveSupport::Autoload
autoload :AdvAttrAccessor
autoload :Collector
autoload :Base
autoload :DeliveryMethod
autoload :DeprecatedBody
autoload :DeliveryMethods
autoload :DeprecatedApi
autoload :MailHelper
autoload :OldApi
autoload :Quoting
autoload :TestCase
autoload :TestHelper
......
require 'abstract_controller/collector'
require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/core_ext/array/extract_options'
module ActionMailer #:nodoc:
class Collector
include AbstractController::Collector
attr_reader :responses
def initialize(context, &block)
@context = context
@responses = []
@default_render = block
@default_formats = context.formats
end
def any(*args, &block)
options = args.extract_options!
raise "You have to supply at least one format" if args.empty?
args.each { |type| send(type, options.dup, &block) }
end
alias :all :any
def custom(mime, options={}, &block)
options.reverse_merge!(:content_type => mime.to_s)
@context.formats = [mime.to_sym]
options[:body] = if block
block.call
else
@default_render.call
end
@responses << options
@context.formats = @default_formats
end
end
end
\ No newline at end of file
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
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.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
}
def perform_delivery(mail)
FileUtils.mkdir_p settings[:location]
mail.destinations.uniq.each do |to|
::File.open(::File.join(settings[:location], to), 'a') { |f| f.write(mail) }
end
end
end
end
end
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
require 'net/smtp'
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
sender = (mail['return-path'] && mail['return-path'].address) || 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
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
require 'tmpdir'
module ActionMailer
# This modules handles everything related to the delivery, from registering new
# delivery methods to configuring the mail object to be send.
module DeliveryMethods
extend ActiveSupport::Concern
included do
extlib_inheritable_accessor :delivery_methods, :delivery_method,
:instance_writer => false
# Do not make this inheritable, because we always want it to propagate
cattr_accessor :raise_delivery_errors
self.raise_delivery_errors = true
cattr_accessor :perform_deliveries
self.perform_deliveries = true
self.delivery_methods = {}
self.delivery_method = :smtp
add_delivery_method :smtp, Mail::SMTP,
:address => "localhost",
:port => 25,
:domain => 'localhost.localdomain',
:user_name => nil,
:password => nil,
:authentication => nil,
:enable_starttls_auto => true
add_delivery_method :file, Mail::FileDelivery,
:location => defined?(Rails.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
add_delivery_method :sendmail, Mail::Sendmail,
:location => '/usr/sbin/sendmail',
:arguments => '-i -t'
add_delivery_method :test, Mail::TestMailer
end
module ClassMethods
# Provides a list of emails that have been delivered by Mail::TestMailer
delegate :deliveries, :deliveries=, :to => Mail::TestMailer
# Adds a new delivery method through the given class using the given symbol
# as alias and the default options supplied:
#
# Example:
#
# add_delivery_method :sendmail, Mail::Sendmail,
# :location => '/usr/sbin/sendmail',
# :arguments => '-i -t'
#
def add_delivery_method(symbol, klass, default_options={})
unless respond_to?(:"#{symbol}_settings")
extlib_inheritable_accessor(:"#{symbol}_settings", :instance_writer => false)
end
send(:"#{symbol}_settings=", default_options)
self.delivery_methods[symbol.to_sym] = klass
end
def wrap_delivery_behavior(mail, method=nil) #:nodoc:
method ||= self.delivery_method
mail.delivery_handler = self
if method.is_a?(Symbol)
if klass = delivery_methods[method.to_sym]
mail.delivery_method(klass, send(:"#{method}_settings"))
else
raise "Invalid delivery method #{method.inspect}"
end
else
mail.delivery_method(method)
end
mail.perform_deliveries = perform_deliveries
mail.raise_delivery_errors = raise_delivery_errors
end
end
def wrap_delivery_behavior!(*args) #:nodoc:
self.class.wrap_delivery_behavior(message, *args)
end
end
end
\ No newline at end of file
module ActionMailer
# This is the API which is deprecated and is going to be removed on Rails 3.1 release.
# Part of the old API will be deprecated after 3.1, for a smoother deprecation process.
# Chech those in OldApi instead.
module DeprecatedApi #:nodoc:
extend ActiveSupport::Concern
module ClassMethods
# Deliver the given mail object directly. This can be used to deliver
# a preconstructed mail object, like:
#
# email = MyMailer.create_some_mail(parameters)
# email.set_some_obscure_header "frobnicate"
# MyMailer.deliver(email)
def deliver(mail, show_warning=true)
if show_warning
ActiveSupport::Deprecation.warn "#{self}.deliver is deprecated, call " <<
"deliver in the mailer instance instead", caller[0,2]
end
raise "no mail object available for delivery!" unless mail
wrap_delivery_behavior(mail)
mail.deliver
mail
end
def template_root
self.view_paths && self.view_paths.first
end
def template_root=(root)
ActiveSupport::Deprecation.warn "template_root= is deprecated, use view_paths.unshift instead", caller[0,2]
self.view_paths = ActionView::Base.process_view_paths(root)
end
def respond_to?(method_symbol, include_private = false)
matches_dynamic_method?(method_symbol) || super
end
def method_missing(method_symbol, *parameters)
if match = matches_dynamic_method?(method_symbol)
case match[1]
when 'create'
ActiveSupport::Deprecation.warn "#{self}.create_#{match[2]} is deprecated, " <<
"use #{self}.#{match[2]} instead", caller[0,2]
new(match[2], *parameters).message
when 'deliver'
ActiveSupport::Deprecation.warn "#{self}.deliver_#{match[2]} is deprecated, " <<
"use #{self}.#{match[2]}.deliver instead", caller[0,2]
new(match[2], *parameters).message.deliver
else super
end
else
super
end
end
private
def matches_dynamic_method?(method_name)
method_name = method_name.to_s
/^(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name)
end
end
# Delivers a Mail object. By default, it delivers the cached mail
# object (from the <tt>create!</tt> method). If no cached mail object exists, and
# no alternate has been given as the parameter, this will fail.
def deliver!(mail = @_message)
ActiveSupport::Deprecation.warn "Calling deliver in the AM::Base object is deprecated, " <<
"please call deliver in the Mail instance", caller[0,2]
self.class.deliver(mail, false)
end
alias :deliver :deliver!
def render(*args)
options = args.last.is_a?(Hash) ? args.last : {}
if options[:body]
ActiveSupport::Deprecation.warn(':body in render deprecated. Please use instance ' <<
'variables as assigns instead', caller[0,1])
body options.delete(:body)
end
super
end
# Render a message but does not set it as mail body. Useful for rendering
# data for part and attachments.
#
# Examples:
#
# render_message "special_message"
# render_message :template => "special_message"
# render_message :inline => "<%= 'Hi!' %>"
#
def render_message(*args)
ActiveSupport::Deprecation.warn "render_message is deprecated, use render instead", caller[0,2]
render(*args)
end
private
def create_parts
if @body.is_a?(Hash) && !@body.empty?
ActiveSupport::Deprecation.warn "Giving a hash to body is deprecated, please use instance variables instead", caller[0,2]
@body.each { |k, v| instance_variable_set(:"@#{k}", v) }
end
super
end
end
end
\ No newline at end of file
module ActionMailer
# TODO Remove this module all together in a next release. Ensure that super
# hooks and @assigns_set in ActionMailer::Base are removed as well.
module DeprecatedBody
extend ActionMailer::AdvAttrAccessor
# 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
def initialize_defaults(method_name)
@body ||= {}
end
def attachment(params, &block)
if params[:body]
ActiveSupport::Deprecation.warn('attachment :body => "string" is deprecated. To set the body of an attachment ' <<
'please use :data instead, like attachment :data => "string"', caller[0,10])
params[:data] = params.delete(:body)
end
end
def create_parts
if String === @body && !defined?(@assigns_set)
ActiveSupport::Deprecation.warn('body(String) is deprecated. To set the body with a text ' <<
'call render(:text => "body")', caller[0,10])
self.response_body = @body
elsif self.response_body
@body = self.response_body
end
end
def render(*args)
options = args.last.is_a?(Hash) ? args.last : {}
if options[:body]
ActiveSupport::Deprecation.warn(':body in render deprecated. Please call body ' <<
'with a hash instead', caller[0,1])
body options.delete(:body)
end
super
end
end
end
......@@ -17,8 +17,13 @@ def block_format(text)
end
# Access the mailer instance.
def mailer #:nodoc:
def mailer
@_controller
end
# Access the message instance.
def message
@_message
end
end
end
module ActionMailer
module OldApi #:nodoc:
extend ActiveSupport::Concern
included do
extend ActionMailer::AdvAttrAccessor
@@protected_instance_variables = %w(@parts)
cattr_reader :protected_instance_variables
# Specify the BCC addresses for the message
adv_attr_accessor :bcc
# Specify the CC addresses for the message.
adv_attr_accessor :cc
# Specify the charset to use for the message. This defaults to the
# +default_charset+ specified for ActionMailer::Base.
adv_attr_accessor :charset
# Specify the content type for the message. This defaults to <tt>text/plain</tt>
# in most cases, but can be automatically set in some situations.
adv_attr_accessor :content_type
# Specify the from address for the message.
adv_attr_accessor :from
# Specify the address (if different than the "from" address) to direct
# replies to this message.
adv_attr_accessor :reply_to
# Specify additional headers to be added to the message.
adv_attr_accessor :headers
# Specify the order in which parts should be sorted, based on content-type.
# This defaults to the value for the +default_implicit_parts_order+.
adv_attr_accessor :implicit_parts_order
# Defaults to "1.0", but may be explicitly given if needed.
adv_attr_accessor :mime_version
# The recipient addresses for the message, either as a string (for a single
# address) or an array (for multiple addresses).
adv_attr_accessor :recipients
# The date on which the message was sent. If not set (the default), the
# header will be set by the delivery agent.
adv_attr_accessor :sent_on
# Specify the subject of the message.
adv_attr_accessor :subject
# Specify the template name to use for current message. This is the "base"
# template name, without the extension or directory, and may be used to
# have multiple mailer methods share the same template.
adv_attr_accessor :template
# 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.
adv_attr_accessor :mailer_name
# 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
# Alias controller_path to mailer_name so render :partial in views work.
alias :controller_path :mailer_name
end
def process(method_name, *args)
initialize_defaults(method_name)
super
unless @mail_was_called
create_parts
create_mail
end
@_message
end
# Add a part to a multipart message, with the given content-type. The
# part itself is yielded to the block so that other properties (charset,
# body, headers, etc.) can be set on it.
def part(params)
params = {:content_type => params} if String === params
if custom_headers = params.delete(:headers)
params.merge!(custom_headers)
end
part = Mail::Part.new(params)
yield part if block_given?
@parts << part
end
# Add an attachment to a multipart message. This is simply a part with the
# content-disposition set to "attachment".
def attachment(params, &block)
params = { :content_type => params } if String === params
params[:content] ||= params.delete(:data) || params.delete(:body)
if params[:filename]
params = normalize_file_hash(params)
else
params = normalize_nonfile_hash(params)
end
part(params, &block)
end
protected
def normalize_nonfile_hash(params)
content_disposition = "attachment;"
mime_type = params.delete(:mime_type)
if content_type = params.delete(:content_type)
content_type = "#{mime_type || content_type};"
end
params[:body] = params.delete(:data) if params[:data]
{ :content_type => content_type,
:content_disposition => content_disposition }.merge(params)
end
def normalize_file_hash(params)
filename = File.basename(params.delete(:filename))
content_disposition = "attachment; filename=\"#{File.basename(filename)}\""
mime_type = params.delete(:mime_type)
if (content_type = params.delete(:content_type)) && (content_type !~ /filename=/)
content_type = "#{mime_type || content_type}; filename=\"#{filename}\""
end
params[:body] = params.delete(:data) if params[:data]
{ :content_type => content_type,
:content_disposition => content_disposition }.merge(params)
end
def create_mail
m = @_message
quote_fields!({:subject => subject, :to => recipients, :from => from,
:bcc => bcc, :cc => cc, :reply_to => reply_to}, charset)
m.mime_version = mime_version unless mime_version.nil?
m.date = sent_on.to_time rescue sent_on if sent_on
@headers.each { |k, v| m[k] = v }
real_content_type, ctype_attrs = parse_content_type
main_type, sub_type = split_content_type(real_content_type)
if @parts.size == 1 && @parts.first.parts.empty?
m.content_type([main_type, sub_type, ctype_attrs])
m.body = @parts.first.body.encoded
else
@parts.each do |p|
m.add_part(p)
end
m.body.set_sort_order(@implicit_parts_order)
m.body.sort_parts!
if real_content_type =~ /multipart/
ctype_attrs.delete "charset"
m.content_type([main_type, sub_type, ctype_attrs])
end
end
wrap_delivery_behavior!
m.content_transfer_encoding = '8bit' unless m.body.only_us_ascii?
@_message
end
# 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 ||= self.class.default_charset.dup
@content_type ||= self.class.default_content_type.dup
@implicit_parts_order ||= self.class.default_implicit_parts_order.dup
@mime_version ||= self.class.default_mime_version.dup if self.class.default_mime_version
@mailer_name ||= self.class.mailer_name.dup
@template ||= method_name
@mail_was_called = false
@parts ||= []
@headers ||= {}
@sent_on ||= Time.now
@body ||= {}
end
def create_parts
if String === @body
self.response_body = @body
end
if String === response_body
@parts.unshift create_inline_part(response_body)
else
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)
end
if @parts.size > 1
@content_type = "multipart/alternative" if @content_type !~ /^multipart/
end
# 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 create_inline_part(body, mime_type=nil)
ct = mime_type || "text/plain"
main_type, sub_type = split_content_type(ct.to_s)
Mail::Part.new(
:content_type => [main_type, sub_type, {:charset => charset}],
:content_disposition => "inline",
:body => body
)
end
def split_content_type(ct)
ct.to_s.split("/")
end
def parse_content_type(defaults=nil)
if @content_type.blank?
[ nil, {} ]
else
ctype, *attrs = @content_type.split(/;\s*/)
attrs = attrs.inject({}) { |h,s| k,v = s.split(/\=/, 2); h[k] = v; h }
[ctype, {"charset" => @charset}.merge(attrs)]
end
end
end
end
\ No newline at end of file
......@@ -37,7 +37,7 @@ def determine_default_mailer(name)
def initialize_test_deliveries
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
ActionMailer::Base.deliveries.clear
end
def set_expected_mail
......
......@@ -58,7 +58,6 @@ def assert_no_emails(&block)
end
end
# TODO: Deprecate this
module Test
module Unit
class TestCase
......
......@@ -2,19 +2,27 @@ module Mail
class Message
def set_content_type(*args)
STDERR.puts("Message#set_content_type is deprecated, please just call Message#content_type with the same arguments.\n#{caller}")
ActiveSupport::Deprecation.warn('Message#set_content_type is deprecated, please just call ' <<
'Message#content_type with the same arguments', caller[0,2])
content_type(*args)
end
alias :old_transfer_encoding :transfer_encoding
def transfer_encoding(value = nil)
if value
STDERR.puts("Message#transfer_encoding is deprecated, please call Message#content_transfer_encoding with the same arguments.\n#{caller}")
ActiveSupport::Deprecation.warn('Message#transfer_encoding is deprecated, please call ' <<
'Message#content_transfer_encoding with the same arguments', caller[0,2])
content_transfer_encoding(value)
else
old_transfer_encoding
end
end
def original_filename
ActiveSupport::Deprecation.warn('Message#original_filename is deprecated, ' <<
'please call Message#filename', caller[0,2])
filename
end
end
end
\ No newline at end of file
......@@ -8,7 +8,6 @@
require 'rubygems'
require 'test/unit'
require 'action_mailer'
# Show backtraces for deprecated behavior for quicker cleanup.
......@@ -18,14 +17,10 @@
ActionView::Template.register_template_handler :haml, lambda { |template| "Look its HAML!".inspect }
ActionView::Template.register_template_handler :bak, lambda { |template| "Lame backup".inspect }
ActionView::Base::DEFAULT_CONFIG = { :assets_dir => '/nowhere' }
$:.unshift "#{File.dirname(__FILE__)}/fixtures/helpers"
FIXTURE_LOAD_PATH = File.expand_path('fixtures', File.dirname(__FILE__))
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
ActionMailer::Base.template_root = FIXTURE_LOAD_PATH
class MockSMTP
class MockSMTP
def self.deliveries
@@deliveries
end
......@@ -49,19 +44,11 @@ def self.new(*args)
end
end
def uses_gem(gem_name, test_name, version = '> 0')
gem gem_name.to_s, version
require gem_name.to_s
yield
rescue LoadError
$stderr.puts "Skipping #{test_name} tests. `gem install #{gem_name}` and try again."
end
def set_delivery_method(delivery_method)
def set_delivery_method(method)
@old_delivery_method = ActionMailer::Base.delivery_method
ActionMailer::Base.delivery_method = delivery_method
ActionMailer::Base.delivery_method = method
end
def restore_delivery_method
ActionMailer::Base.delivery_method = @old_delivery_method
end
end
\ No newline at end of file
# encoding: utf-8
require 'abstract_unit'
class BaseTest < ActiveSupport::TestCase
DEFAULT_HEADERS = {
:to => 'mikel@test.lindsaar.net',
:subject => 'The first email on new API!'
}
class BaseMailer < ActionMailer::Base
delivers_from 'jose@test.plataformatec.com'
self.mailer_name = "base_mailer"
def welcome(hash = {})
headers['X-SPAM'] = "Not SPAM"
mail(DEFAULT_HEADERS.merge(hash))
end
def attachment_with_content(hash = {})
attachments['invoice.pdf'] = 'This is test File content'
mail(DEFAULT_HEADERS.merge(hash))
end
def attachment_with_hash
attachments['invoice.jpg'] = { :data => "you smiling", :mime_type => "image/x-jpg",
:transfer_encoding => "base64" }
mail(DEFAULT_HEADERS)
end
def implicit_multipart(hash = {})
attachments['invoice.pdf'] = 'This is test File content' if hash.delete(:attachments)
mail(DEFAULT_HEADERS.merge(hash))
end
def implicit_with_locale(hash = {})
mail(DEFAULT_HEADERS.merge(hash))
end
def explicit_multipart(hash = {})
attachments['invoice.pdf'] = 'This is test File content' if hash.delete(:attachments)
mail(DEFAULT_HEADERS.merge(hash)) do |format|
format.text { render :text => "TEXT Explicit Multipart" }
format.html { render :text => "HTML Explicit Multipart" }
end
end
def explicit_multipart_templates(hash = {})
mail(DEFAULT_HEADERS.merge(hash)) do |format|
format.html
format.text
end
end
def explicit_multipart_with_any(hash = {})
mail(DEFAULT_HEADERS.merge(hash)) do |format|
format.any(:text, :html){ render :text => "Format with any!" }
end
end
def custom_block(include_html=false)
mail(DEFAULT_HEADERS) do |format|
format.text(:content_transfer_encoding => "base64"){ render "welcome" }
format.html{ render "welcome" } if include_html
end
end
end
test "method call to mail does not raise error" do
assert_nothing_raised { BaseMailer.welcome.deliver }
end
# Basic mail usage without block
test "mail() should set the headers of the mail message" do
email = BaseMailer.welcome.deliver
assert_equal(email.to, ['mikel@test.lindsaar.net'])
assert_equal(email.from, ['jose@test.plataformatec.com'])
assert_equal(email.subject, 'The first email on new API!')
end
test "mail() with from overwrites the class level default" do
email = BaseMailer.welcome(:from => 'someone@else.com').deliver
assert_equal(email.from, ['someone@else.com'])
end
test "mail() with bcc, cc, content_type, charset, mime_version, reply_to and date" do
@time = Time.now
email = BaseMailer.welcome(:bcc => 'bcc@test.lindsaar.net',
:cc => 'cc@test.lindsaar.net',
:content_type => 'multipart/mixed',
:charset => 'iso-8559-1',
:mime_version => '2.0',
:reply_to => 'reply-to@test.lindsaar.net',
:date => @time).deliver
assert_equal(email.bcc, ['bcc@test.lindsaar.net'])
assert_equal(email.cc, ['cc@test.lindsaar.net'])
assert_equal(email.content_type, 'multipart/mixed')
assert_equal(email.charset, 'iso-8559-1')
assert_equal(email.mime_version, '2.0')
assert_equal(email.reply_to, ['reply-to@test.lindsaar.net'])
assert_equal(email.date, @time)
end
test "mail() renders the template using the method being processed" do
email = BaseMailer.welcome.deliver
assert_equal("Welcome", email.body.encoded)
end
test "can pass in :body to the mail method hash" do
email = BaseMailer.welcome(:body => "Hello there").deliver
assert_equal("text/plain", email.mime_type)
assert_equal("Hello there", email.body.encoded)
end
# Custom headers
test "custom headers" do
email = BaseMailer.welcome.deliver
assert_equal("Not SPAM", email['X-SPAM'].decoded)
end
# Attachments
test "attachment with content" do
email = BaseMailer.attachment_with_content.deliver
assert_equal(1, email.attachments.length)
assert_equal('invoice.pdf', email.attachments[0].filename)
assert_equal('This is test File content', email.attachments['invoice.pdf'].decoded)
end
test "attachment gets content type from filename" do
email = BaseMailer.attachment_with_content.deliver
assert_equal('invoice.pdf', email.attachments[0].filename)
end
test "attachment with hash" do
email = BaseMailer.attachment_with_hash.deliver
assert_equal(1, email.attachments.length)
assert_equal('invoice.jpg', email.attachments[0].filename)
assert_equal("\312\213\254\232)b", email.attachments['invoice.jpg'].decoded)
end
test "sets mime type to multipart/mixed when attachment is included" do
email = BaseMailer.attachment_with_content.deliver
assert_equal(1, email.attachments.length)
assert_equal("multipart/mixed", email.mime_type)
end
test "adds the rendered template as part" do
email = BaseMailer.attachment_with_content.deliver
assert_equal(2, email.parts.length)
assert_equal("multipart/mixed", email.mime_type)
assert_equal("text/html", email.parts[0].mime_type)
assert_equal("Attachment with content", email.parts[0].body.encoded)
assert_equal("application/pdf", email.parts[1].mime_type)
assert_equal("VGhpcyBpcyB0ZXN0IEZpbGUgY29udGVudA==\r\n", email.parts[1].body.encoded)
end
test "adds the given :body as part" do
email = BaseMailer.attachment_with_content(:body => "I'm the eggman").deliver
assert_equal(2, email.parts.length)
assert_equal("multipart/mixed", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("I'm the eggman", email.parts[0].body.encoded)
assert_equal("application/pdf", email.parts[1].mime_type)
assert_equal("VGhpcyBpcyB0ZXN0IEZpbGUgY29udGVudA==\r\n", email.parts[1].body.encoded)
end
# Defaults values
test "uses default charset from class" do
swap BaseMailer, :default_charset => "US-ASCII" do
email = BaseMailer.welcome.deliver
assert_equal("US-ASCII", email.charset)
email = BaseMailer.welcome(:charset => "iso-8559-1").deliver
assert_equal("iso-8559-1", email.charset)
end
end
test "uses default content type from class" do
swap BaseMailer, :default_content_type => "text/html" do
email = BaseMailer.welcome.deliver
assert_equal("text/html", email.mime_type)
email = BaseMailer.welcome(:content_type => "text/plain").deliver
assert_equal("text/plain", email.mime_type)
end
end
test "uses default mime version from class" do
swap BaseMailer, :default_mime_version => "2.0" do
email = BaseMailer.welcome.deliver
assert_equal("2.0", email.mime_version)
email = BaseMailer.welcome(:mime_version => "1.0").deliver
assert_equal("1.0", email.mime_version)
end
end
test "subject gets default from I18n" do
email = BaseMailer.welcome(:subject => nil).deliver
assert_equal "Welcome", email.subject
I18n.backend.store_translations('en', :actionmailer => {:base_mailer => {:welcome => {:subject => "New Subject!"}}})
email = BaseMailer.welcome(:subject => nil).deliver
assert_equal "New Subject!", email.subject
end
# Implicit multipart
test "implicit multipart" do
email = BaseMailer.implicit_multipart.deliver
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("TEXT Implicit Multipart", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("HTML Implicit Multipart", email.parts[1].body.encoded)
end
test "implicit multipart with sort order" do
order = ["text/html", "text/plain"]
swap BaseMailer, :default_implicit_parts_order => order do
email = BaseMailer.implicit_multipart.deliver
assert_equal("text/html", email.parts[0].mime_type)
assert_equal("text/plain", email.parts[1].mime_type)
email = BaseMailer.implicit_multipart(:parts_order => order.reverse).deliver
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("text/html", email.parts[1].mime_type)
end
end
test "implicit multipart with attachments creates nested parts" do
email = BaseMailer.implicit_multipart(:attachments => true).deliver
assert_equal("application/pdf", email.parts[0].mime_type)
assert_equal("multipart/alternative", email.parts[1].mime_type)
assert_equal("text/plain", email.parts[1].parts[0].mime_type)
assert_equal("TEXT Implicit Multipart", email.parts[1].parts[0].body.encoded)
assert_equal("text/html", email.parts[1].parts[1].mime_type)
assert_equal("HTML Implicit Multipart", email.parts[1].parts[1].body.encoded)
end
test "implicit multipart with attachments and sort order" do
order = ["text/html", "text/plain"]
swap BaseMailer, :default_implicit_parts_order => order do
email = BaseMailer.implicit_multipart(:attachments => true).deliver
assert_equal("application/pdf", email.parts[0].mime_type)
assert_equal("multipart/alternative", email.parts[1].mime_type)
assert_equal("text/plain", email.parts[1].parts[1].mime_type)
assert_equal("text/html", email.parts[1].parts[0].mime_type)
end
end
test "implicit multipart with default locale" do
email = BaseMailer.implicit_with_locale.deliver
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("Implicit with locale TEXT", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("Implicit with locale EN HTML", email.parts[1].body.encoded)
end
test "implicit multipart with other locale" do
swap I18n, :locale => :pl do
email = BaseMailer.implicit_with_locale.deliver
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("Implicit with locale PL TEXT", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("Implicit with locale HTML", email.parts[1].body.encoded)
end
end
test "implicit multipart with several view paths uses the first one with template" do
begin
BaseMailer.view_paths.unshift(File.join(FIXTURE_LOAD_PATH, "another.path"))
email = BaseMailer.welcome.deliver
assert_equal("Welcome from another path", email.body.encoded)
ensure
BaseMailer.view_paths.shift
end
end
test "implicit multipart with inexistent templates uses the next view path" do
begin
BaseMailer.view_paths.unshift(File.join(FIXTURE_LOAD_PATH, "unknown"))
email = BaseMailer.welcome.deliver
assert_equal("Welcome", email.body.encoded)
ensure
BaseMailer.view_paths.shift
end
end
# Explicit multipart
test "explicit multipart" do
email = BaseMailer.explicit_multipart.deliver
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("TEXT Explicit Multipart", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("HTML Explicit Multipart", email.parts[1].body.encoded)
end
test "explicit multipart does not sort order" do
order = ["text/html", "text/plain"]
swap BaseMailer, :default_implicit_parts_order => order do
email = BaseMailer.explicit_multipart.deliver
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("text/html", email.parts[1].mime_type)
email = BaseMailer.explicit_multipart(:parts_order => order.reverse).deliver
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("text/html", email.parts[1].mime_type)
end
end
test "explicit multipart with attachments creates nested parts" do
email = BaseMailer.explicit_multipart(:attachments => true).deliver
assert_equal("application/pdf", email.parts[0].mime_type)
assert_equal("multipart/alternative", email.parts[1].mime_type)
assert_equal("text/plain", email.parts[1].parts[0].mime_type)
assert_equal("TEXT Explicit Multipart", email.parts[1].parts[0].body.encoded)
assert_equal("text/html", email.parts[1].parts[1].mime_type)
assert_equal("HTML Explicit Multipart", email.parts[1].parts[1].body.encoded)
end
test "explicit multipart with templates" do
email = BaseMailer.explicit_multipart_templates.deliver
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/html", email.parts[0].mime_type)
assert_equal("HTML Explicit Multipart Templates", email.parts[0].body.encoded)
assert_equal("text/plain", email.parts[1].mime_type)
assert_equal("TEXT Explicit Multipart Templates", email.parts[1].body.encoded)
end
test "explicit multipart with any" do
email = BaseMailer.explicit_multipart_with_any.deliver
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("Format with any!", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("Format with any!", email.parts[1].body.encoded)
end
test "explicit multipart with options" do
email = BaseMailer.custom_block(true).deliver
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("base64", email.parts[0].content_transfer_encoding)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("7bit", email.parts[1].content_transfer_encoding)
end
test "explicit multipart with one part is rendered as body" do
email = BaseMailer.custom_block.deliver
assert_equal(0, email.parts.size)
assert_equal("text/plain", email.mime_type)
assert_equal("base64", email.content_transfer_encoding)
end
# Class level API with method missing
test "should respond to action methods" do
assert BaseMailer.respond_to?(:welcome)
assert BaseMailer.respond_to?(:implicit_multipart)
assert !BaseMailer.respond_to?(:mail)
assert !BaseMailer.respond_to?(:headers)
end
test "calling just the action should return the generated mail object" do
BaseMailer.deliveries.clear
email = BaseMailer.welcome
assert_equal(0, BaseMailer.deliveries.length)
assert_equal('The first email on new API!', email.subject)
end
test "calling deliver on the action should deliver the mail object" do
BaseMailer.deliveries.clear
BaseMailer.expects(:deliver_mail).once
BaseMailer.welcome.deliver
end
test "calling deliver on the action should increment the deliveries collection" do
BaseMailer.deliveries.clear
BaseMailer.welcome.deliver
assert_equal(1, BaseMailer.deliveries.length)
end
test "calling deliver, ActionMailer should yield back to mail to let it call :do_delivery on itself" do
mail = Mail::Message.new
mail.expects(:do_delivery).once
BaseMailer.expects(:welcome).returns(mail)
BaseMailer.welcome.deliver
end
test "explicit multipart should be multipart" do
mail = BaseMailer.explicit_multipart
assert_not_nil(mail.content_type_parameters[:boundary])
end
protected
# Execute the block setting the given values and restoring old values after
# the block is executed.
def swap(object, new_values)
old_values = {}
new_values.each do |key, value|
old_values[key] = object.send key
object.send :"#{key}=", value
end
yield
ensure
old_values.each do |key, value|
object.send :"#{key}=", value
end
end
end
\ No newline at end of file
require 'abstract_unit'
class DefaultDeliveryMethodMailer < ActionMailer::Base
end
class NonDefaultDeliveryMethodMailer < ActionMailer::Base
self.delivery_method = :sendmail
end
class FileDeliveryMethodMailer < ActionMailer::Base
self.delivery_method = :file
end
class CustomDeliveryMethod
attr_accessor :custom_deliveries
def initialize()
@customer_deliveries = []
end
def self.perform_delivery(mail)
self.custom_deliveries << mail
end
end
class CustomerDeliveryMailer < ActionMailer::Base
self.delivery_method = CustomDeliveryMethod.new
end
class ActionMailerBase_delivery_method_Test < Test::Unit::TestCase
def setup
set_delivery_method :smtp
end
def teardown
restore_delivery_method
end
def test_should_be_the_default_smtp
assert_instance_of ActionMailer::DeliveryMethod::Smtp, ActionMailer::Base.delivery_method
end
end
class DefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
def setup
set_delivery_method :smtp
end
def teardown
restore_delivery_method
end
def test_should_be_the_default_smtp
assert_instance_of ActionMailer::DeliveryMethod::Smtp, DefaultDeliveryMethodMailer.delivery_method
end
end
class NonDefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
def setup
set_delivery_method :smtp
end
def teardown
restore_delivery_method
end
def test_should_be_the_set_delivery_method
assert_instance_of ActionMailer::DeliveryMethod::Sendmail, NonDefaultDeliveryMethodMailer.delivery_method
end
end
class FileDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
def setup
set_delivery_method :smtp
end
def teardown
restore_delivery_method
end
def test_should_be_the_set_delivery_method
assert_instance_of ActionMailer::DeliveryMethod::File, FileDeliveryMethodMailer.delivery_method
end
def test_should_default_location_to_the_tmpdir
assert_equal "#{Dir.tmpdir}/mails", ActionMailer::Base.file_settings[:location]
end
end
class CustomDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
def setup
set_delivery_method :smtp
end
def teardown
restore_delivery_method
end
def test_should_be_the_set_delivery_method
assert_instance_of CustomDeliveryMethod, CustomerDeliveryMailer.delivery_method
end
end
require 'abstract_unit'
require 'mail'
class MyCustomDelivery
end
class BogusDelivery
def initialize(*)
end
def deliver!(mail)
raise "failed"
end
end
class DefaultsDeliveryMethodsTest < ActiveSupport::TestCase
test "default smtp settings" do
settings = { :address => "localhost",
:port => 25,
:domain => 'localhost.localdomain',
:user_name => nil,
:password => nil,
:authentication => nil,
:enable_starttls_auto => true }
assert_equal settings, ActionMailer::Base.smtp_settings
end
test "default file delivery settings" do
settings = {:location => "#{Dir.tmpdir}/mails"}
assert_equal settings, ActionMailer::Base.file_settings
end
test "default sendmail settings" do
settings = {:location => '/usr/sbin/sendmail',
:arguments => '-i -t'}
assert_equal settings, ActionMailer::Base.sendmail_settings
end
end
class CustomDeliveryMethodsTest < ActiveSupport::TestCase
def setup
@old_delivery_method = ActionMailer::Base.delivery_method
ActionMailer::Base.add_delivery_method :custom, MyCustomDelivery
end
def teardown
ActionMailer::Base.delivery_method = @old_delivery_method
ActionMailer::Base.delivery_methods.delete(:custom)
end
test "allow to add custom delivery method" do
ActionMailer::Base.delivery_method = :custom
assert_equal :custom, ActionMailer::Base.delivery_method
end
test "allow to customize custom settings" do
ActionMailer::Base.custom_settings = { :foo => :bar }
assert_equal Hash[:foo => :bar], ActionMailer::Base.custom_settings
end
test "respond to custom settings" do
assert_respond_to ActionMailer::Base, :custom_settings
assert_respond_to ActionMailer::Base, :custom_settings=
end
test "does not respond to unknown settings" do
assert_raise NoMethodError do
ActionMailer::Base.another_settings
end
end
end
class MailDeliveryTest < ActiveSupport::TestCase
class DeliveryMailer < ActionMailer::Base
DEFAULT_HEADERS = {
:to => 'mikel@test.lindsaar.net',
:from => 'jose@test.plataformatec.com'
}
def welcome(hash={})
mail(DEFAULT_HEADERS.merge(hash))
end
end
def setup
ActionMailer::Base.delivery_method = :smtp
end
def teardown
DeliveryMailer.delivery_method = :smtp
DeliveryMailer.perform_deliveries = true
DeliveryMailer.raise_delivery_errors = true
end
test "ActionMailer should be told when Mail gets delivered" do
DeliveryMailer.deliveries.clear
DeliveryMailer.expects(:deliver_mail).once
DeliveryMailer.welcome.deliver
end
test "delivery method can be customized per instance" do
email = DeliveryMailer.welcome.deliver
assert_instance_of Mail::SMTP, email.delivery_method
email = DeliveryMailer.welcome(:delivery_method => :test).deliver
assert_instance_of Mail::TestMailer, email.delivery_method
end
test "delivery method can be customized in subclasses not changing the parent" do
DeliveryMailer.delivery_method = :test
assert_equal :smtp, ActionMailer::Base.delivery_method
$BREAK = true
email = DeliveryMailer.welcome.deliver
assert_instance_of Mail::TestMailer, email.delivery_method
end
test "non registered delivery methods raises errors" do
DeliveryMailer.delivery_method = :unknown
assert_raise RuntimeError do
DeliveryMailer.welcome.deliver
end
end
test "does not perform deliveries if requested" do
DeliveryMailer.perform_deliveries = false
DeliveryMailer.deliveries.clear
Mail::Message.any_instance.expects(:deliver!).never
DeliveryMailer.welcome.deliver
end
test "does not append the deliveries collection if told not to perform the delivery" do
DeliveryMailer.perform_deliveries = false
DeliveryMailer.deliveries.clear
DeliveryMailer.welcome.deliver
assert_equal(0, DeliveryMailer.deliveries.length)
end
test "raise errors on bogus deliveries" do
DeliveryMailer.delivery_method = BogusDelivery
DeliveryMailer.deliveries.clear
assert_raise RuntimeError do
DeliveryMailer.welcome.deliver
end
end
test "does not increment the deliveries collection on error" do
DeliveryMailer.delivery_method = BogusDelivery
DeliveryMailer.deliveries.clear
assert_raise RuntimeError do
DeliveryMailer.welcome.deliver
end
assert_equal(0, DeliveryMailer.deliveries.length)
end
test "does not raise errors on bogus deliveries if set" do
DeliveryMailer.delivery_method = BogusDelivery
DeliveryMailer.raise_delivery_errors = false
assert_nothing_raised do
DeliveryMailer.welcome.deliver
end
end
test "does not increment the deliveries collection on bogus deliveries" do
DeliveryMailer.delivery_method = BogusDelivery
DeliveryMailer.raise_delivery_errors = false
DeliveryMailer.deliveries.clear
DeliveryMailer.welcome.deliver
assert_equal(0, DeliveryMailer.deliveries.length)
end
end
\ No newline at end of file
Welcome from another path
\ No newline at end of file
Attachment with content
\ No newline at end of file
HTML Explicit Multipart Templates
\ No newline at end of file
TEXT Explicit Multipart Templates
\ No newline at end of file
HTML Implicit Multipart
\ No newline at end of file
TEXT Implicit Multipart
\ No newline at end of file
Implicit with locale EN HTML
\ No newline at end of file
Implicit with locale HTML
\ No newline at end of file
Implicit with locale PL TEXT
\ No newline at end of file
Implicit with locale TEXT
\ No newline at end of file
Hello, <%= person_name %>. Thanks for registering!
This message brought to you by <%= name_of_the_mailer_class %>.
From "Romeo and Juliet":
<%= block_format @text %>
Good ol' Shakespeare.
module ExampleHelper
def example_format(text)
"<em><strong><small>#{h(text)}</small></strong></em>".html_safe!
end
end
body: <%= @body %>
bar: <%= @bar %>
\ No newline at end of file
require 'abstract_unit'
module MailerHelper
def person_name
"Mr. Joe Person"
end
end
class HelperMailer < ActionMailer::Base
helper MailerHelper
helper :example
def use_helper(recipient)
recipients recipient
subject "using helpers"
from "tester@example.com"
end
def use_example_helper(recipient)
recipients recipient
subject "using helpers"
from "tester@example.com"
@text = "emphasize me!"
end
def use_mail_helper(recipient)
recipients recipient
subject "using mailing helpers"
from "tester@example.com"
def use_mail_helper
@text = "But soft! What light through yonder window breaks? It is the east, " +
"and Juliet is the sun. Arise, fair sun, and kill the envious moon, " +
"which is sick and pale with grief that thou, her maid, art far more " +
"fair than she. Be not her maid, for she is envious! Her vestal " +
"livery is but sick and green, and none but fools do wear it. Cast " +
"it off!"
end
def use_helper_method(recipient)
recipients recipient
subject "using helpers"
from "tester@example.com"
@text = "emphasize me!"
mail_with_defaults do |format|
format.html { render(:inline => "<%= block_format @text %>") }
end
end
private
def name_of_the_mailer_class
self.class.name
def use_mailer
mail_with_defaults do |format|
format.html { render(:inline => "<%= mailer.message.subject %>") }
end
helper_method :name_of_the_mailer_class
end
end
class MailerHelperTest < Test::Unit::TestCase
def new_mail( charset="utf-8" )
mail = Mail.new
mail.set_content_type "text", "plain", { "charset" => charset } if charset
mail
def use_message
mail_with_defaults do |format|
format.html { render(:inline => "<%= message.subject %>") }
end
end
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
protected
@recipient = 'test@localhost'
end
def teardown
restore_delivery_method
end
def test_use_helper
mail = HelperMailer.create_use_helper(@recipient)
assert_match %r{Mr. Joe Person}, mail.encoded
def mail_with_defaults(&block)
mail(:to => "test@localhost", :from => "tester@example.com",
:subject => "using helpers", &block)
end
end
def test_use_example_helper
mail = HelperMailer.create_use_example_helper(@recipient)
assert_match %r{<em><strong><small>emphasize me!}, mail.encoded
class MailerHelperTest < ActionMailer::TestCase
def test_use_mail_helper
mail = HelperMailer.use_mail_helper
assert_match %r{ But soft!}, mail.body.encoded
assert_match %r{east, and\r\n Juliet}, mail.body.encoded
end
def test_use_helper_method
mail = HelperMailer.create_use_helper_method(@recipient)
assert_match %r{HelperMailer}, mail.encoded
def test_use_mailer
mail = HelperMailer.use_mailer
assert_match "using helpers", mail.body.encoded
end
def test_use_mail_helper
mail = HelperMailer.create_use_mail_helper(@recipient)
assert_match %r{ But soft!}, mail.encoded
assert_match %r{east, and\r\n Juliet}, mail.encoded
def test_use_message
mail = HelperMailer.use_message
assert_match "using helpers", mail.body.encoded
end
end
require 'abstract_unit'
class MailTest < Test::Unit::TestCase
def test_body
m = Mail.new
expected = 'something_with_underscores'
m.content_transfer_encoding = 'quoted-printable'
quoted_body = [expected].pack('*M')
m.body = quoted_body
assert_equal "something_with_underscores=\r\n", m.body.encoded
# CHANGED: body returns object, not string, Changed m.body to m.body.to_s
assert_equal expected, m.body.to_s
end
def test_nested_attachments_are_recognized_correctly
fixture = File.read("#{File.dirname(__FILE__)}/fixtures/raw_email_with_nested_attachment")
mail = Mail.new(fixture)
assert_equal 2, mail.attachments.length
assert_equal "image/png", mail.attachments.first.mime_type
assert_equal 1902, mail.attachments.first.decoded.length
assert_equal "application/pkcs7-signature", mail.attachments.last.mime_type
end
end
require 'abstract_unit'
class AssetHostMailer < ActionMailer::Base
def email_with_asset(recipient)
recipients recipient
def email_with_asset
recipients 'test@localhost'
subject "testing email containing asset path while asset_host is set"
from "tester@example.com"
end
......@@ -12,9 +12,7 @@ class AssetHostTest < Test::Unit::TestCase
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
@recipient = 'test@localhost'
ActionMailer::Base.deliveries.clear
end
def teardown
......@@ -23,7 +21,7 @@ def teardown
def test_asset_host_as_string
ActionController::Base.asset_host = "http://www.example.com"
mail = AssetHostMailer.deliver_email_with_asset(@recipient)
mail = AssetHostMailer.email_with_asset
assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.to_s.strip
end
......@@ -35,7 +33,7 @@ def test_asset_host_as_one_arguement_proc
"http://assets.example.com"
end
}
mail = AssetHostMailer.deliver_email_with_asset(@recipient)
mail = AssetHostMailer.email_with_asset
assert_equal "<img alt=\"Somelogo\" src=\"http://images.example.com/images/somelogo.png\" />", mail.body.to_s.strip
end
......@@ -48,7 +46,7 @@ def test_asset_host_as_two_arguement_proc
end
}
mail = nil
assert_nothing_raised { mail = AssetHostMailer.deliver_email_with_asset(@recipient) }
assert_nothing_raised { mail = AssetHostMailer.email_with_asset }
assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.to_s.strip
end
end
\ No newline at end of file
require 'abstract_unit'
class AutoLayoutMailer < ActionMailer::Base
def hello(recipient)
recipients recipient
def hello
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
end
def spam(recipient)
recipients recipient
def spam
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
......@@ -16,8 +17,8 @@ def spam(recipient)
render(:inline => "Hello, <%= @world %>", :layout => 'spam')
end
def nolayout(recipient)
recipients recipient
def nolayout
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
......@@ -25,8 +26,8 @@ def nolayout(recipient)
render(:inline => "Hello, <%= @world %>", :layout => false)
end
def multipart(recipient, type = nil)
recipients recipient
def multipart(type = nil)
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
......@@ -37,14 +38,14 @@ def multipart(recipient, type = nil)
class ExplicitLayoutMailer < ActionMailer::Base
layout 'spam', :except => [:logout]
def signup(recipient)
recipients recipient
def signup
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
end
def logout(recipient)
recipients recipient
def logout
recipients 'test@localhost'
subject "You have a mail"
from "tester@example.com"
end
......@@ -54,9 +55,7 @@ class LayoutMailerTest < Test::Unit::TestCase
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
@recipient = 'test@localhost'
ActionMailer::Base.deliveries.clear
end
def teardown
......@@ -64,12 +63,12 @@ def teardown
end
def test_should_pickup_default_layout
mail = AutoLayoutMailer.create_hello(@recipient)
mail = AutoLayoutMailer.hello
assert_equal "Hello from layout Inside", mail.body.to_s.strip
end
def test_should_pickup_multipart_layout
mail = AutoLayoutMailer.create_multipart(@recipient)
mail = AutoLayoutMailer.multipart
# CHANGED: content_type returns an object
# assert_equal "multipart/alternative", mail.content_type
assert_equal "multipart/alternative", mail.mime_type
......@@ -93,7 +92,7 @@ def test_should_pickup_multipart_layout
end
def test_should_pickup_multipartmixed_layout
mail = AutoLayoutMailer.create_multipart(@recipient, "multipart/mixed")
mail = AutoLayoutMailer.multipart("multipart/mixed")
# CHANGED: content_type returns an object
# assert_equal "multipart/mixed", mail.content_type
assert_equal "multipart/mixed", mail.mime_type
......@@ -115,7 +114,7 @@ def test_should_pickup_multipartmixed_layout
end
def test_should_fix_multipart_layout
mail = AutoLayoutMailer.create_multipart(@recipient, "text/plain")
mail = AutoLayoutMailer.multipart("text/plain")
assert_equal "multipart/alternative", mail.mime_type
assert_equal 2, mail.parts.size
......@@ -128,22 +127,22 @@ def test_should_fix_multipart_layout
def test_should_pickup_layout_given_to_render
mail = AutoLayoutMailer.create_spam(@recipient)
mail = AutoLayoutMailer.spam
assert_equal "Spammer layout Hello, Earth", mail.body.to_s.strip
end
def test_should_respect_layout_false
mail = AutoLayoutMailer.create_nolayout(@recipient)
mail = AutoLayoutMailer.nolayout
assert_equal "Hello, Earth", mail.body.to_s.strip
end
def test_explicit_class_layout
mail = ExplicitLayoutMailer.create_signup(@recipient)
mail = ExplicitLayoutMailer.signup
assert_equal "Spammer layout We do not spam", mail.body.to_s.strip
end
def test_explicit_layout_exceptions
mail = ExplicitLayoutMailer.create_logout(@recipient)
mail = ExplicitLayoutMailer.logout
assert_equal "You logged out", mail.body.to_s.strip
end
end
require 'abstract_unit'
class RenderMailer < ActionMailer::Base
def inline_template(recipient)
recipients recipient
def inline_template
recipients 'test@localhost'
subject "using helpers"
from "tester@example.com"
......@@ -10,46 +10,46 @@ def inline_template(recipient)
render :inline => "Hello, <%= @world %>"
end
def file_template(recipient)
recipients recipient
def file_template
recipients 'test@localhost'
subject "using helpers"
from "tester@example.com"
@recipient = recipient
@recipient = 'test@localhost'
render :file => "templates/signed_up"
end
def implicit_body(recipient)
recipients recipient
def implicit_body
recipients 'test@localhost'
subject "using helpers"
from "tester@example.com"
@recipient = recipient
@recipient = 'test@localhost'
render :template => "templates/signed_up"
end
def rxml_template(recipient)
recipients recipient
def rxml_template
recipients 'test@localhost'
subject "rendering rxml template"
from "tester@example.com"
end
def included_subtemplate(recipient)
recipients recipient
def included_subtemplate
recipients 'test@localhost'
subject "Including another template in the one being rendered"
from "tester@example.com"
end
def mailer_accessor(recipient)
recipients recipient
def mailer_accessor
recipients 'test@localhost'
subject "Mailer Accessor"
from "tester@example.com"
render :inline => "Look, <%= mailer.subject %>!"
end
def no_instance_variable(recipient)
recipients recipient
def no_instance_variable
recipients 'test@localhost'
subject "No Instance Variable"
from "tester@example.com"
......@@ -65,16 +65,16 @@ def initialize_defaults(method_name)
end
class FirstMailer < ActionMailer::Base
def share(recipient)
recipients recipient
def share
recipients 'test@localhost'
subject "using helpers"
from "tester@example.com"
end
end
class SecondMailer < ActionMailer::Base
def share(recipient)
recipients recipient
def share
recipients 'test@localhost'
subject "using helpers"
from "tester@example.com"
end
......@@ -86,7 +86,7 @@ class RenderHelperTest < Test::Unit::TestCase
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
ActionMailer::Base.deliveries.clear
@recipient = 'test@localhost'
end
......@@ -96,37 +96,37 @@ def teardown
end
def test_implicit_body
mail = RenderMailer.create_implicit_body(@recipient)
mail = RenderMailer.implicit_body
assert_equal "Hello there, \n\nMr. test@localhost", mail.body.to_s.strip
end
def test_inline_template
mail = RenderMailer.create_inline_template(@recipient)
mail = RenderMailer.inline_template
assert_equal "Hello, Earth", mail.body.to_s.strip
end
def test_file_template
mail = RenderMailer.create_file_template(@recipient)
mail = RenderMailer.file_template
assert_equal "Hello there, \n\nMr. test@localhost", mail.body.to_s.strip
end
def test_rxml_template
mail = RenderMailer.deliver_rxml_template(@recipient)
mail = RenderMailer.rxml_template.deliver
assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test/>", mail.body.to_s.strip
end
def test_included_subtemplate
mail = RenderMailer.deliver_included_subtemplate(@recipient)
mail = RenderMailer.included_subtemplate.deliver
assert_equal "Hey Ho, let's go!", mail.body.to_s.strip
end
def test_mailer_accessor
mail = RenderMailer.deliver_mailer_accessor(@recipient)
mail = RenderMailer.mailer_accessor.deliver
assert_equal "Look, Mailer Accessor!", mail.body.to_s.strip
end
def test_no_instance_variable
mail = RenderMailer.deliver_no_instance_variable(@recipient)
mail = RenderMailer.no_instance_variable.deliver
assert_equal "Look, subject.nil? is true!", mail.body.to_s.strip
end
end
......@@ -135,7 +135,7 @@ class FirstSecondHelperTest < Test::Unit::TestCase
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
ActionMailer::Base.deliveries.clear
@recipient = 'test@localhost'
end
......@@ -145,13 +145,13 @@ def teardown
end
def test_ordering
mail = FirstMailer.create_share(@recipient)
mail = FirstMailer.share
assert_equal "first mail", mail.body.to_s.strip
mail = SecondMailer.create_share(@recipient)
mail = SecondMailer.share
assert_equal "second mail", mail.body.to_s.strip
mail = FirstMailer.create_share(@recipient)
mail = FirstMailer.share
assert_equal "first mail", mail.body.to_s.strip
mail = SecondMailer.create_share(@recipient)
mail = SecondMailer.share
assert_equal "second mail", mail.body.to_s.strip
end
end
require 'abstract_unit'
class TmailCompatTest < Test::Unit::TestCase
class TmailCompatTest < ActiveSupport::TestCase
def test_set_content_type_raises_deprecation_warning
mail = Mail.new
STDERR.expects(:puts) # Deprecation warning
assert_nothing_raised do
mail.set_content_type "text/plain"
assert_deprecated do
assert_nothing_raised do
mail.set_content_type "text/plain"
end
end
assert_equal mail.mime_type, "text/plain"
end
def test_transfer_encoding_raises_deprecation_warning
mail = Mail.new
STDERR.expects(:puts) # Deprecation warning
assert_nothing_raised do
mail.transfer_encoding "base64"
assert_deprecated do
assert_nothing_raised do
mail.transfer_encoding "base64"
end
end
assert_equal mail.content_transfer_encoding, "base64"
end
......
......@@ -44,7 +44,7 @@ def new_mail( charset="utf-8" )
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
ActionMailer::Base.deliveries.clear
@recipient = 'test@localhost'
end
......@@ -54,6 +54,8 @@ def teardown
end
def test_signed_up_with_url
TestMailer.delivery_method = :test
ActionController::Routing::Routes.draw do |map|
map.connect ':controller/:action/:id'
map.welcome 'welcome', :controller=>"foo", :action=>"bar"
......@@ -67,14 +69,14 @@ def test_signed_up_with_url
expected.date = Time.local(2004, 12, 12)
created = nil
assert_nothing_raised { created = TestMailer.create_signed_up_with_url(@recipient) }
assert_nothing_raised { created = TestMailer.signed_up_with_url(@recipient) }
assert_not_nil created
expected.message_id = '<123@456>'
created.message_id = '<123@456>'
assert_equal expected.encoded, created.encoded
assert_nothing_raised { TestMailer.deliver_signed_up_with_url(@recipient) }
assert_nothing_raised { TestMailer.signed_up_with_url(@recipient).deliver }
assert_not_nil ActionMailer::Base.deliveries.first
delivered = ActionMailer::Base.deliveries.first
......
......@@ -24,21 +24,21 @@ def set_logger(logger)
end
def test_deliver_is_notified
TestMailer.deliver_basic
TestMailer.basic.deliver
wait
assert_equal 1, @logger.logged(:info).size
assert_match /Sent mail to somewhere@example.com/, @logger.logged(:info).first
assert_equal 1, @logger.logged(:debug).size
assert_match /Hello world/, @logger.logged(:debug).first
assert_equal(1, @logger.logged(:info).size)
assert_match(/Sent mail to somewhere@example.com/, @logger.logged(:info).first)
assert_equal(1, @logger.logged(:debug).size)
assert_match(/Hello world/, @logger.logged(:debug).first)
end
def test_receive_is_notified
fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email")
TestMailer.receive(fixture)
wait
assert_equal 1, @logger.logged(:info).size
assert_match /Received mail/, @logger.logged(:info).first
assert_equal 1, @logger.logged(:debug).size
assert_match /Jamis/, @logger.logged(:debug).first
assert_equal(1, @logger.logged(:info).size)
assert_match(/Received mail/, @logger.logged(:info).first)
assert_equal(1, @logger.logged(:debug).size)
assert_match(/Jamis/, @logger.logged(:debug).first)
end
end
\ No newline at end of file
......@@ -12,7 +12,7 @@ def test
class TestHelperMailerTest < ActionMailer::TestCase
def test_setup_sets_right_action_mailer_options
assert_instance_of ActionMailer::DeliveryMethod::Test, ActionMailer::Base.delivery_method
assert_equal :test, ActionMailer::Base.delivery_method
assert ActionMailer::Base.perform_deliveries
assert_equal [], ActionMailer::Base.deliveries
end
......@@ -44,7 +44,7 @@ def test_encode
def test_assert_emails
assert_nothing_raised do
assert_emails 1 do
TestHelperMailer.deliver_test
TestHelperMailer.test.deliver
end
end
end
......@@ -52,27 +52,27 @@ def test_assert_emails
def test_repeated_assert_emails_calls
assert_nothing_raised do
assert_emails 1 do
TestHelperMailer.deliver_test
TestHelperMailer.test.deliver
end
end
assert_nothing_raised do
assert_emails 2 do
TestHelperMailer.deliver_test
TestHelperMailer.deliver_test
TestHelperMailer.test.deliver
TestHelperMailer.test.deliver
end
end
end
def test_assert_emails_with_no_block
assert_nothing_raised do
TestHelperMailer.deliver_test
TestHelperMailer.test.deliver
assert_emails 1
end
assert_nothing_raised do
TestHelperMailer.deliver_test
TestHelperMailer.deliver_test
TestHelperMailer.test.deliver
TestHelperMailer.test.deliver
assert_emails 3
end
end
......@@ -80,7 +80,7 @@ def test_assert_emails_with_no_block
def test_assert_no_emails
assert_nothing_raised do
assert_no_emails do
TestHelperMailer.create_test
TestHelperMailer.test
end
end
end
......@@ -88,7 +88,7 @@ def test_assert_no_emails
def test_assert_emails_too_few_sent
error = assert_raise ActiveSupport::TestCase::Assertion do
assert_emails 2 do
TestHelperMailer.deliver_test
TestHelperMailer.test.deliver
end
end
......@@ -98,8 +98,8 @@ def test_assert_emails_too_few_sent
def test_assert_emails_too_many_sent
error = assert_raise ActiveSupport::TestCase::Assertion do
assert_emails 1 do
TestHelperMailer.deliver_test
TestHelperMailer.deliver_test
TestHelperMailer.test.deliver
TestHelperMailer.test.deliver
end
end
......@@ -109,7 +109,7 @@ def test_assert_emails_too_many_sent
def test_assert_no_emails_failure
error = assert_raise ActiveSupport::TestCase::Assertion do
assert_no_emails do
TestHelperMailer.deliver_test
TestHelperMailer.test.deliver
end
end
......
......@@ -10,6 +10,7 @@ module AbstractController
autoload :Base
autoload :Callbacks
autoload :Collector
autoload :Helpers
autoload :Layouts
autoload :LocalizedCache
......
module AbstractController
module Collector
def self.generate_method_for_mime(mime)
sym = mime.is_a?(Symbol) ? mime : mime.to_sym
const = sym.to_s.upcase
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{sym}(*args, &block) # def html(*args, &block)
custom(Mime::#{const}, *args, &block) # custom(Mime::HTML, *args, &block)
end # end
RUBY
end
Mime::SET.each do |mime|
generate_method_for_mime(mime)
end
protected
def method_missing(symbol, &block)
mime_constant = Mime.const_get(symbol.to_s.upcase)
if Mime::SET.include?(mime_constant)
AbstractController::Collector.generate_method_for_mime(mime_constant)
send(symbol, &block)
else
super
end
end
end
end
\ No newline at end of file
......@@ -41,10 +41,6 @@ def view_context
# Mostly abstracts the fact that calling render twice is a DoubleRenderError.
# Delegates render_to_body and sticks the result in self.response_body.
def render(*args, &block)
if response_body
raise AbstractController::DoubleRenderError
end
options = _normalize_options(*args, &block)
self.response_body = render_to_body(options)
end
......
require 'abstract_controller/collector'
module ActionController #:nodoc:
module MimeResponds #:nodoc:
extend ActiveSupport::Concern
......@@ -265,6 +267,7 @@ def retrieve_response_from_mimes(mimes=nil, &block)
end
class Collector #:nodoc:
include AbstractController::Collector
attr_accessor :order
def initialize(&block)
......@@ -289,32 +292,6 @@ def custom(mime_type, &block)
def response_for(mime)
@responses[mime] || @responses[Mime::ALL] || @default_response
end
def self.generate_method_for_mime(mime)
sym = mime.is_a?(Symbol) ? mime : mime.to_sym
const = sym.to_s.upcase
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{sym}(&block) # def html(&block)
custom(Mime::#{const}, &block) # custom(Mime::HTML, &block)
end # end
RUBY
end
Mime::SET.each do |mime|
generate_method_for_mime(mime)
end
def method_missing(symbol, &block)
mime_constant = Mime.const_get(symbol.to_s.upcase)
if Mime::SET.include?(mime_constant)
self.class.generate_method_for_mime(mime_constant)
send(symbol, &block)
else
super
end
end
end
end
end
......@@ -13,6 +13,10 @@ def process_action(*)
end
def render(*args)
if response_body
raise ::AbstractController::DoubleRenderError
end
args << {} unless args.last.is_a?(Hash)
super(*args)
self.content_type ||= args.last[:_template].mime_type.to_s
......
require 'abstract_unit'
module AbstractController
module Testing
class MyCollector
include Collector
attr_accessor :responses
def initialize
@responses = []
end
def custom(mime, *args, &block)
@responses << [mime, args, block]
end
end
class TestCollector < ActiveSupport::TestCase
test "responds to default mime types" do
collector = MyCollector.new
assert_respond_to collector, :html
assert_respond_to collector, :text
end
test "does not respond to unknown mime types" do
collector = MyCollector.new
assert !collector.respond_to?(:unknown)
end
test "register mime types on method missing" do
AbstractController::Collector.send(:remove_method, :js)
collector = MyCollector.new
assert !collector.respond_to?(:js)
collector.js
assert_respond_to collector, :js
end
test "does not register unknown mime types" do
collector = MyCollector.new
assert_raise NameError do
collector.unknown
end
end
test "generated methods call custom with args received" do
collector = MyCollector.new
collector.html
collector.text(:foo)
collector.js(:bar) { :baz }
assert_equal [Mime::HTML, [], nil], collector.responses[0]
assert_equal [Mime::TEXT, [:foo], nil], collector.responses[1]
assert_equal [Mime::JS, [:bar]], collector.responses[2][0,2]
assert_equal :baz, collector.responses[2][2].call
end
end
end
end
\ No newline at end of file
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/array/access'
require 'active_support/core_ext/array/uniq_by'
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/array/grouping'
......
......@@ -13,19 +13,6 @@ def to_sentence(options = {})
default_two_words_connector = I18n.translate(:'support.array.two_words_connector', :locale => options[:locale])
default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale])
# Try to emulate to_sentences previous to 2.3
if options.has_key?(:connector) || options.has_key?(:skip_last_comma)
::ActiveSupport::Deprecation.warn(":connector has been deprecated. Use :words_connector instead", caller) if options.has_key? :connector
::ActiveSupport::Deprecation.warn(":skip_last_comma has been deprecated. Use :last_word_connector instead", caller) if options.has_key? :skip_last_comma
skip_last_comma = options.delete :skip_last_comma
if connector = options.delete(:connector)
options[:last_word_connector] ||= skip_last_comma ? connector : ", #{connector}"
else
options[:last_word_connector] ||= skip_last_comma ? default_two_words_connector : default_last_word_connector
end
end
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
options.reverse_merge! :words_connector => default_words_connector, :two_words_connector => default_two_words_connector, :last_word_connector => default_last_word_connector
......
class Array
# Return an unique array based on the criteria given as a proc.
#
# [1, 2, 3, 4].uniq_by { |i| i.odd? }
# #=> [1, 2]
#
def uniq_by
hash, array = {}, []
each { |i| hash[yield(i)] ||= (array << i) }
array
end
# Same as uniq_by, but modifies self.
def uniq_by!
replace(uniq_by{ |i| yield(i) })
end
end
class Hash
# Returns a new hash with +self+ and +other_hash+ merged recursively.
def deep_merge(other_hash)
target = dup
other_hash.each_pair do |k,v|
tv = target[k]
target[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_merge(v) : v
end
target
dup.deep_merge!(other_hash)
end
# Returns a new hash with +self+ and +other_hash+ merged recursively.
# Modifies the receiver in place.
def deep_merge!(other_hash)
replace(deep_merge(other_hash))
other_hash.each_pair do |k,v|
tv = self[k]
self[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_merge(v) : v
end
self
end
end
class Hash
# Return a new hash with all keys converted to strings.
def stringify_keys
inject({}) do |options, (key, value)|
options[key.to_s] = value
options
end
dup.stringify_keys!
end
# Destructively convert all keys to strings.
......@@ -18,16 +15,16 @@ def stringify_keys!
# Return a new hash with all keys converted to symbols, as long as
# they respond to +to_sym+.
def symbolize_keys
inject({}) do |options, (key, value)|
options[(key.to_sym rescue key) || key] = value
options
end
dup.symbolize_keys!
end
# Destructively convert all keys to symbols, as long as they respond
# to +to_sym+.
def symbolize_keys!
self.replace(self.symbolize_keys)
keys.each do |key|
self[(key.to_sym rescue key) || key] = delete(key)
end
self
end
alias_method :to_options, :symbolize_keys
......
......@@ -52,8 +52,6 @@ def test_to_param_array
end
class ArrayExtToSentenceTests < Test::Unit::TestCase
include ActiveSupport::Testing::Deprecation
def test_plain_array_to_sentence
assert_equal "", [].to_sentence
assert_equal "one", ['one'].to_sentence
......@@ -62,28 +60,12 @@ def test_plain_array_to_sentence
end
def test_to_sentence_with_words_connector
assert_deprecated(":connector has been deprecated. Use :words_connector instead") do
assert_equal "one, two, three", ['one', 'two', 'three'].to_sentence(:connector => '')
end
assert_deprecated(":connector has been deprecated. Use :words_connector instead") do
assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence(:connector => 'and ')
end
assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(:words_connector => ' ')
assert_equal "one & two, and three", ['one', 'two', 'three'].to_sentence(:words_connector => ' & ')
assert_equal "onetwo, and three", ['one', 'two', 'three'].to_sentence(:words_connector => nil)
end
def test_to_sentence_with_last_word_connector
assert_deprecated(":skip_last_comma has been deprecated. Use :last_word_connector instead") do
assert_equal "one, two and three", ['one', 'two', 'three'].to_sentence(:skip_last_comma => true)
end
assert_deprecated(":skip_last_comma has been deprecated. Use :last_word_connector instead") do
assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence(:skip_last_comma => false)
end
assert_equal "one, two, and also three", ['one', 'two', 'three'].to_sentence(:last_word_connector => ', and also ')
assert_equal "one, twothree", ['one', 'two', 'three'].to_sentence(:last_word_connector => nil)
assert_equal "one, two three", ['one', 'two', 'three'].to_sentence(:last_word_connector => ' ')
......@@ -320,6 +302,28 @@ def test_extract_options
end
end
class ArrayUniqByTests < Test::Unit::TestCase
def test_uniq_by
assert_equal [1,2], [1,2,3,4].uniq_by { |i| i.odd? }
assert_equal [1,2], [1,2,3,4].uniq_by(&:even?)
assert_equal (-5..0).to_a, (-5..5).to_a.uniq_by{ |i| i**2 }
end
def test_uniq_by!
a = [1,2,3,4]
a.uniq_by! { |i| i.odd? }
assert_equal [1,2], a
a = [1,2,3,4]
a.uniq_by! { |i| i.even? }
assert_equal [1,2], a
a = (-5..5).to_a
a.uniq_by! { |i| i**2 }
assert_equal (-5..0).to_a, a
end
end
class ArrayExtRandomTests < Test::Unit::TestCase
def test_random_element_from_array
assert_nil [].rand
......
......@@ -12,7 +12,7 @@ def create_view_folder
def create_view_files
actions.each do |action|
@action, @path = action, File.join(file_path, action)
template "view.erb", File.join("app/views", "#{@path}.erb")
template "view.text.erb", File.join("app/views", "#{@path}.text.erb")
end
end
end
......
<%= class_name %>#<%= @action %>
Find me in app/views/<%= @path %>
<%%= @greeting %>, find me in app/views/<%= @path %>
class <%= class_name %> < ActionMailer::Base
delivers_from "from@example.com"
<% for action in actions -%>
def <%= action %>(sent_at = Time.now)
subject '<%= class_name %>#<%= action %>'
recipients ''
from ''
sent_on sent_at
body :greeting => 'Hi,'
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.actionmailer.<%= file_name %>.<%= action %>.subject
#
def <%= action %>
@greeting = "Hi"
mail(:to => "to@example.com")
end
<% end -%>
end
end
\ No newline at end of file
......@@ -6,8 +6,8 @@ module Generators
class ResourceGenerator < ModelGenerator #metagenerator
include ResourceHelpers
hook_for :resource_controller, :required => true do |base, controller|
base.invoke controller, [ base.controller_name, base.options[:actions] ]
hook_for :resource_controller, :required => true do |controller|
invoke controller, [ controller_name, options[:actions] ]
end
class_option :actions, :type => :array, :banner => "ACTION ACTION", :default => [],
......
......@@ -18,9 +18,9 @@ def create_controller_files
hook_for :template_engine, :test_framework, :as => :scaffold
# Invoke the helper using the controller (pluralized) name.
hook_for :helper, :as => :scaffold do |base, invoked|
base.invoke invoked, [ base.controller_name ]
# Invoke the helper using the controller name (pluralized)
hook_for :helper, :as => :scaffold do |invoked|
invoke invoked, [ controller_name ]
end
end
end
......
<%= class_name %>#<%= @action %>
Find me in app/views/<%= @path %>
Hi, find me in app/views/<%= @path %>
......@@ -3,11 +3,13 @@
class <%= class_name %>Test < ActionMailer::TestCase
<% for action in actions -%>
test "<%= action %>" do
@expected.subject = '<%= class_name %>#<%= action %>'
@expected.body = read_fixture('<%= action %>')
@expected.subject = <%= action.to_s.humanize.inspect %>
@expected.to = "to@example.com"
@expected.from = "from@example.com"
@expected.body = read_fixture("<%= action %>")
@expected.date = Time.now
assert_equal @expected.encoded, <%= class_name %>.create_<%= action %>(@expected.date).encoded
assert_equal @expected, <%= class_name %>.<%= action %>
end
<% end -%>
......
......@@ -6,17 +6,9 @@ module Generators
class NamedBase < Base
argument :name, :type => :string
no_tasks {
attr_reader :class_name, :singular_name, :plural_name, :table_name,
:class_path, :file_path, :class_nesting_depth
alias :file_name :singular_name
}
def initialize(args, *options) #:nodoc:
# Unfreeze name in case it's given as a frozen string
args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen?
super
assign_names!(self.name)
parse_attributes! if respond_to?(:attributes)
......@@ -24,28 +16,48 @@ def initialize(args, *options) #:nodoc:
protected
def assign_names!(given_name) #:nodoc:
base_name, @class_path, @file_path, class_nesting, @class_nesting_depth = extract_modules(given_name)
class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
attr_reader :class_path, :file_name
alias :singular_name :file_name
@table_name = if pluralize_table_names?
plural_name
else
singular_name
def file_path
@file_path ||= (class_path + [file_name]).join('/')
end
def class_name
@class_name ||= (class_path + [file_name]).map!{ |m| m.camelize }.join('::')
end
def plural_name
@plural_name ||= singular_name.pluralize
end
def i18n_scope
@i18n_scope ||= file_path.gsub('/', '.')
end
def table_name
@table_name ||= begin
base = pluralize_table_names? ? plural_name : singular_name
(class_path + [base]).join('_')
end
end
if class_nesting.empty?
@class_name = class_name_without_nesting
# Tries to retrieve the application name or simple return application.
def application_name
if defined?(Rails) && Rails.application
Rails.application.class.name.split('::').first.underscore
else
@table_name = class_nesting.underscore << "_" << @table_name
@class_name = "#{class_nesting}::#{class_name_without_nesting}"
"application"
end
end
@table_name.gsub!('/', '_')
def assign_names!(name) #:nodoc:
@class_path = name.include?('/') ? name.split('/') : name.split('::')
@class_path.map! { |m| m.underscore }
@file_name = @class_path.pop
end
# Convert attributes hash into an array with GeneratedAttribute objects.
#
# Convert attributes array into GeneratedAttribute objects.
def parse_attributes! #:nodoc:
self.attributes = (attributes || []).map do |key_value|
name, type = key_value.split(':')
......@@ -53,29 +65,6 @@ def parse_attributes! #:nodoc:
end
end
# Extract modules from filesystem-style or ruby-style path. Both
# good/fun/stuff and Good::Fun::Stuff produce the same results.
#
def extract_modules(name) #:nodoc:
modules = name.include?('/') ? name.split('/') : name.split('::')
name = modules.pop
path = modules.map { |m| m.underscore }
file_path = (path + [name.underscore]).join('/')
nesting = modules.map { |m| m.camelize }.join('::')
[name, path, file_path, nesting, modules.size]
end
# Receives name and return camelized, underscored and pluralized names.
#
def inflect_names(name) #:nodoc:
camel = name.camelize
under = camel.underscore
plural = under.pluralize
[camel, under, plural]
end
def pluralize_table_names?
!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names
end
......
......@@ -9,14 +9,7 @@ module ResourceHelpers
mattr_accessor :skip_warn
def self.included(base) #:nodoc:
base.class_eval do
class_option :force_plural, :type => :boolean, :desc => "Forces the use of a plural ModelName"
no_tasks {
attr_reader :controller_name, :controller_class_name, :controller_file_name,
:controller_class_path, :controller_file_path
}
end
base.class_option :force_plural, :type => :boolean, :desc => "Forces the use of a plural ModelName"
end
# Set controller variables on initialization.
......@@ -29,29 +22,40 @@ def initialize(*args) #:nodoc:
say "Plural version of the model detected, using singularized version. Override with --force-plural."
ResourceHelpers.skip_warn = true
end
name.replace name.singularize
assign_names!(self.name)
assign_names!(name)
end
@controller_name = name.pluralize
end
base_name, @controller_class_path, @controller_file_path, class_nesting, class_nesting_depth = extract_modules(@controller_name)
class_name_without_nesting, @controller_file_name, controller_plural_name = inflect_names(base_name)
protected
attr_reader :controller_name
@controller_class_name = if class_nesting.empty?
class_name_without_nesting
else
"#{class_nesting}::#{class_name_without_nesting}"
def controller_class_path
@class_path
end
end
protected
def controller_file_name
@controller_file_name ||= file_name.pluralize
end
def controller_file_path
@controller_file_path ||= (controller_class_path + [controller_file_name]).join('/')
end
def controller_class_name
@controller_class_name ||= (controller_class_path + [controller_file_name]).map!{ |m| m.camelize }.join('::')
end
def controller_i18n_scope
@controller_i18n_scope ||= controller_file_path.gsub('/', '.')
end
# Loads the ORM::Generators::ActiveModel class. This class is responsable
# to tell scaffold entities how to generate an specific method for the
# ORM. Check Rails::Generators::ActiveModel for more information.
#
def orm_class
@orm_class ||= begin
# Raise an error if the class_option :orm was not defined.
......@@ -68,7 +72,6 @@ def orm_class
end
# Initialize ORM::Generators::ActiveModel to access instance methods.
#
def orm_instance(name=file_name)
@orm_instance ||= @orm_class.new(name)
end
......
......@@ -7,7 +7,18 @@ class MailerGeneratorTest < Rails::Generators::TestCase
def test_mailer_skeleton_is_created
run_generator
assert_file "app/mailers/notifier.rb", /class Notifier < ActionMailer::Base/
assert_file "app/mailers/notifier.rb" do |mailer|
assert_match /class Notifier < ActionMailer::Base/, mailer
assert_match /delivers_from "from@example.com"/, mailer
end
end
def test_mailer_with_i18n_helper
run_generator
assert_file "app/mailers/notifier.rb" do |mailer|
assert_match /en\.actionmailer\.notifier\.foo\.subject/, mailer
assert_match /en\.actionmailer\.notifier\.bar\.subject/, mailer
end
end
def test_check_class_collision
......@@ -24,8 +35,15 @@ def test_invokes_default_test_framework
def test_invokes_default_template_engine
run_generator
assert_file "app/views/notifier/foo.erb", /app\/views\/notifier\/foo/
assert_file "app/views/notifier/bar.erb", /app\/views\/notifier\/bar/
assert_file "app/views/notifier/foo.text.erb" do |view|
assert_match /app\/views\/notifier\/foo/, view
assert_match /<%= @greeting %>/, view
end
assert_file "app/views/notifier/bar.text.erb" do |view|
assert_match /app\/views\/notifier\/bar/, view
assert_match /<%= @greeting %>/, view
end
end
def test_invokes_default_template_engine_even_with_no_action
......@@ -40,7 +58,18 @@ def test_logs_if_the_template_engine_cannot_be_found
def test_actions_are_turned_into_methods
run_generator
assert_file "app/mailers/notifier.rb", /def foo/
assert_file "app/mailers/notifier.rb", /def bar/
assert_file "app/mailers/notifier.rb" do |mailer|
assert_instance_method :foo, mailer do |foo|
assert_match /mail\(:to => "to@example.com"\)/, foo
assert_match /@greeting = "Hi"/, foo
end
assert_instance_method :bar, mailer do |bar|
assert_match /mail\(:to => "to@example.com"\)/, bar
assert_match /@greeting = "Hi"/, bar
end
end
end
end
......@@ -16,28 +16,68 @@ class NamedBaseTest < Rails::Generators::TestCase
tests Rails::Generators::ScaffoldControllerGenerator
def test_named_generator_attributes
g = generator ["admin/foo"]
assert_equal 'admin/foo', g.name
assert_equal %w(admin), g.class_path
assert_equal 1, g.class_nesting_depth
assert_equal 'Admin::Foo', g.class_name
assert_equal 'foo', g.singular_name
assert_equal 'foos', g.plural_name
assert_equal g.singular_name, g.file_name
assert_equal "admin_#{g.plural_name}", g.table_name
g = generator ['admin/foo']
assert_name g, 'admin/foo', :name
assert_name g, %w(admin), :class_path
assert_name g, 'Admin::Foo', :class_name
assert_name g, 'admin/foo', :file_path
assert_name g, 'foo', :file_name
assert_name g, 'foo', :singular_name
assert_name g, 'foos', :plural_name
assert_name g, 'admin.foo', :i18n_scope
assert_name g, 'admin_foos', :table_name
end
def test_named_generator_attributes_as_ruby
g = generator ['Admin::Foo']
assert_name g, 'Admin::Foo', :name
assert_name g, %w(admin), :class_path
assert_name g, 'Admin::Foo', :class_name
assert_name g, 'admin/foo', :file_path
assert_name g, 'foo', :file_name
assert_name g, 'foo', :singular_name
assert_name g, 'foos', :plural_name
assert_name g, 'admin.foo', :i18n_scope
assert_name g, 'admin_foos', :table_name
end
def test_named_generator_attributes_without_pluralized
ActiveRecord::Base.pluralize_table_names = false
g = generator ["admin/foo"]
assert_equal "admin_#{g.singular_name}", g.table_name
g = generator ['admin/foo']
assert_name g, 'admin_foo', :table_name
end
def test_scaffold_plural_names
g = generator ["ProductLine"]
assert_equal "ProductLines", g.controller_name
assert_equal "ProductLines", g.controller_class_name
assert_equal "product_lines", g.controller_file_name
g = generator ['admin/foo']
assert_name g, 'admin/foos', :controller_name
assert_name g, %w(admin), :controller_class_path
assert_name g, 'Admin::Foos', :controller_class_name
assert_name g, 'admin/foos', :controller_file_path
assert_name g, 'foos', :controller_file_name
assert_name g, 'admin.foos', :controller_i18n_scope
end
def test_scaffold_plural_names_as_ruby
g = generator ['Admin::Foo']
assert_name g, 'Admin::Foos', :controller_name
assert_name g, %w(admin), :controller_class_path
assert_name g, 'Admin::Foos', :controller_class_name
assert_name g, 'admin/foos', :controller_file_path
assert_name g, 'foos', :controller_file_name
assert_name g, 'admin.foos', :controller_i18n_scope
end
def test_application_name
g = generator ['Admin::Foo']
Rails.stubs(:application).returns(Object.new)
assert_name g, "object", :application_name
Rails.stubs(:application).returns(nil)
assert_name g, "application", :application_name
end
protected
def assert_name(generator, value, method)
assert_equal value, generator.send(method)
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册