Модуль Ruby со статическим вызовом метода из класса includer

Мне нужно определить константу в модуле, который использует метод из класса, включающего этот модуль:

module B 
  def self.included(base)
    class << base
  CONST = self.find
    end
  end
end 

class A
  def self.find
    "AAA"
  end
  include B 
end

puts A::CONST

Но компилятор выдает ошибку на 4-й строке.

Есть ли другой способ определить константу?


person Bogdan Gusiev    schedule 26.06.2009    source источник


Ответы (3)


Более идиоматический способ добиться этого в Ruby:

module B 
  def self.included(klass)
    klass.class_eval <<-ruby_eval
      CONST = find
    ruby_eval

    # note that the block form of class_eval won't work
    # because you can't assign a constant inside a method
  end
end

class A
  def self.find
    "AAA"
  end
  include B 
end

puts A::CONST

То, что вы делали (база класса ‹‹), на самом деле помещает вас в контекст metaclass А, а не самого А. Метод find относится к самому A, а не к его метаклассу. Следует помнить, что классы сами по себе являются объектами и поэтому имеют свои собственные метаклассы.

Чтобы попытаться сделать это более понятным:

class Human
  def parent
    # this method is on the Human class and available
    # to all instances of Human.
  end

  class << self
    def build
      # this method is on the Human metaclass, and
      # available to its instance, Human itself.
    end

    # the "self" here is Human's metaclass, so build
    # cannot be called.
  end

  def self.build
    # exactly the same as the above
  end

  build # the "self" here is Human itself, so build can
        # be called
end

Не уверен, что это поможет, но если вы этого не понимаете, вы все равно можете использовать приведенную выше идиому class_eval.

person Yehuda Katz    schedule 30.06.2009

В вашем конкретном случае.

module B 
  def self.included(base)
    base.const_set("CONST", base.find)
  end
end 

class A
  def self.find
    "AAA"
  end
  include B 
end

puts A::CONST

Несмотря на то, что это работает, это немного грязно. Вы уверены, что не можете пойти другим путем для достижения своей цели?

person Simone Carletti    schedule 26.06.2009
comment
Да, я тоже достиг этого решения. Но этот мета-вызов — не очень хорошая идея. Есть ли более прямой путь? - person Bogdan Gusiev; 26.06.2009
comment
Вы пытаетесь динамически присвоить постоянное значение во время выполнения. Насколько мне известно, другие способы вызовут ошибку присваивания динамической константы. - person Simone Carletti; 26.06.2009

module B 
  def self.included(base)
    class << base
      CONST = self.find
    end
  end
end 

class A
  class << self
    def self.find
       "AAA"
    end
  end
  include B 
end

тогда ошибка компилятора исправлена, пожалуйста, попробуйте.

person 古井好月    schedule 19.10.2010