Generalnie nie jest dobrym pomysłem zdefiniowanie klasy jako "klasy A", ale potem "magiczne" sprawdzenie jej w module B. Jeśli chcesz odwołać się do klasy A jako B :: A, powinieneś zdefiniować ją za pomocą:
module B
class A
# contents
end
end
czyli
class B::A
# contents
end
przeciwnym razie ktoś, kto czyta kod będzie mylić. W tym przypadku nie uzyskuje się niczego w jasności, zwięzłości lub wygodzie, używając "sztuczek", więc prostszy kod jest lepszy. Tutaj jest lekcja: cechy metaprogramowania Ruby są świetne, ale nie ma potrzeby ich używać bezinteresownie. Używaj ich tylko wtedy, gdy naprawdę coś zyskujesz. W przeciwnym razie po prostu sprawisz, że twój kod będzie trudny do zrozumienia.
ALE, po przeczytaniu komentarza, wygląda na to, że istnieje naprawdę dobry powód, aby zrobić coś takiego w swoim przypadku. Sugeruję, że poniższe rozwiązanie byłoby jeszcze lepsze niż to, co sobie wyobrażasz:
m = Module.new
m.module_eval("class C; end")
m.constants
=> [:C]
m.const_get(:C)
=> #<Module:0xfd0da0>::C
Widzisz? Jeśli chcesz mieć "gwarantowaną unikalną" przestrzeń nazw, możesz użyć anonimowego modułu. Możesz przechowywać te moduły w haszach lub innych strukturach danych i wyciągnąć je z nich w razie potrzeby. To rozwiązuje problem, o którym wspomniałeś, że użytkownicy Twojej aplikacji dodadzą własne klasy i nie chcesz, aby imiona się kolidowały.
do jakiego końca? Dlaczego nie możesz po prostu użyć klasy A bezpośrednio?Czy możesz czerpać korzyści z jego modularyzacji? 'load' i' require' nie będą faktycznie ładować klasy do modułu, tylko ładują kod źródłowy, więc twoje klasy są zdefiniowane dokładnie tak, jak są w pliku. Nie wiesz, dlaczego chcesz to zrobić? – brad
@brad Ponieważ te pliki zewnętrzne mają być napisane przez użytkowników i mogą być nazwane arbitralnie. Jeśli zdefiniuję te klasy w głównym środowisku, zepsują przestrzeń nazw. – sawa
Uważaj na manipulowanie innymi obszarami nazw za pomocą 'ObjectSpace # each_object'. – Reactormonk