2012-02-22 23 views
9

Oluşturulacak olana kadar sınıfın adını bilmeden yeni bir sınıf oluşturmaya çalışıyorum.Dinamik bir sınıf oluşturma

Böyle bir şey; Mümkünse

variable = "ValidClassName" 

     class variable 

     end 

Test = ValidClassName.new 

, ben de dinamik olarak bu yeni sınıfa özelliklerini (ve yöntemler) ekleme hakkında som ipuçları takdir ediyorum.

derse 'ayarları' retreiving olacak ve onlar bu gibi bir şey olacaktır:

title :Person 
attribute :name, String 
attribute :age, Fixnum 

Ama sadece o açık dosyayı kabul edecek şekilde tasarlanmış olmaması gerektiğini, nitelikleri sayı sonunda farklı olabilir yazın.

class Person 
    def initialize(name, age) 

     @name_out = name 
     @age_out = age 
    end 

end 

Yardım:

sonunda hangi gibi görünmelidir bir sınıf oluşturur?

variable = "SomeClassName" 
klass = Class.new(ParentClass) 
# ...maybe evaluate some code in the context of the new, anonymous class 
klass.class_eval { } 
# ...or define some methods 
klass.send(:title, :Person) 
klass.send(:attribute, :name, String) 
# Finally, name that class! 
ParentClass.send(:const_set, variable, klass) 

... yoksa sadece eval kullanabilirsiniz:

+1

Sadece bir sınıf için kaynak kodu oluşturmak mı istiyorsunuz? ya da kaynağı üretmek ve çalışma zamanında sınıfı derlemek/yüklemek için Ruby'ye söylemek ister misiniz? – ardnew

+1

Merak etme, hangi problemi çözüyorsun? Bu dinamik olarak oluşturulmuş sınıfları kullanmayı nasıl planlıyorsunuz? – ctcherry

+0

Sınıfımın bir 'çerçeve' olarak hareket etmesi gerekiyor, bir kez de objetcs'i (sınıfın belirlediği talepleri karşıladıkları sürece) bir yaml dosyasından çıkarmak için kötü bir şekilde kullanıldı. YAML bir grup "insan" bulundurur ve bazılarının gereksinimleriyle eşleşen özniteliklere sahiptir. – BSG

cevap

23

A sınıfı bir sabit atanan adını kazanır. Yani const_set ile genel bir şekilde yapmak kolaydır. Örneğin

yapabilirsiniz, Diyelim ki bazı özelliklere sahip bir sınıf oluşturmak için Struct kullanmak istediğinizi varsayalım:

name = "Person" 
attributes = [:name, :age] 

klass = Object.const_set name, Struct.new(*attributes) 
# Now use klass or Person or const_get(name) to refer to your class: 
Person.new("John Doe", 42) # => #<struct Person name="John Doe", age=42> 

başka bir sınıftan devralmak için, yerine Class.new(MyBaseClass) tarafından Struct.new derler:

class MyBaseClass; end 

klass = Class.new(MyBaseClass) do 
    ATTRIBUTES = attributes 
    attr_accessor *ATTRIBUTES 
    def initialize(*args) 
    raise ArgumentError, "Too many arguments" if args.size > ATTRIBUTES.size 
    ATTRIBUTES.zip(args) do |attr, val| 
     send "#{attr}=", val 
    end 
    end 
end 
Object.const_set name, klass 
Person.new("John Doe", 42) # => #<Person:0x007f934a975830 @name="John Doe", @age=42> 
+0

Klass bildirilirken hata alıyorum ve ad sabit olmalı, bu yüzden Klass'ı 2, 3 satırda sermayeledim ve şimdi çalışıyor. – tebayoso

+0

Oh, doğru. Örnek değiştirildi. –

6

Kodunuz buna benzer bir şey olmazdı

eval <<DYNAMIC 
    class #{name} 
    title :Person 
    attribute :name, String 
    # ...or substitute other stuff in here. 
    end 
DYNAMIC 
+1

Özür dilerim, burada gerçekten derinlikten uzakım. Üç yaşındaymış gibi açıklamaya çalışabilir misiniz lütfen? : p – BSG

+1

Bunun çok daha kolay olduğundan emin değilim. İkinci durumun anlaşılması muhtemelen daha kolay: 'eval' bir dizgeyi alır ve * çağrı sırasında * Ruby kodu gibi değerlendirir. Bu nedenle, çalışma zamanında dinamik sınıfınızın kaynak koduna sahip bir dize oluşturun, ardından bunu değerlendirin. İlk durum yeni bir sınıf nesnesi oluşturur, istenen yöntemleri, vb. Oluşturmak için bir şeyler yapar ve ona bir isim verir - Ruby'de sınıf nesnesini bir sabite atamakla aynıdır. –