Public Methods

Public methods are the most crucial methods in Object Oriented Programming. They expose the external signature of your class to other classes. In a Car for example, you as a driver can do things like “opening the door”, “starting the ignition”, or “turn the steering wheel”.

However, under the hood (pun intended) there’s a plethora of supporting actions that are not accessible by the driver. Things like “send electicity to spark plug”, “engage disc brakes”, etc. are the hidden methods to driving a car and are not part of the public interface.

In PHP, for each method we need to explictly define if the method is public, protected or private.

In Ruby, methods are public by default. You don’t need to specify they’re public, it’s assumed unless otherwise marked that all methods in a class are part of the class’s signature.

class Car {
    /**
     * Turn the steering wheel a certain direction
     */
    public method turnWheel($direction) {
        $this->axel->turn($direction);
    }
}

No need to define any kind of public anywhere in a Ruby class, it’s just implict that unless a method is defined otherwise - then it’s a public method:


class Car
  # Turn the steering wheel a certain direction
  def turn_wheel(direction)
    axel.turn(direction)
  end
end

Using Private Methods

I’m going to go ahead and assume you’ve used some OOP in PHP in the past. One key concept is understanding “Private Methods”. This methods are used to organize logic internally inside of the Class.

The only difference between private methods and public methods, is that private methods are not accessible outside of the Object.

    class Cat {
        public function stalk() {
            $this->moveLeftLegs();
            sleep(1);
            $this->moveRightLegs();
            sleep(1);
        }
        
        public function run() {
            $this->moveLeftLegs();
            $this->moveRightLegs();        
        }
        
        private function moveLeftLegs() {
            // somehow this function makes the Cat move
        }
        
        private function moveRightLegs() {
             // somehow this function makes the Cat move
        }
    }
    
    $cat = new Cat;
    $cat->stalk();
    $cat->run();
    
    $cat->moveLeftLegs();
    
    => Cannot access private method 'moveLeftLegs' on Cat

Private methods are not part of the Cat’s signature. A signature is just the available public methods on a particular object.

We have private method in Objects in Ruby as well. But they are defined a little differently:


    class Cat
        def walk
            move_left_legs
            sleep 1
            move_right_legs
            sleep 2
        end
        
        def run
            move_left_legs
            move_right_legs
        def
            
        private
            
        def move_left_legs
            # use your imagination here ok?
        end
        
        def move_right_legs
            # yup, the right legs will move
        end        
    end
            
    cat = Cat.new
    cat.stalk
    cat.run
    
    cat.move_left_legs
    
    => Cannot call 'move_left_legs'

Yup private methods are still a thing in Ruby.

In PHP, we have to explictly place the keyword private in front of each method in a class:

  private function moveLeftLegs() {
    // things happen here
  }

  private function moveRightLegs() {
    // things happen here
  }

However, Ruby’s take it on just requires you to set it once. Anything beneath the keyword private becomes a private method:


  private

  def moveLeftLegs
    # things happen here
  end

  def moveRightLegs
    # things happen here
  end

Protected Methods

Protected methods are essentially a step between a private and a public method. It’s still private in that an outside class cannot use the protected methods, but it’s accessible to other inheriting classes a.k.a. children.

Take this generic Car class for example:

class Car {
    public method turnIgnition($key) {
        if($this->car->checkKey($key)) {
            $this->car->igniteSparkPlug();
        }
    }

    private method igniteSparkPlug() {
        $this->car->igniteSparkPlug();
    }

    protected method checkKey($key) {
        return $key == $this->slot
    }
}

Pretty simple, the external user a.k.a. Driver is able to insert a $key into the ignition and 2 interior methods will do the actual work. If the checkKey method fails, then the car doesn’t start.

Alrightly let’s implement our Car class in Ruby:


class Car
  def turn_ignition(key)
    # using a combination of a guard statement + implict paranthesis around an argument
    ignite_spark_plug if check_key key
  end

  protected

  def ignite_spark_plug
    car.ignite_spark_plug
  end

  private

  def check_key(key)
    key == slot
  end

Again, much less typing required for the same result.

What if we had a car that had one of those fancy keyless entries? Technically we wouldn’t have to have a $key inserted into the car, but we want to extend the class for similar functionality:

class KeylessCar extends Car {
    public function turnIgnition() {
        if($this->car->checkKey()) {
            $this->car->igniteSparkPlug();
        }
    }

    protected function checkKey() {
        $key = $this->searchForKey();

        return $key == $this->superSecretHash();
    }

    private function searchForKey() {
        // some kind of bluetooth ping and response
        // just use your imagination
        return $this->key
    }

    private function superSecretHash() {
        // Car developers, please don't do this
        return 'supersecretstringshhhh';
    }
}

Now, this is a sneak peak into extending classes in Ruby, but you’re ready for a little taste:


class KeylessCar < Car
  def turn_ignition
    # using a combination of a guard statement + implict paranthesis around an argument
    ignite_spark_plug if check_key
  end

  protected

  def ignite_spark_plug
    car.ignite_spark_plug
  end

  private

  def check_key
    key == slot
  end

  def super_secret_hash
    # Car developers, please don't do this
    'supersecretstringshhhh'
  end

Where is $this in Ruby?

So, I might have jumped ahead of myself in the last example. From inside of the Cat Class, we called the private method move_left_legs and move_right_legs, but we didn’t prepend this. You’d expect to have to explictly tell Ruby to look for that method on the current Class.

Again, it’s optional you still can.

If you’d like to keep Ruby familiar as possible to what you already know. You can use the keyword self to refer to the current Class. We can rewrite the run method in our Cat Class as such:


        def run
            self.move_left_legs
            self.move_right_legs
        def

That’s totally valid as well. However, don’t be surprised to see a lack of self in Classes by other Rubyists. After awhile you just get used to the implict nature of the language.