在 ruby 上调用模型中的方法之前
call before methods in model on ruby
这是我在模型中的所有方法
之前开发 运行 代码的实现
调用"before_hook :months_used"方法需要在class底层调用ExecutionHooks才能获取模块中加载的instance_method。我想在顶部加载实例方法
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
在调用 before_hook
时,您可以重写 method_added
挂钩,以便在方法定义后立即将 before 挂钩添加到方法之前,而不是重新定义该方法。这样,您的 before_hook
调用可以(实际上,必须)放置在 class 定义的顶部。
您可以使用 prepend
执行此操作。 prepend
类似于 include
,因为它向 class 的祖先添加了一个模块,但是它不是在 class 之后添加它,而是在 [=17= 之前添加它。 ]
这意味着如果一个方法同时存在于前置模块和 class 中,那么首先调用模块实现(如果它想调用基础 super
,它可以选择调用 super
=25=]).
这允许您像这样编写一个 hooks 模块:
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
在实际使用中,您可能希望将该模块存储在某处,以便每次调用 before
都不会创建新模块,但这只是一个实现细节
@rathrio 这是我使用您所说的 method_added 实现的。谢谢
module ExecutionHooks
def validation
p "works1"
end
def self.included(base)
base.send :extend, ClassMethods
end
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
这是我在模型中的所有方法
之前开发 运行 代码的实现调用"before_hook :months_used"方法需要在class底层调用ExecutionHooks才能获取模块中加载的instance_method。我想在顶部加载实例方法
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
在调用 before_hook
时,您可以重写 method_added
挂钩,以便在方法定义后立即将 before 挂钩添加到方法之前,而不是重新定义该方法。这样,您的 before_hook
调用可以(实际上,必须)放置在 class 定义的顶部。
您可以使用 prepend
执行此操作。 prepend
类似于 include
,因为它向 class 的祖先添加了一个模块,但是它不是在 class 之后添加它,而是在 [=17= 之前添加它。 ]
这意味着如果一个方法同时存在于前置模块和 class 中,那么首先调用模块实现(如果它想调用基础 super
,它可以选择调用 super
=25=]).
这允许您像这样编写一个 hooks 模块:
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
在实际使用中,您可能希望将该模块存储在某处,以便每次调用 before
都不会创建新模块,但这只是一个实现细节
@rathrio 这是我使用您所说的 method_added 实现的。谢谢
module ExecutionHooks
def validation
p "works1"
end
def self.included(base)
base.send :extend, ClassMethods
end
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