5

ルビーでは、これを行うことができます:

class Thing
  public
  def f1
    puts "f1"
  end

  private
  def f2
    puts "f2"
  end

  public
  def f3
    puts "f3"
  end

  private
  def f4
    puts "f4"
  end
end

ここで、f1 と f3 とパブリック、f2 と f4 はプライベートです。メソッド定義を変更するクラスメソッドを呼び出すことを可能にする内部で何が起こっているのでしょうか? どうすれば同じ機能を実装できますか (表向きはアノテーションのような独自の Java を作成するため)

例えば...

class Thing
  fun
  def f1
    puts "hey"
  end

  notfun
  def f2
    puts "hey"
  end
end

fun と notfun は、次の関数定義を変更します。

ありがとう

4

3 に答える 3

8

Rubyをエスプレッソカップに押し込むことができる場合があります。方法を見てみましょう。

これがモジュールFunNotFunです...

module FunNotFun

  def fun
    @method_type = 'fun'
  end

  def notfun
    @method_type = 'not fun'
  end

  def method_added(id)
    return unless @method_type
    return if @bypass_method_added_hook
    orig_method = instance_method(id)
    @bypass_method_added_hook = true
    method_type = @method_type
    define_method(id) do |*args|
      orig_method.bind(self).call(*args).tap do
        puts "That was #{method_type}"
      end
    end
    @bypass_method_added_hook = false
  end

end

...クラスを拡張するために使用できる...

class Thing

  extend FunNotFun

  fun
  def f1
    puts "hey"
  end

  notfun
  def f2
    puts "hey"
  end
end

...この結果で:

Thing.new.f1
# => hey
# => That was fun

Thing.new.f2
# => hey
# => That was not fun

しかし、より良い方法については、線の下を参照してください。


注釈(normalocityの回答を参照)は問題が少なく、一般的なRubyイディオムであるため、コードの意図をより簡単に伝えることができます。アノテーションを使用してこれを行う方法は次のとおりです。

module FunNotFun

  def fun(method_id)
    wrap_method(method_id, "fun")
  end

  def notfun(method_id)
    wrap_method(method_id, "not fun")
  end

  def wrap_method(method_id, type_of_method)
    orig_method = instance_method(method_id)
    define_method(method_id) do |*args|
      orig_method.bind(self).call(*args).tap do
        puts "That was #{type_of_method}"
      end
    end
  end

end

使用中、アノテーションはメソッドが定義された後ではなく、次のようになります。

class Thing

  extend FunNotFun

  def f1
    puts "hey"
  end
  fun :f1

  def f2
    puts "hey"
  end
  notfun :f2

end

結果は同じです:

Thing.new.f1
# => hey
# => That was fun

Thing.new.f2
# => hey
# => That was not fun
于 2011-10-12T23:01:28.787 に答える
1

Ruby 言語自体に拡張機能を書きたいと思われますが、それは可能です。簡単に説明できるものではありませんが、次のリンクから始めてください。

http://ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html

Ruby のアノテーションに関係するこのリファレンスも参考になるかもしれません:

http://martinfowler.com/bliki/RubyAnnotations.html

于 2011-10-12T22:37:16.167 に答える
1

これは、正しい方向に導くための純粋なルビーのソリューションです。にかかっていmethod_addedます。ガード句を使用して再帰を避けるように注意してください。

module Annotations
  def fun
    @state = :fun
  end

  def not_fun
    @state = :not_fun
  end

  def inject_label(method_name)
    state = @state
    define_method(:"#{method_name}_with_label") do |*args, &block|
      puts "Invoking #{method_name} in state #{state}"
      send(:"#{method_name}_without_label", *args, &block)
     end

    alias_method :"#{method_name}_without_label", :"#{method_name}"
    alias_method :"#{method_name}", :"#{method_name}_with_label"
  end

  def self.extended(base)
    base.instance_eval do
      def self.method_added(method_name)
        return if method_name.to_s =~ /_with(out)?_label\Z/
        @seen ||= {}
        unless @seen[method_name]
          @seen[method_name] = true
          inject_label(method_name)
        end
      end
    end
  end
end

class Foo
  extend Annotations

  fun

  def something
    puts "I'm something"
  end

  not_fun

  def other
    puts "I'm the other"
  end
end
于 2011-10-12T23:17:54.153 に答える