Weird problem with case expressions

I have no problem doing this:

if foo :bar then

end

Yet when I do this:

case “foo”
when bar :baz then “bur”
end

I get the following syntax error:

SyntaxError: compile error
(irb):30: parse error, unexpected tSYMBEG, expecting kDO or ‘{’ or
‘(’
when bar :baz then “bur”
^

Is this intentional? Having the expression span multiple lines doesn’t
solve it.

Daniel

Daniel S. wrote:

end

I get the following syntax error:

SyntaxError: compile error
(irb):30: parse error, unexpected tSYMBEG, expecting kDO or ‘{’ or ‘(’
when bar :baz then “bur”
^

Is this intentional? Having the expression span multiple lines doesn’t
solve it.

case/when have an “alternative syntax”:

case “foo”
when bar: “bur”
end

probably this syntax is clashing with your construction.

On Jul 28, 2006, at 12:45, Daniel S. wrote:

I have no problem doing this:

if foo :bar then

end

Which is odd, 'cause I get this error:

c = [something]
if c :foo then
puts “blah”
end
SyntaxError: compile error
(irb):3: parse error, unexpected kTHEN, expecting kEND
from (irb):5
from :0

What would you expect an expression of the form ‘c :symbol’ to mean
in the first place? The only parallel I can think of is some sort of
implicit concatenation like happens with strings (“foo” “bar” =>
“foobar”), but I don’t think that’s a generalisable operation.

or ‘(’
when bar :baz then “bur”
^

Is this intentional? Having the expression span multiple lines
doesn’t solve it.

At this point it strikes me as intentional in the sense that it’s not
a valid expression to begin with. Sorry if that’s not the most
helpful answer; maybe further explanations might clear things up for me.

matthew smillie.

Hi –

On Fri, 28 Jul 2006, Matthew S. wrote:

c = [something]
first place?
I think in Daniel’s example foo is a method, and :bar is a method
argument.

David

On Jul 28, 2006, at 13:41, [email protected] wrote:

end
from :0

What would you expect an expression of the form ‘c :symbol’ to
mean in the first place?

I think in Daniel’s example foo is a method, and :bar is a method
argument.

Ah, that would explain it. I admit the method/variable ambiguity
didn’t even occur to me.

matthew smillie.

Hi –

On Fri, 28 Jul 2006, Daniel S. wrote:

end

I get the following syntax error:

SyntaxError: compile error
(irb):30: parse error, unexpected tSYMBEG, expecting kDO or ‘{’ or ‘(’
when bar :baz then “bur”

I guess when binds more tightly than a parentheses-less method call.
You could do:

when bar(:baz) …

David

Carlos wrote:

case “foo”
Is this intentional? Having the expression span multiple lines doesn’t
solve it.

case/when have an “alternative syntax”:

case “foo”
when bar: “bur”
end

probably this syntax is clashing with your construction.

if expressions have this syntax as well:

if foo: “bar”
elsif bar: “foo”
end

Daniel

On Jul 28, 2006, at 13:50, Daniel S. wrote:

Matthew S. wrote:

What would you expect an expression of the form ‘c :symbol’ to
mean in the first place?

I expect foo :bar' to be the same asfoo(:bar)’.

Indeed - mea culpa once again.

m.s.

Matthew S. wrote:

What would you expect an expression of the form ‘c :symbol’ to mean in
the first place?

I expect foo :bar' to be the same asfoo(:bar)’.

Daniel

[email protected] wrote:

Yet when I do this:

I guess when binds more tightly than a parentheses-less method call.
You could do:

when bar(:baz) …

Thank you for the response. Yes, it seems there is no way to get around
using parentheses. It’s actually just an aesthetic problem; the method
in question has a question mark suffix, and I like to call such methods
without parentheses. Specifically, it was an attempt at an aesthetically
pleasing version of the code in “Symbols are your friend”:

case “foo”
when of_type? :int then “integer”
when of_type? :str then “string”
end

Unfortunately, I’ll have to write it like this:

case “foo”
when of_type?(:int) then “integer”
when of_type?(:str) then “string”
end

It doesn’t really matter that much though – I’m not even sure I like
that solution.

Cheers, and thanks for replying,
Daniel

[email protected] wrote:

when of_type? :str then “string”
that solution.
:int => Integer,
when :str.like? then ‘string’
[Integer, String, Array].detect{|c| c === ‘foo’ and c.name.downcase}
That would work, but I don’t think classes and types are always the
same. An ordered hash is still a hash, even if it doesn’t descend from
Hash. This way, all objects that respond to #to_hash is in some way a
hash, and I can trust (to some degree) that the object returned when
calling that method implements the interface of Hash.

Cheers,
Daniel

On Fri, 28 Jul 2006, Daniel S. wrote:

Cheers, and thanks for replying,
Daniel

you could do

class Symbol
def like?
{
:int => Integer,
:str => String,
:ary => Array,
}[self] or raise ‘no type!’
end
end

then

case ‘foo’
when :int.like? then ‘integer’
when :str.like? then ‘string’
end

althogh i personally would use

[Integer, String, Array].detect{|c| c === ‘foo’}

since i can easily become a one liner, even with many classes. if you
need
the string then

[Integer, String, Array].detect{|c| c === ‘foo’ and c.name.downcase}

regards.

-a

On Sat, 29 Jul 2006, Daniel S. wrote:

ordered hash is still a hash, even if it doesn’t descend from Hash. This
way, all objects that respond to #to_hash is in some way a hash, and I can
trust (to some degree) that the object returned when calling that method
implements the interface of Hash.

indeed. still, the technique is more compact than a case:

%w( to_int to_str to_hash to_ary ).detect{|m| ‘foo’.respond_to? m}

and, for returning values

{
‘to_int’ => ‘integer’,
‘to_str’ => ‘string’,
‘to_hash’ => ‘hash’,
}.detect{|m,s| break s if ‘foo’.respond_to? m}

note that this returns ‘nil’ when no match is found. but this isn’t
quite as
compact.

cheers.

-a

[email protected] wrote:

[Integer, String, Array].detect{|c| c === ‘foo’ and c.name.downcase}

%w( to_int to_str to_hash to_ary ).detect{|m| ‘foo’.respond_to? m}

Very nice solution! It could even be written as:

%w{int str ary}.detect{|type| obj.respond_to? “to_#{type}”}

the only problem is that it violates DRY when used in case expressions:

case [:int, :str, :ary].detect{|type| obj.respond_to? “to_#{type}”}
when :int then “integer”
when :str then “string”
when :ary then “array”
end

(note that this isn’t about mapping “ary” to “array” – it’s about
determining the type of an object, and behave in accordance with that.)

Cheers,
Daniel

On a side note, this could be interesting:

class Object
def types
methods.grep(/^to_/).map{|type| type[3…-1].to_sym}
end
end

“foo”.types #=> [:a, :sym, :s, :i, :f, :str]

and maybe also

class Object
def of_type?(type)
respond_to? “to_#{type}”
end
end

foo(obj) if obj.of_type? :bar

Though of course it’s just an easier way to use #respond_to?

Cheers,
Daniel