Question on the Ruby Programming Language Book

B

Bharat Ruparel

I have been reading The Ruby Programming 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
 
B

Bill Kelly

From: "Bharat Ruparel said:
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
 
B

Bharat Ruparel

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?

2. 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
 
A

Avdi Grimm

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.
 
7

7stud --

Bharat said:
I have been reading The Ruby Programming 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.
 
B

Bharat Ruparel

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
 
J

James Britt

Bharat said:
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 Britt

"The greatest obstacle to discovery is not ignorance, but the illusion
of knowledge."
- D. Boorstin
 
C

Christopher Dicely

Bharat said:
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


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
 
C

Christopher Dicely

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.

Bharat said:
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


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.)
 
J

James Britt

Bharat said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top