Ripper 클래스
Ripper 클래스
Ripper는 Ruby 스크립트 파서(parser)예요. 이벤트 기반(event-based) 방식으로 파서로부터 정보를 얻을 수 있어요. 예를 들어 Ruby 프로그램의 추상 구문 트리(abstract syntax tree)나 간단한 어휘 분석(lexical analysis) 정보 같은 걸 얻을 수 있죠.
출처: Ruby 3.3 API
본문
사용법 (Usage)
Ripper는 프로그램을 기호 표현식 트리(문자 표현식을 담은 트리, S-expression)로 파싱하는 쉬운 인터페이스를 제공해요. 파서의 출력을 이해하는 건 어려울 수 있으니, 가독성을 위해 PP로 출력을 정리하는 걸 권장해요.
require 'ripper'
require 'pp'
pp Ripper.sexp('def hello(world) "Hello, #{world}!"; end')
#=> [:program,
[[:def,
[:@ident, "hello", [1, 4]],
[:paren,
[:params, [[:@ident, "world", [1, 10]]], nil, nil, nil, nil, nil, nil]],
[:bodystmt,
[[:string_literal,
[:string_content,
[:@tstring_content, "Hello, ", [1, 18]],
[:string_embexpr, [[:var_ref, [:@ident, "world", [1, 27]]]]],
[:@tstring_content, "!", [1, 33]]]]],
nil,
nil,
nil]]]]
위 예제에서 표현식이 :program으로 시작하는 걸 볼 수 있어요. 여기서부터 메서드 정의는 :def로 시작하고, 그다음 메서드의 식별자 :@ident가 나와요. 메서드 식별자 다음에는 괄호 :paren가 오고, :params 아래에 메서드 매개변수가 놓여요.
그다음은 메서드 본문인데 :bodystmt(stmt는 statement를 뜻해요)로 시작하며, 메서드의 전체 정의를 담고 있어요. 여기서는 단순히 String을 반환하므로 다음으로 :string_literal 표현식이 와요. :string_literal 안에는 @tstring_content가 두 개 있는데, Hello, 와 !의 리터럴 부분이에요. 두 @tstring_content 사이에는 :string_embexpr이 있고, embexpr은 삽입된 표현식(embedded expression)을 의미해요. 우리 표현식은 world라는 식별자(@ident)를 가진 지역 변수, 즉 var_ref로 구성돼 있어요.
상수 (Constants)
EVENTS: 모든 ripper 이벤트의 이름을 담고 있는 배열이에요.PARSER_EVENTS: 파서 이벤트의 이름을 담고 있는 배열이에요.SCANNER_EVENTS: 스캐너 이벤트의 이름을 담고 있는 배열이에요.
Public Class Methods
lex(src, filename = '-', lineno = 1, **kw)
Ruby 프로그램을 토큰화하고 [[lineno, column], type, token, state]처럼 형식화된 배열의 배열을 반환해요. filename 인자는 대부분 무시돼요. 기본적으로 이 메서드는 src의 문법 오류를 처리하지 않고, src의 오류에 대해 SyntaxError를 발생시키려면 raise_errors 키워드를 사용해요.
require 'ripper'
require 'pp'
pp Ripper.lex("def m(a) nil end")
#=> [[[1, 0], :on_kw, "def", FNAME ],
[[1, 3], :on_sp, " ", FNAME ],
[[1, 4], :on_ident, "m", ENDFN ],
[[1, 5], :on_lparen, "(", BEG|LABEL],
[[1, 6], :on_ident, "a", ARG ],
[[1, 7], :on_rparen, ")", ENDFN ],
[[1, 8], :on_sp, " ", BEG ],
[[1, 9], :on_kw, "nil", END ],
[[1, 12], :on_sp, " ", END ],
[[1, 13], :on_kw, "end", END ]]
parse(src, filename = '(ripper)', lineno = 1)
src에서 읽은 주어진 Ruby 프로그램을 파싱해요. src는 String이거나 IO, 또는 gets 메서드를 가진 객체여야 해요.
sexp(src, filename = '-', lineno = 1, raise_errors: false)
EXPERIMENTAL — src를 파싱해 S-exp 트리를 만들어요. Ripper.sexp_raw보다 더 읽기 쉬운 트리를 반환해요. 주로 개발자용 메서드예요. filename 인자는 대부분 무시돼요. 기본적으로 이 메서드는 src의 문법 오류를 처리하지 않고, 그러한 경우 nil을 반환해요. 오류에 대해 SyntaxError를 발생시키려면 raise_errors 키워드를 사용해요.
require 'ripper'
require 'pp'
pp Ripper.sexp("def m(a) nil end")
#=> [:program,
[[:def,
[:@ident, "m", [1, 4]],
[:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil, nil, nil, nil]],
[:bodystmt, [[:var_ref, [:@kw, "nil", [1, 9]]]], nil, nil, nil]]]]
sexp_raw(src, filename = '-', lineno = 1, raise_errors: false)
EXPERIMENTAL — src를 파싱해 S-exp 트리를 만들어요. 주로 개발자용 메서드예요. filename 인자는 대부분 무시돼요. 기본적으로 문법 오류가 있으면 nil을 반환하고, raise_errors 키워드로 SyntaxError를 발생시킬 수 있어요.
require 'ripper'
require 'pp'
pp Ripper.sexp_raw("def m(a) nil end")
#=> [:program,
[:stmts_add,
[:stmts_new],
[:def,
[:@ident, "m", [1, 4]],
[:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil]],
[:bodystmt,
[:stmts_add, [:stmts_new], [:var_ref, [:@kw, "nil", [1, 9]]]],
nil,
nil,
nil]]]]
slice(src, pattern, n = 0)
EXPERIMENTAL — src를 파싱하고 pattern에 매칭된 문자열을 반환해요. pattern은 Regexp로 표현해야 해요.
require 'ripper'
p Ripper.slice('def m(a) nil end', 'ident') #=> "m"
p Ripper.slice('def m(a) nil end', '[ident lparen rparen]+') #=> "m(a)"
p Ripper.slice("<<EOS\nstring\nEOS",
'heredoc_beg nl $(tstring_content*) heredoc_end', 1)
#=> "string\n"
tokenize(src, filename = '-', lineno = 1, **kw)
Ruby 프로그램을 토큰화하고 문자열 배열을 반환해요. 반환값이 그냥 토큰화된 입력이므로 filename과 lineno 인자는 대부분 무시돼요. 기본적으로 문법 오류를 처리하지 않고, raise_errors 키워드로 SyntaxError를 발생시킬 수 있어요.
p Ripper.tokenize("def m(a) nil end")
# => ["def", " ", "m", "(", "a", ")", " ", "nil", " ", "end"]
Private Instance Methods
compile_error(msg)
파서가 문법 오류를 찾았을 때 호출되는 메서드예요.
warn(fmt, *args)
파서가 약한 경고(weak warning)를 만들 때 호출되는 메서드예요. fmt와 args는 printf 스타일이에요.
warning(fmt, *args)
파서가 강한 경고(strong warning)를 만들 때 호출되는 메서드예요. fmt와 args는 printf 스타일이에요.