Question on the Ruby Programming Language Book

I have been reading The Ruby P.ming Language book by David Flanagan
and Matz. It is written quite well. Some examples are not clear (to
me): Here is one from Chapter 7 page 244 which defines a class to set
enumerated types:

class Season
NAMES = %w{ Spring Summer Autumn Winter } # Array of season names
INSTANCES = [] # Array of Season objects

def initialize(n) # The state of a season is just its
@n = n # index in the NAMES and INSTANCES arrays
end

def to_s # Return the name of a season
NAMES[@n]
end

This code creates instances of this class to represent the seasons

and defines constants to refer to those instances.

Note that we must do this after initialize is defined.

NAMES.each_with_index do |name,index|
instance = new(index) # Create a new instance
INSTANCES[index] = instance # Save it in an array of instances
const_set name, instance # Define a constant to refer to it
end

Now that we have created all the instances we’ll ever need, we must

prevent any other instances from being created

private_class_method :new,:allocate # Make the factory methods
private
private :dup, :clone # Make copying methods private
end

My question is how do you use this class from the client code? Can
someone give some examples?

Thanks.

Bharat

From: “Bharat R.” [email protected]

My question is how do you use this class from the client code? Can
someone give some examples?

spring = Season::Spring
summer = Season::Summer

etc.

Regards,

Bill

Hello Bill,
Thanks for your quick response. You gave me the following example.

spring = Season::Spring
summer = Season::Summer
I typed this into my NetBeans IDE and it indeed shows that both spring
and summer are valid object. My follow-up questions are more to learn
than to question the validity of your answer since I am trying to
understand this:

1 Why do you have to create enumerated objects this way? This seems a
long way off from Ruby’s philosophy of being succint. Just to define a
few “object” constants I have to go through this?

  1. In the code block below:

NAMES.each_with_index do |name,index|
instance = new(index) # Create a new instance
INSTANCES[index] = instance # Save it in an array of instances
const_set name, instance # Define a constant to refer to it
end

The block is apparently setting the “name” to the “instance”. What does
this buy us from a programming point of view?

Bharat

On Mon, Mar 3, 2008 at 5:44 PM, Bharat R. [email protected]
wrote:

1 Why do you have to create enumerated objects this way? This seems a
long way off from Ruby’s philosophy of being succint. Just to define a
few “object” constants I have to go through this?

In general, Ruby programmers don’t create enumerated objects. There’s
rarely a need for them. The solution you demonstrated above is looks
like an example of how one might go about it if one really wanted to
emulate C+±style enumerations. Generally you would just use symbols,
though.

The block is apparently setting the “name” to the “instance”. What does
this buy us from a programming point of view?

That’s the part that actually creates those constants Season::Summer,
Season::Autumn, etc. Without it they would not exist.

In general, Ruby programmers don’t create enumerated objects. There’s
rarely a need for them. The solution you demonstrated above is looks
like an example of how one might go about it if one really wanted to
emulate C+±style enumerations. Generally you would just use symbols,
though.

Thank you. On one hand, I have a high regard for David Flanagan and
Matz. On the other hand, I must admit that I am a bit disappointed with
their selection of examples though. “Technicallly,” the book is mostly
quite correct, you just have to stretch your brain-cells a bit for more
realistic applications. C++ was a long time ago, but thanks for the
reminder, it does look a bit like the past coming back to haunt me.

Regards,

Bharat

Bharat R. wrote:

I have been reading The Ruby P.ming Language book by David Flanagan
and Matz. It is written quite well. Some examples are not clear (to
me):

I looked at the book in the bookstore. I was very disappointed. I read
the first chapter, and it is way too technical for me. It is nothing
like the author’s Javascript book, which is very easy to read, yet is
still the definitive book on the subject. I was surprised at how thin
the book was. I wish the author had fleshed things out a little more
and made the book easier to read.

The prologue does say that it is not a beginner’s book.

season = Season::Autumn
puts season
puts season.next
puts season.next.next

Thanks Jim. That is cool! No, way cool!!

Bharat R. wrote:

1 Why do you have to create enumerated objects this way? This seems a
long way off from Ruby’s philosophy of being succint. Just to define a
few “object” constants I have to go through this?

Well, you can add this method:

def next
INSTANCES[ (@n+1) % 4]
end

and then do this:

season = Season::Autumn
puts season
puts season.next
puts season.next.next


James B.

“The greatest obstacle to discovery is not ignorance, but the illusion
of knowledge.”

  • D. Boorstin

And, no, I can’t explain why I used this:

NAMES.each {|name| yield const_get(name.to_s)}

Instead of:

INSTANCES.each {|season| yield season}

Just trying to make things too complex, I guess.

On Mon, Mar 3, 2008 at 3:44 PM, James B. [email protected]
wrote:

def next
puts season.next.next

Or, better (in Ruby 1.9) add this instead:

class Season

extend Enumerable

def self.each
NAMES.each {|name| yield const_get(name.to_s)}
self
end

more direct than making it sortable by defining a <=> operator,

though you could do that instead.

def self.sort(&block)
if block then to_a.sort(&block) else to_a end
end

end

And then try (not really all that useful for seasons, but shows that
you’ve got the full power of Enumerable at hand):

Season.sort {|s1, s2| s1.to_s <=> s2.to_s}.each {|s| puts s.to_s}
Season.sort_by {|season| season.to_s}.each {|s| puts s.to_s}
Season.map {|season| season.to_s}.each {|s| puts s}

And finally (the one I like the most):

seasons = Season.cycle
puts seasons.next
puts seasons.next
puts seasons.next
.
.
.

(You can do the same thing to make the class Season an
Enumerable in Ruby 1.8, but Ruby 1.9’s Enumerators
and the Enumerable#cycle method really make this
cool, IMO.)

Bharat R. wrote:

season = Season::Autumn
puts season
puts season.next
puts season.next.next

Thanks Jim. That is cool! No, way cool!!

Thanks.

The main point is that, if you just want cheap, reliable constant
things, symbols are handy (e.g. :winter, :summer will work as fixed
values), but if you have a set of constants for which you want some
associated behavior, then a class makes sense.


James B.

Liberty means responsibility. That is why most men dread it.

  • George Bernard Shaw