-
Notifications
You must be signed in to change notification settings - Fork 1
Types and Literals
The following types are used inherently in the Ruby language.
Note that all ruby values have these characteristics:
- A class (and therefore, methods that can be called on them)
- A set of instance variables
This has interesting consequences for immediate type values:
class Fixnum
alias old_minus -
def - val
@counter ||= 0
@counter += 1
print "Hello #{self} - #{val}! #@counter\n"
old_minus val
end
end
p 43 - 12
p 30 + 13 - 5
p (45 - 2) - 5
=>
Hello 43 - 12! 1
31
Hello 43 - 5! 2
38
Hello 45 - 2! 1
Hello 43 - 5! 3
38
Note that from Ruby 2.0 all immediate types except Symbols are frozen, so this example will no longer work.
Reference types also support "flags" including tainted, untrusted, frozen, and other implementation-defined flags that Ruby C API components can specify. Ruby has implemented freezing for immediate types, but not tainting/untrusting.
3.taint; 3.tainted?
=> false
3.untrust; 3.untrusted?
=> false
3.freeze; 3.frozen?
=> true
Immediate type values have no object ID or unique memory location associated with them, so two of these with the same value are actually the same object e.g. (3-2) and 1 are the same object.
These are the literals true, false and nil.
true.class => TrueClass
false.class => FalseClass
nil.class => NilClass
In true/false contexts, false and nil evaluate to false, every other value evaluates to true.
!false and !nil => true
!true or !0 or !"" => false
This is the basic integer data type of Ruby, a signed integer of probably 31 bits on a 32 bit platform, or 63 bits on a 64 bit platform. Integer literals have a C-like form, but digits can also be separated by underscores as long as the underscores are not consecutive or leading/trailing the digits.
If the integer literal is too large to be represented as a Fixnum, it will be a Bignum instead.
Decimal:
1_000_000 => 1000
0d1_000_000 => 1000000
Hexadecimal:
0x1000000 => 16777216
Octal:
01_000_000 => 262144
0_1_000_000 => 262144
0o1_000_000 => 262144
Binary:
0b1000000 => 64
##Symbol
A symbol can be thought of as an immutable string which is stored internally as an index into the global symbol table - the same global symbol table where the names of all types of variables and methods are stored. It is an immediate type - if two sections of ruby code access :mysym, they are both accessing the same object.
They are useful in situations where you would like to reference something by a string, but with the performance of using a number - they are similar in this way to the "enum" type in other languages, although with Ruby's typical thin type safety.
There are 3 forms of symbol literal, although all create the same Symbol type.
This form can be used for symbol literals on any valid Ruby identifier (i.e. anything valid as a function name, or a global/instance/class variable).
The symbol name is resolved to an index at compile time.
:hello
:hello?
:hello!
:hello=
:HELLO
:$hello
:@hello
:@@hello
:>=
This form can be used for symbol literals on any string. The string is delimited by single- or double-quotes, and is processed according to the same rules as for such string literals.
The symbol name is resolved to an index at compile time, unless the string has interpolated components, in which case it's resolved at runtime.
:'' => :""
:'hello' => :hello
:"hello" => :hello
:'hello hello' => :"hello hello"
:"hello #{'wo' + 'rld'}" => :"hello world"
This form follows the same rules as a %q... string literal (i.e. single-quote style), but its result is made a symbol.
%s(hello (world)) => :"hello (world)"
Reference types have a unique ID - two separately created instances of them are distinct even if they have the same value.
Floating point and scientific notation literals of the usual format are represented as a Float object, whose value is internally represented as a C "double" type. In these literals, no leading 0 is permitted. Underscores can once again separate digits but they most not be consecutive or leading/trailing a set of digits.
100.5 => 100.5
-100e-5 => -0.001
100E+5 => 10000000.0
1_000e4 => 10000000.0
If an integer literal would overflow a Fixnum, it becomes a Bignum instead. Bignums are signed integers of unlimited size.
Strings can be created by a few different kinds of literal.
Single- and double-quoted string literals:
'hello \'world\'' => hello 'world'
"hello #{"\"world\""}" => hello "world"
Strings may contain any character (including newlines).
Double-quoted string literals are "expanded" (see interpretation rules below).
If you prefer to delimit your strings with something other than single- or double-quotes.
%q|hello world| # hello world - type "q" - single-quote style string
%Q;hello world; # hello world - type "Q" - double-quote style string
%<hello <world>> # hello <world> - no type specified - double-quote style string
String literals appearing consecutively are concatenated together. They can be single-quote, double-quote or %... style, however only the first of the consecutive literals may be %... style.
%|hello| ' ' "world" => hello world
- You can choose any ASCII, non-alphanumeric character to delimit the string. Even spaces, tabs, newlines and other wackies.
- If the opening delimiter is one of
([{<, then the closing delimiter must be its respective)]}>. When these delimiters are used, the string can contain "nested" opening/closing delimiter pairs which Ruby will recognise as part of the string.
Simple (single-quote style) string interpretation:
- You can
\-escape: - a delimiting character (e.g.
',"or either opening or closing delimiter in the case of %... literals) - a
\
Expanded (double-quote style) string interpretation:
- The following
\-escape codes are recognized: -
\u00A0- a 4-digit hexadecimal unicode character code -
\u{A0 A0 A0}- a sequence of 1- to 6-digit hexadecimal unicode character codes separated by a single space or tab -
\n- a newline -
\t- a tab -
\r- a carriage return -
\f- a form feed -
\v- a vertical tab -
\a- an alert (bell) -
\e- an escape -
\b- a backspace -
\s- a space -
\\- a backslash -
\040- a 1- to 3-digit octal byte -
\xA0- a 1- to 2-digit hexadecimal byte -
\C-Jor\cJ- control - the next character following\C-or\c-will be converted to a control character by having bits 6 and 7 cleared, unless it's?, in which case it will become code 127. It can be any ASCII character or any escape sequence except unicode sequences, but\<newline>is read as a newline character -
\M-J- meta - the next character following\M-will have its bit 8 set. It can be any ASCII character or any escape sequence except unicode sequences, but\<newline>is read as a newline character - Note that control and meta can be used together, but only one of each e.g.
\C-\M-J -
\<newline>- if a backslash precedes a newline, both the backslash and newline are ignored - Anything else - the backslash is removed and the character is reported unchanged
- Code can be "interpolated" in the string with the following structures, whose value will be converted to string if necessary and inserted in the string:
-
#$...- any global variable name -
#@...- any instance variable name -
#@@...- any class variable name -
#{...}- any Ruby code (specifically, a block of statements) - Note that the parser will stop parsing of the string when it detects a valid global/instance/class variable reference or
#{, and regular Ruby parsing will take over for the interpolated component until the full variable name has been read, or a valid sequence of Ruby code has been read followed by}- in this way interpolated components are parsed independently of the string. This means, for example, that characters with special meaning in the string such as\and terminators don't have special meaning in the interpolated components (and don't need to be escaped).
In Ruby a character literal is just another type of string literal which may only have 1 character. Its form is ?<literal> with <literal> being one of the following:
- Any non-escaped character, except for
- whitespace (as defined in the source encoding)
- an ASCII alphanumeric or
_character if it's immediately followed by an alphanumeric,_or non-ASCII character - A
\-escaped sequence as per the rules for expanded strings, with the following exceptions: - In the
?\u{...}form only one unicode character code may be present -
?\<newline>is a newline character literal
Examples:
?% => "%"
?\x41 => "A"
Backquote literals are a string literal whose value is processed in some way and the result returned - typically, the backquote literal is an OS shell command which is executed and it's output on the STDOUT stream is collected into a string and returned as the value of the backquote.
`ruby --version` => ruby 1.9.3p545 (2014-02-24) [i386-mingw32]
Specifically, a backquote literal is processed according to expanded string literal rules, and the literal's value then becomes the value of self.`(<string>) as called on the processed string. The backquote literal behaviour can therefore be changed by overriding the ` method for whatever object is currently self.
The default behaviour for backquote literals (as implemented by Kernel.` ) is effectively to execute the following:
pipe = IO.popen <backquoted string>, :internal_encoding => nil
if pipe == nil
''
else
result = pipe.read
pipe.close
result
end
In this way it executes the backquoted string as a shell command and returns its result.
The pipe == nil condition is there to support the forking feature of IO.popen. If the backquote literal is `-`, instead of calling a shell command it will fork the current process. It will return an empty string to the child process immediately, and when the child process completes, it will return the outputted value of the child process to the parent process (which may also be an empty string if the child did not output).
puts "Parent PID: #$$"
v = `-`
if v == ""
puts "Child PID: #$$"
else
puts "Child data begin"
puts v
puts "Child data end"
end
=>
Parent PID: 59292
Child data begin
Child PID: 29916
Child data end
Note also that this default behaviour of backquote literals apparently has other side effects e.g. setting the value of $?.
This form follows the same rules as a %Q... string literal (i.e. double-quote style), but its result is processed as per a backquote literal.
%x|ruby --version| => "ruby 1.9.3p545 (2014-02-24) [i386-mingw32]\n"
Arrays can be created by [...] array literals. The array literal's contents are similar to a method call's arguments, and can contain:
- An optional comma-separated list of optionally splatted arguments, followed by
- An optional comma-separated list of hash associations as per hash literals (these will be combined into a Hash which is added to the end of the array), followed by
- An optional trailing comma
Examples:
[] => []
['a', 'b', 'c'] => ["a", "b", "c"]
['a', 'b', 3.times.collect { "Hello" }] => ["a", "b", ["Hello", "Hello", "Hello"]]
['a', 'b', * 3.times.collect { "Hello" }] => ["a", "b", "Hello", "Hello", "Hello"]
['a', 'b', c: 'd', 'e' => 'f', ] => ["a", "b", {:c=>"d", "e"=>"f"}]
A word literal is a shorthand literal for creating an array of strings. The contents of the literal are a string, which will be split by whitespace (removing consecutive whitespace characters) into an array of strings. The splitting by whitespace is resolved at compile time and before any interpolated components are resolved. Word literals follow the same opening and closing delimiter rules as other %... literals.
%w... word literals have single-quote style interpretation, and %W... word literals have double-quote style interpretation. In addition to these interpretation rules, for both forms of word literal, any whitespace character can be \-escaped so that it appears as is in the word, instead of being a word separator (this applies even for \-escaped newlines in double-quote style word literals, the newline is part of the word instead of being ignored).
%w|hello world| => ["hello", "world"]
%w|hello\ world| => ["hello world"]
%W|:#{3.times.collect{'hello'}.join(' ')}: world | => [":hello hello hello:", "world"]
Hashes (i.e. hash tables/associative arrays) can be created by {...} hash literals. The hash literal's contents are:
- An optional comma-separated list of hash associations, followed by
- An optional trailing comma
A hash association can have the 2 forms below:
-
a => b- bothaandbare ruby expressions,ais the key forb -
a: b-bis a ruby expression,ais a "label" and may be any valid constant or local variable name, optionally followed by?or!. The Symbol forais they key forb.
Examples:
{} => {}
{30 => 'hello'} => {30=>"hello"}
{'hello' => 30} => {"hello"=>30}
{:hello => 30} => {:hello=>30}
{hello: 30} => {:hello=>30}
{hello?: 30} => {:hello?=>30}
{HELLO: 30,} => {:HELLO=>30}
{HELLO!: 30} => {:"HELLO!"=>30}
A regular expression literal creates a Regexp object.
/<pattern>/<options>
%r(<pattern>)<options>
A regular expression literal is processed similar to double-quoted strings:
- Interpolation is processed as per double-quoted strings
- Processing of
\escape sequences is delegated to Regexp code (except for\<newline>and\<nonascii>) and is handled slightly differently. For example, regular expressions have additional escape sequence rules such as\p...and some rules are context dependent, such as a\1which can be a backreference or (in a character class) an octal value.
A note on character encodings - as with String objects, Regexp objects have an associated encoding. By default, regular expression literals will try to assign themselves the US-ASCII encoding, which means they can only match ASCII characters, but then they operate in "ascii-compatible mode" and are able to match against strings in any ascii-compatible encoding. If they are unable to become US-ASCII, and are forced into an encoding other than ASCII-8BIT, then they will be in "fixed encoding mode" and will only be able to match Strings of the same encoding. The following scenarios can force a regular expression literal out of the US-ASCII encoding:
- Non-ascii characters in the literal - forces the Regexp to the source file's encoding
- \u... unicode escapes - forces the Regexp to UTF-8
- Encoding override options (see below) - forces the Regexp to the encoding specified
- Hex escapes, octal escapes, or
\p...escapes - forces the Regexp to either the source file's encoding or, if encoding is overridden by an option, to the override encoding
TODO: check these rules
An error is raised if a regular expression is forced to 2 different encodings by the rules above.
Options may be some combination (concatenated as is) of the following characters:
-
o- "once" - any interpolated components are only evaluated once, the first time the regular expression literal is encountered at runtime, and the resulting Regexp object saved and reused subsequently - 'i' - "ignore case" - case-insensitive matching
- 'x' - "extend" - ignore whitespace and comments in the pattern, see Regexp documentation
- 'm' - "multiline mode" - treat a newline as a character matched by
. - 'n' - "encoding: none" - force ASCII-8BIT encoding, which is the same as having no encoding and matching on bytes. This is not a fixed-encoding regular expression - it will match on any string by bytes.
- 'e' - "encoding: EUC-JP" - fix encoding to EUC-JP
- 's' - "encoding: Windows-31J" - fix encoding to Windows-31J
- 'u' - "encoding: UTF-8" - fix encoding to UTF-8
As a special Ruby language feature, in certain circumstances Ruby will automatically assign matches to named subexpressions in a regular expression literal to Ruby variables of the same name - this is called "named capture assignment". For example:
/(?<name1>.)(?<name2>.)/ =~ <value>
Ruby will create variables name1 and name2 which have the value of the corresponding subexpressions - the above code is effectively translated to:
(
/(?<name1>.)(?<name2>.)/ =~ <value>
if $~
name1 = $~[:name1]
name2 = $~[:name2]
$~.begin 0
else
name1 = nil
name2 = nil
nil
end
)
Note that as per Regexp class documentation, any time a regular expression is matched (whether literal or otherwise, with the =~ operator or otherwise) it will assign the Match result to $~.
Named capture assignment is applied according to the following rules:
- It only occurs when a regular expression literal without interpolated components occurs to the left of a
=~operator when parsing source code - Each named capture is only assigned once - note that a multiple subexpressions with the same name can appear in the regular expression
- Each named capture is only assigned to a variable if it's a valid non-constant variable name
A Ruby Language Reference
Copyright © by Michael Hore, 2016.
Introduction to This Document
Ruby Elements
- Classes and Modules
- Methods
- Blocks, Procs and Lambdas
- Execution Context and Closures
- Variables, Constants and Namespaces
- Types and Literals
- Ruby Expressions
- Operators
Syntax Grammar
Exceptions and Throw
Ruby Sourcefiles and Libraries
Multi Threading
Execution and Lifecycle