Object-Oriented Ruby Basics
Tags: ruby, oop, database, beginners
Published: 2023-05-08 17:35:42

It's no surprise that **Object-Oriented Programming (OOP)** is  the most popular programming paradigm. OOP is actually very similar to the way that we think. Our world is so incomprehensibly complex that our perception of reality is reduced to a simpler interface—much like a computer program. We don't see every single unique tree we drive past. We see objects that resemble a broad category of tree. Having low-resolution models of a variety of objects allows us to interface with the world without becoming overwhelmed. We constantly update our models of the world based on our experiences. Occasionally, we have to debug—or completely rewrite—our models due to tragedy, loss or incorrect assumptions. 

However, we don't only see the world in low-resolution. We also have complex high-resolution perceptions as well. Recalling my grandparents' walnut tree with the tire swing or my parents' pear tree in the backyard returns a trove of specific memories and sensory information. I can "feel" the texture of the bark, "see" the color of the leaves, and "taste" the sweetness of the fruit. I know these two trees very well.

## Classes and Instances
In OOP, we write low-resolution models called ***classes*** that generate high-resolution objects called ***instances***. Extending the analogy above, **Tree** is the `class` and my grandparents' walnut tree is the `instance`. My parents' pear tree is another `instance` of the **Tree** `class`. 

### Class
```ruby
class Tree
end
```
This example in ruby is the beginning of a model class: Tree. Class names are always capitalized and singular in ruby. (Why Ruby? While many languages can be used for OOP, Ruby was specifically created with OOP in mind.) 

OOP object models contain both data (attributes) and code (methods). This Tree class is currently lacking in both categories. Attributes are stored in variables. Instance variables begin with `@` while class variables begin with `@@`. Attributes are read, written or modified through methods. Instance methods start with `def method_name`. Class methods start with `def self.method_name`.

```ruby
class Tree
  
  def name= name
    @name = name
  end

  def name
    @name
  end

end
```
While it's still not much, here is a Tree class that can create and retrieve tree names. The first method `.name=` writes the instance variable: `@name`. This is called a setter method. The second method `.name` reads the instance variable: `@name`. This is called a getter method.

### Instance
```ruby
grandpas_tree = Tree.new 
#=> #<Tree:0x00007f87799b9af8>
grandpas_tree.name = 'Grandpa\'s Tree'
#=> "Grandpa's Tree"
grandpas_tree.name 
#=> "Grandpa's Tree"
grandpas_tree
#=> #<Tree:0x00007f87799b9af8 @name="Grandpa's Tree">
```
So here is the first instance of Tree. Renaming the tree is just as easy as calling the setter method again. Verify with the getter method.
```ruby
grandpas_tree.name = 'Tire Swing Tree'
#=> "Tire Swing Tree"
grandpas_tree.name 
#=> "Tire Swing Tree"
```
## Macros
Getter and setter methods are useful and all, but there is an easier way. Macros are code that write code. Three macros that are particularly helpful are `attr_reader` (attribute getter), `attr_writer` (attribute setter) and `attr_accessor` (attribute getter & setter).
```ruby
class Tree
  attr_reader :name
  attr_writer :name
end
```
Refactoring the Tree class this way still provides the same functionality as before. Macros use symbols to represent the variables they access. 
```ruby
class Tree
  attr_accessor :name
end
```
This is the simplest way to refactor the Tree class. Now many attributes can be added efficiently.
```ruby
class Tree
  attr_accessor :name, :type, :age, :height
end
```
## Self
Since a class will have many instances, the word `self` is a designated keyword used to access a given instance within a method. Self is also used at the beginning of class methods to differentiate them from instance methods. 
```ruby
class Tree
  # macros
  attr_accessor :name, :type

  # class variable
  @@all = []

  # special instance method called when a new instance is created: Tree.new('Grandpa\'s Tree', 'walnut')
  def initialize(name, type) 
    @name = name
    @type = type
    # the instance is shoveled into the @@all array upon initialization
    @@all << self
  end

  # class method
  def self.all
    @@all
  end
end
``` 
This updated Tree class creates tree instances with name and type attributes. Calling Tree.all returns an array of all the tree instances that have been created. With method chaining, Tree.all.count will return the number of Tree instances created. (The `.count` method is built-in to ruby.)
```ruby
Tree.new('Mom\'s', 'pear')
#=> #<Tree:0x00007f877f837710 @name="Mom's", @type="pear"> 
Tree.new('Grandpa\'s', 'walnut')
#=> #<Tree:0x00007f87799b9af8 @name="Grandpa's", @type="walnut"> 
Tree.new('Christmas', 'white pine')
#=> #<Tree:0x00007f877f82d170 @name="Christmas", @type="white pine"> 
Tree.all
#=> [#<Tree:0x00007f877f837710 @name="Mom's", @type="pear">, #<Tree:0x00007f87799b9af8 @name="Grandpa's", @type="walnut">, #<Tree:0x00007f877f82d170 @name="Christmas", @type="white pine">]
Tree.all.count
#=> 2
```
## Inheritance
Inheritance creates a hierarchy of classes by which a child or subclass can access all of the attributes and methods of the parent or superclass. To write an inheritance the subclass is "less-than" the superclass: `class Tree < Forest`.
```ruby
class Forest 
  attr_accessor :location, :area, :protected_status

  def protected
    @protected_status = true
  end
end

# The Tree class inherits attributes and methods from the Forest class.
class Tree < Forest
  attr_accessor :name, :type

  @@all = []

  def initialize(name, type) 
    @name = name
    @type = type
    @@all << self
  end

  def self.all
    @@all
  end
end
``` 
While this example may be contrived, inheritance is particularly helpful when using libraries such as [ActiveRecord](https://guides.rubyonrails.org/active_record_basics.html) or [Sinatra](https://sinatrarb.com/). Libraries such as these have a host of methods that keep code DRY and allow the programmer to focus on writing unique methods specific for the individual app rather than writing methods that are the same in every app. 

As a general rule in Ruby, methods cap out at 5 lines and classes cap out at 100 lines of code. This keeps classes and methods from becoming overly complicated and unmanageable. Complying with this standard encourages the simplest, cleanest code.

## Conclusion
Classes, instances, attributes, methods, macros, self and inheritance are some of the basics in OOP. These tools allow programmers to write code that models the world around them. It's just a hunch, but I'm guessing you'll notice a lot more trees today. 

###
####
#####
###### Credit
Photo by <a href="https://unsplash.com/pt-br/@emben?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Johann Siemens</a> on <a href="https://unsplash.com/images/nature/tree?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>