2012-12-16 21:26:15 -05:00
|
|
|
= Methods
|
|
|
|
|
|
|
|
Methods implement the functionality of your program. Here is a simple method
|
|
|
|
definition:
|
|
|
|
|
|
|
|
def one_plus_one
|
|
|
|
1 + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
A method definition consists of the +def+ keyword, a method name, the body of
|
|
|
|
the method, then the +end+ keyword. When called the method will execute the
|
2013-01-04 18:39:48 -05:00
|
|
|
body of the method. This method returns +2+.
|
2012-12-16 21:26:15 -05:00
|
|
|
|
2013-01-15 13:29:05 -05:00
|
|
|
This section only covers defining methods. See also the {syntax documentation
|
|
|
|
on calling methods}[rdoc-ref:syntax/calling_methods.rdoc].
|
|
|
|
|
2013-01-14 23:33:28 -05:00
|
|
|
== Method Names
|
|
|
|
|
|
|
|
Method names may be one of the operators or must start a letter or a character
|
|
|
|
with the eight bit set. Typically method names are US-ASCII compatible since
|
|
|
|
the keys to type them exist on all keyboards.
|
|
|
|
|
|
|
|
(Ruby programs must be written in a US-ASCII-compatible character set. In
|
|
|
|
such character sets if the eight bit is set it indicates an extended
|
|
|
|
character. Ruby allows method names and other identifiers to contain such
|
|
|
|
characters.)
|
|
|
|
|
|
|
|
Method names may contain letters, numbers, an <code>_</code> (underscore or
|
|
|
|
low line) or a character with the eight bit set.
|
|
|
|
|
|
|
|
Method names may end with a <code>!</code> (bang or exclamation mark), a
|
|
|
|
<code>?</code> (question mark) or <code>=</code> equals sign.
|
|
|
|
|
|
|
|
In the ruby core library when a method ends with a bang it indicates there is
|
|
|
|
a non-bang method that has does not modify the receiver. This is typically
|
|
|
|
true for the standard library but does not hold true for other ruby libraries.
|
|
|
|
|
|
|
|
Methods that end with a question mark do not always return just +true+ or
|
|
|
|
+false+. Often they will may return an object to indicate a true value (or
|
|
|
|
"truthy" value).
|
|
|
|
|
|
|
|
Methods that end with an equals sign indicate an assignment method. For
|
|
|
|
assignment methods the return value is ignored, the arguments are returned
|
|
|
|
instead.
|
|
|
|
|
|
|
|
These are method names for the various ruby operators. Each of these
|
|
|
|
operators accept only one argument. Following the operator is the typical
|
|
|
|
use or name of the operator. Creating an alternate meaning for the operator
|
|
|
|
may lead to confusion as the user expects plus to add things, minus to
|
|
|
|
subtract things, etc. Additionally, you cannot alter the precedence of the
|
|
|
|
operators.
|
|
|
|
|
|
|
|
<code>+</code> :: add
|
|
|
|
<code>-</code> :: subtract
|
|
|
|
<code>*</code> :: multiply
|
|
|
|
<code>**</code> :: power
|
|
|
|
<code>/</code> :: divide
|
|
|
|
<code>%</code> :: modulus division, String#%
|
|
|
|
<code>&</code> :: AND
|
|
|
|
<code>^</code> :: XOR (exclusive OR)
|
|
|
|
<code>>></code> :: right-shift
|
|
|
|
<code><<</code> :: left-shift, append
|
|
|
|
<code>==</code> :: equal
|
|
|
|
<code>!=</code> :: not equal
|
|
|
|
<code>===</code> :: case equality. See Object#===
|
|
|
|
<code>=~</code> :: pattern match. (Not just for regular expressions)
|
|
|
|
<code>!~</code> :: does not match
|
|
|
|
<code><=></code> :: comparison aka spaceship operator. See Comparable
|
|
|
|
<code><</code> :: less-than
|
|
|
|
<code><=</code> :: less-than or equal
|
|
|
|
<code>></code> :: greater-than
|
|
|
|
<code>>=</code> :: greater-than or equal
|
|
|
|
|
|
|
|
To define unary methods minus, plus, tilde and not (<code>!</code>) follow the
|
2013-01-15 13:29:05 -05:00
|
|
|
operator with an <code>@</code> as in <code>+@</code> or <code>!@</code>:
|
2013-01-14 23:33:28 -05:00
|
|
|
|
|
|
|
class C
|
|
|
|
def -@
|
|
|
|
puts "you inverted this object"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
obj = C.new
|
|
|
|
|
|
|
|
-obj # prints "you inverted this object"
|
|
|
|
|
|
|
|
Unary methods accept zero arguments.
|
|
|
|
|
|
|
|
== Return Values
|
2013-01-04 18:39:48 -05:00
|
|
|
|
|
|
|
By default, a method returns the last expression that was evaluated in the body
|
|
|
|
of the method. In the example above, the last (and only) expression evaluated
|
|
|
|
was the simple sum <code>1 + 1</code>. The +return+ keyword can be used to
|
|
|
|
make it explicit that a method returns a value.
|
|
|
|
|
|
|
|
def one_plus_one
|
|
|
|
return 1 + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
It can also be used to make a method return before the last expression is
|
|
|
|
evaluated.
|
|
|
|
|
|
|
|
def two_plus_two
|
|
|
|
return 2 + 2
|
|
|
|
1 + 1 # this expression is never evaluated
|
|
|
|
end
|
|
|
|
|
2013-01-14 23:33:28 -05:00
|
|
|
Note that for assignment methods the return value will always be ignored.
|
|
|
|
Instead the argument will be returned:
|
|
|
|
|
|
|
|
def a=(value)
|
|
|
|
return 1 + value
|
|
|
|
end
|
|
|
|
|
|
|
|
p(a = 5) # prints 5
|
|
|
|
|
2013-01-04 18:39:48 -05:00
|
|
|
== Scope
|
|
|
|
|
|
|
|
The standard syntax to define a method:
|
|
|
|
|
|
|
|
def my_method
|
|
|
|
# ...
|
|
|
|
end
|
|
|
|
|
2013-01-04 20:23:49 -05:00
|
|
|
adds the method to a class. You can define an instance method on a specific
|
2013-01-04 18:39:48 -05:00
|
|
|
class with the +class+ keyword:
|
|
|
|
|
|
|
|
class C
|
|
|
|
def my_method
|
|
|
|
# ...
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
A method may be defined on another object. You may define a "class method" (a
|
|
|
|
method that is defined on the class, not an instance of the class) like this:
|
2012-12-16 22:05:45 -05:00
|
|
|
|
|
|
|
class C
|
|
|
|
def self.my_method
|
|
|
|
# ...
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-01-04 18:39:48 -05:00
|
|
|
However, this is simply a special case of a greater syntactical power in Ruby,
|
|
|
|
the ability to add methods to any object. Classes are objects, so adding
|
|
|
|
class methods is simply adding methods to the Class object.
|
|
|
|
|
|
|
|
The syntax for adding a method to an object is as follows:
|
|
|
|
|
|
|
|
greeting = "Hello"
|
|
|
|
|
|
|
|
def greeting.broaden
|
|
|
|
self + ", world!"
|
|
|
|
end
|
|
|
|
|
|
|
|
greeting.broaden # returns "Hello, world!"
|
|
|
|
|
2013-01-04 20:23:49 -05:00
|
|
|
+self+ is a keyword referring to the current object under consideration
|
2013-01-04 18:39:48 -05:00
|
|
|
by the compiler, which might make the use of +self+ in defining a class
|
|
|
|
method above a little clearer. Indeed, the example of adding a +hello+
|
|
|
|
method to the class +String+ can be rewritten thus:
|
|
|
|
|
|
|
|
def String.hello
|
|
|
|
"Hello, world!"
|
2012-12-16 22:05:45 -05:00
|
|
|
end
|
|
|
|
|
2013-01-04 18:39:48 -05:00
|
|
|
A method defined like this is called a "singleton method". +broaden+ will only
|
|
|
|
exist on the string instance +greeting+. Other strings will not have +broaden+.
|
|
|
|
|
|
|
|
== Overriding
|
|
|
|
|
|
|
|
When Ruby encounters the +def+ keyword, it doesn't consider it an error if the
|
|
|
|
method already exists: it simply redefines it. This is called
|
|
|
|
_overriding_. Rather like extending core classes, this is a potentially
|
|
|
|
dangerous ability, and should be used sparingly because it can cause unexpected
|
|
|
|
results. For example, consider this irb session:
|
|
|
|
|
|
|
|
>> "43".to_i
|
|
|
|
=> 43
|
|
|
|
>> class String
|
|
|
|
>> def to_i
|
|
|
|
>> 42
|
|
|
|
>> end
|
|
|
|
>> end
|
|
|
|
=> nil
|
|
|
|
>> "43".to_i
|
|
|
|
=> 42
|
|
|
|
|
|
|
|
This will effectively sabotage any code which makes use of the method
|
|
|
|
<code>String#to_i</code> to parse numbers from strings.
|
2012-12-16 22:05:45 -05:00
|
|
|
|
2012-12-16 21:26:15 -05:00
|
|
|
== Arguments
|
|
|
|
|
|
|
|
A method may accept arguments. The argument list follows the method name:
|
|
|
|
|
|
|
|
def add_one(value)
|
|
|
|
value + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
When called, the user of the +add_one+ method must provide an argument. The
|
|
|
|
argument is a local variable in the method body. The method will then add one
|
2013-01-04 18:39:48 -05:00
|
|
|
to this argument and return the value. If given +1+ this method will
|
|
|
|
return +2+.
|
2012-12-16 21:26:15 -05:00
|
|
|
|
|
|
|
The parentheses around the arguments are optional:
|
|
|
|
|
|
|
|
def add_one value
|
|
|
|
value + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
Multiple arguments are separated by a comma:
|
|
|
|
|
|
|
|
def add_values(a, b)
|
|
|
|
a + b
|
|
|
|
end
|
|
|
|
|
|
|
|
When called, the arguments must be provided in the exact order. In other
|
|
|
|
words, the arguments are positional.
|
|
|
|
|
|
|
|
=== Default Values
|
|
|
|
|
|
|
|
Arguments may have default values:
|
|
|
|
|
|
|
|
def add_values(a, b = 1)
|
|
|
|
a + b
|
|
|
|
end
|
|
|
|
|
2012-12-19 04:05:44 -05:00
|
|
|
The default value does not need to appear first, but arguments with defaults
|
|
|
|
must be grouped together. This is ok:
|
2012-12-16 21:26:15 -05:00
|
|
|
|
|
|
|
def add_values(a = 1, b = 2, c)
|
|
|
|
a + b + c
|
|
|
|
end
|
|
|
|
|
|
|
|
This will raise a SyntaxError:
|
|
|
|
|
|
|
|
def add_values(a = 1, b, c = 1)
|
|
|
|
a + b + c
|
|
|
|
end
|
|
|
|
|
2013-01-18 00:15:44 -05:00
|
|
|
=== Array Decomposition
|
|
|
|
|
|
|
|
You can decompose (unpack or extract values from) an Array using extra
|
|
|
|
parentheses in the arguments:
|
|
|
|
|
|
|
|
def my_method((a, b))
|
|
|
|
p a: a, b: b
|
|
|
|
end
|
|
|
|
|
|
|
|
my_method([1, 2])
|
|
|
|
|
|
|
|
This prints:
|
|
|
|
|
|
|
|
{:a=>1, :b=>2}
|
|
|
|
|
|
|
|
If the argument has extra elements in the Array they will be ignored:
|
|
|
|
|
|
|
|
def my_method((a, b))
|
|
|
|
p a: a, b: b
|
|
|
|
end
|
|
|
|
|
|
|
|
my_method([1, 2, 3])
|
|
|
|
|
|
|
|
This has the same output as above.
|
|
|
|
|
|
|
|
You can use a <code>*</code> to collect the remaining arguments. This splits
|
|
|
|
an Array into a first element and the rest:
|
|
|
|
|
|
|
|
def my_method((a, *b))
|
|
|
|
p a: a, b: b
|
|
|
|
end
|
|
|
|
|
|
|
|
my_method([1, 2, 3])
|
|
|
|
|
|
|
|
This prints:
|
|
|
|
|
|
|
|
{:a=>1, :b=>[2, 3]}
|
|
|
|
|
|
|
|
The argument will be decomposed if it responds to #to_ary. You should only
|
|
|
|
define #to_ary if you can use your object in place of an Array.
|
|
|
|
|
|
|
|
Use of the inner parentheses only uses one of the sent arguments. If the
|
|
|
|
argument is not an Array it will be assigned to the first argument in the
|
|
|
|
decomposition and the remaining arguments in the decomposition will be +nil+:
|
|
|
|
|
|
|
|
def my_method(a, (b, c), d)
|
|
|
|
p a: a, b: b, c: c, d: d
|
|
|
|
end
|
|
|
|
|
|
|
|
my_method(1, 2, 3)
|
|
|
|
|
|
|
|
This prints:
|
|
|
|
|
|
|
|
{:a=>1, :b=>2, :c=>nil, :d=>3}
|
|
|
|
|
|
|
|
You can nest decomposition arbitrarily:
|
|
|
|
|
|
|
|
def my_method(((a, b), c))
|
|
|
|
# ...
|
|
|
|
end
|
|
|
|
|
2012-12-16 21:26:15 -05:00
|
|
|
=== Array/Hash Argument
|
|
|
|
|
2013-01-14 19:11:46 -05:00
|
|
|
Prefixing an argument with <code>*</code> causes any remaining arguments to be
|
|
|
|
converted to an Array:
|
2012-12-16 21:26:15 -05:00
|
|
|
|
|
|
|
def gather_arguments(*arguments)
|
|
|
|
p arguments
|
|
|
|
end
|
|
|
|
|
|
|
|
gather_arguments 1, 2, 3 # prints [1, 2, 3]
|
|
|
|
|
|
|
|
The array argument must be the last positional argument, it must appear before
|
|
|
|
any keyword arguments.
|
|
|
|
|
|
|
|
The array argument will capture a Hash as the last entry if a hash was sent by
|
|
|
|
the caller after all positional arguments.
|
|
|
|
|
|
|
|
gather_arguments 1, a: 2 # prints [1, {:a=>2}]
|
|
|
|
|
|
|
|
However, this only occurs if the method does not declare any keyword arguments.
|
|
|
|
|
|
|
|
def gather_arguments_keyword(*positional, keyword: nil)
|
2012-12-19 02:19:59 -05:00
|
|
|
p positional: positional, keyword: keyword
|
2012-12-16 21:26:15 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
gather_arguments_keyword 1, 2, three: 3
|
|
|
|
#=> raises: unknown keyword: three (ArgumentError)
|
|
|
|
|
2013-01-14 19:11:46 -05:00
|
|
|
Also, note that a bare <code>*</code> can be used to ignore arguments:
|
|
|
|
|
|
|
|
def ignore_arguments(*)
|
|
|
|
end
|
|
|
|
|
|
|
|
=== Keyword Arguments
|
|
|
|
|
|
|
|
Keyword arguments are similar to positional arguments with default values:
|
|
|
|
|
|
|
|
def add_values(first: 1, second: 2)
|
|
|
|
first + second
|
|
|
|
end
|
|
|
|
|
|
|
|
Arbitrary keyword arguments will be accepted with <code>**</code>:
|
|
|
|
|
|
|
|
def gather_arguments(first: nil, **rest)
|
|
|
|
p first, rest
|
|
|
|
end
|
|
|
|
|
|
|
|
gather_arguments first: 1, second: 2, third: 3
|
|
|
|
# prints 1 then {:second=>2, :third=>3}
|
|
|
|
|
|
|
|
When calling a method with keyword arguments the arguments may appear in any
|
|
|
|
order. If an unknown keyword argument is sent by the caller an ArgumentError
|
|
|
|
is raised.
|
|
|
|
|
|
|
|
When mixing keyword arguments and positional arguments, all positional
|
|
|
|
arguments must appear before any keyword arguments.
|
|
|
|
|
2013-01-14 21:49:54 -05:00
|
|
|
== Block Argument
|
|
|
|
|
|
|
|
The block argument is indicated by <code>&</code> and must come last:
|
|
|
|
|
|
|
|
def my_method(&my_block)
|
|
|
|
my_method.call(self)
|
|
|
|
end
|
|
|
|
|
|
|
|
Most frequently the block argument is used to pass a block to another method:
|
|
|
|
|
|
|
|
def each_item(&block)
|
|
|
|
@items.each(&block)
|
|
|
|
end
|
|
|
|
|
|
|
|
If you are only going to call the block and will not otherwise manipulate it
|
|
|
|
or send it to another method using <code>yield</code> without an explicit
|
|
|
|
block parameter is preferred. This method is equivalent to the first method
|
|
|
|
in this section:
|
|
|
|
|
|
|
|
def my_method
|
|
|
|
yield self
|
|
|
|
end
|
|
|
|
|
|
|
|
There is also a performance benefit to using yield over a calling a block
|
|
|
|
parameter. When a block argument is assigned to a variable a Proc object is
|
|
|
|
created which holds the block. When using yield this Proc object is not
|
|
|
|
created.
|
|
|
|
|
|
|
|
If you only need to use the block sometimes you can use Proc.new to create a
|
|
|
|
proc from the block that was passed to your method. See Proc.new for further
|
|
|
|
details.
|
|
|
|
|
2012-12-16 21:26:15 -05:00
|
|
|
== Exception Handling
|
|
|
|
|
|
|
|
Methods have an implied exception handling block so you do not need to use
|
|
|
|
+begin+ or +end+ to handle exceptions. This:
|
|
|
|
|
|
|
|
def my_method
|
|
|
|
begin
|
|
|
|
# code that may raise an exception
|
|
|
|
rescue
|
|
|
|
# handle exception
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
May be written as:
|
|
|
|
|
|
|
|
def my_method
|
|
|
|
# code that may raise an exception
|
|
|
|
rescue
|
|
|
|
# handle exception
|
|
|
|
end
|
|
|
|
|
|
|
|
If you wish to rescue an exception for only part of your method use +begin+ and
|
2013-01-18 19:16:08 -05:00
|
|
|
+end+. For more details see the page on {exception
|
|
|
|
handling}[rdoc-ref:syntax/exceptions.rdoc].
|
2012-12-16 21:26:15 -05:00
|
|
|
|