3

私はJavaのより動的な代替手段を探しているので、Rubyを調べ始めました。定義後にRubyでクラスを変更する方法が好きです。たとえば、次のようになります。

class A
  def print
    "A"
  end
end

class B < A
  def print
    super + "B"
  end
end

class A
  alias_method :print_orig, :print
  def print
    print_orig + "+"
  end
end

puts B.new.print # A+B

今、私はミックスインで同じことをしようとしています:

class A
  def print
    "A"
  end
end

class B < A
  def print
    super + "B"
  end
end

module Plus
  alias_method :print_orig, :print
  def print
    print_orig + "+"
  end
end

A.extend(Plus) # variant 1
B.extend(Plus) # variant 2
class A # variant 3
  include Plus
end
class B # variant 4
  include Plus
end
puts B.new.print

ただし、どのバリアントも期待される結果を生成しません。ところで、期待される結果は次のとおりです。動作を変更するために、クラスAをミックスインで「パッチ」できるようにしたい。同じ動作で複数のクラスに「パッチ」を適用したいので、ミックスインを使用したいと思います。

私がやりたいことをすることは可能ですか?はいの場合、どのように?

4

2 に答える 2

5

モジュールコードは間違ったコンテキストで実行されているため、機能しません。のコンテキストで実行する必要がありますがA、代わりにのコンテキストで評価されますPlusselfつまり、からPlusに変更する必要がありますA

観察:

class A
  def print
    "A"
  end
end

class B < A
  def print
    super + "B"
  end
end

module Plus
  self # => Plus
  def self.included base
    self # => Plus
    base # => A
    base.class_eval do
      self # => A
      alias_method :print_orig, :print
      def print
        print_orig + "+"
      end
    end
  end
end

A.send :include, Plus
B.new.print # => "A+B"
于 2012-04-13T06:48:14.423 に答える
1

このようにMixinを実際に使用することはできません。クラスとそのミックスインの間に競合が発生しています。Mixinは、線形化によって競合を暗黙的に解決します。結論は次のとおりです。競合する場合は、クラスのメソッドがミックスインよりも優先されます。これを修正するには、SergioのTulentsevのアプローチを使用して、ミックスインに基本クラスを積極的に変更させることができます。

または、リフレクティブにメソッドを追加できます。マークのブログから盗んだこの例を考えてみましょう。

class Talker

  [:hello, :good_bye].each do |arg|
    method_name = ("say_" + arg.to_s).to_sym
    send :define_method, method_name do
      puts arg
    end
  end

end


t = Talker.new
t.say_hello
t.say_good_bye
于 2012-04-13T06:53:33.627 に答える