Language consists of a system:
- Semantics studies the aspects of meaning.
- Syntax studies the structure, principles and relationships.
Quick reference
Structure:
- Read documentation (API)
- Debugging
- Literals
- Variables
- Control flow
- Methods
- Classes
- Collections
- Inheritance
- Modules
- Exceptions
- Input and output
- Concurrency
- Testing
- General rules
- References
Read documentation
- Documentation is a representation of the language (im)possibilities.
- Documentation can be found at
- https://docs.ruby-lang.org/en/master/index.html
- https://docs.ruby-lang.org/en/master/table_of_contents.html
- https://rubyreferences.github.io/rubyref/
- https://rubyapi.org
- via ruby info
ri
command in terminal, e.g.ri Array#map
orri .map
- via
help
command in interactive ruby. Firstirb
thenhelp Array#map
orhelp .map
-
ruby-lang.org
search shows more results from the documentation,rubyapi.org
shows less results. - Class methods are called on the class itself and are defined with self. Instance methods are called on an instance of a class and are defined without self.
-
::
is a scope resolution operator. It is used to reference a constant, module, or class defined within another class or module. It is documented as a class method. -
#
is a method call operator. It is documented as an instance method.
Debugging
For debugging use p
instead of puts
:
-
p
(print the value of the expression, including the value of the expression) -
pp
(pretty print the value of the expression) -
print
(prints without trailing new line) -
puts
(prints expression and nil)
Reserved keywords
Keywords
__ENCODING__
The script encoding of the current file.
__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.
END
Runs after any other code in the current file.
alias
Creates an alias between two methods (and other things).
and
Short-circuit Boolean and with lower precedence than &&
begin
Starts an exception handling block.
break
Leaves a block early.
case
Starts a case expression.
class
Creates or opens a class.
def
Defines a method.
defined?
Returns a string describing its argument.
do
Starts a block.
else
The unhandled condition in case, if and unless expressions.
elsif
An alternate condition for an if expression.
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.
false
Boolean false.
for
A loop that is similar to using the each method.
if
Used for if and modifier if statements.
in
Used to separate the iterable object and iterator variable in a for loop. It also serves as a pattern in a case expression.
module
Creates or opens a module.
next
Skips the rest of the block.
nil
A false value usually indicating “no value” or “unknown”.
not
Inverts the following boolean expression. Has a lower precedence than !
or
Boolean or with lower precedence than ||
redo
Restarts execution in the current block.
rescue
Starts an exception section of code in a begin block.
retry
Retries an exception block.
return
Exits a method. If met in top-level scope, immediately stops interpretation of the current file.
self
The object the current method is attached to.
super
Calls the current method in a superclass.
then
Indicates the end of conditional blocks in control structures.
true
Boolean true.
undef
Prevents a class or module from responding to a method call.
unless
Used for unless and modifier unless statements.
until
Creates a loop that executes until the condition is true.
when
A condition in a case expression.
while
Creates a loop that executes while the condition is true.
yield
Starts execution of the block sent to the current method.
- Version: 3.3
- With definition: https://ruby-doc.org/docs/keywords/1.9/
Literals
https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html
A literal is any notation that lets you represent a fixed value in source code (wikipedia).
What does that even mean?
The notation is it's direct or literal value: e.g. 1
is a literal for the number 1, "hello"
is a literal for the string "hello"
, [1, 2, 3]
is a literal for the array [1, 2, 3]
. It's a constant or fixed value, it doesn't change. (e.g. 1
is always 1, "hello"
is always "hello"
, [1, 2, 3]
is always [1, 2, 3]
). It's the primary way to introduce values into a program.
This is different from the indirect or variable notation: x = 1
where x
is a variable which refers to 1, which can change. Or for Constants FOO = 1
, Expressions (1 + 2)
, or Methods def foo; puts 1 end
which all have indirect or computed values.
Basic literals:
# Numbers: Integers and Floats
1, 2, 3.00, 4e2
# Strings
'That\'s right', "double quotes", "Interpolation like #{2+2}"
# Symbols (immutable strings)
:pending, :"rejected", :"#{var}_name"
# Arrays
[1, 2, 3, 4, 5]
# Hashes
{ key1: 'value1', key2: 'value2' }
# Ranges
1..100, 'a'..'z'
# Boolean:
true, false
# Nil
nil
# Here Document or Heredoc
a_variable = <<HEREDOC
This is a heredoc
It is used for multi-line strings
HEREDOC
Regular Expression - Regex
A regular expression (also called a regex or regexp) is pattern that can be matched against a string. It is a way of specifying a set of characters that matches a string or part of a string. It is a match pattern (also simply called a pattern). Regex can be used for pattern matching and pattern replacement. Specific patterns can be defined with: Anchors, word boundaries, character classes, repetition, alternation and grouping.
re = /red/ # or %r{red}
re.match?('redirect') # => true # Match at beginning of target.
re.match?('bored') # => true # Match at end of target.
re.match?('foo') # => false # No match.
"bored".match?(re) # => true
The following are metacharacters with specific meaning: . ? - + * ^ \ | $ ( ) [ ] { }
https://docs.ruby-lang.org/en/master/Regexp.html#class-Regexp-label-Special+Characters
Operater =~ returns characters offset of beginning:
/cat/ =~ 'dog and cat' # => 8
/cat/ =~ 'cat' # => 0
'cat' =~ /cat/ # => 0
!~ is the negative match operator, which returns true if the string does not match the pattern:
/cat/ !~ 'dog and cat' # => false
Changing strings with patterns: .sub, .gsub, .sub!, and .gsub!. Sub is for the first match, gsub is for all matches.
Regex has modifiers, with the x
at the last example below, you can add newlines, whitespace and comments inside to make it more readable:
/cat/i # => case insensitive
/cat/m # => multiline
/cat/s # => single line
%r{(\d{5}), # 5 digits followed by comma
\s, # a whitespace
([A-Z]) # 1 character
}x # => extended
After a succesful match via Regexp#match or =~ it returns a MatchData object, which is a collection of information about the match:
https://docs.ruby-lang.org/en/master/MatchData.html
/all/.match("all things")
=> #
Numbers
Ruby supports integers, floating-point, rational and complex numbers. Intergers are assumed to be decimal base 10, but can be specified with a leading sign, as base indicatar: 0 for octal, 0x for hexadecimal and 0b for binary (and 0d for decimal), followed by a string of digits in the appropriate base.
12345 => 12345 # base 10
0d12345 => 12345 # base 10
123_456 => 123456 # base 10
-543 => -543 # base 10
0xaabb => 43707 # base 16 (hexadecimal)
0377 => 255 # base 8 (octal)
-0b10_1010 => -42 # base 2 (binary)
1_2_3 => 123 # base 10
BigDecimal is Ruby's high-precision decimal number class.
Rational numbers are the ratio of two integers (they are fractions) and therefor have an exact representation:
3/4 #=> 0
3/4r #=> (3/4)
0.75r #=> (3/4)
"3/4".to_r #=> (3/4)
Rational(3,4) #=> (3/4)
Rational("3/4") #=> (3/4)
Complex numbers represent points on the complex plane, and have 2 components: the real and imaginary parts.
1+2i # => (1+2i)
"1+2i".to_c # => (1+2i)
Complex(1,2) # => (1+2i)
Complex("1+2i") # => (1+2i)
Looping using Numbers
3.times { print "A " }
1.upto(5) { |i| print i, " " }
99.downto(97) { |i| print i, " " }
50.step(60, 5) { |i| print i, " " }
# A A A 1 2 3 4 5 99 98 97 50 55 60
Strings
Ruby strings are sequences of characters and instances of class String
.
Usually strings are created using string literals - sequences of characters between single or double quotes (delimiters). How the string literal is created, defines the amount of processing that is done on the characters in the string.
Escaping characters inside single-quote is a form of processing:
'hi \\' # => hi \
'that\'s right' # => that's right
'hi "\\"' # => hi "\"
Double-quoted strings support:
- many escape sequences, e.g.
\n
the newline character. - string interpolation, which means you can use any ruby code into a string using
#{ expression }
. - global, class or instance variables: #$foo, #@@foo or #@foo.
Not recommended:
puts "now is #{
def the(a)
'the ' + a
end
the('time')
} for all bad coders..."
Produces: now is the time for all bad coders...
Some style guides prefer single quotes, if interpolation isn't used, because they are faster.
Syntax to create a string literal can also be as follows, with any nonalphanumeric or nonmultibyte character:
%q/abc/ #=> abc
%Q!abc! #=> abc
%Q{abc #{2*3}} #=> abc 6
%!abc! #=> abc
%{abc #{2*3}} #=> abc 6
# usually current style guides suggest this:
%q(abc) #=> abc
Finally, you can construct a string using a here document, or heredoc.
string = <<END_OF_STRING
This is a string
with two lines.
END_OF_STRING
# with a minus sign, you can indent the terminator
string = <<-END_OF_STRING
This is a string
with two lines.
END_OF_STRING
# with tilde, ruby will strip the indentation, to enable long strings
string = <<~END_OF_STRING
This is a string
with two lines.
END_OF_STRING
# Or generally considered super confusing:
print <<-S1, <<-S2
Concat
S1
enate
S2
Type conversion:
# to string
1.to_s
# to integer
'1'.to_i
Encoding
Encoding is a mechanism for translating bits into characters. For many years, most developers who used English used ASCII, a 7-bit encoding of English characters, such as binary 101 to capital A. Later, an 8-bit representation called Latin-1 that included most characters in European languages became common. All of these were superseded by Unicode, a global standard for all text characters used in all languages: https://home.unicode.org/
Struct
A Struct
is a class that is used to create objects that have attributes.
Ranges
Ranges represent a range of values. Ruby uses ranges to implement sequences and intervals.
arr = [1,2,3,4,5]
arr[..2] # => [1,2,3]
arr[2..] # => [3,4,5]
arr === 3 # => true
arr === 6 # => false
arr.include?(3) # => true
Blocks
A code block is a chunk of code that can be passed to a method. You can think of a block as somewhat like the body of an anonymous method, as if the block were another parameter passed to that method. Usually between braces on one line and do/end when block spans multiple lines. Parameters to a block are separated by commas, and they are always local to the block. You can define block-local variables using the ;
character in the block's parameter list.
# general syntax
[1,2].each { puts 'x' }
[1,2].each do puts 'x' end
[1,2].each { |x| puts x }
[1,2].each { puts _1 } # _1 first positional argument, _2, _3 etc.
# block-local variable y (syntax is rare)
y = 100
sum = 0
[1,2].each do |x; y|
y = x*x
sum += y
end
puts sum
puts y
# method say first, then parameters, only one block after.
object.say("dave") { puts 'hello' }
The act of doing something to all objects in a collection is called enumeration in Ruby; in other languages it is called iteration. e.g. each, find, map, sort_by, group_by, map, reduce.
Ruby remembers the context of an object, local variables, block, and so on, this is called binding
. Within the method, the block may be invoked, using the yield
statement. A block returns a value to the method that yields to it. The value of the last expressions evaluated in the block is passed back to the method as the value of the yield expression.
def two_times
yield
yield
end
two_times { puts "Hello" }
Hello
Hello
`.tap` # is a no-op, it taps into the object and returns the object. It is useful for debugging e.g.:
`.tap { |result| puts "result: #{result}\n\n" }`
# map implementation looks something like this, which constructs a new array
class Array
def map
result = []
each do |value|
result << yield(value)
end
result
end
end
If the last parameter is prefixed by &
(such as &action
), that code block is converted to an object of class Proc
. The Proc
object is then assigned to the parameter. This allows you to pass a code block to a method as if it were a regular parameter.
- https://docs.ruby-lang.org/en/master/Proc.html
- https://docs.ruby-lang.org/en/master/Kernel.html#method-i-lambda
# Long
class ProcObject
def pass_in(&action)
@stored_proc = action
end
def use_proc(parameter)
@stored_proc.call(parameter)
end
end
foo = ProcObject.new
foo.pass_in{ |paramz| puts "Hello, #{paramz}!" }
foo.use_proc("Dave")
# => Hello, Dave!
# shorter
def create_block_object(&block)
block
end
bl = create_block_object { |x| puts "Hello, #{x}!" }
bl.call('Dave')
# => Hello, Dave!
# shortest
# stabby lambda
bl = -> (param) { puts "you called with #{param}" }
bl.call("Dave")
# => Hello, Dave!
# short: lambda (Ruby Kernal method)
bl = lambda { |param| puts "you called with #{param}" }
bl.call("Dave")
# => Hello, Dave!
# short: Kernal method proc
bl = proc { |param| puts "you called with #{param}" }
bl.call("Dave")
# => Hello, Dave!
# Proc.new (not the preferred method)
bl = Proc.new { |param| puts "you called with #{param}" }
bl.call("Dave")
# => Hello, Dave!
Blocks as closures
Variables in the surrounding scope that are referenced in a block remain accessible for the life of that block and the life of any Proc object created from that block. This is called a closure. More on closures: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
def n_times(thing)
->(n) { puts thing * n }
end
p1 = n_times("Hello,")
p1.call(3)
# => Hello,Hello,Hello,
# Parameter list
# it can take default values, splat arguments, keywords arguments, and block parameters.
-> (parameter list) { block }
# Example
proc2 = -> (x, *y, &z) do
puts x
puts y
z.call
end
proc2.call(1, 2, 3, 4) { puts "Hello, World!" }
# => 1
# => [2, 3, 4]
# => Hello, World!
Enumerators
Can iterate over two collections in parallel. Enumerator class is not to be confused with the Enumerable module. The Enumerator class is used to create custom external iterator.
short_enum = [1,2,3].to_enum
long_enum = ('a'..'z').to_enum
loop do
# will end after the 3rd iteration, this will terminate cleanly
puts "#{short_enum.next} - #{long_enum.next}"
end
Control Flow and Expressions
https://docs.ruby-lang.org/en/master/syntax/control_expressions_rdoc.html
Ruby has a variety of ways to control execution. All the expressions described here return a value.
Expressions and Return Values:
# Expression is evaluated
1 + 1
# and will return a value
1 + 1
=> 2
# => is called a hash rocket
# 2 is returned
puts 1+1
2
=> nil
# expression puts 1+1 is evaluated
# 2 is printed
# nil is returned
- Basic Operator Expressions:
+ - * / % **
- Command Expressions: string with backquotes or backticks will be executed as command by OS.
ls
.split will give array of content of the current folder. Copying , using`echo 'hi' | pbcopy`
will copy the output of echo to clipboard, which is the same assystem("echo '123' | pbcopy")
. Copying resource attributes:`echo "#{User.first.id}" | pbcopy`
. - Assignment is setting the lvalue (left value) to refer to the rvalue (right value), and returns rvalue. Ruby has 2 forms of assignment: first an object reference to a variable or constant, ABC = 4. Second is object attribute or element reference on the left side of the assignment operator, ABC[1] = 4. Also possible, is the rightward assignment, since ruby 3.0: data => variable (e.g. 2=>x).
- For parallel assignment, to swap vales:
a, b = 1, 2
a, b = b, a
- Splats and assignment:
- for rvalues
a,b,c,d,e = *(1..2), 3 # a=1, b=2, c=3, d=nil, e=nil
- greedy for splat for lvalue:
- for rvalues
a, *b = 1,2,3,4,5
# a=1, b=[2,3,4,5]
*a, b = 1,2,3,4,5
# a=[1,2,3,4], b=5
first, *, last = [1,2,3,4,5]
# first=1, last=5
- Nested assignments:
a, (b, c) = 1, [2, 3]
# a=1, b=2, c=3
a, (b, c), d = 1, [2, 3, 4], 5
# a=1, b=2, c=3, d=5
Conditional Execution
- boolean expressions: Ruby has simple definition of truth: any value that is 1. not
nil
, or 2. the constantfalse
, is true. So,"c", 9, 0, :a
, are true, also,"", [], {}
are true. The set of false values are sometimes referred to as falsey and set of true values are referred to as truthy.nil && 99
returnsnil
,"c" && 99
returns99
. When it's false, the first argument is returned, when it's truee, the second argument is returned (short circuit evaluation). There is a difference in using&&
andand
, terms of precedence compared to the assignment. Examples:result = "" && [], which returns the #=> []
, and will showresult #=> []
, howeverresult = "" and [] which returns the #=> []
and will showresult # => ""
. - the
defined?
Keyword:defined? 1 #=> "expression"
anddefined? a #=> nil
anddefined? a = 1 #=> "assignment"
. - Comparing objects: == equal value, ===, <=>, <, >, <=, >=, =~, eql? (equal type and value), equal? (same object id).
- if and unless:
# then is optional
if condition then
# code
elsif condition2 then
# code
else
# code
end
# also possible
if condition then #code
elsif condition2 then #code
else #code
end
# assignment
variable =
if condition then #code
elsif condition2 then #code
else #code
end
# ternary operator
condition ? true_value : false_value
# unless. Negated if statement. As reminder: if not
unless expression
# some code to be executed if the expression is FALSE
else
# some code to be executed if the expression is true
end
# also possible
if not false then true end #=> true
Safe navigation operator: &.
, also called the lonely operator. It returns nil if the object is nil.
Loops and iterators:
https://docs.ruby-lang.org/en/master/Kernel.html#method-i-loop
# a method defined in Kernel, but it looks like a control structure.
# loop
# e.g. iteration over api endpoint that is paginated
page = 1
collection = []
loop do
# response = send_request(:get, '/endpoint', page)
# collection += response[:data]
# page += 1
# break if page > response.dig(:pagination, :total_pages)
end
# while (do keyword is optional)
a = 0
while a < 10 do
p a
a += 1
end
p a
# until. As reminder: while not
until condition
# loop as long as condition is false
end
Break, next:
- Use
break
to leave a block early. - Use
next
to skip the rest of the current iteration.
loop do
next if condition_1
break if condition_2
end
Iterators:
2.times do; puts 'Hello' end # => Hello Hello
2.times { puts 'Hello' } # => Hello Hello
0.upto(5) { |i| puts i } # => 0 1 2 3 4 5
0.step(10, 2) { |i| puts i } # => 0 2 4 6 8 10
A different way to write an each loop with a Ruby built-in looping primitive:
for i in 0..5
puts i
end
# => 0 1 2 3 4 5
Block local variables:
square = 'start'
[1,2].each do |i; square| # square is now also a block local variable
square = i * i
end
puts square # => start
Pattern Matching
https://docs.ruby-lang.org/en/master/doc/syntax/pattern_matching_rdoc.html
Pattern matching compares a target which can be any Ruby object to a pattern. If the target matches the pattern, the target is deconstructed into the pattern, setting the value of those variables.
"abc" in "abc" # => true
"abc" in "def" # => false
3 in 3 # => true
3 in 4 # => false
3 in 1..5 # => true
"abc" in String # => true
"abc" in Integer # => false
[1,2,3] in [Integer, Integer, Integer] # => true
{a: 1, b: "3"} in {a: Integer, b: String } # => true
# or
[1,2] in [Integer, Integer] | [Integer, String] # => true
Variable binding: Assign values in the target to variables in the pattern and then use those variables in the pattern.
value in pattern => variable
puts variable # => value
# example
"aaa" in String => var
puts var # => aaa
# short
"baa" => var
puts var # => baa
# another way
"abc" in var
puts var # => abc
Case pattern matching:
# case, with when clause
case expression
when condition1 then # code
when condition2
# code
else # code
end
# case, with in clause
case expression
in condition1 then # code
in condition2 then # code
else # code
end
# pinning values, in a case statemen. With the pin operator ^ : It will pin the value to the part of the pattern..
def get_status(idea_to_look_for, status_to_look_for, list)
case list
in [*, {idea: ^idea_to_look_for, status: }, *] then puts "#{idea_to_look_for} is #{status_to_look_for}"
in [*, {idea:, status: ^status_to_look_for}, *] then puts "second"
else # code
end
puts get_status('idea1', 'status1',
[{idea: 'idea1', status: 'status1'},
{idea: 'idea2', status: 'status2'}
])
#=> idea1 is status1
# guard clause, additionally to the pattern matching, it checks the condition
case expression
in pattern if condition # code
else # code
end
# pattern matching against a class, requires a deconstruct_keys or deconstruct
class MyClass
attr_accessor :name
def initialize(name)
@name = name
end
def deconstruct_keys(keys)
{name: @name}
end
end
my_object = MyClass.new('my_object')
case my_object
in {name: /^my/} then puts "starts with my"
in {name: /^your/} then puts "starts with your"
else # code
end
Variables
https://docs.ruby-lang.org/en/master/doc/syntax/assignment_rdoc.html
A variable is an identifier that is assigned to an object, and which may hold a value. A variable is not an object in Ruby, so it is a reference to an object. A local variable name may contain letters, numbers, an _ (underscore or low line) or a character with the eighth bit set.
Assignment aliases objects, potentially giving multiple variables that reference the same object. String#dup will create a new string object with the same content. String#freeze will make a string immutable. Numbers and symbols are always frozen (immutable) in Ruby.
Examples:
$global_variable
@@class_variable
@instance_variable
CONSTANT
::TOP_LEVEL_CONSTANT
OtherClass::CONSTANT
local_variable
In a file:
# Defining variables
# global variable, can be mutated
$some_global_variable = "accessible everywhere"
# Top level constant, can not be mutated
TOP_LEVEL_CONSTANT = "accessible everywhere"
class Toy
CONSTANT = "Some value"
end
class Human
# A class variable is shared by all instances of this class.
@@species = 'H. sapiens'
# Constant is a variable that is set only once and never changed.
A_CONSTANT = 1
# Basic initializer
def initialize(name, age = 0)
# Assign the argument (name) to the '@name' instance variable for the instance.
@name = name
# If no age given, we will fall back to the default in the arguments list (age=0).
@age = age
end
def some_method
# local_variable is only accessible within this method
local_variable = 1
end
def some_other_method
# TOP_LEVEL_CONSTANT can be accessed from anywhere in the program using :: prefix
::TOP_LEVEL_CONSTANT
end
def some_last_method
# From another class
Toy::CONSTANT
end
end
# Showing variables
p $some_global_variable
Human.class_variable_get(:@@species)
Human::A_CONSTANT
h = Human.new('foo', 10)
h.instance_variable_get(:@name)
h.instance_variable_get(:@age)
h.some_method
h.some_other_method
h.some_last_method
# Aliasing global variables
$some_global_variable = "accessible everywhere"
alias $b $some_global_variable
p $b # => 'accessible everywhere'
# parallel variable assignment
x, y, z = 100, 200, 500
Pseudo Variables
They provide information about the program's execution environment or serve specific purposes within Ruby.
Characteristics: Predefined, read-only and available throughout the program.
self # The receiver object of the current method.
super # The receiver object of the current method in the superclass.
true # boolean; singleton; TrueClass
false # boolean; singleton; FalseClass
nil # empty; uninitialized; NilClass; falsey; singleton
__FILE__ # The name of the current source file.
__LINE__ # The current line number in the source file.
Pre-defined global variables
- https://docs.ruby-lang.org/en/master/globals_rdoc.html
- https://github.com/ruby/ruby/blob/HEAD/spec/ruby/language/predefined_spec.rb
- https://github.com/ruby/ruby/blob/HEAD/lib/English.rb
In irb:
global_variables.count
# => 43
global_variables.sort.inspect
# => "[:$!, :$\", :$$, :$&, :$', :$*, :$+, :$,, :$-0, :$-F, :$-I, :$-W, :$-a, :$-d, :$-i, :$-l, :$-p, :$-v, :$-w, :$., :$/, :$0, :$:, :$;, :$<, :$=, :$>, :$?, :$@, :$DEBUG, :$DEBUG_RDOC, :$FILENAME, :$LOADED_FEATURES, :$LOAD_PATH, :$PROGRAM_NAME, :$VERBOSE, :$\\, :$_, :$`, :$stderr, :$stdin, :$stdout, :$~]"
Exceptions
$! (Exception)
$@ (Backtrace)
Pattern Matching
$~ (MatchData)
$& (Matched Substring)
$` (Pre-Match Substring)
$' (Post-Match Substring)
$+ (Last Matched Group)
$1, $2, Etc. (Matched Group)
Separators
$/ (Input Record Separator)
$; (Input Field Separator)
$\ (Output Record Separator)
Streams
$stdin (Standard Input)
$stdout (Standard Output)
$stderr (Standard Error)
$< (ARGF or $stdin)
$> (Default Standard Output)
$. (Input Position)
$_ (Last Read Line)
Processes
$0
$* (ARGV)
$$ (Process ID)
$? (Child Status)
$LOAD_PATH (Load Path)
$LOADED_FEATURES
Debugging
$FILENAME
$DEBUG
$VERBOSE
Other Variables
$-a
$-i
$-l
$-p
Deprecated
$=
$,
Pre-defined global constants
Streams
STDIN
STDOUT
STDERR
Environment
ENV
ARGF
ARGV
TOPLEVEL_BINDING
RUBY_VERSION
RUBY_RELEASE_DATE
RUBY_PLATFORM
RUBY_PATCHLEVEL
RUBY_REVISION
RUBY_COPYRIGHT
RUBY_ENGINE
RUBY_ENGINE_VERSION
RUBY_DESCRIPTION
Embedded Data
DATA
Methods
https://docs.ruby-lang.org/en/master/syntax/methods_rdoc.html
Defined by keyword def
. You can undefine by undef
.
Can begin with lowercase or underscore, followed by letters, numbers or underscores. May end with ?, !, =.
-
Predicate
methods end with a ? and return a boolean result. -
Bang
methods end with a ! and modify the object in some way. E.g. String .reverse or .reverse!. The first one returns a modified string and the second one modifies the receiver in place. -
Assignment
methods end with = and modify the object in some way.
Parentheses are optional: def hello; end
is the same as def hello() end
.
A method is invoked using dot syntax: receiver.method
In other words:
- We ask the object to perform an action.
- The object receives a message.
- We send a message to the object.
Preference to use parentheses in all but the simplest cases. This would be idiomatic, it means in line with the language's conventions.
def hello
puts 'hi'
end
Since Ruby 3.0 endless method:
def a_method(arg) = puts arg
Method arguments
def hello(greeting = "hi", name = "bob", question, *args)
puts "#{greeting} #{name} #{question} #{args}"
end
- `greeting` is a default argument.
- `name` is a default argument.
- `question` is a required argument.
- `args` is a splat argument. It collects all remaining arguments into an array.
A class method: def self.method_name
and an instance method: def method_name
.
Positional arguments: are passed to the method based on their position.
Keyword arguments: are passed based on the keyword and can be listed in any order.
Keyword arguments: def method_name(city: "value", state:)
When calling the method, you can pass the arguments in any order, but each keyword argument must be part of the call: method_name(state: "CA", city: "San Francisco")
.
Collect arguments into Hash with double-splat, or : `def method_name(args)`. A bare single splat will catch positional arguments, bare double splat will catch keyword arguments.
def do_stuff(*)
# anonymous splat parameter
do_stuff_2(*)
end
def do_stuff_2(*array_args)
array_args
end
def do_stuff_3(first, *, last)
puts "first: #{first}, last: #{last}"
end
# passing bare & character to pass block
class Child < Parent
def do_it(&)
do_it_2(&)
end
end
# will catch all arguments.
def do_it(*args, **kwargs, &block); end
# the triple dot syntax will catch and pass all arguments, in a simpler anonymous way.
def do_it(...)
do_it_2(...)
end
Calling a method.
connection.download_mp3("jazz", speed: :slow) { |p| show_progress(p) }
# receiver.method(postional_parameter, keyword_parameter: "value") { |block_parameter| block_code(block_parameter) }
# 1. object invokes method
# 2. inside that method, self is set to that (receiver) object
# 3. method body is executed, possibly the block is called as well
# Ruby allows you to omit the receiver, in which case Ruby will default to use `self`.
class Thing
def hello
self.greet
greet
end
private def greet
puts 'hi'
end
end
Thing.new.hello
# "hi"
# "hi"
# => nil
Method calls without parentheses are sometimes called commands.
rule: If in doubt, use parentheses.
A return
statement exists from the currently executing method. It can be used to return a value from a method. If no value is specified, nil is returned.
def method_name(city:, country:)
puts city
puts country
end
data = {city: "ab", country: "bb"}
method_name(**data)
#ok
city = "cc"
country = "aac"
method_name(city:, country:)
#ok
# Passing block arguments:
["a", "f"].map(&:upcase)
# take the argument to this proc, and call the method whose name matches this symbol.
# the class Symbol implements the to_proc method, returning a Proc method.
# https://ruby-doc.org/3.3.4/Object.html#method-i-method
# objects have a method named method, which takes a symbol and returns the object's method of the same name
number = 2
method = number.method(:*)
(1..3).map(&method)
# => [2, 4, 6]
Classes
In object oriented programming, a class is a blueprint for a domain concept.
Instances are created by a constructor. The standard constructor method is called new
. When you call Bike.new, Ruby holds an uninitialized object and calls that objects initialize
method, passing all arguments from .new
. This sets up the object's state. Instances have a unique object_id (object identifier).
#
is the default string representation of an object.
class Bike
def initialize(price)
@price = price
end
end
bike = Bike.new(100)
puts bike
#