PrettyPrint 클래스
PrettyPrint 클래스
이 클래스는 pretty printing 알고리즘을 구현해요. 그룹화된 구조의 줄바꿈 지점과 보기 좋은 들여쓰기를 찾아내요.
출처: Ruby 3.3 API
본문
기본적으로 이 클래스는 원시 요소가 문자열이고, 문자열의 각 바이트가 가로 폭 1열을 차지한다고 가정해요. 하지만 일부 메서드에 적절한 인자를 주면 다른 상황에서도 쓸 수 있어요:
PrettyPrint.new의 newline 객체와 공백 생성 블록PrettyPrint#text,PrettyPrint#breakable의 선택적 width 인자
사용 후보가 몇 가지 있어요:
- 비례 폰트를 사용한 텍스트 포매팅
- 바이트 수와 다른 열 수를 가진 멀티바이트 문자
- 문자열이 아닌 포매팅
버그 (Bugs)
- 박스 기반 포매팅?
- 다른(더 나은) 모델/알고리즘?
버그는 bugs.ruby-lang.org에 보고해 주세요.
참고자료 (References)
- Christian Lindig, Strictly Pretty, March 2000, lindig.github.io/papers/strictly-pretty-2000.pdf
- Philip Wadler, A prettier printer, March 1998, homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier
저자: Tanaka Akira <[email protected]>
상수 (Constants)
- VERSION
Attributes
genspace
Integer 하나를 인자로 받아 그 숫자만큼의 공백을 반환하는 lambda 또는 Proc이에요.
기본값은 이래요.
lambda {|n| ' ' * n}
group_queue
pretty print할 스택에 있는 그룹들의 PrettyPrint::GroupQueue예요.
indent
들여쓸 공백의 수예요.
maxwidth
줄이 새 줄로 나뉘기 전의 최대 너비예요.
기본값은 79이고, Integer여야 해요.
newline
output에 새 줄을 추가하기 위해 덧붙여지는 값이에요.
기본값은 "n"이고, String이어야 해요.
output
출력 객체예요.
기본값은 ""이고, << 메서드를 받아들여야 해요.
Public Class Methods
format (output=''.dup, maxwidth=79, newline="\n", genspace=lambda {|n| ' ' * n}) { |q| ... }
편의 메서드로, 다음과 같아요.
begin
q = PrettyPrint.new(output, maxwidth, newline, &genspace)
...
q.flush
output
end
new (output=''.dup, maxwidth=79, newline="\n", &genspace)
pretty printing용 버퍼를 만들어요.
output은 출력 대상이에요. 지정하지 않으면 ""으로 간주해요. PrettyPrint#text의 첫 인자 obj, PrettyPrint#breakable의 첫 인자 sep, PrettyPrint.new의 첫 인자 newline, 그리고 PrettyPrint.new에 주어진 블록의 결과를 받아들이는 << 메서드를 가져야 해요.
maxwidth는 최대 줄 길이를 지정해요. 지정하지 않으면 79로 간주해요. 다만 긴 줄바꿈 불가 텍스트가 제공되면 실제 출력은 maxwidth를 넘어설 수 있어요.
newline은 줄바꿈에 사용돼요. 지정하지 않으면 "n"이 사용돼요.
블록은 공백을 생성하는 데 사용돼요. 주어지지 않으면 {|width| ' ' * width}가 사용돼요.
singleline_format (output=''.dup, maxwidth=nil, newline=nil, genspace=nil) { |q| ... }
PrettyPrint::format과 비슷하지만 결과에 줄바꿈이 없어요.
maxwidth, newline, genspace는 무시돼요.
블록 안의 breakable 호출은 줄을 끊지 않고 text 호출처럼 취급돼요.
Public Instance Methods
break_outmost_groups ()
버퍼를 maxwidth보다 짧은 줄들로 나눠요.
breakable (sep=' ', width=sep.length)
"필요하면 여기서 줄을 끊어도 돼요"라고 말하는 것과 같아요. 그 지점에서 줄이 끊기지 않으면 width열 너비의 텍스트 sep이 삽입돼요.
sep이 지정되지 않으면 " "이 사용돼요.
width가 지정되지 않으면 sep.length가 사용돼요. sep이 멀티바이트 문자인 경우 등에는 이걸 지정해야 해요.
current_group ()
스택에 가장 최근에 추가된 그룹을 반환해요.
인위적인 예시:
out = ""
=> ""
q = PrettyPrint.new(out)
=> #<PrettyPrint:0x82f85c0 @output="", @maxwidth=79, @newline="\n", @genspace=#<Proc:0x82f8368@/home/vbatts/.rvm/rubies/ruby-head/lib/ruby/2.0.0/prettyprint.rb:82 (lambda)>, @output_width=0, @buffer_width=0, @buffer=[], @group_stack=[#<PrettyPrint::Group:0x82f8138 @depth=0, @breakables=[], @break=false>], @group_queue=#<PrettyPrint::GroupQueue:0x82fb7c0 @queue=[[#<PrettyPrint::Group:0x82f8138 @depth=0, @breakables=[], @break=false>]]>, @indent=0>
q.group {
q.text q.current_group.inspect
q.text q.newline
q.group(q.current_group.depth + 1) {
q.text q.current_group.inspect
q.text q.newline
q.group(q.current_group.depth + 1) {
q.text q.current_group.inspect
q.text q.newline
q.group(q.current_group.depth + 1) {
q.text q.current_group.inspect
q.text q.newline
}
}
}
}
=> 284
puts out
#<PrettyPrint::Group:0x8354758 @depth=1, @breakables=[], @break=false>
#<PrettyPrint::Group:0x8354550 @depth=2, @breakables=[], @break=false>
#<PrettyPrint::Group:0x83541cc @depth=3, @breakables=[], @break=false>
#<PrettyPrint::Group:0x8347e54 @depth=4, @breakables=[], @break=false>
fill_breakable (sep=' ', width=sep.length)
breakable과 비슷하지만 끊을지 말지의 결정이 개별적으로 정해져요.
그룹 아래의 두 fill_breakable은 4가지 결과를 만들 수 있어요: (break,break), (break,non-break), (non-break,break), (non-break,non-break). 두 breakable이 2가지 결과만 만드는 것과 달라요: (break,break), (non-break,non-break).
이 지점에서 줄이 끊기지 않으면 텍스트 sep이 삽입돼요.
sep이 지정되지 않으면 " "이 사용돼요.
width가 지정되지 않으면 sep.length가 사용돼요. sep이 멀티바이트 문자인 경우 등에는 이걸 지정해야 해요.
flush ()
버퍼링된 데이터를 출력해요.
group (indent=0, open_obj='', close_obj='', open_width=open_obj.length, close_width=close_obj.length) { || ... }
블록에서 추가된 줄바꿈 힌트들을 그룹화해요. 줄바꿈 힌트들은 모두 사용되거나 모두 사용되지 않아요.
indent가 지정되면 이 메서드 호출은 nest(indent) { … }으로 중첩된 것으로 간주돼요.
open_obj가 지정되면 그룹화 전에 text open_obj, open_width가 호출돼요. close_obj가 지정되면 그룹화 후에 text close_obj, close_width가 호출돼요.
group_sub () { || ... }
블록을 받아 한 단계 더 들여쓰기된 새 그룹을 큐에 넣어요.
nest (indent) { || ... }
블록에서 추가된 줄바꿈에 대해 새 줄 이후의 왼쪽 여백을 indent만큼 늘려요.
text (obj, width=obj.length)
obj를 width열 너비의 텍스트로 추가해요.
width가 지정되지 않으면 obj.length가 사용돼요.