2016-10-12 14 views
15

Czy istnieje sposób sprawdzenia, czy obiekt ma klasę singleton bez tworzenia?Jak sprawdzić, czy obiekt ma klasę singleton (eigenclass) bez tworzenia?

Inne niż wymienione w Check if an object has a singleton class, nie jest prawdą, że każdy obiekt ma klasę singleton (patrz dowód pod https://repl.it/DuVJ/2).

następujących podejść przyszło mi do głowy, ale nie działa:

  1. obj.singleton_class

    To automatycznie tworzy nową klasę singleton, jeżeli żaden istnieje (patrz https://ruby-doc.org/core-1.9.2/Object.html#method-i-singleton_class).

  2. Korzystanie ObjectSpace:

    has_singleton_class = ObjectSpace.each_object(Class).any? do |klass| 
        klass < self.class && klass.singleton_class? && self.is_a?(klass) 
    end 
    

    ten jest bardzo powolny i nie może pracować pod JRuby jak ObjectSpace może nie być dostępne.

  3. obj.singleton_methods działa tylko wtedy, gdy klasa singleton ma co najmniej jedną metodę.

+2

Jaki problem starasz się rozwiązać? Jak napisał Jörg w połączonej odpowiedzi: "Ilekroć szukasz klasy singleton, będzie tam". Jaki jest twój przypadek użycia? –

+0

Pracujemy nad https: // github.com/rail/rails/pull/26771. Problem polega na tym, że dodajemy niezamierzone klasy za pomocą 'singleton_class', które przerywa niektóre testy Railsowe, które sprawdzają liczbę klas. Chcielibyśmy przejrzeć 'self.singleton_class' jeśli istnieje, i inaczej wywołać metodę na' self.class'. – Remo

+7

Moja ocena: "ObjectSpace" pozwala spojrzeć za kurtynę. Ale jeśli to zrobisz, możesz zobaczyć rzeczy, których nie powinieneś widzieć. Popieram moje stwierdzenie dotyczące połączonego pytania: klasy singleton zawsze istnieją. Tłumacz może ewentualnie * fizycznie * tworzyć je, gdy są potrzebne, ale za każdym razem, gdy patrzysz na * sprawdzić * czy istnieje, tam * będzie * być jednym. YARV, na przykład, zawsze tworzy klasy singleton dla modułów i klas, bez względu na to, czy są one potrzebne czy nie, i nigdy nie tworzy ich dla innych obiektów, chyba że faktycznie otworzysz je lub dodasz metodę singleton. –

Odpowiedz

0

Można użyć metody ancestors. Ponieważ chcesz sprawdzić, czy klasa (nie obiekt) jest pojedynczą, możesz pobrać wszystkie moduły wymieszane w klasie i sprawdzić, czy któraś z nich jest klasą singleton.

class Klass 
    include Singleton 
end 

Klass.ancestors.include? Singleton # true 

W Ruby, tworzenia singleton należy zawierać moduł Singleton. Jeśli więc sprawdzisz ten moduł, oznacza to, że ta klasa jest singletonem. Dziedziczenie klasy podstawowej Ruby w klasie modułu oznacza, że ​​masz dostęp do metody ancestors.

Odniesienia:

  1. https://ruby-doc.org/core-2.1.0/Module.html#method-i-ancestors
  2. https://ruby-doc.org/core-2.2.0/Class.html
  3. https://ruby-doc.org/stdlib-2.1.0/libdoc/singleton/rdoc/Singleton.html#module-Singleton-label-Usage
+0

Dzięki za odpowiedź. W przeciwieństwie do zdrowego rozsądku, kwestia ta nie dotyczy pojedynczego wzoru, ale zaawansowanej funkcji ruby ​​/ interny zwanej "Eigenclass", która niestety jest również nazywana "klasą Singleton". Jest to w zasadzie klasa, która istnieje tylko dla jednej instancji i może się różnić od "prawdziwej" klasy instancji. Podczas gdy twoja odpowiedź sama w sobie jest całkowicie poprawna, obawiam się, że nie jest ona związana z tematem, który ma pod ręką. – Remo

0

Sposób przodkowie zwraca uporządkowaną listę klas i modułów, która odpowiada sekwencji metodą wyszukiwania. Poniżej przykład instancji klasy CheckKlass klasy będzie szukać metod w CheckKlass, Object, Kernel i BasicObject przed wywołaniem A # method_missing.

class CheckKlass; end 
CheckKlass.ancestors # => [CheckKlass, Object, Kernel, BasicObject] 

A jeśli Singleton jest włączone to będzie wyglądać poniżej

class CheckKlass 
    include Singleton 
end 

To może dać =>

[CheckKlass, Singleton, ActiveSupport::ToJsonWithActiveSupportEncoder, Object, PP::ObjectMixin, ActiveSupport::Dependencies::Loadable, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Tryable, Kernel, BasicObject]