diff options
Diffstat (limited to 'doc/syntax')
| -rw-r--r-- | doc/syntax/assignment.rdoc | 4 | ||||
| -rw-r--r-- | doc/syntax/calling_methods.rdoc | 97 | ||||
| -rw-r--r-- | doc/syntax/comments.rdoc | 2 | ||||
| -rw-r--r-- | doc/syntax/control_expressions.rdoc | 2 | ||||
| -rw-r--r-- | doc/syntax/exceptions.rdoc | 2 | ||||
| -rw-r--r-- | doc/syntax/keywords.rdoc | 162 | ||||
| -rw-r--r-- | doc/syntax/layout.rdoc | 118 | ||||
| -rw-r--r-- | doc/syntax/literals.rdoc | 103 | ||||
| -rw-r--r-- | doc/syntax/methods.rdoc | 1 | ||||
| -rw-r--r-- | doc/syntax/pattern_matching.rdoc | 8 | ||||
| -rw-r--r-- | doc/syntax/refinements.rdoc | 69 |
11 files changed, 477 insertions, 91 deletions
diff --git a/doc/syntax/assignment.rdoc b/doc/syntax/assignment.rdoc index f45f5bc0ea..3988f82e5f 100644 --- a/doc/syntax/assignment.rdoc +++ b/doc/syntax/assignment.rdoc @@ -9,7 +9,7 @@ Assignment creates a local variable if the variable was not previously referenced. An assignment expression result is always the assigned value, including -{assignment methods}[rdoc-ref:syntax/assignment.rdoc@Assignment+Methods]. +{assignment methods}[rdoc-ref:@Assignment+Methods]. == Local Variable Names @@ -279,7 +279,7 @@ An uninitialized global variable has a value of +nil+. Ruby has some special globals that behave differently depending on context such as the regular expression match variables or that have a side-effect when -assigned to. See the {global variables documentation}[rdoc-ref:globals.rdoc] +assigned to. See the {global variables documentation}[rdoc-ref:language/globals.md] for details. == Assignment Methods diff --git a/doc/syntax/calling_methods.rdoc b/doc/syntax/calling_methods.rdoc index c2c6c61a10..a24c5fbf1f 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. @@ -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,6 +322,59 @@ Both are equivalent to: my_method(1, 2, 3) +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: + + class Name + def initialize(name) + @name = name + end + + def to_a = @name.split(' ') + end + + 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"> + +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. @@ -329,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: @@ -356,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: {first: "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>: diff --git a/doc/syntax/comments.rdoc b/doc/syntax/comments.rdoc index 00d19d588a..cb6829a984 100644 --- a/doc/syntax/comments.rdoc +++ b/doc/syntax/comments.rdoc @@ -170,7 +170,7 @@ In this mode, all values assigned to constants are made shareable. # shareable_constant_value: experimental_everything FOO = Set[1, 2, {foo: []}] - # same as FOO = Ractor.make_sharable(...) + # same as FOO = Ractor.make_shareable(...) # OR same as `FOO = Set[1, 2, {foo: [].freeze}.freeze].freeze` var = [{foo: []}] diff --git a/doc/syntax/control_expressions.rdoc b/doc/syntax/control_expressions.rdoc index 9126289389..3de6cd293f 100644 --- a/doc/syntax/control_expressions.rdoc +++ b/doc/syntax/control_expressions.rdoc @@ -255,7 +255,7 @@ Again, the +then+ and +else+ are optional. The result value of a +case+ expression is the last value executed in the expression. -Since Ruby 2.7, +case+ expressions also provide a more powerful experimental +Since Ruby 2.7, +case+ expressions also provide a more powerful pattern matching feature via the +in+ keyword: case {a: 1, b: 2, c: 3} diff --git a/doc/syntax/exceptions.rdoc b/doc/syntax/exceptions.rdoc index ac5ff78a95..cdf9d367a7 100644 --- a/doc/syntax/exceptions.rdoc +++ b/doc/syntax/exceptions.rdoc @@ -103,4 +103,4 @@ You may also run some code when an exception is not raised: # It will not return implicitly. end -NB : Without explicit +return+ in the +ensure+ block, +begin+/+end+ block will return the last evaluated statement before entering in the `ensure` block. +NB : Without explicit +return+ in the +ensure+ block, +begin+/+end+ block will return the last evaluated statement before entering in the +ensure+ block. diff --git a/doc/syntax/keywords.rdoc b/doc/syntax/keywords.rdoc new file mode 100644 index 0000000000..7c368205ef --- /dev/null +++ b/doc/syntax/keywords.rdoc @@ -0,0 +1,162 @@ += Keywords + +The following keywords are used by Ruby. + +__ENCODING__:: + The script encoding of the current file. See Encoding. + +__LINE__:: + The line number of this keyword in the current file. + +__FILE__:: + The path to the current file. + +BEGIN:: + Runs before any other code in the current file. See {miscellaneous + syntax}[rdoc-ref:syntax/miscellaneous.rdoc] + +END:: + Runs after any other code in the current file. See {miscellaneous + syntax}[rdoc-ref:syntax/miscellaneous.rdoc] + +alias:: + Creates an alias between two methods (and other things). See {modules and + classes syntax}[rdoc-ref:syntax/modules_and_classes.rdoc] + +and:: + Short-circuit Boolean and with lower precedence than <code>&&</code> + +begin:: + Starts an exception handling block. See {exceptions + syntax}[rdoc-ref:syntax/exceptions.rdoc] + +break:: + Leaves a block early. See {control expressions + syntax}[rdoc-ref:syntax/control_expressions.rdoc] + +case:: + Starts a +case+ expression. See {control expressions + syntax}[rdoc-ref:syntax/control_expressions.rdoc] + +class:: + Creates or opens a class. See {modules and classes + syntax}[rdoc-ref:syntax/modules_and_classes.rdoc] + +def:: + Defines a method. See {methods syntax}[rdoc-ref:syntax/methods.rdoc] + +defined?:: + Returns a string describing its argument. See {miscellaneous + syntax}[rdoc-ref:syntax/miscellaneous.rdoc] + +do:: + Starts a block. + +else:: + The unhandled condition in +case+, +if+ and +unless+ expressions. See + {control expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +elsif:: + An alternate condition for an +if+ expression. See {control + expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +end:: + The end of a syntax block. Used by classes, modules, methods, exception + handling and control expressions. + +ensure:: + Starts a section of code that is always run when an exception is raised. + See {exception handling}[rdoc-ref:syntax/exceptions.rdoc] + +false:: + Boolean false. See {literals}[rdoc-ref:syntax/literals.rdoc] + +for:: + A loop that is similar to using the +each+ method. See {control + expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +if:: + Used for +if+ and modifier +if+ statements. See {control + expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +in:: + Used to separate the iterable object and iterator variable in a +for+ loop. + See {control expressions}[rdoc-ref:syntax/control_expressions.rdoc] + It also serves as a pattern in a +case+ expression. + See {pattern matching}[rdoc-ref:syntax/pattern_matching.rdoc] + +module:: + Creates or opens a module. See {modules and classes + syntax}[rdoc-ref:syntax/modules_and_classes.rdoc] + +next:: + Skips the rest of the block. See {control + expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +nil:: + A false value usually indicating "no value" or "unknown". See + {literals}[rdoc-ref:syntax/literals.rdoc] + +not:: + Inverts the following boolean expression. Has a lower precedence than + <code>!</code> + +or:: + Boolean or with lower precedence than <code>||</code> + +redo:: + Restarts execution in the current block. See {control + expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +rescue:: + Starts an exception section of code in a +begin+ block. See {exception + handling}[rdoc-ref:syntax/exceptions.rdoc] + +retry:: + Retries an exception block. See {exception + handling}[rdoc-ref:syntax/exceptions.rdoc] + +return:: + Exits a method. See {methods}[rdoc-ref:syntax/methods.rdoc]. + If met in top-level scope, immediately stops interpretation of + the current file. + +self:: + The object the current method is attached to. See + {methods}[rdoc-ref:syntax/methods.rdoc] + +super:: + Calls the current method in a superclass. See + {methods}[rdoc-ref:syntax/methods.rdoc] + +then:: + Indicates the end of conditional blocks in control structures. See + {control expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +true:: + Boolean true. See {literals}[rdoc-ref:syntax/literals.rdoc] + +undef:: + Prevents a class or module from responding to a method call. + See {modules and classes}[rdoc-ref:syntax/modules_and_classes.rdoc] + +unless:: + Used for +unless+ and modifier +unless+ statements. See {control + expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +until:: + Creates a loop that executes until the condition is true. See + {control expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +when:: + A condition in a +case+ expression. See + {control expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +while:: + Creates a loop that executes while the condition is true. See + {control expressions}[rdoc-ref:syntax/control_expressions.rdoc] + +yield:: + Starts execution of the block sent to the current method. See + {methods}[rdoc-ref:syntax/methods.rdoc] + diff --git a/doc/syntax/layout.rdoc b/doc/syntax/layout.rdoc new file mode 100644 index 0000000000..31e51d9ff1 --- /dev/null +++ b/doc/syntax/layout.rdoc @@ -0,0 +1,118 @@ += Code Layout + +Expressions in Ruby are separated by line breaks: + + x = 1 + y = 2 + z = x + y + +Line breaks are also used as logical separators of the headers of some control structures from their bodies: + + if z > 3 # line break ends the condition and starts the body + puts "more" + end + + while x < 3 # line break ends the condition and starts the body + x += 1 + end + +<tt>;</tt> can be used as an expressions separator instead of a line break: + + x = 1; y = 2; z = x + y + if z > 3; puts "more"; end + +Traditionally, expressions separated by <tt>;</tt> are used only in short scripts and experiments. + +In some control structures, there is an optional keyword that can be used instead of a line break to separate their elements: + + # if, elsif, until and case ... when: 'then' is an optional separator: + + if z > 3 then puts "more" end + + case x + when Numeric then "number" + when String then "string" + else "object" + end + + # while and until: 'do' is an optional separator + while x < 3 do x +=1 end + +Also, line breaks can be skipped in some places where it doesn't create any ambiguity. Note in the example above: no line break needed before +end+, just as no line break needed after +else+. + +== Breaking expressions in lines + +One expression might be split into several lines when each line can be unambiguously identified as "incomplete" without the next one. + +These works: + + x = # incomplete without something after = + 1 + # incomplete without something after + + 2 + + File.read "test.txt", # incomplete without something after , + enconding: "utf-8" + +These would not: + + # unintended interpretation: + x = 1 # already complete expression + + 2 # interpreted as a separate +2 + + # syntax error: + File.read "test.txt" # already complete expression + , encoding: "utf-8" # attempt to parse as a new expression, SyntaxError + +The exceptions to the rule are lines starting with <tt>.</tt> ("leading dot" style of method calls) or logical operators <tt>&&</tt>/<tt>||</tt> and <tt>and</tt>/<tt>or</tt>: + + # OK, interpreted as a chain of calls + File.read('test.txt') + .strip("\n") + .split("\t") + .sort + + # OK, interpreted as a chain of logical operators: + File.empty?('test.txt') + || File.size('test.txt') < 10 + || File.read('test.txt').strip.empty? + +If the expressions is broken into multiple lines in any of the ways described above, comments between separate lines are allowed: + + sum = base_salary + + # see "yearly bonuses section" + yearly_bonus(year) + + # per-employee coefficient is described + # in another module + personal_coeff(employee) + + # We want to short-circuit on empty files + File.empty?('test.txt') + # Or almost empty ones + || File.size('test.txt') < 10 + # Otherwise we check if it is full of spaces + || File.read('test.txt').strip.empty? + +Finally, the code can explicitly tell Ruby that the expression is continued on the next line with <tt>\\</tt>: + + # Unusual, but works + File.read "test.txt" \ + , encoding: "utf-8" + + # More regular usage (joins the strings on parsing instead + # of concatenating them in runtime, as + would do): + TEXT = "One pretty long line" \ + "one more long line" \ + "one other line of the text" + +The <tt>\\</tt> works as a parse time line break escape, so with it, comments can not be inserted between the lines: + + TEXT = "line 1" \ + # here would be line 2: + "line 2" + + # This is interpreted as if there was no line break where \ is, + # i.e. the same as + TEXT = "line 1" # here would be line 2: + "line 2" + + puts TEXT #=> "line 1" diff --git a/doc/syntax/literals.rdoc b/doc/syntax/literals.rdoc index 6d681419a2..c876558d4e 100644 --- a/doc/syntax/literals.rdoc +++ b/doc/syntax/literals.rdoc @@ -3,7 +3,7 @@ Literals create objects you can use in your program. Literals include: * {Boolean and Nil Literals}[#label-Boolean+and+Nil+Literals] -* {Number Literals}[#label-Number+Literals] +* {Numeric Literals}[#label-Numeric+Literals] * {Integer Literals}[#label-Integer+Literals] * {Float Literals}[#label-Float+Literals] @@ -36,7 +36,7 @@ Literals create objects you can use in your program. Literals include: +true+ is a true value. All objects except +nil+ and +false+ evaluate to a true value in conditional expressions. -== Number Literals +== \Numeric Literals === \Integer Literals @@ -136,49 +136,9 @@ Also \Rational numbers may be imaginary numbers. 12.3ir #=> Syntax error -== Strings +== \String Literals -=== Escape Sequences - -Some characters can be represented as escape sequences in -double-quoted strings, -character literals, -here document literals (non-quoted, double-quoted, and with backticks), -double-quoted symbols, -double-quoted symbol keys in Hash literals, -Regexp literals, and -several percent literals (<tt>%</tt>, <tt>%Q,</tt> <tt>%W</tt>, <tt>%I</tt>, <tt>%r</tt>, <tt>%x</tt>). - -They allow escape sequences such as <tt>\n</tt> for -newline, <tt>\t</tt> for tab, etc. The full list of supported escape -sequences are as follows: - - \a bell, ASCII 07h (BEL) - \b backspace, ASCII 08h (BS) - \t horizontal tab, ASCII 09h (TAB) - \n newline (line feed), ASCII 0Ah (LF) - \v vertical tab, ASCII 0Bh (VT) - \f form feed, ASCII 0Ch (FF) - \r carriage return, ASCII 0Dh (CR) - \e escape, ASCII 1Bh (ESC) - \s space, ASCII 20h (SPC) - \\ backslash, \ - \nnn octal bit pattern, where nnn is 1-3 octal digits ([0-7]) - \xnn hexadecimal bit pattern, where nn is 1-2 hexadecimal digits ([0-9a-fA-F]) - \unnnn Unicode character, where nnnn is exactly 4 hexadecimal digits ([0-9a-fA-F]) - \u{nnnn ...} Unicode character(s), where each nnnn is 1-6 hexadecimal digits ([0-9a-fA-F]) - \cx or \C-x control character, where x is an ASCII printable character - \M-x meta character, where x is an ASCII printable character - \M-\C-x meta control character, where x is an ASCII printable character - \M-\cx same as above - \c\M-x same as above - \c? or \C-? delete, ASCII 7Fh (DEL) - \<newline> continuation line (empty string) - -The last one, <tt>\<newline></tt>, represents an empty string instead of a character. -It is used to fold a line in a string. - -=== Double-quoted \String Literals +=== Double-Quoted \String Literals The most common way of writing strings is using <tt>"</tt>: @@ -213,7 +173,7 @@ See also: * {% and %Q: Interpolable String Literals}[#label-25+and+-25Q-3A+Interpolable+String+Literals] -=== Single-quoted \String Literals +=== Single-Quoted \String Literals Interpolation may be disabled by escaping the "#" character or using single-quoted strings: @@ -244,7 +204,7 @@ Any combination of adjacent single-quote, double-quote, percent strings will be concatenated as long as a percent-string is not last. %q{a} 'b' "c" #=> "abc" - "a" 'b' %q{c} #=> NameError: uninitialized constant q + "a" 'b' %q{c} #=> NoMethodError: undefined method 'q' for main === Character Literal @@ -265,6 +225,46 @@ that corresponds to a single codepoint in the script encoding: ?\C-\M-a #=> "\x81", same as above ?あ #=> "あ" +=== Escape Sequences + +Some characters can be represented as escape sequences in +double-quoted strings, +character literals, +here document literals (non-quoted, double-quoted, and with backticks), +double-quoted symbols, +double-quoted symbol keys in Hash literals, +Regexp literals, and +several percent literals (<tt>%</tt>, <tt>%Q</tt>, <tt>%W</tt>, <tt>%I</tt>, <tt>%r</tt>, <tt>%x</tt>). + +They allow escape sequences such as <tt>\n</tt> for +newline, <tt>\t</tt> for tab, etc. The full list of supported escape +sequences are as follows: + + \a bell, ASCII 07h (BEL) + \b backspace, ASCII 08h (BS) + \t horizontal tab, ASCII 09h (TAB) + \n newline (line feed), ASCII 0Ah (LF) + \v vertical tab, ASCII 0Bh (VT) + \f form feed, ASCII 0Ch (FF) + \r carriage return, ASCII 0Dh (CR) + \e escape, ASCII 1Bh (ESC) + \s space, ASCII 20h (SPC) + \\ backslash, \ + \nnn octal bit pattern, where nnn is 1-3 octal digits ([0-7]) + \xnn hexadecimal bit pattern, where nn is 1-2 hexadecimal digits ([0-9a-fA-F]) + \unnnn Unicode character, where nnnn is exactly 4 hexadecimal digits ([0-9a-fA-F]) + \u{nnnn ...} Unicode character(s), where each nnnn is 1-6 hexadecimal digits ([0-9a-fA-F]) + \cx or \C-x control character, where x is an ASCII printable character + \M-x meta character, where x is an ASCII printable character + \M-\C-x meta control character, where x is an ASCII printable character + \M-\cx same as above + \c\M-x same as above + \c? or \C-? delete, ASCII 7Fh (DEL) + \<newline> continuation line (empty string) + +The last one, <tt>\<newline></tt>, represents an empty string instead of a character. +It is used to fold a line in a string. + === Here Document Literals If you are writing a large block of text you may use a "here document" or @@ -513,7 +513,7 @@ The created string is the same as if you created it with single quotes: %q{foo{bar}baz} # => "foo{bar}baz" # braces can be nested. %q<foo<bar>baz> # => "foo<bar>baz" # angle brackets can be nested. -This is similar to single-quoted string but only backslashs and +This is similar to single-quoted string but only backslashes and the specified delimiters can be escaped with a backslash. === <tt>% and %Q</tt>: Interpolable String Literals @@ -547,6 +547,13 @@ with <tt>%w</tt> (non-interpolable) or <tt>%W</tt> (interpolable): # (not nested array). %w[foo[bar baz]qux] # => ["foo[bar", "baz]qux"] +The interpolated string is treated as a single word even if it contains +whitespace. + + s = "bar baz" + %W[foo #{s} zot] #=> ["foo", "bar baz", "zot"] + %W[foo #{"bar baz zot"} qux] # => ["foo", "bar baz zot", "qux"] + The following characters are considered as white spaces to separate words: * space, ASCII 20h (SPC) @@ -590,7 +597,7 @@ You can write a symbol with <tt>%s</tt>: This is non-interpolable. No interpolation allowed. -Only backslashs and the specified delimiters can be escaped with a backslash. +Only backslashes and the specified delimiters can be escaped with a backslash. === <tt>%r</tt>: Regexp Literals diff --git a/doc/syntax/methods.rdoc b/doc/syntax/methods.rdoc index 8dafa6bb0c..14810a188f 100644 --- a/doc/syntax/methods.rdoc +++ b/doc/syntax/methods.rdoc @@ -100,6 +100,7 @@ operators. <code>/</code> :: divide <code>%</code> :: modulus division, String#% <code>&</code> :: AND +<code>|</code> :: OR <code>^</code> :: XOR (exclusive OR) <code>>></code> :: right-shift <code><<</code> :: left-shift, append diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc index 6a30380f46..06aae26d49 100644 --- a/doc/syntax/pattern_matching.rdoc +++ b/doc/syntax/pattern_matching.rdoc @@ -221,7 +221,7 @@ For hash patterns, even a simpler form exists: key-only specification (without a end #=> "matched: 1" -Binding works for nested patterns as well: +\Binding works for nested patterns as well: case {name: 'John', friends: [{name: 'Jane'}, {name: 'Rajesh'}]} in name:, friends: [{name: first_friend}, *] @@ -247,17 +247,17 @@ The "rest" part of a pattern also can be bound to a variable: else "not matched" end - #=> "matched: 1, {:b=>2, :c=>3}" + #=> "matched: 1, {b: 2, c: 3}" -Binding to variables currently does NOT work for alternative patterns joined with <code>|</code>: +\Binding to variables currently does NOT work for alternative patterns joined with <code>|</code>: case {a: 1, b: 2} in {a: } | Array + # ^ SyntaxError (variable capture in alternative pattern) "matched: #{a}" else "not matched" end - # SyntaxError (illegal variable in alternative pattern (a)) Variables that start with <code>_</code> are the only exclusions from this rule: diff --git a/doc/syntax/refinements.rdoc b/doc/syntax/refinements.rdoc index 17d5e67c21..80595eb445 100644 --- a/doc/syntax/refinements.rdoc +++ b/doc/syntax/refinements.rdoc @@ -210,43 +210,58 @@ all refinements from the same module are active when a refined method == Method Lookup -When looking up a method for an instance of class +C+ Ruby checks: +Method lookup in Ruby is based on the ancestor chain. You can see the +ancestor chain for any object in Ruby by doing: -* If refinements are active for +C+, in the reverse order they were activated: - * The prepended modules from the refinement for +C+ - * The refinement for +C+ - * The included modules from the refinement for +C+ -* The prepended modules of +C+ -* +C+ -* The included modules of +C+ + object.singleton_class.ancestors + # or, if the object does not support a singleton class: + object.class.ancestors -If no method was found at any point this repeats with the superclass of +C+. +The ancestor chain is constructed as follows: -Note that methods in a subclass have priority over refinements in a -superclass. For example, if the method <code>/</code> is defined in a -refinement for Numeric <code>1 / 2</code> invokes the original Integer#/ -because Integer is a subclass of Numeric and is searched before the refinements -for the superclass Numeric. Since the method <code>/</code> is also present -in child +Integer+, the method lookup does not move up to the superclass. +* Subclasses are before superclasses in the ancestor chain +* Prepended modules are before the class they prepend in the ancestor + chain, in reverse order in which they were prepended. +* Included modules are after the class they are included in in the + ancestor chain, in reverse order in which they were included. + +When looking up a method for an object, Ruby goes through each ancestor: + +* If the class/module has been refined, Ruby will consider the refinements + activated at the point the method was called, in reverse order of + activation. +* Otherwise, Ruby will check the methods of the class/module itself. + +If no method was found at either point this repeats with the next +ancestor. -However, if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code> +Note that methods in a earlier ancestor have priority over refinements in a +later ancestor. For example, if the method <code>/</code> is defined in a +refinement for Numeric <code>1 / 2</code> invokes the original Integer#/ +because Integer is a comes before Numeric in the ancestor chain. However, +if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code> invokes that method since +foo+ does not exist on Integer. == +super+ -When +super+ is invoked method lookup checks: +When +super+ is invoked, method lookup starts: + +* If the method is in a refinement, at the refined class or module +* Otherwise, at the next ancestor + +Method lookup then proceeds as described in the Method Lookup section +above. -* The included modules of the current class. Note that the current class may - be a refinement. -* If the current class is a refinement, the method lookup proceeds as in the - Method Lookup section above. -* If the current class has a direct superclass, the method proceeds as in the - Method Lookup section above using the superclass. +Refinements activated at the call site of a refinement method do not +affect +super+ inside that method. Only refinements activated at the +point +super+ was called affect method lookup for that +super+ call. +You cannot use refinements to insert into the middle of a method +lookup chain, only to insert at the start of a method lookup chain, +unless you control the +super+ call sites. -Note that +super+ in a method of a refinement invokes the method in the -refined class even if there is another refinement which has been activated in -the same context. This is only true for +super+ in a method of a refinement, it -does not apply to +super+ in a method in a module that is included in a refinement. +Note that if you refine a module, the refinement method can call +super+ +to call the method in the module, but the method in the module cannot +call +super+ to continue the method lookup process to further ancestors. == Methods Introspection |
