summaryrefslogtreecommitdiff
path: root/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'proc.c')
-rw-r--r--proc.c89
1 files changed, 80 insertions, 9 deletions
diff --git a/proc.c b/proc.c
index d3f96d703a..c0fcb20b95 100644
--- a/proc.c
+++ b/proc.c
@@ -4252,19 +4252,86 @@ proc_ruby2_keywords(VALUE procval)
* Since +return+ and +break+ exits the block itself in lambdas,
* lambdas cannot be orphaned.
*
- * == Numbered parameters
+ * == Anonymous block parameters
*
- * Numbered parameters are implicitly defined block parameters intended to
- * simplify writing short blocks:
+ * To simplify writing short blocks, Ruby provides two different types of
+ * anonymous parameters: +it+ (single parameter) and numbered ones: <tt>_1</tt>,
+ * <tt>_2</tt> and so on.
*
* # Explicit parameter:
* %w[test me please].each { |str| puts str.upcase } # prints TEST, ME, PLEASE
* (1..5).map { |i| i**2 } # => [1, 4, 9, 16, 25]
*
- * # Implicit parameter:
+ * # it:
+ * %w[test me please].each { puts it.upcase } # prints TEST, ME, PLEASE
+ * (1..5).map { it**2 } # => [1, 4, 9, 16, 25]
+ *
+ * # Numbered parameter:
* %w[test me please].each { puts _1.upcase } # prints TEST, ME, PLEASE
* (1..5).map { _1**2 } # => [1, 4, 9, 16, 25]
*
+ * === +it+
+ *
+ * +it+ is a name that is available inside a block when no explicit parameters
+ * defined, as shown above.
+ *
+ * %w[test me please].each { puts it.upcase } # prints TEST, ME, PLEASE
+ * (1..5).map { it**2 } # => [1, 4, 9, 16, 25]
+ *
+ * +it+ is a "soft keyword": it is not a reserved name, and can be used as
+ * a name for methods and local variables:
+ *
+ * it = 5 # no warnings
+ * def it(&block) # RSpec-like API, no warnings
+ * # ...
+ * end
+ *
+ * +it+ can be used as a local variable even in blocks that use it as an
+ * implicit parameter (though this style is obviously confusing):
+ *
+ * [1, 2, 3].each {
+ * # takes a value of implicit parameter "it" and uses it to
+ * # define a local variable with the same name
+ * it = it**2
+ * p it
+ * }
+ *
+ * In a block with explicit parameters defined +it+ usage raises an exception:
+ *
+ * [1, 2, 3].each { |x| p it }
+ * # syntax error found (SyntaxError)
+ * # [1, 2, 3].each { |x| p it }
+ * # ^~ `it` is not allowed when an ordinary parameter is defined
+ *
+ * But if a local name (variable or method) is available, it would be used:
+ *
+ * it = 5
+ * [1, 2, 3].each { |x| p it }
+ * # Prints 5, 5, 5
+ *
+ * Blocks using +it+ can be nested:
+ *
+ * %w[test me].each { it.each_char { p it } }
+ * # Prints "t", "e", "s", "t", "m", "e"
+ *
+ * Blocks using +it+ are considered to have one parameter:
+ *
+ * p = proc { it**2 }
+ * l = lambda { it**2 }
+ * p.parameters # => [[:opt, nil]]
+ * p.arity # => 1
+ * l.parameters # => [[:req]]
+ * l.arity # => 1
+ *
+ * === Numbered parameters
+ *
+ * Numbered parameters are another way to name block parameters implicitly.
+ * Unlike +it+, numbered parameters allow to refer to several parameters
+ * in one block.
+ *
+ * %w[test me please].each { puts _1.upcase } # prints TEST, ME, PLEASE
+ * {a: 100, b: 200}.map { "#{_1} = #{_2}" } # => "a = 100", "b = 200"
+ *
* Parameter names from +_1+ to +_9+ are supported:
*
* [10, 20, 30].zip([40, 50, 60], [70, 80, 90]).map { _1 + _2 + _3 }
@@ -4279,11 +4346,16 @@ proc_ruby2_keywords(VALUE procval)
* [10, 20, 30].map { |x| _1**2 }
* # SyntaxError (ordinary parameter is defined)
*
+ * Numbered parameters can't be mixed with +it+ either:
+ *
+ * [10, 20, 30].map { _1 + it }
+ * # SyntaxError: `it` is not allowed when a numbered parameter is already used
+ *
* To avoid conflicts, naming local variables or method
- * arguments +_1+, +_2+ and so on, causes a warning.
+ * arguments +_1+, +_2+ and so on, causes an error.
*
- * _1 = 'test'
- * # warning: `_1' is reserved as numbered parameter
+ * _1 = 'test'
+ * # ^~ _1 is reserved for numbered parameters (SyntaxError)
*
* Using implicit numbered parameters affects block's arity:
*
@@ -4297,11 +4369,10 @@ proc_ruby2_keywords(VALUE procval)
* Blocks with numbered parameters can't be nested:
*
* %w[test me].each { _1.each_char { p _1 } }
- * # SyntaxError (numbered parameter is already used in outer block here)
+ * # numbered parameter is already used in outer block (SyntaxError)
* # %w[test me].each { _1.each_char { p _1 } }
* # ^~
*
- * Numbered parameters were introduced in Ruby 2.7.
*/