Now let’s create a greeter object and use it:
irb(main):035:0> g = Greeter.new("Pat") => # irb(main):036:0> g.say_hi Hi Pat! => nil irb(main):037:0> g.say_bye Bye Pat, come back soon. => nilOnce the g
object is created, it remembers that the name is Pat.
Hmm, what if we want to get at the name directly?
Nope, can’t do it.
Instance variables are hidden away inside the
object. They’re not terribly hidden, you see them whenever you
inspect the object, and there are other ways of accessing them, but
Ruby uses the good object-oriented approach of keeping data sort-of
hidden away.
So what methods do exist for Greeter objects?
irb(main):039:0> Greeter.instance_methods => ["method", "send", "object_id", "singleton_methods", "__send__", "equal?", "taint", "frozen?", "instance_variable_get", "kind_of?", "to_a", "instance_eval", "type", "protected_methods", "extend", "eql?", "display", "instance_variable_set", "hash", "is_a?", "to_s", "class", "tainted?", "private_methods", "untaint", "say_hi", "id", "inspect", "==", "===", "clone", "public_methods", "respond_to?", "freeze", "say_bye", "__id__", "=~", "methods", "nil?", "dup", "instance_variables", "instance_of?"]Whoa. That’s a lot of methods. We only defined two methods. What’s
going on here? Well this is all of the methods for Greeter objects,
a complete list, including ones defined by ancestor classes. If we want to just list
methods defined for Greeter we can tell it to not include ancestors by
passing it the parameter false
, meaning we don’t want methods
defined by ancestors.
Ah, that’s more like it. So let’s see which methods our greeter
object responds to:
So, it knows say_hi
, and to_s
(meaning convert something to a
string, a method that’s defined by default for every object), but it
doesn’t know name
.
But what if you want to be able to view or change the name? Ruby
provides an easy way of providing access to an object’s variables.
In Ruby, you can open a class up again and modify it. The changes
will be present in any new objects you create and even available in existing
objects of that class. So, let’s create a new object and play with its
@name
property.
Using attr_accessor
defined two new methods for us, name
to get
the value, and name=
to set it.
This greeter isn’t all that interesting though, it can only deal with
one person at a time. What if we had some kind of MegaGreeter that
could either greet the world, one person, or a whole list of people?
Let’s write this one in a file instead of directly in the interactive
Ruby interpreter IRB.
To quit IRB, type “quit”, “exit” or just hit Control-D.
#!/usr/bin/env ruby class MegaGreeter attr_accessor :names # Create the object def initialize(names = "World") @names = names end # Say hi to everybody def say_hi if @names.nil? puts "..." elsif @names.respond_to?("each") # @names is a list of some kind, iterate! @names.each do |name| puts "Hello #{name}!" end else puts "Hello #{@names}!" end end # Say bye to everybody def say_bye if @names.nil? puts "..." elsif @names.respond_to?("join") # Join the list elements with commas puts "Goodbye #{@names.join(", ")}. Come back soon!" else puts "Goodbye #{@names}. Come back soon!" end end end if __FILE__ == $0 mg = MegaGreeter.new mg.say_hi mg.say_bye # Change name to be "Zeke" mg.names = "Zeke" mg.say_hi mg.say_bye # Change the name to an array of names mg.names = ["Albert", "Brenda", "Charles", "Dave", "Englebert"] mg.say_hi mg.say_bye # Change to nil mg.names = nil mg.say_hi mg.say_bye endSave this file as “ri20min.rb”, and run it as “ruby ri20min.rb”. The
output should be:
There are a lot of new things thrown into this final example that we can take a deeper look at.