2013-10-22 4 views
1

Mongoid의 집계 파이프 라인 (예 : Mongo DB)을 래핑하기 위해 DSL을 작성하려고합니다.인스턴스 eval을 기반으로 인스턴스 변수를 DSL로 전달

나는 모듈을 포함 시켰을 때 블록을 받아들이는 클래스 메소드를 추가했다. 블록 메소드는 몽고 이드에게 요청을 전달하는 객체에 전달한다.

그래서 내가 할 수있는 :

class Project 
    include MongoidAggregationHelper 
end 

result = Project.pipeline do 
    match dept_id: 1 
end 

#...works! 

은 "일치"차단되고 배포되는 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

''def pipeline (* args, & block)''및'Project.pipeline dept_id : dept_id do'을 사용해도 될까요? – MrYoshiji

+0

좋은 제안 @MyYoshiji, 생산 코드에서 그렇게하고 작동합니다. 그러나 옵션 해시로 변수를 전달하지 않아도되고 싶다면 이전에 선언 된 변수를 사용해야합니다. –

+0

대안으로 답변을 게시했습니다 – MrYoshiji

답변

1

당신은 다음을 수행 할 수 있습니다 : (좀, 인수의 무제한 해시를 사용해야합니다)

# 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 
+0

소원을 전달할 필요없이 원활하게 처리 할 수 ​​있지만 가능한 것은 아닙니다. –

관련 문제