문제

I am extending a class to accept a DSL. The instance should always respond with a default value, but the code may change. The code below works fine when I call who_am_i, which sets the i_am method, but I can't figure out how to set a default method.

module Helper
  def i_am
    "Default code"
  end
  def who_am_i
    class_eval(<<-EOS, __FILE__, __LINE__ + 1)
      def i_am
        "This was executed in class: \#{self.class.to_s}"
      end
  EOS
  end
end

class Test
  extend Helper
end

t = Test.new
t.i_am

I can make this work by doing this:

class Test2
  extend Helper
  include Helper
end

t2 = Test2.new
t2.i_am

but this seems weird. Thoughts?

도움이 되었습니까?

해결책

You need to use included method/hook. It is being run every time given module is included into other class or module, with this class or module for a param. In your case you want:

module Helper
  def i_am
    "Default code"
  end

  def self.included mod
    mod.extend ClassMethods
  end

  module ClassMethods
    def who_am_i
      class_eval(<<-EOS, __FILE__, __LINE__ + 1)
        def i_am
          "This was executed in class: \#{self.class.to_s}"
        end
    EOS
    end
  end
end

class Tester
  include Helper
end

다른 팁

Ah ha!

The answer is to use module.included() to cause it to extend the class. This way you can use "include Helper", and the "include" part will call "Helper.included" and that is passed the caller, and you use that to extend it!

reference: http://www.railstips.org/blog/archives/2009/05/15/include-vs-extend-in-ruby/

module Helper

  def i_am
    "Default code"
  end

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def who_am_i
      class_eval(<<-EOS, __FILE__, __LINE__ + 1)
        def i_am
          "This was executed in class: \#{self.class.to_s}"
        end
  EOS
    end
  end
end


class Test
  include Helper
end
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top