0

I made a class with these methods:

def promotion_available?
  promotion.present?
end

def promotion
  @promotion ||= PromotionUser.user(@user.id).available.first
end

Then, a colleague removed the promotion method, and changed the predicate promotion_available? in this way:

def promotion_available?
  @promotion ||= PromotionUser.user(@user.id).available.first
end
  • Can I set an instance variable directly on a predicate method?
  • Can a predicate method return an entire object instead of true/false (I think no, but my colleague says the opposite)?
toro2k
  • 19,020
  • 7
  • 64
  • 71
easteregg
  • 149
  • 9

2 Answers2

3

Can I set an instance variable directly on a predicate method?

Yes, there's nothing wrong with it. I do it often.

Can a predicate method return an entire object instead of tre/false (I think no, but my colleague says the opposite)

Yes, this is also common. But it only works if you use idiomatic ruby truthiness checks.

if obj.promotion_available? # GOOD
if obj.promotion_available? == true # BAD!

Remember, that only nil and false in ruby are falsey values. Everything else is true. This is why returning an object or nil works kinda like returning true or false.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • The question is not clear at which level it is asking: Whether it is about syntactic correctness or about the convention. Your answer kind of inherits that ambiguity. But, +1. – sawa Feb 06 '14 at 09:49
1

Although the change "works", it introduces a side effect: you have to call promotion_available? before you can actually use the promotion (assuming that there is a promotion method):

your_object.promotion             #=> nil

your_object.promotion_available?
your_object.promotion             #=> <#PromotionUser ...>

You original code doesn't have this dependency.

IMO it would be more intuitive to keep the promotion method and to remove promotion_available?. You could just write:

if obj.promotion
  # with promotion
else
  # without promotion
end
Stefan
  • 109,145
  • 14
  • 143
  • 218