2010-07-07 14 views
5

मेरा पहला विचार इस तरह की कुछ बात कर रहे हैं:मैं उप वर्ग में किसी विधि के पहले और बाद में कोड कैसे चला सकता हूं?

class AbstractBuilder 
    attr_reader :time_taken 

    def build_with_timer 
    started_at = Time.now 
    build 
    @time_taken = Time.now - started_at 
    end 

    def build 
    raise 'Implement this method in a subclass' 
    end 
end 

class MyBuilder < AbstractBuilder 
    def build 
    sleep(5) 
    end 
end 

builder = MyBuilder.new.build_with_timer 
puts builder.time_taken 

मुझे लगता होगा वहाँ एक बेहतर तरीका है, जो बेहतर लचीलापन प्रदान करता है, उदाहरण के लिए आदर्श मैं बजाय MyBuilder का एक उदाहरण पर 'निर्माण' कॉल करना चाहते है 'build_with_timer' और हमेशा निष्पादन समय दर्ज किया गया है।

मैंने कक्षा उत्तराधिकारी के बजाय मॉड्यूल मिक्स्डिन को प्रारंभ करने या यहां तक ​​कि यहां तक ​​कि alias_method का उपयोग करने पर विचार किया था जो मध्य में सुपर कॉल करने वाली बिल्ड विधि को ओवरराइड करेगा (सुनिश्चित नहीं है कि यह काम करेगा)। खरगोश छेद नीचे जाने से पहले मैंने सोचा कि मैं देखता हूं कि एक स्थापित अभ्यास है या नहीं।

+0

स्पष्टीकरण के लिए मैं एक ज्ञात नाम की एक विधि को परिभाषित करना चाहता हूं, जो उप-वर्ग में पारदर्शी रूप से लपेटा गया है (पहले और बाद में) बेस क्लास में परिभाषित कोड के साथ। ActiveRecord फ़िल्टर कहने से मुझे कम लचीलापन/ओवरहेड चाहिए। – Kris

+0

https://github.com/PragTob/after_do – Kris

उत्तर

2

मैं alias_method के साथ खेलते हैं:

module Timeable 
    def time_methods *meths 
    meths.each do |meth| 
     alias_method "old_#{meth}", meth 

     define_method meth do |*args| 
     started_at = Time.now 
     res = send "old_#{meth}", *args 
     puts "Execution took %f seconds" % (Time.now - started_at) 
     res 
     end 
    end 
    end 

end 

class Foo 
    def bar str 
    puts str 
    end 
end 

Foo.extend Timeable 
Foo.time_methods :bar 
Foo.new.bar('asd') 
#=>asd 
#=>Execution took 0.000050 seconds 
+0

ऐसा लगता है कि यह काम कर सकता है, मैं समय-समय पर कॉल करना नहीं चाहता क्योंकि मेरे मामले में सबक्लास में एक और एक ही विधि है, हमेशा उसी नाम से, जिसे मैं चारों ओर कोड लपेटना चाहता हूं। मैं बेस क्लास में प्रारंभ करने से alias_method और define_method का उपयोग करने का प्रयास करूंगा। यह माना जा रहा है कि प्रारंभिक होने पर subclass में विधियां मौजूद हैं?! – Kris

+0

आपने मुझे वहां खो दिया है। यह मदद करेगा यदि आप वर्णन करेंगे कि आप किस वास्तविक समस्या को हल करने की कोशिश कर रहे हैं। शुरुआत के लिए, क्या आपके पास अभिभावक वर्ग का नियंत्रण है? क्या आप 'build_with_timer' विधि बदल सकते हैं या नहीं? –

+0

हां मैं दोनों वर्गों को नियंत्रित करता हूं, उप-वर्गों में 'बिल्ड' नामक एक विधि होने का एक सम्मेलन होगा, जिसे विधि के पहले और बाद में चलने वाले बेस क्लास में निर्दिष्ट कोड के साथ बुलाया जाता है, पहले/बाद कोड हमेशा होगा वही। उम्मीद है कि समझ में आता है। – Kris

0

लगता है जैसे आप ऑब्जेक्ट लाइफसाइकिल घटनाओं में हुक की तलाश में हैं। आपको इसे अपनी मूल वस्तु में बनाना होगा और थोड़ा डीएसएल प्रदान करना होगा - मुझे लगता है कि आप ActiveRecord Callbacks जैसे कुछ के बाद हैं। यहाँ कैसे हम ऐसा ही कुछ अनुमति देने के लिए अपने उदाहरण में बदलाव आ सकते हैं:

class AbstractBuilder 
    attr_reader :time_taken 

    def construct! # i.e., build, and also call your hooks 
    @@prebuild.each { |sym| self.send(sym) } 
    build 
    @@postbuild.each { |sym| self.send(sym) } 
    end 

    def construct_with_timer 
    started_at = Time.now 
    construct! 
    @time_taken = Time.now - started_at 

    puts "!!! Build time: #@time_taken" 
    end 

    class << self 
    def before_build(fn); @@prebuild ||= []; @@prebuild << fn; end 
    def after_build(fn); @@postbuild ||= []; @@postbuild << fn; end 
    end 
end 

class MyBuilder < AbstractBuilder 
    before_build :preprocess 
    after_build :postprocess 

    def build; puts "BUILDING"; sleep(3); end 
    def preprocess; puts "Preparing to build..."; end 
    def postprocess; puts "Done building. Thank you for waiting."; end 
end 

builder = MyBuilder.new 
builder.construct_with_timer 

# => Preparing to build... 
# => BUILDING 
# => Done building. Thank you for waiting. 
# => !!! Build time: 3.000119 
+0

हां और नहीं, मैं फिल्टर के पहले/बाद में (या आसपास) की अवधारणा चाहता हूं लेकिन केवल एक ही नाम होने वाला है, हमेशा एक ही नाम के साथ, मुझे चाहिए लपेटने के लिए, और यह हमेशा एक ही कोड में लपेटा जाएगा। तो मुझे इस तरह के एक कठिन कोडित संस्करण की जरूरत है। आपके उदाहरण से ऐसा लगता है कि मुझे कक्षा के स्तर पर कोड के पहले/बाद में स्टोर करने की आवश्यकता है, फिर ऑब्जेक्ट को तुरंत चालू करने के बाद इसे इंजेक्ट करें? – Kris

+0

दाएं - तर्क के पहले/बाद में बच्चे कक्षाओं को जल्दी से बनाने के लिए एक छोटी सी भाषा है। अधिक जटिल आवश्यकताओं के लिए, ध्यान दें कि रूबी स्वयं यहां कुछ आंतरिक कॉलबैक भी प्रदान करता है जो उपयोगी हैं। आप 'विरासत' और 'शामिल' नामक विधियों को लिख सकते हैं और कक्षा को विरासत में शामिल या शामिल होने पर इन्हें निकाल दिया जाएगा। –

4

मैं एक संस्करण में एक चाकू था प्राप्त करने के लिए आप क्या चाहते हैं। इस संस्करण में सबक्लास के पास कोई अतिरिक्त कोड होने की आवश्यकता नहीं है।

class AbstractBuilder 

    @@disable_override = false 

    def before_method 
    puts "before" 
    end 

    def after_method 
    puts "after" 
    end 

    def self.method_added name 
    unless @@disable_override 
     if name == :build 
     @@disable_override = true # to stop the new build method 
     self.send :alias_method, :sub_build, :build 
     self.send :remove_method, :build 
     self.send :define_method, :build do 
      before_method 
      sub_build 
      after_method 
     end 
     @@disable_override = false 
     else 
     puts "defining other method #{name}" 
     end 
    end 
    end 

end 

class MyBuilder < AbstractBuilder 

    def build 
    puts "starting build" 
    sleep(5) 
    puts "built." 
    end 

    def unnaffected_method 
    # this method won't get redefined 
    end 

end 

b = MyBuilder.new 
b.build 

आउटपुट

defining other method unnaffected_method 
before 
starting build 
built. 
after 
0

यह Aspect-Oriented Programming लिए एक पाठ्यपुस्तक परिभाषा उपयोग है। यह आमतौर पर चिंताओं का एक क्लीनर अलगाव प्रदान करता है। इस क्षेत्र में, रूबी Aquarium और AspectR प्रदान करता है। हालांकि, आप अपनी परियोजना में एक और निर्भरता नहीं जोड़ना चाहेंगे। इस प्रकार, आप अभी भी अन्य दृष्टिकोणों में से एक का उपयोग करने पर विचार कर सकते हैं।

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

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