4. The Ruby Language
Ruby is a dynamic programming language with a
complex but expressive grammar and
a core class library with a rich and powerful
API. Ruby draws inspiration from Lisp,
Smalltalk, and Perl, but uses a grammar that is
easy for C and Java programmers to
learn. Ruby is a pure object-oriented language,
but it is also suitable for procedural and
functional programming styles. It includes
powerful metaprogramming capabilities
and can be used to create domain-specific
languages or DSLs.
13. Package Management with gem
# gem install rails
Successfully installed activesupport-1.4.4
Successfully installed activerecord-1.15.5
Successfully installed actionpack-1.13.5
Successfully installed actionmailer-1.3.5
Successfully installed actionwebservice-1.2.5
Successfully installed rails-1.2.5
6 gems installed
Installing ri documentation for activesupport-1.4.4...
Installing ri documentation for activerecord-1.15.5...
...etc...
14. Rake
# Rake is a software task management and build automation
# tool
task :default => [:test]
task :test do
ruby "test/tc_simple_number.rb"
end
15. app/
bin/ #Files for command-line
execution
lib/
appname.rb #Classes and so on
lolcatz/
moar.rb #lolcatz::moar
Rakefile #Tasks like testing, building
Gemfile #Defines the source of the gem
README
test,spec,features/ #Whichever means of testing you go for
appname.gemspec #If it's a gem
Project Structure
16.
17. require
Use the keyword require to import code you want to use
$ irb
>> time.now
Traceback (most recent call last):
4: from
/Users/dlresende/.rbenv/versions/2.7.1/bin/irb:23:in `<main>'
3: from
/Users/dlresende/.rbenv/versions/2.7.1/bin/irb:23:in `load'
2: from
/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gem
s/irb-1.2.3/exe/irb:11:in `<top (required)>'
1: from (irb):1
NameError (undefined local variable or method `time' for
main:Object)
Did you mean? timeout
>> require 'date'
=> true
>> Time.now
=> 2020-06-14 22:29:51.240806 +0100
18. $LOAD_PATH
require will load code that's available in $LOAD_PATH
$ irb
>> $LOAD_PATH
=> ["/usr/local/Cellar/rbenv/1.1.2/rbenv.d/exec/gem-rehash",
"/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7
.0",
"/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7
.0/x86_64-darwin19",
"/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/site_ruby",
"/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/vendor_ruby/2
.7.0",
"/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/vendor_ruby/2
.7.0/x86_64-darwin19",
"/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/vendor_ruby",
"/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/2.7.0",
"/Users/dlresende/.rbenv/versions/2.7.1/lib/ruby/2.7.0/x86_64-
darwin19"]
19. Comments
# Comment line with #
=begin
Comment multiple lines...
…like this
Not very popular
=end
23. Combined comparison
operator (2/2)
# === (case equality)
# For class Object, effectively the same as calling ==,
# but typically overridden by descendants to provide meaningful
# semantics in case statements.
case some_object
when /a regex/
# The regex matches
when 2..4
# some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
# the lambda returned true
end
24. Regexp and Range
# Regular Expressions and Ranges have a literal syntax in Ruby:
/[Rr]uby/ # Matches "Ruby" or "ruby"
/d{5}/ # Matches 5 consecutive digits
1..3 # All x where 1 <= x <= 3
1...3 # All x where 1 <= x < 3
# Regexp and Range objects define the normal == operator for
# testing equality. In addition, they also define the === operator for
# testing matching and membership.
# Ruby’s case statement (like the switch statement of C or Java)
# matches its expression against each of the possible cases using
# ===, so this operator is often called the case equality operator.
25. Bitwise operators
a = 60 # (0011 1100)
b = 13 # (0000 1101)
a & b # => 12 (0000 1100) # AND
a | b # => 60 (0011 1101) # OR
a ^ b # => 49 (0011 0001) # XOR
~a # => -61 (1100 0011) # One Complement
a << 2 # => 240 (1111 0000) # Left Shift
a >> 2 # => 15 (0000 1111) # Right Shift
26. Everything is Object
# Numeric literals are objects
3.class # => Fixnum
3.to_s # => "3"
# Arithmetic is just syntactic sugar
# for calling a method on an object
1.+(3) # => 4
10.* 5 # => 50
27. Special Values are Objects
nil # equivalent to null in other languages
true
false
nil.class # => NilClass
true.class # => TrueClass
false.class # => FalseClass
28. Logical Operators (1/2)
!true #=> false # Not
true && true #=> true # AND
true || false #=> true # OR
not true #=> false # Not
true and true #=> true # And
true or 0 #=> true # Or
# and is the same as && but with lower precedence
# they both use short-circuit evaluation (same for or)
29. Logical Operators (2/2)
# and, or operators are meant to be used as flow-control
# constructs to chain statements together until one of them
# returns true or false.
# do_something_else only called if do_something succeeds.
do_something() and do_something_else()
# log_error only called if do_something fails.
do_something() or log_error()
30. Strings
# Strings are objects
'I am a string'.class # => String
"I am a string too".class # => String
# Prefer single quoted strings to double quoted ones where
# possible
# Double quoted strings perform additional inner calculations
31. Multi-line String
$ irb
>>> puts 'This '
>>> 'is '
>>> 'a '
>>>'multi-line '
>>> 'string'
This is a multi-line string
32. String Interpolation
placeholder = 'use string interpolation'
"I can #{placeholder} when using double quoted strings"
# => "I can use string interpolation when using double quoted
strings"
34. Print to the output
# print to the output with a newline at the end
puts "I'm printing!"
# => I'm printing!
# => nil
# print to the output without a newline
print "I'm printing!"
# => I'm printing! => nil
35. Assignments (1/3)
x = 25 # => 25
x # => 25
# Note that assignment returns the value assigned
# This means you can do multiple assignment:
x = y = 10 # => 10
x # => 10
y # => 10
# By convention, use snake_case for variable names
snake_case = true
36. Assignments (2/3)
# Assignment can be combined with operators such as + and - :
x += 1 # Increment x: note Ruby does not have ++.
y -= 1 # Decrement y: no -- operator, either.
37. Assignments (3/3)
# Ruby supports parallel assignment, allowing more than one
value # and more than one variable in assignment expressions:
x, y = 1, 2 # Same as x = 1; y = 2
a, b = b, a # Swap the value of two variables
x,y,z = [1,2,3] # Array elements automatically assigned to variables
38. Symbols
# Symbols are objects.
# Symbols are immutable, reusable constants represented
# internally by an integer value.
# They're often used instead of strings to efficiently convey
# specific, meaningful values.
:pending.class # => Symbol
status = :pending
status == :pending # => true
status == 'pending' # => false
status == :approved # => false
39. Arrays (1/4)
# This is an array
array = [1, 2, 3, 4, 5] # => [1, 2, 3, 4, 5]
array.class # => Array
# Arrays can contain items of different types
[1, 'hello', false] # => [1, "hello", false]
40. Arrays (2/4)
# Arrays can be indexed…
# ...from the front
array[0] # => 1
array.first # => 1
array[12] # => nil
# ...from the end
array[-1] # => 5
array.last # => 5
# ...with a start index and length
array[2, 3] # => [3, 4, 5]
# ...or with a range
array[1..3] # => [2, 3, 4]
array[*'a'..'z'] # => ['a','b', 'c', …, 'z']
41. Arrays (3/4)
# Like arithmetic, [var] access
# is just syntactic sugar
# for calling a method [] on an object
array.[](0) # => 1
array.[] 0 # => 1
array.[] 12 # => nil
# In Ruby, parentheses are usually optional and they are
# commonly omitted, especially when the method being invoked
# takes no arguments.
42. Arrays (4/4)
# Reverse an Array
a = [1, 2, 3]
a.reverse! # => [3, 2, 1]
# Add to an array like this
array << 6 # => [1, 2, 3, 4, 5, 6]
# Or like this
array.push(6) # => [1, 2, 3, 4, 5, 6]
# Check if an item exists in the array
array.include?(1) # => true
43. Exclamation and question
marksarray = [1, 2, 3]
# The question mark is a code style convention;
# it indicates that a method returns a boolean value.
# The question mark is a valid character at the end of a method.
# These methods are called predicated methods.
array.include?(1) # => true
# In general, methods that end in ! indicate that the method will
# modify the object it's called on. Ruby calls these "dangerous
# methods" because they change state that someone else might
# have a reference to.
# These methods are called mutator methods.
array.reverse! # => [3, 2, 1]
array # => [3, 2, 1]
44. Hashes (1/2)
# Hashes are Ruby's primary dictionary with keys/value pairs.
# Hashes are denoted with curly braces:
hash = { 'color' => 'green', 'number' => 5 }
hash.keys # => ['color', 'number']
# Hashes can be quickly looked up by key:
hash['color'] # => 'green'
hash['number'] # => 5
# Asking a hash for a key that doesn't exist returns nil:
hash['nothing here'] # => nil
45. # Since Ruby 1.9, there's a special syntax when using symbols as
# keys.
# Hashes can use any object as a key, but Symbol objects are the
# most commonly used. Symbols are immutable, interned strings.
new_hash = { defcon: 3, action: true }
new_hash.keys # => [:defcon, :action]
new_hash.values # => [3, true]
# Check the existence of keys and values in hash
new_hash.key?(:defcon) # => true
new_hash.value?(3) # => true
# Tip: Both Arrays and Hashes are Enumerable
# They share a lot of useful methods such as each, map, count,
# and more
Hashes (2/2)
46. # Code blocks are chunks of code that you can associate with
# method invocations. It’s analogous to lambdas,
# anonymous functions or closures in other languages.
# We can define blocks between braces...
some_method { puts 'hello' }
# ...or between do..end
some_method do
print 'hello '
print 'world'
end
# The Ruby standard is to use braces {} for single-line blocks and
# do..end for multi-line blocks.
Blocks (1/2)
47. # The keyword yield executes the block passed to the method
def some_method
yield('hello', 'world')
end
# You can pass parameters to blocks like this:
some_method { |str1, str2| puts str1 + ' ' + str2 }
# The ability to associate a block of code with a method invocation
# is a fundamental and very powerful feature of Ruby.
Blocks (2/2)
48. # Control structures such as if that would be called
# statements in other languages are actually expressions
if true
'if'
elsif false
'else if, optional'
else
'else, optional'
end
# => "if"
Control Structures (1/7)
49. for counter in 1..5
puts "iteration #{counter}"
end
# => iteration 1
# => iteration 2
# => iteration 3
# => iteration 4
# => iteration 5
Control Structures (2/7)
50. # HOWEVER, No-one uses for loops.
# Instead you should use the "each" method and pass it a block.
# The "each" method of a range runs the block once for each
# element of the range.
# The block is passed a counter as a parameter.
# Calling the "each" method with a block looks like this:
(1..5).each { |counter| puts "iteration #{counter}" }
# => iteration 1
# => iteration 2
# => iteration 3
# => iteration 4
# => iteration 5
Control Structures (3/7)
51. # If you still need an index you can use "each_with_index"
# and define an index variable
array.each_with_index do |element, index|
puts "#{element} is number #{index} in the array"
end
Control Structures (4/7)
52. counter = 1
while counter <= 5 do
puts "iteration #{counter}"
counter += 1
end
# => iteration 1
# => iteration 2
# => iteration 3
# => iteration 4
# => iteration 5
# although the language does support while loops, it is more
# common to perform loops with iterator methods:
3.times { print "Ruby! " } # Prints "Ruby! Ruby! Ruby! "
Control Structures (5/7)
53. letter = 'B'
case letter
when 'A'
puts 'a'
when 'B'
puts 'b'
when 'C'
puts 'c'
else
puts 'none of the above'
end
#=> "b"
Control Structures (6/7)
54. # cases can also use ranges
grade = 82
case grade
when 90..100
puts 'Hooray!'
when 80...90
puts 'OK job'
else
puts 'You failed!'
end
#=> "OK job"
Control Structures (7/7)
55. begin
# code here that might raise an exception
raise NoMemoryError, 'You ran out of memory.'
rescue NoMemoryError => exception_variable
puts 'NoMemoryError was raised', exception_variable
rescue RuntimeError => other_exception_variable
puts 'RuntimeError was raised now'
else
puts 'This runs if no exceptions were thrown at all'
ensure
puts 'This code always runs no matter what'
end
Exception handling
56. # Methods (and all blocks) implicitly return the value of the last
# statement
def sum(x, y)
x + y
end
# Parentheses are optional where the result is unambiguous
# Method arguments are separated by a comma
sum 3, 4 #=> 7
sum sum(3, 4), 5 #=> 12
Methods (1/10)
58. # Define another name for the same method.
# It is common for methods to have multiple names in Ruby
alias size length # size is now a synonym for length
Methods (3/10)
59. # All methods have an implicit, optional block parameter
# that can be invoked with the yield keyword
def surround
print '{'
yield
print '}'
end
surround { print 'hello'}
# => {hello}
Methods (4/10)
60. # You can pass a block to a function
# "&" marks a reference to a passed block
def guests(&block)
block.call 'some_argument'
end
guests { |input| print input}
#=> some_argument
Methods (5/10)
61. # If you pass a list of arguments, it will be converted to an array
# That's what splat operator ("*") is for
def list(*array)
array.each { |elem| print elem }
end
list(1, 2, 3)
#=> 123
Methods (6/10)
62. # If a method returns an array, you can use destructuring
# assignment
def foods
['pancake', 'sandwich', 'quesadilla']
end
breakfast, lunch, dinner = foods
breakfast #=> 'pancake'
dinner #=> 'quesadilla'
lunch #=> 'sandwich'
Methods (7/10)
63. def global_quare(x)
x*x
end
# When a method is defined outside of a class or a module, it is
effectively a global function rather than a method to be invoked
on an object. (Technically, however, a method like this becomes a
private method of the Object class.)
# In Ruby there are 3 types of methods:
- public: anyone can access
- protected: can only be called by instances of a class (or
subclasses)
- private: can only be called by instances of the class
Methods (8/10)
64. # Methods can also be defined on individual objects by prefixing
# the name of the method with the object on which it is defined.
# Methods like these are known as singleton methods, and they
# are how Ruby defines class methods:
def Math.square(x)
x*x
end
# Define a class method of the Math module
# The Math module is part of the core Ruby library, and this code
adds a new method to it. This is a key feature of Ruby—classes
and modules are “open” and can be modified and extended at
runtime.
Methods (9/10)
65. # Methods that end with an equals sign = are special because
# Ruby allows them to be invoked using assignment syntax.
# If an object o has a method named x= , then the following two
# lines of code do the very same thing:
o.x=(1) # Normal method invocation syntax
o.x = 1 # Method invocation through assignment
Methods (10/10)
66. # A class is a collection of related methods that operate on the state of an object
class Human
# A class variable (or attributes) is shared by all instances of this class.
@@species = 'H. sapiens'
def initialize(name, age = 0) # Basic initializer, gets called on Human.new
# Assign the argument 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 = age
end
def name=(name) # Basic setter method
@name = name
end
def name # Basic getter method
@name
end
end
Classes (1/5)
67. class Human
@@species = 'H. sapiens'
# A class method uses self to distinguish from instance methods.
# It can only be called on the class, not an instance.
# self is actually the class name.
# In Ruby docs class methods are represented with a ".": Human.say
def self.say(msg)
puts msg
end
# Also use self when calling writer methods: self.species=
# ...so that Ruby knows we're calling the method, not the variable
# Instance method
# In Ruby docs instance methods are represented with a "#": Human#species
def species
@@species
end
end
Classes (2/5)
68. # Instantiate a class
diego = Human.new('Diego Lemos')
# Calling methods
diego.species #=> "H. sapiens"
diego.name #=> "Diego Lemos"
diego.name = 'Diego LEMOS' #=> "Diego LEMOS"
diego.name #=> "Diego LEMOS"
# Calling the class method
Human.say('hello') #=> "hello"
Classes (3/5)
69. class Person
# Getter/setter methods can also be created individually like this:
attr_reader :name # will create the conventional method name
attr_writer :name # will create the conventional method name=
end
person = Person.new
person.name = 'Diego'
person.name # => "Diego"
Classes (4/5)
70. class Person
# Even this can get repetitive.
# When you want both reader and writer just use accessor!
attr_accessor :name
end
person = Person.new
person.name = 'Diego'
person.name # => "Diego"
Classes (5/5)
71. # Variables that start with $ have global scope
$var = 'global variable'
defined? $var #=> "global-variable"
# Variables that start with @ have instance scope
@var = 'instance variable'
defined? @var #=> "instance-variable"
# Variables that start with @@ have class scope
@@var = 'class var'
defined? @@var #=> "class variable"
# Variables that start with a capital letter are constants
Var = 'constant'
defined? Var #=> "constant"
Variables’ scope
72. class Human
# Class variable is shared among the class and all of its descendants
@@foo = 0
def self.foo
@@foo
end
def self.foo=(value)
@@foo = value
end
end
class Worker < Human
end
Human.foo #=> 0
Worker.foo #=> 0
Human.foo = 2 #=> 2
Worker.foo #=> 2
Derived classes (1/2)
73. class Human
# Class instance variable is not shared by the class's descendants
@bar = 0
def self.bar
@bar
end
def self.bar=(value)
@bar = value
end
end
class Doctor < Human
end
Human.bar # => 0
Doctor.bar # => nil
Derived classes (2/2)
74. module ModuleExample
def foo
'foo'
end
class MyClass; end # Module becomes a namespace: ModuleExample::MyClass.new
end
# Including modules binds their methods to the class instances
class Person
include ModuleExample
end
Person.foo # => NoMethodError: undefined method `foo' for Person:Class
Person.new.foo # => 'foo'
# Extending modules binds their methods to the class itself
class Book
extend ModuleExample
end
Book.foo # => 'foo'
Book.new.foo # => NoMethodError: undefined method `foo' << Modules cannot be
instantiated
Modules
75.
76. # Ruby provides a framework in its standard library for setting up,
# organizing, and running tests called Test::Unit.
require_relative "../lib/simple_number"
require "test/unit"
class TestSimpleNumber < Test::Unit::TestCase
def test_simple
assert_equal(4, SimpleNumber.new(2).add(2) )
assert_equal(6, SimpleNumber.new(2).multiply(3) )
end
end
Test::Unit