2011-08-25 22 views
5

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

module VerboseJob 
    def self.included(job_class) 
    class << job_class 
     alias_method :original_perform, :perform 
     def perform(*args) 
     JobLogger.verbose { original_perform(*args) } 
     end 
    end 
    end 
end 

class HelloJob 
    include VerboseJob 

    def self.perform(arg1, arg2) 
    puts "Job invoked with #{arg1} and #{arg2}" 
    end 
end 

मैं क्या करना चाहते हैं, HelloJob.perform वास्तव में VerboseJob.perform आह्वान करने के लिए के लिए (जो फिर एक ब्लॉक के अंदर मूल विधि कॉल) है। चूंकि यहां मॉड्यूल कक्षा के शीर्ष पर शामिल है, यह काम नहीं करता है, क्योंकि perform अभी तक परिभाषित नहीं है। अंत में include को स्थानांतरित करना काम करता है, लेकिन क्या ऐसा कोई तरीका है जो थोड़ा और क्षमा कर रहा है? मैं अपनी कक्षा परिभाषाओं के शीर्ष पर सभी शामिल मॉड्यूल रखना चाहता हूं।

मैं Module या Class पर कुछ विधि की तलाश में हूं, जब इसे पूरी तरह से लोड किया गया है, इसके बजाए रनटाइम द्वारा इसका अर्थ लिया गया है।

उत्तर

2

यहाँ यह करने का एक बल्कि राउंडअबाउट/hackish तरीका है कि मैं जब तक मूल विधि परिभाषित किया गया था आवरण विधि की परिभाषा टाल द्वारा के साथ आया है:

module A 
    def self.included(base) 
    base.class_eval do 
     def self.singleton_method_added(name) 
     @@ran||=false 
     if name==:perform && [email protected]@ran 
      @@ran=true 
      class<<self 
      alias_method :original_perform, :perform 
      def perform(*args) 
       puts "Hello" 
       original_perform(*args) 
      end 
      end 
     end 
     end 
    end 
    end 
end 

class B 
    include A 

    def self.perform 
    puts "Foobar" 
    end 
end 

B.perform 

संपादित करें:

d11wtq अधिक स्वच्छ के इस सरल:

module VerboseJob 
    module ClassMethods 
    def wrap_perform! 
     class << self 
     def perform_with_verbose(*args) 
      JobLogger.verbose { perform_without_verbose(*args) } 
     end 

     alias_method_chain :perform, :verbose \ 
      unless instance_method(:perform) == instance_method(:perform_with_verbose) 
     end 
    end 

    def singleton_method_added(name) 
     wrap_perform! if name == :perform 
    end 
    end 

    def self.included(job_class) 
    job_class.extend ClassMethods 
    job_class.wrap_perform! if job_class.respond_to?(:perform) 
    end 
end 
+0

क्यों नहीं है 'प्रदर्शन' को लपेटने के लिए 'method_added' का उपयोग न करें .. er .. जोड़ा गया? :) –

+2

मुझे यकीन नहीं है कि मुझे आपका अर्थ मिल गया है, क्या मैं ऐसा नहीं कर रहा हूं? –

+2

मैंने आपका जवाब लिया (इस http://pivotallabs.com/users/rolson/blog/articles/1162-redefine-a-method-from-a- मॉड्यूल-like-a-gentleman के साथ संयुक्त) और साथ आया अधिक संक्षिप्त https://gist.github.com/1170661 (यह कोई फर्क नहीं पड़ता कि 'शामिल' किया गया है)। अपने उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें। मैं वैसे भी इसे स्वीकार करूंगा :) – d11wtq

-1

यह मानते हुए कि आप अपनी कक्षाओं के सभी से पहले परिभाषित चाहते आप perform रन चाहते हैं, आप Kernel#at_exit उपयोग कर सकते हैं:

एक प्रोक वस्तु को ब्लॉक में कनवर्ट करता है (और इसलिए बिंदु कॉल की पर यह बांधता है) और निष्पादन जब कार्यक्रम बाहर निकलता है के लिए यह पंजीकृत करता है। यदि एकाधिक हैंडलर पंजीकृत हैं, तो उन्हें पंजीकरण के के विपरीत क्रम में निष्पादित किया जाता है।

def do_at_exit(str1) 
    at_exit { print str1 } 
    end 
    at_exit { puts "cruel world" } 
    do_at_exit("goodbye ") 
    exit 

पैदा करता है:

अलविदा क्रूर दुनिया

आप भी इस तरह के टेस्ट :: यूनिट या MiniTest के रूप में कैसे इकाई परीक्षण चौखटे, को देखने के लिए, देरी संभाल कर सकते हैं कार्यों का चल रहा है।

+0

मुझे यकीन नहीं है कि मैं समझता हूं कि यह मेरे प्रश्न से कैसे संबंधित है, जो एक मॉड्यूल के अंदर से कक्षा/उदाहरण विधि को "लपेटने" के बारे में है? – d11wtq

+0

@ d11wtq: मैं उस समस्या को हल करने की कोशिश कर रहा हूं जो आपके पास सबसे उचित तरीके से है। देखें [लक्ष्य का वर्णन करें, चरण नहीं] (http://catb.org/~esr/faqs/smart-questions.html#goal) –

संबंधित मुद्दे