Question

I need to check if a variable is an array, and if not convert it into one before proceed with further processing. So, my code looks like this:

class Test < Struct.new(:args)
    def eval
        p "1. #{args}"
        args = (args.instance_of? Array) ? args : [args]
        p "2. #{args}" # woah! [nil]?
        # ...other things, with "args" being an array for sure..or not?!?
    end
end

I am quite new to ruby, so perhaps this is not very idiomatic, but to me looks like this code should at least work. Instead, the second time I print the args variable, it is [nil]. Notice that if I change the method eval slightly:

def eval
    p "1. #{args}"
    a = args
    args = (a.instance_of? Array) ? a : [a]
    p "2. #{args}"
end

everything works as expected. So, is there something very specific to the Struct class that I don't get it, or something fishy is going on here? (using ruby 1.9.3-dev on macosx, using rvm)

Was it helpful?

Solution

Actually there's a Ruby idiom for what you are trying to do: [*args]. * in this context is called the splat operator:

http://raflabs.com/blogs/silence-is-foo/2010/08/07/ruby-idioms-what-is-the-splatunary-operator-useful-for/

If you get passed an array, splat will "flatten" the array into the new one, if you pass a single argument, it will become a one element array.

For the odd behavior: it looks to me like you create a local variable args in your eval method, which gets initialized to nil because it's on the LHS of an assignment. Then the ternary evaluates to false because args is not an array and makes an array of the current value, which is still nil. If args would be an instance variable (@args), things would work the way you expect. In other words, while inheriting from the Struct will give you args and args= methods, it won't give you an @args instance variable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top