在Rails中,我们可以定义一个类,例如:
class Test < ActiveRecord::Base
before_initialize :method
end
,并且在调用Test.new
时,将在实例上调用method()
。我试图学习更多有关Ruby和类似的类方法的信息,但是我很难在普通的Ruby中实现它。
这是我到目前为止所拥有的:
class LameAR
def self.before_initialize(*args, &block)
# somehow store the symbols or block to be called on init
end
def new(*args)
## Call methods/blocks here
super(*args)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end
我正在尝试找出将块存储在self.before_initialize
中的位置。我最初尝试使用@before_init_methods
之类的实例变量,但是那时该实例变量在内存中不存在,因此无法存储或检索它。我不确定在类定义期间如何/在哪里存储这些块/过程/符号,以便稍后在new
内部调用。
我该如何实施? (无论是before_initialize
都是一个符号块/程序/符号列表,我现在都不会介意,只是试图理解这个概念)
答案 0 :(得分:3)
要获得全面的描述,您随时可以check the Rails source;毕竟,它本身是用“普通的Ruby”实现的。 (但是它可以处理很多边缘情况,因此对于快速浏览并不太好。)
快速版本是:
module MyCallbacks
def self.included(klass)
klass.extend(ClassMethods) # we don't have ActiveSupport::Concern either
end
module ClassMethods
def initialize_callbacks
@callbacks ||= []
end
def before_initialize(&block)
initialize_callbacks << block
end
end
def initialize(*)
self.class.initialize_callbacks.each do |callback|
instance_eval(&callback)
end
super
end
end
class Tester
include MyCallbacks
before_initialize { puts "hello world" }
end
Tester.new
留给读者:
:if
/ :unless
)...但是消除所有这些是[希望]使此实现更容易实现的方式。
答案 1 :(得分:2)
一种方法是覆盖Class#new
:
class LameAR
def self.before_initialize(*symbols_or_callables, &block)
@before_init_methods ||= []
@before_init_methods.concat(symbols_or_callables)
@before_init_methods << block if block
nil
end
def self.new(*args, &block)
obj = allocate
@before_init_methods.each do |symbol_or_callable|
if symbol_or_callable.is_a?(Symbol)
obj.public_send(symbol_or_callable)
else
symbol_or_callable.(obj)
end
end
obj.__send__(:initialize, *args, &block)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end