This is a first pass at converting the RDTool docs for lib/prettyprint.rb into rdoc format. I've left the rdtool docs in place so people can still use them, see what I started out with, etc. Again, this is against the -rw-r--r-- 1 hgs staff 4467539 Jul 13 13:08 stable-snapshot.tar.gz as last time. HTH Hugh --- lib/prettyprint.rb.orig 2004-03-27 01:46:05.000000000 +0000 +++ lib/prettyprint.rb 2006-07-14 14:54:31.532577000 +0100 @@ -60,7 +60,7 @@ == methods --- text(obj[, width]) - adds ((|obj|)) as a text of ((|width|)) columns in width. + adds ((|obj|)) as a text of ((|width|)y columns in width. If ((|width|)) is not specified, (({((|obj|)).length})) is used. @@ -125,7 +125,45 @@ Tanaka Akira <akr / m17n.org> =end +# The class implements pretty printing algorithm. +# It finds line breaks and nice indentations for grouped structure. +# +# By default, the class assumes that primitive elements are strings and +# each byte in the strings have single column in width. +# But it can be used for other situations +# by giving suitable arguments for some methods: +# newline object and space generation block for PrettyPrint.new, +# optional width argument for PrettyPrint#text, +# PrettyPrint#breakable, etc. +# There are several candidates to use them: +# text formatting using proportional fonts, +# multibyte characters which has columns different to number of bytes, +# non-string formatting, etc. +# +# == Bugs +# * Box based formatting? Other (better) model/algorithm? +# +# == References +# Christian Lindig, Strictly Pretty, March 2000, +# <URL:http://www.st.cs.uni-sb.de/~lindig/papers/#pretty> +# +# Philip Wadler, A prettier printer, March 1998, +# <URL:http://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier> +# +# == AUTHOR +# Tanaka Akira <akr / m17n.org> +# class PrettyPrint + + # This is a convenience method which is same as follows: + # + # begin + # q = PrettyPrint.new(output, maxwidth, newline, &genspace) + # ... + # q.flush + # output + # end + # def PrettyPrint.format(output='', maxwidth=79, newline="\n", genspace=lambda {|n| ' ' * n}) q = PrettyPrint.new(output, maxwidth, newline, &genspace) yield q @@ -133,12 +171,40 @@ output end + # This is similar to (({PrettyPrint.format})) but the result has no breaks. + # + # +maxwidth+, +newline+ and +genspace+ are ignored. + # The invocation of +breakable+ in the block doesn't break a line and + # treated as just an invocation of +text+. + # def PrettyPrint.singleline_format(output='', maxwidth=nil, newline=nil, genspace=nil) q = SingleLine.new(output) yield q output end + # creates a buffer for pretty printing. + # + # +output+ is an output target. + # If it is not specified, '' is assumed. + # It should have a << method which accepts + # the first argument +obj+ of PrettyPrint#text, + # the first argument +sep+ of PrettyPrint#breakable, + # the first argument +newline+ of PrettyPrint.new, + # and + # the result of a given block for PrettyPrint.new. + # + # +maxwidth+ specifies maximum line length. + # If it is not specified, 79 is assumed. + # However actual outputs may overflow +maxwidth+ if + # long non-breakable texts are provided. + # + # +newline+ is used for line breaks. + # "\n" is used if it is not specified. + # + # The block is used to generate spaces. + # {|width| ' ' * width} is used if it is not given. + # def initialize(output='', maxwidth=79, newline="\n", &genspace) @output = output @maxwidth = maxwidth @@ -161,6 +227,22 @@ @group_stack.last end + # first? is obsoleted at 1.8.2. + # + # first? is a predicate to test the call is a first call to first? with + # current group. + # It is useful to format comma separated values as: + # + # q.group(1, '[', ']') { + # xxx.each {|yyy| + # unless q.first? + # q.text ',' + # q.breakable + # end + # ... pretty printing yyy ... + # } + # } + # def first? warn "PrettyPrint#first? is obsoleted at 1.8.2." current_group.first? @@ -182,6 +264,10 @@ end end + # This adds +obj+ as a text of +width+ columns in width. + # + # If +width+ is not specified, obj.length is used. + # def text(obj, width=obj.length) if @buffer.empty? @output << obj @@ -202,6 +288,16 @@ group { breakable sep, width } end + # This tells "you can break a line here if necessary", and a + # +width+\-column text +sep+ is inserted if a line is not + # broken at the point. + # + # If +sep+ is not specified, " " is used. + # + # If +width+ is not specified, +sep.length+ is used. + # You will have to specify this when +sep+ is a multibyte + # character, for example. + # def breakable(sep=' ', width=sep.length) group = @group_stack.last if group.break? @@ -217,6 +313,17 @@ end end + # groups line break hints added in the block. + # The line break hints are all to be breaked or not. + # + # If indent is specified, the method call is regarded as nested by + # nest(indent) { ... }. + # + # If open_obj is specified, text open_obj, open_width is called + # at first. + # If close_obj is specified, text close_obj, close_width is + # called at last. + # def group(indent=0, open_obj='', close_obj='', open_width=open_obj.length, close_width=close_obj.length) text open_obj, open_width group_sub { @@ -241,6 +348,9 @@ end end + # increases left margin after newline with +indent+ for line breaks added + # in the block. + # def nest(indent) @indent += indent begin @@ -250,6 +360,7 @@ end end + # outputs buffered data. def flush @buffer.each {|data| @output_width = data.output(@output, @output_width)