Hashes in Ruby are used often to represent an object instead of or before an actual class object. This often happens when we get some type of input that can be parsed into sane parts. This could come in many different formats such as JSON, XML, YAML, or CSV. For example if we have some data:
Why isn't this updating?
name | |
---|---|
Jeremy Flores | [email protected] |
Kari Bancroft | [email protected] |
Each line of this could be represented as a Hash, using the table headers as keys:
person1 = {name: "Jeremy Flores", email: "[email protected]"}
person2 = {name: "Kari Bancroft", email: "[email protected]"}
Further we could groups these in an Array:
people = [
{ name: "Jeremy Flores", email: "[email protected]" },
{ name: "Kari Bancroft", email: "[email protected]" }
]
A Hash key can have any object as its value, even another Hash.
{ jeremy: # this is the key
{ # this entire hash is the value
last_name: "Flores",
first_name: "Jeremy",
address: {
street: "123 fake st",
city: "Seattle",
state: "WA"
},
pets: [
{
name: "Rosalita",
species: "dog"
},
{
name: "Raquel",
species: "cat"
}
]
}
}
A Hash is a great way to pass in arguments to the initialize
method of a Class. Have a look at this Class:
class Address
def initialize(first_name, last_name, street_one, street_two, city, state, country, postal_code)
@first_name = first_name
@last_name = last_name
@street_one = street_one
@street_two = street_two
@city = city
@state = state
@country = country
@postal_code = postal_code
end
end
What's the problem here? What happens if you don't have a street_two
attribute?
Let's try again using a hash:
class Address
def initialize(address_hash)
@first_name = address_hash[:first_name]
@last_name = address_hash[:last_name]
@street_one = address_hash[:street_one]
@street_two = address_hash[:street_two]
@city = address_hash[:city]
@state = address_hash[:state]
@country = address_hash[:country]
@postal_code = address_hash[:postal_code]
end
end
Address.new(first_name: "Jeremy", state: "WA")
Using a hash to provide parameters to a class' initialize
method lets us omit parameters that may not exist for some instances. It also adds clarity to instantiation process by explicitely providing keys and values.
Compare:
Address.new(first_name: "Jeremy", state: "WA")
with
Address.new("Jeremy","","","","WA","","")
It's very common for a method to have optional arguments. These arguments can represent common values, slightly modified functionality, or similar minor deviations.
Every method should embrace SRP (single responsibility principle).
Here's a method that might look familiar:
def exponate(base, power)
base ** power
end
We can define an optional argument by assigning a default value to an argument in the method declaration:
def exponate(base, power = 2)
# if we don't pass in a power, it will be assigned 2 by default
base ** power
end
exponate(2)
exponate(2, 3)
exponate(4)
Question: Is this a good use case for an optional argument?
Let's look at another example:
def exponate(base, power, abs = false)
if abs
(base ** power).abs
else
base ** power
end
end
exponate(2)
exponate(-2, 3)
exponate(-2, 3, true)
Question: Is this a good use case for an optional argument?