2011-11-29 3 views
4

이것은 Sinatra의 라우트 메소드 처리와 관련된 이전 질문에 초점을 맞춘 버전입니다.Sinatra가 경로의 메소드 블록을 복사하는 이유는 무엇입니까?

시나가 경로 내에서 메소드 블록 소요 소스 코드에 대한 이해에서

, 같은 몸 밖으로 즉 포함하는 새로운 방법을 전달합니다

get "some/url" do 
    return "Hello World" # this gets taken out 
end 

그래서이 예에서 메소드 본문을 카피 한 것을 Sinatra 객체에 적용되는 새로운 메서드로 변환합니다. 나는 왜 이런 일이 일어 났는지 궁금해서 IRC 채널을 시도했지만 아무도 없었고 메일 링리스트는 그다지 바빴다.

def generate_method(method_name, &block) 
    define_method(method_name, &block) 
    method = instance_method method_name 
    remove_method method_name 
    method 
    end 

그래서 그들은 이렇게 그냥 참조하지 왜 어떤 특별한 이유가 :

내가 그들의 프레임 워크에 대해 이야기하고 소스 코드의 주요 벌크 선 1180 주위에 base.rb 내 방법 자체?

내가이 질문을하는 이유는 Sinatra가 현재이 방법을 처리하기 때문에 외부의 지식을 가진 메서드를 가질 수 없으며 문맥없이 단일 메서드를 사용하여 클래스 캡슐화를 해제하기 때문입니다.

답변

4

위의 설명에 따라 메소드를 생성합니다. 적절한 방법. Sinatra가 generate_method에서 다시 메서드를 제거하지 않으면 실제로 send("GET some/url")과 같은 작업을 수행하여 호출 할 수 있습니다. 문제는 Sinatra가이 방법을 다시 제거하는 이유는 무엇입니까? 간단합니다. 경로 당 하나 이상의 핸들러가있을 수 있습니다.

get 'some/route' do 
    pass if request.referrer == '/foo' 
    "didn't come from /foo" 
end 

get 'some/route' do 
    "did come from /foo" 
end 

두 메소드 모두 같은 이름입니다.

서브 클래스 및 방법에 대한 의견에 관해서는,이 작동합니다 :

class MyApp < Sinatra::Base 
    def content 
    return "did come from /foo" if request.referrer == '/foo' 
    "didn't come from /foo" 
    end 

    get('some/route') { content } 
end 

을 고전적인 응용 프로그램을 수행 할 때 또는 :

helper do 
    def content 
    return "did come from /foo" if request.referrer == '/foo' 
    "didn't come from /foo" 
    end 
end 

get('some/route') { content } 
+0

나는이 질문에 대한 대답이 명확 해 졌다고 생각하는데, 그것은 익명의 방법이 아니라 일류 방법이라는 오해였다. 그것은 여전히 ​​* 실제 * 문제는 도움이되지 않지만 그것은 다른 질문 내에 있습니다. – Grofit

+0

방금 ​​들었던 한 가지 ... 마지막 예제에서 익명 메소드의 범위를 벗어나는 것에 액세스하는 방법을 보여줍니다. 이는 ** IS ** 내 문제이지만 외모를 보일 때 유일한 방법은 헬퍼에 추가하거나 세트를 사용하는 것입니다. 이것은 메소드 블록이 실제로 필요한 모든 것을 수행하는 작은 것들에 유용 할 것입니다. 그러나 다른 클래스와 인스턴스에 의존성이있을 때 범위에 들어가기 위해 거의 모든 것을 도우미에 추가하는 것처럼 보입니다. 내가 가진 주된 문제를 표시하는 질문은 KL-7에 대한 의견 중 하나입니다. – Grofit

+0

모듈 식 응용 프로그램을 조사해야합니다. –

3

내 생각 엔 모든 경로에 대해 (다른 인스턴스 및 클래스 메서드에 액세스 할 수있는) 본격적인 방법을 원하지만 네임 스페이스를 오염시키지 않으려 고합니다. 메소드 이름은 "#{verb} #{path}"으로 생성됩니다. 예를 들어, 동일한 경로 충돌에 대해 여러 조건을 가진 여러 경로가있는 경우 정의하고 다른 곳에서 저장 한 후에 메소드를 제거하지 않으면 충돌이 불가피합니다. 그리고 그것이 바로 그들이하는 일입니다. 메서드는 바인딩되지 않지만 나중에 클래스의 인스턴스에 바인딩 할 수 있으므로 문제가되지 않습니다.

참고, 단지 추측입니다. 저는 Sinatra에 익숙하지 않으므로이 구현은 완전히 다른 생각을 가질 수 있습니다.

+0

어쩌면 올바르게 이해하지 못했을 수도 있지만 방법 키를 가리키는 경로 목록을 가질 수 없습니까? 그 메소드 키는 새로 생성 된 메소드가 아니라 ACTUAL 메소드를 참조합니다. 이는 동일한 방법으로 여러 경로를 갖는 기준을 충족시킵니다. 나는 이것이 내게있어 훌륭한 프레임 워크/라이브러리 인 것처럼 보이는 것에 대해 거의 끔찍한 문제라고 생각한다. 정적/전역 객체를 실제로 사용할 수 있기 때문에 이러한 메서드 내에서 비즈니스 로직을 수행하는 것은 거의 불가능하므로 모든 객체 지향 작업이 거의 중단됩니다. – Grofit

+0

'실제'방법을 어떻게 의미합니까? sinatra에서 경로를 정의 할 때 경로 문자열, 일부 옵션 및 마지막으로 블록을'get' 메소드에 전달합니다. 이 시점에서이 특정 경로에 대한 방법은 없습니다. 액션은'generate_method' 내에서 발생합니다. 여기서는 'GET /'과 같이 꽤 못생긴 이름을 가진 새로운 메소드가 생성되어 일부 배열에 다른 옵션과 함께 저장됩니다. 이 질문에서 '방법 본문'과 '복사 방법'으로 참조하는 것은 실제로 '블록 본문'과 '블록을 메서드로 변환'입니다. –

+0

Btw, 어떻게 OO를 사용하지 못하게합니까? –

0

을 내가 그냥 루비에게보다 오래된 지원하기 위해 instance_exec을 시뮬레이션 추측 1.8.7

관련 문제