【问题标题】:Ruby - Is it possible to alias a method to the safe navigation operatorRuby - 是否可以将方法别名为安全导航运算符
【发布时间】:2018-05-22 15:33:21
【问题描述】:

Ruby 2.3 引入了安全导航运算符,但是我发现它的语法过于离散,在简单扫描代码时很容易错过。相反,我更喜欢try 的语法,因为它看起来更加明显和有意。

所以我的问题是在 Ruby 2.3+ 中,有没有办法将安全导航运算符 &. 的方法别名或猴子修补到自定义方法名称,即。 s.fast_try(:upcase!).fast_try(:downcase) 而不是写s&.upcase!&.downcase

主要思想是尝试通过另一种实现来提高性能,例如try 方法。不,我不关心尝试和安全导航操作员之间的细微行为差异。另外,我不介意一些晦涩的论点限制,如果它们无法避免,请指出它们。

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    我猜你可以用一些简单的东西

    class Object
      def fast_try(meth,*args,&block)
        self&.public_send(meth,*args,&block)
      end
    end
    

    例如:

    ["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"]
    

    虽然您的问题是,“不,我不在乎 try 和安全导航运算符之间的细微行为差异。”,因为您已经编写了 gem 并注意到以下内容

    FastTry 和 ActiveSupport#try 之间的区别

    我们的目标不是保持与 try 方法的 ActiveSupport 版本的任何一致性。但是,我确实想保留一个简单的差异列表。如果您发现应在此处记录的差异,请创建 PR 或问题。

    尚未报告任何内容

    我认为谨慎地提及两者之间存在明显且可能令人心酸的差异,这里是 Repl Spec 以显示差异,并且为了这个答案以及链接可能会导致输出的事实本规范如下:

    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
    

    【讨论】:

    • 当心:nil&.nil? # => nil
    • @SergioTulentsev 是的,这就是运算符的工作方式(我没有设计它),问题是如何将安全运算符修补到方法调用中
    • 啊,我明白了。需要休息 :) 认为导航操作员在那里没有做任何有用的事情(public_send 就足够了)
    • 显然安全导航不适用于类或模块
    • @WestonGanger 你是什么意思?它工作得很好Class&.to_s #=>"Class"
    【解决方案2】:

    我创建了一个 gem 来根据这个 StackOverflow 答案中的信息来解决这个问题。

    fast_try 是安全导航运算符的简单方法包装器。

    特点/目标:

    • 在提高可读性的同时利用安全导航运算符 (&.)
    • 与其他实现(例如 ActiveSupport#try 方法)相比,提高性能
    • 如果无法避免大多数晦涩的参数/语法限制,请不要担心。简单和速度是关键。
    • 所提供的方法的行为应该与安全导航运算符非常相似。如果您需要保留 ActiveSupport try 的确切行为,只需为 FastTry 设置您自己的自定义方法名称。
    • 唯一的依赖是 Ruby 2.3+。它不需要 Rails /ActiveSupport 其他任何东西,但它也可以很好地工作!

    在初始化器中:

    FastTry.method_names = [:try, :custom_try, :try!]
    require 'fast_try/apply'
    

    用法:

    str.try(:upcase).try(:downcase)
    
    # the above statement is now equivalent to using the safe navigation operator Ex.
    str&.upcase&.downcase
    

    【讨论】:

    • 不过,它不是别名。它可能是一个行为相同的实现,但它不是别名。
    • “应该总是表现得像安全导航操作员”——在这个 gem 中只有一个测试。 ¯\_(ツ)_/¯
    • @SergioTulentsev 是对的,这不是别名,只是方法包装器。此外,由于您在 gem 中指出没有已知差异,我认为值得一提的是,安全导航器和 try 之间存在显着而深刻的差异。请在This Repl Spec 中查看其中一些显着差异
    • 回购是开源的。一切都与合作有关。只需在您认为合适的时候在 repo 中添加 PR 或 issue。
    • @WestonGanger 我很清楚开源是如何工作的,但考虑到您的 gem 是单个文件。我基本上会重写你的整个库,这不是我的意图,也不允许你展示自己的作品。
    猜你喜欢
    • 2017-12-22
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 2011-09-30
    • 2016-04-07
    • 2012-03-13
    相关资源
    最近更新 更多