2011-08-21 12 views
9

Attualmente ho una superclasse che ha una funzione che voglio che tutta la sottoclasse chiami all'interno di ciascuna sua funzione. Si suppone che la funzione si comporti come una funzione before_filter in rail, ma non sono sicuro su come implementare before_filter. Ecco un esempioCome posso intercettare la chiamata al metodo in ruby?

class Superclass 
    def before_each_method 
    puts "Before Method" #this is supposed to be invoked by each extending class' method 
    end 
end 

class Subclass < Superclass 
    def my_method 
    #when this method is called, before_each_method method is supposed to get invoked 
    end 
end 
+0

possibile duplicato del [codice di esecuzione per ogni chiamata di metodo in un modulo Rubino] (http://stackoverflow.com/questions/5513558/executing-code-for-every-method-call-in-a- ruby-module) –

+0

IMHO è una situazione diversa e una domanda molto bella. – lucapette

+0

http://stackoverflow.com/questions/29785454/call-before-methods-in-model-on-ruby/29837450#29837450 la soluzione di Federico –

risposta

10

Questo è un modo per farlo:

class Superclass 
    def before_each_method name 
    p [:before_method, name] 
    end 

    def self.method_added name 
    return if @__last_methods_added && @__last_methods_added.include?(name) 
    with = :"#{name}_with_before_each_method" 
    without = :"#{name}_without_before_each_method" 
    @__last_methods_added = [name, with, without] 
    define_method with do |*args, &block| 
     before_each_method name 
     send without, *args, &block 
    end 
    alias_method without, name 
    alias_method name, with 
    @__last_methods_added = nil 
    end 
end 

class SubclassA < Superclass 
    def my_new_method 
    p :my_new_method 
    end 

    def my_new_other_method 
    p :my_new_other_method 
    end 
end 

SubclassA.new.my_new_method 
SubclassA.new.my_new_other_method 

questo creerà un metodo involucro utilizzando il metodo alias_method_chaining non appena il metodo che si desidera avvolgere è definito in la sottoclasse.

4

Questa è la mia soluzione:

require 'active_support/all' 

module BeforeEach 
    extend ActiveSupport::Concern 

    module InstanceMethods 
    def before_each 
     raise NotImplementedError('Please define before_each method') 
    end 
    end 

    module ClassMethods 
    def method_added(method) 
     method = method.to_s.gsub(/_with(out)?_before$/, '') 
     with_method, without_method = "#{method}_with_before", "#{method}_without_before" 

     return if method == 'before_each' or method_defined?(with_method) 

     define_method(with_method) do |*args, &block| 
     before_each 
     send(without_method, *args, &block) 
     end 
     alias_method_chain(method, :before) 
    end 
    end 
end 

Per utilizzarlo, è sufficiente includere BeforeEach nella tua classe in questo modo:

class Superclass 
    include BeforeEach 

    def before_each 
    puts "Before Method" #this is supposed to be invoked by each extending class' method 
    end 
end 

class Subclass < Superclass 
    def my_method 
    #when this method is called, before_each_method method is supposed to get invoked 
    end 
end 

Subclass.new.my_method 

# => Before Method 

Speriamo che questo funzionerà per voi!

0
class BalanceChart < BalanceFind 
include ExecutionHooks 

attr_reader :options 

def initialize(options = {}) 
@options = options 
@begin_at = @options[:begin_at] 
end 

def months_used 
range.map{|date| I18n.l date, format: :month_year}.uniq! 
end 

before_hook :months_data, :months_used, :debits_amount 
end 

module ExecutionHooks 

def self.included(base) 
base.send :extend, ClassMethods 
end 

module ClassMethods 

def before 
    @hooks.each do |name| 
    m = instance_method(name) 
    define_method(name) do |*args, &block| 

     return if @begin_at.blank? ## the code you can execute before methods 

     m.bind(self).(*args, &block) ## your old code in the method of the class 
    end 
    end 
end 

def before_hook(*method_name) 
    @hooks = method_name 
    before 
end 

def hooks 
    @hooks ||= [] 
end 
end 
end 
Problemi correlati