diff --git a/ChangeLog b/ChangeLog index be0ec9d477..520fbb9d39 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +Tue Jan 15 10:54:59 2013 Eric Hodel + + * doc/syntax/calling_methods.rdoc (Arguments): Added improved + introduction to arguments including passing style and lazy + evaluation. Thanks to Matt Aimonetti. + * doc/syntax/calling_methods.rdoc (Positional Arguments): Added + description for sending a message to a method with *arguments + * doc/syntax/calling_methods.rdoc (Default Positional Arguments): + Added description. Thanks to Andy Lindeman. + * doc/syntax/calling_methods.rdoc (Block Local Arguments): + Added description of block locals. Thanks to Justin Collins. + * doc/syntax/calling_methods.rdoc (Hash to Keyword Arguments): Added + section describing ** operator. Thanks to Justin Collins. + Tue Jan 15 10:40:18 2013 Marc-Andre Lafortune * test_lazy_enumerator: Test that map & flat_map also require a block diff --git a/doc/syntax/calling_methods.rdoc b/doc/syntax/calling_methods.rdoc index 9b284def61..edb2dfe617 100644 --- a/doc/syntax/calling_methods.rdoc +++ b/doc/syntax/calling_methods.rdoc @@ -27,14 +27,36 @@ NoMethodError. You may also use :: to designate a receiver, but this is rarely used due to the potential for confusion with :: for namespaces. -== Positional Arguments +== Arguments + +There are three types of arguments when sending a message, the positional +arguments, keyword (or named) arguments and the block argument. Each message +sent may use one, two or all types of arguments, but the arguments must be +supplied in this order. + +All arguments in ruby are passed by reference and are not lazily evaluated. + +Each argument is separated by a ,: + + my_method(1, '2', :three) + +Arguments may be an expression, a hash argument: + + 'key' => value + +or a keyword argument: + + key: value + +Hash and keyword arguments must be contiguous and must appear after all +positional arguments, but may be mixed: + + my_method('a' => 1, b: 2, 'c' => 3) + +=== Positional Arguments The positional arguments for the message follow the method name: - my_method(argument1) - -Multiple arguments are separated by a ,: - my_method(argument1, argument2) In many cases parenthesis are not necessary when sending a message: @@ -47,7 +69,76 @@ to: method_one argument1, method_two argument2, argument3 -== Keyword Arguments +If the method definition has a *argument extra positional +arguments will be assigned to +argument+ in the method as an Array. + +If the method definition doesn't include keyword arguments the keyword or +hash-type arguments are assigned as a single hash to the last argument: + + def my_method(options) + p options + end + + my_method('a' => 1, b: 2) # prints: {'a'=>1, :b=>2} + +If too many positional arguments are given an ArgumentError is raised. + +=== Default Positional Arguments + +When the method defines default arguments you do not need to supply all the +arguments to the method. Ruby will fill in the missing arguments in-order. + +First we'll cover the simple case where the default arguments appear on the +right. Consider this method: + + def my_method(a, b, c = 3, d = 4) + p [a, b, c, d] + end + +Here +c+ and +d+ have default values which ruby will apply for you. If you +send only two arguments to this method: + + my_method(1, 2) + +You will see ruby print [1, 2, 3, 4]. + +If you send three arguments: + + my_method(1, 2, 5) + +You will see ruby print [1, 2, 5, 4] + +Ruby fills in the missing arguments from left to right. + +Ruby allows default values to appear in the middle of positional arguments. +Consider this more complicated method: + + def my_method(a, b = 2, c = 3, d) + p [a, b, c, d] + end + +Here +b+ and +c+ have default values. If you send only two arguments to this +method: + + my_method(1, 4) + +You will see ruby print [1, 2, 3, 4]. + +If you send three arguments: + + my_method(1, 5, 6) + +You will see ruby print [1, 5, 3, 6]. + +Describing this in words gets complicated and confusing. I'll describe it +in variables and values instead. + +First 1 is assigned to +a+, then 6 is assigned to ++d+. This leaves only the arguments with default values. Since +5 has not been assigned to a value yet, it is given to +b+ and ++c+ uses its default value of 3. + +=== Keyword Arguments Keyword arguments follow any positional arguments and are separated by commas like positional arguments: @@ -58,7 +149,9 @@ Any keyword arguments not given will use the default value from the method definition. If a keyword argument is given that the method did not list an ArgumentError will be raised. -== Block Argument +=== Block Argument + +The block argument sends a closure from the calling scope to the method. The block argument is always last when sending a message to a method. A block is sent to a method using do ... end or { ... }: @@ -97,14 +190,45 @@ go in | ... | following the opening do or # ... end -== Array to Arguments Conversion +==== Block Local Arguments + +You may also declare block-local arguments to a block using ; in +the block arguments list. Assigning to a block-local argument will not +override local arguments outside the block in the caller's scope: + + def my_method + yield self + end + + place = "world" + + my_method do |obj; place| + place = "block" + puts "hello #{obj} this is #{place}" + end + + puts "place is: #{place}" + +This prints: + + hello main this is block + place is world + +So the +place+ variable in the block is not the same +place+ variable as +outside the block. Removing ; place from the block arguments +gives this result: + + hello main this is block + place is block + +=== Array to Arguments Conversion Given the following method: - def my_method(argument1, argument2) + def my_method(argument1, argument2, argument3) end -You can turn an Array into an Argument list with * (or splat) +You can turn an Array into an argument list with * (or splat) operator: arguments = [1, 2, 3] @@ -120,7 +244,16 @@ 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. +at the end of the array into keyword arguments: + + def my_method(a, b, c: 3) + end + + arguments = [1, 2, { c: 4 }] + my_method(*arguments) + +You may also use the ** (described next) to convert a Hash into +keyword arguments. If the number of objects in the Array do not match the number of arguments for the method an ArgumentError will be raised. @@ -128,7 +261,44 @@ the method an ArgumentError will be raised. If the splat operator comes first in the call, parentheses must be used to avoid a warning. -== Proc to Block Conversion +=== Hash to Keyword Arguments Conversion + +Given the following method: + + def my_method(first: 1, second: 2, third: 3) + end + +You can turn a Hash into keyword arguments with the ** operator: + + arguments = { first: 3, second: 4, third: 5 } + my_method(**arguments) + +or: + + arguments = { first: 3, second: 4 } + my_method(third: 5, **arguments) + +Both are equivalent to: + + my_method(first: 3, second: 4, third: 5) + +If the method definition uses ** to gather arbitrary keyword +arguments they will not be gathered by *: + + def my_method(*a, **kw) + p arguments: a, keywords: kw + end + + my_method(1, 2, '3' => 4, five: 6) + +Prints: + + {:arguments=>[1, 2], :keywords=>{"3"=>4, :five=>6}} + +Unlike the splat operator described above the ** operator has no +commonly recognized name. + +=== Proc to Block Conversion Given a method that use a block: @@ -146,6 +316,6 @@ operator: If the splat operator comes first in the call, parenthesis must be used to avoid a warning. -Unlike the splat operator described above the & has no commonly -recognized name. +Unlike the splat operator described above the & operator has no +commonly recognized name.