2010-06-19 1 views
2

루비 애호가! 나는 루비에 DSL을 작성하려고 노력 중이다. 그리고 나는 어떤 마법 방법을 만들 수 있기를 바란다. (내가 원하는 것에 가장 정확한 용어인지는 모르겠다.)Ruby의 Magic Methods?

a = [1, 2, 3] 
b = 2 

(a contains b) 

을 그리고 그것은 true 또는 false로 해결이 :

나는 다음과 같은 일을 할 수 있도록하고 싶습니다.

기본적으로 "contains"함수를 정의하여 배열 a과 변수 b을 가져오고 a.contains?(b)을 수행하지만 관련된 모든 루비 고유 구문이 없어도됩니다. 내가 생각할 수

+2

사용이 :'a.include 다음으로

DSL.new do a = [1, 2, 3] b = 2 a contains b end 

: 당신은이 코드를 실행할 수 있습니다

? b' – Adrian

+0

그래, 이미 존재하는 방법을 사용하여 그렇게 쉽게 할 수있을 때 그 이점은 무엇입니까? –

답변

0

가장 가까운 일이 될 것이다 : 나는 생각하지 않는다

contains b, :in, a 


을 사용할 수있는 방법이있다 :

def contains var, useless_symbol, arr 
    arr.include? var 
end 

그런 다음 당신이 좋아하는 그것을 호출 할 수 있습니다 당신 자신의 함수에서 중위 표기법. 당신은 루비 구문을 사용하지 않는 DSL을 원하는 경우

+0

왜 쉼표를 생략 하시겠습니까? 그것은'contains b, : in, a' 일 것입니다. – horseyguy

+0

@banister : 당신 말이 맞아요, 지금 편집되었습니다. – bennybdbc

2

, 당신은 변환을 수행하기 위해 적어도 파서를 작성해야 (raganwalds는 LIB는 출발점이 될 수도, 다시 쓰기 http://github.com/raganwald/rewrite)는 상기

, 너는 이것을 원하지 않는다. 이것은 유지 보수하는 데 더 많은 코드이며 Ruby는 이미 언어 구문을 어렵게 만드는 많은 어려운 결정을 내 렸습니다. 프로그래머가 아닌 사람들도 형식의 정확성이 까다로운 편이기 때문에 자연 언어 프로그래밍이 훨씬 쉽지는 않습니다 (예를 들어 applescript 참조).

1

method_missing을 남용 할 수 있습니다. 까다로운 점은 블록 로컬 변수에 직접 액세스 할 수 없다는 것입니다. 어딘가에 내부 바인딩을 캡쳐해야합니다 (불행히도 block.binding은 블록의 외부 바인딩을 반환합니다).

class DSL 
    attr_reader :last_binding 

    def initialize(&block) 
    set_trace_func method(:trace).to_proc 
    instance_eval(&block) 
    set_trace_func nil 
    end 

    def trace(event, file, line, id, binding, klass) 
    if event.to_s == "call" and klass == self.class and id.to_s == "method_missing" 
     @last_binding ||= @current_binding 
     set_trace_func nil 
    else 
     @current_binding = binding 
    end 
    end 

    def lvars 
    eval('local_variables', last_binding).map(&:to_s) 
    end 

    def method_missing(name, *args) 
    name = name.to_s 
    if lvars.include? name 
     eval(name, last_binding).send(*args.flatten) 
    else 
     ["#{name}?", *args] 
    end 
    end 
end 

class Array 
    alias contains? include? 
end