Strange ruby syntax
what the syntax is in Action Mailer Basics rails guide ?
class UserMailer < ActionMailer::Base
def welcome_email(user)
recipients user.email
from "My Awesome Site Notifications <notifications@example.com>"
subject "Welcome to My Awesome Site"
sent_on Time.now
body {:user => user, :url => "http://example.com/login"}
end
end
How should i understand the construction, like
from "Some text for this field"
Is it an assignment the value to a 开发者_开发问答variable, called "from" ?
No, it's a method call. The name of the method is from
, and the argument is a string. In Ruby, parentheses around method calls are optional, so
from "Some text for this field"
is the same as
from("Some text for this field")
Rails (and many Ruby libraries) like to express code in a natural language style, though, so the parentheses-less version reads better, hence why it is used in examples.
It is a call to a method from
with the argument "Some text for this field"
The method comes from the ActionMailer::Base
class that your UserMailer extends from.
In Ruby the parentheses around a method call are optional unless something would be ambiguous so the statement is equivalent to from("Some text for this field")
Rails has a coding style that prefers to be close to natural language where possible, hence not using parentheses unless necessary.
Calling this method sets an instance variable @from
to the value you provide so that it can be used later when sending the message.
Normally when you have accessor methods for getting and setting a variable you would have from=
to set the value and from
to return the value, however ActionMailer
uses something called adv_attr_accessor
to define the from
method so that if you call it with a parameter then it acts as a setter but if you call it with no parameters then it acts as a getter.
This can be seen in actionmailer-2.x.x/lib/action_mailer/base.rb and actionmailer-2.x.x/lib/action_mailer/adv_attr_accessor.rb
It's not an assignment. In Ruby, assignments are done using the assignment operator =
like this:
var = val
You are probably thinking of some Lisp dialects where assignment looks like this:
(def var val)
It's just a simple receiverless message send.
In Ruby, the general syntax for a message send is
receiver.selector(argument1, argument2)
However, if the receiver
is self
, you can leave off the receiver
, so
selector(argument1, argument2)
is the same as
self.selector(argument1, argument2)
[Note: this is not quite true. In Ruby, private methods can only be invoked via a receiverless message send, so if in this example self
responds to the selector
message by invoking a private method, only the first variant will work, the second will raise a NoMethodError
exception.]
Also, in cases where there are no ambiguities, you can leave off the parentheses around the arguments like this:
receiver.selector argument1, argument2
If you put the two things together, you can now see that
selector argument1, argument2
is equivalent to
self.selector(argument1, argument2)
and thus
from "Some text for this field"
is equivalent to
self.from("Some text for this field")
There is a third shortcut in Ruby's message sending syntax: if the very last argument to a message send is a Hash
literal, then you can leave out the curly braces. So, the last line in the above example could also be written as
body :user => user, :url => "http://example.com/login"
Also, in Ruby 1.9, a Hash
literal where all keys are Symbol
s can be written using an alternative Hash
literal syntax:
{ key1: val1, key2: val2 }
is the same as the old syntax
{ :key1 => val1, :key2 => val2 }
which means that, at least in Ruby 1.9, that last line could also be written as
body user: user, url: "http://example.com/login"
You could also call from
an attribute. It's a property of the email, but how it's implemented is hidden from you (encapsulation). This is a Good Thing. It means that if Rails core decided it's better to change @from
into several variables, you wouldn't need to change any of your code.
精彩评论