puts A.new.metaclass
puts B.new.metaclass[/code]
Problem wtedy jest taki, że putsy na końcu wypisują:
[code]AMetaClass
BMetaClass
BMetaClass
BMetaClass[/code]
Czyli same zmienne klasowe są dobrze ustawione, ale w przypadku gdy próbuję dostać się do nich przez metodę metaclass to jakoś dziwnie się nadpisują. Jeżeli zamienię definicje klas A i B miejscami to dwa ostatnie puts wypisują AMetaClass:|
Po paru godzinach walki z tym wiem już, kod z linijki -1- to powodował i jeżeli ją wywalę i odkomentuję -2- to wszystko będzie ok, ale czy mogłby mi ktoś wyjaśnić o co tutaj chodzi?;)
Hmm, ale u mnie A i B nie są w jednej hierarchii (chyba, że bieżemy pod uwagę też dziedziczenie z Object). Zmienna @@meta, w każdej z nich ma dobrą wartość ustawioną.
puts A.class_variable_get(:@@meta) # => AMetaClass
puts B.class_variable_get(:@@meta) # => BMetaClass
Metoda metaclass w wersji -1-, którą dodaję dynamicznie przez base.class_eval, zwraca w przypadku klasy A inną wartość niż ta, która na prawdę zapisana jest w tej klasie w @@meta.
Biorąc pod uwagę to co napisałeś o hierarchii dziedziczenia, czy dzieje się coś takiego, że tak na prawdę próbując pobrać wartość @@meta z Object, a że tam jej nie ma to szuka dalej i znajduje ją dopiero w klasie B?
Definitywnie nie spodziewałbym się takiego zachowania… Orientujesz się, z czego ono wynika? Przecież w procu dla class_eval użyliśmy def a nie define_method. Dlaczego więc @@meta z def miałby brać coś z jakiegoś innego kontekstu ?
rbx-2.0.0pre :002 > module MyModule
rbx-2.0.0pre :003?> def self.included(base)
rbx-2.0.0pre :004?> base.class_variable_set(:@@meta, rand)
rbx-2.0.0pre :005?> base.class_eval do
rbx-2.0.0pre :006 > def metaclass
rbx-2.0.0pre :007?> @@meta
rbx-2.0.0pre :008?> end
rbx-2.0.0pre :009?> end
rbx-2.0.0pre :010?> end
rbx-2.0.0pre :011?> end
=> #<Rubinius::CompiledMethod included file=(irb)>
rbx-2.0.0pre :012 > class A; include MyModule; end
=> A
rbx-2.0.0pre :013 > class B; include MyModule; end
=> B
rbx-2.0.0pre :014 > class C; include MyModule; end
=> C
rbx-2.0.0pre :015 > C.class_variable_get(:@@meta)
=> 0.6407884506400079
rbx-2.0.0pre :016 > B.class_variable_get(:@@meta)
=> 0.03229476647600815
rbx-2.0.0pre :017 > A.class_variable_get(:@@meta)
=> 0.16896995826723749
rbx-2.0.0pre :018 > A.new.metaclass
NameError: uninitialized class variable @@meta in module MyModule
from A#metaclass at (irb):7
from { } in Object#irb_binding at (irb):18
from Rubinius::BlockEnvironment#call_on_instance at kernel/common/block_environment.rb:72
Czyli próbuje wziąć @@meta widziane z modułu, które nie jest zdefiniowane. Ze stringiem z oczywistych powodów nie ma tego problemu.
Teraz tylko pytanie, dlaczego yarv ma takie domyślne zachowanie? Skąd się bierze to przypisanie pierwszej ustawionej wartości do @@meta?
Ja chyba wszedzie gdzie jest uzyte class_eval widzialem ze przekazywany jest string i wydaje mi sie to bardziej naturalne - wez stringa i evaluj gdziestam w jakims kontekscie.
A taka jeszcze:
[code]module MyModule
def self.included(base)
base.class_eval do
def metaclass
[
@@meta,
self.class.class_eval("@@meta"),
eval(self.class.class_variables[0].to_s),
self.class.class_eval(self.class.class_variables[0].to_s),
self.class.class_variable_get(:@@meta)
]
end
end
end
end
class A
include MyModule
@@meta = “A”
end
class B
include MyModule
@@meta =“B”
end
class C
include MyModule
@@meta =“C”
end
a = A.new
puts a.metaclass #C #A #C #A #A[/code]
Jesli uzyje stringa to dostaje same A. Nie mam okazji ostatnio duzo w Ruby robic, a jak juz to i tak nie zaglebiam sie w takie rzeczy, wiec jesli ten post jest w stylu Captain Obvious to sorki