-3

Ruby 2.0 で導入された、いわゆる改良がありました。私は彼らと遊んでいましたが、今では完全に甘やかされています:

— の主な宣言された利点refineは、グローバル スコープではないことです。ああ。

module MyModule
  class ::String
    def my_locally_needed_func
      # do smth 
    end
  end
end

# here I need it
require 'mymodule'
"".my_locally_needed_func

悪くはありません。

— 絞り込みはクラス メソッドをサポートしません。ああ。もちろん、それらはハックによるものです (覚えておいてください、すべてがオブジェクトです)。

module VoidRefinements
  refine String do
    def self.singleton_method_for_string_class
      puts "inside singleton_method_for_string_class"
    end 
  end 
end

module VoidRefinementsOK
  refine Class do
    def singleton_method_for_string_class
      err_msg = "NoMethodError: undefined method ‘#{__method__}’ for ‘#{self}:#{self.class}’"
      raise NoMethodError.new(err_msg) unless String == self
      puts "inside proper singleton_method_for_string_class"
    end 
  end 
end

using VoidRefinements
String.singleton_method_for_string_class rescue puts $!

using VoidRefinementsOK
String.singleton_method_for_string_class rescue puts $!

# undefined method `singleton_method_for_string_class' for String:Class
# inside proper singleton_method_for_string_class

後者は、誰も故意に呼び出すことはないため、パフォーマンスが低下することさえありませんFixnum.substr

— 改良は を通じて実行されますevalrefineはキーワードではありません。ああ。(まあ、「バー!」再び。)

それで、私の質問は次のとおりです。私はスマートを逃していますか、それとも新しく導入された機能に誰も利点がないと考えていますか?

4

1 に答える 1

21

Refinements がグローバルにスコープされていないという事実を完全に却下しますが、それが導入のまさに理由です。もちろん、何かの存在理由を単純に無視するのであれば、明らかに何の価値も見出せません。

しかし、実際の分離を見てください。Refinements を使用するように変更した例を次に示します。

module MyModule
  refine String do
    def my_locally_needed_func
      # do smth 
    end
  end
end

module MyOtherModule
  # The monkeypatch is invisible:
  "".my_locally_needed_func
  # NoMethodError: undefined method `my_locally_needed_func' for "":String

  # I first have to use the Refinement:
  using MyModule
  "".my_locally_needed_func
end

# The monkeypatch is scoped. Even though we were able to use 
# it in MyOtherModule, we still cannot use it at the top-level:
"".my_locally_needed_func
# NoMethodError: undefined method `my_locally_needed_func' for "":String

# We have to call `using` again, for the top-level:
using MyModule
"".my_locally_needed_func

比較のための例を次に示します

module MyModule
  class ::String
    def my_locally_needed_func
      # do smth 
    end
  end
end

# here I need it
"".my_locally_needed_func

注:usingとにかく絞り込みを使用していないため、意味をなさない呼び出しを削除しました。

あなたの場合、単にStringクラスを変更しただけなので、monkeypatch はグローバルに利用できます。この機能は「オープン クラス」と呼ばれ、まさに Refinements が避けるべきものです。

于 2013-03-05T12:38:50.183 に答える