Ruby self.extended вызывается как метод экземпляра - PullRequest
0 голосов
/ 08 мая 2020
module Country
  def location
    puts "location"
  end

  def self.included(base)
    def cities
      puts "cities"
    end
  end

  def self.extended(base)
    def animals
      puts "animals"
    end
  end
end

class Test
  include Country
end

class Test2
  extend Country
end

Насколько я понимаю, self.included будет вызываться, когда модуль включается как метод экземпляра, а как self.extended будет вызываться, когда модуль расширяется как метод класса stati c.

Но когда у меня есть два класса в одном файле, почему он не выдает ошибку

Test.new.animals

=> животные

И если я удален класс Test 2,

 # class Test2
  # extend Country
# end

Test.new.animals

=> Нет ошибки метода

Ответы [ 2 ]

3 голосов
/ 08 мая 2020

def bar без явного definee (т.е. def foo.bar) определяет bar в ближайшем лексически включающем модуле. Ближайшим лексически охватывающим модулем для всех трех ваших def s всегда является Country, поэтому все три метода определены в модуле Country.

Если вы хотите определить одноэлементный метод , вы можете использовать

module Country
  def self.extended(base)
    def base.animals
      puts "animals"
    end
  end
end

См. Ruby какой класс получает метод, когда нет явного получателя? для более подробной информации.

0 голосов
/ 08 мая 2020

Возможно, я четко проясню то, что, по моему мнению, не полностью и явно адресовано прекрасному ответу Йорга (с величайшим уважением) тем, кто не знаком с « объектной моделью » Ruby:

module Country
  def location
    puts "location"
  end

  def self.included(base)
    def cities
      puts "cities"
    end
  end

  def self.extended(base)

    puts "#{self}"  ## NOTICE THIS NEW LINE! NEW LINE

    def animals
      puts "animals"
    end
  end
end


class Test
  include Country
end

class Test2
  extend Country
end

Test.new.animals

В чем проблема?

Мы расширяем Test2, не так ли? Как же тогда метод животных определен в Тесте 1?

Ключ должен добавить строку puts "#{self} над методом животных.

Здесь мы видим, что метод животных определен в Страновой модуль. Так что на самом деле, когда вы думаете, что расширяете, вы на самом деле убедитесь, что он добавлен как метод экземпляра, а не как «метод класса stati c» (если вы исходите из c# / java фон). Строго говоря, это не совсем точно: когда вы «расширяете» таким образом - и если вы делаете это правильно - вы фактически добавляете метод в одноэлементный класс Test2. В этом отношении объектная модель Ruby немного сложна. Метод класса stati c - это метод, ДОБАВЛЕННЫЙ в одноэлементный класс класса. Что такое одноэлементный класс? Теперь вы попадаете в объектную модель ruby. Это сложно и требует утечки мозгов, но как только вы это поймете, вы сможете делать некоторые довольно мощные (и опасные?) Вещи, такие как: исправление обезьян.

Решение:

говорит Йорг. это лучше, чем я мог. вам нужно определить животных следующим образом: def base.animals.

...