summaryrefslogtreecommitdiff
path: root/doc/syntax/methods.rdoc
blob: 70a916387d4ecd0af10568431e79b472c76a4dbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
= 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
body of the method.  This method returns +2+.

== Return values

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

== Scope

The standard syntax to define a method:

  def my_method
    # ...
  end

adds the method to a class.  You can define an instance method on a specific
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:

  class C
    def self.my_method
      # ...
    end
  end

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!"

+self+ is a keyword referring to the current object under consideration
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!"
  end

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.

== 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
to this argument and return the value.  If given +1+ this method will
return +2+.

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

The default value does not need to appear first, but arguments with defaults
must be grouped together.  This is ok:

  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

=== Array/Hash Argument

Prefixing an argument with <code>*</code> causes any remaining arguments to be
converted to an Array:

  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)
   p positional: positional, keyword: keyword
  end

  gather_arguments_keyword 1, 2, three: 3
  #=> raises: unknown keyword: three (ArgumentError)

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.

== 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
+end+.  For more details see the page on {Exception
Handling}[rdoc-ref:doc/syntax/exceptions.rdoc].