Forum: Ruby What's the easiest way to check if param[:x][:y] exists?

Fc582698581884352e745d1d4c64699d?d=identicon&s=25 Joshua Muheim (josh)
on 2008-08-12 18:06
Hi all

In PHP I can simply check whether $param['x']['y'] exists regardless
whether $param['x'] exists or not.
In Rails I get a NoMethodError when using

if param[:x][:y]
  ..
end

when param[:x] is nil. So I always have to use

if param[:x] and param[:x][:y]
  ..
end

but I think that's not very beautiful - think about a case where I have
to check whether param[:a][:b][:c][:d][:...] exists or not!

Maybe there's a cooler way to do this? ;-)

Thanks
Josh
7ff0c83b7ff0249aad31b76ea4f6b3e7?d=identicon&s=25 Shadowfirebird (Guest)
on 2008-08-12 18:19
(Received via mailing list)
It looks to me as if you should be able to check for nil.

foo( param[:x][:y] ) unless (param[:x][:y] == nil)
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 David A. Black (Guest)
on 2008-08-12 18:20
(Received via mailing list)
Hi --

On Wed, 13 Aug 2008, Joshua Muheim wrote:

> when param[:x] is nil. So I always have to use
>
> if param[:x] and param[:x][:y]
>  ..
> end
>
> but I think that's not very beautiful - think about a case where I have
> to check whether param[:a][:b][:c][:d][:...] exists or not!
>
> Maybe there's a cooler way to do this? ;-)

Yes: design your data structures with classes and modules and methods,
instead of quintuply-nested hashes :-) But if you want to have a hash
that automatically inserts a hash for an unknown key, you can do:

func = lambda {|h,k| h[k] = Hash.new(&func) }
hash = Hash.new(&func)

I think that's the OK version.... You can also rescue NoMethodError,
though that's kind of fuzzy with lots of nesting.


David
Fc582698581884352e745d1d4c64699d?d=identicon&s=25 Joshua Muheim (josh)
on 2008-08-12 18:22
Shadowfirebird wrote:
> It looks to me as if you should be able to check for nil.
>
> foo( param[:x][:y] ) unless (param[:x][:y] == nil)

I tried it on IRB, but it doesn't seem to work.
Fc582698581884352e745d1d4c64699d?d=identicon&s=25 Joshua Muheim (josh)
on 2008-08-12 18:26
David A. Black wrote:
>> Maybe there's a cooler way to do this? ;-)
>
> Yes: design your data structures with classes and modules and methods,
> instead of quintuply-nested hashes :-)

You're right, I just saw that I don't need such a nested hash... ;-)
7ff0c83b7ff0249aad31b76ea4f6b3e7?d=identicon&s=25 Shadowfirebird (Guest)
on 2008-08-12 18:27
(Received via mailing list)
Sorry, you're right:

irb(main):001:0> a = {:a=>{:x=>1}}
=> {:a=>{:x=>1}}
irb(main):003:0> p a[:a][:x]
1
=> nil
irb(main):004:0> p a[:a][:y]
nil
=> nil
irb(main):005:0> p a[:b][:x]
NoMethodError: undefined method `[]' for nil:NilClass
        from (irb):5

David's *much* smarter than me, so listen to him...


On Tue, Aug 12, 2008 at 5:18 PM, Shadowfirebird
C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2008-08-12 18:29
(Received via mailing list)
On Tuesday 12 August 2008, Joshua Muheim wrote:
> when param[:x] is nil. So I always have to use
> Thanks
> Josh

You can use the rescue modifier, like this:

if (param[:x][:y] rescue nil)
  ...
end

The expression in brackets will return the value of param[:x][:y] but if
param[:x][:y] raises an exception derived from StandardError (like
NoMethodError), the exception will be caught by the rescue modifier, and
the
statement to the right of rescue (nil) will be returned.

I hope this helps

Stefano
F7b9d923c02d775dcfcfb9df7f705547?d=identicon&s=25 Tommy Morgan (Guest)
on 2008-08-12 18:33
(Received via mailing list)
> foo( param[:x][:y] ) unless (param[:x][:y] == nil)

That only works if param[:x] exists. It's also not perfect, since
[aram[:x][:y] can return a non-nil value if param[:x] exists but is
not an array... so you probably need to check for that case also.

To my knowledge, the only way you could handle this easily would be to
rescue the NoMethodError as follows:

param[:x][:y] rescue NoMethodError { nil } # return nil if
NoMethodError is raised

Although that's tricky too, as depending on the nature of your object
structure, you may catch a NoMethodError you didn't intend to catch.

Hope that helps.

--Tommy M.
50b2daf0e7666574579b9edaf8f2b69a?d=identicon&s=25 Pit Capitain (Guest)
on 2008-08-13 21:35
(Received via mailing list)
2008/8/12 David A. Black <dblack@rubypal.com>:
> But if you want to have a hash
> that automatically inserts a hash for an unknown key, you can do:
>
> func = lambda {|h,k| h[k] = Hash.new(&func) }
> hash = Hash.new(&func)

David, hashes like this don't solve Josh's problem. He wants two
conflicting things:

1) param[:x][:y] should be false or nil, so that you can use it as a
condition
2) you should be able to nest arbitrarily deep, for example
param[:x][:y][:z]

If Josh really wanted to do that, he'd have to define FalseClass#[] or
NilClass#[], but as you have written he'd better change his data
structures.

Regards,
Pit
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.