Ruby existentialism

What is the self? Philosophers have been pondering that question for centuries. Luckily, we don’t have to worry about such complex contemplation when we consider self in object-oriented programming (also called this or Me, depending on the language).

Recap: object-oriented programming

Object-oriented programming is a paradigm in which state (data) and behaviors that operate on or with that data are encapsulated in objects. In a way, objects in programming are similar to real-life objects—they have attributes and can do different things depending on those attributes.

A class is a template for creating objects, and contains definitions of the data formats and available behaviours for all instances of itself. For instance, if we were representing a car in code, we could have a Car class that defines all car objects as having attributes, such as color, horsepower, weight, etc., as well as behaviors, like accelerate, that would act differently depending that object‘s specific attributes:

class Car

  attr_accessor :color, :horsepower, :weight
  
  def accelerate
    ...
  end

end

attr_accessor allows us to get and set the attributes of an object. Here’s it’s letting us get or set a Car‘s color, horsepower, and weight.

Self keyword

When we’re defining the behaviors in a class, we need to have a way to access the data of a specific instance of that class (an object). In Ruby, as in many other languages, we use the keyword self. Objects are self-aware!

In our Car example, let’s say we want to define the accelerate behavior (method in Ruby) as returning the specific Car object’s horsepower divided by its weight (a vast simplification). We would define it like this:

def accelerate
  self.horsepower / self.weight
end

Let’s do it for real!

Ok, we’re going to write a program to pass Learn’s “Object-Oriented Counting Sentences” Lab. We’re going to be monkey patching Ruby’s String class with a few additional methods:

  1. #sentence?
    Returns true if the String object it’s called on is a sentence (ends with a period).
  2. #question?
    Returns true if the String object it’s called on is a question (ends with a question mark).
  3. #exclamation?
    Returns true if the String object it’s called on is an exclamation (ends with an exclamation point).
  4. #count_sentences
    Returns the number of sentences in a String object. In this case, a “sentence” can end with a period, question mark, or exclamation point.

Remember, we can use the self keyword in our method definitions to refer to the String object on which it is called. Let’s look at an implementation of our first three methods (hint – use the #ends_with? method to check the last character of a String):

class String

  def sentence?
    self.ends_with?('.')
  end

  def question?
    self.ends_with?('?')
  end

  def exclamation?
    self.ends_with?('!')
  end

end

For our final method, we just have to count the number of periods, question marks, and exclamation points, right?!?!?!? Well, that would work as long as people don’t use multiple marks in a row, like I just did. Instead, let’s count the number of substrings that end with one or more of these marks. For that, we can use our friend the #split method and a regular expression.

Do you remember how you’d write a regular expression for “one or more of periods, question marks, or exclamation points?” I recommend Rubular for checking RegExes in Ruby. Don’t continue until you’ve figured it out!

Yep, it’s /[.!?]+/. Note that you don’t need to escape characters inside the brackets. So, our final method inside the String class would look like this:

def count_sentences
  self.split(/[.!?]+/).count
end

That’s it!