After implementing Null Object Pattern in a Rails application (also described in RubyTapas episode 112) I refactored out some code, but there's a syntax construct that seems to not work anymore.
I used to write statements like current_user || redirect_out
, where, if current_user was set it would return it, and if it was nil
it redirects out, but now current_user
may be an instance of Null::User
and thus "truthy", and that snippet would never redirect out.
I tried defining the ||
operator, but didn't work. Is there any way this syntax can still be used with null (but "truthy") objects?
I think you have only halfway adopted that pattern, and have not correctly adopted its spirit. My understanding is that the very purpose of the pattern is to avoid ||
.
You should have some purpose for calling current_user || redirect_out
, and that could be doing something with it, or getting some attribute of it. For example, suppose your code has:
(current_user || redirect_out).foo
When current_user
is not an instance of Null::User
, you wanted to call foo
on it. In that case, what you should do is define Null::User#foo
to be redirect_out
(possibly followed by some more operations like foo
on other classes).
class Null::User
def foo; redirect_out ... end
end
and in place of (current_user || redirect_out).foo
, you should just do
current_user.foo
When current_user
is not a Null::User
instance, it will call foo
. When it is such instance, then the redirect_out ...
routine will be called on it.
I once wrote an article about how it's not possible to define "falsy" objects in Ruby, and why attempts to make a Null Object falsy are generally misguided.
Basically, the best you can do is come up with a confusingly inconsistent object using #!
, nil?
, etc.
As others have noted, usually when you want to make a Null Object "falsy" it's because you're not full leveraging polymorphism. The whole point of a Null Object is to avoid type checks, and checking for NilClass
in the form of an if
statement is just as much a type check as any other.
That said, sometimes it's unavoidable. That's why in my Naught library I generate a helper conversion function called Actual()
(among several other conversions). Actual()
converts Null Objects back to nil
values, but leaves all other objects alone. So for the cases where you need to switch on an object's truthiness, you can do it like this:
if Actual(obj_that_might_be_null)
# ...do stuff...
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With