sawa
sawa

Reputation: 168269

Condition in the middle or at the tail of a chain

It is easy to have a condition at the head of a chain and share the rest:

if condition
    get_this
else
    get_that
end
.foo.bar.baz

But often, I want a condition in the middle or at the tail of a chain. The best I can think of is using instance_eval:

foo.bar
.instance_eval{
    if condition
        get_this
    else
        get_that
    end
}
.baz

But I have concern that calling instance_eval is heavy, so I actually end up not doing it. Is it worth doing so? Is there a better way, or should I just simply write:

if condition
    foo.bar.get_this
else
    foo.bar.get_that
end
.baz

Upvotes: 3

Views: 156

Answers (3)

lwe
lwe

Reputation: 2625

Why not provide a method on bar which accepts a boolean value and then acts accordingly? This encapsulates the logic and can even shield complex logic or multiple conditions, without getting too messy.

class Bar
  def get_what(condition)
    case condition
      when qux; get_this(param1)
      when quux; get_that(param1, param2)
      else get_other(param1)
    end
  end
end

# assuming `bar` is an instance of `Bar`
foo.bar.get_what(cond).baz

PS: Depending on the use case I often try to avoid stuff like overly long message chains (because according to the Law of Demeter (Wikipedia) this might be considered bad practice :)), though when working with hashes and arrays in ruby it's kind of useful. So I suppose you have a valid use case for using a long message chain.

Upvotes: 3

Lindydancer
Lindydancer

Reputation: 26164

Sometimes a low-tech solution is the best:

my_bar = foo.bar
if condition
  my_thing = my_bar.get_this
else
  my_thing = my_bar.get_that
end
my_thing.baz

Seriously, I consider it far more important that the meaning of source code is 100% clear to everybody (including yourself some time in the future) than it being shortened by a line or two.

Upvotes: 2

clyfe
clyfe

Reputation: 23770

How about using Object#send to conditionally call a method:

foo.bar.send(condition? ? :get_this : :get_that).baz

In a more complicated case, with multiple/different parameters one could use the splat operator to unwrap an array into parameters:

foo.bar.send(
  * case conditional
    when qux
      [:get_this, param1]
    when quux
      [:get_that, param1, param2]
    else
      [:get_other, param1, param2]
    end
).baz

Upvotes: 3

Related Questions