* transcode.c (trans_open_i): check the result of rb_transcoding_open.
[ruby-svn.git] / lib / pp.rb
blobec896b3ce583a07a5c2b72a5be0e361718ed0c1b
1 # == Pretty-printer for Ruby objects.
2
3 # = Which seems better?
4
5 # non-pretty-printed output by #p is:
6 #   #<PP:0x81fedf0 @genspace=#<Proc:0x81feda0>, @group_queue=#<PrettyPrint::GroupQueue:0x81fed3c @queue=[[#<PrettyPrint::Group:0x81fed78 @breakables=[], @depth=0, @break=false>], []]>, @buffer=[], @newline="\n", @group_stack=[#<PrettyPrint::Group:0x81fed78 @breakables=[], @depth=0, @break=false>], @buffer_width=0, @indent=0, @maxwidth=79, @output_width=2, @output=#<IO:0x8114ee4>>
7
8 # pretty-printed output by #pp is:
9 #   #<PP:0x81fedf0
10 #    @buffer=[],
11 #    @buffer_width=0,
12 #    @genspace=#<Proc:0x81feda0>,
13 #    @group_queue=
14 #     #<PrettyPrint::GroupQueue:0x81fed3c
15 #      @queue=
16 #       [[#<PrettyPrint::Group:0x81fed78 @break=false, @breakables=[], @depth=0>],
17 #        []]>,
18 #    @group_stack=
19 #     [#<PrettyPrint::Group:0x81fed78 @break=false, @breakables=[], @depth=0>],
20 #    @indent=0,
21 #    @maxwidth=79,
22 #    @newline="\n",
23 #    @output=#<IO:0x8114ee4>,
24 #    @output_width=2>
25
26 # I like the latter.  If you do too, this library is for you.
27
28 # = Usage
29
30 #   pp(obj)
32 # output +obj+ to +$>+ in pretty printed format.
33
34 # It returns +nil+.
35
36 # = Output Customization
37 # To define your customized pretty printing function for your classes,
38 # redefine a method #pretty_print(+pp+) in the class.
39 # It takes an argument +pp+ which is an instance of the class PP.
40 # The method should use PP#text, PP#breakable, PP#nest, PP#group and
41 # PP#pp to print the object.
43 # = Author
44 # Tanaka Akira <akr@m17n.org>
46 require 'prettyprint'
48 module Kernel
49   # returns a pretty printed object as a string.
50   def pretty_inspect
51     PP.pp(self, '')
52   end
54   private
55   # prints arguments in pretty form.
56   #
57   # pp returns nil.
58   def pp(*objs) # :doc:
59     objs.each {|obj|
60       PP.pp(obj)
61     }
62     nil
63   end
64   module_function :pp
65 end
67 class PP < PrettyPrint
68   # Outputs +obj+ to +out+ in pretty printed format of
69   # +width+ columns in width.
70   # 
71   # If +out+ is omitted, +$>+ is assumed.
72   # If +width+ is omitted, 79 is assumed.
73   # 
74   # PP.pp returns +out+.
75   def PP.pp(obj, out=$>, width=79)
76     q = PP.new(out, width)
77     q.guard_inspect_key {q.pp obj}
78     q.flush
79     #$pp = q
80     out << "\n"
81   end
83   # Outputs +obj+ to +out+ like PP.pp but with no indent and
84   # newline.
85   # 
86   # PP.singleline_pp returns +out+.
87   def PP.singleline_pp(obj, out=$>)
88     q = SingleLine.new(out)
89     q.guard_inspect_key {q.pp obj}
90     q.flush
91     out
92   end
94   # :stopdoc:
95   def PP.mcall(obj, mod, meth, *args, &block)
96     mod.instance_method(meth).bind(obj).call(*args, &block)
97   end
98   # :startdoc:
100   @sharing_detection = false
101   class << self
102     # Returns the sharing detection flag as a boolean value.
103     # It is false by default.
104     attr_accessor :sharing_detection
105   end
107   module PPMethods
108     def guard_inspect_key
109       if Thread.current[:__recursive_key__] == nil
110         Thread.current[:__recursive_key__] = {}
111       end
113       if Thread.current[:__recursive_key__][:inspect] == nil
114         Thread.current[:__recursive_key__][:inspect] = {}
115       end
117       save = Thread.current[:__recursive_key__][:inspect]
119       begin
120         Thread.current[:__recursive_key__][:inspect] = {}
121         yield
122       ensure
123         Thread.current[:__recursive_key__][:inspect] = save
124       end
125     end
127     def check_inspect_key(id)
128       Thread.current[:__recursive_key__] &&
129       Thread.current[:__recursive_key__][:inspect] &&
130       Thread.current[:__recursive_key__][:inspect].include?(id)
131     end
132     def push_inspect_key(id)
133       Thread.current[:__recursive_key__][:inspect][id] = true
134     end
135     def pop_inspect_key(id)
136       Thread.current[:__recursive_key__][:inspect].delete id
137     end
139     # Adds +obj+ to the pretty printing buffer
140     # using Object#pretty_print or Object#pretty_print_cycle.
141     # 
142     # Object#pretty_print_cycle is used when +obj+ is already
143     # printed, a.k.a the object reference chain has a cycle.
144     def pp(obj)
145       id = obj.object_id
147       if check_inspect_key(id)
148         group {obj.pretty_print_cycle self}
149         return
150       end
152       begin
153         push_inspect_key(id)
154         group {obj.pretty_print self}
155       ensure
156         pop_inspect_key(id) unless PP.sharing_detection
157       end
158     end
160     # A convenience method which is same as follows:
161     # 
162     #   group(1, '#<' + obj.class.name, '>') { ... }
163     def object_group(obj, &block) # :yield:
164       group(1, '#<' + obj.class.name, '>', &block)
165     end
167     if 0x100000000.class == Bignum
168       # 32bit
169       PointerMask = 0xffffffff
170     else
171       # 64bit
172       PointerMask = 0xffffffffffffffff
173     end
175     case Object.new.inspect
176     when /\A\#<Object:0x([0-9a-f]+)>\z/
177       PointerFormat = "%0#{$1.length}x"
178     else
179       PointerFormat = "%x"
180     end
182     def object_address_group(obj, &block)
183       id = PointerFormat % (obj.object_id * 2 & PointerMask)
184       group(1, "\#<#{obj.class}:0x#{id}", '>', &block)
185     end
187     # A convenience method which is same as follows:
188     # 
189     #   text ','
190     #   breakable
191     def comma_breakable
192       text ','
193       breakable
194     end
196     # Adds a separated list.
197     # The list is separated by comma with breakable space, by default.
198     # 
199     # #seplist iterates the +list+ using +iter_method+.
200     # It yields each object to the block given for #seplist.
201     # The procedure +separator_proc+ is called between each yields.
202     # 
203     # If the iteration is zero times, +separator_proc+ is not called at all.
204     # 
205     # If +separator_proc+ is nil or not given,
206     # +lambda { comma_breakable }+ is used.
207     # If +iter_method+ is not given, :each is used.
208     # 
209     # For example, following 3 code fragments has similar effect.
210     # 
211     #   q.seplist([1,2,3]) {|v| xxx v }
212     # 
213     #   q.seplist([1,2,3], lambda { q.comma_breakable }, :each) {|v| xxx v }
214     # 
215     #   xxx 1
216     #   q.comma_breakable
217     #   xxx 2
218     #   q.comma_breakable
219     #   xxx 3
220     def seplist(list, sep=nil, iter_method=:each) # :yield: element
221       sep ||= lambda { comma_breakable }
222       first = true
223       list.__send__(iter_method) {|*v|
224         if first
225           first = false
226         else
227           sep.call
228         end
229         yield(*v)
230       }
231     end
233     def pp_object(obj)
234       object_address_group(obj) {
235         seplist(obj.pretty_print_instance_variables, lambda { text ',' }) {|v|
236           breakable
237           v = v.to_s if Symbol === v
238           text v
239           text '='
240           group(1) {
241             breakable ''
242             pp(obj.instance_eval(v))
243           }
244         }
245       }
246     end
248     def pp_hash(obj)
249       group(1, '{', '}') {
250         seplist(obj, nil, :each_pair) {|k, v|
251           group {
252             pp k
253             text '=>'
254             group(1) {
255               breakable ''
256               pp v
257             }
258           }
259         }
260       }
261     end
262   end
264   include PPMethods
266   class SingleLine < PrettyPrint::SingleLine
267     include PPMethods
268   end
270   module ObjectMixin
271     # 1. specific pretty_print
272     # 2. specific inspect
273     # 3. specific to_s if instance variable is empty
274     # 4. generic pretty_print
276     # A default pretty printing method for general objects.
277     # It calls #pretty_print_instance_variables to list instance variables.
278     # 
279     # If +self+ has a customized (redefined) #inspect method,
280     # the result of self.inspect is used but it obviously has no
281     # line break hints.
282     # 
283     # This module provides predefined #pretty_print methods for some of
284     # the most commonly used built-in classes for convenience.
285     def pretty_print(q)
286       if /\(Kernel\)#/ !~ Object.instance_method(:method).bind(self).call(:inspect).inspect
287         q.text self.inspect
288       elsif /\(Kernel\)#/ !~ Object.instance_method(:method).bind(self).call(:to_s).inspect && instance_variables.empty?
289         q.text self.to_s
290       else
291         q.pp_object(self)
292       end
293     end
295     # A default pretty printing method for general objects that are
296     # detected as part of a cycle.
297     def pretty_print_cycle(q)
298       q.object_address_group(self) {
299         q.breakable
300         q.text '...'
301       }
302     end
304     # Returns a sorted array of instance variable names.
305     # 
306     # This method should return an array of names of instance variables as symbols or strings as:
307     # +[:@a, :@b]+.
308     def pretty_print_instance_variables
309       instance_variables.sort
310     end
312     # Is #inspect implementation using #pretty_print.
313     # If you implement #pretty_print, it can be used as follows.
314     # 
315     #   alias inspect pretty_print_inspect
316     #
317     # However, doing this requires that every class that #inspect is called on
318     # implement #pretty_print, or a RuntimeError will be raised.
319     def pretty_print_inspect
320       if /\(PP::ObjectMixin\)#/ =~ Object.instance_method(:method).bind(self).call(:pretty_print).inspect
321         raise "pretty_print is not overridden for #{self.class}"
322       end
323       PP.singleline_pp(self, '')
324     end
325   end
328 class Array
329   def pretty_print(q)
330     q.group(1, '[', ']') {
331       q.seplist(self) {|v|
332         q.pp v
333       }
334     }
335   end
337   def pretty_print_cycle(q)
338     q.text(empty? ? '[]' : '[...]')
339   end
342 class Hash
343   def pretty_print(q)
344     q.pp_hash self
345   end
347   def pretty_print_cycle(q)
348     q.text(empty? ? '{}' : '{...}')
349   end
352 class << ENV
353   def pretty_print(q)
354     h = {}
355     ENV.keys.sort.each {|k|
356       h[k] = ENV[k]
357     }
358     q.pp_hash h
359   end
362 class Struct
363   def pretty_print(q)
364     q.group(1, '#<struct ' + PP.mcall(self, Kernel, :class).name, '>') {
365       q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
366         q.breakable
367         q.text member.to_s
368         q.text '='
369         q.group(1) {
370           q.breakable ''
371           q.pp self[member]
372         }
373       }
374     }
375   end
377   def pretty_print_cycle(q)
378     q.text sprintf("#<struct %s:...>", PP.mcall(self, Kernel, :class).name)
379   end
382 class Range
383   def pretty_print(q)
384     q.pp self.begin
385     q.breakable ''
386     q.text(self.exclude_end? ? '...' : '..')
387     q.breakable ''
388     q.pp self.end
389   end
392 class File
393   class Stat
394     def pretty_print(q)
395       require 'etc.so'
396       q.object_group(self) {
397         q.breakable
398         q.text sprintf("dev=0x%x", self.dev); q.comma_breakable
399         q.text "ino="; q.pp self.ino; q.comma_breakable
400         q.group {
401           m = self.mode
402           q.text sprintf("mode=0%o", m)
403           q.breakable
404           q.text sprintf("(%s %c%c%c%c%c%c%c%c%c)",
405             self.ftype,
406             (m & 0400 == 0 ? ?- : ?r),
407             (m & 0200 == 0 ? ?- : ?w),
408             (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) :
409                              (m & 04000 == 0 ? ?x : ?s)),
410             (m & 0040 == 0 ? ?- : ?r),
411             (m & 0020 == 0 ? ?- : ?w),
412             (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) :
413                              (m & 02000 == 0 ? ?x : ?s)),
414             (m & 0004 == 0 ? ?- : ?r),
415             (m & 0002 == 0 ? ?- : ?w),
416             (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) :
417                              (m & 01000 == 0 ? ?x : ?t)))
418         }
419         q.comma_breakable
420         q.text "nlink="; q.pp self.nlink; q.comma_breakable
421         q.group {
422           q.text "uid="; q.pp self.uid
423           begin
424             pw = Etc.getpwuid(self.uid)
425           rescue ArgumentError
426           end
427           if pw
428             q.breakable; q.text "(#{pw.name})"
429           end
430         }
431         q.comma_breakable
432         q.group {
433           q.text "gid="; q.pp self.gid
434           begin
435             gr = Etc.getgrgid(self.gid)
436           rescue ArgumentError
437           end
438           if gr
439             q.breakable; q.text "(#{gr.name})"
440           end
441         }
442         q.comma_breakable
443         q.group {
444           q.text sprintf("rdev=0x%x", self.rdev)
445           q.breakable
446           q.text sprintf('(%d, %d)', self.rdev_major, self.rdev_minor)
447         }
448         q.comma_breakable
449         q.text "size="; q.pp self.size; q.comma_breakable
450         q.text "blksize="; q.pp self.blksize; q.comma_breakable
451         q.text "blocks="; q.pp self.blocks; q.comma_breakable
452         q.group {
453           t = self.atime
454           q.text "atime="; q.pp t
455           q.breakable; q.text "(#{t.tv_sec})"
456         }
457         q.comma_breakable
458         q.group {
459           t = self.mtime
460           q.text "mtime="; q.pp t
461           q.breakable; q.text "(#{t.tv_sec})"
462         }
463         q.comma_breakable
464         q.group {
465           t = self.ctime
466           q.text "ctime="; q.pp t
467           q.breakable; q.text "(#{t.tv_sec})"
468         }
469       }
470     end
471   end
474 class MatchData
475   def pretty_print(q)
476     nc = []
477     self.regexp.named_captures.each {|name, indexes|
478       indexes.each {|i| nc[i] = name }
479     }
480     q.object_group(self) {
481       q.breakable
482       q.seplist(0...self.size, lambda { q.breakable }) {|i|
483         if i == 0
484           q.pp self[i]
485         else
486           if nc[i]
487             q.text nc[i]
488           else
489             q.pp i
490           end
491           q.text ':'
492           q.pp self[i]
493         end
494       }
495     }
496   end
499 class Object
500   include PP::ObjectMixin
503 [Numeric, Symbol, FalseClass, TrueClass, NilClass, Module].each {|c|
504   c.class_eval {
505     def pretty_print_cycle(q)
506       q.text inspect
507     end
508   }
511 [Numeric, FalseClass, TrueClass, Module].each {|c|
512   c.class_eval {
513     def pretty_print(q)
514       q.text inspect
515     end
516   }
519 # :enddoc:
520 if __FILE__ == $0
521   require 'test/unit'
523   class PPTest < Test::Unit::TestCase
524     def test_list0123_12
525       assert_equal("[0, 1, 2, 3]\n", PP.pp([0,1,2,3], '', 12))
526     end
528     def test_list0123_11
529       assert_equal("[0,\n 1,\n 2,\n 3]\n", PP.pp([0,1,2,3], '', 11))
530     end
532     OverriddenStruct = Struct.new("OverriddenStruct", :members, :class)
533     def test_struct_override_members # [ruby-core:7865]
534       a = OverriddenStruct.new(1,2)
535       assert_equal("#<struct Struct::OverriddenStruct members=1, class=2>\n", PP.pp(a, ''))
536     end
538     def test_redefined_method
539       o = ""
540       def o.method
541       end
542       assert_equal(%(""\n), PP.pp(o, ""))
543     end
544   end
546   class HasInspect
547     def initialize(a)
548       @a = a
549     end
551     def inspect
552       return "<inspect:#{@a.inspect}>"
553     end
554   end
556   class HasPrettyPrint
557     def initialize(a)
558       @a = a
559     end
561     def pretty_print(q)
562       q.text "<pretty_print:"
563       q.pp @a
564       q.text ">"
565     end
566   end
568   class HasBoth
569     def initialize(a)
570       @a = a
571     end
573     def inspect
574       return "<inspect:#{@a.inspect}>"
575     end
577     def pretty_print(q)
578       q.text "<pretty_print:"
579       q.pp @a
580       q.text ">"
581     end
582   end
584   class PrettyPrintInspect < HasPrettyPrint
585     alias inspect pretty_print_inspect
586   end
588   class PrettyPrintInspectWithoutPrettyPrint
589     alias inspect pretty_print_inspect
590   end
592   class PPInspectTest < Test::Unit::TestCase
593     def test_hasinspect
594       a = HasInspect.new(1)
595       assert_equal("<inspect:1>\n", PP.pp(a, ''))
596     end
598     def test_hasprettyprint
599       a = HasPrettyPrint.new(1)
600       assert_equal("<pretty_print:1>\n", PP.pp(a, ''))
601     end
603     def test_hasboth
604       a = HasBoth.new(1)
605       assert_equal("<pretty_print:1>\n", PP.pp(a, ''))
606     end
608     def test_pretty_print_inspect
609       a = PrettyPrintInspect.new(1)
610       assert_equal("<pretty_print:1>", a.inspect)
611       a = PrettyPrintInspectWithoutPrettyPrint.new
612       assert_raise(RuntimeError) { a.inspect }
613     end
615     def test_proc
616       a = proc {1}
617       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
618     end
620     def test_to_s_with_iv
621       a = Object.new
622       def a.to_s() "aaa" end
623       a.instance_eval { @a = nil }
624       result = PP.pp(a, '')
625       assert_equal("#{a.inspect}\n", result)
626       assert_match(/\A#<Object.*>\n\z/m, result)
627       a = 1.0
628       a.instance_eval { @a = nil }
629       result = PP.pp(a, '')
630       assert_equal("#{a.inspect}\n", result)
631     end
632     
633     def test_to_s_without_iv
634       a = Object.new
635       def a.to_s() "aaa" end
636       result = PP.pp(a, '')
637       assert_equal("#{a.inspect}\n", result)
638       assert_equal("aaa\n", result)
639     end
640   end
642   class PPCycleTest < Test::Unit::TestCase
643     def test_array
644       a = []
645       a << a
646       assert_equal("[[...]]\n", PP.pp(a, ''))
647       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
648     end
650     def test_hash
651       a = {}
652       a[0] = a
653       assert_equal("{0=>{...}}\n", PP.pp(a, ''))
654       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
655     end
657     S = Struct.new("S", :a, :b)
658     def test_struct
659       a = S.new(1,2)
660       a.b = a
661       assert_equal("#<struct Struct::S a=1, b=#<struct Struct::S:...>>\n", PP.pp(a, ''))
662       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
663     end
665     def test_object
666       a = Object.new
667       a.instance_eval {@a = a}
668       assert_equal(a.inspect + "\n", PP.pp(a, ''))
669     end
671     def test_anonymous
672       a = Class.new.new
673       assert_equal(a.inspect + "\n", PP.pp(a, ''))
674     end
676     def test_withinspect
677       a = []
678       a << HasInspect.new(a)
679       assert_equal("[<inspect:[...]>]\n", PP.pp(a, ''))
680       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
681     end
683     def test_share_nil
684       begin
685         PP.sharing_detection = true
686         a = [nil, nil]
687         assert_equal("[nil, nil]\n", PP.pp(a, ''))
688       ensure
689         PP.sharing_detection = false
690       end
691     end
692   end
694   class PPSingleLineTest < Test::Unit::TestCase
695     def test_hash
696       assert_equal("{1=>1}", PP.singleline_pp({ 1 => 1}, '')) # [ruby-core:02699]
697       assert_equal("[1#{', 1'*99}]", PP.singleline_pp([1]*100, ''))
698     end
699   end