2011-07-05 10 views
22

में नामित कक्षाओं को गतिशील रूप से परिभाषित करें मैं रूबी में एक आंतरिक डीएसएल लिख रहा हूं। इसके लिए, मुझे प्रोग्रामेटिक रूप से नामित कक्षाएं और नेस्टेड कक्षाएं बनाने की आवश्यकता है। ऐसा करने का सबसे अच्छा तरीका क्या है? मैं टोह वहाँ ऐसा करने के दो तरीके हैं कि:रुबी

  1. उपयोग Class.new, एक गुमनाम वर्ग बनाने के लिए तो यह करने के तरीकों को जोड़ने के लिए define_method उपयोग करते हैं, और अंत में उन्हें कुछ नाम स्थान के लिए नामित स्थिरांक के रूप में जोड़ने के लिए const_set कहते हैं।
  2. की eval

मैं पहली बार जिस तरह से परीक्षण किया है किसी प्रकार का उपयोग करें और यह काम किया, लेकिन रूबी के लिए नया किया जा रहा है, मुझे यकीन है कि स्थिरांक के रूप में कक्षाएं लगाने सही तरीका है नहीं कर रहा हूँ।

क्या अन्य, बेहतर तरीके हैं? यदि नहीं, तो उपरोक्त में से कौन सा बेहतर है?

+0

'eval' जिससे बचना है। http://stackoverflow.com/questions/637421/is-eval-supposed-to-be-nasty –

उत्तर

20

आप एक गतिशील नाम के साथ एक वर्ग का निर्माण करना चाहते हैं, तो आप लगभग ठीक है कि तुम क्या कहा करना होगा। हालांकि, आपको define_method का उपयोग करने की आवश्यकता नहीं है। आप बस ब्लॉक को Class.new पर पास कर सकते हैं जिसमें आप कक्षा आरंभ करते हैं। यह class/end की सामग्रियों के समान रूप से समान है।

उस क्षेत्र में रिसीवर (self) के ईमानदार होने के लिए const_set के साथ याद रखें। यदि आप विश्व स्तर पर परिभाषित कक्षा चाहते हैं तो आपको टॉपलेवल मॉड्यूल पर const_set पर कॉल करना होगा (जो रुबी द्वारा नाम और विवरण में भिन्न होता है)।

a_new_class = Class.new(Object) do 
    attr_accessor :x 

    def initialize(x) 
    print #{self.class} initialized with #{x}" 
    @x = x 
    end 
end 

SomeModule.const_set("ClassName", a_new_class) 

c = ClassName.new(10) 

... 
+1

मुझे यह भी उल्लेख करना चाहिए कि कक्षा के नाम मूल रूप से स्थिर हैं। उन्हें मॉड्यूल के स्थिरांक के रूप में परिभाषित किया गया है, जिनमें वे शामिल हैं। –

+3

क्या आप शीर्ष-स्तरीय मॉड्यूल के नाम के बारे में अधिक विशिष्ट हो सकते हैं? –

4

आपको वास्तव में const_set का उपयोग करने की आवश्यकता नहीं है। Class.new का वापसी मूल्य पर स्थिरांक और Class.new का ब्लॉक class_eval है।

class Ancestor; end 
SomeClass = Class.new(Ancestor) do 
    def initialize(var) 
    print "#{self.class} initialized with #{var}" 
    end 
end 
=> SomeClass 
SomeClass.new("foo") 
# SomeClass initialized with foo=> #<SomeClass:0x668b68> 
+3

यह गतिशील नाम वाला वर्ग नहीं बनाता है। कुछ क्लास स्थिर रूप से निर्धारित है। –

+0

वास्तव में नहीं। जब किसी वर्ग के लिए कक्षा का उपयोग किया जा रहा है तो निरंतर नाम घटाया जाएगा। https://gist.github.com/1064909 – Julik

+2

आपके उदाहरण में, आप अपनी नई कक्षा को "SomeClass" में परिभाषित कर रहे हैं। उदाहरण जो आपने अभी चिपकाया है, वह आपके बयान के विपरीत है कि "आपको वास्तव में const_set का उपयोग करने की आवश्यकता नहीं है"। मॉड्यूल निरंतर कुछ करने के लिए आपको इसका उपयोग करने की आवश्यकता है। –

3

होना चाहिए की तरह इस

a_new_class = Class.new(Object) do 

attr_accessor :x 

def initialize(x) 
    @x = x 
end 
end 

SomeModule = Module.new 
SomeModule.const_set("ClassName", a_new_class) 

c = SomeModule::ClassName.new(10)