Reputation: 13491
How can you construct an array in Ruby which only uses a variable if it exists, and otherwise uses nil
in its place. With the conditional logic inside the array constructor.
Simplified Example:
a = 1
c = 3
arr = [a, b || nil, c]
I've tried a number of different way but they are not working so I feel like I'm missing something fundamental here.
(b || nil)
b ? b : nil
b.nil? ? nil : b
Is this possible?
Context:
This array constructor is used inside a loop used by multiple different models. Some models have the b
attribute and some do not, making it difficult extrapolate the logic outside.
Upvotes: 2
Views: 792
Reputation: 434665
Given that your b
is actually a model attribute which may or may not be supported by the current self
, then b
is not a variable at all, b
is a method call and you're not interested in whether or not the "variable" exists, you're interested in whether or not self
responds to b
. Hence you want to use respond_to?
:
arr = [a, respond_to?(:b) ? b : nil, c]
or perhaps:
arr = [a, respond_to?(:b, true) ? b : nil, c]
if you want to allow b
to be a non-public method.
defined?(b)
should also work in this case (unless b
's accessor method is automatically created via method_missing
) but it will be rather puzzling to anyone looking at your code. Using respond_to?
to see if an object has a method/attribute would be more idiomatic.
Using respond_to?
when faced with method_missing
of course assumes that both method_missing
and respond_to?
have been overridden but that should be a relatively safe assumption.
Upvotes: 2
Reputation: 160551
Ugh. Don't write code like that. Instead break it into more understandable pieces:
a = 1
c = 3
b ||= nil
arr = [a, b, c]
Or, use vertical space to help the brain see what's going on:
arr = [
a,
b ||= 3,
c
]
Upvotes: 0
Reputation: 4615
Yea, you can use defined?
method. It return "local-variable"
if variable exist, if not it will return nil
.
arr = [a, defined?(b) ? b : nil, c]
Upvotes: 3
Reputation: 13354
You can do:
arr = [a, (b ||= nil), c]
Example:
a = 1
b = nil
c = 3
> arr = [a, (b ||= 33), c]
=> [1, 33, 3]
b = 2
> arr = [a, (b ||= 33), c]
=> [1, 2, 3]
If b
may not be defined, you'll need to use defined?
:
> arr = [a, (defined?(b) ? b : nil), c]
=> [1, nil, 3]
Upvotes: 0
Reputation: 9497
This will do the trick:
arr = [a, b = b || nil, c]
Example 1:
a = 1
c = 3
arr = [a, b = b || nil, c]
p arr #=> [1, nil, 3]
Example 2:
a = 1
b = 2
c = 3
arr = [a, b = b || nil, c]
p arr #=> [1, 2, 3]
Upvotes: 0