2013-05-21 2 views
1

Конечно, добиться того, что я прошу в названии, можно написать следующий код:Лучший способ перечислить где везде модуль был включен

module Foo 
    class << self 
    def included receiver 
     my_herd << receiver 
    end 

    def my_herd; @my_herd ||= [] end 
    alias where_everywhere_am_I_included my_herd 
    end 
end 

Foo.where_everywhere_am_I_included #=> [] 

module Bar 
    include Foo 
end 

Foo.where_everywhere_am_I_included #=> [Bar] 
# etc. 

Я могу себе представить хуже пути для этого, например, для поиска ObjectSpace для всех модулей и grep их предков. Что я хочу знать, есть ли лучший способ? Я что-то забываю, например, что-то вроде метода Module#included_in. Я пропустил что-то умное, например. известный #append_features метод? Какие лучшие альтернативы у меня есть?

Отредактировано: Проблема с реальным миром, которую я решаю, связана с my library SY, которая предоставляет физические единицы измерения. Методы физического устройства, такие как 1.metre, 1.m, 1.s, 1.lb, 1.K, имеют тенденцию быть простыми символами, склонными к столкновениям. Например. ActiveSupport уже определены методы времени #hour, #minute, #second на Numeric. С.Ю. также определяет методы #hour псевдоним #h, #minute псевдоним #min, #second#s псевдоним на Numeric средствами в Mixin, обеспечивающей #method_missing реакцию с методами на единицу продукции. Но люди, которые используют ActiveSupport уже #hour, #minute, #second определены и поэтому #method_missing не пинать. Они все еще могут получить доступ SY метод по #h, #min, #s сокращениям, но это, кроме точки. Дело в том, что люди должны быть предупреждены, когда mixin находит возможные столкновения в модулях, в которые он включен. Это было бы просто достигнуто путем кодирования проверки столкновения в крюке Module#included. Но проблема заключается в том, что пользователь может также определить единицу динамически, например:

PINT = Unit.of Volume, amount: 568.26.cm³ 
QUART = Unit.of Volume, amount: 2.pint 

Но можно представить себе, что пользователь уже имеет метод #quart, определенный на Numeric, делать что-то другое, например, вычисление 1 четверть приемник или возврат 4-го музыкального интервала относительно приемника и т. д. Поэтому, когда ze вызывает QUART = Unit#of... конструктор, я хочу попросить mixin SY::ExpressibleInUnits сообщить, где он повесился, и предупредить, увидев столкновение в Numeric. Я просто хочу сохранить своего пользователя от сюрпризов, и мне интересно, что является самым добродетельным (с использованием слова торговой марки Avdi).

+0

Не знаю, как лучше, чем переопределять метод «Module.included». Btw. вы пытаетесь решить какую-то реальную проблему или просто играть с рубином? – Torimus

+0

Это не имеет большого значения, потому что, как сказал Мац, Ruby должен сделать программистов счастливыми. Но на самом деле я действительно решаю настоящую проблему. Это было всего несколько дней назад, когда, прочитав код многих других проектов, я понял, что моя [библиотека SY] (https://github.com/boris-s/sy), наряду с [физическими единицами] (https://github.com/masa16/phys-units), является лучшей физической единицей системы в Ruby. Поэтому я стараюсь вести себя ответственно.Методы физических единиц, такие как '1.metre',' 1.m', '1.s',' 1.lb', '1.K' и т. Д., Часто являются короткими словами, склонными к столкновениям методов. (Я просто отредактирую OP). –

+1

С точки зрения вашей реальной проблемы вы можете использовать 'method_added' и сообщать о столкновениях там. –

ответ

1

Использование method_added позволит вам предоставить предупреждение в вашем реальном мире.

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

    module ClassMethods 
    def method_added(method_name) 
     if method_name == :my_magic 
     puts 'So sorry you did not like my code, it will not bother you now' 
     end 
    end 
    end 
end 


class Something 
    include MethodAdded 

    def my_magic 
    'I can create this method without worries.' 
    end 
end 

Вот пример маловероятного риска распространения, что я методы класса упоминается в комментариях.

module ClassMethods 
  def self.extended(base) 
    puts 'I am going to do all sorts of evil stuff now' 
  end 
end 

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

  module ClaszMethods #Intentional typo to demonstrate "risk" 
  end 
end 
+0

Да, это определенно помогите поймать определения методов, идущих _after_ в 'SY' включает, это еще одна моя головная боль, что, если пользователь требует' ActiveSupport' или что-то еще _after_ 'require 'sy'' ... –

+0

Небольшой вопрос: это полностью безопасно сказать 'base.extend (ClassMethods)'? Разве бесполезно говорить «base.extend (MethodAdded :: ClassMethods)»? –

+0

Единственный риск, о котором я могу думать, это если вы не определяете 'ClassMethods' в своем модуле, тогда он будет использовать' :: ClassMethods', если он существует, что может вызвать проблемы. См. Редактирование для примера. На самом деле это не риск, о котором я беспокоюсь. –

Смежные вопросы