2015-04-22 14 views
5

này thực hiện của tôi để phát triển cách để chạy mã trước khi tất cả các phương pháp trong mô hình của bạngọi trước khi phương pháp trong mô hình trên ruby ​​

Cuộc gọi "before_hook: months_used" phương pháp cần phải được trên dưới cùng của lớp học để các ExecutionHooks có thể nhận được instance_method được tải trong module. Tôi muốn tải các phương pháp dụ trên

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_used 
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 
+0

Bạn có nghĩa là bạn muốn gọi before_hook ở đầu lớp học của mình? –

+0

Có @FrederickCheung –

Trả lời

4

Bạn có thể thực hiện việc này với prepend. prepend giống như include ở chỗ nó thêm một mô-đun cho tổ tiên của lớp, tuy nhiên thay vì thêm nó sau lớp mà nó thêm vào trước đó. Điều này có nghĩa là nếu một phương thức tồn tại cả trong mô-đun được thêm trước và lớp thì thực hiện mô-đun được gọi trước (và nó có thể tùy chọn gọi super nếu nó muốn gọi lớp cơ sở).

này cho phép bạn viết một module móc như vậy:

module Hooks 
    def before(*method_names) 
    to_prepend = Module.new do 
     method_names.each do |name| 
     define_method(name) do |*args, &block| 
      puts "before #{name}" 
      super(*args,&block) 
     end 
     end 
    end 
    prepend to_prepend 
    end 
end 


class Example 
    extend Hooks 
    before :foo, :bar 

    def foo 
    puts "in foo" 
    end 
    def bar 
    puts "in bar" 
    end 
end 

Trong sử dụng thực tế có thể bạn sẽ muốn giấu module nơi nào đó để mỗi cuộc gọi đến before không tạo ra một mô-đun mới nhưng đó là chỉ là một chi tiết thực hiện

+0

cảm ơn. Tôi sẽ thử kiểm tra mã của bạn sau và repply một thông tin phản hồi –

+0

Nó hoạt động hoàn hảo và thực hiện tuyệt vời. –

+0

Umm .. Dường như không hoạt động đối với tôi. Đã thử trong 'irb' (Ruby-2.0.0-p247). Gọi 'Example.new.foo' chỉ in' trước foo' 'trong foo'. Tôi có làm điều gì sai? –

1

Thay vì xác định lại phương pháp này khi gọi before_hook, bạn có thể ghi đè lên method_added móc để thêm vào trước trước khi móc đến một phương pháp ngay sau khi nó đã được xác định của bạn. Bằng cách này, các cuộc gọi before_hook của bạn có thể thực sự được đặt ở đầu định nghĩa lớp.

1

@rathrio Đây là triển khai của tôi bằng cách sử dụng phương thức_đã được bạn nói. Cảm ơn

module ExecutionHooks 

def validation 
    p "works1" 
end 

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

module ClassMethods 

    attr_writer :hooked 

    def hooked 
    @hooked ||= [] 
    end 

    def method_added(method) 
    return if @hooks.nil? 
    return unless @hooks.include?(method) 
    m = self.instance_method(method) 
    unless hooked.include?(method) 
     hooked << method 
     define_method(method) do |*args, &block| 
     validation  
     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 
    end 

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

class BalanceChart < BalanceFind 
include ExecutionHooks 
before_hook :months_data, :months_used, :debits_amount, :test 

    def test 
    "test" 
    end 
end 
Các vấn đề liên quan