9
class C1
  unless method_defined? :hello  # Certainly, it's not correct. I am asking to find something to do this work.
    def_method(:hello) do
      puts 'Hi Everyone'
    end
  end
end

では、メソッドが定義されているかどうかを判断するにはどうすればよいでしょうか。

4

3 に答える 3

18

投稿したコードは、メソッドが定義されているかどうかを確認するのに問題なく機能します。Module#method_defined?まさに正しい選択です。(バリアント、、もありModule#public_method_defined?ますModule#protected_method_defined?Module#private_method_defined?)問題は、への呼び出しにありますがdef_method、これは存在しません。(それはと呼ばれModule#define_methodます)。

これは魅力のように機能します:

class C1      
  define_method(:hello) do
    puts 'Hi Everyone'
  end unless method_defined? :hello
end

ただし、名前は事前にわかっていて、クロージャを使用しないため、を使用する必要はありません。代わりにキーワードをModule#define_method使用できます。def

class C1
  def hello
    puts 'Hi Everyone'
  end unless method_defined? :hello
end

または、私はあなたの質問を誤解していて、あなたは継承について心配していますか?その場合、Module#method_defined?継承チェーン全体を歩くため、は正しい選択ではありません。その場合、またはそのいとこの1つ、またはを使用する必要があります。Module#instance_methodsこれModule#public_instance_methodsは、スーパークラス/ミックスインのメソッドを含めるかどうかを指示するオプションの引数を取ります。(ドキュメントが間違っていることに注意してください。引数を渡さない場合、継承されたすべてのメソッドが含まれます。)Module#protected_instance_methodsModule#private_instance_methods

class C1
  unless instance_methods(false).include? :hello
    def hello
      puts 'Hi Everyone'
    end
  end
end

これが私の提案が機能することを示す小さなテストスイートです:

require 'test/unit'
class TestDefineMethodConditionally < Test::Unit::TestCase
  def setup
    @c1 = Class.new do
      def self.add_hello(who)
        define_method(:hello) do
          who
        end unless method_defined? :hello
      end
    end

    @o = @c1.new
  end

  def test_that_the_method_doesnt_exist_when_it_hasnt_been_defined_yet
    assert !@c1.method_defined?(:hello)
    assert !@c1.instance_methods.include?(:hello)
    assert !@o.methods.include?(:hello)
    assert !@o.respond_to?(:hello)
    assert_raise(NoMethodError) { @o.hello }
  end

  def test_that_the_method_does_exist_after_it_has_been_defined
    @c1.add_hello 'one'

    assert @c1.method_defined?(:hello)
    assert @c1.instance_methods.include?(:hello)
    assert @o.methods.include?(:hello)
    assert_respond_to @o, :hello
    assert_nothing_raised { @o.hello }
    assert_equal 'one', @o.hello
  end

  def test_that_the_method_cannot_be_redefined
    @c1.add_hello 'one'

    assert @c1.method_defined?(:hello)
    assert @c1.instance_methods.include?(:hello)
    assert @o.methods.include?(:hello)
    assert_respond_to @o, :hello
    assert_nothing_raised { @o.hello }
    assert_equal 'one', @o.hello

    @c1.add_hello 'two'

    assert @c1.method_defined?(:hello)
    assert @c1.instance_methods.include?(:hello)
    assert @o.methods.include?(:hello)
    assert_respond_to @o, :hello
    assert_nothing_raised { @o.hello }
    assert_equal 'one', @o.hello, 'it should *still* respond with "one"!'
  end
end
于 2010-08-04T07:23:01.927 に答える
2

RubyObjectクラスを見てください。methodsメソッドのリストを取得する機能と、特定のメソッドrespond_to?をチェックする機能があります。したがって、次のようなコードが必要です。

class C1
  def add_hello
    unless self.respond_to? "hello"
      def hello
        puts 'Hi Everyone'
      end
    end  
  end
end

cone.hello      #This would fail
cone.add_hello  
cone.hello      #This would work
于 2010-08-04T06:16:03.700 に答える
1

Objectクラスには、メソッド「methods」があります:docs

 class Klass
   def kMethod()
   end
 end
 k = Klass.new
 k.methods[0..9]    #=> ["kMethod", "freeze", "nil?", "is_a?",
                    #    "class", "instance_variable_set",
                    #    "methods", "extend", "__send__", "instance_eval"]
 k.methods.length   #=> 42
于 2010-08-04T06:12:36.240 に答える