2013-01-16 17 views
7

के साथ गतिशील वर्ग परिभाषा तो मुझे यह स्थिति मिली है जहां मैं प्रोग्रामिंग के एक समूह को परिभाषित करना चाहता हूं। जिस विधि का मैं नीचे उपयोग कर रहा हूं, वह ठीक काम करता है, इस तथ्य को छोड़कर कि मैं यहां से प्राप्त तृतीय पक्ष वर्ग को इस तथ्य को पसंद नहीं करता कि कक्षा को गुमनाम रूप से परिभाषित किया गया है (मूल रूप से, इसमें इसकी जानकारी नहीं है, यानी क्लास नाम, 'विरासत में' हुक में, मुझे अज्ञात वर्ग को निरंतर सेट करने का मौका मिलने से पहले)।ब्लॉक

['one', 'two', 'three'].each do |model| 
    cls = Class.new(ThirdPartyClass) do 
     define_method :model do 
      model 
     end 
    end 
    ThirdPartyClass.const_set(model.capitalize, cls) 
end 

मैं बस एक eval का उपयोग करें और जैसे वर्ग कुछ निर्धारित कर सकते हैं:

['one', 'two', 'three'].each do |model| 
    eval "class ThirdPartyClass::#{model.capitalize} < ThirdPartyClass; ...; end" 
end 

लेकिन मैं इसे पसंद नहीं है क्योंकि तब यह गंदा स्ट्रिंग प्रक्षेप है। ब्लॉक आधारित विधि 'nicer', सौंदर्यशास्त्र बोलने लगता है।

क्या कोई तरीका है कि मैं उस वर्ग को गैर-गुमनाम रूप से परिभाषित कर सकता हूं (यानी एक नाम से सीधे नाम से) ब्लॉक-आधारित सिंटैक्स का उपयोग करके, या क्या मैं eval के गन्दा स्ट्रिंग इनपुट की भूमि में रहने के लिए बर्बाद हूं?

+0

यह अजीब बात है कि आप कक्षा को उसी स्थान के उप-वर्ग के नाम के भीतर होना चाहते हैं। – sawa

+0

सच है, लेकिन नेमस्पेस चीज इस विशेष समस्या के लिए ऑर्थोगोनल है (कम से कम मुझे ऐसा लगता है)। यदि आप उत्सुक हैं, तो मैं classy_enum मणि का उपयोग कर रहा हूं, और उस मणि के सम्मेलन के द्वारा, enum मान मुख्य enum वर्ग के नामस्थान के भीतर होना चाहिए। यह कुछ भाषाओं के समान कुछ enum वाक्यविन्यास पैदा करता है। – elsurudo

उत्तर

0

Class#inherited क्लास बनने पर कॉलबैक लागू हो जाता है। अज्ञात वर्ग को तुरंत चालू करते समय, कक्षा हमेशा स्थिर होने के लिए, इसे एक नाम असाइन करने से पहले यह हमेशा होगा। मैं इस के आसपास काम करने के लिए कोई रास्ता नहीं देख सकता। आप को कम कर सकते हैं, विशेष कक्षा वाक्यविन्यास का उपयोग करके रिक्त वर्ग बनाने के लिए eval का उपयोग करके eval का उपयोग करके eval का उपयोग करके inherited से पहले नाम दिखाई देता है, फिर अपनी विधियों को परिभाषित करने के लिए ब्लॉक फॉर्म में class_eval के साथ अनुवर्ती करें।

class Super 
    def self.inherited(child) 
    puts "#{self.name} inherited by #{child.inspect} named '#{child.name}'" 
    end 
end 

# Your way, inherited can't see name 
['one', 'two', 'three'].each do |model| 
    klassname = model.capitalize 
    klass = Class.new(Super) do 
    puts "defining #{model} inheriting from Super" 
    define_method :model do 
     model 
    end 
    end 
    Super.const_set(klassname, klass) 
end 

# this way inherited sees name because we use special class definition syntax in minimal string eval 
['four', 'five', 'six'].each do |model| 
    klassname = model.capitalize 

    eval %Q{ 
    class Super::#{klassname} < Super 
     puts %Q[defining Super::#{klassname} inheriting from Super] 
    end 
    } 

    Super.const_get(klassname).class_eval do 
    puts "defining methods for Super::#{klassname} inheriting from Super" 
    define_method :model do 
     model 
    end 
    end 
end 

# produces: 
Super inherited by #<Class:0x0000010084c988> named '' 
defining one inheriting from Super 
Super inherited by #<Class:0x0000010084c640> named '' 
defining two inheriting from Super 
Super inherited by #<Class:0x0000010084c320> named '' 
defining three inheriting from Super 
Super inherited by Super::Four named 'Super::Four' 
defining Super::Four inheriting from Super 
defining methods for Super::Four inheriting from Super 
Super inherited by Super::Five named 'Super::Five' 
defining Super::Five inheriting from Super 
defining methods for Super::Five inheriting from Super 
Super inherited by Super::Six named 'Super::Six' 
defining Super::Six inheriting from Super 
defining methods for Super::Six inheriting from Super 
+0

धन्यवाद, यह एक सभ्य-पर्याप्त कामकाज है। – elsurudo