我正在尝试编写一个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
答案 0 :(得分: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