0

在我正在处理的一个 Ruby 项目中,我将 ActiveRecord 风格的 MVC 功能添加到具有类似于以下混合架构的模型类中:

module Model

  # Classes that mixin this module gain ActiveRecord-style class methods
  # like Model.all, Model.first, Model.last et al.
  #
  # Throughout this module, @@database_bridge will contain a reference to a
  # database ORM bridge, that does the dirty implementation of these methods.

  def all
    # Implementation stuff here, using @@database_bridge as appropriate
  end

  def first
    ...
  end

  # et al

end


class ExampleModel

  extend Model

  # Model-specific implementation goes here...

end

调用e = ExampleModel.first会将ExampleModel数据库中的第一个分配给e.

我想@@database_bridge在运行时使用依赖注入进行设置,这样每个包含的类都extend Model使用相同的指定 ORM 对象。

我怎样才能做到这一点?

如果我可以编写某种辅助方法来按需设置该类变量,那就太好了。

4

2 回答 2

0

这不是答案,而是一个潜在的解决方案您可以调用class_variable_set一个模块,通过调用Module.class_variable_set.

因此,您可以在某个适当的命名空间中创建一个辅助方法,该方法调用Module.class_variable_set :@@class_var, "new value".

对于上面的示例,我的辅助函数如下所示:

def set_database_bridge(new_bridge)
  Model.class_variable_set :@@database_bridge, new_bridge
end

这种解决方案在辅助函数和 mixin 的实现之间产生了一定程度的耦合Model,好像 @@database_bridge 的名称要更改,辅助函数就会中断。

如果有人对更松散耦合/更封装的解决方案有想法(我们可能将辅助函数封装在Model某个地方),那就太棒了!

于 2013-07-13T14:26:19.563 回答
0

我找到了一个比以前更好的解决方案,它比我想象的要简单得多(d'oh!):通过self.在 mixin 模块中为方法添加前缀,该方法的公共接口 viaModule.method变得可用。

因此,我们只需使用语句向我们的模块添加一个 setter 。self.attribute_set

在上面的示例中,上述方法将产生以下代码:

module Model

  # Classes that mixin this module gain ActiveRecord-style class methods
  # like Model.all, Model.first, Model.last et al.
  #
  # Throughout this module, @@database_bridge will contain a reference to a
  # database ORM bridge, that does the dirty implementation of these methods.

  def all
    # Implementation stuff here, using @@database_bridge as appropriate
  end

  def first
    ...
  end

  def self.set_database_bridge(ref_to_new_bridge)
    @@database_bridge = ref_to_new_bridge
    ## any additional intialisation/sanitisation logic goes here
  end

  # et al

end


class ExampleModel

  extend Model

  # Model-specific implementation goes here...

end

调用Model.set_database_bridge将允许我们传入一个新的数据库桥

如果我们在辅助函数中实际上不需要任何初始化或清理逻辑,还有另一种更优雅的方法 -attr_accessorclass << selfblock中添加一个,因此:

module Model

  # ...

  class << self
    attr_accessor :database_bridge
  end

end

这样,我们就可以调用 Ruby 的标准setter 方法Model.database_bridge = the_new_bridge

甜的。

于 2013-07-13T14:55:52.107 回答