user2448377
user2448377

Reputation: 69

In Ruby, why is my base class only being puts once?

I'd appreciate knowing why the instance of "Cat" below isn't also putting the "This animal can:" text before its specific instance attributes. I'm expecting an output like this:

This animal can:
Say it's name: 'Rover'
Bark
This animal can:
Say its name: 'Satan'
Meow

Here's the code:

class Animal
    puts "This animal can:"
end

class Dog < Animal
    def initialize(name)
        @name = name
        puts "Say its @name: '%s'" % [name]
    end
    def bark
        puts "Bark"
    end
end

class Cat < Animal
    def initialize(name)
        @name = name
        puts "Say its @name: '%s'" % [name]
    end
    def meow
        puts "Meow"
    end
end

rover = Dog.new("Rover").bark
satan = Cat.new("Satan").meow

What I'm seeing is this:

This animal can:
Say it's name: 'Rover'
Bark
Say its name: 'Satan'
Meow

Doesn't "cat" also inherit from the Animal class? Shouldn't its output also begin with "This animal can:"?

Upvotes: 0

Views: 202

Answers (5)

Boris Stitnicky
Boris Stitnicky

Reputation: 12578

Install name_magic (gem install y_support) and have fun

require 'y_support/name_magic';     

class Animal
  include NameMagic
  def initialize; puts "This animal #{sound}s." end
  def sound; "growl" end
  def speak; puts "#{sound.capitalize}!" end
end

class Dog < Animal
  def sound; "bark" end
end

class Cat < Animal
  def sound; "meow" end
end

def hullo( animal )
  Animal.instance( animal ).speak
end

Rover = Dog.new
#=> This animal barks.
Satan = Cat.new
#=> This animal meows.

hullo :Rover
#=> Bark!

Animal.instances.each( &:speak )
#=> Bark!
#=> Meow!

Upvotes: -1

lis2
lis2

Reputation: 4264

Exactly!

class Animal
  def initialize(name)
    puts "This animal can:"
  end
end

def initialize(name)
  @name = name
  puts "Say its @name: '%s'" % [name]
  super # initializer from parent class
end

why that don't work ?

class Animal
  puts "This animal can:"
end

when ruby parser read code it evaluate everything on way. I mean even if you will not create any object it will display "This animal can:" That's why you saw that for the first time and had impression that Dog class worked correctly

Upvotes: 0

wjl
wjl

Reputation: 7361

The "This Animal can:" line only occurs when the class is defined, since it doesn't live in a method. Since both animals have common behavior in their initializers, you might want to promote the initializer to the Animal class.

class Animal
  def introduce_myself
    puts "Hello! My name is #{@name} and I know how to: "
  end

  def initialize(name)
    @name = name
    introduce_myself
  end
end

class Dog < Animal
  def bark
    puts "Woof!"
  end
end

class Cat < Animal
  def meow
    puts "Meow!"
  end
end

Dog.new("Fido").bark
Cat.new("Sparky").meow

Output:

Hello! My name is Fido and I know how to: 
Woof!
Hello! My name is Sparky and I know how to: 
Meow!

Upvotes: 2

Louis Kottmann
Louis Kottmann

Reputation: 16638

Your Animal class doesn't define a constructor, nor is it called by inheritors:

class Animal
   def initialize
      puts "This animal can:"
   end
end

class Dog < Animal    
   def initialize(name)
       super()
       @name = name
       puts "Say its @name: '%s'" % [name]
   end

   def bark
       puts "Bark"
   end    
end

Upvotes: 1

Denis de Bernardy
Denis de Bernardy

Reputation: 78523

The problem in your code is that:

puts "This animal can:"

is run when the Animal class gets defined. It seems like you want this in the initializer:

class Animal
  def initialize(name)
    puts "This animal can:"
  end
end

You'll then need to call super in the other initializers for the result you're expecting.

Upvotes: 5

Related Questions