alexandernst
alexandernst

Reputation: 15089

Interfaces in Ruby

Let's say I have the following structure inside my Ruby project (actually, Ruby On Rails 5, but I guess this is more about Ruby than RoR5):

main.rb
greeter.rb
impl/dog.rb
impl/cat.rb
config.yaml

How would I implement an interface in 'greeter.rb' in such a way so I could get to see a 'bau bau!' in the output if I run the following (pseudo)code:

//main.rb
include greeter.rb
greet()

//config.yaml
greeter = Dog

//dog.rb
def greet()
    print 'bau bau!'
end

//cat.rb
def greet()
    print 'miau!'
end

Upvotes: 0

Views: 1338

Answers (1)

tadman
tadman

Reputation: 211670

While this might be the way you're thinking about solving the problem, from the perspective of Ruby it's totally wrong. What you want is something like this:

# lib/animal.rb
class Animal
  def self.of_type(type, *args)
    case (type)
    when 'cat'
      Cat.new(*args)
    when 'dog'
      Dog.new(*args)
    end
  end
end

# Explicitly load subclasses
require_relative('./cat')
require_relative('./dog')

Now that loads in two specific sub-classes that implement the specific behaviours:

# lib/cat.rb
class Cat < Animal
  def greet
    "Mew!"
  end
end

# lib/dog.rb
class Dog < Animal
  def greet
    "Woof!"
  end
end

You can write a simple test script to verify this, but using test/unit, rspec or Minitest is even better:

# test/example.rb
require_relative('../lib/animal')

Animal.of_type('dog').greet
# => "Woof!"

Note that in Ruby methods with no arguments have their brackets removed, they're not required and tradition holds they be omitted for simplicity. Likewise, lib/ is where most library "implementations" are stored.

There's generally no main.rb file as there's generally no main method. You just set up things in either a bin/ type script, or as part of something else, like your test framework or web environment.

Upvotes: 1

Related Questions