diff options
187 files changed, 3380 insertions, 2633 deletions
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG index 785bf98c55..0018a2ed5d 100644 --- a/actionmailer/CHANGELOG +++ b/actionmailer/CHANGELOG @@ -1,5 +1,7 @@ *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'} diff --git a/actionmailer/README b/actionmailer/README index 0e16ea6ec6..e0e2ee436a 100644 --- a/actionmailer/README +++ b/actionmailer/README @@ -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 diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index 6c19371514..2619d9359e 100644 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -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 diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 96549bf29c..d73f86cd65 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |s| 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 diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index 55ddbb24f4..8339826197 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -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 diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 356861b591..2288a30691 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -1,6 +1,11 @@ require 'active_support/core_ext/class' +require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/array/uniq_by' +require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/string/inflections' require 'mail' require 'action_mailer/tmail_compat' +require 'action_mailer/collector' module ActionMailer #:nodoc: # Action Mailer allows you to send email from your application using a mailer model and views. @@ -11,46 +16,76 @@ module ActionMailer #:nodoc: # # $ script/generate mailer Notifier # - # The generated model inherits from ActionMailer::Base. Emails are defined by creating methods within the model which are then - # used to set variables to be used in the mail template, to change options on the mail, or - # to add attachments. + # The generated model inherits from ActionMailer::Base. Emails are defined by creating methods + # within the model which are then used to set variables to be used in the mail template, to + # change options on the mail, or to add attachments. # # Examples: # # class Notifier < ActionMailer::Base - # def signup_notification(recipient) - # recipients recipient.email_address_with_name - # bcc ["bcc@example.com", "Order Watcher <watcher@example.com>"] - # from "system@example.com" - # subject "New account information" - # body :account => recipient + # defaults :from => 'no-reply@example.com', + # :return_path => 'system@example.com' + # + # def welcome(recipient) + # @account = recipient + # mail(:to => recipient.email_address_with_name, + # :bcc => ["bcc@example.com", "Order Watcher <watcher@example.com>"]) + # end # end - # end + # + # Within the mailer method, you have access to the following methods: + # + # * <tt>attachments[]=</tt> - Allows you to add attachments to your email in an intuitive + # manner; <tt>attachments['filename.png'] = File.read('path/to/filename.png')</tt> + # + # * <tt>headers[]=</tt> - Allows you to specify non standard headers in your email such + # as <tt>headers['X-No-Spam'] = 'True'</tt> + # + # * <tt>headers(hash)</tt> - Allows you to specify multiple headers in your email such + # as <tt>headers({'X-No-Spam' => 'True', 'In-Reply-To' => '1234@message.id'})</tt> + # + # * <tt>mail</tt> - Allows you to specify your email to send. + # + # The hash passed to the mail method allows you to specify any header that a Mail::Message + # will accept (any valid Email header including optional fields). Obviously if you specify + # the same header in the headers method and then again in the mail method, the last one + # will over write the first, unless you are specifying a header field that can appear more + # than once per RFC, in which case, both will be inserted (X-value headers for example can + # appear multiple times.) + # + # The mail method, if not passed a block, will inspect your views and send all the views with + # the same name as the method, so the above action would send the +welcome.plain.erb+ view file + # as well as the +welcome.html.erb+ view file in a +multipart/alternative+ email. + # + # If you want to explicitly render only certain templates, pass a block: + # + # mail(:to => user.emai) do |format| + # format.text + # format.html + # end # - # Mailer methods have the following configuration methods available. + # The block syntax is useful if also need to specify information specific to a part: # - # * <tt>recipients</tt> - Takes one or more email addresses. These addresses are where your email will be delivered to. Sets the <tt>To:</tt> header. - # * <tt>subject</tt> - The subject of your email. Sets the <tt>Subject:</tt> header. - # * <tt>from</tt> - Who the email you are sending is from. Sets the <tt>From:</tt> header. - # * <tt>cc</tt> - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the <tt>Cc:</tt> header. - # * <tt>bcc</tt> - Takes one or more email addresses. These addresses will receive a blind carbon copy of your email. Sets the <tt>Bcc:</tt> header. - # * <tt>reply_to</tt> - Takes one or more email addresses. These addresses will be listed as the default recipients when replying to your email. Sets the <tt>Reply-To:</tt> header. - # * <tt>sent_on</tt> - The date on which the message was sent. If not set, the header will be set by the delivery agent. - # * <tt>content_type</tt> - Specify the content type of the message. Defaults to <tt>text/plain</tt>. - # * <tt>headers</tt> - Specify additional headers to be set for the message, e.g. <tt>headers 'X-Mail-Count' => 107370</tt>. + # mail(:to => user.emai) do |format| + # format.text(:content_transfer_encoding => "base64") + # format.html + # end # - # When a <tt>headers 'return-path'</tt> is specified, that value will be used as the 'envelope from' - # address. Setting this is useful when you want delivery notifications sent to a different address than - # the one in <tt>from</tt>. + # Or even to renderize a special view: # + # mail(:to => user.emai) do |format| + # format.text + # format.html { render "some_other_template" } + # end # # = Mailer views # - # Like Action Controller, each mailer class has a corresponding view directory - # in which each method of the class looks for a template with its name. - # To define a template to be used with a mailing, create an <tt>.erb</tt> file with the same name as the method - # in your mailer model. For example, in the mailer defined above, the template at - # <tt>app/views/notifier/signup_notification.erb</tt> would be used to generate the email. + # Like Action Controller, each mailer class has a corresponding view directory in which each + # method of the class looks for a template with its name. + # + # To define a template to be used with a mailing, create an <tt>.erb</tt> file with the same + # name as the method in your mailer model. For example, in the mailer defined above, the template at + # <tt>app/views/notifier/signup_notification.text.erb</tt> would be used to generate the email. # # Variables defined in the model are accessible as instance variables in the view. # @@ -64,9 +99,9 @@ module ActionMailer #:nodoc: # You got a new note! # <%= truncate(@note.body, 25) %> # - # If you need to access the subject, from or the recipients in the view, you can do that through mailer object: + # If you need to access the subject, from or the recipients in the view, you can do that through message object: # - # You got a new note from <%= mailer.from %>! + # You got a new note from <%= message.from %>! # <%= truncate(@note.body, 25) %> # # @@ -106,54 +141,13 @@ module ActionMailer #:nodoc: # Once a mailer action and template are defined, you can deliver your message or create it and save it # for delivery later: # - # Notifier.deliver_signup_notification(david) # sends the email - # mail = Notifier.create_signup_notification(david) # => a tmail object - # Notifier.deliver(mail) - # - # You never instantiate your mailer class. Rather, your delivery instance - # methods are automatically wrapped in class methods that start with the word - # <tt>deliver_</tt> followed by the name of the mailer method that you would - # like to deliver. The <tt>signup_notification</tt> method defined above is - # delivered by invoking <tt>Notifier.deliver_signup_notification</tt>. + # Notifier.welcome(david).deliver # sends the email + # mail = Notifier.welcome(david) # => a Mail::Message object + # mail.deliver # sends the email # + # You never instantiate your mailer class. Rather, you just call the method on the class itself. # - # = HTML email - # - # To send mail as HTML, make sure your view (the <tt>.erb</tt> file) generates HTML and - # set the content type to html. - # - # class MyMailer < ActionMailer::Base - # def signup_notification(recipient) - # recipients recipient.email_address_with_name - # subject "New account information" - # from "system@example.com" - # body :account => recipient - # content_type "text/html" - # end - # end - # - # - # = Multipart email - # - # You can explicitly specify multipart messages: - # - # class ApplicationMailer < ActionMailer::Base - # def signup_notification(recipient) - # recipients recipient.email_address_with_name - # subject "New account information" - # from "system@example.com" - # content_type "multipart/alternative" - # body :account => recipient - # - # part :content_type => "text/html", - # :data => render_message("signup-as-html") - # - # part "text/plain" do |p| - # p.body = render_message("signup-as-plain") - # p.content_transfer_encoding = "base64" - # end - # end - # end + # = Multipart Emails # # Multipart messages can also be used implicitly because Action Mailer will automatically # detect and use multipart templates, where each template is named after the name of the action, followed @@ -163,13 +157,12 @@ module ActionMailer #:nodoc: # * signup_notification.text.plain.erb # * signup_notification.text.html.erb # * signup_notification.text.xml.builder - # * signup_notification.text.x-yaml.erb + # * signup_notification.text.yaml.erb # - # Each would be rendered and added as a separate part to the message, - # with the corresponding content type. The content type for the entire - # message is automatically set to <tt>multipart/alternative</tt>, which indicates - # that the email contains multiple different representations of the same email - # body. The same body hash is passed to each template. + # Each would be rendered and added as a separate part to the message, with the corresponding content + # type. The content type for the entire message is automatically set to <tt>multipart/alternative</tt>, + # which indicates that the email contains multiple different representations of the same email + # body. The same instance variables defined in the action are passed to all email templates. # # Implicit template rendering is not performed if any attachments or parts have been added to the email. # This means that you'll have to manually add each part to the email and set the content type of the email @@ -177,32 +170,35 @@ module ActionMailer #:nodoc: # # = Attachments # - # Attachments can be added by using the +attachment+ method. - # - # Example: + # You can see above how to make a multipart HTML / Text email, to send attachments is just + # as easy: # # class ApplicationMailer < ActionMailer::Base - # # attachments - # def signup_notification(recipient) - # recipients recipient.email_address_with_name - # subject "New account information" - # from "system@example.com" - # - # attachment :content_type => "image/jpeg", - # :body => File.read("an-image.jpg") - # - # attachment "application/pdf" do |a| - # a.body = generate_your_pdf_here() - # end + # def welcome(recipient) + # attachments['free_book.pdf'] = { :data => File.read('path/to/file.pdf') } + # mail(:to => recipient, :subject => "New account information") # end # end + # + # Which will (if it had both a <tt>.text.erb</tt> and <tt>.html.erb</tt> tempalte in the view + # directory), send a complete <tt>multipart/mixed</tt> email with two parts, the first part being + # a <tt>multipart/alternative</tt> with the text and HTML email parts inside, 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+. # # # = Configuration options # # These options are specified on the class level, like <tt>ActionMailer::Base.template_root = "/my/templates"</tt> # - # * <tt>template_root</tt> - Determines the base from which template references will be made. + # * <tt>defaults</tt> - This is a class wide hash of <tt>:key => value</tt> pairs containing + # default values for the specified header fields of the <tt>Mail::Message</tt>. You can + # specify a default for any valid header for <tt>Mail::Message</tt> and it will be used if + # you do not override it. The defaults set by Action Mailer are: + # * <tt>:mime_version => "1.0"</tt> + # * <tt>:charset => "utf-8",</tt> + # * <tt>:content_type => "text/plain",</tt> + # * <tt>:parts_order => [ "text/plain", "text/enriched", "text/html" ]</tt> # # * <tt>logger</tt> - the logger is used for generating information on the mailing run if available. # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers. @@ -236,23 +232,22 @@ module ActionMailer #:nodoc: # * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with <tt>delivery_method :test</tt>. Most useful # for unit and functional testing. # - # * <tt>default_charset</tt> - The default charset used for the body and to encode the subject. Defaults to UTF-8. You can also - # pick a different charset from inside a method with +charset+. + # * <tt>default_charset</tt> - This is now deprecated, use the +defaults+ method above to + # set the default +:charset+. # - # * <tt>default_content_type</tt> - The default content type used for the main part of the message. Defaults to "text/plain". You - # can also pick a different content type from inside a method with +content_type+. + # * <tt>default_content_type</tt> - This is now deprecated, use the +defaults+ method above + # to set the default +:content_type+. # - # * <tt>default_mime_version</tt> - The default mime version used for the message. Defaults to <tt>1.0</tt>. You - # can also pick a different value from inside a method with +mime_version+. + # * <tt>default_mime_version</tt> - This is now deprecated, use the +defaults+ method above + # to set the default +:mime_version+. # - # * <tt>default_implicit_parts_order</tt> - When a message is built implicitly (i.e. multiple parts are assembled from templates - # which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to - # <tt>["text/html", "text/enriched", "text/plain"]</tt>. Items that appear first in the array have higher priority in the mail client - # and appear last in the mime encoded message. You can also pick a different order from inside a method with - # +implicit_parts_order+. + # * <tt>default_implicit_parts_order</tt> - This is now deprecated, use the +defaults+ method above + # to set the default +:parts_order+. Parts Order is used when a message is built implicitly + # (i.e. multiple parts are assembled from templates which specify the content type in their + # filenames) this variable controls how the parts are ordered. class Base < AbstractController::Base - include Quoting - extend AdvAttrAccessor + include DeliveryMethods, Quoting + abstract! include AbstractController::Logger include AbstractController::Rendering @@ -260,131 +255,34 @@ module ActionMailer #:nodoc: include AbstractController::Layouts include AbstractController::Helpers include AbstractController::UrlFor + include AbstractController::Translation helper ActionMailer::MailHelper - include ActionMailer::DeprecatedBody - - private_class_method :new #:nodoc: - - @@raise_delivery_errors = true - cattr_accessor :raise_delivery_errors - - @@perform_deliveries = true - cattr_accessor :perform_deliveries - - @@deliveries = [] - cattr_accessor :deliveries - - @@default_charset = "utf-8" - cattr_accessor :default_charset - - @@default_content_type = "text/plain" - cattr_accessor :default_content_type - - @@default_mime_version = "1.0" - cattr_accessor :default_mime_version - - # This specifies the order that the parts of a multipart email will be. Usually you put - # text/plain at the top so someone without a MIME capable email reader can read the plain - # text of your email first. - # - # Any content type that is not listed here will be inserted in the order you add them to - # the email after the content types you list here. - @@default_implicit_parts_order = [ "text/plain", "text/enriched", "text/html" ] - cattr_accessor :default_implicit_parts_order - - @@protected_instance_variables = %w(@parts @mail) - 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 + include ActionMailer::OldApi + include ActionMailer::DeprecatedApi - # 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 - - # Expose the internal mail - attr_reader :mail + private_class_method :new #:nodoc: - # Alias controller_path to mailer_name so render :partial in views work. - alias :controller_path :mailer_name + extlib_inheritable_accessor :default_params + self.default_params = { + :mime_version => "1.0", + :charset => "utf-8", + :content_type => "text/plain", + :parts_order => [ "text/plain", "text/enriched", "text/html" ] + } class << self - attr_writer :mailer_name - - delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::File, :prefix => :file - delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::Sendmail, :prefix => :sendmail - delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::Smtp, :prefix => :smtp def mailer_name @mailer_name ||= name.underscore end + attr_writer :mailer_name alias :controller_path :mailer_name - def delivery_method=(method_name) - @delivery_method = ActionMailer::DeliveryMethod.lookup_method(method_name) - end - - def respond_to?(method_symbol, include_private = false) #:nodoc: - matches_dynamic_method?(method_symbol) || super - end - - def method_missing(method_symbol, *parameters) #:nodoc: - if match = matches_dynamic_method?(method_symbol) - case match[1] - when 'create' then new(match[2], *parameters).mail - when 'deliver' then new(match[2], *parameters).deliver! - when 'new' then nil - else super - end - else - super - end + def defaults(value=nil) + self.default_params.merge!(value) if value + self.default_params end # Receives a raw email, parses it into an email object, decodes it, @@ -406,26 +304,24 @@ module ActionMailer #:nodoc: end end - # 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) - new.deliver!(mail) + # Delivers a mail object. This is actually called by the <tt>Mail::Message</tt> object + # itself through a call back when you call <tt>:deliver</tt> on the Mail::Message, + # calling +deliver_mail+ directly and passing an Mail::Message will do nothing. + def deliver_mail(mail) #:nodoc: + ActiveSupport::Notifications.instrument("action_mailer.deliver") do |payload| + self.set_payload_for_mail(payload, mail) + yield # Let Mail do the delivery actions + end end - def template_root - self.view_paths && self.view_paths.first + def respond_to?(method, *args) #:nodoc: + super || action_methods.include?(method.to_s) end - # Should template root overwrite the whole view_paths? - def template_root=(root) - self.view_paths = ActionView::Base.process_view_paths(root) - end + protected def set_payload_for_mail(payload, mail) #:nodoc: + payload[:mailer] = self.name payload[:message_id] = mail.message_id payload[:subject] = mail.subject payload[:to] = mail.to @@ -436,61 +332,16 @@ module ActionMailer #:nodoc: payload[:mail] = mail.encoded end - private - - def matches_dynamic_method?(method_name) #:nodoc: - method_name = method_name.to_s - /^(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name) + def method_missing(method, *args) #:nodoc: + if action_methods.include?(method.to_s) + new(method, *args).message + else + super end - end - - # Configure delivery method. Check ActionMailer::DeliveryMethod for more - # instructions. - superclass_delegating_reader :delivery_method - self.delivery_method = :smtp - - # 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) - ActiveSupport::Deprecation.warn('Passing custom headers with :headers => {} is deprecated. ' << - 'Please just pass in custom headers directly.', caller[0,10]) - 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) - super # Run deprecation hooks - - params = { :content_type => params } if String === params - params = { :content_disposition => "attachment", - :content_transfer_encoding => "base64" }.merge(params) - - part(params, &block) end - # Allow you to set assigns for your template: - # - # body :greetings => "Hi" - # - # Will make @greetings available in the template to be rendered. - def body(object=nil) - returning(super) do # Run deprecation hooks - if object.is_a?(Hash) - @assigns_set = true - object.each { |k, v| instance_variable_set(:"@#{k}", v) } - end - end - end + attr_internal :message # Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer # will be initialized according to the named method. If not, the mailer will @@ -498,167 +349,263 @@ module ActionMailer #:nodoc: # method, for instance). def initialize(method_name=nil, *args) super() + @_message = Mail.new process(method_name, *args) if method_name end - # Process the mailer via the given +method_name+. The body will be - # rendered and a new Mail object created. - def process(method_name, *args) - initialize_defaults(method_name) - super - - # Create e-mail parts - create_parts - - # Set the subject if not set yet - @subject ||= I18n.t(:subject, :scope => [:actionmailer, mailer_name, method_name], - :default => method_name.humanize) - - # Build the mail object itself - create_mail - 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 = @mail) - raise "no mail object available for delivery!" unless mail - - ActiveSupport::Notifications.instrument("action_mailer.deliver", - :template => template, :mailer => self.class.name) do |payload| - - self.class.set_payload_for_mail(payload, mail) - - begin - self.delivery_method.perform_delivery(mail) if perform_deliveries - rescue Exception => e # Net::SMTP errors or sendmail pipe errors - raise e if raise_delivery_errors - end + # Allows you to pass random and unusual headers to the new +Mail::Message+ object + # which will add them to itself. + # + # headers['X-Special-Domain-Specific-Header'] = "SecretValue" + # + # You can also pass a hash into headers of header field names and values, which + # will then be set on the Mail::Message object: + # + # headers 'X-Special-Domain-Specific-Header' => "SecretValue", + # 'In-Reply-To' => incoming.message_id + # + # The resulting Mail::Message will have the following in it's header: + # + # X-Special-Domain-Specific-Header: SecretValue + def headers(args=nil) + if args + @_message.headers(args) + else + @_message end - - mail end - private + # Allows you to add attachments to an email, like so: + # + # mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg') + # + # If you do this, then Mail will take the file name and work out the mime type + # set the Content-Type, Content-Disposition, Content-Transfer-Encoding and + # base64 encode the contents of the attachment all for you. + # + # You can also specify overrides if you want by passing a hash instead of a string: + # + # mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip', + # :content => File.read('/path/to/filename.jpg')} + # + # If you want to use a different encoding than Base64, you can pass an encoding in, + # but then it is up to you to pass in the content pre-encoded, and don't expect + # Mail to know how to decode this data: + # + # file_content = SpecialEncode(File.read('/path/to/filename.jpg')) + # mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip', + # :encoding => 'SpecialEncoding', + # :content => file_content } + # + # You can also search for specific attachments: + # + # # By Filename + # mail.attachments['filename.jpg'] #=> Mail::Part object or nil + # + # # or by index + # mail.attachments[0] #=> Mail::Part (first attachment) + # + def attachments + @_message.attachments + 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(object) - case object - when String - render_to_body(:template => object) - else - render_to_body(object) - end + # The main method that creates the message and renders the email templates. There are + # two ways to call this method, with a block, or without a block. + # + # Both methods accept a headers hash. This hash allows you to specify the most used headers + # in an email message, these are: + # + # * <tt>:subject</tt> - The subject of the message, if this is omitted, ActionMailer will + # ask the Rails I18n class for a translated <tt>:subject</tt> in the scope of + # <tt>[:actionmailer, mailer_scope, action_name]</tt> or if this is missing, will translate the + # humanized version of the <tt>action_name</tt> + # * <tt>:to</tt> - Who the message is destined for, can be a string of addresses, or an array + # of addresses. + # * <tt>:from</tt> - Who the message is from + # * <tt>:cc</tt> - Who you would like to Carbon-Copy on this email, can be a string of addresses, + # or an array of addresses. + # * <tt>:bcc</tt> - Who you would like to Blind-Carbon-Copy on this email, can be a string of + # addresses, or an array of addresses. + # * <tt>:reply_to</tt> - Who to set the Reply-To header of the email to. + # * <tt>:date</tt> - The date to say the email was sent on. + # + # You can set default values for any of the above headers (except :date) by using the <tt>defaults</tt> + # class method: + # + # class Notifier < ActionMailer::Base + # self.defaults :from => 'no-reply@test.lindsaar.net', + # :bcc => 'email_logger@test.lindsaar.net', + # :reply_to => 'bounces@test.lindsaar.net' + # end + # + # If you need other headers not listed above, use the <tt>headers['name'] = value</tt> method. + # + # When a <tt>:return_path</tt> is specified as header, that value will be used as the 'envelope from' + # address for the Mail message. Setting this is useful when you want delivery notifications + # sent to a different address than the one in <tt>:from</tt>. Mail will actually use the + # <tt>:return_path</tt> in preference to the <tt>:sender</tt> in preference to the <tt>:from</tt> + # 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. + # + # If you do pass a block, you can render specific templates of your choice: + # + # mail(:to => 'mikel@test.lindsaar.net') do |format| + # format.text + # format.html + # end + # + # You can even render text directly without using a template: + # + # mail(:to => 'mikel@test.lindsaar.net') do |format| + # format.text { render :text => "Hello Mikel!" } + # format.html { render :text => "<h1>Hello Mikel!</h1>" } + # end + # + # Which will render a <tt>multipart/alternative</tt> email with <tt>text/plain</tt> and + # <tt>text/html</tt> parts. + # + # The block syntax also allows you to customize the part headers if desired: + # + # mail(:to => 'mikel@test.lindsaar.net') do |format| + # format.text(:content_transfer_encoding => "base64") + # format.html + # end + # + def mail(headers={}, &block) + # Guard flag to prevent both the old and the new API from firing + # Should be removed when old API is removed + @mail_was_called = true + m = @_message + + # At the beginning, do not consider class default for parts order neither content_type + content_type = headers[:content_type] + parts_order = headers[:parts_order] + + # Merge defaults from class + headers = headers.reverse_merge(self.class.defaults) + charset = headers[:charset] + + # Quote fields + headers[:subject] ||= default_i18n_subject + quote_fields!(headers, charset) + + # Render the templates and blocks + responses, explicit_order = collect_responses_and_parts_order(headers, &block) + create_parts_from_responses(m, responses, charset) + + # Finally setup content type and parts order + m.content_type = set_content_type(m, content_type, headers[:content_type]) + m.charset = charset + + if m.multipart? + parts_order ||= explicit_order || headers[:parts_order] + m.body.set_sort_order(parts_order) + m.body.sort_parts! 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) #:nodoc: - @charset ||= @@default_charset.dup - @content_type ||= @@default_content_type.dup - @implicit_parts_order ||= @@default_implicit_parts_order.dup - @mime_version ||= @@default_mime_version.dup if @@default_mime_version + # Set configure delivery behavior + wrap_delivery_behavior!(headers[:delivery_method]) - @mailer_name ||= self.class.mailer_name.dup - @template ||= method_name + # 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) + headers.each { |k, v| m[k] = v } - @parts ||= [] - @headers ||= {} - @sent_on ||= Time.now + m + end - super # Run deprecation hooks + protected + + def set_content_type(m, user_content_type, class_default) + params = m.content_type_parameters || {} + case + when user_content_type.present? + user_content_type + when m.has_attachments? + ["multipart", "mixed", params] + when m.multipart? + ["multipart", "alternative", params] + else + class_default end + end - def create_parts #:nodoc: - super # Run deprecation hooks - - if String === response_body - @parts.unshift create_inline_part(response_body) - else - self.class.template_root.find_all(@template, {}, @mailer_name).each do |template| - @parts << create_inline_part(render_to_body(:_template => template), template.mime_type) - end + def default_i18n_subject #:nodoc: + mailer_scope = self.class.mailer_name.gsub('/', '.') + I18n.t(:subject, :scope => [:actionmailer, mailer_scope, action_name], :default => action_name.humanize) + end - if @parts.size > 1 - @content_type = "multipart/alternative" if @content_type !~ /^multipart/ - end + # 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] + 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? + def collect_responses_and_parts_order(headers) #:nodoc: + responses, parts_order = [], nil + + if block_given? + collector = ActionMailer::Collector.new(self) { render(action_name) } + yield(collector) + parts_order = collector.responses.map { |r| r[:content_type] } + responses = collector.responses + elsif headers[:body] + responses << { + :body => headers[:body], + :content_type => self.class.defaults[:content_type] || "text/plain" + } + else + each_template do |template| + responses << { + :body => render_to_body(:_template => template), + :content_type => template.mime_type.to_s + } end end - def create_inline_part(body, mime_type=nil) #:nodoc: - 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 create_mail #:nodoc: - m = Mail.new - - m.subject, = quote_any_if_necessary(charset, subject) - m.to, m.from = quote_any_address_if_necessary(charset, recipients, from) - m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil? - m.cc = quote_address_if_necessary(cc, charset) unless cc.nil? - m.reply_to = quote_address_if_necessary(reply_to, charset) unless reply_to.nil? - 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 + [responses, parts_order] + end - m.body.set_sort_order(@implicit_parts_order) - m.body.sort_parts! + 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] } - if real_content_type =~ /multipart/ - ctype_attrs.delete "charset" - m.content_type([main_type, sub_type, ctype_attrs]) - end + unless templates.empty? + templates.each(&block) + return end - - m.content_transfer_encoding = '8bit' unless m.body.only_us_ascii? - - @mail = m - end - - def split_content_type(ct) #:nodoc: - ct.to_s.split("/") end + end - def parse_content_type(defaults=nil) #:nodoc: - 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 + def create_parts_from_responses(m, responses, charset) #:nodoc: + if responses.size == 1 && !m.has_attachments? + responses[0].each { |k,v| m[k] = v } + elsif responses.size > 1 && m.has_attachments? + container = Mail::Part.new + container.content_type = "multipart/alternative" + responses.each { |r| insert_part(container, r, charset) } + m.add_part(container) + else + responses.each { |r| insert_part(m, r, charset) } end + end + + def insert_part(container, response, charset) #:nodoc: + response[:charset] ||= charset + part = Mail::Part.new(response) + container.add_part(part) + end end end diff --git a/actionmailer/lib/action_mailer/collector.rb b/actionmailer/lib/action_mailer/collector.rb new file mode 100644 index 0000000000..5431efccfe --- /dev/null +++ b/actionmailer/lib/action_mailer/collector.rb @@ -0,0 +1,36 @@ +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 diff --git a/actionmailer/lib/action_mailer/delivery_method.rb b/actionmailer/lib/action_mailer/delivery_method.rb deleted file mode 100644 index 4f7d3afc3c..0000000000 --- a/actionmailer/lib/action_mailer/delivery_method.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'active_support/core_ext/class' - -module ActionMailer - module DeliveryMethod - autoload :File, 'action_mailer/delivery_method/file' - autoload :Sendmail, 'action_mailer/delivery_method/sendmail' - autoload :Smtp, 'action_mailer/delivery_method/smtp' - autoload :Test, 'action_mailer/delivery_method/test' - - # Creates a new DeliveryMethod object according to the given options. - # - # If no arguments are passed to this method, then a new - # ActionMailer::DeliveryMethod::Stmp object will be returned. - # - # If you pass a Symbol as the first argument, then a corresponding - # delivery method class under the ActionMailer::DeliveryMethod namespace - # will be created. - # For example: - # - # ActionMailer::DeliveryMethod.lookup_method(:sendmail) - # # => returns a new ActionMailer::DeliveryMethod::Sendmail object - # - # If the first argument is not a Symbol, then it will simply be returned: - # - # ActionMailer::DeliveryMethod.lookup_method(MyOwnDeliveryMethod.new) - # # => returns MyOwnDeliveryMethod.new - def self.lookup_method(delivery_method) - case delivery_method - when Symbol - method_name = delivery_method.to_s.camelize - method_class = ActionMailer::DeliveryMethod.const_get(method_name) - method_class.new - when nil # default - Smtp.new - else - delivery_method - end - end - - # An abstract delivery method class. There are multiple delivery method classes. - # See the classes under the ActionMailer::DeliveryMethod, e.g. - # ActionMailer::DeliveryMethod::Smtp. - # Smtp is the default delivery method for production - # while Test is used in testing. - # - # each delivery method exposes just one method - # - # delivery_method = ActionMailer::DeliveryMethod::Smtp.new - # delivery_method.perform_delivery(mail) # send the mail via smtp - # - class Method - superclass_delegating_accessor :settings - self.settings = {} - end - end -end diff --git a/actionmailer/lib/action_mailer/delivery_method/file.rb b/actionmailer/lib/action_mailer/delivery_method/file.rb deleted file mode 100644 index 571e32df49..0000000000 --- a/actionmailer/lib/action_mailer/delivery_method/file.rb +++ /dev/null @@ -1,21 +0,0 @@ -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 diff --git a/actionmailer/lib/action_mailer/delivery_method/sendmail.rb b/actionmailer/lib/action_mailer/delivery_method/sendmail.rb deleted file mode 100644 index db55af79f1..0000000000 --- a/actionmailer/lib/action_mailer/delivery_method/sendmail.rb +++ /dev/null @@ -1,22 +0,0 @@ -module ActionMailer - module DeliveryMethod - - # A delivery method implementation which sends via sendmail. - class Sendmail < Method - self.settings = { - :location => '/usr/sbin/sendmail', - :arguments => '-i -t' - } - - def perform_delivery(mail) - sendmail_args = settings[:arguments] - sendmail_args += " -f \"#{mail['return-path']}\"" if mail['return-path'] - IO.popen("#{settings[:location]} #{sendmail_args}","w+") do |sm| - sm.print(mail.encoded.gsub(/\r/, '')) - sm.flush - end - end - end - - end -end diff --git a/actionmailer/lib/action_mailer/delivery_method/smtp.rb b/actionmailer/lib/action_mailer/delivery_method/smtp.rb deleted file mode 100644 index af30c498b5..0000000000 --- a/actionmailer/lib/action_mailer/delivery_method/smtp.rb +++ /dev/null @@ -1,30 +0,0 @@ -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 diff --git a/actionmailer/lib/action_mailer/delivery_method/test.rb b/actionmailer/lib/action_mailer/delivery_method/test.rb deleted file mode 100644 index 6e3239d52a..0000000000 --- a/actionmailer/lib/action_mailer/delivery_method/test.rb +++ /dev/null @@ -1,12 +0,0 @@ -module ActionMailer - module DeliveryMethod - - # A delivery method implementation designed for testing, which just appends each record to the :deliveries array - class Test < Method - def perform_delivery(mail) - ActionMailer::Base.deliveries << mail - end - end - - end -end diff --git a/actionmailer/lib/action_mailer/delivery_methods.rb b/actionmailer/lib/action_mailer/delivery_methods.rb new file mode 100644 index 0000000000..f6321a240c --- /dev/null +++ b/actionmailer/lib/action_mailer/delivery_methods.rb @@ -0,0 +1,90 @@ +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 + + case method + when NilClass + raise "Delivery method cannot be nil" + when 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 diff --git a/actionmailer/lib/action_mailer/deprecated_api.rb b/actionmailer/lib/action_mailer/deprecated_api.rb new file mode 100644 index 0000000000..36eec1087e --- /dev/null +++ b/actionmailer/lib/action_mailer/deprecated_api.rb @@ -0,0 +1,139 @@ +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 + + included do + [:charset, :content_type, :mime_version, :implicit_parts_order].each do |method| + class_eval <<-FILE, __FILE__, __LINE__ + 1 + def self.default_#{method} + @@default_#{method} + end + + def self.default_#{method}=(value) + ActiveSupport::Deprecation.warn "ActionMailer::Base.default_#{method}=value is deprecated, " << + "use defaults :#{method} => value instead" + @@default_#{method} = value + end + + @@default_#{method} = nil + FILE + end + end + + 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].is_a?(Hash) + ActiveSupport::Deprecation.warn(':body in render deprecated. Please use instance ' << + 'variables as assigns instead', caller[0,1]) + + options[:body].each { |k,v| instance_variable_set(:"@#{k}", v) } + 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 initialize_defaults(*) + @charset ||= self.class.default_charset.try(:dup) + @content_type ||= self.class.default_content_type.try(:dup) + @implicit_parts_order ||= self.class.default_implicit_parts_order.try(:dup) + @mime_version ||= self.class.default_mime_version.try(:dup) + super + end + + 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 diff --git a/actionmailer/lib/action_mailer/deprecated_body.rb b/actionmailer/lib/action_mailer/deprecated_body.rb deleted file mode 100644 index 5379b33a54..0000000000 --- a/actionmailer/lib/action_mailer/deprecated_body.rb +++ /dev/null @@ -1,46 +0,0 @@ -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 diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb index df71330fd5..ab5c3469b2 100644 --- a/actionmailer/lib/action_mailer/mail_helper.rb +++ b/actionmailer/lib/action_mailer/mail_helper.rb @@ -17,8 +17,13 @@ module ActionMailer end # Access the mailer instance. - def mailer #:nodoc: + def mailer @_controller end + + # Access the message instance. + def message + @_message + end end end diff --git a/actionmailer/lib/action_mailer/old_api.rb b/actionmailer/lib/action_mailer/old_api.rb new file mode 100644 index 0000000000..4694958222 --- /dev/null +++ b/actionmailer/lib/action_mailer/old_api.rb @@ -0,0 +1,248 @@ +require 'active_support/core_ext/object/try' + +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.defaults[:charset].try(:dup) + @content_type ||= self.class.defaults[:content_type].try(:dup) + @implicit_parts_order ||= self.class.defaults[:parts_order].try(:dup) + @mime_version ||= self.class.defaults[:mime_version].try(:dup) + + @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 + @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) + 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 diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb index 0ca4f5494e..7c4033a125 100644 --- a/actionmailer/lib/action_mailer/test_case.rb +++ b/actionmailer/lib/action_mailer/test_case.rb @@ -37,7 +37,7 @@ module ActionMailer 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 diff --git a/actionmailer/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb index f234c0248c..3a1612442f 100644 --- a/actionmailer/lib/action_mailer/test_helper.rb +++ b/actionmailer/lib/action_mailer/test_helper.rb @@ -58,7 +58,6 @@ module ActionMailer end end -# TODO: Deprecate this module Test module Unit class TestCase diff --git a/actionmailer/lib/action_mailer/tmail_compat.rb b/actionmailer/lib/action_mailer/tmail_compat.rb index 2fd25ff145..c6efdc53b6 100644 --- a/actionmailer/lib/action_mailer/tmail_compat.rb +++ b/actionmailer/lib/action_mailer/tmail_compat.rb @@ -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 diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index 50b8a53006..ce09bb5d61 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -8,7 +8,6 @@ $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) require 'rubygems' require 'test/unit' - require 'action_mailer' # Show backtraces for deprecated behavior for quicker cleanup. @@ -18,14 +17,10 @@ ActiveSupport::Deprecation.debug = true 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 @@ class Net::SMTP 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 diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb new file mode 100644 index 0000000000..4a65363e3e --- /dev/null +++ b/actionmailer/test/base_test.rb @@ -0,0 +1,468 @@ +# encoding: utf-8 +require 'abstract_unit' + +class BaseTest < ActiveSupport::TestCase + class BaseMailer < ActionMailer::Base + self.mailer_name = "base_mailer" + + defaults :to => 'system@test.lindsaar.net', + :from => 'jose@test.plataformatec.com', + :reply_to => 'mikel@test.lindsaar.net' + + def welcome(hash = {}) + headers['X-SPAM'] = "Not SPAM" + mail({:subject => "The first email on new API!"}.merge!(hash)) + end + + def simple(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' + mail(hash) + end + + def attachment_with_hash + attachments['invoice.jpg'] = { :data => "you smiling", :mime_type => "image/x-jpg", + :transfer_encoding => "base64" } + mail + end + + def implicit_multipart(hash = {}) + attachments['invoice.pdf'] = 'This is test File content' if hash.delete(:attachments) + mail(hash) + end + + def implicit_with_locale(hash = {}) + mail(hash) + end + + def explicit_multipart(hash = {}) + attachments['invoice.pdf'] = 'This is test File content' if hash.delete(:attachments) + mail(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(hash) do |format| + format.html + format.text + end + end + + def explicit_multipart_with_any(hash = {}) + mail(hash) do |format| + format.any(:text, :html){ render :text => "Format with any!" } + end + end + + def custom_block(include_html=false) + mail 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 } + end + + # Basic mail usage without block + test "mail() should set the headers of the mail message" do + email = BaseMailer.welcome + assert_equal(['system@test.lindsaar.net'], email.to) + assert_equal(['jose@test.plataformatec.com'], email.from) + assert_equal('The first email on new API!', email.subject) + end + + test "mail() with from overwrites the class level default" do + email = BaseMailer.welcome(:from => 'someone@example.com', + :to => 'another@example.org') + assert_equal(['someone@example.com'], email.from) + assert_equal(['another@example.org'], email.to) + 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) + assert_equal(['bcc@test.lindsaar.net'], email.bcc) + assert_equal(['cc@test.lindsaar.net'], email.cc) + assert_equal('multipart/mixed', email.content_type) + assert_equal('iso-8559-1', email.charset) + assert_equal('2.0', email.mime_version) + assert_equal(['reply-to@test.lindsaar.net'], email.reply_to) + assert_equal(@time, email.date) + end + + test "mail() renders the template using the method being processed" do + email = BaseMailer.welcome + assert_equal("Welcome", email.body.encoded) + end + + test "can pass in :body to the mail method hash" do + email = BaseMailer.welcome(:body => "Hello there") + assert_equal("text/plain", email.mime_type) + assert_equal("Hello there", email.body.encoded) + end + + # Custom headers + test "custom headers" do + email = BaseMailer.welcome + assert_equal("Not SPAM", email['X-SPAM'].decoded) + end + + 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) + assert_equal('SecretValue', mail['X-Special-Domain-Specific-Header'].decoded) + assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded) + end + + 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) + assert_equal('SecretValue', mail['X-Special-Domain-Specific-Header'].decoded) + assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded) + end + + # Attachments + test "attachment with content" do + email = BaseMailer.attachment_with_content + 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 + assert_equal('invoice.pdf', email.attachments[0].filename) + end + + test "attachment with hash" do + email = BaseMailer.attachment_with_hash + 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 + 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 + 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") + 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 + with_default BaseMailer, :charset => "US-ASCII" do + email = BaseMailer.welcome + assert_equal("US-ASCII", email.charset) + + email = BaseMailer.welcome(:charset => "iso-8559-1") + assert_equal("iso-8559-1", email.charset) + end + end + + test "uses default content type from class" do + with_default BaseMailer, :content_type => "text/html" do + email = BaseMailer.welcome + assert_equal("text/html", email.mime_type) + + email = BaseMailer.welcome(:content_type => "text/plain") + assert_equal("text/plain", email.mime_type) + end + end + + test "uses default mime version from class" do + with_default BaseMailer, :mime_version => "2.0" do + email = BaseMailer.welcome + assert_equal("2.0", email.mime_version) + + email = BaseMailer.welcome(:mime_version => "1.0") + assert_equal("1.0", email.mime_version) + end + 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) + end + end + + test "subject gets default from I18n" do + BaseMailer.defaults[:subject] = nil + email = BaseMailer.welcome(:subject => nil) + assert_equal "Welcome", email.subject + + I18n.backend.store_translations('en', :actionmailer => {:base_mailer => {:welcome => {:subject => "New Subject!"}}}) + email = BaseMailer.welcome(:subject => nil) + assert_equal "New Subject!", email.subject + end + + # Implicit multipart + test "implicit multipart" do + email = BaseMailer.implicit_multipart + 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"] + with_default BaseMailer, :parts_order => order do + email = BaseMailer.implicit_multipart + 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) + 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) + 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"] + with_default BaseMailer, :parts_order => order do + email = BaseMailer.implicit_multipart(:attachments => true) + 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 + 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 + 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 + 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 + assert_equal("Welcome", email.body.encoded) + ensure + BaseMailer.view_paths.shift + end + end + + # Explicit multipart + test "explicit multipart" do + email = BaseMailer.explicit_multipart + 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"] + with_default BaseMailer, :parts_order => order do + email = BaseMailer.explicit_multipart + 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) + 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) + 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 + 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 + 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) + email.ready_to_send! + 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 + 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 + mail = BaseMailer.welcome.deliver + assert_instance_of Mail::Message, mail + 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(klass, new_values) + old_values = {} + new_values.each do |key, value| + old_values[key] = klass.send key + klass.send :"#{key}=", value + end + yield + ensure + old_values.each do |key, value| + klass.send :"#{key}=", value + end + end + + def with_default(klass, new_values) + hash = klass.defaults + old_values = {} + new_values.each do |key, value| + old_values[key] = hash[key] + hash[key] = value + end + yield + ensure + old_values.each do |key, value| + hash[key] = value + end + end +end
\ No newline at end of file diff --git a/actionmailer/test/delivery_method_test.rb b/actionmailer/test/delivery_method_test.rb deleted file mode 100644 index 8f8c6b0275..0000000000 --- a/actionmailer/test/delivery_method_test.rb +++ /dev/null @@ -1,101 +0,0 @@ -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 diff --git a/actionmailer/test/delivery_methods_test.rb b/actionmailer/test/delivery_methods_test.rb new file mode 100644 index 0000000000..4907ca0903 --- /dev/null +++ b/actionmailer/test/delivery_methods_test.rb @@ -0,0 +1,170 @@ +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 diff --git a/actionmailer/test/fixtures/another.path/base_mailer/welcome.erb b/actionmailer/test/fixtures/another.path/base_mailer/welcome.erb new file mode 100644 index 0000000000..ef451298e2 --- /dev/null +++ b/actionmailer/test/fixtures/another.path/base_mailer/welcome.erb @@ -0,0 +1 @@ +Welcome from another path
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/attachment_with_content.erb b/actionmailer/test/fixtures/base_mailer/attachment_with_content.erb new file mode 100644 index 0000000000..deb9dbd03b --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/attachment_with_content.erb @@ -0,0 +1 @@ +Attachment with content
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/explicit_multipart_templates.html.erb b/actionmailer/test/fixtures/base_mailer/explicit_multipart_templates.html.erb new file mode 100644 index 0000000000..c0a61b6249 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/explicit_multipart_templates.html.erb @@ -0,0 +1 @@ +HTML Explicit Multipart Templates
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/explicit_multipart_templates.text.erb b/actionmailer/test/fixtures/base_mailer/explicit_multipart_templates.text.erb new file mode 100644 index 0000000000..507230b1de --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/explicit_multipart_templates.text.erb @@ -0,0 +1 @@ +TEXT Explicit Multipart Templates
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb b/actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb new file mode 100644 index 0000000000..23745cd282 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb @@ -0,0 +1 @@ +HTML Implicit Multipart
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb b/actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb new file mode 100644 index 0000000000..d51437fc72 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb @@ -0,0 +1 @@ +TEXT Implicit Multipart
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/implicit_with_locale.en.html.erb b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.en.html.erb new file mode 100644 index 0000000000..34e39c8fdb --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.en.html.erb @@ -0,0 +1 @@ +Implicit with locale EN HTML
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/implicit_with_locale.html.erb b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.html.erb new file mode 100644 index 0000000000..5ce283f221 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.html.erb @@ -0,0 +1 @@ +Implicit with locale HTML
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/implicit_with_locale.pl.text.erb b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.pl.text.erb new file mode 100644 index 0000000000..c49cbae60a --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.pl.text.erb @@ -0,0 +1 @@ +Implicit with locale PL TEXT
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/implicit_with_locale.text.erb b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.text.erb new file mode 100644 index 0000000000..5a18ff62cd --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.text.erb @@ -0,0 +1 @@ +Implicit with locale TEXT
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/welcome.erb b/actionmailer/test/fixtures/base_mailer/welcome.erb new file mode 100644 index 0000000000..01f3f00c63 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/welcome.erb @@ -0,0 +1 @@ +Welcome
\ No newline at end of file diff --git a/actionmailer/test/fixtures/helper_mailer/use_example_helper.erb b/actionmailer/test/fixtures/helper_mailer/use_example_helper.erb deleted file mode 100644 index fcff3bb1b4..0000000000 --- a/actionmailer/test/fixtures/helper_mailer/use_example_helper.erb +++ /dev/null @@ -1 +0,0 @@ -So, <%= example_format(@text) %> diff --git a/actionmailer/test/fixtures/helper_mailer/use_helper.erb b/actionmailer/test/fixtures/helper_mailer/use_helper.erb deleted file mode 100644 index 378777f8bb..0000000000 --- a/actionmailer/test/fixtures/helper_mailer/use_helper.erb +++ /dev/null @@ -1 +0,0 @@ -Hello, <%= person_name %>. Thanks for registering! diff --git a/actionmailer/test/fixtures/helper_mailer/use_helper_method.erb b/actionmailer/test/fixtures/helper_mailer/use_helper_method.erb deleted file mode 100644 index d5b8b285e7..0000000000 --- a/actionmailer/test/fixtures/helper_mailer/use_helper_method.erb +++ /dev/null @@ -1 +0,0 @@ -This message brought to you by <%= name_of_the_mailer_class %>. diff --git a/actionmailer/test/fixtures/helper_mailer/use_mail_helper.erb b/actionmailer/test/fixtures/helper_mailer/use_mail_helper.erb deleted file mode 100644 index 96ec49d18a..0000000000 --- a/actionmailer/test/fixtures/helper_mailer/use_mail_helper.erb +++ /dev/null @@ -1,5 +0,0 @@ -From "Romeo and Juliet": - -<%= block_format @text %> - -Good ol' Shakespeare. diff --git a/actionmailer/test/fixtures/helpers/example_helper.rb b/actionmailer/test/fixtures/helpers/example_helper.rb deleted file mode 100644 index f6a6a49ced..0000000000 --- a/actionmailer/test/fixtures/helpers/example_helper.rb +++ /dev/null @@ -1,5 +0,0 @@ -module ExampleHelper - def example_format(text) - "<em><strong><small>#{h(text)}</small></strong></em>".html_safe! - end -end diff --git a/actionmailer/test/fixtures/nested_layout_mailer/signup.html.erb b/actionmailer/test/fixtures/nested_layout_mailer/signup.html.erb new file mode 100644 index 0000000000..4789e888c6 --- /dev/null +++ b/actionmailer/test/fixtures/nested_layout_mailer/signup.html.erb @@ -0,0 +1 @@ +We do not spam
\ No newline at end of file diff --git a/actionmailer/test/fixtures/test_mailer/body_ivar.erb b/actionmailer/test/fixtures/test_mailer/body_ivar.erb deleted file mode 100644 index 1421e5c908..0000000000 --- a/actionmailer/test/fixtures/test_mailer/body_ivar.erb +++ /dev/null @@ -1,2 +0,0 @@ -body: <%= @body %> -bar: <%= @bar %>
\ No newline at end of file diff --git a/actionmailer/test/fixtures/test_mailer/multipart_alternative.html.erb b/actionmailer/test/fixtures/test_mailer/multipart_alternative.html.erb new file mode 100644 index 0000000000..73ea14f82f --- /dev/null +++ b/actionmailer/test/fixtures/test_mailer/multipart_alternative.html.erb @@ -0,0 +1 @@ +<strong>foo</strong> <%= @foo %>
\ No newline at end of file diff --git a/actionmailer/test/fixtures/test_mailer/multipart_alternative.plain.erb b/actionmailer/test/fixtures/test_mailer/multipart_alternative.plain.erb new file mode 100644 index 0000000000..779fe4c1ea --- /dev/null +++ b/actionmailer/test/fixtures/test_mailer/multipart_alternative.plain.erb @@ -0,0 +1 @@ +foo: <%= @foo %>
\ No newline at end of file diff --git a/actionmailer/test/mail_helper_test.rb b/actionmailer/test/mail_helper_test.rb index 2d3565d159..7cc0804323 100644 --- a/actionmailer/test/mail_helper_test.rb +++ b/actionmailer/test/mail_helper_test.rb @@ -1,96 +1,54 @@ 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 diff --git a/actionmailer/test/mail_test.rb b/actionmailer/test/mail_test.rb deleted file mode 100644 index ea6f25d157..0000000000 --- a/actionmailer/test/mail_test.rb +++ /dev/null @@ -1,24 +0,0 @@ -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 diff --git a/actionmailer/test/adv_attr_test.rb b/actionmailer/test/old_base/adv_attr_test.rb index f22d733bc5..f22d733bc5 100644 --- a/actionmailer/test/adv_attr_test.rb +++ b/actionmailer/test/old_base/adv_attr_test.rb diff --git a/actionmailer/test/asset_host_test.rb b/actionmailer/test/old_base/asset_host_test.rb index f3383e5608..124032f1d9 100644 --- a/actionmailer/test/asset_host_test.rb +++ b/actionmailer/test/old_base/asset_host_test.rb @@ -1,8 +1,8 @@ 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 @@ class AssetHostTest < Test::Unit::TestCase 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 @@ class AssetHostTest < Test::Unit::TestCase "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 @@ class AssetHostTest < Test::Unit::TestCase 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 diff --git a/actionmailer/test/mail_layout_test.rb b/actionmailer/test/old_base/mail_layout_test.rb index 0877e7b2cb..5679aa5a64 100644 --- a/actionmailer/test/mail_layout_test.rb +++ b/actionmailer/test/old_base/mail_layout_test.rb @@ -1,32 +1,33 @@ 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" @world = "Earth" - render(:inline => "Hello, <%= @world %>", :layout => 'spam') + body 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" @world = "Earth" - render(:inline => "Hello, <%= @world %>", :layout => false) + body 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 @@ end 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 @@ class LayoutMailerTest < Test::Unit::TestCase 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 @@ -78,7 +77,7 @@ class LayoutMailerTest < Test::Unit::TestCase # CHANGED: content_type returns an object # assert_equal 'text/plain', mail.parts.first.content_type assert_equal 'text/plain', mail.parts.first.mime_type - + # CHANGED: body returns an object # assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s @@ -93,7 +92,7 @@ class LayoutMailerTest < Test::Unit::TestCase 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 @@ class LayoutMailerTest < Test::Unit::TestCase 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 @@ class LayoutMailerTest < Test::Unit::TestCase 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 diff --git a/actionmailer/test/mail_render_test.rb b/actionmailer/test/old_base/mail_render_test.rb index 09ce5e4854..405d43d7d3 100644 --- a/actionmailer/test/mail_render_test.rb +++ b/actionmailer/test/old_base/mail_render_test.rb @@ -1,60 +1,43 @@ 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" @world = "Earth" - render :inline => "Hello, <%= @world %>" + body 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 - render :file => "templates/signed_up" - end - - def implicit_body(recipient) - recipients recipient - subject "using helpers" - from "tester@example.com" - - @recipient = recipient - render :template => "templates/signed_up" + @recipient = 'test@localhost' + body render(:file => "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 - 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" silence_warnings do - render :inline => "Look, subject.nil? is <%= @subject.nil? %>!" + body render(:inline => "Look, subject.nil? is <%= @subject.nil? %>!") end end @@ -62,19 +45,46 @@ class RenderMailer < ActionMailer::Base super mailer_name "test_mailer" end + + def multipart_alternative + recipients 'test@localhost' + subject 'multipart/alternative' + from 'tester@example.com' + + build_multipart_message(:foo => "bar") + end + + private + def build_multipart_message(assigns = {}) + content_type "multipart/alternative" + + part "text/plain" do |p| + p.body = build_body_part('plain', assigns, :layout => false) + end + + part "text/html" do |p| + p.body = build_body_part('html', assigns) + end + end + + def build_body_part(content_type, assigns, options = {}) + ActiveSupport::Deprecation.silence do + render "#{template}.#{content_type}", :body => assigns + end + end 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 +96,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 @@ -95,47 +105,47 @@ class RenderHelperTest < Test::Unit::TestCase restore_delivery_method end - def test_implicit_body - mail = RenderMailer.create_implicit_body(@recipient) - 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) - 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 + + def test_legacy_multipart_alternative + mail = RenderMailer.multipart_alternative.deliver + assert_equal(2, mail.parts.size) + assert_equal("multipart/alternative", mail.mime_type) + assert_equal("text/plain", mail.parts[0].mime_type) + assert_equal("foo: bar", mail.parts[0].body.encoded) + assert_equal("text/html", mail.parts[1].mime_type) + assert_equal("<strong>foo</strong> bar", mail.parts[1].body.encoded) + end end 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 +155,13 @@ class FirstSecondHelperTest < Test::Unit::TestCase 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 diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/old_base/mail_service_test.rb index f87d9b2e5b..70dafaf33c 100644 --- a/actionmailer/test/mail_service_test.rb +++ b/actionmailer/test/old_base/mail_service_test.rb @@ -2,7 +2,7 @@ require 'abstract_unit' class FunkyPathMailer < ActionMailer::Base - self.template_root = "#{File.dirname(__FILE__)}/fixtures/path.with.dots" + self.view_paths = "#{File.dirname(__FILE__)}/../fixtures/path.with.dots" def multipart_with_template_path_with_dots(recipient) recipients recipient @@ -27,20 +27,19 @@ class TestMailer < ActionMailer::Base subject "[Cancelled] Goodbye #{recipient}" from "system@loudthinking.com" sent_on Time.local(2004, 12, 12) - - render :text => "Goodbye, Mr. #{recipient}" + body "Goodbye, Mr. #{recipient}" end def from_with_name from "System <system@loudthinking.com>" recipients "root@loudthinking.com" - render :text => "Nothing to see here." + body "Nothing to see here." end def from_without_name from "system@loudthinking.com" recipients "root@loudthinking.com" - render :text => "Nothing to see here." + body "Nothing to see here." end def cc_bcc(recipient) @@ -51,7 +50,7 @@ class TestMailer < ActionMailer::Base cc "nobody@loudthinking.com" bcc "root@loudthinking.com" - render :text => "Nothing to see here." + body "Nothing to see here." end def different_reply_to(recipient) @@ -61,7 +60,7 @@ class TestMailer < ActionMailer::Base sent_on Time.local(2008, 5, 23) reply_to "atraver@gmail.com" - render :text => "Nothing to see here." + body "Nothing to see here." end def iso_charset(recipient) @@ -73,7 +72,7 @@ class TestMailer < ActionMailer::Base bcc "root@loudthinking.com" charset "iso-8859-1" - render :text => "Nothing to see here." + body "Nothing to see here." end def unencoded_subject(recipient) @@ -84,7 +83,7 @@ class TestMailer < ActionMailer::Base cc "nobody@loudthinking.com" bcc "root@loudthinking.com" - render :text => "Nothing to see here." + body "Nothing to see here." end def extended_headers(recipient) @@ -96,7 +95,7 @@ class TestMailer < ActionMailer::Base bcc "Grytøyr <stian3@example.net>" charset "iso-8859-1" - render :text => "Nothing to see here." + body "Nothing to see here." end def utf8_body(recipient) @@ -108,7 +107,7 @@ class TestMailer < ActionMailer::Base bcc "Foo áëô îü <extended@example.net>" charset "utf-8" - render :text => "åœö blah" + body "åœö blah" end def multipart_with_mime_version(recipient) @@ -120,11 +119,11 @@ class TestMailer < ActionMailer::Base content_type "multipart/alternative" part "text/plain" do |p| - p.body = render_message(:text => "blah") + p.body = render(:text => "blah") end part "text/html" do |p| - p.body = render_message(:inline => "<%= content_tag(:b, 'blah') %>") + p.body = render(:inline => "<%= content_tag(:b, 'blah') %>") end end @@ -158,7 +157,7 @@ class TestMailer < ActionMailer::Base attachment :content_type => "image/jpeg", :filename => File.join(File.dirname(__FILE__), "fixtures", "attachments", "foo.jpg"), :data => "123456789" - render :text => "plain text default" + body "plain text default" end def implicitly_multipart_example(recipient, cs = nil, order = nil) @@ -187,12 +186,12 @@ class TestMailer < ActionMailer::Base from "test@example.com" content_type "text/html" - render :text => "<em>Emphasize</em> <strong>this</strong>" + body "<em>Emphasize</em> <strong>this</strong>" end def html_mail_with_underscores(recipient) subject "html mail with underscores" - render :text => %{<a href="http://google.com" target="_blank">_Google</a>} + body %{<a href="http://google.com" target="_blank">_Google</a>} end def custom_template(recipient) @@ -219,7 +218,7 @@ class TestMailer < ActionMailer::Base subject "various newlines" from "test@example.com" - render :text => "line #1\nline #2\rline #3\r\nline #4\r\r" + + body "line #1\nline #2\rline #3\r\nline #4\r\r" + "line #5\n\nline#6\r\n\r\nline #7" end @@ -282,7 +281,7 @@ class TestMailer < ActionMailer::Base from "One: Two <test@example.com>" cc "Three: Four <test@example.com>" bcc "Five: Six <test@example.com>" - render :text => "testing" + body "testing" end def custom_content_type_attributes @@ -290,28 +289,21 @@ class TestMailer < ActionMailer::Base subject "custom content types" from "some.one@somewhere.test" content_type "text/plain; format=flowed" - render :text => "testing" + body "testing" end def return_path recipients "no.one@nowhere.test" subject "return path test" from "some.one@somewhere.test" - headers "return-path" => "another@somewhere.test" - render :text => "testing" - end - - def body_ivar(recipient) - recipients recipient - subject "Body as a local variable" - from "test@example.com" - body :body => "foo", :bar => "baz" + headers["return-path"] = "another@somewhere.test" + body "testing" end def subject_with_i18n(recipient) recipients recipient from "system@loudthinking.com" - render :text => "testing" + body "testing" end class << self @@ -344,7 +336,7 @@ class ActionMailerTest < Test::Unit::TestCase set_delivery_method :test ActionMailer::Base.perform_deliveries = true ActionMailer::Base.raise_delivery_errors = true - ActionMailer::Base.deliveries = [] + ActionMailer::Base.deliveries.clear @original_logger = TestMailer.logger @recipient = 'test@localhost' @@ -357,7 +349,7 @@ class ActionMailerTest < Test::Unit::TestCase def test_nested_parts created = nil - assert_nothing_raised { created = TestMailer.create_nested_multipart(@recipient)} + assert_nothing_raised { created = TestMailer.nested_multipart(@recipient)} assert_equal 2, created.parts.size assert_equal 2, created.parts.first.parts.size @@ -373,8 +365,8 @@ class ActionMailerTest < Test::Unit::TestCase def test_nested_parts_with_body created = nil - TestMailer.create_nested_multipart_with_body(@recipient) - assert_nothing_raised { created = TestMailer.create_nested_multipart_with_body(@recipient)} + TestMailer.nested_multipart_with_body(@recipient) + assert_nothing_raised { created = TestMailer.nested_multipart_with_body(@recipient)} assert_equal 1,created.parts.size assert_equal 2,created.parts.first.parts.size @@ -389,11 +381,13 @@ class ActionMailerTest < Test::Unit::TestCase def test_attachment_with_custom_header created = nil - assert_nothing_raised { created = TestMailer.create_attachment_with_custom_header(@recipient) } + assert_nothing_raised { created = TestMailer.attachment_with_custom_header(@recipient) } assert created.parts.any? { |p| p.header['content-id'].to_s == "<test@test.com>" } end def test_signed_up + TestMailer.delivery_method = :test + Time.stubs(:now => Time.now) expected = new_mail @@ -404,7 +398,7 @@ class ActionMailerTest < Test::Unit::TestCase expected.date = Time.now created = nil - assert_nothing_raised { created = TestMailer.create_signed_up(@recipient) } + assert_nothing_raised { created = TestMailer.signed_up(@recipient) } assert_not_nil created expected.message_id = '<123@456>' @@ -412,7 +406,7 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal expected.encoded, created.encoded - assert_nothing_raised { TestMailer.deliver_signed_up(@recipient) } + assert_nothing_raised { TestMailer.signed_up(@recipient).deliver } delivered = ActionMailer::Base.deliveries.first assert_not_nil delivered @@ -423,15 +417,6 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal expected.encoded, delivered.encoded end - def test_subject_with_i18n - assert_nothing_raised { TestMailer.deliver_subject_with_i18n(@recipient) } - assert_equal "Subject with i18n", ActionMailer::Base.deliveries.first.subject.to_s - - I18n.backend.store_translations('en', :actionmailer => {:test_mailer => {:subject_with_i18n => {:subject => "New Subject!"}}}) - assert_nothing_raised { TestMailer.deliver_subject_with_i18n(@recipient) } - assert_equal "New Subject!", ActionMailer::Base.deliveries.last.subject.to_s - end - def test_custom_template expected = new_mail expected.to = @recipient @@ -441,7 +426,7 @@ class ActionMailerTest < Test::Unit::TestCase expected.date = Time.local(2004, 12, 12) created = nil - assert_nothing_raised { created = TestMailer.create_custom_template(@recipient) } + assert_nothing_raised { created = TestMailer.custom_template(@recipient) } assert_not_nil created expected.message_id = '<123@456>' created.message_id = '<123@456>' @@ -464,7 +449,7 @@ class ActionMailerTest < Test::Unit::TestCase # Now that the template is registered, there should be one part. The text/plain part. created = nil - assert_nothing_raised { created = TestMailer.create_custom_templating_extension(@recipient) } + assert_nothing_raised { created = TestMailer.custom_templating_extension(@recipient) } assert_not_nil created assert_equal 2, created.parts.length assert_equal 'text/plain', created.parts[0].mime_type @@ -480,13 +465,13 @@ class ActionMailerTest < Test::Unit::TestCase expected.date = Time.local(2004, 12, 12) created = nil - assert_nothing_raised { created = TestMailer.create_cancelled_account(@recipient) } + assert_nothing_raised { created = TestMailer.cancelled_account(@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_cancelled_account(@recipient) } + assert_nothing_raised { TestMailer.cancelled_account(@recipient).deliver } assert_not_nil ActionMailer::Base.deliveries.first delivered = ActionMailer::Base.deliveries.first expected.message_id = '<123@456>' @@ -507,7 +492,7 @@ class ActionMailerTest < Test::Unit::TestCase created = nil assert_nothing_raised do - created = TestMailer.create_cc_bcc @recipient + created = TestMailer.cc_bcc @recipient end assert_not_nil created expected.message_id = '<123@456>' @@ -515,7 +500,7 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal expected.encoded, created.encoded assert_nothing_raised do - TestMailer.deliver_cc_bcc @recipient + TestMailer.cc_bcc(@recipient).deliver end assert_not_nil ActionMailer::Base.deliveries.first @@ -527,8 +512,8 @@ class ActionMailerTest < Test::Unit::TestCase end def test_from_without_name_for_smtp - ActionMailer::Base.delivery_method = :smtp - TestMailer.deliver_from_without_name + TestMailer.delivery_method = :smtp + TestMailer.from_without_name.deliver mail = MockSMTP.deliveries.first assert_not_nil mail @@ -538,17 +523,19 @@ class ActionMailerTest < Test::Unit::TestCase end def test_from_with_name_for_smtp - ActionMailer::Base.delivery_method = :smtp - TestMailer.deliver_from_with_name + TestMailer.delivery_method = :smtp + TestMailer.from_with_name.deliver mail = MockSMTP.deliveries.first assert_not_nil mail mail, from, to = mail - assert_equal 'system@loudthinking.com', from.addresses.first + assert_equal 'system@loudthinking.com', from end def test_reply_to + TestMailer.delivery_method = :test + expected = new_mail expected.to = @recipient @@ -560,7 +547,7 @@ class ActionMailerTest < Test::Unit::TestCase created = nil assert_nothing_raised do - created = TestMailer.create_different_reply_to @recipient + created = TestMailer.different_reply_to @recipient end assert_not_nil created @@ -570,7 +557,7 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal expected.encoded, created.encoded assert_nothing_raised do - TestMailer.deliver_different_reply_to @recipient + TestMailer.different_reply_to(@recipient).deliver end delivered = ActionMailer::Base.deliveries.first @@ -583,6 +570,8 @@ class ActionMailerTest < Test::Unit::TestCase end def test_iso_charset + TestMailer.delivery_method = :test + expected = new_mail( "iso-8859-1" ) expected.to = @recipient expected.subject = encode "testing isø charsets", "iso-8859-1" @@ -594,7 +583,7 @@ class ActionMailerTest < Test::Unit::TestCase created = nil assert_nothing_raised do - created = TestMailer.create_iso_charset @recipient + created = TestMailer.iso_charset @recipient end assert_not_nil created @@ -604,7 +593,7 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal expected.encoded, created.encoded assert_nothing_raised do - TestMailer.deliver_iso_charset @recipient + TestMailer.iso_charset(@recipient).deliver end delivered = ActionMailer::Base.deliveries.first @@ -617,6 +606,7 @@ class ActionMailerTest < Test::Unit::TestCase end def test_unencoded_subject + TestMailer.delivery_method = :test expected = new_mail expected.to = @recipient expected.subject = "testing unencoded subject" @@ -628,7 +618,7 @@ class ActionMailerTest < Test::Unit::TestCase created = nil assert_nothing_raised do - created = TestMailer.create_unencoded_subject @recipient + created = TestMailer.unencoded_subject @recipient end assert_not_nil created @@ -638,7 +628,7 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal expected.encoded, created.encoded assert_nothing_raised do - TestMailer.deliver_unencoded_subject @recipient + TestMailer.unencoded_subject(@recipient).deliver end delivered = ActionMailer::Base.deliveries.first @@ -650,41 +640,33 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal expected.encoded, delivered.encoded end - def test_instances_are_nil - assert_nil ActionMailer::Base.new - assert_nil TestMailer.new - end - def test_deliveries_array assert_not_nil ActionMailer::Base.deliveries assert_equal 0, ActionMailer::Base.deliveries.size - TestMailer.deliver_signed_up(@recipient) + TestMailer.signed_up(@recipient).deliver assert_equal 1, ActionMailer::Base.deliveries.size assert_not_nil ActionMailer::Base.deliveries.first end def test_perform_deliveries_flag ActionMailer::Base.perform_deliveries = false - TestMailer.deliver_signed_up(@recipient) + TestMailer.signed_up(@recipient).deliver assert_equal 0, ActionMailer::Base.deliveries.size ActionMailer::Base.perform_deliveries = true - TestMailer.deliver_signed_up(@recipient) + TestMailer.signed_up(@recipient).deliver assert_equal 1, ActionMailer::Base.deliveries.size end def test_doesnt_raise_errors_when_raise_delivery_errors_is_false ActionMailer::Base.raise_delivery_errors = false - TestMailer.delivery_method.expects(:perform_delivery).raises(Exception) - assert_nothing_raised { TestMailer.deliver_signed_up(@recipient) } + Mail::TestMailer.any_instance.expects(:deliver!).raises(Exception) + assert_nothing_raised { TestMailer.signed_up(@recipient).deliver } end def test_performs_delivery_via_sendmail - sm = mock() - sm.expects(:print).with(anything) - sm.expects(:flush) - IO.expects(:popen).once.with('/usr/sbin/sendmail -i -t', 'w+').yields(sm) - ActionMailer::Base.delivery_method = :sendmail - TestMailer.deliver_signed_up(@recipient) + IO.expects(:popen).once.with('/usr/sbin/sendmail -i -t -f "system@loudthinking.com" test@localhost', 'w+') + TestMailer.delivery_method = :sendmail + TestMailer.signed_up(@recipient).deliver end def test_unquote_quoted_printable_subject @@ -769,7 +751,7 @@ EOF created = nil assert_nothing_raised do - created = TestMailer.create_extended_headers @recipient + created = TestMailer.extended_headers @recipient end assert_not_nil created @@ -779,7 +761,7 @@ EOF assert_equal expected.encoded, created.encoded assert_nothing_raised do - TestMailer.deliver_extended_headers @recipient + TestMailer.extended_headers(@recipient).deliver end delivered = ActionMailer::Base.deliveries.first @@ -802,7 +784,7 @@ EOF expected.bcc = quote_address_if_necessary @recipient, "utf-8" expected.date = Time.local 2004, 12, 12 - created = TestMailer.create_utf8_body @recipient + created = TestMailer.utf8_body @recipient assert_match(/åœö blah/, created.encoded) end @@ -817,82 +799,82 @@ EOF expected.bcc = quote_address_if_necessary @recipient, "utf-8" expected.date = Time.local 2004, 12, 12 - created = TestMailer.create_utf8_body @recipient + created = TestMailer.utf8_body @recipient assert_match(/\nFrom: =\?utf-8\?Q\?Foo_.*?\?= <extended@example.net>\r/, created.encoded) assert_match(/\nTo: =\?utf-8\?Q\?Foo_.*?\?= <extended@example.net>, \r\n\tExample Recipient <me/, created.encoded) end def test_receive_decodes_base64_encoded_mail - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email") TestMailer.receive(fixture) assert_match(/Jamis/, TestMailer.received_body.to_s) end def test_receive_attachments - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email2") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email2") mail = Mail.new(fixture) attachment = mail.attachments.last - assert_equal "smime.p7s", attachment.original_filename + assert_equal "smime.p7s", attachment.filename assert_equal "application/pkcs7-signature", mail.parts.last.mime_type end def test_decode_attachment_without_charset - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email3") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email3") mail = Mail.new(fixture) attachment = mail.attachments.last assert_equal 1026, attachment.read.length end def test_attachment_using_content_location - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email12") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email12") mail = Mail.new(fixture) assert_equal 1, mail.attachments.length - assert_equal "Photo25.jpg", mail.attachments.first.original_filename + assert_equal "Photo25.jpg", mail.attachments.first.filename end def test_attachment_with_text_type - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email13") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email13") mail = Mail.new(fixture) assert mail.has_attachments? assert_equal 1, mail.attachments.length - assert_equal "hello.rb", mail.attachments.first.original_filename + assert_equal "hello.rb", mail.attachments.first.filename end def test_decode_part_without_content_type - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email4") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email4") mail = Mail.new(fixture) assert_nothing_raised { mail.body } end def test_decode_message_without_content_type - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email5") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email5") mail = Mail.new(fixture) assert_nothing_raised { mail.body } end def test_decode_message_with_incorrect_charset - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email6") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email6") mail = Mail.new(fixture) assert_nothing_raised { mail.body } end def test_multipart_with_mime_version - mail = TestMailer.create_multipart_with_mime_version(@recipient) + mail = TestMailer.multipart_with_mime_version(@recipient) assert_equal "1.1", mail.mime_version end def test_multipart_with_utf8_subject - mail = TestMailer.create_multipart_with_utf8_subject(@recipient) + mail = TestMailer.multipart_with_utf8_subject(@recipient) assert_match(/\nSubject: =\?utf-8\?Q\?Foo_.*?\?=/, mail.encoded) end def test_implicitly_multipart_with_utf8 - mail = TestMailer.create_implicitly_multipart_with_utf8 + mail = TestMailer.implicitly_multipart_with_utf8 assert_match(/\nSubject: =\?utf-8\?Q\?Foo_.*?\?=/, mail.encoded) end def test_explicitly_multipart_messages - mail = TestMailer.create_explicitly_multipart_example(@recipient) + mail = TestMailer.explicitly_multipart_example(@recipient) assert_equal 3, mail.parts.length assert_equal 'multipart/mixed', mail.mime_type assert_equal "text/plain", mail.parts[0].mime_type @@ -901,6 +883,7 @@ EOF assert_equal "iso-8859-1", mail.parts[1].charset assert_equal "image/jpeg", mail.parts[2].mime_type + assert_equal "attachment", mail.parts[2][:content_disposition].disposition_type assert_equal "foo.jpg", mail.parts[2][:content_disposition].filename assert_equal "foo.jpg", mail.parts[2][:content_type].filename @@ -908,13 +891,13 @@ EOF end def test_explicitly_multipart_with_content_type - mail = TestMailer.create_explicitly_multipart_example(@recipient, "multipart/alternative") + mail = TestMailer.explicitly_multipart_example(@recipient, "multipart/alternative") assert_equal 3, mail.parts.length assert_equal "multipart/alternative", mail.mime_type end def test_explicitly_multipart_with_invalid_content_type - mail = TestMailer.create_explicitly_multipart_example(@recipient, "text/xml") + mail = TestMailer.explicitly_multipart_example(@recipient, "text/xml") assert_equal 3, mail.parts.length assert_equal 'multipart/mixed', mail.mime_type end @@ -922,7 +905,7 @@ EOF def test_implicitly_multipart_messages assert ActionView::Template.template_handler_extensions.include?("bak"), "bak extension was not registered" - mail = TestMailer.create_implicitly_multipart_example(@recipient) + mail = TestMailer.implicitly_multipart_example(@recipient) assert_equal 3, mail.parts.length assert_equal "1.0", mail.mime_version.to_s assert_equal "multipart/alternative", mail.mime_type @@ -937,7 +920,7 @@ EOF def test_implicitly_multipart_messages_with_custom_order assert ActionView::Template.template_handler_extensions.include?("bak"), "bak extension was not registered" - mail = TestMailer.create_implicitly_multipart_example(@recipient, nil, ["application/x-yaml", "text/plain"]) + mail = TestMailer.implicitly_multipart_example(@recipient, nil, ["application/x-yaml", "text/plain"]) assert_equal 3, mail.parts.length assert_equal "application/x-yaml", mail.parts[0].mime_type assert_equal "text/plain", mail.parts[1].mime_type @@ -945,7 +928,7 @@ EOF end def test_implicitly_multipart_messages_with_charset - mail = TestMailer.create_implicitly_multipart_example(@recipient, 'iso-8859-1') + mail = TestMailer.implicitly_multipart_example(@recipient, 'iso-8859-1') assert_equal "multipart/alternative", mail.header['content-type'].content_type @@ -955,23 +938,23 @@ EOF end def test_html_mail - mail = TestMailer.create_html_mail(@recipient) + mail = TestMailer.html_mail(@recipient) assert_equal "text/html", mail.mime_type end def test_html_mail_with_underscores - mail = TestMailer.create_html_mail_with_underscores(@recipient) + mail = TestMailer.html_mail_with_underscores(@recipient) assert_equal %{<a href="http://google.com" target="_blank">_Google</a>}, mail.body.to_s end def test_various_newlines - mail = TestMailer.create_various_newlines(@recipient) + mail = TestMailer.various_newlines(@recipient) assert_equal("line #1\nline #2\nline #3\nline #4\n\n" + "line #5\n\nline#6\n\nline #7", mail.body.to_s) end def test_various_newlines_multipart - mail = TestMailer.create_various_newlines_multipart(@recipient) + mail = TestMailer.various_newlines_multipart(@recipient) assert_equal "line #1\nline #2\nline #3\nline #4\n\n", mail.parts[0].body.to_s assert_equal "<p>line #1</p>\n<p>line #2</p>\n<p>line #3</p>\n<p>line #4</p>\n\n", mail.parts[1].body.to_s assert_equal "line #1\r\nline #2\r\nline #3\r\nline #4\r\n\r\n", mail.parts[0].body.encoded @@ -979,8 +962,8 @@ EOF end def test_headers_removed_on_smtp_delivery - ActionMailer::Base.delivery_method = :smtp - TestMailer.deliver_cc_bcc(@recipient) + TestMailer.delivery_method = :smtp + TestMailer.cc_bcc(@recipient).deliver assert MockSMTP.deliveries[0][2].include?("root@loudthinking.com") assert MockSMTP.deliveries[0][2].include?("nobody@loudthinking.com") assert MockSMTP.deliveries[0][2].include?(@recipient) @@ -990,10 +973,10 @@ EOF end def test_file_delivery_should_create_a_file - ActionMailer::Base.delivery_method = :file - tmp_location = ActionMailer::Base.file_settings[:location] + TestMailer.delivery_method = :file + tmp_location = TestMailer.file_settings[:location] - TestMailer.deliver_cc_bcc(@recipient) + result = TestMailer.cc_bcc(@recipient).deliver assert File.exists?(tmp_location) assert File.directory?(tmp_location) assert File.exists?(File.join(tmp_location, @recipient)) @@ -1002,7 +985,7 @@ EOF end def test_recursive_multipart_processing - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email7") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email7") mail = Mail.new(fixture) assert_equal(2, mail.parts.length) assert_equal(4, mail.parts.first.parts.length) @@ -1013,36 +996,36 @@ EOF end def test_decode_encoded_attachment_filename - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email8") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email8") mail = Mail.new(fixture) attachment = mail.attachments.last expected = "01 Quien Te Dij\212at. Pitbull.mp3" if expected.respond_to?(:force_encoding) - result = attachment.original_filename.dup + result = attachment.filename.dup expected.force_encoding(Encoding::ASCII_8BIT) result.force_encoding(Encoding::ASCII_8BIT) assert_equal expected, result else - assert_equal expected, attachment.original_filename + assert_equal expected, attachment.filename end end def test_decode_message_with_unknown_charset - fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email10") + fixture = File.read(File.dirname(__FILE__) + "/../fixtures/raw_email10") mail = Mail.new(fixture) assert_nothing_raised { mail.body } end def test_empty_header_values_omitted - result = TestMailer.create_unnamed_attachment(@recipient).encoded + result = TestMailer.unnamed_attachment(@recipient).encoded assert_match %r{Content-Type: application/octet-stream;}, result - assert_match %r{Content-Disposition: attachment[^;]}, result + assert_match %r{Content-Disposition: attachment;}, result end def test_headers_with_nonalpha_chars - mail = TestMailer.create_headers_with_nonalpha_chars(@recipient) + mail = TestMailer.headers_with_nonalpha_chars(@recipient) assert !mail.from_addrs.empty? assert !mail.cc_addrs.empty? assert !mail.bcc_addrs.empty? @@ -1051,98 +1034,90 @@ EOF assert_match(/:/, mail[:bcc].decoded) end - def test_deliver_with_mail_object - mail = TestMailer.create_headers_with_nonalpha_chars(@recipient) - assert_nothing_raised { TestMailer.deliver(mail) } + def test_with_mail_object_deliver + TestMailer.delivery_method = :test + mail = TestMailer.headers_with_nonalpha_chars(@recipient) + assert_nothing_raised { mail.deliver } assert_equal 1, TestMailer.deliveries.length end def test_multipart_with_template_path_with_dots - mail = FunkyPathMailer.create_multipart_with_template_path_with_dots(@recipient) + mail = FunkyPathMailer.multipart_with_template_path_with_dots(@recipient) assert_equal 2, mail.parts.length assert "text/plain", mail.parts[1].mime_type assert "utf-8", mail.parts[1].charset end def test_custom_content_type_attributes - mail = TestMailer.create_custom_content_type_attributes + mail = TestMailer.custom_content_type_attributes assert_match %r{format=flowed}, mail.content_type assert_match %r{charset=utf-8}, mail.content_type end def test_return_path_with_create - mail = TestMailer.create_return_path - assert_equal "another@somewhere.test", mail['return-path'].to_s - end - - def test_return_path_with_create - mail = TestMailer.create_return_path - assert_equal ["another@somewhere.test"], mail.return_path + mail = TestMailer.return_path + assert_equal "another@somewhere.test", mail.return_path end def test_return_path_with_deliver - ActionMailer::Base.delivery_method = :smtp - TestMailer.deliver_return_path + TestMailer.delivery_method = :smtp + TestMailer.return_path.deliver assert_match %r{^Return-Path: <another@somewhere.test>}, MockSMTP.deliveries[0][0] assert_equal "another@somewhere.test", MockSMTP.deliveries[0][1].to_s end - def test_body_is_stored_as_an_ivar - mail = TestMailer.create_body_ivar(@recipient) - assert_equal "body: foo\nbar: baz", mail.body.to_s - end - def test_starttls_is_enabled_if_supported - ActionMailer::Base.smtp_settings[:enable_starttls_auto] = true + TestMailer.smtp_settings.merge!(:enable_starttls_auto => true) MockSMTP.any_instance.expects(:respond_to?).with(:enable_starttls_auto).returns(true) MockSMTP.any_instance.expects(:enable_starttls_auto) - ActionMailer::Base.delivery_method = :smtp - TestMailer.deliver_signed_up(@recipient) + TestMailer.delivery_method = :smtp + TestMailer.signed_up(@recipient).deliver end def test_starttls_is_disabled_if_not_supported - ActionMailer::Base.smtp_settings[:enable_starttls_auto] = true + TestMailer.smtp_settings.merge!(:enable_starttls_auto => true) MockSMTP.any_instance.expects(:respond_to?).with(:enable_starttls_auto).returns(false) MockSMTP.any_instance.expects(:enable_starttls_auto).never - ActionMailer::Base.delivery_method = :smtp - TestMailer.deliver_signed_up(@recipient) + TestMailer.delivery_method = :smtp + TestMailer.signed_up(@recipient).deliver end def test_starttls_is_not_enabled - ActionMailer::Base.smtp_settings[:enable_starttls_auto] = false + TestMailer.smtp_settings.merge!(:enable_starttls_auto => false) MockSMTP.any_instance.expects(:respond_to?).never - MockSMTP.any_instance.expects(:enable_starttls_auto).never - ActionMailer::Base.delivery_method = :smtp - TestMailer.deliver_signed_up(@recipient) + TestMailer.delivery_method = :smtp + TestMailer.signed_up(@recipient).deliver ensure - ActionMailer::Base.smtp_settings[:enable_starttls_auto] = true + TestMailer.smtp_settings.merge!(:enable_starttls_auto => true) end end -class InheritableTemplateRootTest < Test::Unit::TestCase +class InheritableTemplateRootTest < ActiveSupport::TestCase def test_attr - expected = File.expand_path("#{File.dirname(__FILE__)}/fixtures/path.with.dots") + expected = File.expand_path("#{File.dirname(__FILE__)}/../fixtures/path.with.dots") assert_equal expected, FunkyPathMailer.template_root.to_s sub = Class.new(FunkyPathMailer) - sub.template_root = 'test/path' + assert_deprecated do + sub.template_root = 'test/path' + end assert_equal File.expand_path('test/path'), sub.template_root.to_s assert_equal expected, FunkyPathMailer.template_root.to_s end end -class MethodNamingTest < Test::Unit::TestCase +class MethodNamingTest < ActiveSupport::TestCase class TestMailer < ActionMailer::Base def send - render :text => 'foo' + body 'foo' end end def setup set_delivery_method :test ActionMailer::Base.perform_deliveries = true - ActionMailer::Base.deliveries = [] + ActionMailer::Base.deliveries.clear end def teardown @@ -1152,12 +1127,13 @@ class MethodNamingTest < Test::Unit::TestCase def test_send_method assert_nothing_raised do assert_emails 1 do - TestMailer.deliver_send + assert_deprecated do + TestMailer.deliver_send + end end end end end - class RespondToTest < Test::Unit::TestCase class RespondToMailer < ActionMailer::Base; end @@ -1220,4 +1196,4 @@ class RespondToTest < Test::Unit::TestCase assert_match(/undefined method.*not_a_method/, error.message) end -end +end
\ No newline at end of file diff --git a/actionmailer/test/tmail_compat_test.rb b/actionmailer/test/old_base/tmail_compat_test.rb index a1ca6a7243..7c1d9a07c1 100644 --- a/actionmailer/test/tmail_compat_test.rb +++ b/actionmailer/test/old_base/tmail_compat_test.rb @@ -1,21 +1,23 @@ 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 diff --git a/actionmailer/test/url_test.rb b/actionmailer/test/old_base/url_test.rb index 12bf609dce..5affb47997 100644 --- a/actionmailer/test/url_test.rb +++ b/actionmailer/test/old_base/url_test.rb @@ -44,7 +44,7 @@ class ActionMailerUrlTest < 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 @@ -54,6 +54,8 @@ class ActionMailerUrlTest < Test::Unit::TestCase 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 @@ class ActionMailerUrlTest < Test::Unit::TestCase 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 diff --git a/actionmailer/test/subscriber_test.rb b/actionmailer/test/subscriber_test.rb index aed5d2ca7e..3d1736d64f 100644 --- a/actionmailer/test/subscriber_test.rb +++ b/actionmailer/test/subscriber_test.rb @@ -11,7 +11,7 @@ class AMSubscriberTest < ActionMailer::TestCase recipients "somewhere@example.com" subject "basic" from "basic@example.com" - render :text => "Hello world" + body "Hello world" end def receive(mail) @@ -24,21 +24,21 @@ class AMSubscriberTest < ActionMailer::TestCase 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 diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb index 1fed26f78f..3a38a91c28 100644 --- a/actionmailer/test/test_helper_test.rb +++ b/actionmailer/test/test_helper_test.rb @@ -12,7 +12,7 @@ end 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 @@ class TestHelperMailerTest < ActionMailer::TestCase 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 @@ class TestHelperMailerTest < ActionMailer::TestCase 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 @@ class TestHelperMailerTest < ActionMailer::TestCase 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 @@ class TestHelperMailerTest < ActionMailer::TestCase 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 @@ class TestHelperMailerTest < ActionMailer::TestCase 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 @@ class TestHelperMailerTest < ActionMailer::TestCase 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 diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 725d8fb8fc..2c2ef16622 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -10,6 +10,7 @@ module AbstractController autoload :Base autoload :Callbacks + autoload :Collector autoload :Helpers autoload :Layouts autoload :LocalizedCache diff --git a/actionpack/lib/abstract_controller/collector.rb b/actionpack/lib/abstract_controller/collector.rb new file mode 100644 index 0000000000..d429333661 --- /dev/null +++ b/actionpack/lib/abstract_controller/collector.rb @@ -0,0 +1,30 @@ +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 diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 6fbf6bc392..56ddf9bf01 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -270,6 +270,9 @@ module AbstractController end end ruby_eval + when Proc + define_method :_layout_from_proc, &@_layout + self.class_eval %{def _layout(details) _layout_from_proc(self) end} when false self.class_eval %{def _layout(details) end} when true diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index a168b1b4c5..1dec3f2c3e 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -41,10 +41,6 @@ module AbstractController # 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 diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 0e3db86861..03ba4b3f83 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -50,12 +50,19 @@ module ActionController include AbstractController::Helpers included do - extlib_inheritable_accessor(:helpers_path) do - defined?(Rails::Application) ? Rails::Application.paths.app.helpers.to_a : [] - end + extlib_inheritable_accessor(:helpers_path) + self.helpers_path = [] end module ClassMethods + def helpers_dir + self.helpers_path + end + + def helpers_dir=(value) + self.helpers_path = Array(value) + end + def inherited(klass) klass.class_eval { default_helper_module! unless name.blank? } super @@ -79,42 +86,42 @@ module ActionController @helper_proxy ||= ActionView::Base.new.extend(_helpers) end - private - # Overwrite _modules_for_helpers to accept :all as argument, which loads - # all helpers in helpers_dir. - # - # ==== Parameters - # args<Array[String, Symbol, Module, all]>:: A list of helpers - # - # ==== Returns - # Array[Module]:: A normalized list of modules for the list of - # helpers provided. - def _modules_for_helpers(args) - args += all_application_helpers if args.delete(:all) - super(args) - end + private + # Overwrite _modules_for_helpers to accept :all as argument, which loads + # all helpers in helpers_dir. + # + # ==== Parameters + # args<Array[String, Symbol, Module, all]>:: A list of helpers + # + # ==== Returns + # Array[Module]:: A normalized list of modules for the list of + # helpers provided. + def _modules_for_helpers(args) + args += all_application_helpers if args.delete(:all) + super(args) + end - def default_helper_module! - module_name = name.sub(/Controller$/, '') - module_path = module_name.underscore - helper module_path - rescue MissingSourceFile => e - raise e unless e.is_missing? "helpers/#{module_path}_helper" - rescue NameError => e - raise e unless e.missing_name? "#{module_name}Helper" - end + def default_helper_module! + module_name = name.sub(/Controller$/, '') + module_path = module_name.underscore + helper module_path + rescue MissingSourceFile => e + raise e unless e.is_missing? "helpers/#{module_path}_helper" + rescue NameError => e + raise e unless e.missing_name? "#{module_name}Helper" + end - # Extract helper names from files in app/helpers/**/*_helper.rb - def all_application_helpers - helpers = [] - helpers_path.each do |path| - extract = /^#{Regexp.quote(path)}\/?(.*)_helper.rb$/ - helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } + # Extract helper names from files in app/helpers/**/*_helper.rb + def all_application_helpers + helpers = [] + helpers_path.each do |path| + extract = /^#{Regexp.quote(path)}\/?(.*)_helper.rb$/ + helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } + end + helpers.sort! + helpers.uniq! + helpers end - helpers.sort! - helpers.uniq! - helpers - end end end end diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 4c02677729..08599d660e 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -1,3 +1,5 @@ +require 'abstract_controller/collector' + module ActionController #:nodoc: module MimeResponds #:nodoc: extend ActiveSupport::Concern @@ -265,6 +267,7 @@ module ActionController #:nodoc: end class Collector #:nodoc: + include AbstractController::Collector attr_accessor :order def initialize(&block) @@ -289,32 +292,6 @@ module ActionController #:nodoc: 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 diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index 72e2bbd00e..8f03035b2b 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -13,6 +13,10 @@ module ActionController 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 diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 29a0a346ec..9151de4462 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -21,5 +21,9 @@ module ActionController initializer "action_controller.initialize_framework_caches" do ActionController::Base.cache_store ||= RAILS_CACHE end + + initializer "action_controller.set_helpers_path" do |app| + ActionController::Base.helpers_path = app.config.paths.app.helpers.to_a + end end end diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index 0dc1d70e37..18a2922fa7 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -55,7 +55,11 @@ module ActionDispatch when Class klass == middleware else - klass == ActiveSupport::Inflector.constantize(middleware.to_s) + if lazy_compare?(@klass) && lazy_compare?(middleware) + normalize(@klass) == normalize(middleware) + else + klass == ActiveSupport::Inflector.constantize(middleware.to_s) + end end end @@ -72,6 +76,14 @@ module ActionDispatch end private + def lazy_compare?(object) + object.is_a?(String) || object.is_a?(Symbol) + end + + def normalize(object) + object.to_s.strip.sub(/^::/, '') + end + def build_args Array(args).map { |arg| arg.respond_to?(:call) ? arg.call : arg } end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index fcbb70749f..5199984814 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -157,10 +157,11 @@ module ActionDispatch end # Invokes Rack::Mount::Utils.normalize path and ensure that - # (:locale) becomes (/:locale) instead of /(:locale). + # (:locale) becomes (/:locale) instead of /(:locale). Except + # for root cases, where the latter is the correct one. def self.normalize_path(path) path = Rack::Mount::Utils.normalize_path(path) - path.sub!(%r{/\(+/?:}, '(/:') + path.sub!(%r{/(\(+)/?:}, '\1/:') unless path =~ %r{^/\(+:.*\)$} path end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index c4b0455c2a..af13f2cd3e 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -276,9 +276,11 @@ module ActionView #:nodoc: @config = nil @formats = formats @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) } - @_controller = controller @helpers = self.class.helpers || Module.new - @_content_for = Hash.new {|h,k| h[k] = ActionView::SafeBuffer.new } + + @_controller = controller + @_content_for = Hash.new {|h,k| h[k] = ActionView::SafeBuffer.new } + @_virtual_path = nil self.view_paths = view_paths end diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index 35c431d78d..ad18339c60 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -25,11 +25,15 @@ module ActionView end alias :l :localize - private + def scope_key_by_partial(key) if key.to_s.first == "." - template.path_without_format_and_extension.gsub(%r{/_?}, ".") + key.to_s + if @_virtual_path + @_virtual_path.gsub(%r{/_?}, ".") + key.to_s + else + raise "Cannot use t(#{key.inspect}) shortcut because path is not available" + end else key end diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index adaf6544a7..cd6b1930a1 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -87,9 +87,9 @@ module ActionView source = <<-end_src def #{method_name}(local_assigns) - old_output_buffer = output_buffer;#{locals_code};#{code} + _old_virtual_path, @_virtual_path = @_virtual_path, #{@details[:virtual_path].inspect};_old_output_buffer = output_buffer;#{locals_code};#{code} ensure - self.output_buffer = old_output_buffer + @_virtual_path, self.output_buffer = _old_virtual_path, _old_output_buffer end end_src diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index c6a17907ff..340a6afe5e 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -117,15 +117,18 @@ module ActionView # # :api: plugin def path_to_details(path) # [:erb, :format => :html, :locale => :en, :partial => true/false] - if m = path.match(%r'(?:^|/)(_)?[\w-]+((?:\.[\w-]+)*)\.(\w+)$') - partial = m[1] == '_' - details = (m[2]||"").split('.').reject { |e| e.empty? } - handler = Template.handler_class_for_extension(m[3]) + if m = path.match(%r'((^|.*/)(_)?[\w-]+)((?:\.[\w-]+)*)\.(\w+)$') + partial = m[3] == '_' + details = (m[4]||"").split('.').reject { |e| e.empty? } + handler = Template.handler_class_for_extension(m[5]) format = Mime[details.last] && details.pop.to_sym locale = details.last && details.pop.to_sym - return handler, :format => format, :locale => locale, :partial => partial + virtual_path = (m[1].gsub("#{@path}/", "") << details.join(".")) + + return handler, :format => format, :locale => locale, :partial => partial, + :virtual_path => virtual_path end end end diff --git a/actionpack/test/abstract/collector_test.rb b/actionpack/test/abstract/collector_test.rb new file mode 100644 index 0000000000..2ebcebbbb7 --- /dev/null +++ b/actionpack/test/abstract/collector_test.rb @@ -0,0 +1,57 @@ +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 diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb index 5c96d1cfff..bf02e5a864 100644 --- a/actionpack/test/abstract/layouts_test.rb +++ b/actionpack/test/abstract/layouts_test.rb @@ -66,7 +66,15 @@ module AbstractControllerTests class WithChildOfImplied < WithStringImpliedChild end - + + class WithProc < Base + layout proc { |c| "omg" } + + def index + render :_template => ActionView::Template::Text.new("Hello proc!") + end + end + class WithSymbol < Base layout :hello @@ -197,6 +205,12 @@ module AbstractControllerTests controller.process(:index) assert_equal "Hello nil!", controller.response_body end + + test "when layout is specified as a proc, call it and use the layout returned" do + controller = WithProc.new + controller.process(:index) + assert_equal "OMGHI2U Hello proc!", controller.response_body + end test "when layout is specified as a symbol, call the requested method and use the layout returned" do controller = WithSymbol.new diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index fe0961e575..e53e62d1ff 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -31,7 +31,7 @@ module LocalAbcHelper def c() end end -class HelperTest < Test::Unit::TestCase +class HelperTest < ActiveSupport::TestCase class TestController < ActionController::Base attr_accessor :delegate_attr def delegate_method() end @@ -135,6 +135,18 @@ class HelperTest < Test::Unit::TestCase assert methods.include?('foobar') end + # TODO Add this deprecation back before Rails 3.0 final release + # def test_deprecation + # assert_deprecated do + # ActionController::Base.helpers_dir = "some/foo/bar" + # end + # assert_deprecated do + # assert_equal ["some/foo/bar"], ActionController::Base.helpers_dir + # end + # ensure + # ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] + # end + private def expected_helper_methods TestHelper.instance_methods.map {|m| m.to_s } @@ -154,7 +166,7 @@ class HelperTest < Test::Unit::TestCase end -class IsolatedHelpersTest < Test::Unit::TestCase +class IsolatedHelpersTest < ActiveSupport::TestCase class A < ActionController::Base def index render :inline => '<%= shout %>' diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb index f4e18308ae..7cf6365af3 100644 --- a/actionpack/test/dispatch/middleware_stack_test.rb +++ b/actionpack/test/dispatch/middleware_stack_test.rb @@ -87,4 +87,10 @@ class MiddlewareStackTest < ActiveSupport::TestCase end assert_equal [:foo], @stack.last.send(:build_args) end + + test "lazy compares so unloaded constants can be loaded" do + @stack.use "UnknownMiddleware" + @stack.use :"MiddlewareStackTest::BazMiddleware" + assert @stack.include?("::MiddlewareStackTest::BazMiddleware") + end end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 6dccabdb3f..dfe824fd70 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -141,19 +141,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resources :rooms end - scope '(:locale)', :locale => /en|pl/ do - resources :descriptions - end + match '/info' => 'projects#info', :as => 'info' namespace :admin do - scope '(/:locale)', :locale => /en|pl/ do + scope '(:locale)', :locale => /en|pl/ do resources :descriptions end end - match '/info' => 'projects#info', :as => 'info' - - root :to => 'projects#index' + scope '(:locale)', :locale => /en|pl/ do + resources :descriptions + root :to => 'projects#index' + end end end @@ -660,6 +659,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_optional_scoped_root + with_test_routes do + assert_equal '/en', root_path("en") + get '/en' + assert_equal 'projects#index', @response.body + end + end + def test_optional_scoped_path with_test_routes do assert_equal '/en/descriptions', descriptions_path("en") diff --git a/actionpack/test/fixtures/test/translation.erb b/actionpack/test/fixtures/test/translation.erb new file mode 100644 index 0000000000..81a837d1ff --- /dev/null +++ b/actionpack/test/fixtures/test/translation.erb @@ -0,0 +1 @@ +<%= t('.helper') %>
\ No newline at end of file diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb index d67d2c7911..4b73c44f7e 100644 --- a/actionpack/test/template/translation_helper_test.rb +++ b/actionpack/test/template/translation_helper_test.rb @@ -1,9 +1,9 @@ require 'abstract_unit' -class TranslationHelperTest < Test::Unit::TestCase +class TranslationHelperTest < ActiveSupport::TestCase include ActionView::Helpers::TagHelper include ActionView::Helpers::TranslationHelper - + attr_reader :request def setup end @@ -25,8 +25,8 @@ class TranslationHelperTest < Test::Unit::TestCase end def test_scoping_by_partial - expects(:template).returns(stub(:path_without_format_and_extension => "people/index")) - I18n.expects(:translate).with("people.index.foo", :locale => 'en', :raise => true).returns("") - translate ".foo", :locale => 'en' + I18n.expects(:translate).with("test.translation.helper", :raise => true).returns("helper") + @view = ActionView::Base.new(ActionController::Base.view_paths, {}) + assert_equal "helper", @view.render(:file => "test/translation") end end diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index ffff0b7e09..a4fa000964 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* PostgreSQLAdapter: set time_zone to UTC when Base.default_timezone == :utc so that Postgres doesn't incorrectly offset-adjust values inserted into TIMESTAMP WITH TIME ZONE columns. #3777 [Jack Christensen] + * Allow relations to be used as scope. class Item diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 1d52c5ec14..b3ce8c79dd 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -998,7 +998,7 @@ module ActiveRecord configure_connection end - # Configures the encoding, verbosity, and schema search path of the connection. + # Configures the encoding, verbosity, schema search path, and time zone of the connection. # This is called by #connect and should not be called manually. def configure_connection if @config[:encoding] @@ -1010,6 +1010,10 @@ module ActiveRecord end self.client_min_messages = @config[:min_messages] if @config[:min_messages] self.schema_search_path = @config[:schema_search_path] || @config[:schema_order] + + # If using ActiveRecord's time zone support configure the connection to return + # TIMESTAMP WITH ZONE types in UTC. + execute("SET time zone 'UTC'") if ActiveRecord::Base.default_timezone == :utc end # Returns the current ID of a table's sequence. diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 0a52f3a6a2..29225b83c5 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -193,20 +193,20 @@ module ActiveRecord SQL execute(sql, name).map do |row| - row[0] + row['name'] end end def columns(table_name, name = nil) #:nodoc: table_structure(table_name).map do |field| - SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'] == "0") + SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0) end end def indexes(table_name, name = nil) #:nodoc: execute("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row| index = IndexDefinition.new(table_name, row['name']) - index.unique = row['unique'] != '0' + index.unique = row['unique'].to_i != 0 index.columns = execute("PRAGMA index_info('#{index.name}')").map { |col| col['name'] } index end diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 18d7cc0187..5e4ce34934 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -49,9 +49,9 @@ module ActiveRecord # Setup database middleware after initializers have run initializer "active_record.initialize_database_middleware" do |app| middleware = app.config.middleware - if middleware.include?(ActiveRecord::SessionStore) - middleware.insert_before ActiveRecord::SessionStore, ActiveRecord::ConnectionAdapters::ConnectionManagement - middleware.insert_before ActiveRecord::SessionStore, ActiveRecord::QueryCache + if middleware.include?("ActiveRecord::SessionStore") + middleware.insert_before "ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement + middleware.insert_before "ActiveRecord::SessionStore", ActiveRecord::QueryCache else middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement middleware.use ActiveRecord::QueryCache diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 88974dd786..2ef8676f39 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -1,7 +1,7 @@ namespace :db do task :load_config => :rails_env do require 'active_record' - ActiveRecord::Base.configurations = Rails::Configuration.new.database_configuration + ActiveRecord::Base.configurations = Rails::Application.config.database_configuration end namespace :create do diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index c3b2e56387..e6d56a7193 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -288,6 +288,9 @@ class CalculationsTest < ActiveRecord::TestCase # Oracle adapter returns floating point value 636.0 after SUM if current_adapter?(:OracleAdapter) assert_equal 636, Account.sum("2 * credit_limit") + elsif current_adapter?(:SQLite3Adapter) + # Future versions of the SQLite3 adapter will return a number + assert_equal 636, Account.sum("2 * credit_limit").to_i else assert_equal '636', Account.sum("2 * credit_limit") end diff --git a/activerecord/test/cases/datatype_test_postgresql.rb b/activerecord/test/cases/datatype_test_postgresql.rb index 88fb6f7384..9454b6e059 100644 --- a/activerecord/test/cases/datatype_test_postgresql.rb +++ b/activerecord/test/cases/datatype_test_postgresql.rb @@ -21,6 +21,9 @@ end class PostgresqlOid < ActiveRecord::Base end +class PostgresqlTimestampWithZone < ActiveRecord::Base +end + class PostgresqlDataTypeTest < ActiveRecord::TestCase self.use_transactional_fixtures = false @@ -50,6 +53,8 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase @connection.execute("INSERT INTO postgresql_oids (obj_id) VALUES (1234)") @first_oid = PostgresqlOid.find(1) + + @connection.execute("INSERT INTO postgresql_timestamp_with_zones (time) VALUES ('2010-01-01 10:00:00-1')") end def test_data_type_of_array_types @@ -201,4 +206,38 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase assert @first_oid.reload assert_equal @first_oid.obj_id, new_value end + + def test_timestamp_with_zone_values_with_rails_time_zone_support + old_tz = ActiveRecord::Base.time_zone_aware_attributes + old_default_tz = ActiveRecord::Base.default_timezone + + ActiveRecord::Base.time_zone_aware_attributes = true + ActiveRecord::Base.default_timezone = :utc + + @connection.reconnect! + + @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1) + assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time + ensure + ActiveRecord::Base.default_timezone = old_default_tz + ActiveRecord::Base.time_zone_aware_attributes = old_tz + @connection.reconnect! + end + + def test_timestamp_with_zone_values_without_rails_time_zone_support + old_tz = ActiveRecord::Base.time_zone_aware_attributes + old_default_tz = ActiveRecord::Base.default_timezone + + ActiveRecord::Base.time_zone_aware_attributes = false + ActiveRecord::Base.default_timezone = :local + + @connection.reconnect! + + @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1) + assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time + ensure + ActiveRecord::Base.default_timezone = old_default_tz + ActiveRecord::Base.time_zone_aware_attributes = old_tz + @connection.reconnect! + end end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 2af6a56b6a..3710f8e40b 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -49,10 +49,16 @@ class QueryCacheTest < ActiveRecord::TestCase end def test_cache_does_not_wrap_string_results_in_arrays + require 'sqlite3/version' if current_adapter?(:SQLite3Adapter) + Task.cache do # Oracle adapter returns count() as Fixnum or Float if current_adapter?(:OracleAdapter) assert Task.connection.select_value("SELECT count(*) AS count_all FROM tasks").is_a?(Numeric) + elsif current_adapter?(:SQLite3Adapter) && SQLite3::Version::VERSION > '1.2.5' + # Future versions of the sqlite3 adapter will return numeric + assert_instance_of Fixnum, + Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") else assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") end diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb index 3d8911bfe9..065d8cfe98 100644 --- a/activerecord/test/schema/postgresql_specific_schema.rb +++ b/activerecord/test/schema/postgresql_specific_schema.rb @@ -1,7 +1,7 @@ ActiveRecord::Schema.define do %w(postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings - postgresql_oids postgresql_xml_data_type defaults geometrics).each do |table_name| + postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones).each do |table_name| execute "DROP TABLE IF EXISTS #{quote_table_name table_name}" end @@ -100,6 +100,13 @@ _SQL obj_id OID ); _SQL + + execute <<_SQL + CREATE TABLE postgresql_timestamp_with_zones ( + id SERIAL PRIMARY KEY, + time TIMESTAMP WITH TIME ZONE + ); +_SQL begin execute <<_SQL diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb index b583c7533e..4688468a8f 100644 --- a/activesupport/lib/active_support/core_ext/array.rb +++ b/activesupport/lib/active_support/core_ext/array.rb @@ -1,5 +1,6 @@ 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' diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 7fcef38372..814567a5a6 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -13,19 +13,6 @@ class Array 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 diff --git a/activesupport/lib/active_support/core_ext/array/uniq_by.rb b/activesupport/lib/active_support/core_ext/array/uniq_by.rb new file mode 100644 index 0000000000..a09b2302fd --- /dev/null +++ b/activesupport/lib/active_support/core_ext/array/uniq_by.rb @@ -0,0 +1,17 @@ +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 diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb index 24d0a2a481..af771c86ff 100644 --- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb @@ -1,17 +1,16 @@ 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 diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index ecd63293b4..045a6944fa 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -1,10 +1,7 @@ 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 @@ class Hash # 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 diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index bc0f99869c..c8d8b85000 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -7,13 +7,13 @@ module ActiveSupport # Loads support for "whiny nil" (noisy warnings when methods are invoked # on +nil+ values) if Configuration#whiny_nils is true. - initializer :initialize_whiny_nils do |app| + initializer "active_support.initialize_whiny_nils" do |app| require 'active_support/whiny_nil' if app.config.whiny_nils end # Sets the default value for Time.zone # If assigned value cannot be matched to a TimeZone, an exception will be raised. - initializer :initialize_time_zone do |app| + initializer "active_support.initialize_time_zone" do |app| require 'active_support/core_ext/time/zones' zone_default = Time.__send__(:get_zone, app.config.time_zone) @@ -33,9 +33,10 @@ module I18n railtie_name :i18n # Initialize I18n load paths to an array + config.i18n.engines_load_path = [] config.i18n.load_path = [] - initializer :initialize_i18n do + initializer "i18n.initialize" do require 'active_support/i18n' ActionDispatch::Callbacks.to_prepare do @@ -47,7 +48,10 @@ module I18n # the load_path which should be appended to what's already set instead of overwritten. config.after_initialize do |app| app.config.i18n.each do |setting, value| - if setting == :load_path + case setting + when :engines_load_path + app.config.i18n.load_path.unshift(*value) + when :load_path I18n.load_path += value else I18n.send("#{setting}=", value) diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index f5f91ddd80..d4cd5ddbde 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -52,8 +52,6 @@ class ArrayExtToParamTests < Test::Unit::TestCase 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 @@ class ArrayExtToSentenceTests < Test::Unit::TestCase 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 @@ class ArrayExtractOptionsTests < Test::Unit::TestCase 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 diff --git a/railties/lib/generators/erb/mailer/mailer_generator.rb b/railties/lib/generators/erb/mailer/mailer_generator.rb index 4ec2f4c9f4..408c942cef 100644 --- a/railties/lib/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/generators/erb/mailer/mailer_generator.rb @@ -12,7 +12,7 @@ module Erb 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 diff --git a/railties/lib/generators/erb/mailer/templates/view.erb b/railties/lib/generators/erb/mailer/templates/view.erb deleted file mode 100644 index fcce7bd805..0000000000 --- a/railties/lib/generators/erb/mailer/templates/view.erb +++ /dev/null @@ -1,3 +0,0 @@ -<%= class_name %>#<%= @action %> - -Find me in app/views/<%= @path %> diff --git a/railties/lib/generators/erb/mailer/templates/view.text.erb b/railties/lib/generators/erb/mailer/templates/view.text.erb new file mode 100644 index 0000000000..6d597256a6 --- /dev/null +++ b/railties/lib/generators/erb/mailer/templates/view.text.erb @@ -0,0 +1,3 @@ +<%= class_name %>#<%= @action %> + +<%%= @greeting %>, find me in app/views/<%= @path %> diff --git a/railties/lib/generators/rails/mailer/templates/mailer.rb b/railties/lib/generators/rails/mailer/templates/mailer.rb index 90e0b712d6..cdc6e41266 100644 --- a/railties/lib/generators/rails/mailer/templates/mailer.rb +++ b/railties/lib/generators/rails/mailer/templates/mailer.rb @@ -1,14 +1,15 @@ class <%= class_name %> < ActionMailer::Base + self.defaults :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.org") end - <% end -%> -end +end
\ No newline at end of file diff --git a/railties/lib/generators/rails/resource/resource_generator.rb b/railties/lib/generators/rails/resource/resource_generator.rb index 43c7cc85f4..5acb839f39 100644 --- a/railties/lib/generators/rails/resource/resource_generator.rb +++ b/railties/lib/generators/rails/resource/resource_generator.rb @@ -6,8 +6,8 @@ module Rails 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 => [], diff --git a/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb index e544e29892..49af2974cd 100644 --- a/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb +++ b/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb @@ -18,9 +18,9 @@ module Rails 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 diff --git a/railties/lib/generators/test_unit/mailer/templates/fixture b/railties/lib/generators/test_unit/mailer/templates/fixture index fcce7bd805..171648d6fd 100644 --- a/railties/lib/generators/test_unit/mailer/templates/fixture +++ b/railties/lib/generators/test_unit/mailer/templates/fixture @@ -1,3 +1,3 @@ <%= class_name %>#<%= @action %> -Find me in app/views/<%= @path %> +Hi, find me in app/views/<%= @path %> diff --git a/railties/lib/generators/test_unit/mailer/templates/functional_test.rb b/railties/lib/generators/test_unit/mailer/templates/functional_test.rb index 4de94076e9..e1aeb2db90 100644 --- a/railties/lib/generators/test_unit/mailer/templates/functional_test.rb +++ b/railties/lib/generators/test_unit/mailer/templates/functional_test.rb @@ -3,11 +3,13 @@ require 'test_helper' 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.org" + @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 -%> diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 6633c36a21..9e41210119 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -6,8 +6,10 @@ require 'rails/engine' module Rails class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' + autoload :Configurable, 'rails/application/configurable' autoload :Configuration, 'rails/application/configuration' autoload :Finisher, 'rails/application/finisher' + autoload :Metal, 'rails/application/metal' autoload :Railties, 'rails/application/railties' autoload :RoutesReloader, 'rails/application/routes_reloader' @@ -16,10 +18,10 @@ module Rails alias :configure :class_eval def instance - if instance_of?(Rails::Application) - Rails.application.instance + if self == Rails::Application + Rails.application else - @instance ||= new + @@instance ||= new end end @@ -41,10 +43,6 @@ module Rails require environment if environment end - def config - @config ||= Application::Configuration.new(self.class.find_root_with_flag("config.ru", Dir.pwd)) - end - def routes ::ActionController::Routing::Routes end @@ -90,10 +88,10 @@ module Rails end def initializers - initializers = Bootstrap.initializers + initializers = Bootstrap.initializers_for(self) railties.all { |r| initializers += r.initializers } initializers += super - initializers += Finisher.initializers + initializers += Finisher.initializers_for(self) initializers end diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 3c339ffc57..b20e53f2de 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -3,28 +3,28 @@ module Rails module Bootstrap include Initializable - initializer :load_environment_config do |app| - app.require_environment! + initializer :load_environment_config do + require_environment! end - initializer :load_all_active_support do |app| - require "active_support/all" unless app.config.active_support.bare + initializer :load_all_active_support do + require "active_support/all" unless config.active_support.bare end # Preload all frameworks specified by the Configuration#frameworks. # Used by Passenger to ensure everything's loaded before forking and # to avoid autoload race conditions in JRuby. - initializer :preload_frameworks do |app| + initializer :preload_frameworks do require 'active_support/dependencies' - ActiveSupport::Autoload.eager_autoload! if app.config.preload_frameworks + ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks end # Initialize the logger early in the stack in case we need to log some deprecation. - initializer :initialize_logger do |app| - Rails.logger ||= app.config.logger || begin - path = app.config.paths.log.to_a.first + initializer :initialize_logger do + Rails.logger ||= config.logger || begin + path = config.paths.log.to_a.first logger = ActiveSupport::BufferedLogger.new(path) - logger.level = ActiveSupport::BufferedLogger.const_get(app.config.log_level.to_s.upcase) + logger.level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase) logger.auto_flushing = false if Rails.env.production? logger rescue StandardError => e @@ -39,23 +39,23 @@ module Rails end # Initialize cache early in the stack so railties can make use of it. - initializer :initialize_cache do |app| + initializer :initialize_cache do unless defined?(RAILS_CACHE) - silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(app.config.cache_store) } + silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(config.cache_store) } if RAILS_CACHE.respond_to?(:middleware) - app.config.middleware.insert_after(:"Rack::Lock", RAILS_CACHE.middleware) + config.middleware.insert_after(:"Rack::Lock", RAILS_CACHE.middleware) end end end # Initialize rails subscriber on top of notifications. - initializer :initialize_subscriber do |app| + initializer :initialize_subscriber do require 'active_support/notifications' - if app.config.colorize_logging == false - Rails::Subscriber.colorize_logging = false - app.config.generators.colorize_logging = false + if config.colorize_logging == false + Rails::Subscriber.colorize_logging = false + config.generators.colorize_logging = false end ActiveSupport::Notifications.subscribe do |*args| @@ -63,8 +63,8 @@ module Rails end end - initializer :set_clear_dependencies_hook do |app| - unless app.config.cache_classes + initializer :set_clear_dependencies_hook do + unless config.cache_classes ActionDispatch::Callbacks.after do ActiveSupport::Dependencies.clear end @@ -73,8 +73,12 @@ module Rails # Sets the dependency loading mechanism. # TODO: Remove files from the $" and always use require. - initializer :initialize_dependency_mechanism do |app| - ActiveSupport::Dependencies.mechanism = app.config.cache_classes ? :require : :load + initializer :initialize_dependency_mechanism do + ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load + end + + initializer :bootstrap_load_path do + # This is just an initializer used as hook so all load paths are loaded together end end end diff --git a/railties/lib/rails/application/configurable.rb b/railties/lib/rails/application/configurable.rb new file mode 100644 index 0000000000..f598e33965 --- /dev/null +++ b/railties/lib/rails/application/configurable.rb @@ -0,0 +1,19 @@ +module Rails + class Application + module Configurable + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def inherited(base) + raise "You cannot inherit from a Rails::Application child" + end + end + + def config + @config ||= Application::Configuration.new(self.class.find_root_with_flag("config.ru", Dir.pwd)) + end + end + end +end
\ No newline at end of file diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 5cc5b4ae88..d67420938a 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -15,26 +15,26 @@ module Rails end end - initializer :add_builtin_route do |app| + initializer :add_builtin_route do if Rails.env.development? Rails::Application::RoutesReloader.paths << File.join(RAILTIES_PATH, 'builtin', 'routes.rb') end end - initializer :build_middleware_stack do |app| - app.app + initializer :build_middleware_stack do + app end # Fires the user-supplied after_initialize block (config#after_initialize) - initializer :after_initialize do |app| - app.config.after_initialize_blocks.each do |block| - block.call(app) + initializer :after_initialize do + config.after_initialize_blocks.each do |block| + block.call(self) end end # Disable dependency loading during request cycle - initializer :disable_dependency_loading do |app| - if app.config.cache_classes && !app.config.dependency_loading + initializer :disable_dependency_loading do + if config.cache_classes && !config.dependency_loading ActiveSupport::Dependencies.unhook! end end diff --git a/railties/lib/rails/rack/metal.rb b/railties/lib/rails/application/metal.rb index 732936da32..17786dd4ba 100644 --- a/railties/lib/rails/rack/metal.rb +++ b/railties/lib/rails/application/metal.rb @@ -1,12 +1,16 @@ require 'action_dispatch' module Rails - module Rack + class Application class Metal def self.paths @paths ||= [] end + def self.metals + @metals ||= [] + end + def initialize(list=nil) metals = [] list = Array(list || :all).map(&:to_sym) @@ -26,6 +30,7 @@ module Rails end @metals = metals.map { |m| m.to_s.camelize.constantize } + self.class.metals.concat(@metals) end def new(app) diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 3c5c1c1e16..c5cb7b2d09 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -16,7 +16,7 @@ module Rails middleware.use('::ActionDispatch::Cookies') middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options }) middleware.use('::ActionDispatch::Flash', :if => lambda { ActionController::Base.session_store }) - middleware.use(lambda { Rails::Rack::Metal.new(Rails.application.config.metals) }) + middleware.use(lambda { Rails::Application::Metal.new(Rails.application.config.metals) }, :if => lambda { Rails::Application::Metal.metals.any? }) middleware.use('ActionDispatch::ParamsParser') middleware.use('::Rack::MethodOverride') middleware.use('::ActionDispatch::Head') diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index e40052e0f1..ebbee67cf4 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -47,7 +47,7 @@ module Rails end # Add configured load paths to ruby load paths and remove duplicates. - initializer :set_load_path do + initializer :set_load_path, :before => :bootstrap_load_path do config.load_paths.reverse_each do |path| $LOAD_PATH.unshift(path) if File.directory?(path) end @@ -56,13 +56,13 @@ module Rails # Set the paths from which Rails will automatically load source files, # and the load_once paths. - initializer :set_autoload_paths do |app| - ActiveSupport::Dependencies.load_paths.concat(config.load_paths) + initializer :set_autoload_paths, :before => :bootstrap_load_path do |app| + ActiveSupport::Dependencies.load_paths.unshift(*config.load_paths) if reloadable?(app) - ActiveSupport::Dependencies.load_once_paths.concat(config.load_once_paths) + ActiveSupport::Dependencies.load_once_paths.unshift(*config.load_once_paths) else - ActiveSupport::Dependencies.load_once_paths.concat(config.load_paths) + ActiveSupport::Dependencies.load_once_paths.unshift(*config.load_paths) end # Freeze so future modifications will fail rather than do nothing mysteriously @@ -86,18 +86,20 @@ module Rails end end + # I18n load paths are a special case since the ones added + # later have higher priority. initializer :add_locales do - config.i18n.load_path.unshift(*paths.config.locales.to_a) + config.i18n.engines_load_path.concat(paths.config.locales.to_a) end initializer :add_view_paths do views = paths.app.views.to_a - ActionController::Base.view_paths.concat(views) if defined?(ActionController) - ActionMailer::Base.view_paths.concat(views) if defined?(ActionMailer) + ActionController::Base.view_paths.unshift(*views) if defined?(ActionController) + ActionMailer::Base.view_paths.unshift(*views) if defined?(ActionMailer) end initializer :add_metals do - Rails::Rack::Metal.paths.concat(paths.app.metals.to_a) + Rails::Application::Metal.paths.unshift(*paths.app.metals.to_a) end initializer :load_application_initializers do diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 83b8c74966..2281746b00 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -200,6 +200,7 @@ module Rails # Print Rails defaults first. rails = groups.delete("rails") rails.map! { |n| n.sub(/^rails:/, '') } + rails.delete("app") print_list("rails", rails) groups.sort.each { |b, n| print_list(b, n) } diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 3e851bf888..12e918731e 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -6,17 +6,9 @@ module Rails 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 @@ module Rails 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 @@ module Rails 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 diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 7e00a222ed..3a98a8f9c1 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -9,14 +9,7 @@ module Rails 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 @@ module Rails 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 @@ module Rails end # Initialize ORM::Generators::ActiveModel to access instance methods. - # def orm_instance(name=file_name) @orm_instance ||= @orm_class.new(name) end diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index cea4a0fdf7..d91f67823f 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -64,10 +64,7 @@ module Rails end def initializers - @initializers ||= begin - initializers = self.class.initializers_chain - Collection.new(initializers.map { |i| i.bind(self) }) - end + @initializers ||= self.class.initializers_for(self) end module ClassMethods @@ -84,6 +81,10 @@ module Rails initializers end + def initializers_for(binding) + Collection.new(initializers_chain.map { |i| i.bind(binding) }) + end + def initializer(name, opts = {}, &blk) raise ArgumentError, "A block must be passed when defining an initializer" unless blk initializers << Initializer.new(name, nil, opts, &blk) diff --git a/railties/lib/rails/rack.rb b/railties/lib/rails/rack.rb index 4bc0c2c88b..1f20ceae44 100644 --- a/railties/lib/rails/rack.rb +++ b/railties/lib/rails/rack.rb @@ -3,7 +3,6 @@ module Rails autoload :Debugger, "rails/rack/debugger" autoload :Logger, "rails/rack/logger" autoload :LogTailer, "rails/rack/log_tailer" - autoload :Metal, "rails/rack/metal" autoload :Static, "rails/rack/static" end end diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index 91a613092f..de21fb4f10 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -9,27 +9,23 @@ module Rails end def call(env) - @env = env - before_dispatch - result = @app.call(@env) - after_dispatch - result + before_dispatch(env) + @app.call(env) + ensure + after_dispatch(env) end protected - def request - @request ||= ActionDispatch::Request.new(@env) - end - - def before_dispatch + def before_dispatch(env) + request = ActionDispatch::Request.new(env) path = request.request_uri.inspect rescue "unknown" info "\n\nStarted #{request.method.to_s.upcase} #{path} " << "for #{request.remote_ip} at #{Time.now.to_s(:db)}" end - def after_dispatch + def after_dispatch(env) Rails::Subscriber.flush_all! end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 3cf358d75f..c038d0ac70 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -17,7 +17,7 @@ module Rails def inherited(base) unless abstract_railtie?(base) - base.send(:include, self::Configurable) if add_configurable?(base) + base.send(:include, self::Configurable) subclasses << base end end @@ -53,14 +53,6 @@ module Rails def abstract_railtie?(base) ABSTRACT_RAILTIES.include?(base.name) end - - # Just add configurable behavior if a Configurable module is defined - # and the class is a direct child from self. This is required to avoid - # application or plugins getting class configuration method from Railties - # and/or Engines. - def add_configurable?(base) - defined?(self::Configurable) && base.ancestors[1] == self - end end def rake_tasks diff --git a/railties/lib/rails/tasks/middleware.rake b/railties/lib/rails/tasks/middleware.rake index c3aaddb153..251da67c96 100644 --- a/railties/lib/rails/tasks/middleware.rake +++ b/railties/lib/rails/tasks/middleware.rake @@ -3,5 +3,5 @@ task :middleware => :environment do Rails.configuration.middleware.active.each do |middleware| puts "use #{middleware.inspect}" end - puts "run #{Rails::Application.class.name}" + puts "run #{Rails::Application.instance.class.name}.routes" end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 6968e87986..666c47af67 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -1,7 +1,7 @@ require "isolation/abstract_unit" module ApplicationTests - class InitializerTest < Test::Unit::TestCase + class ConfigurationTest < Test::Unit::TestCase include ActiveSupport::Testing::Isolation def new_app @@ -19,6 +19,13 @@ module ApplicationTests FileUtils.rm_rf("#{app_path}/config/environments") end + test "Rails::Application.instance is nil until app is initialized" do + require 'rails' + assert_nil Rails::Application.instance + require "#{app_path}/config/environment" + assert_equal AppTemplate::Application.instance, Rails::Application.instance + end + test "the application root is set correctly" do require "#{app_path}/config/environment" assert_equal Pathname.new(app_path), Rails.application.root @@ -52,21 +59,12 @@ module ApplicationTests end end - test "if there's no config.active_support.bare, all of ActiveSupport is required" do - use_frameworks [] + test "Rails.root should be a Pathname" do + add_to_config <<-RUBY + config.root = "#{app_path}" + RUBY require "#{app_path}/config/environment" - assert_nothing_raised { [1,2,3].rand } - end - - test "config.active_support.bare does not require all of ActiveSupport" do - add_to_config "config.active_support.bare = true" - - use_frameworks [] - - Dir.chdir("#{app_path}/app") do - require "#{app_path}/config/environment" - assert_raises(NoMethodError) { [1,2,3].rand } - end + assert_instance_of Pathname, Rails.root end test "marking the application as threadsafe sets the correct config variables" do @@ -129,7 +127,7 @@ module ApplicationTests value = value.reverse if key =~ /baz/ }] RUBY - + assert_nothing_raised do require "#{app_path}/config/application" end diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index e1e51c318c..1e6e30e9c3 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -92,18 +92,5 @@ module ApplicationTests assert_equal({ :plugin => { :generator => "-g" } }, c.generators.aliases) end end - - test "generators with hashes are deep merged" do - with_config do |c| - c.generators do |g| - g.orm :datamapper, :migration => false - g.plugin :aliases => { :generator => "-g" }, - :generator => true - end - end - - assert Rails::Generators.aliases.size >= 1 - assert Rails::Generators.options.size >= 1 - end end end diff --git a/railties/test/application/initializer_test.rb b/railties/test/application/initializer_test.rb deleted file mode 100644 index 053757979b..0000000000 --- a/railties/test/application/initializer_test.rb +++ /dev/null @@ -1,196 +0,0 @@ -require "isolation/abstract_unit" - -module ApplicationTests - class InitializerTest < Test::Unit::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - boot_rails - FileUtils.rm_rf "#{app_path}/config/environments" - end - - test "initializing an application adds the application paths to the load path" do - add_to_config <<-RUBY - config.root = "#{app_path}" - RUBY - - require "#{app_path}/config/environment" - assert $:.include?("#{app_path}/app/models") - end - - test "eager loading loads parent classes before children" do - app_file "lib/zoo.rb", <<-ZOO - class Zoo ; include ReptileHouse ; end - ZOO - app_file "lib/zoo/reptile_house.rb", <<-ZOO - module Zoo::ReptileHouse ; end - ZOO - - add_to_config <<-RUBY - config.root = "#{app_path}" - config.eager_load_paths << "#{app_path}/lib" - RUBY - - require "#{app_path}/config/environment" - - assert Zoo - end - - test "load environment with global" do - app_file "config/environments/development.rb", <<-RUBY - $initialize_test_set_from_env = 'success' - AppTemplate::Application.configure do - config.cache_classes = true - config.time_zone = "Brasilia" - end - RUBY - - assert_nil $initialize_test_set_from_env - add_to_config <<-RUBY - config.root = "#{app_path}" - config.time_zone = "UTC" - RUBY - - require "#{app_path}/config/environment" - assert_equal "success", $initialize_test_set_from_env - assert AppTemplate::Application.config.cache_classes - assert_equal "Brasilia", AppTemplate::Application.config.time_zone - end - - test "action_controller load paths set only if action controller in use" do - assert_nothing_raised NameError do - add_to_config <<-RUBY - config.root = "#{app_path}" - RUBY - - use_frameworks [] - require "#{app_path}/config/environment" - end - end - - test "after_initialize block works correctly" do - add_to_config <<-RUBY - config.root = "#{app_path}" - config.after_initialize { $test_after_initialize_block1 = "success" } - config.after_initialize { $test_after_initialize_block2 = "congratulations" } - RUBY - require "#{app_path}/config/environment" - - assert_equal "success", $test_after_initialize_block1 - assert_equal "congratulations", $test_after_initialize_block2 - end - - test "after_initialize block works correctly when no block is passed" do - add_to_config <<-RUBY - config.root = "#{app_path}" - config.after_initialize { $test_after_initialize_block1 = "success" } - config.after_initialize # don't pass a block, this is what we're testing! - config.after_initialize { $test_after_initialize_block2 = "congratulations" } - RUBY - require "#{app_path}/config/environment" - - assert_equal "success", $test_after_initialize_block1 - assert_equal "congratulations", $test_after_initialize_block2 - end - - test "after_initialize runs after frameworks have been initialized" do - $activerecord_configurations = nil - add_to_config <<-RUBY - config.after_initialize { $activerecord_configurations = ActiveRecord::Base.configurations } - RUBY - - require "#{app_path}/config/environment" - assert $activerecord_configurations - assert $activerecord_configurations['development'] - end - - # i18n - test "setting another default locale" do - add_to_config <<-RUBY - config.root = "#{app_path}" - config.i18n.default_locale = :de - RUBY - require "#{app_path}/config/environment" - - assert_equal :de, I18n.default_locale - end - - test "no config locales dir present should return empty load path" do - FileUtils.rm_rf "#{app_path}/config/locales" - add_to_config <<-RUBY - config.root = "#{app_path}" - RUBY - require "#{app_path}/config/environment" - - assert_equal [], Rails.application.config.i18n.load_path - end - - test "config locales dir present should be added to load path" do - add_to_config <<-RUBY - config.root = "#{app_path}" - RUBY - - require "#{app_path}/config/environment" - assert_equal ["#{app_path}/config/locales/en.yml"], Rails.application.config.i18n.load_path - end - - test "config defaults should be added with config settings" do - add_to_config <<-RUBY - config.root = "#{app_path}" - config.i18n.load_path << "my/other/locale.yml" - RUBY - require "#{app_path}/config/environment" - - assert_equal [ - "#{app_path}/config/locales/en.yml", "my/other/locale.yml" - ], Rails.application.config.i18n.load_path - end - - # DB middleware - test "database middleware doesn't initialize when session store is not active_record" do - add_to_config <<-RUBY - config.root = "#{app_path}" - config.action_controller.session_store = :cookie_store - RUBY - require "#{app_path}/config/environment" - - assert !Rails.application.config.middleware.include?(ActiveRecord::SessionStore) - end - - test "database middleware initializes when session store is active record" do - add_to_config "config.action_controller.session_store = :active_record_store" - - require "#{app_path}/config/environment" - - expects = [ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActiveRecord::SessionStore] - middleware = Rails.application.config.middleware.map { |m| m.klass } - assert_equal expects, middleware & expects - end - - test "Rails.root should be a Pathname" do - add_to_config <<-RUBY - config.root = "#{app_path}" - RUBY - require "#{app_path}/config/environment" - assert_instance_of Pathname, Rails.root - end - end - - class InitializerCustomFrameworkExtensionsTest < Test::Unit::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - boot_rails - FileUtils.rm_rf "#{app_path}/config/environments" - end - - test "database middleware doesn't initialize when activerecord is not in frameworks" do - use_frameworks [] - require "#{app_path}/config/environment" - - assert_nil defined?(ActiveRecord) - end - end -end diff --git a/railties/test/initializer/boot_test.rb b/railties/test/application/initializers/boot_test.rb index 5ee3c45b21..5ec562f12f 100644 --- a/railties/test/initializer/boot_test.rb +++ b/railties/test/application/initializers/boot_test.rb @@ -1,6 +1,6 @@ require "isolation/abstract_unit" -module BootTests +module ApplicationTests class GemBooting < Test::Unit::TestCase include ActiveSupport::Testing::Isolation diff --git a/railties/test/initializer/check_ruby_version_test.rb b/railties/test/application/initializers/check_ruby_version_test.rb index 311f19a28a..58782b2511 100644 --- a/railties/test/initializer/check_ruby_version_test.rb +++ b/railties/test/application/initializers/check_ruby_version_test.rb @@ -1,6 +1,6 @@ require "isolation/abstract_unit" -module InitializerTests +module ApplicationTests class CheckRubyVersionTest < Test::Unit::TestCase include ActiveSupport::Testing::Isolation diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb new file mode 100644 index 0000000000..ea052320ef --- /dev/null +++ b/railties/test/application/initializers/frameworks_test.rb @@ -0,0 +1,80 @@ +require "isolation/abstract_unit" + +module ApplicationTests + class FrameworlsTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + FileUtils.rm_rf "#{app_path}/config/environments" + end + + # AC & AM + test "set load paths set only if action controller or action mailer are in use" do + assert_nothing_raised NameError do + add_to_config <<-RUBY + config.root = "#{app_path}" + RUBY + + use_frameworks [] + require "#{app_path}/config/environment" + end + end + + test "sets action_controller and action_mailer load paths" do + add_to_config <<-RUBY + config.root = "#{app_path}" + RUBY + + require "#{app_path}/config/environment" + ActionController::Base.view_paths.include?(File.expand_path("app/views", app_path)) + ActionMailer::Base.view_paths.include?(File.expand_path("app/views", app_path)) + end + + # AS + test "if there's no config.active_support.bare, all of ActiveSupport is required" do + use_frameworks [] + require "#{app_path}/config/environment" + assert_nothing_raised { [1,2,3].rand } + end + + test "config.active_support.bare does not require all of ActiveSupport" do + add_to_config "config.active_support.bare = true" + + use_frameworks [] + + Dir.chdir("#{app_path}/app") do + require "#{app_path}/config/environment" + assert_raises(NoMethodError) { [1,2,3].rand } + end + end + + # AR + test "database middleware doesn't initialize when session store is not active_record" do + add_to_config <<-RUBY + config.root = "#{app_path}" + config.action_controller.session_store = :cookie_store + RUBY + require "#{app_path}/config/environment" + + assert !Rails.application.config.middleware.include?(ActiveRecord::SessionStore) + end + + test "database middleware initializes when session store is active record" do + add_to_config "config.action_controller.session_store = :active_record_store" + + require "#{app_path}/config/environment" + + expects = [ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActiveRecord::SessionStore] + middleware = Rails.application.config.middleware.map { |m| m.klass } + assert_equal expects, middleware & expects + end + + test "database middleware doesn't initialize when activerecord is not in frameworks" do + use_frameworks [] + require "#{app_path}/config/environment" + assert_nil defined?(ActiveRecord) + end + end +end diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb new file mode 100644 index 0000000000..99b2d86013 --- /dev/null +++ b/railties/test/application/initializers/i18n_test.rb @@ -0,0 +1,55 @@ +require "isolation/abstract_unit" + +module ApplicationTests + class I18nTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + FileUtils.rm_rf "#{app_path}/config/environments" + end + + # i18n + test "setting another default locale" do + add_to_config <<-RUBY + config.root = "#{app_path}" + config.i18n.default_locale = :de + RUBY + require "#{app_path}/config/environment" + + assert_equal :de, I18n.default_locale + end + + test "no config locales dir present should return empty load path" do + FileUtils.rm_rf "#{app_path}/config/locales" + add_to_config <<-RUBY + config.root = "#{app_path}" + RUBY + require "#{app_path}/config/environment" + + assert_equal [], Rails.application.config.i18n.load_path + end + + test "config locales dir present should be added to load path" do + add_to_config <<-RUBY + config.root = "#{app_path}" + RUBY + + require "#{app_path}/config/environment" + assert_equal ["#{app_path}/config/locales/en.yml"], Rails.application.config.i18n.load_path + end + + test "config defaults should be added with config settings" do + add_to_config <<-RUBY + config.root = "#{app_path}" + config.i18n.load_path << "my/other/locale.yml" + RUBY + require "#{app_path}/config/environment" + + assert_equal [ + "#{app_path}/config/locales/en.yml", "my/other/locale.yml" + ], Rails.application.config.i18n.load_path + end + end +end
\ No newline at end of file diff --git a/railties/test/application/initializers/initializers_test.rb b/railties/test/application/initializers/initializers_test.rb new file mode 100644 index 0000000000..0c3de7ce33 --- /dev/null +++ b/railties/test/application/initializers/initializers_test.rb @@ -0,0 +1,55 @@ +require "isolation/abstract_unit" + +module ApplicationTests + class InitializersTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + FileUtils.rm_rf "#{app_path}/config/environments" + end + + test "load initializers" do + app_file "config/initializers/foo.rb", "$foo = true" + require "#{app_path}/config/environment" + assert $foo + end + + test "after_initialize block works correctly" do + add_to_config <<-RUBY + config.root = "#{app_path}" + config.after_initialize { $test_after_initialize_block1 = "success" } + config.after_initialize { $test_after_initialize_block2 = "congratulations" } + RUBY + require "#{app_path}/config/environment" + + assert_equal "success", $test_after_initialize_block1 + assert_equal "congratulations", $test_after_initialize_block2 + end + + test "after_initialize block works correctly when no block is passed" do + add_to_config <<-RUBY + config.root = "#{app_path}" + config.after_initialize { $test_after_initialize_block1 = "success" } + config.after_initialize # don't pass a block, this is what we're testing! + config.after_initialize { $test_after_initialize_block2 = "congratulations" } + RUBY + require "#{app_path}/config/environment" + + assert_equal "success", $test_after_initialize_block1 + assert_equal "congratulations", $test_after_initialize_block2 + end + + test "after_initialize runs after frameworks have been initialized" do + $activerecord_configurations = nil + add_to_config <<-RUBY + config.after_initialize { $activerecord_configurations = ActiveRecord::Base.configurations } + RUBY + + require "#{app_path}/config/environment" + assert $activerecord_configurations + assert $activerecord_configurations['development'] + end + end +end diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb new file mode 100644 index 0000000000..714b6114a2 --- /dev/null +++ b/railties/test/application/initializers/load_path_test.rb @@ -0,0 +1,62 @@ +require "isolation/abstract_unit" + +module ApplicationTests + class LoadPathTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + FileUtils.rm_rf "#{app_path}/config/environments" + end + + # General + test "initializing an application adds the application paths to the load path" do + add_to_config <<-RUBY + config.root = "#{app_path}" + RUBY + + require "#{app_path}/config/environment" + assert $:.include?("#{app_path}/app/models") + end + + test "eager loading loads parent classes before children" do + app_file "lib/zoo.rb", <<-ZOO + class Zoo ; include ReptileHouse ; end + ZOO + app_file "lib/zoo/reptile_house.rb", <<-ZOO + module Zoo::ReptileHouse ; end + ZOO + + add_to_config <<-RUBY + config.root = "#{app_path}" + config.eager_load_paths << "#{app_path}/lib" + RUBY + + require "#{app_path}/config/environment" + + assert Zoo + end + + test "load environment with global" do + app_file "config/environments/development.rb", <<-RUBY + $initialize_test_set_from_env = 'success' + AppTemplate::Application.configure do + config.cache_classes = true + config.time_zone = "Brasilia" + end + RUBY + + assert_nil $initialize_test_set_from_env + add_to_config <<-RUBY + config.root = "#{app_path}" + config.time_zone = "UTC" + RUBY + + require "#{app_path}/config/environment" + assert_equal "success", $initialize_test_set_from_env + assert AppTemplate::Application.config.cache_classes + assert_equal "Brasilia", AppTemplate::Application.config.time_zone + end + end +end diff --git a/railties/test/application/notifications_test.rb b/railties/test/application/initializers/notifications_test.rb index 061bb34c19..061bb34c19 100644 --- a/railties/test/application/notifications_test.rb +++ b/railties/test/application/initializers/notifications_test.rb diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 31696598ce..0b92cdba54 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -23,7 +23,6 @@ module ApplicationTests "ActionDispatch::Cookies", "ActionDispatch::Session::CookieStore", "ActionDispatch::Flash", - "ActionDispatch::Cascade", "ActionDispatch::ParamsParser", "Rack::MethodOverride", "ActionDispatch::Head", @@ -70,6 +69,12 @@ module ApplicationTests assert_equal "Rack::Config", middleware.first end + test "shows cascade if any metal exists" do + app_file "app/metal/foo.rb", "class Foo; end" + boot! + assert middleware.include?("ActionDispatch::Cascade") + end + private def boot! require "#{app_path}/config/environment" diff --git a/railties/test/initializer/path_test.rb b/railties/test/application/paths_test.rb index 2048dc57bb..ac0aa27c64 100644 --- a/railties/test/initializer/path_test.rb +++ b/railties/test/application/paths_test.rb @@ -1,7 +1,7 @@ require "isolation/abstract_unit" -module InitializerTests - class PathTest < Test::Unit::TestCase +module ApplicationTests + class PathsTest < Test::Unit::TestCase include ActiveSupport::Testing::Isolation def setup diff --git a/railties/test/application/load_test.rb b/railties/test/application/rackup_test.rb index 1c5811b07a..f909c1b282 100644 --- a/railties/test/application/load_test.rb +++ b/railties/test/application/rackup_test.rb @@ -1,7 +1,7 @@ require "isolation/abstract_unit" module ApplicationTests - class LoadTest < Test::Unit::TestCase + class RackupTest < Test::Unit::TestCase include ActiveSupport::Testing::Isolation def rackup diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 50cb9e3acc..b93e349a46 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -14,7 +14,6 @@ module ApplicationTests def app @app ||= begin require "#{app_path}/config/environment" - Rails.application end end @@ -26,7 +25,7 @@ module ApplicationTests test "simple controller" do controller :foo, <<-RUBY - class FooController < ActionController::Base + class FooController < ApplicationController def index render :text => "foo" end @@ -43,9 +42,36 @@ module ApplicationTests assert_equal 'foo', last_response.body end + test "simple controller with helper" do + controller :foo, <<-RUBY + class FooController < ApplicationController + def index + render :inline => "<%= foo_or_bar? %>" + end + end + RUBY + + app_file 'app/helpers/bar_helper.rb', <<-RUBY + module BarHelper + def foo_or_bar? + "bar" + end + end + RUBY + + app_file 'config/routes.rb', <<-RUBY + AppTemplate::Application.routes.draw do |map| + match ':controller(/:action)' + end + RUBY + + get '/foo' + assert_equal 'bar', last_response.body + end + test "multiple controllers" do controller :foo, <<-RUBY - class FooController < ActionController::Base + class FooController < ApplicationController def index render :text => "foo" end @@ -75,7 +101,7 @@ module ApplicationTests test "nested controller" do controller 'foo', <<-RUBY - class FooController < ActionController::Base + class FooController < ApplicationController def index render :text => "foo" end @@ -84,7 +110,7 @@ module ApplicationTests controller 'admin/foo', <<-RUBY module Admin - class FooController < ActionController::Base + class FooController < ApplicationController def index render :text => "admin::foo" end @@ -105,47 +131,9 @@ module ApplicationTests assert_equal 'admin::foo', last_response.body end - test "merges with plugin routes" do - controller 'foo', <<-RUBY - class FooController < ActionController::Base - def index - render :text => "foo" - end - end - RUBY - - app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do |map| - match 'foo', :to => 'foo#index' - end - RUBY - - plugin 'bar', 'require File.dirname(__FILE__) + "/app/controllers/bar"' do |plugin| - plugin.write 'app/controllers/bar.rb', <<-RUBY - class BarController < ActionController::Base - def index - render :text => "bar" - end - end - RUBY - - plugin.write 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do |map| - match 'bar', :to => 'bar#index' - end - RUBY - end - - get '/foo' - assert_equal 'foo', last_response.body - - get '/bar' - assert_equal 'bar', last_response.body - end - test "reloads routes when configuration is changed" do controller :foo, <<-RUBY - class FooController < ActionController::Base + class FooController < ApplicationController def bar render :text => "bar" end @@ -191,7 +179,7 @@ module ApplicationTests RUBY controller 'yazilar', <<-RUBY - class YazilarController < ActionController::Base + class YazilarController < ApplicationController def index render :text => 'yazilar#index' end diff --git a/railties/test/fixtures/eager/zoo.rb b/railties/test/fixtures/eager/zoo.rb deleted file mode 100644 index 8b10ef984b..0000000000 --- a/railties/test/fixtures/eager/zoo.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Zoo - include ReptileHouse -end
\ No newline at end of file diff --git a/railties/test/fixtures/eager/zoo/reptile_house.rb b/railties/test/fixtures/eager/zoo/reptile_house.rb deleted file mode 100644 index 82bbafce79..0000000000 --- a/railties/test/fixtures/eager/zoo/reptile_house.rb +++ /dev/null @@ -1,2 +0,0 @@ -module Zoo::ReptileHouse -end
\ No newline at end of file diff --git a/railties/test/fixtures/environment_with_constant.rb b/railties/test/fixtures/environment_with_constant.rb deleted file mode 100644 index 23e1f7afd9..0000000000 --- a/railties/test/fixtures/environment_with_constant.rb +++ /dev/null @@ -1 +0,0 @@ -$initialize_test_set_from_env = 'success' diff --git a/railties/test/fixtures/plugins/alternate/a/generators/a_generator/a_generator.rb b/railties/test/fixtures/plugins/alternate/a/generators/a_generator/a_generator.rb deleted file mode 100644 index b33f2dad18..0000000000 --- a/railties/test/fixtures/plugins/alternate/a/generators/a_generator/a_generator.rb +++ /dev/null @@ -1,4 +0,0 @@ -class AGenerator < Rails::Generator::Base - def manifest - end -end diff --git a/railties/test/fixtures/plugins/alternate/a/lib/.gitignore b/railties/test/fixtures/plugins/alternate/a/lib/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/test/fixtures/plugins/alternate/a/lib/.gitignore +++ /dev/null diff --git a/railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.gitignore b/railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.gitignore +++ /dev/null diff --git a/railties/test/fixtures/plugins/default/empty/.gitignore b/railties/test/fixtures/plugins/default/empty/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/test/fixtures/plugins/default/empty/.gitignore +++ /dev/null diff --git a/railties/test/fixtures/plugins/default/gemlike/init.rb b/railties/test/fixtures/plugins/default/gemlike/init.rb deleted file mode 100644 index 6a771b5b68..0000000000 --- a/railties/test/fixtures/plugins/default/gemlike/init.rb +++ /dev/null @@ -1 +0,0 @@ -raise 'This init.rb should not be evaluated because rails/init.rb exists' diff --git a/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb b/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb deleted file mode 100644 index 2088103e45..0000000000 --- a/railties/test/fixtures/plugins/default/gemlike/lib/gemlike.rb +++ /dev/null @@ -1,2 +0,0 @@ -module Gemlike -end
\ No newline at end of file diff --git a/railties/test/fixtures/plugins/default/gemlike/rails/init.rb b/railties/test/fixtures/plugins/default/gemlike/rails/init.rb deleted file mode 100644 index 171a293eb3..0000000000 --- a/railties/test/fixtures/plugins/default/gemlike/rails/init.rb +++ /dev/null @@ -1,7 +0,0 @@ -# I have access to my directory and the Rails config. -raise 'directory expected but undefined in init.rb' unless defined? directory -raise 'config expected but undefined in init.rb' unless defined? config - -# My lib/ dir must be in the load path. -require 'gemlike' -raise 'missing mixin from my lib/ dir' unless defined? Gemlike diff --git a/railties/test/fixtures/plugins/default/plugin_with_no_lib_dir/init.rb b/railties/test/fixtures/plugins/default/plugin_with_no_lib_dir/init.rb deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/test/fixtures/plugins/default/plugin_with_no_lib_dir/init.rb +++ /dev/null diff --git a/railties/test/fixtures/plugins/default/stubby/about.yml b/railties/test/fixtures/plugins/default/stubby/about.yml deleted file mode 100644 index d85a7cc0e3..0000000000 --- a/railties/test/fixtures/plugins/default/stubby/about.yml +++ /dev/null @@ -1,2 +0,0 @@ -author: Plugin Author -version: 1.0.0
\ No newline at end of file diff --git a/railties/test/fixtures/plugins/default/stubby/init.rb b/railties/test/fixtures/plugins/default/stubby/init.rb deleted file mode 100644 index 81beeb0d32..0000000000 --- a/railties/test/fixtures/plugins/default/stubby/init.rb +++ /dev/null @@ -1,7 +0,0 @@ -# I have access to my directory and the Rails config. -raise 'directory expected but undefined in init.rb' unless defined? directory -raise 'config expected but undefined in init.rb' unless defined? config - -# My lib/ dir must be in the load path. -require 'stubby_mixin' -raise 'missing mixin from my lib/ dir' unless defined? StubbyMixin diff --git a/railties/test/fixtures/plugins/default/stubby/lib/stubby_mixin.rb b/railties/test/fixtures/plugins/default/stubby/lib/stubby_mixin.rb deleted file mode 100644 index 2d569e5002..0000000000 --- a/railties/test/fixtures/plugins/default/stubby/lib/stubby_mixin.rb +++ /dev/null @@ -1,2 +0,0 @@ -module StubbyMixin -end diff --git a/railties/test/fixtures/plugins/engines/engine/app/controllers/engine_controller.rb b/railties/test/fixtures/plugins/engines/engine/app/controllers/engine_controller.rb deleted file mode 100644 index 323ee1c4dc..0000000000 --- a/railties/test/fixtures/plugins/engines/engine/app/controllers/engine_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class EngineController -end
\ No newline at end of file diff --git a/railties/test/fixtures/plugins/engines/engine/app/metal/engine_metal.rb b/railties/test/fixtures/plugins/engines/engine/app/metal/engine_metal.rb deleted file mode 100644 index d67a127ca7..0000000000 --- a/railties/test/fixtures/plugins/engines/engine/app/metal/engine_metal.rb +++ /dev/null @@ -1,10 +0,0 @@ -class EngineMetal - def self.call(env) - if env["PATH_INFO"] =~ /^\/metal/ - [200, {"Content-Type" => "text/html"}, ["Engine metal"]] - else - [404, {"Content-Type" => "text/html"}, ["Not Found"]] - end - end -end - diff --git a/railties/test/fixtures/plugins/engines/engine/app/models/engine_model.rb b/railties/test/fixtures/plugins/engines/engine/app/models/engine_model.rb deleted file mode 100644 index e265712185..0000000000 --- a/railties/test/fixtures/plugins/engines/engine/app/models/engine_model.rb +++ /dev/null @@ -1,2 +0,0 @@ -class EngineModel -end
\ No newline at end of file diff --git a/railties/test/fixtures/plugins/engines/engine/config/locales/en.yml b/railties/test/fixtures/plugins/engines/engine/config/locales/en.yml deleted file mode 100644 index 641a7e035c..0000000000 --- a/railties/test/fixtures/plugins/engines/engine/config/locales/en.yml +++ /dev/null @@ -1,2 +0,0 @@ -en: - hello: "Hello from Engine" diff --git a/railties/test/fixtures/plugins/engines/engine/config/routes.rb b/railties/test/fixtures/plugins/engines/engine/config/routes.rb deleted file mode 100644 index da44595693..0000000000 --- a/railties/test/fixtures/plugins/engines/engine/config/routes.rb +++ /dev/null @@ -1,3 +0,0 @@ -ActionController::Routing::Routes.draw do |map| - match '/engine', :to => "engine" -end diff --git a/railties/test/fixtures/plugins/engines/engine/init.rb b/railties/test/fixtures/plugins/engines/engine/init.rb deleted file mode 100644 index 64e9ae6c30..0000000000 --- a/railties/test/fixtures/plugins/engines/engine/init.rb +++ /dev/null @@ -1,3 +0,0 @@ -# My app/models dir must be in the load path. -require 'engine_model' -raise LoadError, 'missing model from my app/models dir' unless defined?(EngineModel) diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb index dfc3130f77..0b7f5c6817 100644 --- a/railties/test/generators/mailer_generator_test.rb +++ b/railties/test/generators/mailer_generator_test.rb @@ -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 /self\.defaults :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 @@ class MailerGeneratorTest < Rails::Generators::TestCase 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 @@ class MailerGeneratorTest < Rails::Generators::TestCase 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.org"\)/, foo + assert_match /@greeting = "Hi"/, foo + end + + assert_instance_method :bar, mailer do |bar| + assert_match /mail\(:to => "to@example.org"\)/, bar + assert_match /@greeting = "Hi"/, bar + end + end + end end diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index 99eb431a49..f327fb1282 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -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 diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index f37b684f73..33cc27bd84 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -99,6 +99,7 @@ class GeneratorsTest < Rails::Generators::TestCase assert_match /Rails:/, output assert_match /^ model$/, output assert_match /^ scaffold_controller$/, output + assert_no_match /^ app$/, output end def test_rails_generators_with_others_information diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index dc5fddb19d..940585836c 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -100,6 +100,8 @@ module TestHelpers end class Bukkit + attr_reader :path + def initialize(path) @path = path end @@ -118,10 +120,29 @@ module TestHelpers def plugin(name, string = "") dir = "#{app_path}/vendor/plugins/#{name}" FileUtils.mkdir_p(dir) + File.open("#{dir}/init.rb", 'w') do |f| f.puts "::#{name.upcase} = 'loaded'" f.puts string end + + Bukkit.new(dir).tap do |bukkit| + yield bukkit if block_given? + end + end + + def engine(name) + dir = "#{app_path}/random/#{name}" + FileUtils.mkdir_p(dir) + + app = File.readlines("#{app_path}/config/application.rb") + app.insert(2, "$:.unshift(\"#{dir}/lib\")") + app.insert(3, "require #{name.inspect}") + + File.open("#{app_path}/config/application.rb", 'r+') do |f| + f.puts app + end + Bukkit.new(dir).tap do |bukkit| yield bukkit if block_given? end diff --git a/railties/test/mocks/routes.rb b/railties/test/mocks/routes.rb deleted file mode 100644 index ea12863683..0000000000 --- a/railties/test/mocks/routes.rb +++ /dev/null @@ -1,6 +0,0 @@ -module ActionController - module Routing - class Routes - end - end -end diff --git a/railties/test/plugins/vendored_test.rb b/railties/test/plugins/vendored_test.rb deleted file mode 100644 index 41073d33a2..0000000000 --- a/railties/test/plugins/vendored_test.rb +++ /dev/null @@ -1,388 +0,0 @@ -require "isolation/abstract_unit" - -module PluginsTest - class VendoredTest < Test::Unit::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - - @plugin = plugin "bukkits", "::LEVEL = config.log_level" do |plugin| - plugin.write "lib/bukkits.rb", "class Bukkits; end" - end - end - - def boot_rails - super - require "#{app_path}/config/environment" - end - - def app - @app ||= Rails.application - end - - test "it loads the plugin's init.rb file" do - boot_rails - assert_equal "loaded", BUKKITS - end - - test "the init.rb file has access to the config object" do - boot_rails - assert_equal :debug, LEVEL - end - - test "the plugin puts its lib directory on the load path" do - boot_rails - require "bukkits" - assert_equal "Bukkits", Bukkits.name - end - - test "plugin init is ran before application initializers" do - plugin "foo", "$foo = true" do |plugin| - plugin.write "lib/foo.rb", "module Foo; end" - end - - app_file 'config/initializers/foo.rb', <<-RUBY - raise "no $foo" unless $foo - raise "no Foo" unless Foo - RUBY - - boot_rails - end - - test "plugin paths get added to the AS::Dependency list" do - boot_rails - assert_equal "Bukkits", Bukkits.name - end - - test "plugin constants do not get reloaded by default" do - boot_rails - assert_equal "Bukkits", Bukkits.name - ActiveSupport::Dependencies.clear - @plugin.delete("lib/bukkits.rb") - assert_nothing_raised { Bukkits } - end - - test "plugin constants get reloaded if config.reload_plugins is set" do - add_to_config <<-RUBY - config.reload_plugins = true - RUBY - - boot_rails - - assert_equal "Bukkits", Bukkits.name - ActiveSupport::Dependencies.clear - @plugin.delete("lib/bukkits.rb") - assert_raises(NameError) { Bukkits } - end - - test "plugin should work without init.rb" do - @plugin.delete("init.rb") - - boot_rails - - require "bukkits" - assert_nothing_raised { Bukkits } - end - - test "the plugin puts its models directory on the load path" do - @plugin.write "app/models/my_bukkit.rb", "class MyBukkit ; end" - - boot_rails - - assert_nothing_raised { MyBukkit } - end - - test "the plugin puts is controllers directory on the load path" do - @plugin.write "app/controllers/bukkit_controller.rb", "class BukkitController ; end" - - boot_rails - - assert_nothing_raised { BukkitController } - end - - test "the plugin adds its view to the load path" do - @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY - class BukkitController < ActionController::Base - def index - end - end - RUBY - - @plugin.write "app/views/bukkit/index.html.erb", "Hello bukkits" - - boot_rails - - require "action_controller" - require "rack/mock" - response = BukkitController.action(:index).call(Rack::MockRequest.env_for("/")) - assert_equal "Hello bukkits\n", response[2].body - end - - test "the plugin adds helpers to the controller's views" do - @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY - class BukkitController < ActionController::Base - def index - end - end - RUBY - - @plugin.write "app/helpers/bukkit_helper.rb", <<-RUBY - module BukkitHelper - def bukkits - "bukkits" - end - end - RUBY - - @plugin.write "app/views/bukkit/index.html.erb", "Hello <%= bukkits %>" - - boot_rails - - require "rack/mock" - response = BukkitController.action(:index).call(Rack::MockRequest.env_for("/")) - assert_equal "Hello bukkits\n", response[2].body - end - - test "routes.rb are added to the router" do - @plugin.write "config/routes.rb", <<-RUBY - class Sprokkit - def self.call(env) - [200, {'Content-Type' => 'text/html'}, ["I am a Sprokkit"]] - end - end - - ActionController::Routing::Routes.draw do - match "/sprokkit", :to => Sprokkit - end - RUBY - - boot_rails - require "rack/mock" - response = Rails.application.call(Rack::MockRequest.env_for("/sprokkit")) - assert_equal "I am a Sprokkit", response[2].join - end - - test "tasks are loaded by default" do - $executed = false - @plugin.write "lib/tasks/foo.rake", <<-RUBY - task :foo do - $executed = true - end - RUBY - - boot_rails - require 'rake' - require 'rake/rdoctask' - require 'rake/testtask' - Rails.application.load_tasks - Rake::Task[:foo].invoke - assert $executed - end - - test "deprecated tasks are also loaded" do - $executed = false - @plugin.write "tasks/foo.rake", <<-RUBY - task :foo do - $executed = true - end - RUBY - - boot_rails - require 'rake' - require 'rake/rdoctask' - require 'rake/testtask' - Rails.application.load_tasks - Rake::Task[:foo].invoke - assert $executed - end - - test "i18n files are added with lower priority than application ones" do - add_to_config <<-RUBY - config.i18n.load_path << "#{app_path}/app/locales/en.yml" - RUBY - - app_file 'app/locales/en.yml', <<-YAML -en: - bar: "1" -YAML - - app_file 'config/locales/en.yml', <<-YAML -en: - foo: "2" - bar: "2" -YAML - - @plugin.write 'config/locales/en.yml', <<-YAML -en: - foo: "3" -YAML - - boot_rails - - assert_equal %W( - #{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/locale/en.yml - #{RAILS_FRAMEWORK_ROOT}/activemodel/lib/active_model/locale/en.yml - #{RAILS_FRAMEWORK_ROOT}/activerecord/lib/active_record/locale/en.yml - #{RAILS_FRAMEWORK_ROOT}/actionpack/lib/action_view/locale/en.yml - #{app_path}/vendor/plugins/bukkits/config/locales/en.yml - #{app_path}/config/locales/en.yml - #{app_path}/app/locales/en.yml - ).map { |path| File.expand_path(path) }, I18n.load_path.map { |path| File.expand_path(path) } - - assert_equal "2", I18n.t(:foo) - assert_equal "1", I18n.t(:bar) - end - - test "plugin metals are added to the middleware stack" do - @plugin.write 'app/metal/foo_metal.rb', <<-RUBY - class FooMetal - def self.call(env) - [200, { "Content-Type" => "text/html"}, ["FooMetal"]] - end - end - RUBY - - boot_rails - require 'rack/test' - extend Rack::Test::Methods - - get "/" - assert_equal 200, last_response.status - assert_equal "FooMetal", last_response.body - end - - test "use plugin middleware in application config" do - plugin "foo" do |plugin| - plugin.write "lib/foo.rb", <<-RUBY - class Foo - def initialize(app) - @app = app - end - - def call(env) - @app.call(env) - end - end - RUBY - end - - add_to_config "config.middleware.use :Foo" - - boot_rails - end - - test "namespaced controllers with namespaced routes" do - @plugin.write "config/routes.rb", <<-RUBY - ActionController::Routing::Routes.draw do - namespace :admin do - match "index", :to => "admin/foo#index" - end - end - RUBY - - @plugin.write "app/controllers/admin/foo_controller.rb", <<-RUBY - class Admin::FooController < ApplicationController - def index - render :text => "Rendered from namespace" - end - end - RUBY - - boot_rails - - require 'rack/test' - extend Rack::Test::Methods - - get "/admin/index" - assert_equal 200, last_response.status - assert_equal "Rendered from namespace", last_response.body - end - - test "plugin with initializers" do - $plugin_initializer = false - @plugin.write "config/initializers/foo.rb", <<-RUBY - $plugin_initializer = true - RUBY - - boot_rails - assert $plugin_initializer - end - - test "plugin cannot declare an engine for it" do - @plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits - class Engine < Rails::Engine - end - end - RUBY - - @plugin.write "init.rb", <<-RUBY - require "bukkits" - RUBY - - rescued = false - - begin - boot_rails - rescue Exception => e - rescued = true - assert_equal '"bukkits" is a Railtie/Engine and cannot be installed as plugin', e.message - end - - assert rescued, "Expected boot rails to fail" - end - end - - class VendoredOrderingTest < Test::Unit::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - $arr = [] - plugin "a_plugin", "$arr << :a" - plugin "b_plugin", "$arr << :b" - plugin "c_plugin", "$arr << :c" - end - - def boot_rails - super - require "#{app_path}/config/environment" - end - - test "plugins are loaded alphabetically by default" do - boot_rails - assert_equal [:a, :b, :c], $arr - end - - test "if specified, only those plugins are loaded" do - add_to_config "config.plugins = [:b_plugin]" - boot_rails - assert_equal [:b], $arr - end - - test "the plugins are initialized in the order they are specified" do - add_to_config "config.plugins = [:b_plugin, :a_plugin]" - boot_rails - assert_equal [:b, :a], $arr - end - - test "if :all is specified, the remaining plugins are loaded in alphabetical order" do - add_to_config "config.plugins = [:c_plugin, :all]" - boot_rails - assert_equal [:c, :a, :b], $arr - end - - test "if :all is at the beginning, it represents the plugins not otherwise specified" do - add_to_config "config.plugins = [:all, :b_plugin]" - boot_rails - assert_equal [:a, :c, :b], $arr - end - - test "plugin order array is strings" do - add_to_config "config.plugins = %w( c_plugin all )" - boot_rails - assert_equal [:c, :a, :b], $arr - end - end -end diff --git a/railties/test/plugins/configuration_test.rb b/railties/test/railties/configuration_test.rb index c59040c712..c5ff6dad9c 100644 --- a/railties/test/plugins/configuration_test.rb +++ b/railties/test/railties/configuration_test.rb @@ -1,6 +1,6 @@ require "isolation/abstract_unit" -module PluginsTest +module RailtiesTest class ConfigurationTest < Test::Unit::TestCase def setup build_app diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb new file mode 100644 index 0000000000..374f5ea93c --- /dev/null +++ b/railties/test/railties/engine_test.rb @@ -0,0 +1,23 @@ +require "isolation/abstract_unit" +require "railties/shared_tests" + +module RailtiesTest + class EngineTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + include SharedTests + + def setup + build_app + + @plugin = engine "bukkits" do |plugin| + plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + end + end + RUBY + plugin.write "lib/another.rb", "class Another; end" + end + end + end +end diff --git a/railties/test/plugins/framework_extension_test.rb b/railties/test/railties/framework_extension_test.rb index d57fd4e635..48e513cf01 100644 --- a/railties/test/plugins/framework_extension_test.rb +++ b/railties/test/railties/framework_extension_test.rb @@ -1,6 +1,6 @@ require "isolation/abstract_unit" -module PluginsTest +module RailtiesTest class FrameworkExtensionTest < Test::Unit::TestCase include ActiveSupport::Testing::Isolation @@ -46,6 +46,20 @@ module PluginsTest AppTemplate::Application.load_generators assert $ran_block end + + test "railtie initializer" do + $ran_block = false + + class MyTie < Rails::Railtie + initializer :something_nice do + $ran_block = true + end + end + + assert !$ran_block + require "#{app_path}/config/environment" + assert $ran_block + end end class ActiveRecordExtensionTest < Test::Unit::TestCase diff --git a/railties/test/railties/plugin_ordering_test.rb b/railties/test/railties/plugin_ordering_test.rb new file mode 100644 index 0000000000..f6ca493fdf --- /dev/null +++ b/railties/test/railties/plugin_ordering_test.rb @@ -0,0 +1,72 @@ +require "isolation/abstract_unit" + +module RailtiesTest + class PluginOrderingTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + $arr = [] + plugin "a_plugin", "$arr << :a" + plugin "b_plugin", "$arr << :b" + plugin "c_plugin", "$arr << :c" + end + + def boot_rails + super + require "#{app_path}/config/environment" + end + + test "plugins are loaded alphabetically by default" do + boot_rails + assert_equal [:a, :b, :c], $arr + end + + test "if specified, only those plugins are loaded" do + add_to_config "config.plugins = [:b_plugin]" + boot_rails + assert_equal [:b], $arr + end + + test "the plugins are initialized in the order they are specified" do + add_to_config "config.plugins = [:b_plugin, :a_plugin]" + boot_rails + assert_equal [:b, :a], $arr + end + + test "if :all is specified, the remaining plugins are loaded in alphabetical order" do + add_to_config "config.plugins = [:c_plugin, :all]" + boot_rails + assert_equal [:c, :a, :b], $arr + end + + test "if :all is at the beginning, it represents the plugins not otherwise specified" do + add_to_config "config.plugins = [:all, :b_plugin]" + boot_rails + assert_equal [:a, :c, :b], $arr + end + + test "plugin order array is strings" do + add_to_config "config.plugins = %w( c_plugin all )" + boot_rails + assert_equal [:c, :a, :b], $arr + end + + test "can require lib file from a different plugin" do + plugin "foo", "require 'bar'" do |plugin| + plugin.write "lib/foo.rb", "$foo = true" + end + + plugin "bar", "require 'foo'" do |plugin| + plugin.write "lib/bar.rb", "$bar = true" + end + + add_to_config "config.plugins = [:foo, :bar]" + + boot_rails + + assert $foo + assert $bar + end + end +end
\ No newline at end of file diff --git a/railties/test/railties/plugin_test.rb b/railties/test/railties/plugin_test.rb new file mode 100644 index 0000000000..0adc31e3ed --- /dev/null +++ b/railties/test/railties/plugin_test.rb @@ -0,0 +1,99 @@ +require "isolation/abstract_unit" +require "railties/shared_tests" + +module RailtiesTest + class PluginTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + include SharedTests + + def setup + build_app + + @plugin = plugin "bukkits", "::LEVEL = config.log_level" do |plugin| + plugin.write "lib/bukkits.rb", "class Bukkits; end" + plugin.write "lib/another.rb", "class Another; end" + end + end + + test "plugin can load the file with the same name in lib" do + boot_rails + require "bukkits" + assert_equal "Bukkits", Bukkits.name + end + + test "it loads the plugin's init.rb file" do + boot_rails + assert_equal "loaded", BUKKITS + end + + test "the init.rb file has access to the config object" do + boot_rails + assert_equal :debug, LEVEL + end + + test "plugin_init_is_ran_before_application_ones" do + plugin "foo", "$foo = true" do |plugin| + plugin.write "lib/foo.rb", "module Foo; end" + end + + app_file 'config/initializers/foo.rb', <<-RUBY + raise "no $foo" unless $foo + raise "no Foo" unless Foo + RUBY + + boot_rails + assert $foo + end + + test "plugin should work without init.rb" do + @plugin.delete("init.rb") + + boot_rails + + require "bukkits" + assert_nothing_raised { Bukkits } + end + + test "plugin cannot declare an engine for it" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < Rails::Engine + end + end + RUBY + + @plugin.write "init.rb", <<-RUBY + require "bukkits" + RUBY + + rescued = false + + begin + boot_rails + rescue Exception => e + rescued = true + assert_equal '"bukkits" is a Railtie/Engine and cannot be installed as plugin', e.message + end + + assert rescued, "Expected boot rails to fail" + end + + test "deprecated tasks are also loaded" do + $executed = false + @plugin.write "tasks/foo.rake", <<-RUBY + task :foo do + $executed = true + end + RUBY + + boot_rails + require 'rake' + require 'rake/rdoctask' + require 'rake/testtask' + Rails.application.load_tasks + Rake::Task[:foo].invoke + assert $executed + end + + end +end diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb new file mode 100644 index 0000000000..fc4a19e7e7 --- /dev/null +++ b/railties/test/railties/shared_tests.rb @@ -0,0 +1,306 @@ +module RailtiesTest + # Holds tests shared between plugin and engines + module SharedTests + def boot_rails + super + require "#{app_path}/config/environment" + end + + def app + @app ||= Rails.application + end + + def test_plugin_puts_its_lib_directory_on_load_path + boot_rails + require "another" + assert_equal "Another", Another.name + end + + def test_plugin_paths_get_added_to_as_dependency_list + boot_rails + assert_equal "Another", Another.name + end + + def test_plugins_constants_are_not_reloaded_by_default + boot_rails + assert_equal "Another", Another.name + ActiveSupport::Dependencies.clear + @plugin.delete("lib/another.rb") + assert_nothing_raised { Another } + end + + def test_plugin_constants_get_reloaded_if_config_reload_plugins + add_to_config <<-RUBY + config.reload_plugins = true + RUBY + + boot_rails + + assert_equal "Another", Another.name + ActiveSupport::Dependencies.clear + @plugin.delete("lib/another.rb") + assert_raises(NameError) { Another } + end + + def test_plugin_puts_its_models_directory_on_load_path + @plugin.write "app/models/my_bukkit.rb", "class MyBukkit ; end" + boot_rails + assert_nothing_raised { MyBukkit } + end + + def test_plugin_puts_its_controllers_directory_on_the_load_path + @plugin.write "app/controllers/bukkit_controller.rb", "class BukkitController ; end" + boot_rails + assert_nothing_raised { BukkitController } + end + + def test_plugin_adds_its_views_to_view_paths + @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY + class BukkitController < ActionController::Base + def index + end + end + RUBY + + @plugin.write "app/views/bukkit/index.html.erb", "Hello bukkits" + + boot_rails + + require "action_controller" + require "rack/mock" + response = BukkitController.action(:index).call(Rack::MockRequest.env_for("/")) + assert_equal "Hello bukkits\n", response[2].body + end + + def test_plugin_adds_its_views_to_view_paths_with_lower_proriority + @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY + class BukkitController < ActionController::Base + def index + end + end + RUBY + + @plugin.write "app/views/bukkit/index.html.erb", "Hello bukkits" + app_file "app/views/bukkit/index.html.erb", "Hi bukkits" + + boot_rails + + require "action_controller" + require "rack/mock" + response = BukkitController.action(:index).call(Rack::MockRequest.env_for("/")) + assert_equal "Hi bukkits\n", response[2].body + end + + def test_plugin_adds_helpers_to_controller_views + @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY + class BukkitController < ActionController::Base + def index + end + end + RUBY + + @plugin.write "app/helpers/bukkit_helper.rb", <<-RUBY + module BukkitHelper + def bukkits + "bukkits" + end + end + RUBY + + @plugin.write "app/views/bukkit/index.html.erb", "Hello <%= bukkits %>" + + boot_rails + + require "rack/mock" + response = BukkitController.action(:index).call(Rack::MockRequest.env_for("/")) + assert_equal "Hello bukkits\n", response[2].body + end + + def test_routes_are_added_to_router + @plugin.write "config/routes.rb", <<-RUBY + class Sprokkit + def self.call(env) + [200, {'Content-Type' => 'text/html'}, ["I am a Sprokkit"]] + end + end + + ActionController::Routing::Routes.draw do + match "/sprokkit", :to => Sprokkit + end + RUBY + + boot_rails + require 'rack/test' + extend Rack::Test::Methods + + get "/sprokkit" + assert_equal "I am a Sprokkit", last_response.body + end + + def test_routes_in_plugins_have_lower_priority_than_application_ones + controller "foo", <<-RUBY + class FooController < ActionController::Base + def index + render :text => "foo" + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do |map| + match 'foo', :to => 'foo#index' + end + RUBY + + @plugin.write "app/controllers/bar_controller.rb", <<-RUBY + class BarController < ActionController::Base + def index + render :text => "bar" + end + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + ActionController::Routing::Routes.draw do |map| + match 'foo', :to => 'bar#index' + match 'bar', :to => 'bar#index' + end + RUBY + + boot_rails + require 'rack/test' + extend Rack::Test::Methods + + get '/foo' + assert_equal 'foo', last_response.body + + get '/bar' + assert_equal 'bar', last_response.body + end + + def test_rake_tasks_lib_tasks_are_loaded + $executed = false + @plugin.write "lib/tasks/foo.rake", <<-RUBY + task :foo do + $executed = true + end + RUBY + + boot_rails + require 'rake' + require 'rake/rdoctask' + require 'rake/testtask' + Rails.application.load_tasks + Rake::Task[:foo].invoke + assert $executed + end + + def test_i18n_files_have_lower_priority_than_application_ones + add_to_config <<-RUBY + config.i18n.load_path << "#{app_path}/app/locales/en.yml" + RUBY + + app_file 'app/locales/en.yml', <<-YAML +en: + bar: "1" +YAML + + app_file 'config/locales/en.yml', <<-YAML +en: + foo: "2" + bar: "2" +YAML + + @plugin.write 'config/locales/en.yml', <<-YAML +en: + foo: "3" +YAML + + boot_rails + + assert_equal %W( + #{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/locale/en.yml + #{RAILS_FRAMEWORK_ROOT}/activemodel/lib/active_model/locale/en.yml + #{RAILS_FRAMEWORK_ROOT}/activerecord/lib/active_record/locale/en.yml + #{RAILS_FRAMEWORK_ROOT}/actionpack/lib/action_view/locale/en.yml + #{@plugin.path}/config/locales/en.yml + #{app_path}/config/locales/en.yml + #{app_path}/app/locales/en.yml + ).map { |path| File.expand_path(path) }, I18n.load_path.map { |path| File.expand_path(path) } + + assert_equal "2", I18n.t(:foo) + assert_equal "1", I18n.t(:bar) + end + + def test_plugin_metals_added_to_middleware_stack + @plugin.write 'app/metal/foo_metal.rb', <<-RUBY + class FooMetal + def self.call(env) + [200, { "Content-Type" => "text/html"}, ["FooMetal"]] + end + end + RUBY + + boot_rails + require 'rack/test' + extend Rack::Test::Methods + + get "/" + assert_equal 200, last_response.status + assert_equal "FooMetal", last_response.body + end + + def test_namespaced_controllers_with_namespaced_routes + @plugin.write "config/routes.rb", <<-RUBY + ActionController::Routing::Routes.draw do + namespace :admin do + match "index", :to => "admin/foo#index" + end + end + RUBY + + @plugin.write "app/controllers/admin/foo_controller.rb", <<-RUBY + class Admin::FooController < ApplicationController + def index + render :text => "Rendered from namespace" + end + end + RUBY + + boot_rails + require 'rack/test' + extend Rack::Test::Methods + + get "/admin/index" + assert_equal 200, last_response.status + assert_equal "Rendered from namespace", last_response.body + end + + def test_plugin_initializers + $plugin_initializer = false + @plugin.write "config/initializers/foo.rb", <<-RUBY + $plugin_initializer = true + RUBY + + boot_rails + assert $plugin_initializer + end + + def test_plugin_midleware_referenced_in_configuration + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + def initialize(app) + @app = app + end + + def call(env) + @app.call(env) + end + end + RUBY + + add_to_config "config.middleware.use \"Bukkits\"" + boot_rails + end + end +end
\ No newline at end of file diff --git a/railties/test/vendor/gems/dummy-gem-a-0.4.0/.specification b/railties/test/vendor/gems/dummy-gem-a-0.4.0/.specification deleted file mode 100644 index 86dba2092c..0000000000 --- a/railties/test/vendor/gems/dummy-gem-a-0.4.0/.specification +++ /dev/null @@ -1,28 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-a -version: !ruby/object:Gem::Version - version: 0.4.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -files: -- lib -- lib/dummy-gem-a.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem A diff --git a/railties/test/vendor/gems/dummy-gem-a-0.4.0/lib/dummy-gem-a.rb b/railties/test/vendor/gems/dummy-gem-a-0.4.0/lib/dummy-gem-a.rb deleted file mode 100644 index 0453b38ab8..0000000000 --- a/railties/test/vendor/gems/dummy-gem-a-0.4.0/lib/dummy-gem-a.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_A_VERSION="0.4.0" diff --git a/railties/test/vendor/gems/dummy-gem-b-0.4.0/.specification b/railties/test/vendor/gems/dummy-gem-b-0.4.0/.specification deleted file mode 100644 index 5ea692d7a1..0000000000 --- a/railties/test/vendor/gems/dummy-gem-b-0.4.0/.specification +++ /dev/null @@ -1,28 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-b -version: !ruby/object:Gem::Version - version: 0.4.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -files: -- lib -- lib/dummy-gem-b.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem B diff --git a/railties/test/vendor/gems/dummy-gem-b-0.4.0/lib/dummy-gem-b.rb b/railties/test/vendor/gems/dummy-gem-b-0.4.0/lib/dummy-gem-b.rb deleted file mode 100644 index 850b5dda83..0000000000 --- a/railties/test/vendor/gems/dummy-gem-b-0.4.0/lib/dummy-gem-b.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_B_VERSION="0.4.0" diff --git a/railties/test/vendor/gems/dummy-gem-b-0.6.0/.specification b/railties/test/vendor/gems/dummy-gem-b-0.6.0/.specification deleted file mode 100644 index ab4707124a..0000000000 --- a/railties/test/vendor/gems/dummy-gem-b-0.6.0/.specification +++ /dev/null @@ -1,28 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-b -version: !ruby/object:Gem::Version - version: 0.6.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -files: -- lib -- lib/dummy-gem-b.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem B diff --git a/railties/test/vendor/gems/dummy-gem-b-0.6.0/lib/dummy-gem-b.rb b/railties/test/vendor/gems/dummy-gem-b-0.6.0/lib/dummy-gem-b.rb deleted file mode 100644 index 7d6d01cd48..0000000000 --- a/railties/test/vendor/gems/dummy-gem-b-0.6.0/lib/dummy-gem-b.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_B_VERSION="0.6.0" diff --git a/railties/test/vendor/gems/dummy-gem-c-0.4.0/.specification b/railties/test/vendor/gems/dummy-gem-c-0.4.0/.specification deleted file mode 100644 index f90f60424c..0000000000 --- a/railties/test/vendor/gems/dummy-gem-c-0.4.0/.specification +++ /dev/null @@ -1,28 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-c -version: !ruby/object:Gem::Version - version: 0.4.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -files: -- lib -- lib/dummy-gem-c.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem C diff --git a/railties/test/vendor/gems/dummy-gem-c-0.4.0/lib/dummy-gem-c.rb b/railties/test/vendor/gems/dummy-gem-c-0.4.0/lib/dummy-gem-c.rb deleted file mode 100644 index 1a416bef82..0000000000 --- a/railties/test/vendor/gems/dummy-gem-c-0.4.0/lib/dummy-gem-c.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_C_VERSION="0.4.0" diff --git a/railties/test/vendor/gems/dummy-gem-c-0.6.0/.specification b/railties/test/vendor/gems/dummy-gem-c-0.6.0/.specification deleted file mode 100644 index e75c0aa66a..0000000000 --- a/railties/test/vendor/gems/dummy-gem-c-0.6.0/.specification +++ /dev/null @@ -1,28 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-c -version: !ruby/object:Gem::Version - version: 0.6.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -files: -- lib -- lib/dummy-gem-c.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem C diff --git a/railties/test/vendor/gems/dummy-gem-c-0.6.0/lib/dummy-gem-c.rb b/railties/test/vendor/gems/dummy-gem-c-0.6.0/lib/dummy-gem-c.rb deleted file mode 100644 index 9ba2ca8bb5..0000000000 --- a/railties/test/vendor/gems/dummy-gem-c-0.6.0/lib/dummy-gem-c.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_C_VERSION="0.6.0" diff --git a/railties/test/vendor/gems/dummy-gem-d-1.0.0/lib/dummy-gem-d.rb b/railties/test/vendor/gems/dummy-gem-d-1.0.0/lib/dummy-gem-d.rb deleted file mode 100644 index e5cb007e5f..0000000000 --- a/railties/test/vendor/gems/dummy-gem-d-1.0.0/lib/dummy-gem-d.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_D_VERSION="1.0.0" diff --git a/railties/test/vendor/gems/dummy-gem-e-1.0.0/.specification b/railties/test/vendor/gems/dummy-gem-e-1.0.0/.specification deleted file mode 100644 index ce4443c8be..0000000000 --- a/railties/test/vendor/gems/dummy-gem-e-1.0.0/.specification +++ /dev/null @@ -1,28 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-e -version: !ruby/object:Gem::Version - version: 1.3.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -files: -- lib -- lib/dummy-gem-e.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem E diff --git a/railties/test/vendor/gems/dummy-gem-e-1.0.0/lib/dummy-gem-e.rb b/railties/test/vendor/gems/dummy-gem-e-1.0.0/lib/dummy-gem-e.rb deleted file mode 100644 index 48bf91a701..0000000000 --- a/railties/test/vendor/gems/dummy-gem-e-1.0.0/lib/dummy-gem-e.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_E_VERSION="1.0.0" diff --git a/railties/test/vendor/gems/dummy-gem-f-1.0.0/.specification b/railties/test/vendor/gems/dummy-gem-f-1.0.0/.specification deleted file mode 100644 index 70a36b9a8c..0000000000 --- a/railties/test/vendor/gems/dummy-gem-f-1.0.0/.specification +++ /dev/null @@ -1,39 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-f -version: !ruby/object:Gem::Version - version: 1.3.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -dependencies: -- !ruby/object:Gem::Dependency - name: absolutely-no-such-gem - type: :runtime - version_requirement: - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.0.0 - version: -files: -- lib -- lib/dummy-gem-f.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem F diff --git a/railties/test/vendor/gems/dummy-gem-f-1.0.0/lib/dummy-gem-f.rb b/railties/test/vendor/gems/dummy-gem-f-1.0.0/lib/dummy-gem-f.rb deleted file mode 100644 index 0271c8c48a..0000000000 --- a/railties/test/vendor/gems/dummy-gem-f-1.0.0/lib/dummy-gem-f.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_F_VERSION="1.0.0" diff --git a/railties/test/vendor/gems/dummy-gem-g-1.0.0/.specification b/railties/test/vendor/gems/dummy-gem-g-1.0.0/.specification deleted file mode 100644 index 27e29912a6..0000000000 --- a/railties/test/vendor/gems/dummy-gem-g-1.0.0/.specification +++ /dev/null @@ -1,39 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-g -version: !ruby/object:Gem::Version - version: 1.3.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -dependencies: -- !ruby/object:Gem::Dependency - name: dummy-gem-f - type: :runtime - version_requirement: - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.0.0 - version: -files: -- lib -- lib/dummy-gem-g.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem G diff --git a/railties/test/vendor/gems/dummy-gem-g-1.0.0/lib/dummy-gem-g.rb b/railties/test/vendor/gems/dummy-gem-g-1.0.0/lib/dummy-gem-g.rb deleted file mode 100644 index 8fc056586c..0000000000 --- a/railties/test/vendor/gems/dummy-gem-g-1.0.0/lib/dummy-gem-g.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_G_VERSION="1.0.0" diff --git a/railties/test/vendor/gems/dummy-gem-h-1.0.0/.specification b/railties/test/vendor/gems/dummy-gem-h-1.0.0/.specification deleted file mode 100644 index b3f7930948..0000000000 --- a/railties/test/vendor/gems/dummy-gem-h-1.0.0/.specification +++ /dev/null @@ -1,29 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-h -version: !ruby/object:Gem::Version - version: 1.3.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -dependencies: -files: -- lib -- lib/dummy-gem-h.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem H diff --git a/railties/test/vendor/gems/dummy-gem-h-1.0.0/lib/dummy-gem-h.rb b/railties/test/vendor/gems/dummy-gem-h-1.0.0/lib/dummy-gem-h.rb deleted file mode 100644 index 0f91234936..0000000000 --- a/railties/test/vendor/gems/dummy-gem-h-1.0.0/lib/dummy-gem-h.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_H_VERSION="1.0.0" diff --git a/railties/test/vendor/gems/dummy-gem-i-1.0.0/.specification b/railties/test/vendor/gems/dummy-gem-i-1.0.0/.specification deleted file mode 100644 index 50b4969da5..0000000000 --- a/railties/test/vendor/gems/dummy-gem-i-1.0.0/.specification +++ /dev/null @@ -1,41 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-i -version: !ruby/object:Gem::Version - version: 1.3.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -dependencies: -- !ruby/object:Gem::Dependency - name: dummy-gem-i - type: :runtime - version_requirement: - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.0.0 - version: -extensions: -- ext/dummy-gem-i/extconf.rb -files: -- lib -- lib/dummy-gem-i.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem G diff --git a/railties/test/vendor/gems/dummy-gem-i-1.0.0/ext/dummy-gem-i/Makefile b/railties/test/vendor/gems/dummy-gem-i-1.0.0/ext/dummy-gem-i/Makefile deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/test/vendor/gems/dummy-gem-i-1.0.0/ext/dummy-gem-i/Makefile +++ /dev/null diff --git a/railties/test/vendor/gems/dummy-gem-i-1.0.0/lib/dummy-gem-i.rb b/railties/test/vendor/gems/dummy-gem-i-1.0.0/lib/dummy-gem-i.rb deleted file mode 100644 index 2f9a376c2c..0000000000 --- a/railties/test/vendor/gems/dummy-gem-i-1.0.0/lib/dummy-gem-i.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_I_VERSION="1.0.0" diff --git a/railties/test/vendor/gems/dummy-gem-j-1.0.0/.specification b/railties/test/vendor/gems/dummy-gem-j-1.0.0/.specification deleted file mode 100644 index 2c456546fc..0000000000 --- a/railties/test/vendor/gems/dummy-gem-j-1.0.0/.specification +++ /dev/null @@ -1,41 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-j -version: !ruby/object:Gem::Version - version: 1.3.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -dependencies: -- !ruby/object:Gem::Dependency - name: dummy-gem-j - type: :runtime - version_requirement: - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.0.0 - version: -extensions: -- ext/dummy-gem-j/extconf.rb -files: -- lib -- lib/dummy-gem-j.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem G diff --git a/railties/test/vendor/gems/dummy-gem-j-1.0.0/lib/dummy-gem-j.rb b/railties/test/vendor/gems/dummy-gem-j-1.0.0/lib/dummy-gem-j.rb deleted file mode 100644 index 8ecd363ff8..0000000000 --- a/railties/test/vendor/gems/dummy-gem-j-1.0.0/lib/dummy-gem-j.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_J_VERSION="1.0.0" diff --git a/railties/test/vendor/gems/dummy-gem-k-1.0.0/.specification b/railties/test/vendor/gems/dummy-gem-k-1.0.0/.specification deleted file mode 100644 index 20edd0f856..0000000000 --- a/railties/test/vendor/gems/dummy-gem-k-1.0.0/.specification +++ /dev/null @@ -1,49 +0,0 @@ ---- !ruby/object:Gem::Specification -name: dummy-gem-k -version: !ruby/object:Gem::Version - version: 1.3.0 -platform: ruby -authors: -- "Nobody" -date: 2008-10-03 00:00:00 -04:00 -dependencies: -- !ruby/object:Gem::Dependency - name: dummy-gem-k - type: :runtime - version_requirement: - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.0.0 - version: -- !ruby/object:Gem::Dependency - name: dummy-gem-h - type: :development - version_requirement: - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.0.0 - version: -files: -- lib -- lib/dummy-gem-k.rb -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] -specification_version: 2 -summary: Dummy Gem I diff --git a/railties/test/vendor/gems/dummy-gem-k-1.0.0/lib/dummy-gem-k.rb b/railties/test/vendor/gems/dummy-gem-k-1.0.0/lib/dummy-gem-k.rb deleted file mode 100644 index 97fb1d69ce..0000000000 --- a/railties/test/vendor/gems/dummy-gem-k-1.0.0/lib/dummy-gem-k.rb +++ /dev/null @@ -1 +0,0 @@ -DUMMY_GEM_K_VERSION="1.0.0" |