From: George Ogata Date: 2005-11-27T19:43:38+09:00 Subject: [PATCH] ri displaying lists in columns Hi List, While ri is a really nice quick reference, I found it hard to read the long lists of comma-separated method names. So I patched it to format these lists in columns. Now, instead of this: -------------------------------------------------------------- Class: IO (no description...) ------------------------------------------------------------------------ Includes: --------- Enumerable(all?, any?, collect, count, detect, each_cons, each_slice, each_with_index, entries, enum_cons, enum_slice, enum_with_index, find, find_all, grep, include?, inject, map, max, max_by, member?, min, min_by, partition, reject, select, sort, sort_by, to_a, to_set, zip), File::Constants() Constants: ---------- SEEK_SET: INT2FIX(SEEK_SET) SEEK_CUR: INT2FIX(SEEK_CUR) SEEK_END: INT2FIX(SEEK_END) Class methods: -------------- for_fd, foreach, new, new, open, pipe, popen, read, readlines, select, sysopen Instance methods: ----------------- <<, binmode, close, close_read, close_write, closed?, each, each_byte, each_line, eof, eof?, fcntl, fileno, flush, fsync, getc, gets, inspect, ioctl, isatty, lineno, lineno=, pid, pos, pos=, print, printf, putc, puts, read, readchar, readline, readlines, readpartial, reopen, rewind, seek, stat, sync, sync=, sysread, sysseek, syswrite, tell, to_i, to_io, tty?, ungetc, write ...you get this: -------------------------------------------------------------- Class: IO (no description...) ------------------------------------------------------------------------ Includes: --------- File::Constants: (no instance methods) Enumerable: all? each_with_index find_all max_by select any? entries grep member? sort collect enum_cons include? min sort_by count enum_slice inject min_by to_a detect enum_with_index map partition to_set each_cons find max reject zip each_slice Constants: ---------- SEEK_SET: INT2FIX(SEEK_SET) SEEK_CUR: INT2FIX(SEEK_CUR) SEEK_END: INT2FIX(SEEK_END) Class methods: -------------- for_fd new open pipe popen read readlines select sysopen foreach new Instance methods: ----------------- << eof inspect print readpartial sysseek binmode eof? ioctl printf reopen syswrite close fcntl isatty putc rewind tell close_read fileno lineno puts seek to_i close_write flush lineno= read stat to_io closed? fsync pid readchar sync tty? each getc pos readline sync= ungetc each_byte gets pos= readlines sysread write each_line What do you think? Patch follows. Cheers, George. diff -Naur ruby/lib/rdoc/ri/ri_display.rb ruby.mod/lib/rdoc/ri/ri_display.rb --- ruby/lib/rdoc/ri/ri_display.rb 2004-03-25 06:17:13.000000000 +1100 +++ ruby.mod/lib/rdoc/ri/ri_display.rb 2005-11-27 20:07:39.000000000 +1100 @@ -88,7 +88,7 @@ display_flow(klass.comment) @formatter.draw_line - + unless klass.includes.empty? @formatter.blankline @formatter.display_heading("Includes:", 2, "") @@ -96,15 +96,14 @@ klass.includes.each do |inc| inc_desc = ri_reader.find_class_by_name(inc.name) if inc_desc - str = inc.name + "(" - str << inc_desc.instance_methods.map{|m| m.name}.join(", ") - str << ")" - incs << str + methods = inc_desc.instance_methods.map{|m| m.name} + methods = ['(no instance methods)'] if methods.empty? + @formatter.wrap("#{inc.name}:") + @formatter.wrap_list(methods.sort, @formatter.indent*2) else - incs << inc.name + @formatter.wrap(inc.name) end - end - @formatter.wrap(incs.sort.join(', ')) + end end unless klass.constants.empty? @@ -122,19 +121,19 @@ unless klass.class_methods.empty? @formatter.blankline @formatter.display_heading("Class methods:", 2, "") - @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', ')) + @formatter.wrap_list(klass.class_methods.map{|m| m.name}.sort) end unless klass.instance_methods.empty? @formatter.blankline @formatter.display_heading("Instance methods:", 2, "") - @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', ')) + @formatter.wrap_list(klass.instance_methods.map{|m| m.name}.sort) end unless klass.attributes.empty? @formatter.blankline - @formatter.wrap("Attributes:", "") - @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', ')) + @formatter.display_heading("Attributes:", 2, "") + @formatter.wrap_list(klass.attributes.map{|a| a.name}.sort) end end end @@ -147,7 +146,7 @@ page do puts "More than one method matched your request. You can refine" puts "your search by asking for information on one of:\n\n" - @formatter.wrap(methods.map {|m| m.full_name} .join(", ")) + @formatter.wrap_list(methods.map {|m| m.full_name}.sort) end end @@ -157,7 +156,7 @@ page do puts "More than one class or module matched your request. You can refine" puts "your search by asking for information on one of:\n\n" - @formatter.wrap(namespaces.map {|m| m.full_name}.join(", ")) + @formatter.wrap_list(namespaces.map {|m| m.full_name}.sort) end end @@ -170,7 +169,7 @@ page do @formatter.draw_line("Known classes and modules") @formatter.blankline - @formatter.wrap(classes.sort.join(", ")) + @formatter.wrap_list(classes.sort) end end end diff -Naur ruby/lib/rdoc/ri/ri_formatter.rb ruby.mod/lib/rdoc/ri/ri_formatter.rb --- ruby/lib/rdoc/ri/ri_formatter.rb 2004-12-31 16:12:37.000000000 +1100 +++ ruby.mod/lib/rdoc/ri/ri_formatter.rb 2005-11-27 20:07:26.000000000 +1100 @@ -47,6 +47,64 @@ end ###################################################################### + + def wrap_list(list, prefix=@indent, linelen=@width) + return if list.empty? + + cols = wrap_list_cols(list, linelen - prefix.length) + widths = cols.map do |col| + col.map{|s| s.length}.max + end + + cols[0].each_index do |rowno| + items = (0...cols.length).map do |colno| + cols[colno][rowno].to_s.ljust(widths[colno]) + end + puts "#{prefix}#{items.join(' ')}" + end + end + + def wrap_list_cols(list, width) + num_cols = 1 + while num_cols < list.length && + wrap_list_fit?(list, width, num_cols+1) + num_cols += 1 + end + ranges = wrap_list_ranges(list.length, num_cols) + ranges.map{|r| list[r]} + end + protected :wrap_list_cols + + def wrap_list_ranges(num_items, num_cols) + ranges = [] + q, r = num_items.divmod(num_cols) + k = 0 + num_cols.times do |i| + len = i < r ? q+1 : q + ranges << (k...k+len) + k += len + end + return ranges + end + private :wrap_list_ranges + + def wrap_list_fit?(list, linelen, num_cols) + ranges = wrap_list_ranges(list.length, num_cols) + + widths = ranges.map do |range| + list[range].map{|s| s.length}.max + end + pad = 2*(num_cols - 1) + + if widths.inject(0){|sum,w| sum+w} + pad > linelen + return false + else + return true + end + end + private :wrap_list_fit? + + ###################################################################### def blankline puts @@ -560,6 +618,19 @@ puts("") end + def wrap_list(list, prefix=@indent, linelen=@width) + cols = wrap_list_cols(list, linelen - prefix.length) + puts "" + cols[0].each_index do |rowno| + print " " + cols.each_index do |colno| + print "" + end + puts "" + end + puts "
#{cols[colno][rowno]}
" + end + private ATTR_MAP = {