Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 525 lines (481 sloc) 13.608 kB
511dc44 initial import
Laurent Sansonetti authored
1 # == Pretty-printer for Ruby objects.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
2 #
511dc44 initial import
Laurent Sansonetti authored
3 # = Which seems better?
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
4 #
511dc44 initial import
Laurent Sansonetti authored
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>>
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
7 #
511dc44 initial import
Laurent Sansonetti authored
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>
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
25 #
511dc44 initial import
Laurent Sansonetti authored
26 # I like the latter. If you do too, this library is for you.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
27 #
511dc44 initial import
Laurent Sansonetti authored
28 # = Usage
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
29 #
511dc44 initial import
Laurent Sansonetti authored
30 # pp(obj)
31 #
32 # output +obj+ to +$>+ in pretty printed format.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
33 #
511dc44 initial import
Laurent Sansonetti authored
34 # It returns +nil+.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
35 #
511dc44 initial import
Laurent Sansonetti authored
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.
42 #
43 # = Author
44 # Tanaka Akira <akr@m17n.org>
45
46 require 'prettyprint'
47
48 module Kernel
49 # returns a pretty printed object as a string.
50 def pretty_inspect
51 PP.pp(self, '')
52 end
53
54 private
55 # prints arguments in pretty form.
56 #
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
57 # pp returns argument(s).
511dc44 initial import
Laurent Sansonetti authored
58 def pp(*objs) # :doc:
59 objs.each {|obj|
60 PP.pp(obj)
61 }
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
62 objs.size <= 1 ? objs.first : objs
511dc44 initial import
Laurent Sansonetti authored
63 end
64 module_function :pp
65 end
66
67 class PP < PrettyPrint
68 # Outputs +obj+ to +out+ in pretty printed format of
69 # +width+ columns in width.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
70 #
511dc44 initial import
Laurent Sansonetti authored
71 # If +out+ is omitted, +$>+ is assumed.
72 # If +width+ is omitted, 79 is assumed.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
73 #
511dc44 initial import
Laurent Sansonetti authored
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
82
83 # Outputs +obj+ to +out+ like PP.pp but with no indent and
84 # newline.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
85 #
511dc44 initial import
Laurent Sansonetti authored
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
93
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:
99
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
106
107 module PPMethods
108 def guard_inspect_key
109 if Thread.current[:__recursive_key__] == nil
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
110 Thread.current[:__recursive_key__] = {}.untrust
511dc44 initial import
Laurent Sansonetti authored
111 end
112
113 if Thread.current[:__recursive_key__][:inspect] == nil
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
114 Thread.current[:__recursive_key__][:inspect] = {}.untrust
511dc44 initial import
Laurent Sansonetti authored
115 end
116
117 save = Thread.current[:__recursive_key__][:inspect]
118
119 begin
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
120 Thread.current[:__recursive_key__][:inspect] = {}.untrust
511dc44 initial import
Laurent Sansonetti authored
121 yield
122 ensure
123 Thread.current[:__recursive_key__][:inspect] = save
124 end
125 end
126
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
138
139 # Adds +obj+ to the pretty printing buffer
140 # using Object#pretty_print or Object#pretty_print_cycle.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
141 #
511dc44 initial import
Laurent Sansonetti authored
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
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
146
511dc44 initial import
Laurent Sansonetti authored
147 if check_inspect_key(id)
148 group {obj.pretty_print_cycle self}
149 return
150 end
151
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
159
160 # A convenience method which is same as follows:
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
161 #
511dc44 initial import
Laurent Sansonetti authored
162 # group(1, '#<' + obj.class.name, '>') { ... }
163 def object_group(obj, &block) # :yield:
164 group(1, '#<' + obj.class.name, '>', &block)
165 end
166
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
167 PointerMask = (1 << ([""].pack("p").size * 8)) - 1
511dc44 initial import
Laurent Sansonetti authored
168
169 case Object.new.inspect
170 when /\A\#<Object:0x([0-9a-f]+)>\z/
171 PointerFormat = "%0#{$1.length}x"
172 else
173 PointerFormat = "%x"
174 end
175
176 def object_address_group(obj, &block)
177 id = PointerFormat % (obj.object_id * 2 & PointerMask)
178 group(1, "\#<#{obj.class}:0x#{id}", '>', &block)
179 end
180
181 # A convenience method which is same as follows:
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
182 #
511dc44 initial import
Laurent Sansonetti authored
183 # text ','
184 # breakable
185 def comma_breakable
186 text ','
187 breakable
188 end
189
190 # Adds a separated list.
191 # The list is separated by comma with breakable space, by default.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
192 #
511dc44 initial import
Laurent Sansonetti authored
193 # #seplist iterates the +list+ using +iter_method+.
194 # It yields each object to the block given for #seplist.
195 # The procedure +separator_proc+ is called between each yields.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
196 #
511dc44 initial import
Laurent Sansonetti authored
197 # If the iteration is zero times, +separator_proc+ is not called at all.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
198 #
511dc44 initial import
Laurent Sansonetti authored
199 # If +separator_proc+ is nil or not given,
200 # +lambda { comma_breakable }+ is used.
201 # If +iter_method+ is not given, :each is used.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
202 #
511dc44 initial import
Laurent Sansonetti authored
203 # For example, following 3 code fragments has similar effect.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
204 #
511dc44 initial import
Laurent Sansonetti authored
205 # q.seplist([1,2,3]) {|v| xxx v }
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
206 #
511dc44 initial import
Laurent Sansonetti authored
207 # q.seplist([1,2,3], lambda { q.comma_breakable }, :each) {|v| xxx v }
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
208 #
511dc44 initial import
Laurent Sansonetti authored
209 # xxx 1
210 # q.comma_breakable
211 # xxx 2
212 # q.comma_breakable
213 # xxx 3
214 def seplist(list, sep=nil, iter_method=:each) # :yield: element
215 sep ||= lambda { comma_breakable }
216 first = true
217 list.__send__(iter_method) {|*v|
218 if first
219 first = false
220 else
221 sep.call
222 end
223 yield(*v)
224 }
225 end
226
227 def pp_object(obj)
228 object_address_group(obj) {
229 seplist(obj.pretty_print_instance_variables, lambda { text ',' }) {|v|
230 breakable
231 v = v.to_s if Symbol === v
232 text v
233 text '='
234 group(1) {
235 breakable ''
236 pp(obj.instance_eval(v))
237 }
238 }
239 }
240 end
241
242 def pp_hash(obj)
243 group(1, '{', '}') {
244 seplist(obj, nil, :each_pair) {|k, v|
245 group {
246 pp k
247 text '=>'
248 group(1) {
249 breakable ''
250 pp v
251 }
252 }
253 }
254 }
255 end
256 end
257
258 include PPMethods
259
260 class SingleLine < PrettyPrint::SingleLine
261 include PPMethods
262 end
263
264 module ObjectMixin
265 # 1. specific pretty_print
266 # 2. specific inspect
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
267 # 3. specific to_s
511dc44 initial import
Laurent Sansonetti authored
268 # 4. generic pretty_print
269
270 # A default pretty printing method for general objects.
271 # It calls #pretty_print_instance_variables to list instance variables.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
272 #
511dc44 initial import
Laurent Sansonetti authored
273 # If +self+ has a customized (redefined) #inspect method,
274 # the result of self.inspect is used but it obviously has no
275 # line break hints.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
276 #
511dc44 initial import
Laurent Sansonetti authored
277 # This module provides predefined #pretty_print methods for some of
278 # the most commonly used built-in classes for convenience.
279 def pretty_print(q)
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
280 method_method = Object.instance_method(:method).bind(self)
281 begin
282 inspect_method = method_method.call(:inspect)
283 rescue NameError
284 end
285 begin
286 to_s_method = method_method.call(:to_s)
287 rescue NameError
288 end
289 if inspect_method && /\(Kernel\)#/ !~ inspect_method.inspect
290 q.text self.inspect
291 elsif !inspect_method && self.respond_to?(:inspect)
511dc44 initial import
Laurent Sansonetti authored
292 q.text self.inspect
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
293 elsif to_s_method && /\(Kernel\)#/ !~ to_s_method.inspect
294 q.text self.to_s
295 elsif !to_s_method && self.respond_to?(:to_s)
511dc44 initial import
Laurent Sansonetti authored
296 q.text self.to_s
297 else
298 q.pp_object(self)
299 end
300 end
301
302 # A default pretty printing method for general objects that are
303 # detected as part of a cycle.
304 def pretty_print_cycle(q)
305 q.object_address_group(self) {
306 q.breakable
307 q.text '...'
308 }
309 end
310
311 # Returns a sorted array of instance variable names.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
312 #
511dc44 initial import
Laurent Sansonetti authored
313 # This method should return an array of names of instance variables as symbols or strings as:
314 # +[:@a, :@b]+.
315 def pretty_print_instance_variables
316 instance_variables.sort
317 end
318
319 # Is #inspect implementation using #pretty_print.
320 # If you implement #pretty_print, it can be used as follows.
8f21162 @richkilmer bring lib up to r22701 (ruby 1.9.1_0 tag). there are build issues us…
richkilmer authored
321 #
511dc44 initial import
Laurent Sansonetti authored
322 # alias inspect pretty_print_inspect
323 #
324 # However, doing this requires that every class that #inspect is called on
325 # implement #pretty_print, or a RuntimeError will be raised.
326 def pretty_print_inspect
327 if /\(PP::ObjectMixin\)#/ =~ Object.instance_method(:method).bind(self).call(:pretty_print).inspect
328 raise "pretty_print is not overridden for #{self.class}"
329 end
330 PP.singleline_pp(self, '')
331 end
332 end
333 end
334
335 class Array
336 def pretty_print(q)
337 q.group(1, '[', ']') {
338 q.seplist(self) {|v|
339 q.pp v
340 }
341 }
342 end
343
344 def pretty_print_cycle(q)
345 q.text(empty? ? '[]' : '[...]')
346 end
347 end
348
349 class Hash
350 def pretty_print(q)
351 q.pp_hash self
352 end
353
354 def pretty_print_cycle(q)
355 q.text(empty? ? '{}' : '{...}')
356 end
357 end
358
359 class << ENV
360 def pretty_print(q)
361 h = {}
362 ENV.keys.sort.each {|k|
363 h[k] = ENV[k]
364 }
365 q.pp_hash h
366 end
367 end
368
369 class Struct
370 def pretty_print(q)
467bc1b Update library and removing working tags
Thibault Martin-Lagardette authored
371 q.group(1, sprintf("#<struct %s", PP.mcall(self, Kernel, :class).name), '>') {
511dc44 initial import
Laurent Sansonetti authored
372 q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
373 q.breakable
374 q.text member.to_s
375 q.text '='
376 q.group(1) {
377 q.breakable ''
378 q.pp self[member]
379 }
380 }
381 }
382 end
383
384 def pretty_print_cycle(q)
385 q.text sprintf("#<struct %s:...>", PP.mcall(self, Kernel, :class).name)
386 end
387 end
388
389 class Range
390 def pretty_print(q)
391 q.pp self.begin
392 q.breakable ''
393 q.text(self.exclude_end? ? '...' : '..')
394 q.breakable ''
395 q.pp self.end
396 end
397 end
398
399 class File
400 class Stat
401 def pretty_print(q)
75f2ab2 require 'etc' not 'etc.so'
Laurent Sansonetti authored
402 require 'etc'
511dc44 initial import
Laurent Sansonetti authored
403 q.object_group(self) {
404 q.breakable
405 q.text sprintf("dev=0x%x", self.dev); q.comma_breakable
406 q.text "ino="; q.pp self.ino; q.comma_breakable
407 q.group {
408 m = self.mode
409 q.text sprintf("mode=0%o", m)
410 q.breakable
411 q.text sprintf("(%s %c%c%c%c%c%c%c%c%c)",
412 self.ftype,
413 (m & 0400 == 0 ? ?- : ?r),
414 (m & 0200 == 0 ? ?- : ?w),
415 (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) :
416 (m & 04000 == 0 ? ?x : ?s)),
417 (m & 0040 == 0 ? ?- : ?r),
418 (m & 0020 == 0 ? ?- : ?w),
419 (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) :
420 (m & 02000 == 0 ? ?x : ?s)),
421 (m & 0004 == 0 ? ?- : ?r),
422 (m & 0002 == 0 ? ?- : ?w),
423 (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) :
424 (m & 01000 == 0 ? ?x : ?t)))
425 }
426 q.comma_breakable
427 q.text "nlink="; q.pp self.nlink; q.comma_breakable
428 q.group {
429 q.text "uid="; q.pp self.uid
430 begin
431 pw = Etc.getpwuid(self.uid)
432 rescue ArgumentError
433 end
434 if pw
435 q.breakable; q.text "(#{pw.name})"
436 end
437 }
438 q.comma_breakable
439 q.group {
440 q.text "gid="; q.pp self.gid
441 begin
442 gr = Etc.getgrgid(self.gid)
443 rescue ArgumentError
444 end
445 if gr
446 q.breakable; q.text "(#{gr.name})"
447 end
448 }
449 q.comma_breakable
450 q.group {
451 q.text sprintf("rdev=0x%x", self.rdev)
452 q.breakable
453 q.text sprintf('(%d, %d)', self.rdev_major, self.rdev_minor)
454 }
455 q.comma_breakable
456 q.text "size="; q.pp self.size; q.comma_breakable
457 q.text "blksize="; q.pp self.blksize; q.comma_breakable
458 q.text "blocks="; q.pp self.blocks; q.comma_breakable
459 q.group {
460 t = self.atime
461 q.text "atime="; q.pp t
462 q.breakable; q.text "(#{t.tv_sec})"
463 }
464 q.comma_breakable
465 q.group {
466 t = self.mtime
467 q.text "mtime="; q.pp t
468 q.breakable; q.text "(#{t.tv_sec})"
469 }
470 q.comma_breakable
471 q.group {
472 t = self.ctime
473 q.text "ctime="; q.pp t
474 q.breakable; q.text "(#{t.tv_sec})"
475 }
476 }
477 end
478 end
479 end
480
481 class MatchData
482 def pretty_print(q)
483 nc = []
484 self.regexp.named_captures.each {|name, indexes|
485 indexes.each {|i| nc[i] = name }
486 }
487 q.object_group(self) {
488 q.breakable
489 q.seplist(0...self.size, lambda { q.breakable }) {|i|
490 if i == 0
491 q.pp self[i]
492 else
493 if nc[i]
494 q.text nc[i]
495 else
496 q.pp i
497 end
498 q.text ':'
499 q.pp self[i]
500 end
501 }
502 }
503 end
504 end
505
506 class Object
507 include PP::ObjectMixin
508 end
509
510 [Numeric, Symbol, FalseClass, TrueClass, NilClass, Module].each {|c|
511 c.class_eval {
512 def pretty_print_cycle(q)
513 q.text inspect
514 end
515 }
516 }
517
518 [Numeric, FalseClass, TrueClass, Module].each {|c|
519 c.class_eval {
520 def pretty_print(q)
521 q.text inspect
522 end
523 }
524 }
Something went wrong with that request. Please try again.