我如何实现Rails之类的东西';在普通Ruby中初始化之前/新建之前?

我如何实现Rails之类的东西';在普通Ruby中初始化之前/新建之前?,ruby,Ruby,在Rails中,我们可以定义如下类: class Test < ActiveRecord::Base before_initialize :method end 在初始化之前,我试图找出在self.中存储块的位置。我最初尝试在_init_methods之前使用一个实例变量,如,但该实例变量当时不存在于内存中,因此我无法存储或检索它。我不确定在类定义期间如何/在何处存储这些块/过程/符号,稍后将在new中调用这些块/过程/符号 我如何实现这一点?(要么在初始化之前使用,获取一个块/pr

在Rails中,我们可以定义如下类:

class Test < ActiveRecord::Base
  before_initialize :method
end
在初始化之前,我试图找出在
self.中存储块的位置。我最初尝试在_init_methods
之前使用一个实例变量,如
,但该实例变量当时不存在于内存中,因此我无法存储或检索它。我不确定在类定义期间如何/在何处存储这些块/过程/符号,稍后将在
new
中调用这些块/过程/符号


我如何实现这一点?(要么在初始化之前使用
获取一个块/proc/符号列表,我不介意这一点,只是尝试理解这个概念)

对于全面的描述,您可以始终;毕竟,它本身是用“纯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
模块MyCallbacks
def包括在内(klass)
extend(ClassMethods)#我们也没有ActiveSupport::Concern
结束
模块类方法
def初始化\u回调
@回调| |=[]
结束
初始化前定义(&block)

初始化&u回调一种方法是重写
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
class-LameAR
初始化前定义自身(*符号或可调用项和块)
@在|init|方法之前|=[]
@before_init_methods.concat(符号或可调用项)

@在初始化方法之前,你的问题有点让人困惑。您所说的“像
@这样的实例方法先于\u init\u方法
”是什么意思
@before_init_methods
是一个实例变量,而不是一个方法。另外,您所说的“那个实例方法在那个时候不存在于内存中,所以我无法存储或检索它”是什么意思?实例方法一经定义就存在,实例变量一经第一次赋值就存在。事实上,一个实例变量正是解决您的问题的正确方法,所以我有点困惑您为什么如此反对它。@JörgWMittag我已经编辑了这个问题。我的意思是“实例变量”,而不是“实例方法”。实例变量在创建实例之前不存在,因此在类定义期间无法向其添加内容。您可以检查我的答案,该答案使用实例变量没有任何问题。这可以按照我的要求工作,谢谢!虽然我有一个问题,我觉得有些困惑,这就是这里的过程。如果我像这样创建一个proc
proc=proc.new{puts“Hi!”}
,那么我必须像
proc[]
proc.call()
那样调用它,但是当它在初始化之前通过
添加,然后在
self.new
中调用时,它可以像
proc.(obj)
一样调用。为什么会这样?它仍然是一个proc,但在这种情况下,它可以以通常无法的方式调用。我不理解你的问题<代码>过程。(
只是
proc.call()
的语法糖,就像
proc[]
proc的语法糖。[]
-a+b
a.-@().+(b)
的语法糖一样。请注意,这与procs无关。它只是语法上的糖,它不在乎接收者是什么。它只会导致发送
调用
消息,如果对象响应该消息,则可以,否则会得到
命名错误
。您所说的“以通常无法实现的方式调用”是什么意思?顺便说一句:此代码所做的(当然减去中间部分),也正是默认情况下
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