2

我正在尝试编写一个 DSL 来包装 Mongoid 的聚合管道(即 Mongo DB)。

我制作了一个模块,当包含该模块时,它添加了一个接受块的类方法,它将请求传递给 Mongoid 的对象(通过缺少方法)。

所以我可以这样做:

class Project
  include MongoidAggregationHelper
end

result = Project.pipeline do
  match dept_id: 1
end

#...works!

“match”是Mongoid的聚合管道上的一个方法,被拦截并传递。

但是在块外设置的实例变量不可用,因为它是在代理类的上下文中执行的。

dept_id = 1

result = Project.pipeline do
  match dept_id: dept_id
end

#...fails, dept_id not found :(

有什么方法可以在块中传递/重新定义外部实例变量?

以下是修剪后的代码:

module MongoidAggregationHelper
  def self.included base
    base.extend ClassMethods
  end

  module ClassMethods
    def pipeline &block
      p = Pipeline.new self
      p.instance_eval &block
      return p.execute
    end
  end

  class Pipeline
    attr_accessor :cmds, :mongoid_class
    def initialize klass
      self.mongoid_class = klass
    end

    def method_missing name, opts={}
      #...proxy to mongoid...
    end

    def execute
      #...execute pipeline, return the results...
    end
  end
end
4

1 回答 1

2

您可以执行以下操作:(无限数量的参数,有点必须使用哈希)

# definition
def pipeline(*args, &block)
  # your logic here
end

# usage
dept_id = 1
result = Project.pipeline(dept_id: dept_id) do
  match dept_id: dept_id
end

或者您可以使用命名参数,如果您知道执行 DSL 需要多少个参数:

# definition
def pipeline(dept_id, needed_variable, default_variable = false, &block)
  # your logic here
end

# usage
dept_id = 1
result = Project.pipeline(dept_id, other_variable) do
  match dept_id: dept_id
end
于 2013-10-22T14:23:22.803 回答