H = , B = = ["HomePage", "w7.cgi?n=%s"]
c = CGI.new("html4")
n, d = (not (c["n"] == "")) ? (c["n"]) : (H), c["d"]
t = `\ncat #{n}`
((not (d == "")) and `echo #{t = CGI.escapeHTML(d)} >#{n}`)
c.instance_eval do
out do
(((h1 { n } + a((B % H)) { H }) + pre { t.gsub(/([A-Z]\w+){2}/) { a((B % $&)) { $& } } }) + form("get") { ((textarea("d") { t } + hidden("n", n)) + submit) })
end
end
ParseTree와 Ruby2Ruby를 이용해 또 어떤 재미있는 일을 할 수 있을까?
Forbidden Fruit: A Taste of Ruby's ParseTree
Goruko2008에 이와 관련된 재미있는 발표가 있으니 한번 확인해보자 . 아래는 루비 코드를 SQL로 바꿔주는 참신한 ORM인 Ambition을 공개한 Chris Wanstrath의 발표자료를 보자. 동영상도 공개되어 있다.
Ambition: 루비 Enumerable을 이용한 코드를 SQL, ActiveRecord 코드, LDAP 쿼리 등으로 변환한다.
다시 한번 생각해보자. 또 어떤 재미있는 일을 할 수 있을까?
프로덕션에서도 사용가능하다: merb의 예
성능을 떨어뜨리는 코드는 버그라는 철학을 가진 Merb에서도 ruby2ruby를 사용한다. merb-action-args가 그 예인데 요청의 쿼리 파라메터를 컨트롤러의 액션 메서드의 파라매터로 매핑해주는 역할을 한다. def bar(baz) 라는 액션이 있고, "/foo/bar?baz=bat"라는 요청이 들어오면 foo("bat")을 호출해주는 식이다. 조금 더 자세한 설명은 이 링크에서 확인할 수 있다.
이 사용예에서의 핵심은 특정 루비 메서드의 파라메터 목록을 런타임에 찾아내는 아래 코드다.
def get_args
klass, meth = self.to_s.split(/ /).to_a[1][0..-2].split("#")
# Remove stupidity for #<Method: Class(Object)#foo>
klass = $` if klass =~ /\(/
ParseTreeArray.translate(Object.const_get(klass), meth).get_args
end
merb-action-args는 구동시에 Merb::AbstractController를 상속받는 모든 클래스의 메서드에 대해 파라매터 정보를 구축해놓고 있다가, 디스패치 작업에 이용한다.
메타프로그래밍의 재미
메타프로그래밍은 조금 더 일을 잘하기 위한 노력이다. 약간이라도 읽기 쉬운 코드, 반복을 최대한 줄이고 효율적인 작업이 가능하려면 어떻게 해야할까?를 고민하다보면 어느새 메타프로그래밍에 푹 빠지게 된다. 루비는 메타프로그래밍을 자연스럽게 할 수 있는 언어다. 그리고 다양한 예제와 프랙티스, 그리고 도구들이 있다. 남은 것은 코드를 조금 더 잘 만들려는 개발자들의 작은 열정과 틀을 깨는 상상력이 아닐까 싶다.