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

Discussion in 'Ruby' started by william robb, Jul 8, 2006.

  1. william robb

    william robb Guest

    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



    --
    Posted via http://www.ruby-forum.com/.
    william robb, Jul 8, 2006
    #1
    1. Advertising

  2. william robb

    Hal Fulton Guest

    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
    Hal Fulton, Jul 8, 2006
    #2
    1. Advertising

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

    > 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
    >
    >
    >
    > --
    > 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 Capaldo, Jul 8, 2006
    #3
  4. william robb

    william robb Guest

    Re: newbie Q - calling a method for an object in an .each bl

    Logan Capaldo 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


    --
    Posted via http://www.ruby-forum.com/.
    william robb, Jul 8, 2006
    #4
  5. Re: newbie Q - calling a method for an object in an .each bl

    2006/7/8, william robb <>:
    > Logan Capaldo 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.


    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

    --
    Have a look: http://www.flickr.com/photos/fussel-foto/
    Robert Klemme, Jul 8, 2006
    #5
  6. Re: newbie Q - calling a method for an object in an .each bl

    Robert Klemme 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
    Daniel Schierbeck, Jul 8, 2006
    #6
  7. william robb

    william robb Guest

    calling a method for an object in a .each block cont./chat

    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.

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



    --
    Posted via http://www.ruby-forum.com/.
    william robb, Jul 9, 2006
    #7
  8. Re: calling a method for an object in a .each block cont./chat

    william robb wrote:
    > 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.

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


    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
    Robert Klemme, Jul 9, 2006
    #8
  9. william robb

    william robb Guest

    Re: calling a method for an object in a .each block cont./ch

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

    --
    Posted via http://www.ruby-forum.com/.
    william robb, Jul 11, 2006
    #9
  10. Re: calling a method for an object in a .each block cont./ch

    (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. :)

    > 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 Klemme, Jul 30, 2006
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. morrell
    Replies:
    1
    Views:
    946
    roy axenov
    Oct 10, 2006
  2. Mr. x

    Calling a method each time the Web-Service is called.

    Mr. x, Oct 4, 2003, in forum: ASP .Net Web Services
    Replies:
    0
    Views:
    112
    Mr. x
    Oct 4, 2003
  3. Wolfgang Nádasi-Donner
    Replies:
    0
    Views:
    121
    Wolfgang Nádasi-Donner
    May 31, 2007
  4. Kyung won Cheon
    Replies:
    0
    Views:
    200
    Kyung won Cheon
    Nov 21, 2008
  5. why-em-jay

    Calling a method of the calling object ...

    why-em-jay, Sep 15, 2005, in forum: Perl Misc
    Replies:
    3
    Views:
    175
    Anno Siegel
    Sep 15, 2005
Loading...

Share This Page