Ruby: safe navigation operator, undefined `call` method

I am trying to compare a numeric literal with the return value of a function that can return nil

or numeric. Consider this:

def unreliable
  [nil, 42].sample  
end

unreliable > 10

      

This will explode 50% of the time with NoMethodError: undefined method '>' for nil:NilClass

. So I tried this:

unreliable&.(:>, 10)

      

This approach protects nil

, but I get this when it unreliable

returns 42

:

NoMethodError: undefined method `call' for 42:Fixnum

      

I suspect this is due to quirks of only allowing one instance to exist for each Numeric

, see here . And I know I can do this:

foo = unreliable
foo && foo > 10

      

But there is a way to use the safe navigation operator with numerical and :>

, :<

, :==

, :+

, :-

, :/

, :*

, etc.


Edit . The focus on Numeric

my question is the red herring. See @ Jörg's answer. I was confusing the Rails try

syntax with the safe navigation statement syntax.

+3


source to share


2 answers


This works great in Ruby 2.3+:

unreliable&.> 10

      

For example:

[-5, 0, nil, 5].each do |unreliable|
  p unreliable&.> 0
end
# false
# false
# nil
# true

      



As you tried it, Ruby expects to unreliable

be a callable object, for example Proc

:

unreliable = Proc.new{ |*params| puts "unreliable has been called with #{params}" }
unreliable&.(:>, 10)
# unreliable has been called with [:>, 10]
unreliable.call(:>, 10)
# unreliable has been called with [:>, 10]
unreliable&.call(:>, 10)
# unreliable has been called with [:>, 10]
unreliable[:>, 10]
# unreliable has been called with [:>, 10]

      

With the safe navigation operator, there is no need to put pairs and the method must be a method name, not a symbol (Rails try

expects a symbol).

+4


source


I suspect this is due to quirks of allowing only one instance to exist for each Numeric

No, it has nothing to do with it.

foo.(bar)

      

- syntactic sugar for

foo.call(bar)

      

Ergo,

foo&.(bar)

      

- syntactic sugar for

foo&.call(bar)

      

So your code:



unreliable&.(:>, 10)

      

- syntactic sugar for

unreliable&.call(:>, 10)

      

I'm not sure who told you that the safe navigation operator takes a message as a character argument. The whole point of the safe navigation statement is that you only have trivial syntactic overhead, adding one character &

before .

, and the expression is otherwise unchanged.

So,

unreliable > 10

      

which is the same as

unreliable.>(10)

      

just becomes

unreliable&.>(10)

      

+1


source







All Articles