PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/jruby-1.1.6RC1/lib/ruby/1.8/pp.rb

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