diff options
Diffstat (limited to 'doc/syntax')
| -rw-r--r-- | doc/syntax/assignment.rdoc | 14 | ||||
| -rw-r--r-- | doc/syntax/calling_methods.rdoc | 101 | ||||
| -rw-r--r-- | doc/syntax/comments.rdoc | 4 | ||||
| -rw-r--r-- | doc/syntax/control_expressions.rdoc | 72 | ||||
| -rw-r--r-- | doc/syntax/exceptions.rdoc | 10 | ||||
| -rw-r--r-- | doc/syntax/keywords.rdoc | 162 | ||||
| -rw-r--r-- | doc/syntax/layout.rdoc | 118 | ||||
| -rw-r--r-- | doc/syntax/literals.rdoc | 217 | ||||
| -rw-r--r-- | doc/syntax/methods.rdoc | 1 | ||||
| -rw-r--r-- | doc/syntax/modules_and_classes.rdoc | 28 | ||||
| -rw-r--r-- | doc/syntax/operators.rdoc | 75 | ||||
| -rw-r--r-- | doc/syntax/pattern_matching.rdoc | 40 | ||||
| -rw-r--r-- | doc/syntax/refinements.rdoc | 7 |
13 files changed, 727 insertions, 122 deletions
diff --git a/doc/syntax/assignment.rdoc b/doc/syntax/assignment.rdoc index 1321bbf3ac..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 @@ -107,7 +107,7 @@ Rather than printing "true" you receive a NameError, "undefined local variable or method `a'". Since ruby parses the bare +a+ left of the +if+ first and has not yet seen an assignment to +a+ it assumes you wish to call a method. Ruby then sees the assignment to +a+ and will assume you are referencing a local -method. +variable. The confusion comes from the out-of-order execution of the expression. First the local variable is assigned-to then you attempt to call a nonexistent @@ -162,9 +162,7 @@ Here is an example of instance variable usage: p object1.value # prints "some value" p object2.value # prints "other value" -An uninitialized instance variable has a value of +nil+. If you run Ruby with -warnings enabled, you will get a warning when accessing an uninitialized -instance variable. +An uninitialized instance variable has a value of +nil+. The +value+ method has access to the value set by the +initialize+ method, but only for the same object. @@ -281,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 @@ -403,6 +401,10 @@ assigning. This is similar to multiple assignment: p a # prints [1, 2, 3] + b = *1 + + p b # prints [1] + You can splat anywhere in the right-hand side of the assignment: a = 1, *[2, 3] 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>: diff --git a/doc/syntax/comments.rdoc b/doc/syntax/comments.rdoc index dbc7816984..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: []}] @@ -196,7 +196,7 @@ The method Module#const_set is not affected. In this mode, all values assigned to constants are deeply copied and made shareable. It is safer mode than +experimental_everything+. - # shareable_constant_value: experimental_everything + # shareable_constant_value: experimental_copy var = [{foo: []}] var.frozen? # => false (assignment was made to local variable) X = var # => calls `Ractor.make_shareable(var, copy: true)` diff --git a/doc/syntax/control_expressions.rdoc b/doc/syntax/control_expressions.rdoc index df3b5ced38..3de6cd293f 100644 --- a/doc/syntax/control_expressions.rdoc +++ b/doc/syntax/control_expressions.rdoc @@ -189,7 +189,7 @@ The same is true for +unless+. The +case+ expression can be used in two ways. The most common way is to compare an object against multiple patterns. The -patterns are matched using the +===+ method which is aliased to +==+ on +patterns are matched using the <tt>===</tt> method which is aliased to <tt>==</tt> on Object. Other classes must override it to give meaningful behavior. See Module#=== and Regexp#=== for examples. @@ -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} @@ -569,3 +569,71 @@ evaluated on the following iteration: Here, the flip-flop turns on when +value+ equals 2, but doesn't turn off on the same iteration. The `off' condition isn't evaluated until the following iteration and +value+ will never be two again. + +== throw/catch + ++throw+ and +catch+ are used to implement non-local control flow in Ruby. They +operate similarly to exceptions, allowing control to pass directly from the +place where +throw+ is called to the place where the matching +catch+ is +called. The main difference between +throw+/+catch+ and the use of exceptions +is that +throw+/+catch+ are designed for expected non-local control flow, +while exceptions are designed for exceptional control flow situations, such +as handling unexpected errors. + +When using +throw+, you provide 1-2 arguments. The first argument is the +value for the matching +catch+. The second argument is optional (defaults to ++nil+), and will be the value that +catch+ returns if there is a matching ++throw+ inside the +catch+ block. If no matching +throw+ method is called +inside a +catch+ block, the +catch+ method returns the return value of the +block passed to it. + + def a(n) + throw :d, :a if n == 0 + b(n) + end + + def b(n) + throw :d, :b if n == 1 + c(n) + end + + def c(n) + throw :d if n == 2 + end + + 4.times.map do |i| + catch(:d) do + a(i) + :default + end + end + # => [:a, :b, nil, :default] + +If the first argument you pass to +throw+ is not handled by a matching ++catch+, an UncaughtThrowError exception will be raised. This is because ++throw+/+catch+ should only be used for expected control flow changes, so +using a value that is not already expected is an error. + ++throw+/+catch+ are implemented as Kernel methods (Kernel#throw and +Kernel#catch), not as keywords. So they are not usable directly if you are +in a BasicObject context. You can use Kernel.throw and Kernel.catch in +this case: + + BasicObject.new.instance_exec do + def a + b + end + + def b + c + end + + def c + ::Kernel.throw :d, :e + end + + result = ::Kernel.catch(:d) do + a + end + result # => :e + end diff --git a/doc/syntax/exceptions.rdoc b/doc/syntax/exceptions.rdoc index 31e2f0175c..cdf9d367a7 100644 --- a/doc/syntax/exceptions.rdoc +++ b/doc/syntax/exceptions.rdoc @@ -86,7 +86,7 @@ To always run some code whether an exception was raised or not, use +ensure+: rescue # ... ensure - # this always runs + # this always runs BUT does not implicitly return the last evaluated statement. end You may also run some code when an exception is not raised: @@ -96,7 +96,11 @@ You may also run some code when an exception is not raised: rescue # ... else - # this runs only when no exception was raised + # this runs only when no exception was raised AND return the last evaluated statement ensure - # ... + # this always runs. + # It is evaluated after the evaluation of either the `rescue` or the `else` block. + # 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. 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..f07447587b --- /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 also used as logical separators of the headers of some of 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> is 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 5e10e6a140..87a891bf2d 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,9 +136,9 @@ Also \Rational numbers may be imaginary numbers. 12.3ir #=> Syntax error -== Strings +== \String Literals -=== \String Literals +=== Double-Quoted \String Literals The most common way of writing strings is using <tt>"</tt>: @@ -150,35 +150,14 @@ Any internal <tt>"</tt> must be escaped: "This string has a quote: \". As you can see, it is escaped" -Double-quote strings allow escaped characters 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) +Double-quoted strings allow escape sequences described in +{Escape Sequences}[#label-Escape+Sequences]. -Any other character following a backslash is interpreted as the +In a double-quoted string, +any other character following a backslash is interpreted as the character itself. -Double-quote strings allow interpolation of other values using +Double-quoted strings allow interpolation of other values using <tt>#{...}</tt>: "One plus one is two: #{1 + 1}" @@ -190,8 +169,14 @@ You can also use <tt>#@foo</tt>, <tt>#@@foo</tt> and <tt>#$foo</tt> as a shorthand for, respectively, <tt>#{ @foo }</tt>, <tt>#{ @@foo }</tt> and <tt>#{ $foo }</tt>. +See also: + +* {% and %Q: Interpolable String Literals}[#label-25+and+-25Q-3A+Interpolable+String+Literals] + +=== Single-Quoted \String Literals + Interpolation may be disabled by escaping the "#" character or using -single-quote strings: +single-quoted strings: '#{1 + 1}' #=> "\#{1 + 1}" @@ -199,6 +184,16 @@ In addition to disabling interpolation, single-quoted strings also disable all escape sequences except for the single-quote (<tt>\'</tt>) and backslash (<tt>\\\\</tt>). +In a single-quoted string, +any other character following a backslash is interpreted as is: +a backslash and the character itself. + +See also: + +* {%q: Non-Interpolable String Literals}[#label-25q-3A+Non-Interpolable+String+Literals] + +=== Literal String Concatenation + Adjacent string literals are automatically concatenated by the interpreter: "con" "cat" "en" "at" "ion" #=> "concatenation" @@ -209,12 +204,14 @@ 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 There is also a character literal notation to represent single character strings, which syntax is a question mark (<tt>?</tt>) -followed by a single character or escape sequence that corresponds to -a single codepoint in the script encoding: +followed by a single character or escape sequence (except continuation line) +that corresponds to a single codepoint in the script encoding: ?a #=> "a" ?abc #=> SyntaxError @@ -228,10 +225,45 @@ a single codepoint in the script encoding: ?\C-\M-a #=> "\x81", same as above ?あ #=> "あ" -See also: +=== Escape Sequences -* {%q: Non-Interpolable String Literals}[#label-25q-3A+Non-Interpolable+String+Literals] -* {% and %Q: Interpolable String Literals}[#label-25+and+-25Q-3A+Interpolable+String+Literals] +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 @@ -277,9 +309,16 @@ the content. Note that empty lines and lines consisting solely of literal tabs and spaces will be ignored for the purposes of determining indentation, but escaped tabs and spaces are considered non-indentation characters. -A heredoc allows interpolation and escaped characters. You may disable -interpolation and escaping by surrounding the opening identifier with single -quotes: +For the purpose of measuring an indentation, a horizontal tab is regarded as a +sequence of one to eight spaces such that the column position corresponding to +its end is a multiple of eight. The amount to be removed is counted in terms +of the number of spaces. If the boundary appears in the middle of a tab, that +tab is not removed. + +A heredoc allows interpolation and the escape sequences described in +{Escape Sequences}[#label-Escape+Sequences]. +You may disable interpolation and the escaping by surrounding the opening +identifier with single quotes: expected_result = <<-'EXPECTED' One plus one is #{1 + 1} @@ -320,12 +359,15 @@ details on what symbols are and when ruby creates them internally. You may reference a symbol using a colon: <tt>:my_symbol</tt>. -You may also create symbols by interpolation: +You may also create symbols by interpolation and escape sequences described in +{Escape Sequences}[#label-Escape+Sequences] with double-quotes: :"my_symbol1" :"my_symbol#{1 + 1}" + :"foo\sbar" -Like strings, a single-quote may be used to disable interpolation: +Like strings, a single-quote may be used to disable interpolation and +escape sequences: :'my_symbol#{1 + 1}' #=> :"my_symbol\#{1 + 1}" @@ -408,9 +450,9 @@ slash (<tt>'/'</tt>) characters: re = /foo/ # => /foo/ re.class # => Regexp -The trailing slash may be followed by one or more _flag_ characters -that modify the behavior. -See {Regexp options}[rdoc-ref:Regexp@Options] for details. +The trailing slash may be followed by one or more modifiers characters +that set modes for the regexp. +See {Regexp modes}[rdoc-ref:Regexp@Modes] for details. Interpolation may be used inside regular expressions along with escaped characters. Note that a regular expression may require additional escaped @@ -445,7 +487,12 @@ may use these paired delimiters: * <tt>(</tt> and <tt>)</tt>. * <tt>{</tt> and <tt>}</tt>. * <tt><</tt> and <tt>></tt>. -* Any other character, as both beginning and ending delimiters. +* Non-alphanumeric ASCII character except above, as both beginning and ending delimiters. + +The delimiters can be escaped with a backslash. +However, the first four pairs (brackets, parenthesis, braces, and +angle brackets) are allowed without backslash as far as they are correctly +paired. These are demonstrated in the next section. @@ -454,13 +501,20 @@ These are demonstrated in the next section. You can write a non-interpolable string with <tt>%q</tt>. The created string is the same as if you created it with single quotes: - %[foo bar baz] # => "foo bar baz" # Using []. - %(foo bar baz) # => "foo bar baz" # Using (). - %{foo bar baz} # => "foo bar baz" # Using {}. - %<foo bar baz> # => "foo bar baz" # Using <>. - %|foo bar baz| # => "foo bar baz" # Using two |. - %:foo bar baz: # => "foo bar baz" # Using two :. + %q[foo bar baz] # => "foo bar baz" # Using []. + %q(foo bar baz) # => "foo bar baz" # Using (). + %q{foo bar baz} # => "foo bar baz" # Using {}. + %q<foo bar baz> # => "foo bar baz" # Using <>. + %q|foo bar baz| # => "foo bar baz" # Using two |. + %q:foo bar baz: # => "foo bar baz" # Using two :. %q(1 + 1 is #{1 + 1}) # => "1 + 1 is \#{1 + 1}" # No interpolation. + %q[foo[bar]baz] # => "foo[bar]baz" # brackets can be nested. + %q(foo(bar)baz) # => "foo(bar)baz" # parenthesis can be nested. + %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 backslashes and +the specified delimiters can be escaped with a backslash. === <tt>% and %Q</tt>: Interpolable String Literals @@ -470,30 +524,63 @@ or with its alias <tt>%</tt>: %[foo bar baz] # => "foo bar baz" %(1 + 1 is #{1 + 1}) # => "1 + 1 is 2" # Interpolation. +This is similar to double-quoted string. +It allow escape sequences described in +{Escape Sequences}[#label-Escape+Sequences]. +Other escaped characters (a backslash followed by a character) are +interpreted as the character. + === <tt>%w and %W</tt>: String-Array Literals -You can write an array of strings with <tt>%w</tt> (non-interpolable) -or <tt>%W</tt> (interpolable): +You can write an array of strings as whitespace-separated words +with <tt>%w</tt> (non-interpolable) or <tt>%W</tt> (interpolable): %w[foo bar baz] # => ["foo", "bar", "baz"] %w[1 % *] # => ["1", "%", "*"] # Use backslash to embed spaces in the strings. %w[foo\ bar baz\ bat] # => ["foo bar", "baz bat"] + %W[foo\ bar baz\ bat] # => ["foo bar", "baz bat"] %w(#{1 + 1}) # => ["\#{1", "+", "1}"] %W(#{1 + 1}) # => ["2"] + # The nested delimiters evaluated to a flat array of strings + # (not nested array). + %w[foo[bar baz]qux] # => ["foo[bar", "baz]qux"] + +The following characters are considered as white spaces to separate words: + +* space, ASCII 20h (SPC) +* form feed, ASCII 0Ch (FF) +* newline (line feed), ASCII 0Ah (LF) +* carriage return, ASCII 0Dh (CR) +* horizontal tab, ASCII 09h (TAB) +* vertical tab, ASCII 0Bh (VT) + +The white space characters can be escaped with a backslash to make them +part of a word. + +<tt>%W</tt> allow escape sequences described in +{Escape Sequences}[#label-Escape+Sequences]. +However the continuation line <tt>\<newline></tt> is not usable because +it is interpreted as the escaped newline described above. + === <tt>%i and %I</tt>: Symbol-Array Literals -You can write an array of symbols with <tt>%i</tt> (non-interpolable) -or <tt>%I</tt> (interpolable): +You can write an array of symbols as whitespace-separated words +with <tt>%i</tt> (non-interpolable) or <tt>%I</tt> (interpolable): %i[foo bar baz] # => [:foo, :bar, :baz] %i[1 % *] # => [:"1", :%, :*] # Use backslash to embed spaces in the symbols. %i[foo\ bar baz\ bat] # => [:"foo bar", :"baz bat"] + %I[foo\ bar baz\ bat] # => [:"foo bar", :"baz bat"] %i(#{1 + 1}) # => [:"\#{1", :+, :"1}"] %I(#{1 + 1}) # => [:"2"] +The white space characters and its escapes are interpreted as the same as +string-array literals described in +{%w and %W: String-Array Literals}[#label-25w+and+-25W-3A+String-Array+Literals]. + === <tt>%s</tt>: Symbol Literals You can write a symbol with <tt>%s</tt>: @@ -501,6 +588,10 @@ You can write a symbol with <tt>%s</tt>: %s[foo] # => :foo %s[foo bar] # => :"foo bar" +This is non-interpolable. +No interpolation allowed. +Only backslashes and the specified delimiters can be escaped with a backslash. + === <tt>%r</tt>: Regexp Literals You can write a regular expression with <tt>%r</tt>; @@ -517,12 +608,18 @@ A few "symmetrical" character pairs may be used as delimiters: %r(foo) # => /foo/ %r<foo> # => /foo/ -The trailing delimiter may be followed by one or more _flag_ characters -that modify the behavior. -See {Regexp options}[rdoc-ref:Regexp@Options] for details. +The trailing delimiter may be followed by one or more modifier characters +that set modes for the regexp. +See {Regexp modes}[rdoc-ref:Regexp@Modes] for details. === <tt>%x</tt>: Backtick Literals You can write and execute a shell command with <tt>%x</tt>: - %x(echo 1) # => "1\n" + %x(echo 1) # => "1\n" + %x[echo #{1 + 2}] # => "3\n" + %x[echo \u0030] # => "0\n" + +This is interpolable. +<tt>%x</tt> allow escape sequences described in +{Escape Sequences}[#label-Escape+Sequences]. 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/modules_and_classes.rdoc b/doc/syntax/modules_and_classes.rdoc index 024815a5a6..9e05c5c774 100644 --- a/doc/syntax/modules_and_classes.rdoc +++ b/doc/syntax/modules_and_classes.rdoc @@ -40,9 +40,9 @@ functionality: remove_method :my_method end -Reopening classes is a very powerful feature of Ruby, but it is best to only -reopen classes you own. Reopening classes you do not own may lead to naming -conflicts or difficult to diagnose bugs. +Reopening modules (or classes) is a very powerful feature of Ruby, but it is +best to only reopen modules you own. Reopening modules you do not own may lead +to naming conflicts or difficult to diagnose bugs. == Nesting @@ -259,6 +259,28 @@ includes a minimum of built-in methods. You can use BasicObject to create an independent inheritance structure. See the BasicObject documentation for further details. +Just like modules, classes can also be reopened. You can omit its superclass +when you reopen a class. Specifying a different superclass than the previous +definition will raise an error. + + class C + end + + class D < C + end + + # OK + class D < C + end + + # OK + class D + end + + # TypeError: superclass mismatch for class D + class D < String + end + == Inheritance Any method defined on a class is callable from its subclass: diff --git a/doc/syntax/operators.rdoc b/doc/syntax/operators.rdoc new file mode 100644 index 0000000000..d3045ac99e --- /dev/null +++ b/doc/syntax/operators.rdoc @@ -0,0 +1,75 @@ += Operators + +In Ruby, operators such as <code>+</code>, are defined as methods on the class. +Literals[rdoc-ref:syntax/literals.rdoc] define their methods within the lower +level, C language. String class, for example. + +Ruby objects can define or overload their own implementation for most operators. + +Here is an example: + + class Foo < String + def +(str) + self.concat(str).concat("another string") + end + end + + foobar = Foo.new("test ") + puts foobar + "baz " + +This prints: + + test baz another string + +What operators are available is dependent on the implementing class. + +== Operator Behavior + +How a class behaves to a given operator is specific to that class, since +operators are method implementations. + +When using an operator, it's the expression on the left-hand side of the +operation that specifies the behavior. + + 'a' * 3 #=> "aaa" + 3 * 'a' # TypeError: String can't be coerced into Integer + +== Logical Operators + +Logical operators are not methods, and therefore cannot be +redefined/overloaded. They are tokenized at a lower level. + +Short-circuit logical operators (<code>&&</code>, <code>||</code>, +<code>and</code>, and <code>or</code>) do not always result in a boolean value. +Similar to blocks, it's the last evaluated expression that defines the result +of the operation. + +=== <code>&&</code>, <code>and</code> + +Both <code>&&</code>/<code>and</code> operators provide short-circuiting by executing each +side of the operator, left to right, and stopping at the first occurrence of a +falsey expression. The expression that defines the result is the last one +executed, whether it be the final expression, or the first occurrence of a falsey +expression. + +Some examples: + + true && 9 && "string" #=> "string" + (1 + 2) && nil && "string" #=> nil + (a = 1) && (b = false) && (c = "string") #=> false + + puts a #=> 1 + puts b #=> false + puts c #=> nil + +In this last example, <code>c</code> was initialized, but not defined. + +=== <code>||</code>, <code>or</code> + +The means by which <code>||</code>/<code>or</code> short-circuits, is to return the result of +the first expression that is truthy. + +Some examples: + + (1 + 2) || true || "string" #=> 3 + false || nil || "string" #=> "string" diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc index b7d614770c..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: @@ -415,9 +415,15 @@ Additionally, when matching custom classes, the expected class can be specified end #=> "matched: 1" +These core and library classes implement deconstruction: + +* MatchData#deconstruct and MatchData#deconstruct_keys; +* Time#deconstruct_keys, Date#deconstruct_keys, DateTime#deconstruct_keys. + == Guard clauses -+if+ can be used to attach an additional condition (guard clause) when the pattern matches. This condition may use bound variables: ++if+ can be used to attach an additional condition (guard clause) when the pattern matches in +case+/+in+ expressions. +This condition may use bound variables: case [1, 2] in a, b if b == a*2 @@ -445,28 +451,10 @@ Additionally, when matching custom classes, the expected class can be specified end #=> "matched" -== Current feature status - -As of Ruby 3.1, find patterns are considered _experimental_: its syntax can change in the future. Every time you use these features in code, a warning will be printed: - - [0] => [*, 0, *] - # warning: Find pattern is experimental, and the behavior may change in future versions of Ruby! - # warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby! - -To suppress this warning, one may use the Warning::[]= method: - - Warning[:experimental] = false - eval('[0] => [*, 0, *]') - # ...no warning printed... - -Note that pattern-matching warnings are raised at compile time, so this will not suppress the warning: - - Warning[:experimental] = false # At the time this line is evaluated, the parsing happened and warning emitted - [0] => [*, 0, *] - -So, only subsequently loaded files or `eval`-ed code is affected by switching the flag. +Note that <code>=></code> and +in+ operator can not have a guard clause. +The following examples is parsed as a standalone expression with modifier +if+. -Alternatively, the command line option <code>-W:no-experimental</code> can be used to turn off "experimental" feature warnings. + [1, 2] in a, b if b == a*2 == Appendix A. Pattern syntax diff --git a/doc/syntax/refinements.rdoc b/doc/syntax/refinements.rdoc index c900ab1bdc..4095977284 100644 --- a/doc/syntax/refinements.rdoc +++ b/doc/syntax/refinements.rdoc @@ -212,10 +212,7 @@ all refinements from the same module are active when a refined method When looking up a method for an instance of class +C+ Ruby checks: -* 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 refinements of +C+, in reverse order of activation * The prepended modules of +C+ * +C+ * The included modules of +C+ @@ -279,6 +276,6 @@ Refinements in descendants have higher precedence than those of ancestors. == Further Reading -See https://bugs.ruby-lang.org/projects/ruby-master/wiki/RefinementsSpec for the +See https://github.com/ruby/ruby/wiki/Refinements-Spec for the current specification for implementing refinements. The specification also contains more details. |
