2011-12-29 3 views
1

런타임의 일부 Lisp 마술에서 영감을 얻은 소스 코드 편집루비에서 소스 코드 텍스트를 얻는 방법은 무엇입니까?

나는 루비에서하고 싶다. 소스 코드를 메서드/클래스에서 가져올 수없는 것처럼 보입니다. 할 방법이 있습니까?

def helloworld n 
    "hello #{n}" 
end 

o = Kernel.method :helloword 

Kernel.define_singleton_method o.name do |n| 
    eval o.source_code.sub('hello', 'hello world') 
end 

helloworld 'halida' #=> 'hello world halida' 
+0

에 유래에 비슷한 질문을 볼 수 http://stackoverflow.com/questions/4740684/ruby-get-source-code 또는 http://stackoverflow.com/questions/3393096/how - 소스 코드 - 메서드 - 동적 - 및 - 파일 -이 - m 또는 http://stackoverflow.com/questions/4719649/ruby-print-source를 참조하십시오. -code 또는 http://stackoverflow.com/questions/1164903/find-the-source-of-eval-code ... – mliebelt

답변

0

당신은, 코드의 일부의 문자열 표현을 얻을 편집 루비 변경 사항을 재평가 할 것으로 예상 할 수 없습니다

는 여기 샘플 소스 코드를 작성합니다. 당신이 원하는 것에 가깝게 뭔가를하는 유일한 방법은 ParseTree을 사용하여 소스의 s- 표현식을 얻고 편집하고 Ruby2Ruby을 사용하여 루비 코드 문자열을 생성하는 것입니다. 그 (것)들은 def ...end를 끈에 추가하고 그것으로 eval를 부른다.

실제 상황에서는 유용하기가 너무 어렵고 오류가 발생하기 쉽습니다. 그러나 나는 다른 어떤 방법을 모른다.

참고 : ParseTree는 Ruby 1.8에서만 작동합니다.

+0

좋아,이 종류의 마법을 던지기 위해 리스프를 사용합니다 .. – linjunhalida

+0

당신은 절대적으로 소스 코드의 문자열 표현. 클래스 메쏘드에는'.method.source'를, 인스턴스 메쏘드에는'.instance_method.source'를 사용하십시오. 문자열을 편집하고 다시 적용하려면 클래스를 열어 메서드를 재정의하고 새 문자열에'eval'을 사용하면됩니다. –

+0

'class_eval'과'instance_eval'도 참고하십시오. –

0

method_source 보석을 살펴보십시오. 그것은 pry REPL에 의해 show-method 명령에 사용됩니다.

이 보석은 표준 Method#source_location (Ruby 1.9에서 사용 가능)을 사용하여 메소드를 찾고 소스 코드를 가져옵니다. 분명히 동적으로 정의 된 메소드와 C 메소드에서는 작동하지 않습니다. 자세한 내용은 docs를 참조하십시오.

0

Ruby에서 메소드의 소스 코드를 쉽게 얻을 수 있습니다.

다음과 같은 가상 클래스 상상 :

class Klass 
    def self.foo 
    :foo 
    end 

    def bar 
    :bar 
    end 
end 

을 당신이 볼 수 있듯이,이 클래스는 두 가지 방법이 있습니다

  • 클래스 메소드 .foo
  • 인스턴스 메서드 #bar

.method.instance_method을 사용하여 프로그램에 액세스하십시오. matically :

m1 = Klass.method :foo 
=> #<Method: Klass.foo> 

m2 = Klass.instance_method :bar 
=> #<UnboundMethod: Klass#bar> 

당신은 자신의 소스 코드를 볼 수 .source 방법을 사용할 수 있습니다 :

puts m1.source 
    def self.foo 
    :foo 
    end 
=> nil 

puts m2.source 
    def self.bar 
    :bar 
    end 
=> nil 

을 루비가 열려 클래스와 동적 로딩을 가지고 있기 때문에, 당신은 또한 추가하거나 런타임에 변경 방법 할 수 있습니다. 그냥 클래스를 다시 열고 방법을 재정의 : 이전 클래스에 정의

Klass.foo 
=> :foo 

class Klass 
    def self.foo 
    :foobar 
    end 
end 

Klass.foo 
=> :footer 

다른 방법은 영향을받지 않습니다 :

Klass.bar 
=> :bar 

경고 : 런타임시 재정의 클래스 동작을 (또한 "라는 Monkey Patching ") 은 매우 강력한 도구이며 다소 위험 할 수도 있습니다. Ruby 의 최신 버전은 '정교화'라고하는 훨씬 더 제어 된 방식을 지원합니다.

당신은 learn more about using refinements here

관련 문제