You are on page 1of 33

CodeCademy Ruby

Introduction to Ruby
Ruby is a powerful, flexible programming language. Ruby is:

 High-Level, meaning reading and writing Ruby is really easy-it looks a lot like regular English
 Interpreted, meaning you don’t need a compiler to write and run Ruby. Interpreters directly
execute the code, compilers do not.
 Object-oriented, meaning it allows users to manipulate data structures called objects in order
to build and execute programs. Everything in Ruby is an object.
 Easy to use, Ruby was designed by Yukihiro Matsumoto, or “Matz”, in 1995. Matz set out to
design a language that emphasized human needs over those of the computer, which is why
Ruby is so easy to pick up.

Creating variables can be done like in python where you do not need to state the type of variable:

# Use # to make single line comments


my_num = 25 # Variable of type Numeric, which is any number
my_boolean = true # Variable of type Boolean, true or false
my_string = “Ruby” # Variable of type String, double quotes
# Ruby is case-sensitive

Ruby has the 6 basic arithmetic operators that most languages have:

Addition + Subtraction - Multiplication * Division / Exponentiation ** Modulo %

The print command takes whatever you give it and prints it to the screen. It does not add a line
after it so you can print on the same line. The puts statement does the same as print but adds a
new line after. It is equivalent to System.out.println(); in Java

Because everything in Ruby is an object, everything in Ruby has certain built-in abilities called
methods. For instance strings have built-in methods that can tell you the length of the string,
reverse the string and more.

The interpreter is the program that takes your code you write and runs it. You type code in the
editor, the interpreter reads your code, and its shows you the result of running your code in the
console.

Methods are summoned using . (dot).

puts “Harvey”.length # .length on strings will return string length


# returns 6
puts “Harvey”.reverse # .reverse on strings will reverse the string
# returns yevraH
puts “Harvey”.upcase # .upcase to convert string to uppercase
# returns HARVEY
puts “Harvey”.downcase # .downcase to convert string to lowercase
# returns harvey
# This is a single-line comment

=begin
this is a multi-line comment
do not put anything or spaces after =begin otherwise it breaks comment
=end

Local variables, by convention, should start with a lowercase letter and words should be
separated by underscores, like counter or masterful_method. Ruby won’t stop you from
starting your local variables with other symbols, such as capital letters, $s, or @s, however it is
best you follow convention.

Methods can be chained like this:

name = “Harvey”.downcase.reverse.upcase # returns YEVRAH


Putting the Form in Formatter
You can use the gets method to get user input:

Variable_name = gets.chomp # gets method gets input from user


# Ruby automatically adds a blank line after each bit of input;
# chomp removes that extra line.

# we can print out formatted strings using: #{variable}


first_name = “Kevin”
puts “Your name is #{first_name}!” # prints Your name is Kevin!

# we can use .capatilize to return capatilised strings


first_name = gets.chomp
first_name = first_name.capitalize # returns capitalised string

# .capatilize! will instead modify the value contained within the


# variable itself.
first_name = gets.chomp.capitalize! # modifies the input before assigned
# or
first_name.capitalize! # modifies value contained
Control Flow In Ruby
Ruby does not care about whitespace, however it’s a convention that is followed.

An If statement allows for you to run an expression and execute code depending on whether the
expression evaluates to true or false. Starts with ’if’ and ends with ‘end’.
'elsif’ is equivalent to else if, and you can have any amount of them. ‘else’ and ‘if’ only one.

if user_num < 0
puts "You picked a negative integer!"
elsif user_num > 0
puts "You picked a positive integer!"
else
puts "You picked zero!"
end

Sometimes you want to use control flow to check if something is false, rather than true.
You can reverse your if/else, but you can instead use an unless statement.

unless condition
# do if false
else
# do if true
end

Executes code if the condition is false, if true then the code in the else is executed

Can compare using comparators:


== equals < less than > greater than <= less than or equals >= greater than or equals
!= not equals

Can also compare using logical or Boolean operators:


&& and || or ! not ( ) use brackets to choose what is evaluated first
Thith Meanth War!
The .include? method evaluates to true if it finds what its looking for and false otherwise. As a
general rule, Ruby methods that end with ? evaluated to the Boolean values.

# returns true if “substring” in my_string


if my_string.include? “substring”
# do if true
end

The .gsub(pattern, replacement) method, which stands for global substitution, can replace any
substring if it fits a regex pattern. Replaces all instances not just first.

string_to_change.gsub!(pattern, replacement)

A possible pattern could be /s/ which would change all instances where there is the letter ‘s’

string = “shelf”
string.gsub!(/s/, “b”) # string now contains “bhelf”

string = “cat”
string.gsub!(“at”, “ote”) # string now contains “cote”
Loops and Iterators
A while loop checks to see if a certain condition is true, and while it is, the loop keeps running.

while condition
# do while true
end

# example: prints 1 to 10
while counter < 11
puts counter
counter += 1
end

The until loop is a backwards while loop, in that it will continue to loop while false

i = 0
until i == 6
i += 1
end
puts i

Assignment operators:
+= -= *= /=

A for loop is used when you know how many times you will be looping such as in dealing with
arrays.

for num in 1...10 # 3 dots = for num in range 1 to 10 (excluding 10)


puts num
end # prints 1 2 3 4 5 6 7 8 9

for num in 1..15 # 2 dots = for num in range 1 to 10 (including 10)


puts num
end # prints 1 2 3 4 5 6 7 8 9 10

3 dots are exclusive and 2 dots are inclusive.

It is possible to repeat a task using an iterator. An iterator is just a Ruby method that repeatedly
invokes a block of code. The code block is just the bit that contains the instructions to be repeated.
The simplest iterator is the loop method:

loop { puts “Hello, world!” }

In Ruby, curly braces {} are generally interchangeable with the keywords do and end.
Knowing this, we can write a smarter loop than the one above:

rb i = 0 loop do i += 1 print “#{i}” break if i > 5 end

The break keyword breaks a loop as soon as its condition is met.

break if true
The next keyword can be used to skip over certain steps in the loop. For instance printing out only
odd numbers:

for i in 1..5 # inclusive range 1 to 5


next if i % 2 == 0 # skips if i is even
print i # prints i with no new line
end

An array is just a list of items between square brackets, like [1,2,3,4].


They do not need to be in order.

my_array = [1,2,3,4,5]

The .each method can apply an expression to each element of an object, one at a time.

object.each { |item|
# expression
}
# you can also use the do keyword instead:
object.each do |item|
#expression
end

The variable name of the array goes in the | |. Actual example:

array = [1,2,3,4,5]
array.each do |x| # for each element in the array add 10 to it and print
x += 10
print “#{x}”
end

The .times method is like a super compact for loop: it can be used to run code a specified number
of times. For example printing wow five times:

5.times {print “wow”}


# or
5.times do print “wow” end
Redacted!
The .split method takes in a string and returns an array. If we pass in a bit of text in
parentheses, .split will divide the string wherever it sees that bit of text, called a delimiter. For
example:

array = text.split(“,”)

tells ruby to split up the string text whenever it sees a comma.


Creating Arrays
array = [1, 2, 3, 4, 5]

Each element in an array has an index, the first being 0, then 1 and so on. We can access
elements of the array directly through these numbers using brackets like:

print array[2] # prints 3 as 3 is at index 2

You can make an array of any collection of Ruby objects.

string_array = [“hi”,”hello”,”salutations”]

Arrays of Arrays are called multidimensional arrays, for example a two dimensional array:

array_2d = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]

Hashes are sort of like python dictionaries, they are a collection of key-value pairs. Syntax:

hash = {
key1 => value1,
key2 => value2,
key3 => value3
}

Values are assigned to keys using =>, you can use any Ruby object for a key or value.

my_hash = {
"name" => "Eric",
"age" => 26,
"hungry?" => true
}

You can also create a hash using Hash.new, like so:

my_hash = Hash.new

Setting a variable equal to Hash.new creates a new, empty hash; same as setting the variable
equal to empty curly braces. It is used over curly braces as it is more concise.
We can add to a hash in two ways: if we created it using literal notation, we can simply add a new
key-value pair directly between the curly braces. If we used Hash.new, we can add to the hash
using bracket notation.

my_hash[key] = value

You can access values in a hash just like in an array.

puts my_hash[key]
When we loop over an array or hash, we say that we iterate over it. We’ll be using the .each
iterator to iterate over arrays and hashes in this section.

Iterating over arrays:

my_array.each {|element| puts element} # prints element


# can be other action/operation

Example:

languages = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]


languages.each {|language| puts language}

We can iterate through multi-dimensional arrays using nested .each methods:

s = [["ham", "swiss"], ["turkey", "cheddar"], ["roast beef", "gruyere"]]


s.each {|sub_array| sub_array.each {|item| puts item}}

When iterating over hashes, we need two placeholder variables to represent each key/value pair.

my_hash.each {|key, value| action}

Example:

secret_identities = {
"The Batman" => "Bruce Wayne",
"Superman" => "Clark Kent",
"Wonder Woman" => "Diana Prince",
"Freakazoid" => "Dexter Douglas"
}

secret_identities.each {|key, value| puts "#{key}: #{value}"}


Create a Histogram
Hashes can have default values:

h=hash.new(default value)
puts h # {} printed
puts h[“any key”] # default value printed

The .sort_by function sorts an array and returns an array of arrays.

frequencies = frequencies.sort_by {|word,count|count}


# Sorts by word count smallest to largest, reverse to get opposite
Methods, Blocks and Sorting
A method is a reusable section of code written to perform a specific task in a program. Methods
make it easier to find and fix bugs if you’ve organized your program well. By assigning specific
tasks to separate methods, you make your program less redundant and your code more reusable.

Methods are defined using the keyword def, short for define. They have three parts:

1. The header, which includes the def keyword, the name of the method, and any arguments the
method takes.
2. The body, which is the code block that describes the procedures the method carries out. The
body is indented by convention.
3. The method ends with the end keyword.

Example:

def welcome
puts “Welcome to Ruby!”
end

You can call a method just by typing its name.


If the method can’t be found then you get a NameError.

welcome # calls welcome method, prints “Welcome to Ruby”

If a method takes arguments, we say it accepts or expects those arguments. For example:

def square(n)
puts n ** 2
end

square(12) # prints “144”

The argument is the piece of code you put between the method’s parentheses when you call it,
and the parameter is the name you put between the methods parentheses when you define it.

For example above we gave the method the parameter n and passed it the argument 12.

You can think of parameters as placeholders the method definition gives to arguments since it
doesn’t know what arguments it’s going to get.

Splat arguments are arguments that are preceded by a *, which tells the program that a method
can receive one or more arguments.

def what_up(greeting, *friends)


friends.each { |friend| puts "#{greeting}, #{friend}!" }
end

what_up("What up", "Ian", "Zoe", "Zenas", "Eleanor")

friends is turned into an array to hold all the values.


We can use a method to return a value with return.

def double(n)
return n * 2
end

You can think of blocks as a way of creating methods that don’t have a name, similar to lambdas
in Python. Blocks can be defined with the keywords do and end or curly braces. Example:

1.times do
puts "I'm a code block!"
end

1.times { puts "As am I!" }

A method can take a block as a parameter, such as what .each method does. Passing a block to a
method is a great way of abstracting certain tasks from the method and defining those tasks when
we call the method.

Use .sort to return a sorted array or .sort! to sort an array.

my_array.sort!
my_array = my_array.sort

We can use an operator called the combined comparison operator to compare two Ruby objects.
The combined comparison operator looks like this: <=>. It returns 0 if the first operand equals the
second, 1 if the first operand is greater than the second, and -1 if the first operand is less than the
second.

book_1 = "A Wrinkle in Time"


book_2 = "A Brief History of Time"

puts book_1 <=> book_2 # prints 1, so the first book should go second

A block that is passed into the sort method should return -1 if the first block parameter should
come before the second, 1 if vice versa and 0 if equal.

The sort method assumes by default that you want to sort in ascending order, but it accepts a
block as an additional argument that allows you to specify how two items should be compared.

books = ["Charlie and the Chocolate Factory",


"War and Peace",
"Utopia",
"A Brief History of Time",
"A Wrinkle in Time"]

# To sort our books in ascending order, in-place


books.sort! { |firstBook, secondBook| firstBook <=> secondBook }

# Sort your books in descending order, in-place below


books.sort! { |firstBook, secondBook| secondBook <=> firstBook}
To sort an array in descending order:

fruits = ["orange", "apple", "banana", "pear", "grapes"]

fruits.sort! do |fruitOne, fruitTwo|


fruitTwo <=> fruitOne
end
puts fruits
Ordering Your Library
With methods we can put default values for parameters.

def alphabetize(arr, rev=false)


#actions
end
Hashes and Symbols
If you try to access a key in a hash that does not exist you get the special value nil. Along with
false, nil is one of two non-true values in Ruby. Every other object is “truthy”, so if you were to type

if 2
if “bacon”

these would be run.

false and nil are not equivalent, false means “not true”, while nil means “nothing at all”.

If you create your hash using the Hash.new syntax, you can specify a default like so:

my_hash = Hash.new("Trady Blix")

If you try to access a non-existent key in my_hash, you’ll get “Trady Blix” as a result.

The .object_id method gets the ID of an object-it’s how Ruby knows whether two objects are the
exact same object.

You can think of a Ruby symbol as a sort of name. Symbols aren’t strings.
There’s a key behaviour of symbols that makes them different from strings. While there can be
multiple different strings that all have the same value, there’s only one copy of any particular
symbol at a given time.

Symbols always start with a colon : . They must be valid Ruby variable names, so the first
character after the colon has to be a letter or underscore.

:symbol

Symbols are primarily used as either hash keys or referencing method names. Symbols make
good hash keys for a few reasons:
1. They are immutable, meaning they can’t be changed once created.
2. Only one copy exists at a given time, so they save memory
3. Symbols-as-keys are faster than strings-as-keys because of reasons 1 and 2

To convert between strings and symbols use .to_s and .to_sym.

:sasquatch.to_s
# ==> "sasquatch"

"sasquatch".to_sym
# ==> :sasquatch

.push(element) allows you to add an element to the end of an array.

arr = Array.new
arr.push(“www”) # array arr now contains “www”

Besides .to_sym, you can use .intern. This will internalize the string into a symbol and work just
like .to_sym

"hello".intern
# ==> :hello
The hash syntax, with the => symbol, is sometimes nicknamed the hash rocket style. This is
because => looks like a rocket.

Now you can type hashes like in python with the semi-colon at the end of the symbol and it
replacing the rocket. Example:

new_hash = {
one: 1,
two: 2,
three: 3
}

These are still symbols

.to_a can convert a range into an array. .zip can combine two equal sized arrays or ranges into a
Hash. Benchmark object can be used to benchmark operations and methods etc.

require 'benchmark' # imports file for use

string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]

string_time = Benchmark.realtime do
1000000.times { string_AZ["r"] }
end

symbol_time = Benchmark.realtime do
1000000.times { symbol_AZ[:r] }
end

puts "String time: #{string_time} seconds."


puts "Symbol time: #{symbol_time} seconds."

This builds two alphabet hashes: one that pairs string letters with their place in the alphabet and
one that uses symbols instead of string letters. We then benchmark the two to compare how fast it
is to look up a key in each array.

We can use .select to filter a hash for values that meet certain criteria.

grades = { alice: 100, bob: 92, chris: 95, dave: 97 }

grades.select { |name, grade| grade < 97 }


# ==> { :bob => 92, :chris => 95 }

grades.select will return a hash containing :bob and :chris and their values.

To iterate over just keys or just values we can use .each_key and .each_value.

my_hash = { one: 1, two: 2, three: 3 }

my_hash.each_key { |k| print k, " " } # the “ ” at the end is to put a


my_hash.each_value { |v| print v, " " } # space after the print
A Night At The Movies
The case statement can be used to match a variable to a number of possible values and then
execute code if it matches.

case language
when "Ruby"
puts "Web apps!"
else # ran if no other matches
puts "I don't know!"
end

to_i converts an string into an integer.

To remove a key value pair from the hash use .delete(key).

CRUD, Create, Read, Update, Delete, are the four basic functions of persistent storage.
The Zen Of Ruby
As a language Ruby prioritizes programmer productivity over program optimization. This mean
that it will not always run a program in the fastest way possible but strives to be a language that
programmers find easy and fun to use.

You can put an if statement on a single line: expression if boolean

puts “It’s true!” if true

You don’t need an end when you write your if statement all on one line.
You can do the same with the unless statement

puts “It’s false!” unless false

The ternary conditional expression is an more concise version of if/else. It’s called ternary because
it takes three arguments: a Boolean, an expression to evaluate if the Boolean is true, and an
expression to evaluate if false.

boolean ? expression_if_true : expression_if_false

puts 3 < 4 ? “3 is less than 4!” : “3 is not less than 4.”

The case statement can be folded up. Like:

case language when "Ruby" then puts "Web apps!" else puts "I don't
know!" end

The conditional assignment operator ||= assigns a value to a variable if it hasn’t already been
assigned.

fav_book ||= “book1”


fav_book ||= “book2”
puts fav_book # prints “book1”

Ruby’s methods will return the last evaluated expression if there is no return statement.

def add(a,b)
return a + b
end
#and
def add(a,b)
a + b
end

will both return the same value.

Ruby has short-circuit evaluation, which means that it doesn’t look at both expressions unless it
has to.

It we want to repeat something a specific number of times we can use the .times method. If we
want to repeat an action for every element in a collection we can use .each.
We can use .upto and .downto to print out a specific range of values:

95.upto(100) { |num| print num, " " }

"L".upto("P") {|letter| puts letter}

.repsond_to takes a symbol and returns true if an object can receive that method and false
otherwise. For example,

[1, 2, 3].respond_to?(:push)

Would return true as you can call .push on an array object. However

[1, 2, 3].respond_to?(:to_sym)

Would return false, as you can’t turn an array into a symbol.

.next will return the integer immediately following the integer its called on, meaning 4.next will
return 5.

Instead of typing out the .push method name, you can simply use <<, the concatenation operator,
also known as the shovel to add an element to the end of an array:

[1, 2, 3] << 4
# ==> [1, 2, 3, 4]

It also works on strings:

"Yukihiro " << "Matsumoto"


# ==> “Yukihiro Matsumoto”

You can always + or << to add a variable value into a string:

drink = "espresso"
"I love " + drink
# ==> I love espresso
"I love " << drink
# ==> I love espresso

But if you want to do it for non-string values, you have to use .to_s to make it a string:

age = 26
"I am " + age.to_s + " years old."
# ==> "I am 26 years old."
"I am " << age.to_s << " years old."
# ==> "I am 26 years old."

A better way is to use string interpolation which works with all types:

"I love #{drink}."


# ==> I love espresso.
"I am #{age} years old."
# ==> I am 26 years old.

Refactoring is improving the structure or appearance of our code without changing what it does.
The Refactor Factory
Blocks, Procs, and Lambdas
A Ruby block is just a bit of code that can be executed. Blocks can be combined with methods like
.each and .times to execute an instruction for each element in a collection, like a hash or array.

The collect method takes a block and applies the expression in the block to every element in an
array and returns it.

my_nums = [1, 2, 3]
my_new_nums = my_nums.collect { |num| num ** 2 }
# my_new_nums ==> [1, 4, 9]

To change or mutate the original my_nums array we must use .collect!

A method ending with ! will always change the value of the object, not return a copy.

Methods that accept blocks have a way of transferring control from the calling method to the block
and back again. We can build this into the methods we define by using the yield keyword.

def block_test
puts "We're in the method!"
puts "Yielding to the block..."
yield
puts "We're back in the method!"
end

block_test { puts ">>> We're in the block!" }

You can also pass parameters to yield.

def yield_name(name)
puts "In the method! Let's yield."
yield("Kim")
puts "In between the yields!"
yield(name)
puts "Block complete! Back in the method."
end

yield_name("Eric") { |n| puts "My name is #{n}." }

# Now call the method with your name!


yield_name("Harvey") {|n| puts "My name is #{n}!"}

blocks are not objects, and this is one of the very few exceptions to the “everything is an object”
rule in Ruby. Because of this blocks can’t be saved to variables and don’t have all the powers and
abilities of a real object.

A proc is like a “saved” block: you can name a block and turn it into a proc. Procs are great for
keeping your code DRY, which stands for Don’t Repeat Yourself. With a proc you only need to
write your code once and can use it many times.
To define a proc, you call Proc.new and pass in the block you want to save then assign those to a
variable.

cube = Proc.new { |x| x ** 3 }

We can than pass the proc to a method that would otherwise take a block, and we don’t have to
rewrite the block over and over. We do this with the & character which converts the proc into a
block.

[1, 2, 3].collect!(&cube)
# ==> [1, 8, 27]
[4, 5, 6].map!(&cube)
# ==> [64, 125, 216]

Procs have two main advantages:

1. Procs are full-fledged objects, so they have all the powers and abilities of objects.
2. Unlike blocks, procs can be called over and over without rewriting them.

We can call procs directly by using Ruby’s .call method.

test = Proc.new { # does something }


test.call
# does that something!

You can convert symbols to procs using & for example:

strings = ["1", "2", "3"]


nums = strings.map(&:to_i)
# ==> [1, 2, 3]

By mapping &:to_i over every element of strings, we turned each string into an integer!

Like procs, lambdas are objects. Lambdas are almost identical to procs in exception of syntax and
a few behavioural quirks.

lambda { puts "Hello!" }

Is the same as:

Proc.new { puts "Hello!" }

Lambdas are defined using the following syntax:

lambda { |param| block }

There are two main differences between lambdas and procs:

1. A lambda checks the number of arguments passed to it, while a proc does not.
This means that a lambda will throw an error if you pass it the wrong number of arguments,
whereas a proc will ignore unexpected arguments and assign nil to any missing.
2. When a lambda returns, it passes control back to the calling method; when a proc returns, it
does so immediately, without going back to the calling method.
.is_a? checks if a method is of a certain type
Object-Oriented Programming 1
A basic class consists only of the class keyword and the name of the class.

class NewClass
# Class magic here
end

By convention, class names start with a capital letter and use CamelCase instead of underscores

Initialize method is the constructor of the class and is equivalent to main method in java.

class Person
def initialize
#code
end
end

In Ruby, we use @ before a variable to signify that it’s an instance variable. This means that it
belongs to the instance of the class not the class itself.

def initialize(name)
@name = name
end

We can create an instance of a class just by calling .new on the class name, like so:

me = Person.new("Eric")

The scope of a variable is the context in which it’s visible to the program. You have global
variables, available everywhere, local variables, only in certain methods, class variables, belongs
to class, and instance variables, belongs to specific instances of the class.

Global variables start with $, instance variables start with @, class variables start with @@

class MyClass
$my_variable = "Hello!" #global variable
end
puts $my_variable

Global variables can be changed from anywhere in your program and are generally not a very
good idea. It’s much better to create variables with limited scope that can be changed from few
places. Global variables can be used to count how many instances of your class there is for
example.

Inheritance is the process by which one class takes on the attributes and methods of another, and
it’s used to express a is-a relationship. In Ruby inheritance works like this:

class DerivedClass < BaseClass


# Some stuff!
end

The derived class is the new class you’re making and the base class is the class from which the
new class inherits. You read “<” as “inherits from”.
To override a method simply define the method in your class with the exact same name.
The interpreter will use your method over the parent method.

You can directly access the attributes or methods of a superclass with the super keyword.

class DerivedClass < Base


def some_method
super(optional args)
# Some stuff
end
end
end

When you call super from inside a method, that tells Ruby to look in the superclass of the current
class and find a method with the same name as the one from which super is called. If it finds it,
Ruby will use the superclass version instead of the method.

Any given Ruby class can have only one superclass. Some languages allow a class to have more
than one parent, which is a model called multiple inheritance.

If you want to end a Ruby statement without going to a new line, you can just type a semicolon.
Like: class Monkey; end
This is a time saver when you’re writing something very short, like an empty class or a method
definition.
Virtual Computer
time.now returns the current time

A class method belongs to the class itself, and as such it’s prefixed with the class name.
Object-Oriented Programming 2
Ruby allows you to explicitly make some methods public and private. Public methods allow for an
interface with the rest of the program. Private methods cannot be accessed outside of the class.

Methods are public by default in Ruby. However we want to make it clear which methods are
public. We do this by putting public before our method definitions. Like:

class ClassName
# Some class stuff
public
def public_method
# public_method stuff
end
end

Everything after the public keyword to the end keyword will be public unless we say otherwise.

Private methods are private to the object where they are defined. This means that you can only
call these methods from the other code inside the object. The method cannot be called with an
explicit receiver. These are the objects on which methods are called. In object.method, object is
the receiver of method.

In order to access private information we need to create public methods that know how to get it.
This separates the private implementation from the public interface. So you create getter and
setter methods to validate all data that goes in and out.

Ruby needs methods in order to access attributes. We can use attr_reader to access a variable
and attr_writer to change it. If we write:

class Person
attr_reader :name
attr_writer :name
def initialize(name)
@name = name
end
end

Ruby does something like this for us automatically:

def name
@name
end

def name=(value)
@name = value
end

We can now read and write values as we please. We just pass our instance variables as symbols
to attr_reader or attr_writer. name= is just a Ruby convention saying “hey, this method sets a
value!”

attr_accessor makes a variable readable and writeable.


A module is like a toolbox that contains a set methods and constants. There are lots and lots of
Ruby tools you might want to use, but it would clutter the interpreter to keep them around all the
time. For that reason, we keep a bunch of them in modules and only pull in those module
toolboxes when we need the constants and methods inside.

You can think of modules as being very much like classes, only modules can’t create instances
and can’t have subclasses. They’re just used to store things. Example of a module Circle:

module Circle

PI = 3.141592653589793

def Circle.area(radius)
PI * radius**2
end

def Circle.circumference(radius)
2 * PI * radius
end
end

You can pull in pre-existing modules, but you can also make your own. You just use the module
keyword, like so:

module ModuleName
# Bits 'n pieces
End

Likes classes, module names are written in CapitalizedCamelCase, rather than


lowercase_with_underscores.

It doesn’t make much sense to include variables in modules, since variables change. Constants
however are supposed to always stay the same, so including helpful constants in modules is a
great idea.

Ruby doesn’t make you keep the same value for a constant once its’s initialized, but it will warn
you if you try to change it. Ruby constants are written in ALL_CAPS and are separated with
underscores if there’s more than one word.

An example of a Ruby constant is PI, which lives in the Math module.

One of the main purposes of modules is to separate methods and constants into named spaces.
This is called namespacing, is it’s how Ruby doesn’t confuse Math::PI with Circle::PI.

The double colon we used is called the scope resolution operator, which tells Ruby where you’re
looking for a specific bit of code. If we say Math::PI, Ruby knows to look inside the Math module to
get that PI, not any other PI.

puts Math::PI # prints PI constant from the Math module


Some modules like Math, are already present in the interpreter. Others need to be explicitly
brought in, however, and we can do this using require. Example:

require ModuleName

Any class that includes a certain module can use those module’s methods!

include ModuleName

A nice effect of this is that you no longer have to prepend your constants and methods with the
module name. Sine everything has been pulled in, we can simply write PI instead of Math::PI

When a module is used to mix additional behaviour and information into a class, it’s called a mixin.
Mixins allow us to customize a class without having to rewrite code.

Whereas include mixes a module’s methods in at the instance level, allowing instances of a
particular class to use the methods, the extend keyword mixes a module’s methods at the class
level. This means that class itself can use the methods as opposed to instances of the class.

module ThePresent
def now
puts "It's #{Time.new.hour > 12 ? Time.new.hour - 12 :
Time.new.hour}:#{Time.new.min} #{Time.new.hour > 12 ? 'PM' : 'AM'}
(GMT)."
end
end

class TheHereAnd
extend ThePresent
end

TheHereAnd.now
Banking on Ruby
class Account

attr_reader :name
attr_reader :balance

def initialize(name, balance=100)


@name = name
@balance = balance
end

private
def pin
@pin = 1234
end

private
def pin_error
return "Access denied: incorrect PIN."
end

public
def display_balance(pin_number)
if pin_number == pin
puts "Balance: $#{@balance}."
else
puts pin_error
end
end

public
def withdraw(pin_number, amount)
if pin_number == pin
@balance -= amount
puts "Withdrew #{amount}. New balance $#{@balance}."
else
puts pin_error
end
end

end

checking_account = Account.new("heloow",150000)

You might also like