summaryrefslogtreecommitdiff
path: root/doc/syntax/calling_methods.rdoc
diff options
context:
space:
mode:
Diffstat (limited to 'doc/syntax/calling_methods.rdoc')
-rw-r--r--doc/syntax/calling_methods.rdoc101
1 files changed, 86 insertions, 15 deletions
diff --git a/doc/syntax/calling_methods.rdoc b/doc/syntax/calling_methods.rdoc
index da061dbfdb..76babcc3dc 100644
--- a/doc/syntax/calling_methods.rdoc
+++ b/doc/syntax/calling_methods.rdoc
@@ -30,7 +30,7 @@ NoMethodError.
You may also use <code>::</code> to designate a receiver, but this is rarely
used due to the potential for confusion with <code>::</code> for namespaces.
-=== Chaining \Method Calls
+=== Chaining Method Calls
You can "chain" method calls by immediately following one method call with another.
@@ -210,7 +210,7 @@ definition. If a keyword argument is given that the method did not list,
and the method definition does not accept arbitrary keyword arguments, an
ArgumentError will be raised.
-Keyword argument value can be omitted, meaning the value will be be fetched
+Keyword argument value can be omitted, meaning the value will be fetched
from the context by the name of the key
keyword1 = 'some value'
@@ -291,16 +291,16 @@ override local arguments outside the block in the caller's scope:
This prints:
hello main this is block
- place is world
+ place is: world
So the +place+ variable in the block is not the same +place+ variable as
outside the block. Removing <code>; place</code> from the block arguments
gives this result:
hello main this is block
- place is block
+ place is: block
-=== Array to Arguments Conversion
+=== Unpacking Positional Arguments
Given the following method:
@@ -322,17 +322,58 @@ Both are equivalent to:
my_method(1, 2, 3)
-If the method accepts keyword arguments, the splat operator will convert a
-hash at the end of the array into keyword arguments:
+The <code>*</code> unpacking operator can be applied to any object, not only
+arrays. If the object responds to a <code>#to_a</code> method, this method
+is called, and is expected to return an Array, and elements of this array are passed
+as separate positional arguments:
- def my_method(a, b, c: 3)
+ class Name
+ def initialize(name)
+ @name = name
+ end
+
+ def to_a = @name.split(' ')
end
- arguments = [1, 2, { c: 4 }]
- my_method(*arguments)
+ name = Name.new('Jane Doe')
+ p(*name)
+ # prints separate values:
+ # Jane
+ # Doe
+
+If the object doesn't have a <code>#to_a</code> method, the object itself is passed
+as one argument:
+
+ class Name
+ def initialize(name)
+ @name = name
+ end
+ end
+
+ name = Name.new('Jane Doe')
+ p(*name)
+ # Prints the object itself:
+ # #<Name:0x00007f9d07bca650 @name="Jane Doe">
-Note that this behavior is currently deprecated and will emit a warning.
-This behavior will be removed in Ruby 3.0.
+This allows to handle one or many arguments polymorphically. Note also that <tt>*nil</tt>
+is unpacked to an empty list of arguments, so conditional unpacking is possible:
+
+ my_method(*(some_arguments if some_condition?))
+
+If <code>#to_a</code> method exists and does not return an Array, it would be an
+error on unpacking:
+
+ class Name
+ def initialize(name)
+ @name = name
+ end
+
+ def to_a = @name
+ end
+
+ name = Name.new('Jane Doe')
+ p(*name)
+ # can't convert Name to Array (Name#to_a gives String) (TypeError)
You may also use the <code>**</code> (described next) to convert a Hash into
keyword arguments.
@@ -341,12 +382,13 @@ If the number of objects in the Array do not match the number of arguments for
the method, an ArgumentError will be raised.
If the splat operator comes first in the call, parentheses must be used to
-avoid a warning:
+avoid an ambiguity of interpretation as an unpacking operator or multiplication
+operator. In this case, Ruby issues a warning in verbose mode:
- my_method *arguments # warning
+ my_method *arguments # warning: '*' interpreted as argument prefix
my_method(*arguments) # no warning
-=== Hash to Keyword Arguments Conversion
+=== Unpacking Keyword Arguments
Given the following method:
@@ -368,6 +410,35 @@ Both are equivalent to:
my_method(first: 3, second: 4, third: 5)
+The <code>**</code> unpacking operator can be applied to any object, not only
+hashes. If the object responds to a <code>#to_hash</code> method, this method
+is called, and is expected to return an Hash, and elements of this hash are passed
+as keyword arguments:
+
+ class Name
+ def initialize(name)
+ @name = name
+ end
+
+ def to_hash = {first: @name.split(' ').first, last: @name.split(' ').last}
+ end
+
+ name = Name.new('Jane Doe')
+ p(**name)
+ # Prints: {name: "Jane", last: "Doe"}
+
+Unlike <code>*</code> operator, <code>**</code> raises an error when used on an
+object that doesn't respond to <code>#to_hash</code>. The one exception is
++nil+, which doesn't explicitly define this method, but is still allowed to
+be used in <code>**</code> unpacking, not adding any keyword arguments.
+
+Again, this allows for conditional unpacking:
+
+ my_method(some: params, **(some_extra_params if pass_extra_params?))
+
+Like <code>*</code> operator, <code>**</code> raises an error when the object responds
+to <code>#to_hash</code>, but it doesn't return a Hash.
+
If the method definition uses the keyword splat operator to
gather arbitrary keyword arguments, they will not be gathered
by <code>*</code>: