2011-01-11 22 views
30

सहित किसी अन्य मॉड्यूल में रूबी मॉड्यूल का विस्तार करना जब भी मैं रूबी मॉड्यूल का विस्तार करने का प्रयास करता हूं, तो मैं मॉड्यूल विधियों को खो देता हूं। न तो इसमें शामिल हैं और न ही विस्तार करेंगे। स्निपेट पर विचार करें:मॉड्यूल विधियों

module A 
    def self.say_hi 
    puts "hi" 
    end 
end 

module B 
    include A 
end 

B.say_hi #undefined_method 

चाहे बी शामिल या विस्तार करता है, say_hi परिभाषित नहीं किया जाएगा।

क्या ऐसा कुछ करने का कोई तरीका है?

+1

क्या आप एक ठोस मामला प्रदान कर सकते हैं जहां आप यह करना चाहते हैं? मॉड्यूल विरासत वह है जो आप वास्तव में चाहते हैं, और यह विशेष रूप से और जानबूझकर रूबी में कक्षाओं के लिए समर्थित है। क्यों नहीं ए) हमेशा एक ही वस्तु में बी और ए शामिल करते हैं, या बी) बी सहित बी भी शामिल है? – Phrogz

+0

कारण मैं चाहता हूं कि यह थोड़ा जटिल हो। प्रश्न में मॉड्यूल का उपयोग डीएम टेबल और रिश्तों का वर्णन करने वाले एक्सएमएल दस्तावेज़ से बहुत सारे ActiveRecord :: बेस क्लास बनाने के लिए किया जाता है। मैं इसे कई अलग-अलग बार करने में सक्षम होना चाहता हूं। मॉड्यूल कोड प्रत्येक के लिए समान है, लेकिन नामस्थान और संबंधित कक्षाएं संघर्ष नहीं करती हैं, उन्हें अलग-अलग मॉड्यूल होने की आवश्यकता होती है। मैं हर बार मॉड्यूल को शामिल करने के लिए कक्षा को तुरंत चालू नहीं करना चाहता हूं, हर बार जब मैं ऐसा करता हूं, निर्णय लेता हूं और उदाहरण विधियों को शामिल करता हूं। –

उत्तर

9

मुझे नहीं लगता कि ऐसा करने का कोई आसान तरीका है। आप module A के लेखक हैं और इस जरूरत अक्सर जाएगा

class Module 
    def include_module_methods(mod) 
    mod.singleton_methods.each do |m| 
     (class << self; self; end).send :define_method, m, mod.method(m).to_proc 
    end 
    end 
end 

module B 
    include_module_methods A 
end 
+1

शानदार! यह मुझे हमेशा इस त्रुटि के आसपास काम करने के तरीके के बारे में जानने के लिए ले गया: 'टाइप एरर: सिंगलटन विधि एक अलग ऑब्जेक्ट के लिए बुलाया जाता है'। '# to_proc' ने इसे आसानी से हल किया। –

24

, आप:

module B 
    class << self 
    A.singleton_methods.each do |m| 
     define_method m, A.method(m).to_proc 
    end 
    end 
end 

आप इस प्रकार का सहायक विधि में रख सकते हैं:

तो यहाँ एक जटिल तरीका है फिर से लेखक कर सकते हैं एक तरह तो:

module A 
    module ClassMethods 
    def say_hi 
     puts "hi" 
    end 
    end 
    extend ClassMethods 
    def self.included(other) 
    other.extend(ClassMethods) 
    end 
end 

module B 
    include A 
end 

A.say_hi #=> "hi" 
B.say_hi #=> "hi" 
+0

मैंने कोशिश की, और यह मेरे मामले के लिए काम नहीं करता है। जैसा कि मैंने अपनी टिप्पणी में उल्लेख किया है (मुझे लगता है कि आपके उत्तर के बाद) इसका उद्देश्य एक ऐसे फ़ंक्शन का उपयोग करना है जो मॉड्यूल स्पेस के भीतर कक्षाओं को const_set और Class.new का उपयोग कर बनाता है ... लेकिन! अगर मैं इसे इस तरह से करता हूं और B.create_classes का आह्वान करता हूं, तो मुझे लगता है कि कक्षाएं बी में परिभाषित नहीं हैं, बल्कि ए में भी हैं। –

+0

@ जोनाथन मार्टिन आपको फिर से एक पुन: उत्पन्न परीक्षण मामले के साथ अपने प्रश्न को अपडेट करने की आवश्यकता होगी। हो सकता है कि ActiveRecord कुछ पागल जादू कर रहा है और अपनी जगहों को स्पैमिंग कर रहा है, लेकिन इसे सिर्फ काम करना चाहिए। – Phrogz

+0

यह अच्छा है। Thanx। –

3

उपयोग include_complete

gem install include_complete

module A 
    def self.say_hi 
    puts "hi" 
    end 
end 

module B 
    include_complete A 
end 

B.say_hi #=> "hi" 
+0

आपने कहा, कि आप मणि सी ext केवल रूबी 1.9.2 के साथ काम करता है। =) – puchu

+0

@ पचू ने राज्य को देखा, मैंने यह जवाब छोड़ा - 2011 – horseyguy

+0

जुलाई 16, 2015. और आपका मणि आज भी 2.2 और 2.3 रूबी के साथ काम नहीं कर रहा है। – puchu

2

Johnathan, मुझे यकीन है कि अगर आप अभी भी इस बारे में सोच रहे हैं नहीं कर रहा हूँ, लेकिन वहाँ माणिक में मॉड्यूल का उपयोग करने के दो अलग-अलग तरीके हैं। ए) आप सीधे अपने कोड में, या बी में अपने स्वयं निहित फॉर्म बेस :: Tree.entity (पैरा) में मॉड्यूल का उपयोग करते हैं।) आप मॉड्यूल का उपयोग मिश्रक या सहायक तरीके के रूप में करते हैं।

ए आपको मॉडल्स को नेमस्पेस पैटर्न के रूप में उपयोग करने की अनुमति देगा। यह बड़ी परियोजनाओं के लिए अच्छा है, जहां विधि नाम के लिए मौका

module Base 
    module Tree 
    def self.entity(params={},&block) 
     # some great code goes here 
    end 
    end 
end 

विरोध करता है अब आप बेस के लिए हर कॉल के लिए एक नया वर्ग का दृष्टांत के बिना इस का उपयोग अपने कोड में ट्री संरचना के कुछ प्रकार बनाने के लिए कर सकते हैं, वहाँ है :: Tree.entity।

नेमस्पेस-आईएनजी करने का एक और तरीका कक्षा के आधार पर कक्षा में है।

module Session 
    module Live 
    class Actor 
     attr_accessor :type, :uuid, :name, :status 
     def initialize(params={},&block) 
     # check params, insert init values for vars..etc 
     # save your callback as a class variable, and use it sometime later 
     @block = block 
     end 

     def hit_rock_bottom 
     end 

     def has_hit_rock_bottom? 
     end 

     ... 
    end 
end 
class Actor 
    attr_accessor :id,:scope,:callback 
    def initialize(params={},&block) 
    self.callback = block if block_given? 
    end 

    def respond 
    if self.callback.is_a? Proc 
     # do some real crazy things... 
    end 
    end 
end 
end 

अब हमारे पास कक्षाओं में ओवरलैप करने की क्षमता है। हम जानना चाहते हैं कि जब हम एक अभिनेता वर्ग बनाते हैं कि यह सही वर्ग है, तो यह वह जगह है जहां नामस्थान आसानी से आते हैं।

Session::Live::Actor.new(params) do |res|... 
Session::Actor.new(params) 

बी मिक्स-इन्स ये आपके मित्र हैं। जब भी आपको लगता है कि आपको अपने कोड में एक से अधिक बार करना होगा, तो उनका उपयोग करें।

module Friendly 
    module Formatter 
    def to_hash(xmlstring) 
     #parsing methods 
     return hash 
    end 

    def remove_trailing_whitespace(string,&block) 
     # remove trailing white space from that idiot who pasted from textmate 
    end 
    end 
end 

अब जब भी आप एक हैश के रूप में एक xmlstring प्रारूप, या अपने भविष्य के कोड में से किसी में खाली स्थान के अनुगामी हटाने, बस उससे मिश्रण की जरूरत है।

module Fun 
    class Ruby 
    include Friendly::Formatter 

    attr_accessor :string 

    def initialize(params={}) 
    end 

    end 
end 

अब आप में स्ट्रिंग स्वरूपित कर सकते हैं अपने कक्षा।

fun_ruby = Fun::Ruby.new(params) 
fun_ruby.string = "<xml><why><do>most</do><people></people><use>this</use><it>sucks</it></why></xml>" 
fun_ruby_hash = fun_ruby.to_hash(fun_ruby.string) 

आशा है कि यह एक अच्छा पर्याप्त स्पष्टीकरण है।उपरोक्त उठाए गए अंक कक्षाओं को बढ़ाने के तरीकों के अच्छे उदाहरण हैं, लेकिन मॉड्यूल के साथ, कठिन हिस्सा यह है कि स्वयं कीवर्ड का उपयोग कब करें। यह रूबी के ऑब्जेक्ट पदानुक्रम के भीतर वस्तु के दायरे को संदर्भित करता है। इसलिए यदि आप एक मॉड्यूल का मिश्रण मिश्रण के रूप में उपयोग करना चाहते हैं, और कुछ भी सिंगलटन घोषित नहीं करना चाहते हैं, तो स्वयं कीवर्ड का उपयोग न करें, हालांकि यदि आप ऑब्जेक्ट में स्थिति रखना चाहते हैं, तो बस एक वर्ग और मिश्रण- मॉड्यूल में आप चाहते हैं।

0

मुझे self.included का उपयोग करके सभी को पसंद नहीं है। मेरे पास सरल समाधान है:

module A 
    module ClassMethods 
    def a 
     'a1' 
    end 
    end 
    def a 
    'a2' 
    end 
end 

module B 
    include A 

    module ClassMethods 
    include A::ClassMethods 
    def b 
     'b1' 
    end 
    end 
    def b 
    'b2' 
    end 
end 

class C 
    include B 
    extend B::ClassMethods 
end 

class D < C; end 

puts D.a 
puts D.b 
puts D.new.a 
puts D.new.b 
संबंधित मुद्दे