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)
|
---|
31 | #
|
---|
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.
|
---|
42 | #
|
---|
43 | # = Author
|
---|
44 | # Tanaka Akira <[email protected]>
|
---|
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 | #
|
---|
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
|
---|
66 |
|
---|
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
|
---|
82 |
|
---|
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
|
---|
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 | InspectKey = :__inspect_key__
|
---|
109 |
|
---|
110 | def guard_inspect_key
|
---|
111 | if Thread.current[InspectKey] == nil
|
---|
112 | Thread.current[InspectKey] = []
|
---|
113 | end
|
---|
114 |
|
---|
115 | save = Thread.current[InspectKey]
|
---|
116 |
|
---|
117 | begin
|
---|
118 | Thread.current[InspectKey] = []
|
---|
119 | yield
|
---|
120 | ensure
|
---|
121 | Thread.current[InspectKey] = save
|
---|
122 | end
|
---|
123 | end
|
---|
124 |
|
---|
125 | # Adds +obj+ to the pretty printing buffer
|
---|
126 | # using Object#pretty_print or Object#pretty_print_cycle.
|
---|
127 | #
|
---|
128 | # Object#pretty_print_cycle is used when +obj+ is already
|
---|
129 | # printed, a.k.a the object reference chain has a cycle.
|
---|
130 | def pp(obj)
|
---|
131 | id = obj.__id__
|
---|
132 |
|
---|
133 | if Thread.current[InspectKey].include? id
|
---|
134 | group {obj.pretty_print_cycle self}
|
---|
135 | return
|
---|
136 | end
|
---|
137 |
|
---|
138 | begin
|
---|
139 | Thread.current[InspectKey] << id
|
---|
140 | group {obj.pretty_print self}
|
---|
141 | ensure
|
---|
142 | Thread.current[InspectKey].pop unless PP.sharing_detection
|
---|
143 | end
|
---|
144 | end
|
---|
145 |
|
---|
146 | # A convenience method which is same as follows:
|
---|
147 | #
|
---|
148 | # group(1, '#<' + obj.class.name, '>') { ... }
|
---|
149 | def object_group(obj, &block) # :yield:
|
---|
150 | group(1, '#<' + obj.class.name, '>', &block)
|
---|
151 | end
|
---|
152 |
|
---|
153 | def object_address_group(obj, &block)
|
---|
154 | id = "%x" % (obj.__id__ * 2)
|
---|
155 | id.sub!(/\Af(?=[[:xdigit:]]{2}+\z)/, '') if id.sub!(/\A\.\./, '')
|
---|
156 | group(1, "\#<#{obj.class}:0x#{id}", '>', &block)
|
---|
157 | end
|
---|
158 |
|
---|
159 | # A convenience method which is same as follows:
|
---|
160 | #
|
---|
161 | # text ','
|
---|
162 | # breakable
|
---|
163 | def comma_breakable
|
---|
164 | text ','
|
---|
165 | breakable
|
---|
166 | end
|
---|
167 |
|
---|
168 | # Adds a separated list.
|
---|
169 | # The list is separated by comma with breakable space, by default.
|
---|
170 | #
|
---|
171 | # #seplist iterates the +list+ using +iter_method+.
|
---|
172 | # It yields each object to the block given for #seplist.
|
---|
173 | # The procedure +separator_proc+ is called between each yields.
|
---|
174 | #
|
---|
175 | # If the iteration is zero times, +separator_proc+ is not called at all.
|
---|
176 | #
|
---|
177 | # If +separator_proc+ is nil or not given,
|
---|
178 | # +lambda { comma_breakable }+ is used.
|
---|
179 | # If +iter_method+ is not given, :each is used.
|
---|
180 | #
|
---|
181 | # For example, following 3 code fragments has similar effect.
|
---|
182 | #
|
---|
183 | # q.seplist([1,2,3]) {|v| xxx v }
|
---|
184 | #
|
---|
185 | # q.seplist([1,2,3], lambda { comma_breakable }, :each) {|v| xxx v }
|
---|
186 | #
|
---|
187 | # xxx 1
|
---|
188 | # q.comma_breakable
|
---|
189 | # xxx 2
|
---|
190 | # q.comma_breakable
|
---|
191 | # xxx 3
|
---|
192 | def seplist(list, sep=nil, iter_method=:each) # :yield: element
|
---|
193 | sep ||= lambda { comma_breakable }
|
---|
194 | first = true
|
---|
195 | list.__send__(iter_method) {|*v|
|
---|
196 | if first
|
---|
197 | first = false
|
---|
198 | else
|
---|
199 | sep.call
|
---|
200 | end
|
---|
201 | yield(*v)
|
---|
202 | }
|
---|
203 | end
|
---|
204 |
|
---|
205 | def pp_object(obj)
|
---|
206 | object_address_group(obj) {
|
---|
207 | seplist(obj.pretty_print_instance_variables, lambda { text ',' }) {|v|
|
---|
208 | breakable
|
---|
209 | v = v.to_s if Symbol === v
|
---|
210 | text v
|
---|
211 | text '='
|
---|
212 | group(1) {
|
---|
213 | breakable ''
|
---|
214 | pp(obj.instance_eval(v))
|
---|
215 | }
|
---|
216 | }
|
---|
217 | }
|
---|
218 | end
|
---|
219 |
|
---|
220 | def pp_hash(obj)
|
---|
221 | group(1, '{', '}') {
|
---|
222 | seplist(obj, nil, :each_pair) {|k, v|
|
---|
223 | group {
|
---|
224 | pp k
|
---|
225 | text '=>'
|
---|
226 | group(1) {
|
---|
227 | breakable ''
|
---|
228 | pp v
|
---|
229 | }
|
---|
230 | }
|
---|
231 | }
|
---|
232 | }
|
---|
233 | end
|
---|
234 | end
|
---|
235 |
|
---|
236 | include PPMethods
|
---|
237 |
|
---|
238 | class SingleLine < PrettyPrint::SingleLine
|
---|
239 | include PPMethods
|
---|
240 | end
|
---|
241 |
|
---|
242 | module ObjectMixin
|
---|
243 | # 1. specific pretty_print
|
---|
244 | # 2. specific inspect
|
---|
245 | # 3. specific to_s if instance variable is empty
|
---|
246 | # 4. generic pretty_print
|
---|
247 |
|
---|
248 | # A default pretty printing method for general objects.
|
---|
249 | # It calls #pretty_print_instance_variables to list instance variables.
|
---|
250 | #
|
---|
251 | # If +self+ has a customized (redefined) #inspect method,
|
---|
252 | # the result of self.inspect is used but it obviously has no
|
---|
253 | # line break hints.
|
---|
254 | #
|
---|
255 | # This module provides predefined #pretty_print methods for some of
|
---|
256 | # the most commonly used built-in classes for convenience.
|
---|
257 | def pretty_print(q)
|
---|
258 | if /\(Kernel\)#/ !~ method(:inspect).inspect
|
---|
259 | q.text self.inspect
|
---|
260 | elsif /\(Kernel\)#/ !~ method(:to_s).inspect && instance_variables.empty?
|
---|
261 | q.text self.to_s
|
---|
262 | else
|
---|
263 | q.pp_object(self)
|
---|
264 | end
|
---|
265 | end
|
---|
266 |
|
---|
267 | # A default pretty printing method for general objects that are
|
---|
268 | # detected as part of a cycle.
|
---|
269 | def pretty_print_cycle(q)
|
---|
270 | q.object_address_group(self) {
|
---|
271 | q.breakable
|
---|
272 | q.text '...'
|
---|
273 | }
|
---|
274 | end
|
---|
275 |
|
---|
276 | # Returns a sorted array of instance variable names.
|
---|
277 | #
|
---|
278 | # This method should return an array of names of instance variables as symbols or strings as:
|
---|
279 | # +[:@a, :@b]+.
|
---|
280 | def pretty_print_instance_variables
|
---|
281 | instance_variables.sort
|
---|
282 | end
|
---|
283 |
|
---|
284 | # Is #inspect implementation using #pretty_print.
|
---|
285 | # If you implement #pretty_print, it can be used as follows.
|
---|
286 | #
|
---|
287 | # alias inspect pretty_print_inspect
|
---|
288 | #
|
---|
289 | # However, doing this requires that every class that #inspect is called on
|
---|
290 | # implement #pretty_print, or a RuntimeError will be raised.
|
---|
291 | def pretty_print_inspect
|
---|
292 | if /\(PP::ObjectMixin\)#/ =~ method(:pretty_print).inspect
|
---|
293 | raise "pretty_print is not overridden for #{self.class}"
|
---|
294 | end
|
---|
295 | PP.singleline_pp(self, '')
|
---|
296 | end
|
---|
297 | end
|
---|
298 | end
|
---|
299 |
|
---|
300 | class Array
|
---|
301 | def pretty_print(q)
|
---|
302 | q.group(1, '[', ']') {
|
---|
303 | q.seplist(self) {|v|
|
---|
304 | q.pp v
|
---|
305 | }
|
---|
306 | }
|
---|
307 | end
|
---|
308 |
|
---|
309 | def pretty_print_cycle(q)
|
---|
310 | q.text(empty? ? '[]' : '[...]')
|
---|
311 | end
|
---|
312 | end
|
---|
313 |
|
---|
314 | class Hash
|
---|
315 | def pretty_print(q)
|
---|
316 | q.pp_hash self
|
---|
317 | end
|
---|
318 |
|
---|
319 | def pretty_print_cycle(q)
|
---|
320 | q.text(empty? ? '{}' : '{...}')
|
---|
321 | end
|
---|
322 | end
|
---|
323 |
|
---|
324 | class << ENV
|
---|
325 | def pretty_print(q)
|
---|
326 | q.pp_hash self
|
---|
327 | end
|
---|
328 | end
|
---|
329 |
|
---|
330 | class Struct
|
---|
331 | def pretty_print(q)
|
---|
332 | q.group(1, '#<struct ' + PP.mcall(self, Kernel, :class).name, '>') {
|
---|
333 | q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
|
---|
334 | q.breakable
|
---|
335 | q.text member.to_s
|
---|
336 | q.text '='
|
---|
337 | q.group(1) {
|
---|
338 | q.breakable ''
|
---|
339 | q.pp self[member]
|
---|
340 | }
|
---|
341 | }
|
---|
342 | }
|
---|
343 | end
|
---|
344 |
|
---|
345 | def pretty_print_cycle(q)
|
---|
346 | q.text sprintf("#<struct %s:...>", PP.mcall(self, Kernel, :class).name)
|
---|
347 | end
|
---|
348 | end
|
---|
349 |
|
---|
350 | class Range
|
---|
351 | def pretty_print(q)
|
---|
352 | q.pp self.begin
|
---|
353 | q.breakable ''
|
---|
354 | q.text(self.exclude_end? ? '...' : '..')
|
---|
355 | q.breakable ''
|
---|
356 | q.pp self.end
|
---|
357 | end
|
---|
358 | end
|
---|
359 |
|
---|
360 | class File
|
---|
361 | class Stat
|
---|
362 | def pretty_print(q)
|
---|
363 | require 'etc.so'
|
---|
364 | q.object_group(self) {
|
---|
365 | q.breakable
|
---|
366 | q.text sprintf("dev=0x%x", self.dev); q.comma_breakable
|
---|
367 | q.text "ino="; q.pp self.ino; q.comma_breakable
|
---|
368 | q.group {
|
---|
369 | m = self.mode
|
---|
370 | q.text sprintf("mode=0%o", m)
|
---|
371 | q.breakable
|
---|
372 | q.text sprintf("(%s %c%c%c%c%c%c%c%c%c)",
|
---|
373 | self.ftype,
|
---|
374 | (m & 0400 == 0 ? ?- : ?r),
|
---|
375 | (m & 0200 == 0 ? ?- : ?w),
|
---|
376 | (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) :
|
---|
377 | (m & 04000 == 0 ? ?x : ?s)),
|
---|
378 | (m & 0040 == 0 ? ?- : ?r),
|
---|
379 | (m & 0020 == 0 ? ?- : ?w),
|
---|
380 | (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) :
|
---|
381 | (m & 02000 == 0 ? ?x : ?s)),
|
---|
382 | (m & 0004 == 0 ? ?- : ?r),
|
---|
383 | (m & 0002 == 0 ? ?- : ?w),
|
---|
384 | (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) :
|
---|
385 | (m & 01000 == 0 ? ?x : ?t)))
|
---|
386 | }
|
---|
387 | q.comma_breakable
|
---|
388 | q.text "nlink="; q.pp self.nlink; q.comma_breakable
|
---|
389 | q.group {
|
---|
390 | q.text "uid="; q.pp self.uid
|
---|
391 | begin
|
---|
392 | pw = Etc.getpwuid(self.uid)
|
---|
393 | rescue ArgumentError
|
---|
394 | end
|
---|
395 | if pw
|
---|
396 | q.breakable; q.text "(#{pw.name})"
|
---|
397 | end
|
---|
398 | }
|
---|
399 | q.comma_breakable
|
---|
400 | q.group {
|
---|
401 | q.text "gid="; q.pp self.gid
|
---|
402 | begin
|
---|
403 | gr = Etc.getgrgid(self.gid)
|
---|
404 | rescue ArgumentError
|
---|
405 | end
|
---|
406 | if gr
|
---|
407 | q.breakable; q.text "(#{gr.name})"
|
---|
408 | end
|
---|
409 | }
|
---|
410 | q.comma_breakable
|
---|
411 | q.group {
|
---|
412 | q.text sprintf("rdev=0x%x", self.rdev)
|
---|
413 | q.breakable
|
---|
414 | q.text sprintf('(%d, %d)', self.rdev_major, self.rdev_minor)
|
---|
415 | }
|
---|
416 | q.comma_breakable
|
---|
417 | q.text "size="; q.pp self.size; q.comma_breakable
|
---|
418 | q.text "blksize="; q.pp self.blksize; q.comma_breakable
|
---|
419 | q.text "blocks="; q.pp self.blocks; q.comma_breakable
|
---|
420 | q.group {
|
---|
421 | t = self.atime
|
---|
422 | q.text "atime="; q.pp t
|
---|
423 | q.breakable; q.text "(#{t.tv_sec})"
|
---|
424 | }
|
---|
425 | q.comma_breakable
|
---|
426 | q.group {
|
---|
427 | t = self.mtime
|
---|
428 | q.text "mtime="; q.pp t
|
---|
429 | q.breakable; q.text "(#{t.tv_sec})"
|
---|
430 | }
|
---|
431 | q.comma_breakable
|
---|
432 | q.group {
|
---|
433 | t = self.ctime
|
---|
434 | q.text "ctime="; q.pp t
|
---|
435 | q.breakable; q.text "(#{t.tv_sec})"
|
---|
436 | }
|
---|
437 | }
|
---|
438 | end
|
---|
439 | end
|
---|
440 | end
|
---|
441 |
|
---|
442 | class MatchData
|
---|
443 | def pretty_print(q)
|
---|
444 | q.object_group(self) {
|
---|
445 | q.breakable
|
---|
446 | q.seplist(1..self.size, lambda { q.breakable }) {|i|
|
---|
447 | q.pp self[i-1]
|
---|
448 | }
|
---|
449 | }
|
---|
450 | end
|
---|
451 | end
|
---|
452 |
|
---|
453 | class Object
|
---|
454 | include PP::ObjectMixin
|
---|
455 | end
|
---|
456 |
|
---|
457 | [Numeric, Symbol, FalseClass, TrueClass, NilClass, Module].each {|c|
|
---|
458 | c.class_eval {
|
---|
459 | def pretty_print_cycle(q)
|
---|
460 | q.text inspect
|
---|
461 | end
|
---|
462 | }
|
---|
463 | }
|
---|
464 |
|
---|
465 | [Numeric, FalseClass, TrueClass, Module].each {|c|
|
---|
466 | c.class_eval {
|
---|
467 | def pretty_print(q)
|
---|
468 | q.text inspect
|
---|
469 | end
|
---|
470 | }
|
---|
471 | }
|
---|
472 |
|
---|
473 | # :enddoc:
|
---|
474 | if __FILE__ == $0
|
---|
475 | require 'test/unit'
|
---|
476 |
|
---|
477 | class PPTest < Test::Unit::TestCase
|
---|
478 | def test_list0123_12
|
---|
479 | assert_equal("[0, 1, 2, 3]\n", PP.pp([0,1,2,3], '', 12))
|
---|
480 | end
|
---|
481 |
|
---|
482 | def test_list0123_11
|
---|
483 | assert_equal("[0,\n 1,\n 2,\n 3]\n", PP.pp([0,1,2,3], '', 11))
|
---|
484 | end
|
---|
485 |
|
---|
486 | OverriddenStruct = Struct.new("OverriddenStruct", :members, :class)
|
---|
487 | def test_struct_override_members # [ruby-core:7865]
|
---|
488 | a = OverriddenStruct.new(1,2)
|
---|
489 | assert_equal("#<struct Struct::OverriddenStruct members=1, class=2>\n", PP.pp(a, ''))
|
---|
490 | end
|
---|
491 | end
|
---|
492 |
|
---|
493 | class HasInspect
|
---|
494 | def initialize(a)
|
---|
495 | @a = a
|
---|
496 | end
|
---|
497 |
|
---|
498 | def inspect
|
---|
499 | return "<inspect:#{@a.inspect}>"
|
---|
500 | end
|
---|
501 | end
|
---|
502 |
|
---|
503 | class HasPrettyPrint
|
---|
504 | def initialize(a)
|
---|
505 | @a = a
|
---|
506 | end
|
---|
507 |
|
---|
508 | def pretty_print(q)
|
---|
509 | q.text "<pretty_print:"
|
---|
510 | q.pp @a
|
---|
511 | q.text ">"
|
---|
512 | end
|
---|
513 | end
|
---|
514 |
|
---|
515 | class HasBoth
|
---|
516 | def initialize(a)
|
---|
517 | @a = a
|
---|
518 | end
|
---|
519 |
|
---|
520 | def inspect
|
---|
521 | return "<inspect:#{@a.inspect}>"
|
---|
522 | end
|
---|
523 |
|
---|
524 | def pretty_print(q)
|
---|
525 | q.text "<pretty_print:"
|
---|
526 | q.pp @a
|
---|
527 | q.text ">"
|
---|
528 | end
|
---|
529 | end
|
---|
530 |
|
---|
531 | class PrettyPrintInspect < HasPrettyPrint
|
---|
532 | alias inspect pretty_print_inspect
|
---|
533 | end
|
---|
534 |
|
---|
535 | class PrettyPrintInspectWithoutPrettyPrint
|
---|
536 | alias inspect pretty_print_inspect
|
---|
537 | end
|
---|
538 |
|
---|
539 | class PPInspectTest < Test::Unit::TestCase
|
---|
540 | def test_hasinspect
|
---|
541 | a = HasInspect.new(1)
|
---|
542 | assert_equal("<inspect:1>\n", PP.pp(a, ''))
|
---|
543 | end
|
---|
544 |
|
---|
545 | def test_hasprettyprint
|
---|
546 | a = HasPrettyPrint.new(1)
|
---|
547 | assert_equal("<pretty_print:1>\n", PP.pp(a, ''))
|
---|
548 | end
|
---|
549 |
|
---|
550 | def test_hasboth
|
---|
551 | a = HasBoth.new(1)
|
---|
552 | assert_equal("<pretty_print:1>\n", PP.pp(a, ''))
|
---|
553 | end
|
---|
554 |
|
---|
555 | def test_pretty_print_inspect
|
---|
556 | a = PrettyPrintInspect.new(1)
|
---|
557 | assert_equal("<pretty_print:1>", a.inspect)
|
---|
558 | a = PrettyPrintInspectWithoutPrettyPrint.new
|
---|
559 | assert_raise(RuntimeError) { a.inspect }
|
---|
560 | end
|
---|
561 |
|
---|
562 | def test_proc
|
---|
563 | a = proc {1}
|
---|
564 | assert_equal("#{a.inspect}\n", PP.pp(a, ''))
|
---|
565 | end
|
---|
566 |
|
---|
567 | def test_to_s_with_iv
|
---|
568 | a = Object.new
|
---|
569 | def a.to_s() "aaa" end
|
---|
570 | a.instance_eval { @a = nil }
|
---|
571 | result = PP.pp(a, '')
|
---|
572 | assert_equal("#{a.inspect}\n", result)
|
---|
573 | assert_match(/\A#<Object.*>\n\z/m, result)
|
---|
574 | a = 1.0
|
---|
575 | a.instance_eval { @a = nil }
|
---|
576 | result = PP.pp(a, '')
|
---|
577 | assert_equal("#{a.inspect}\n", result)
|
---|
578 | end
|
---|
579 |
|
---|
580 | def test_to_s_without_iv
|
---|
581 | a = Object.new
|
---|
582 | def a.to_s() "aaa" end
|
---|
583 | result = PP.pp(a, '')
|
---|
584 | assert_equal("#{a.inspect}\n", result)
|
---|
585 | assert_equal("aaa\n", result)
|
---|
586 | end
|
---|
587 | end
|
---|
588 |
|
---|
589 | class PPCycleTest < Test::Unit::TestCase
|
---|
590 | def test_array
|
---|
591 | a = []
|
---|
592 | a << a
|
---|
593 | assert_equal("[[...]]\n", PP.pp(a, ''))
|
---|
594 | assert_equal("#{a.inspect}\n", PP.pp(a, ''))
|
---|
595 | end
|
---|
596 |
|
---|
597 | def test_hash
|
---|
598 | a = {}
|
---|
599 | a[0] = a
|
---|
600 | assert_equal("{0=>{...}}\n", PP.pp(a, ''))
|
---|
601 | assert_equal("#{a.inspect}\n", PP.pp(a, ''))
|
---|
602 | end
|
---|
603 |
|
---|
604 | S = Struct.new("S", :a, :b)
|
---|
605 | def test_struct
|
---|
606 | a = S.new(1,2)
|
---|
607 | a.b = a
|
---|
608 | assert_equal("#<struct Struct::S a=1, b=#<struct Struct::S:...>>\n", PP.pp(a, ''))
|
---|
609 | assert_equal("#{a.inspect}\n", PP.pp(a, ''))
|
---|
610 | end
|
---|
611 |
|
---|
612 | def test_object
|
---|
613 | a = Object.new
|
---|
614 | a.instance_eval {@a = a}
|
---|
615 | assert_equal(a.inspect + "\n", PP.pp(a, ''))
|
---|
616 | end
|
---|
617 |
|
---|
618 | def test_anonymous
|
---|
619 | a = Class.new.new
|
---|
620 | assert_equal(a.inspect + "\n", PP.pp(a, ''))
|
---|
621 | end
|
---|
622 |
|
---|
623 | def test_withinspect
|
---|
624 | a = []
|
---|
625 | a << HasInspect.new(a)
|
---|
626 | assert_equal("[<inspect:[...]>]\n", PP.pp(a, ''))
|
---|
627 | assert_equal("#{a.inspect}\n", PP.pp(a, ''))
|
---|
628 | end
|
---|
629 |
|
---|
630 | def test_share_nil
|
---|
631 | begin
|
---|
632 | PP.sharing_detection = true
|
---|
633 | a = [nil, nil]
|
---|
634 | assert_equal("[nil, nil]\n", PP.pp(a, ''))
|
---|
635 | ensure
|
---|
636 | PP.sharing_detection = false
|
---|
637 | end
|
---|
638 | end
|
---|
639 | end
|
---|
640 |
|
---|
641 | class PPSingleLineTest < Test::Unit::TestCase
|
---|
642 | def test_hash
|
---|
643 | assert_equal("{1=>1}", PP.singleline_pp({ 1 => 1}, '')) # [ruby-core:02699]
|
---|
644 | assert_equal("[1#{', 1'*99}]", PP.singleline_pp([1]*100, ''))
|
---|
645 | end
|
---|
646 | end
|
---|
647 | end
|
---|