Problem: use case stmt on object's class in simple test

Discussion in 'Ruby' started by RichardOnRails, Jan 26, 2011.

  1. Hi,

    The following is a toy abstract from an app I'm writing.

    hash = {:Name=>"Tom"}
    hash.each_key { |key|
    puts "key %s (class = %s) => %s (class = %s)" %
    [key.inspect, key.class, hash[key], hash[key].class]
    case hash[key].class
    when String; p has[key]
    else; puts "hash[key].class not found"

    The output is:
    key :Name (class = Symbol) => Tom (class = String)
    hash[key].class not found

    Why isn't the "when String" statement executed?

    Thanks in Advance,

    P.S. I wonder if the time will come when I won't regularly stumble
    over apparent anomalies when writing Ruby code.
    RichardOnRails, Jan 26, 2011
    1. Advertisements

  2. [email protected]:/path$ irb
    irb(main):001:0> a =3D "Foo"
    =3D> "Foo"
    irb(main):002:0> a.class =3D=3D=3D String
    =3D> false
    irb(main):003:0> a =3D=3D=3D String
    =3D> false
    irb(main):004:0> a.class =3D=3D=3D String.class
    =3D> false
    irb(main):005:0> a
    =3D> "Foo"
    irb(main):006:0> a.inspect
    =3D> "\"Foo\""
    irb(main):007:0> String.inspect
    =3D> "String"
    irb(main):008:0> case a
    irb(main):009:1> when String
    irb(main):010:1> puts 'string'
    irb(main):011:1> else
    irb(main):012:1* puts 'not'
    irb(main):013:1> end
    =3D> nil
    irb(main):014:0> String =3D=3D=3D a
    =3D> true
    irb(main):015:0> a =3D=3D=3D String
    =3D> false
    irb(main):016:0> [email protected]:/usr/ports# irb
    irb(main):001:0> str =3D "a string"
    =3D> "a string"
    irb(main):002:0> str.class
    =3D> String
    irb(main):003:0> String =3D=3D=3D str.class
    =3D> false
    irb(main):004:0> String =3D=3D=3D str
    =3D> true
    irb(main):005:0> case str.class
    irb(main):006:1> when String
    irb(main):007:1> puts 'it is a string'
    irb(main):008:1> else
    irb(main):009:1* puts 'else executed'
    irb(main):010:1> end
    else executed
    =3D> nil
    irb(main):011:0> case str
    irb(main):012:1> when String
    irb(main):013:1> puts 'it is a string'
    irb(main):014:1> else
    irb(main):015:1* puts 'else executed'
    irb(main):016:1> end
    it is a string
    =3D> nil
    I believe case/when uses the when object's =3D=3D=3D method for matching,
    and as you can see from the above irb session, String =3D=3D=3D "a
    string".class evaluates to false. Hence your code doesn't work like
    you expected.

    However, if you change to hash[key] instead of hash[key].class, a
    direct comparison to the class object should work (note the String =3D=3D=
    "a string" evaluates to true).

    Note that "a string" =3D=3D=3D String evaluates to false even though "a
    string" =3D=3D=3D String evaluates to true. That way case String when "a
    string" won't match but case "a string" when String will. (Which
    totally makes sense in the context of case/when.)

    I'm sure I read a great blog post or discussion on this very thing in
    the past on the web, one that explains the gory details about exactly
    why case/when was designed to work this way. It currently slips my

    Anyone got a good URL for an article/post like that?

    Aaron out.
    Aaron D. Gifford, Jan 27, 2011
    1. Advertisements

  3. Hey Aaron,

    You scored a triple. I should say you scored 3 homers. In order of
    importance on my grading scale:

    1. You solved my problem: Lose the ".class"

    2. You showed me that using IRB for experimenting like this is far
    better than littering one's code with debugging statements.

    3. You reminded me to RTFM! Actually, I rotate between books, PDFs
    and blogs on Ruby, Rails, CSS, RSpec, etc. all the time. But as I
    encountered this unfathomable situation, I didn't do what I've now
    done: Consult PickAxe (2nd ed., 2005), which confirmed your belief
    that case uses === for a comparison of the case parameter and when

    Many thanks for your deep and insightful solution to my question.

    Best wishes,
    RichardOnRails, Jan 27, 2011
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.