2011-08-21 11 views
9

Actualmente tengo una superclase que tiene una función que quiero que todas las subclases invoquen dentro de cada una de sus funciones. Se supone que la función se comporta como una función before_filter en los rieles, pero no estoy seguro de cómo implementar el before_filter. Este es un ejemplo¿Cómo puedo interceptar la llamada al método en 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

posible duplicado de [código que se ejecuta para cada llamada a un método en un módulo de Ruby] (http://stackoverflow.com/questions/5513558/executing-code-for-every-method-call-in-a- ruby-module) –

+0

En mi humilde opinión, es una situación diferente y una muy buena pregunta. – lucapette

+0

http://stackoverflow.com/questions/29785454/call-before-methods-in-model-on-ruby/29837450#29837450 la solución de Frederick –

Respuesta

10

Ésta es una manera de hacerlo:

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 

Esto creará un método de envoltura utilizando el método alias_method_chaining tan pronto como el método desea envolver se define en la subclase.

4

Esta es mi solución:

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 

Para usarlo, basta con incluir BeforeEach en su clase, así:

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 

espero que esto funcione para usted!

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 
Cuestiones relacionadas