49 Days of Ruby: Day 11 - Objects
Tags: ruby
Published: 2021-04-07 05:00:14

---
title: 49 Days of Ruby: Day 11 - Objects
published: true
description: Join us on a 49 day learning journey through Ruby!
series: 49 Days of Ruby
tags: #ruby
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/9m73qaetuse3nm3y3it8.png
---

**Welcome to day 11 of the 49 Days of Ruby! 🎉**

After our journey through Strings, Integers, Booleans, Arrays, Hashes, and more, we're ready to dive into *Objects*!

Imagine I had the perfect model for a cup of coffee. I could make unique versions based on that model. Sometimes I may wish to add some sugar to the coffee. Other times, I may wish to add a dash of milk. 

Each cup of coffee based on that perfect coffee model is a coffee *object*. The perfect model of coffee is a coffee *class*. We're going to get into classes more soon. It's enough for today to be familiar with the word.
 
## Create Your First Object

Let's extend our coffee example and use it to create our first object in Ruby. 

I'm going to give you a `Coffee` class from which our first coffee object will come from:

```ruby
class Coffee
  def initialize(sugar:, milk:, size:)
    @sugar = sugar
    @milk = milk
    @size = size
  end
end
```

The new `Coffee` class we created has an `#initialize` method. This method is on the class itself, meaning that it can be accessed on `Coffee` and not on instances we will create.

The `#initialize` method instructs our class we created what kind of things it is composed of and what those values are. In this case, we created a Coffee class that has `sugar`, `milk`, and `size`. We did not specify any default values for those, but rather accept any argument during the *instantiation* of objects from it.

Now that we have a class for Coffee, we can create some coffee! I'll create one for you:

```ruby
irb(main)> breakfast_coffee = Coffee.new(sugar: 1, milk: 1, size: 'venti')

=> #<Coffee:0x000000013a241090 @sugar=1, @milk=1, @size="venti">
```

Did you notice that what was outputted after we created `breakfast_coffee` looked a lot different than things we've seen up until this point? That's how a new object looks like in Ruby.

The `#<>` syntax tells us we're talking about an object. The first word is the class the object comes from. After the number and letter combo, which is not important for us right now, we see the variables assigned to our new object: sugar, milk, and size with their respective values.

What happens if we try to access one of them, perhaps the milk?

```ruby
irb(main)> breakfast_coffee.milk

NoMethodError (undefined method `milk' for #<Coffee:0x000000013a241090 @sugar=1, @milk=1, @size="venti">)
```

What? I can see the `milk` right in that object! Why can't I access them? You can't access them because by default they are private. The data held inside the object is called the *state* of the object, and unless you explicitly say otherwise, it remains locked away.

We can make a new instance method for `Coffee` that exposes the milk in each instance:

```ruby
class Coffee
  def initialize(sugar:, milk:, size:)
    @sugar = sugar
    @milk = milk
    @size = size
  end

  def milk
   @milk
  end
end
```

Now, when we ask for milk from our `breakfast_coffee`, we'll see the value we assigned to it.

This need to expose the data is so common that Ruby has some built-in helpers for you to make it even easier!

Let's open up that Coffee class again and add the following right at the top:

```ruby
class Coffee
  attr_reader :sugar, :milk, :size

  def initialize(sugar:, milk:, size:)
    @sugar = sugar
    @milk = milk
    @size = size
  end
end
```

We were able to remove an entire method with just one line called `attr_reader`, which stands for attributes reader. In other words, you can tell your code these are the attributes that I want to be able to be read from my objects. I can specify all of them, some of them or none of them.

What if you want to be able to change a value after instantiating it? There is another helper called `attr_writer`, which as you can guess, is the complementary helper to `attr_reader`, but defining those things that can be changed (or written). 

How about if I want to be able to *read* and *write* the values after instantiation? We have `attr_accessor`, which is the catch-all and allows you to perform both operations on anything defined in the helper.

Go ahead and experiment more with objects in your IRB session! What else can you discover? Share your learnings and see you tomorrow!

**Come back tomorrow for the next installment of 49 Days of Ruby! You can join the conversation on Twitter with the hashtag [#49daysofruby](https://twitter.com/hashtag/49daysofruby).**