Newbie Q - calling a method for an object in an .each block?

Hello All. Sorry if this is obvious, but I have looked over the list
(and pickax) and not been able to solve it.

I am trying to iterate over a collection of objects, calling a method
defined within each object.

I have a class Card, with a method ‘show’ defined.

I then create an array of these Card objects. For example:

hand = Array.new
ace = Card.new( some_parameters )
hand[0] = ace
hand.push(Card.new( some_other_parameters))
etc.

Now,

ace.show #works:
=>"Card: A of Spades
hand[0].show # works, calls the ‘show’ method, executed for the first
‘card’, the ace:
=>“Card: A of Spades”

But,

hand.each {|c| c.show} # dosn’t produces the following, which looks to me like a dump of the array:
=>[#<Card:0x2647f8 @face=“Up”, @value=12, @suit=“s”>, #<Card:0x20e3e4
@face=“Up”, @value=0, @suit=“d”>]

I fear I am misunderstanding something fundamental here, as I thought
the block parameter c should get each element of the array in turn, and,
each element being an object, I could call the methods associated with
that object.

Thanks for any insight,

Will

william robb wrote:

[snip]

hand.each {|c| c.show} # dosn’t produces the following, which looks to me like a dump of the array:

=>[#<Card:0x2647f8 @face=“Up”, @value=12, @suit=“s”>, #<Card:0x20e3e4
@face=“Up”, @value=0, @suit=“d”>]

I fear I am misunderstanding something fundamental here, as I thought
the block parameter c should get each element of the array in turn, and,
each element being an object, I could call the methods associated with
that object.

Don’t fear, your instincts are good. I doubt you’re
missing anything fundamental, you’ve just got some
kind of (interesting) bug.

The bug would seem to be in the code you haven’t
shown us. Can you post more?

Hal

On Jul 8, 2006, at 12:53 AM, william robb wrote:

ace = Card.new( some_parameters )
=>“Card: A of Spades”
and,
Posted via http://www.ruby-forum.com/.

It’s working but #each returns the array and your #show method
returns a string, it doesn’t have any side effects. You may want to
use map instead or use puts

e.g.:

hand.each { |c| puts c.show }

or hand.map { |c| c.show }

Logan C. wrote:

It’s working but #each returns the array and your #show method
returns a string, it doesn’t have any side effects. You may want to
use map instead or use puts

e.g.:

hand.each { |c| puts c.show }

or hand.map { |c| c.show }

Ah! These work. Thank You!

I do recall from pickax that #each returns the array. It must be, then,
with

hand.each { |c| c.show }

what I am seeing how irb displays an array. Does this mean that the
string returned by #show is produced, but nothing is telling it to
display so it sort of … gets assigned to nothing, and dosn’t display
in irb?

But, then, why doesn’t the block with the puts call first display the
strings followed by the display of the array returned by #each?

Follwing is the code defining the class (the rest I am just testing in
irb) for hal fulton, who asked for it. This is my first every ruby
program so it may be ugly, and could probably be improved upon. Been
programming in procedural languages since fortran 77, so this OO stuff
is a bit mind bending. But … I like it!

class Card

attr_reader :suit, :value, :face

def initialize(suit,value)
raise(IndexError, “Card: Suite out of range: #{suit}”) if suit !~
/[hcds]/
@suit = suit
raise(IndexError, “Card: Value out of range: #{value}” ) if not
((0…12) === value)
@value = value
@face = “Down”
end

def ssuit
case
when @suit == “h” then “Hearts”
when @suit == “c” then “Clubs”
when @suit == “d” then “Diamonds”
when @suit == “s” then “Spades”
end
end

def pips
case @value
when 0 … 8 then " " + (@value+2).to_s + " "
when 9 then " J "
when 10 then " Q "
when 11 then " K "
when 12 then " A "
end
end

def show
if @face == “Down”
“Card: xxx xx xxxxx”
else
“Card: #{pips} of #{ssuit}”
end
end

def flip
if @face == “Down”
then @face = “Up”
else @face = “Down”
end
end

end

Robert K. wrote:
[ … snip …]

Thanks for the explanation. I am a bit hazy on what is getting returned
and displayed in irb, but the structure of oo is comming clearer. I was
simply returning a string from the #show method, and letting irb do the
actual ‘display’, which explaned what was happening.

Been
programming in procedural languages since fortran 77, so this OO stuff
is a bit mind bending. But … I like it!

Yeah, it took me some while to grasp it when I learned OO (Turbo
Pascal at that time). But the OO paradigm is much stronger than plain
procedural code IMHO.

The origional Turbo Pascal? That came on one 5 1/4 inch diskette, the
first IDE I’d ever seen? That wasen’t OO, that was stright-up pascal,
no?

I guess you could call VBA/Excel OO, I’ve messed around with that, but
don’t like it all that much. OK to scrap out stuff, automate a chart
for a client or something … but I can’t stand all the
‘clickey-clickey’ windows interface you have to plow through just to put
in a bit of code.

But, enough chat. I am really interested in what you are saying below.
I had a vauge notion to do this, but couldn’t develop the syntax to
express what I wanted. If you wouldn’t mind, I would appreciate an
example or two.

You could for example create individual classes for suit, face and
maybe also for value implementing the enum pattern, so you end up
having just a single instance for hearts, clubs, face_up, face_down
etc.

Kind regards

robert

2006/7/8, william robb [email protected]:

or hand.map { |c| c.show }

Ah! These work. Thank You!

I do recall from pickax that #each returns the array. It must be, then,
with

hand.each { |c| c.show }

what I am seeing how irb displays an array.

IRB uses method #inspect of any object for display.

Does this mean that the
string returned by #show is produced, but nothing is telling it to
display so it sort of … gets assigned to nothing, and dosn’t display
in irb?

It doesn’t even get assigned. The return value of #show is simply
ignored.

But, then, why doesn’t the block with the puts call first display the
strings followed by the display of the array returned by #each?

That we can only tell if you show us the code you used. Normally it’s
exactly like you describe:

irb(main):004:0> %w{aa bb cc}.each {|c| puts c}
aa
bb
cc
=> [“aa”, “bb”, “cc”]

Follwing is the code defining the class (the rest I am just testing in
irb) for hal fulton, who asked for it. This is my first every ruby
program so it may be ugly, and could probably be improved upon. Been
programming in procedural languages since fortran 77, so this OO stuff
is a bit mind bending. But … I like it!

Yeah, it took me some while to grasp it when I learned OO (Turbo
Pascal at that time). But the OO paradigm is much stronger than plain
procedural code IMHO.

You could for example create individual classes for suit, face and
maybe also for value implementing the enum pattern, so you end up
having just a single instance for hearts, clubs, face_up, face_down
etc.

Kind regards

robert

Thanks for the code. I will have to digest the syntax a bit to see
exactly
what you are doing here … I had wondered what .freeze was good for.

On that other topic, I think it was around V5 that turbo pascal became
OO.
The first version was what made Borland a success, as it was a dirt
simple
implementation of a real programming language, with one of the first
IDEs. I still have the manual, complete, about the size of a paperback.

I do remember thinking, when I encountered Pascal’s Record data type; “I
wish I could store a procedure in one of these fields …” People at
Borland must have
thought that too, eh?

Then came C, and Pascal kinda withered away … Wasen’t ‘cool’, but was
a good workhorse.

Thanks again,

Will

You could for example create individual classes for suit, face and
maybe also for value implementing the enum pattern, so you end up
having just a single instance for hearts, clubs, face_up, face_down
etc.

poor mans enum pattern,

for others see the RAA

Suit = Struct.new :name

class Suit
VALUES = [
HEARTS = new(“Heart”).freeze,
CLUBS = new(“Clubs”).freeze,
DIAMONDS = new(“Diamonds”).freeze,
SPADES = new(“Spades”).freeze,
].freeze
[…etc…]

william robb wrote:

Robert K. wrote:
[ … snip …]

Thanks for the explanation. I am a bit hazy on what is getting returned
and displayed in irb, but the structure of oo is comming clearer. I was
simply returning a string from the #show method, and letting irb do the
actual ‘display’, which explaned what was happening.

Right.

no?
V 5.5 was OO - I’m not sure whether that was the first OO version.

I guess you could call VBA/Excel OO, I’ve messed around with that, but
don’t like it all that much. OK to scrap out stuff, automate a chart
for a client or something … but I can’t stand all the
‘clickey-clickey’ windows interface you have to plow through just to put
in a bit of code.

:-))

But, enough chat. I am really interested in what you are saying below.
I had a vauge notion to do this, but couldn’t develop the syntax to
express what I wanted. If you wouldn’t mind, I would appreciate an
example or two.

You could for example create individual classes for suit, face and
maybe also for value implementing the enum pattern, so you end up
having just a single instance for hearts, clubs, face_up, face_down
etc.

poor mans enum pattern,

for others see the RAA

Suit = Struct.new :name

class Suit
VALUES = [
HEARTS = new(“Heart”).freeze,
CLUBS = new(“Clubs”).freeze,
DIAMONDS = new(“Diamonds”).freeze,
SPADES = new(“Spades”).freeze,
].freeze

def to_s() name end

def self.from_string(s)
VALUES.detect {|su| s == su.name}
end

restrict to the 4 instances created above

def self.new(*a,&b) raise “Not allowed” end
end

Now you can do
Suit::HEARTS
Suit::VALUES.each {|s| puts s}
Suit.from_string “Hearts”
etc.

And also

case x.suit
when Suit::HEARTS
then puts “doing something with hearts…”
when Suit::CLUBS

end

Kind regards

robert

(late reply due to holidays)

william robb wrote:

Thanks for the code. I will have to digest the syntax a bit to see
exactly
what you are doing here … I had wondered what .freeze was good for.

It prevents changing of an object. You probably found out by now…

irb(main):001:0> s=“foo”
=> “foo”
irb(main):002:0> s.gsub! /./, ‘x’
=> “xxx”
irb(main):003:0> s.freeze
=> “xxx”
irb(main):004:0> s.gsub! /./, ‘y’
TypeError: can’t modify frozen string
from (irb):4:in `gsub!’
from (irb):4
from :0

On that other topic, I think it was around V5 that turbo pascal became
OO.

Or even 5.5 - I’m not 100% sure.

The first version was what made Borland a success, as it was a dirt
simple
implementation of a real programming language, with one of the first
IDEs. I still have the manual, complete, about the size of a paperback.

And the compiler was very fast because it was a one pass compiler (like
all PASCAL compilers, it’s made possible by the language’s design).

I do remember thinking, when I encountered Pascal’s Record data type; “I
wish I could store a procedure in one of these fields …” People at
Borland must have
thought that too, eh?

Maybe they even read your mind - or NSA trapped your phone. :slight_smile:

Then came C, and Pascal kinda withered away … Wasen’t ‘cool’, but was
a good workhorse.

Personally I still find PASCAL a pretty good language for learning to
program since it makes many things rather explicit. IO of standard
PASCAL is bad though. MODULA was a complete disaster IMHO - good ideas
but implemented awfully. IIRC you needed to call a different IO
function for every different basic data type - no polymorphism.

Kind regards

robert

Robert K. wrote:

You could for example create individual classes for suit, face and
maybe also for value implementing the enum pattern, so you end up
having just a single instance for hearts, clubs, face_up, face_down
etc.

I’d much rather stick with a single class, and use some of Ruby’s
goodness to get the magic:

class Card
SUITS = [:hearts, :clubs, :diamonds, :spades]
RANKS = (1…13).to_a

 attr_reader :suit, :rank

 def initialize(suit, rank)
   @suit, @rank = suit.to_sym, rank.to_int

   raise unless SUITS.include? @suit
   raise unless RANKS.include? @rank
 end

 # creates the methods #hearts?, #clubs?, #diamonds?, and #spades?
 SUITS.each{|suit| define_method("#{suit}?"){ suit == @suit }}

 # etc. etc.

end

But that’s a matter of opinion, of course.

Cheers,
Daniel