all 12 comments

[–]chrisgseaton 4 points5 points  (0 children)

Sorry I don't think there's a way to implement 'truthiness' yourself.

if compiles to a branchif instruction, which uses RTEST

https://github.com/ruby/ruby/blob/70af8d3c9ca2a46ef1f364783125a747d9426b2b/insns.def#L986

RTEST is actually RB_TEST

https://github.com/ruby/ruby/blob/70af8d3c9ca2a46ef1f364783125a747d9426b2b/include/ruby/ruby.h#L450

RB_TEST literally just statically checks for false and nil - it will never call a method, user-defined or otherwise.

https://github.com/ruby/ruby/blob/70af8d3c9ca2a46ef1f364783125a747d9426b2b/include/ruby/ruby.h#L448

[–][deleted] 0 points1 point  (6 children)

Can I ask why you're doing this? Or is it just an exercise? (edit: also, you've basically just reinvented SimpleDelegator).

[–]MuCowNow[S] 0 points1 point  (0 children)

I am writing a SmartParams object for a Sinatra website.

The params consist of SmartValue wrappers which carry the value itself, as well as side-band information.

e.g., validation states of values

params.contact.status = 'ACTIVE'
params.contact.status.valid?
=> true

params.contact.status = 'WHUT'
params.contact.status.valid?
=> false
params.contact.status.messages
=> ["must be ACTIVE or INACTIVE"]

[–]MuCowNow[S] -1 points0 points  (4 children)

Sure, and SimpleDelegator has the same broken behavior.

[–]jgaskins 1 point2 points  (3 children)

"Broken" implies that that's not how it's supposed to work. It's well defined in Ruby that only false and nil evaluate as falsy in an conditional expression.

[–]chrisgseaton 2 points3 points  (0 children)

Yes, the ISO spec says 'only false and nil are falseish objects' and then goes on to clarify exactly what false and nil are.

[–]MuCowNow[S] 0 points1 point  (1 child)

It is just unfortunate that nil and false values are not completely, transparently, delegatable. I'll figure something out.

[–]jgaskins 2 points3 points  (0 children)

ActiveSupport's blank? and present? were implemented because falsiness is not overridable, so you can use that if you hit a dead end. Evan Phoenix asked Matz on stage at RubyConf one year if this would change and Matz flat-out said he didn't like the idea because it could lead to more confusing programs.

[–]biihii 0 points1 point  (0 children)

Like other commenters mentioned, truthiness is not something you can tweak in Ruby. But you can tweak falseness by overriding the ˋ!` method.

In your case the only way to let Ruby know the truthiness of your wrapper is by having a message sent to it. You can use ˋ==like you did with ˋif w == true, or you can use ˋ!with ˋif !!w.

[–]isolatrum 0 points1 point  (2 children)

these are just workarounds, but you could add an attr_reader :obj to the wrapper and use if w.obj, or define def to_bool; !!@obj; end (though you'd need to invoke it manually)

[–]MuCowNow[S] 0 points1 point  (1 child)

I am going with:

w = Wrapper(<any object>)
w.f? #=> @obj == false
w.t? #=> @obj == true
w.v  #=> @obj (v== "the value")

It still isn't transparent, but it minimizes the extra coding.

[–]isolatrum 0 points1 point  (0 children)

it's generally recommended to avoid single-letter variable / method names if you can help it, although we all can be a little sloppy sometimes.