2013-04-14 5 views
7

라이브러리를 필요로하거나로드하는 Ruby 코드 내에서 라이브러리의 소스 코드에 액세스하는 데는 여러 가지 방법이 있습니다. 이러한 방법 중 일부는 라이브러리 파일을 직접 읽고 파싱합니다. 다른 일부는 소스 (예 : 추상 구문 트리)에 대한 정보를 제공하는 내장 된 메소드를 통해 소스에 액세스합니다. 필자가 파일의 내용을 직접 읽을 수있는 권한이없는 경우 (예 : 이전 방법) 소스에 액세스하는 유일한 방법은 정보를 제공하는 기본 제공 방법에 액세스하는 것입니다. 이 메소드를 재정의하여 다른 것을하기 때문에 나는 소스 코드에 대한 접근을 완전히 잃어 버릴 것이다. 최소의 메소드 세트는 무엇인가? 다시 정의하면, 외부 파일에있는 라이브러리의 소스 코드에 대한 액세스가 완전히 해제됩니다. 어떤 방법으로 소스 코드에 액세스 할 수 있습니까?


가정 해 질문을 바꿔하려면

  • 파일 A에 어떤 루비 코드를 작성할 수 있습니다 사용자가이를
  • 에 의해 작성된 정적 루비 파일 B가 나는 파일 A를로드하고 A에 정의 된 기본 루틴을 호출하며 사용자가 A에서 사용할 수있는 몇 가지 클래스/메소드를 정의합니다.
  • 사용자가 ha

어떤 표준 Ruby 메소드를 다시 정의 (무효화)해야하거나 불가능하게하기 위해 B 파일에 써서 제거해야합니까? 사용자가 파일 B에서 작성된 소스에 액세스하려면 (파일 A에서 사용자가 작성할 수있는 코드를 통해) 파일 B를 실행할 때?

액세스 할 수있는 메소드의 소스 코드를 추출 할 수있는 sorcerer, pry와 같은 라이브러리가 있습니다. 일반 Ruby에는 원시 코드에 액세스 할 수 있도록하기 위해 이러한 라이브러리가 의존하는 원시 명령어가 있어야합니다. 이런 종류의 일을 가능하게하는 방법은 무엇입니까?

전체 답변을 모르지만 특정 라이브러리가 특정 방법의 소스를 추출하는 방법을 알고 있다면 여전히 도움이됩니다.

+0

나는 어떤 추상 클래스 나 자바에서 인터페이스와 비슷한 것을 구현할 수 있다고 생각한다. 인터페이스는 외부 구성 요소에서 공개적으로 액세스합니다. 그런 다음 추상 클래스를 상속하여 내부적으로 구현할 수 있습니다. –

+0

그런 메소드를 재정의 할 때, 수정중인 원래 메소드의 "복사본"을 가지기 위해'Module # alias_method'를 사용할 수 있습니다. http://apidock.com/ruby/Module/alias_method – fmendez

+1

_system_, _backtick_, _fork/exec_ 등을 사용 중지해야합니다. –

답변

6

TL; DR은 : 그래서 그냥 다시 정의 루비 전용 솔루션 만, source_location를 사용할 수있는이 뭔가를 반환 ['/some/empty/file', 1]입니다. 통역사에 대한 C 해킹은 source_location을 사용하지 않지만 require 및 친구를 차단/화이트리스트로 차단하여 C 확장의 사용을 막을 수 있습니다. 하나


는, 루비 스크립트를 실행 할 수 있도록, 당신은 ... 그것을 읽을 수

을하지만 다시 질문. 나는 Sourcify가 Proc and Method에서 작은 메서드 외에 어떤 신비적인 메서드도 사용하지 않는다는 것을 알고있다. source_location은 파일 이름과 라인 번호를 제공하는 메소드/proc가 정의되었다. 나는이 접근법이 매우 약해서 일종의 파서를 작성해야한다는 것을 경험을 통해 알고 있으며 때로는 합법적 인 상황에서만 작동합니다. 따라서 B에서 source_location을 다시 정의하면 /dev/null, line 0과 같은 것을 반환하고 Sourcify가 Ruby가 아닌 예외를 throw하도록하면 Sourcify가 이미 종료되었습니다.

Pry의 source에서 Pry가 동일한 source_location 접근 방식을 사용하므로 한 돌로 두 마리의 조류가 사용 된 것으로 보입니다.

이제는 C로 드롭 다운하고 인터프리터를 해킹하여 소스 코드를 기록하는 또 다른 옵션이 있습니다. 이것은 거의 완벽합니다. 그러나 우리는 여전히 매우 간단한 방법으로 위험을 피할 수 있습니다. 누군가는 A에 Pry의 메소드 소스에 대한 모든 코드를 포함 할 수 있지만 C 라이브러리를 요구하지 않고 인라인 C/C 확장을 포함 할 수는 없습니다. 따라서 해결 방법은 확실합니다. requirerequire_relativeload을 재정의하거나 특정 라이브러리 만 허용하도록 다시 정의하십시오. 이렇게하면 C 해킹을 막을 수 있습니다.

MRI에서는 source_location 외에는 (Ruby 코드에서) 수행 할 방법이 없습니다. 그래서 거기에 간다!

편집 : @banister에 따르면 MRI 2.0+에서 소스 위치를 바꿀 수있는 binding_of_caller 메서드가 내장되어 있습니다. 핵무기도. ;)

경고 : Ruby는이 언어에 적합하지 않습니다. 메타 프로 그램을 할 수 있다면 다른 프로세스에 있지 않는 한 메타 프로 그램을 사용할 수 있습니다.

+0

감사합니다. 나는 그 지점에 대한 대답을 마침내 얻었다. 'source_location'을 무효화함으로써 AST (Abstract Syntax Tree)에 대한 액세스를 피할 수 있다고 생각합니까? – sawa

+2

@sawa 당신이하려고하는 것은 매우 이상합니다. 그러나 source_location을 망쳐 놓는 것만으로는 충분하지 않습니다. binding_of_caller와 Binding # eval ("__ FILE__") 등의 조합은 source_location과 거의 동일한 정보를 반환합니다. 충분한 영리를 가진 사람이라면 어떤 블록을 제자리에 놓을 수있을 것입니다. Ruby는 * 이런 종류의 언어가 아니라 * 시도해 보지 마십시오. – horseyguy

+0

@sawa : 내가 말할 수있는 것부터 C 확장자를 통해서만 AST에 액세스 할 수 있으며,이 확장은 Ruby 환경을 제어하지 않고로드하거나'require'를 사용하여로드 할 수 없습니다. – Linuxios

0

John Mair (Pry 제작자)가 만든 멋진 'method_source'보석을 사용하면 실제로 매우 쉽습니다. 이 메서드는 Ruby (C가 아님)에서 구현되어야하며 파일에서로드해야합니다 irb가 아니라).

$ rails console 
    > require 'method_source' 

    # the following prints out the method code for #lookup in the Rails I18n Backend: 

    > I18n::Backend::Simple.instance_method(:lookup).source.display 
    def lookup(locale, key, scope = [], options = {}) 
     init_translations unless initialized? 
     keys = I18n.normalize_keys(locale, key, scope, options[:separator]) 

     keys.inject(translations) do |result, _key| 
     _key = _key.to_sym 
     return nil unless result.is_a?(Hash) && result.has_key?(_key) 
     result = result[_key] 
     result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol) 
     result 
     end 
    end 
    => nil 

이미로드 된 파일에서 오는 요구에 표시되는 루비 코드, 는 (분명히가 있습니다

여기 method_source와 레일 콘솔의 방법 소스 코드를 표시하는 예제 읽을 수 있어야하며, 원시 루비 코드 여야합니다 (컴파일 된 라이브러리 나 링크 된 라이브러리에서는 작동하지 않습니다).

은 참조 :

관련 문제