Ruby 2.3 introduced the safe navigation operator, however I find that its syntax is too discrete an can be easy to miss when briefly scanning code. Instead I much prefer the syntax of try as it looks much more obvious and intentional.
So my question is in Ruby 2.3+, Is there a way to alias or monkey patch a method to the safe navigation operator &. to a custom method name ie. s.fast_try(:upcase!).fast_try(:downcase) instead of writing s&.upcase!&.downcase
The main idea is to attempt to improve performance over another implementation such as try method. No, I dont care about the minor behaviour differences between try and safe navigation operator. Also, I do not mind some obscure argument limitations if they cannot be avoided, just point them out.
I guess you could go with something as simple as
class Object
def fast_try(meth,*args,&block)
self&.public_send(meth,*args,&block)
end
end
For Example:
["string","STRING","pOw"].map do |s|
s.fast_try(:upcase!)
.fast_try(:chars)
.fast_try(:find, ->{"No S"}) { |a| a == "S" }
.fast_try(:prepend, "!")
end
#=> ["!S",nil,"!No S"]
While your question states, " No, I don't care about the minor behavior differences between try and safe navigation operator.", given the fact that you have written a gem and noted the following
Differences between FastTry and ActiveSupport#try
It is not our goal to maintain any consistency with the ActiveSupport version of the try method. I do however want to maintain a simple list of the differences. Please create a PR or Issue if you find a difference that should be documented here.
Nothing reported yet
I feel it prudent to mention that there are discernible, and potentially poignant, differences between the 2 here is a Repl Spec to show the differences and for the sake of this answer and the fact that the link might die the output of this spec is as follows:
ActiveSupport#try vs. Safe Navigation (&.)
#try
handles would be NoMethodError with nil (using #respond_to?)
does not work on a BasicObject
behaves like a method call
with no method name given
when block_given?
yields self to a block with arity > 0
evaluates block with arity == 0 in the context of self
when no block_given?
raises an ArgumentError
with a method_name given
a non nil object
uses public_send for message transmission
nil
calls NilClass#try and returns nil
#try!
does not handle NoMethodError
does not work on a BasicObject
behaves like a method call
with no method name given
when block_given?
yields self to a block with arity > 0
evaluates block with arity == 0 in the context of self
when no block_given?
raises an ArgumentError
with a method_name given
a non nil object
uses public_send for message transmission
nil
calls NilClass#try and returns nil
&. (safe navigation)
does not handle NoMethodError
raises a SyntaxError with no method name given when block_given?
raises a SyntaxError with no method name given when no block_given?
works on a BasicObject
does not act like a method call
with a method_name given
a non nil object
&. is not called
nil
returns nil without a method call
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