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

W

william robb

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
 
H

Hal Fulton

william said:
[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
 
L

Logan Capaldo

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

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 }
 
W

william robb

Logan said:
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
 
R

Robert Klemme

2006/7/8 said:
Ah! These work. Thank You!

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


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
 
D

Daniel Schierbeck

Robert said:
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
 
W

william robb

Robert Klemme 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.
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.
 
R

Robert Klemme

william said:
Robert Klemme 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.
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?

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.

# 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
 
W

william robb

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
# 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...]
 
R

Robert Klemme

(late reply due to holidays)

william said:
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. :)
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
 

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,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top