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


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.

[email protected]:/path$ irb
irb(main):001:0> a = “Foo”
=> “Foo”
irb(main):002:0> a.class === String
=> false
irb(main):003:0> a === String
=> false
irb(main):004:0> a.class === String.class
=> false
irb(main):005:0> a
=> “Foo”
irb(main):006:0> a.inspect
=> ““Foo””
irb(main):007:0> String.inspect
=> “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
=> nil
irb(main):014:0> String === a
=> true
irb(main):015:0> a === String
=> false
irb(main):016:0> [email protected]:/usr/ports# irb
irb(main):001:0> str = “a string”
=> “a string”
irb(main):002:0> str.class
=> String
irb(main):003:0> String === str.class
=> false
irb(main):004:0> String === str
=> 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
=> 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
=> nil

Why isn’t the “when String” statement executed?

I believe case/when uses the when object’s === method for matching,
and as you can see from the above irb session, String === “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 ===
“a string” evaluates to true).

Note that “a string” === String evaluates to false even though “a
string” === 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.

On Jan 26, 7:10pm, “Aaron D. Gifford” [email protected] wrote:

=> “Foo”
irb(main):003:0> String === str.class
=> nil

Why isn’t the “when String” statement executed?
Note that “a string” === String evaluates to false even though "a

Aaron out.

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,

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs