2011-08-21 11 views
9

Obecnie mam nadklasę, która ma funkcję, którą chcę wywołać w podklasie każdej z jego funkcji. Ta funkcja powinna zachowywać się jak funkcja before_filter w szynach, ale nie jestem pewien, jak wdrożyć before_filter. Oto przykładJak mogę przechwycić wywołanie metody w 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

możliwe duplikat [kod wykonywany dla każdego wywołania metody w module Ruby] (http://stackoverflow.com/questions/5513558/executing-code-for-every-method-call-in-a- ruby-module) –

+0

IMHO to inna sytuacja i bardzo miłe pytanie. – lucapette

+0

http://stackoverflow.com/questions/29785454/call-before-methods-in-model-on-ruby/29837450#29837450 rozwiązanie Fredericka –

Odpowiedz

10

Jest to jeden ze sposobów, aby to zrobić:

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 

To stworzy metodę otoki jak najszybciej metody chcesz zawinąć definiuje się przy użyciu metody alias_method_chaining podklasa.

4

To jest moje rozwiązanie:

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 

Aby go użyć, po prostu to BeforeEach do klasy tak:

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 

Mam nadzieję, że to będzie pracować dla Ciebie!

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