2010-06-27 11 views
9

में विरासत में गतिशील रूप से परिवर्तन कैसे करें मैं रूबी में कक्षा के लिए मूल रूप से मूल कक्षा निर्दिष्ट करना चाहता हूं। इस कोड पर विचार करें:रुबी

class Agent 
    def self.hook_up(calling_class, desired_parent_class) 
    # Do some magic here 
    end 
end 

class Parent 
    def bar 
    puts "bar" 
    end 
end 

class Child 
    def foo 
    puts "foo" 
    end 

    Agent.hook_up(self, Parent) 
end 

Child.new.bar 

न तो Parent है और न ही Child वर्ग परिभाषा एक माता पिता के वर्ग निर्दिष्ट करता है, तो वे दोनों वस्तु से विरासत। मेरा पहला सवाल यह है कि Child के सुपरक्लास बनाने के लिए Agent.hook_up में मुझे क्या करना होगा (उदाहरण के लिए Child ऑब्जेक्ट्स 'बार' विधि का उत्तराधिकारी हो सकता है)।

मेरी दूसरी सवाल यह है: मैं की जरूरत है करतेAgent.hook_up को पहला तर्क पारित करने के लिए, या वहाँ hook_up विधि प्रोग्राम के रूप में वर्ग जिसमें से यह कहा जाता था निर्धारित कर सकते हैं किसी तरह है?

+2

उम, यदि आप गतिशील रूप से कक्षा के अभिभावक को बदल रहे हैं या बदल रहे हैं तो यह एक उचित दावा है कि आपका ऑब्जेक्ट मॉडल सत्य * एक * रिश्ते को प्रतिबिंबित नहीं करता है। एक अधिक उपयुक्त समाधान शायद संरचना है। – cletus

+1

आपको यह स्पष्ट करना चाहिए कि यह एक विचार अभ्यास है, या आप अभ्यास में इसका उपयोग क्यों करना चाहते हैं। गतिशील प्रतिबिंबित भाषाओं का मतलब यह नहीं है कि यह गतिशील रूप से विरासत को बदलने के लिए साफ है। महान (अभिव्यक्तिपूर्ण) शक्ति के साथ, बड़ी ज़िम्मेदारी आता है :) –

+0

@cletus मैं सामान्य रूप से विरासत का बड़ा प्रशंसक नहीं हूं लेकिन समस्या के लिए मैं वर्तमान में देख रहा हूं, विरासत और एक रिश्ता रिश्ते का पूरी तरह से वर्णन करता है। एकमात्र समस्या यह है कि एक वस्तु को पता नहीं चलेगा कि रन टाइम तक यह 'क्या है'। –

उत्तर

6

यहोशू पहले से ही आप विकल्प की एक महान सूची दी है, लेकिन अपने सवाल का जवाब देने एजेंट के लिए कोई जरूरत नहीं है: आप कर सकते हैं कक्षा के निर्माण के बाद कक्षा के सुपरक्लास को बदल नहीं दिया गया है। यह बस संभव नहीं है।

+6

चुनौती स्वीकार की गई! – Borromakot

22

शायद आप इस

Child = Class.new Parent do 
    def foo 
    "foo" 
    end 
end 

Child.ancestors # => [Child, Parent, Object, Kernel] 
Child.new.bar  # => "bar" 
Child.new.foo  # => "foo" 

लिए देख रहे हैं के बाद से माता-पिता Class.new लिए एक तर्क है, तो आप इसे अन्य वर्गों के साथ बाहर स्वैप कर सकते हैं।

मैंने कुछ प्रकार के परीक्षण लिखने से पहले इस तकनीक का उपयोग किया है। लेकिन मुझे ऐसी चीज करने के लिए कई अच्छे बहाने के बारे में सोचने में कठिनाई है।


मुझे संदेह है कि आप वास्तव में क्या चाहते हैं एक मॉड्यूल है।

class Agent 
    def self.hook_up(calling_class, desired_parent_class) 
    calling_class.send :include , desired_parent_class 
    end 
end 

module Parent 
    def bar 
    "bar" 
    end 
end 

class Child 
    def foo 
    "foo" 
    end 

    Agent.hook_up(self, Parent) 
end 

Child.ancestors # => [Child, Parent, Object, Kernel] 
Child.new.bar  # => "bar" 
Child.new.foo  # => "foo" 

हालांकि, ज़ाहिर है, वहाँ सब पर

module Parent 
    def bar 
    "bar" 
    end 
end 

class Child 
    def foo 
    "foo" 
    end 

    include Parent 
end 

Child.ancestors # => [Child, Parent, Object, Kernel] 
Child.new.bar  # => "bar" 
Child.new.foo  # => "foo" 
+0

धन्यवाद यहोशू। चूंकि ऐसा प्रतीत होता है कि मैं रनटाइम पर विरासत श्रृंखला नहीं बदल सकता, मैं शायद अपने समाधान में अपने पहले विकल्प के कुछ बदलाव का उपयोग कर समाप्त कर दूंगा। मैं आपके द्वारा जवाब देने के समय की सराहना करता हूं। –

+0

एक और चीज जिसे आप देख सकते हैं, यदि यह _really_ है जो आप करना चाहते हैं, तो रायन डेविस द्वारा लिखित change_class है। यहां वह वीडियो है जहां वह 5:00 बजे कोड प्रस्तुत करता है http://rubyconf2008.confreaks.com/evil-code.html यहां प्रोजेक्ट का होम पेज है। http://seattlerb.rubyforge.org/change_class/ अस्वीकरण पर ध्यान दें "हां, यह खतरनाक है ... अगर आपका कंप्यूटर आग लगता है तो मुझे रोना न करें।" –

3

जैसा कि पहले से बताया गया है, आपको शायद मॉड्यूल में देखना चाहिए या गतिशील रूप से कक्षाएं बनाना चाहिए। हालांकि, आप superclass बदलने के लिए evil-ruby का उपयोग कर सकते हैं। fork for Ruby 1.9 भी उपलब्ध है। यह केवल एमआरआई के लिए काम करता है। रूबिनीस पर निर्माण करना आसान होना चाहिए (समाशोधन विधियों के कैश मुख्य मुद्दे होंगे), जेआरबी के बारे में कोई संकेत नहीं। (-> सुपर बजाय 1.8 समान है, लेकिन RCLASS (स्वयं का उपयोग))

require 'inline' 
class Class 
    inline do |builder| 

     builder.c %{    
      VALUE set_super(VALUE sup) { 
       RCLASS(self)->ptr->super = sup; 
       return sup; 
      } 
     } 

     builder.c %{ 
      VALUE get_super() { 
       return RCLASS(self)->ptr->super; 
      } 
     } 

    end 


J = Class.new 
J.set_super(Class.new) 
+0

मुझे लगता है कि 'बुराई' का उपयोग शायद उत्पादन कोड में फेंक दिया जाएगा :-) गतिशील रूप से कक्षा बनाना संभवतः समाधान है जिसका उपयोग मैं समाप्त कर दूंगा। धन्यवाद! –

4

रूबी 1.9 केवल: यहाँ कोड है , बशर्ते कि यह पर्याप्त है कि ऑब्जेक्ट जैसे वर्ग वर्ग वास्तव में के आधार पर बेस क्लास बेस क्लास का उदाहरण हो।इस

class MyClass < inherit_orm("Adapter") 
    end 

पर

require 'delegate' 

class Agent < SimpleDelegator 
    def baz 
    puts "baz" 
    end 
end 

class BarParent 
    def bar 
    puts "bar" 
    end 
end 

class FooParent 
    def foo 
    puts "foo" 
    end 
end 

agent = Agent.new(FooParent.new) 
agent.baz # => baz 
agent.foo # => foo 
agent.__setobj__(BarParent.new) 
agent.baz # => baz 
agent.bar # => bar 
0

रूबी के SimpleDelegator वर्ग (delegate पुस्तकालय में) में मदद कर सकते हैं:

require 'evil' 

class Agent 
    def self.hook_up(calling_class, desired_parent_class) 
    calling_class.superclass = desired_parent_class 
    end 
end 

class Parent 
    def bar 
    puts "bar" 
    end 
end 

class Child 
    def foo 
    puts "foo" 
    end 

    Agent.hook_up(self, Parent) 
end 

Child.new.bar 
0

देखो और वर्ग चयनकर्ता:

def inherit_orm(model="Activity", orm=nil) 
    orm = Config.orm || orm 
    require "orm/#{orm.to_s}" 
    "ORM::#{orm.to_s.classify}::#{model}".constantize 
    end 

तो, जब उदाहरण MyClass यह orm और model के आधार पर एक गतिशील वर्ग से विरासत की जाएगी। मॉड्यूल में दोनों को परिभाषित करना सुनिश्चित करें। यह public_activity मणि (selector example) में ठीक काम करता है।

मुझे मदद करने की उम्मीद है .. अलविदा!