Pytanie Jak określić, które moduły zostały połączone w jedną klasę?


Mam klasy, która ma wiele modułów, które są mieszane z nim na podstawie niektórych kryteriów środowiska wykonawczego.

Chcę uzyskać listę modułów, które zostały wymieszane z tą klasą. Jak możesz to robić?

AKTUALIZACJA

Więc kiedy powiedziałem, że klasa mam na myśli obiekt, ponieważ jest to obiekt, który jest rozszerzany w czasie wykonywania przy użyciu:

obj.extend(MyModule)

obj.included_modules i obj.ancestors nie istnieją, więc nie możesz pobrać modułów, które zostały zmiksowane.


33
2017-08-25 12:46


pochodzenie




Odpowiedzi:


Próbować:

MyClass.ancestors.select {|o| o.class == Module }

na przykład:

>> Array.ancestors.select {|o| o.class == Module}
=> [Enumerable, Kernel]

AKTUALIZACJA

Aby zmodyfikowad moduły w instancję obiektu w czasie wykonywania, musisz pobrać kolejną instancję instancji. Nie ma prostego sposobu na zrobienie tego w Ruby, ale dość rozsądnym idiomem jest:

(class << obj; self; end).included_modules

Jeśli często używasz tego, możesz go ogólnie udostępnić:

module Kernel
  def eigenclass
    class << self
      self
    end
  end
end

a rozwiązaniem jest:

obj.eigenclass.included_modules

39
2017-08-25 12:52



Istnieje gotowa metoda, zwana included_modules. - Swanand
Więc tam jest. Dzięki za wskazówkę. - Daniel Lucraft
Okazuje się, że skoczyłem z pistoletu. Podniosłem pytanie z kilkoma dodatkowymi szczegółami. - Derek Ekins
Czytelnicy zauważają, że ta odpowiedź pochodzi z 2009 roku. Wprowadzono Ruby 1.9 Object#singleton_class, która jest identyczna jak łatka małpy Kernel#eigenclass wdrożenie powyżej. - Gabe Martin-Dempesy


To może być lepszy pomysł:

MyClass.included_modules
irb(main):001:0> Array.included_modules
=> [Enumerable, Kernel]

39
2017-08-25 13:22





Jeśli szukasz całej listy, Odpowiedź Swananda to twój najlepszy zakład.

Jeśli, z drugiej strony, chcesz sprawdzić, czy klasa zawiera szczególny moduł, < operator jest twoim przyjacielem:

module Foo
end

class Bar
  include Foo
end

Bar < Foo
# => true

21
2017-08-25 15:56





obj.singleton_class.included_modules

A jeśli chcesz sprawdzić, czy moduł zawiera:

obj.singleton_class.include? MyModule

19
2017-07-18 20:05



AFAIK, jest to zdecydowanie preferowany sposób na przetestowanie tego. - xiy


Oto kolejny skuteczny sposób sprawdzenia, czy moduł został w zestawie lub rozszerzony przez klasę.

Jak wspomnieli inni, możesz określić, czy moduł jest dołączony do klasy, zaznaczając opcję included_modules metoda klasy, która istnieje we wszystkich klasach ruby.

Więc jeśli masz klasę o nazwie MyClass i chciałeś to zobaczyć w zestawie  Comparable moduł możesz zrobić coś takiego:

# will return true if MyClass.include(Comparable)
MyClass.included_modules.include?(Comparable)

Jeśli chcesz określić, czy twoja klasa ma rozszerzony  ActiveRecord::Querying moduł, tak jak robią to wszystkie klasy modeli szyn, możesz to wykorzystać:

# will return true if MyClass.extend(ActiveRecord::Querying)
MyClass.kind_of?(ActiveRecord::Querying)

Dlaczego to działa? Zacytować książkę Eloquent Ruby, autor: Russ Olsen:

Kiedy miksujesz moduł w klasę, Ruby rewiresuje nieco hierarchię klas, wstawiając moduł jako rodzaj pseudo-nadklasy klasy.

Oznacza to również inny sposób ustalenia, czy moduł został w zestawie do twojej klasy jest zrobienie czegoś takiego (chociaż nadal wolę included_modules metoda):

# will also return true if MyClass.include(Comparable)
MyClass.new.kind_of?(Comparable)

6
2017-10-16 15:05





Tylko klasy mogą opisywać metody, a kiedy dodajesz metodę do instancji, dodajesz ją do metaclassu obiektów. Moduł, którego szukasz, znajduje się na tej liście przodków metaclasu.

module TestModule; end

obj = "test"
obj.extend(TestModule)

class Object
  def metaclass
    class << self; self; end
  end
end

obj.metaclass.ancestors
# => [TestModule, String, Comparable, Object, Kernel, BasicObject]

3
2017-08-25 16:30





Lubię rozwiązanie AlexParamonova, ale bawiłem się i odkryłem, że działa to równie dobrze:

obj.class.include? MyModule

MyClass.include? MyModule

http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-include-3F


2
2018-03-21 10:38



Chyba że zmodyfikowałeś obiekt singleton. Na przykład: a = []; a.extend(MyAwesomeModule). W tym przypadku a.class.included_modules nie obejmuje MyAwesomeModule, ale a.singleton_class.included_modules będzie - AlexParamonov