amazing_print 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/Appraisals +60 -0
  4. data/CHANGELOG.md +2 -0
  5. data/CONTRIBUTING.md +81 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +21 -0
  8. data/README.md +356 -0
  9. data/Rakefile +23 -0
  10. data/lib/amazing_print.rb +46 -0
  11. data/lib/amazing_print/colorize.rb +25 -0
  12. data/lib/amazing_print/core_ext/awesome_method_array.rb +82 -0
  13. data/lib/amazing_print/core_ext/class.rb +23 -0
  14. data/lib/amazing_print/core_ext/kernel.rb +25 -0
  15. data/lib/amazing_print/core_ext/logger.rb +21 -0
  16. data/lib/amazing_print/core_ext/method.rb +21 -0
  17. data/lib/amazing_print/core_ext/object.rb +23 -0
  18. data/lib/amazing_print/core_ext/string.rb +42 -0
  19. data/lib/amazing_print/custom_defaults.rb +57 -0
  20. data/lib/amazing_print/ext/action_view.rb +22 -0
  21. data/lib/amazing_print/ext/active_record.rb +103 -0
  22. data/lib/amazing_print/ext/active_support.rb +45 -0
  23. data/lib/amazing_print/ext/mongo_mapper.rb +125 -0
  24. data/lib/amazing_print/ext/mongoid.rb +68 -0
  25. data/lib/amazing_print/ext/nobrainer.rb +53 -0
  26. data/lib/amazing_print/ext/nokogiri.rb +45 -0
  27. data/lib/amazing_print/ext/ostruct.rb +27 -0
  28. data/lib/amazing_print/ext/ripple.rb +71 -0
  29. data/lib/amazing_print/ext/sequel.rb +55 -0
  30. data/lib/amazing_print/formatter.rb +120 -0
  31. data/lib/amazing_print/formatters.rb +14 -0
  32. data/lib/amazing_print/formatters/array_formatter.rb +139 -0
  33. data/lib/amazing_print/formatters/base_formatter.rb +148 -0
  34. data/lib/amazing_print/formatters/class_formatter.rb +24 -0
  35. data/lib/amazing_print/formatters/dir_formatter.rb +21 -0
  36. data/lib/amazing_print/formatters/file_formatter.rb +21 -0
  37. data/lib/amazing_print/formatters/hash_formatter.rb +106 -0
  38. data/lib/amazing_print/formatters/method_formatter.rb +21 -0
  39. data/lib/amazing_print/formatters/object_formatter.rb +82 -0
  40. data/lib/amazing_print/formatters/simple_formatter.rb +20 -0
  41. data/lib/amazing_print/formatters/struct_formatter.rb +74 -0
  42. data/lib/amazing_print/indentator.rb +17 -0
  43. data/lib/amazing_print/inspector.rb +175 -0
  44. data/lib/amazing_print/version.rb +10 -0
  45. data/lib/ap.rb +10 -0
  46. data/spec/active_record_helper.rb +30 -0
  47. data/spec/colors_spec.rb +114 -0
  48. data/spec/core_ext/logger_spec.rb +44 -0
  49. data/spec/core_ext/string_spec.rb +20 -0
  50. data/spec/ext/action_view_spec.rb +17 -0
  51. data/spec/ext/active_record_spec.rb +297 -0
  52. data/spec/ext/active_support_spec.rb +26 -0
  53. data/spec/ext/mongo_mapper_spec.rb +259 -0
  54. data/spec/ext/mongoid_spec.rb +66 -0
  55. data/spec/ext/nobrainer_spec.rb +58 -0
  56. data/spec/ext/nokogiri_spec.rb +50 -0
  57. data/spec/ext/ostruct_spec.rb +22 -0
  58. data/spec/ext/ripple_spec.rb +47 -0
  59. data/spec/formats_spec.rb +779 -0
  60. data/spec/methods_spec.rb +478 -0
  61. data/spec/misc_spec.rb +245 -0
  62. data/spec/objects_spec.rb +219 -0
  63. data/spec/spec_helper.rb +106 -0
  64. data/spec/support/active_record_data.rb +20 -0
  65. data/spec/support/active_record_data/3_2_diana.txt +24 -0
  66. data/spec/support/active_record_data/3_2_diana_legacy.txt +24 -0
  67. data/spec/support/active_record_data/3_2_multi.txt +50 -0
  68. data/spec/support/active_record_data/3_2_multi_legacy.txt +50 -0
  69. data/spec/support/active_record_data/4_0_diana.txt +98 -0
  70. data/spec/support/active_record_data/4_0_multi.txt +198 -0
  71. data/spec/support/active_record_data/4_1_diana.txt +97 -0
  72. data/spec/support/active_record_data/4_1_multi.txt +196 -0
  73. data/spec/support/active_record_data/4_2_diana.txt +109 -0
  74. data/spec/support/active_record_data/4_2_diana_legacy.txt +109 -0
  75. data/spec/support/active_record_data/4_2_multi.txt +220 -0
  76. data/spec/support/active_record_data/4_2_multi_legacy.txt +220 -0
  77. data/spec/support/active_record_data/5_0_diana.txt +105 -0
  78. data/spec/support/active_record_data/5_0_multi.txt +212 -0
  79. data/spec/support/active_record_data/5_1_diana.txt +104 -0
  80. data/spec/support/active_record_data/5_1_multi.txt +210 -0
  81. data/spec/support/active_record_data/5_2_diana.txt +104 -0
  82. data/spec/support/active_record_data/5_2_multi.txt +210 -0
  83. data/spec/support/active_record_data/6_0_diana.txt +104 -0
  84. data/spec/support/active_record_data/6_0_multi.txt +210 -0
  85. data/spec/support/ext_verifier.rb +41 -0
  86. data/spec/support/mongoid_versions.rb +22 -0
  87. data/spec/support/rails_versions.rb +50 -0
  88. metadata +243 -0
@@ -0,0 +1,120 @@
1
+ # Copyright (c) 2010-2016 Michael Dvorkin and contributors
2
+ #
3
+ # AmazingPrint is freely distributable under the terms of MIT license.
4
+ # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
5
+ #------------------------------------------------------------------------------
6
+ require 'amazing_print/formatters'
7
+
8
+ module AmazingPrint
9
+ class Formatter
10
+ include Colorize
11
+
12
+ attr_reader :inspector, :options
13
+
14
+ CORE_FORMATTERS = %i[array bigdecimal class dir file hash method rational set struct unboundmethod].freeze
15
+
16
+ def initialize(inspector)
17
+ @inspector = inspector
18
+ @options = inspector.options
19
+ end
20
+
21
+ # Main entry point to format an object.
22
+ #------------------------------------------------------------------------------
23
+ def format(object, type = nil)
24
+ core_class = cast(object, type)
25
+ awesome = if core_class != :self
26
+ send(:"awesome_#{core_class}", object) # Core formatters.
27
+ else
28
+ awesome_self(object, type) # Catch all that falls back to object.inspect.
29
+ end
30
+ awesome
31
+ end
32
+
33
+ # Hook this when adding custom formatters. Check out lib/amazing_print/ext
34
+ # directory for custom formatters that ship with amazing_print.
35
+ #------------------------------------------------------------------------------
36
+ def cast(_object, type)
37
+ CORE_FORMATTERS.include?(type) ? type : :self
38
+ end
39
+
40
+ private
41
+
42
+ # Catch all method to format an arbitrary object.
43
+ #------------------------------------------------------------------------------
44
+ def awesome_self(object, type)
45
+ if @options[:raw] && object.instance_variables.any?
46
+ awesome_object(object)
47
+ elsif (hash = convert_to_hash(object))
48
+ awesome_hash(hash)
49
+ else
50
+ awesome_simple(object.inspect.to_s, type, @inspector)
51
+ end
52
+ end
53
+
54
+ def awesome_bigdecimal(n)
55
+ o = n.to_s('F')
56
+ type = :bigdecimal
57
+ awesome_simple(o, type, @inspector)
58
+ end
59
+
60
+ def awesome_rational(n)
61
+ o = n.to_s
62
+ type = :rational
63
+ awesome_simple(o, type, @inspector)
64
+ end
65
+
66
+ def awesome_simple(o, type, inspector = @inspector)
67
+ AmazingPrint::Formatters::SimpleFormatter.new(o, type, inspector).format
68
+ end
69
+
70
+ def awesome_array(a)
71
+ Formatters::ArrayFormatter.new(a, @inspector).format
72
+ end
73
+
74
+ def awesome_set(s)
75
+ Formatters::ArrayFormatter.new(s.to_a, @inspector).format
76
+ end
77
+
78
+ def awesome_hash(h)
79
+ Formatters::HashFormatter.new(h, @inspector).format
80
+ end
81
+
82
+ def awesome_object(o)
83
+ Formatters::ObjectFormatter.new(o, @inspector).format
84
+ end
85
+
86
+ def awesome_struct(s)
87
+ Formatters::StructFormatter.new(s, @inspector).format
88
+ end
89
+
90
+ def awesome_method(m)
91
+ Formatters::MethodFormatter.new(m, @inspector).format
92
+ end
93
+ alias awesome_unboundmethod awesome_method
94
+
95
+ def awesome_class(c)
96
+ Formatters::ClassFormatter.new(c, @inspector).format
97
+ end
98
+
99
+ def awesome_file(f)
100
+ Formatters::FileFormatter.new(f, @inspector).format
101
+ end
102
+
103
+ def awesome_dir(d)
104
+ Formatters::DirFormatter.new(d, @inspector).format
105
+ end
106
+
107
+ # Utility methods.
108
+ #------------------------------------------------------------------------------
109
+ def convert_to_hash(object)
110
+ return nil unless object.respond_to?(:to_hash)
111
+
112
+ return nil if object.method(:to_hash).arity != 0
113
+
114
+ hash = object.to_hash
115
+ return nil if !hash.respond_to?(:keys) || !hash.respond_to?(:[])
116
+
117
+ hash
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,14 @@
1
+ module AmazingPrint
2
+ module Formatters
3
+ require 'amazing_print/formatters/object_formatter'
4
+ require 'amazing_print/formatters/struct_formatter'
5
+ require 'amazing_print/formatters/hash_formatter'
6
+ require 'amazing_print/formatters/array_formatter'
7
+ require 'amazing_print/formatters/simple_formatter'
8
+ require 'amazing_print/formatters/method_formatter'
9
+ require 'amazing_print/formatters/class_formatter'
10
+ require 'amazing_print/formatters/dir_formatter'
11
+ require 'amazing_print/formatters/file_formatter'
12
+ require 'amazing_print/colorize'
13
+ end
14
+ end
@@ -0,0 +1,139 @@
1
+ require_relative 'base_formatter'
2
+
3
+ module AmazingPrint
4
+ module Formatters
5
+ class ArrayFormatter < BaseFormatter
6
+ attr_reader :array, :inspector, :options
7
+
8
+ def initialize(array, inspector)
9
+ @array = array
10
+ @inspector = inspector
11
+ @options = inspector.options
12
+ end
13
+
14
+ def format
15
+ if array.length.zero?
16
+ '[]'
17
+ elsif methods_array?
18
+ methods_array
19
+ else
20
+ simple_array
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def methods_array?
27
+ array.instance_variable_defined?('@__awesome_methods__')
28
+ end
29
+
30
+ def simple_array
31
+ if options[:multiline]
32
+ multiline_array
33
+ else
34
+ '[ ' << array.map { |item| inspector.awesome(item) }.join(', ') << ' ]'
35
+ end
36
+ end
37
+
38
+ def multiline_array
39
+ data = if should_be_limited?
40
+ limited(generate_printable_array, width(array))
41
+ else
42
+ generate_printable_array
43
+ end
44
+
45
+ %([\n#{data.join(",\n")}\n#{outdent}])
46
+ end
47
+
48
+ def generate_printable_array
49
+ array.map.with_index do |item, index|
50
+ array_prefix(index, width(array)).tap do |temp|
51
+ indented { temp << inspector.awesome(item) }
52
+ end
53
+ end
54
+ end
55
+
56
+ def array_prefix(iteration, width)
57
+ generic_prefix(iteration, width)
58
+ end
59
+
60
+ def methods_array
61
+ array.map!(&:to_s).sort!
62
+
63
+ data = generate_printable_tuples.join("\n")
64
+
65
+ "[\n#{data}\n#{outdent}]"
66
+ end
67
+
68
+ def generate_printable_tuples
69
+ tuples.map.with_index do |item, index|
70
+ tuple_prefix(index, width(tuples)).tap do |temp|
71
+ indented { temp << tuple_template(item) }
72
+ end
73
+ end
74
+ end
75
+
76
+ def tuple_template(item)
77
+ name_width, args_width = name_and_args_width
78
+
79
+ [
80
+ colorize(item[0].rjust(name_width), :method),
81
+ colorize(item[1].ljust(args_width), :args),
82
+ ' ',
83
+ colorize(item[2], :class)
84
+ ].join
85
+ end
86
+
87
+ def tuples
88
+ @tuples ||= array.map { |name| generate_tuple(name) }
89
+ end
90
+
91
+ def name_and_args_width
92
+ name_and_args = tuples.transpose
93
+
94
+ [name_and_args[0].map(&:size).max, name_and_args[1].map(&:size).max]
95
+ end
96
+
97
+ def tuple_prefix(iteration, width)
98
+ generic_prefix(iteration, width, ' ')
99
+ end
100
+
101
+ def generate_tuple(name)
102
+ meth = case name
103
+ when Symbol, String
104
+ find_method(name)
105
+ end
106
+
107
+ meth ? method_tuple(meth) : [name.to_s, '(?)', '?']
108
+ end
109
+
110
+ def find_method(name)
111
+ object = array.instance_variable_get('@__awesome_methods__')
112
+
113
+ meth = begin
114
+ object.method(name)
115
+ rescue NameError, ArgumentError
116
+ nil
117
+ end
118
+
119
+ meth || begin
120
+ object.instance_method(name)
121
+ rescue NameError
122
+ nil
123
+ end
124
+ end
125
+
126
+ def generic_prefix(iteration, width, padding = '')
127
+ if options[:index]
128
+ indent + colorize("[#{iteration.to_s.rjust(width)}] ", :array)
129
+ else
130
+ indent + padding
131
+ end
132
+ end
133
+
134
+ def width(items)
135
+ (items.size - 1).to_s.size
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,148 @@
1
+ require_relative '../colorize'
2
+
3
+ module AmazingPrint
4
+ module Formatters
5
+ class BaseFormatter
6
+ include Colorize
7
+
8
+ DEFAULT_LIMIT_SIZE = 7
9
+
10
+ # To support limited output, for example:
11
+ #
12
+ # ap ('a'..'z').to_a, :limit => 3
13
+ # [
14
+ # [ 0] "a",
15
+ # [ 1] .. [24],
16
+ # [25] "z"
17
+ # ]
18
+ #
19
+ # ap (1..100).to_a, :limit => true # Default limit is 7.
20
+ # [
21
+ # [ 0] 1,
22
+ # [ 1] 2,
23
+ # [ 2] 3,
24
+ # [ 3] .. [96],
25
+ # [97] 98,
26
+ # [98] 99,
27
+ # [99] 100
28
+ # ]
29
+ #------------------------------------------------------------------------------
30
+ def should_be_limited?
31
+ options[:limit] || (options[:limit].is_a?(Integer) && (options[:limit] > 0))
32
+ end
33
+
34
+ def get_limit_size
35
+ case options[:limit]
36
+ when true
37
+ DEFAULT_LIMIT_SIZE
38
+ else
39
+ options[:limit]
40
+ end
41
+ end
42
+
43
+ def limited(data, width, is_hash = false)
44
+ limit = get_limit_size
45
+ if data.length <= limit
46
+ data
47
+ else
48
+ # Calculate how many elements to be displayed above and below the separator.
49
+ head = limit / 2
50
+ tail = head - (limit - 1) % 2
51
+
52
+ # Add the proper elements to the temp array and format the separator.
53
+ temp = data[0, head] + [nil] + data[-tail, tail]
54
+
55
+ temp[head] = if is_hash
56
+ "#{indent}#{data[head].strip} .. #{data[data.length - tail - 1].strip}"
57
+ else
58
+ "#{indent}[#{head.to_s.rjust(width)}] .. [#{data.length - tail - 1}]"
59
+ end
60
+
61
+ temp
62
+ end
63
+ end
64
+
65
+ def method_tuple(method)
66
+ if method.respond_to?(:parameters) # Ruby 1.9.2+
67
+ # See http://readruby.chengguangnan.com/methods#method-objects-parameters
68
+ # (mirror: http://archive.is/XguCA#selection-3381.1-3381.11)
69
+ args = method.parameters.inject([]) do |arr, (type, name)|
70
+ name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
71
+ arr << case type
72
+ when :req then name.to_s
73
+ when :opt, :rest then "*#{name}"
74
+ when :block then "&#{name}"
75
+ else '?'
76
+ end
77
+ end
78
+ else # See http://ruby-doc.org/core/classes/Method.html#M001902
79
+ args = (1..method.arity.abs).map { |i| "arg#{i}" }
80
+ args[-1] = "*#{args[-1]}" if method.arity < 0
81
+ end
82
+
83
+ # method.to_s formats to handle:
84
+ #
85
+ # #<Method: Fixnum#zero?>
86
+ # #<Method: Fixnum(Integer)#years>
87
+ # #<Method: User(#<Module:0x00000103207c00>)#_username>
88
+ # #<Method: User(id: integer, username: string).table_name>
89
+ # #<Method: User(id: integer, username: string)(ActiveRecord::Base).current>
90
+ # #<Method: #<Class:0x100c567f>(ActiveRecord::Querying)#first>
91
+ # #<UnboundMethod: Hello#world>
92
+ # #<UnboundMethod: Hello#world() /home/hs/code/amazing_print/spec/methods_spec.rb:68>
93
+ #
94
+ if method.to_s =~ /(Unbound)*Method: ((#<)?[^\/#]*)[#\.]/
95
+ unbound = Regexp.last_match(1) && '(unbound)'
96
+ klass = Regexp.last_match(2)
97
+ if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class?
98
+ klass.sub!(Regexp.last_match(1), '') # Yes, strip the fields leaving class name only.
99
+ end
100
+
101
+ owner = "#{klass}#{unbound}".gsub('(', ' (')
102
+ end
103
+
104
+ [method.name.to_s, "(#{args.join(', ')})", owner.to_s]
105
+ end
106
+
107
+ #
108
+ # Indentation related methods
109
+ #-----------------------------------------
110
+ def indentation
111
+ inspector.current_indentation
112
+ end
113
+
114
+ def indented(&blk)
115
+ inspector.increase_indentation(&blk)
116
+ end
117
+
118
+ # precompute common indentations
119
+ INDENT_CACHE = (0..100).map { |i| ' ' * i }.map(&:freeze).freeze
120
+
121
+ def indent(n = indentation)
122
+ INDENT_CACHE[n] || ' ' * n
123
+ end
124
+
125
+ def outdent
126
+ ' ' * (indentation - options[:indent].abs)
127
+ i = indentation - options[:indent].abs
128
+
129
+ INDENT_CACHE[i] || ' ' * i
130
+ end
131
+
132
+ def align(value, width)
133
+ if options[:multiline]
134
+ indent_option = options[:indent]
135
+ if indent_option > 0
136
+ value.rjust(width)
137
+ elsif indent_option == 0
138
+ "#{indent}#{value.ljust(width)}"
139
+ else
140
+ "#{indent(indentation + indent_option)}#{value.ljust(width)}"
141
+ end
142
+ else
143
+ value
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'base_formatter'
2
+
3
+ module AmazingPrint
4
+ module Formatters
5
+ class ClassFormatter < BaseFormatter
6
+ attr_reader :klass, :inspector, :options
7
+
8
+ def initialize(klass, inspector)
9
+ @klass = klass
10
+ @inspector = inspector
11
+ @options = inspector.options
12
+ end
13
+
14
+ def format
15
+ superclass = klass.superclass
16
+ if superclass
17
+ colorize("#{klass.inspect} < #{superclass}", :class)
18
+ else
19
+ colorize(klass.inspect, :class)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end