Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby - Is it possible to alias a method to the safe navigation operator

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.

like image 808
Weston Ganger Avatar asked Nov 30 '25 11:11

Weston Ganger


1 Answers

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
like image 183
engineersmnky Avatar answered Dec 02 '25 02:12

engineersmnky



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!