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,21 @@
1
+ require_relative 'base_formatter'
2
+ require 'shellwords'
3
+
4
+ module AmazingPrint
5
+ module Formatters
6
+ class DirFormatter < BaseFormatter
7
+ attr_reader :dir, :inspector, :options
8
+
9
+ def initialize(dir, inspector)
10
+ @dir = dir
11
+ @inspector = inspector
12
+ @options = inspector.options
13
+ end
14
+
15
+ def format
16
+ ls = `ls -alF #{dir.path.shellescape}`
17
+ colorize(ls.empty? ? dir.inspect : "#{dir.inspect}\n#{ls.chop}", :dir)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'base_formatter'
2
+ require 'shellwords'
3
+
4
+ module AmazingPrint
5
+ module Formatters
6
+ class FileFormatter < BaseFormatter
7
+ attr_reader :file, :inspector, :options
8
+
9
+ def initialize(file, inspector)
10
+ @file = file
11
+ @inspector = inspector
12
+ @options = inspector.options
13
+ end
14
+
15
+ def format
16
+ ls = File.directory?(file) ? `ls -adlF #{file.path.shellescape}` : `ls -alF #{file.path.shellescape}`
17
+ colorize(ls.empty? ? file.inspect : "#{file.inspect}\n#{ls.chop}", :file)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,106 @@
1
+ require_relative 'base_formatter'
2
+
3
+ module AmazingPrint
4
+ module Formatters
5
+ class HashFormatter < BaseFormatter
6
+ attr_reader :hash, :inspector, :options
7
+
8
+ def initialize(hash, inspector)
9
+ @hash = hash
10
+ @inspector = inspector
11
+ @options = inspector.options
12
+ end
13
+
14
+ def format
15
+ if hash.empty?
16
+ empty_hash
17
+ elsif multiline_hash?
18
+ multiline_hash
19
+ else
20
+ simple_hash
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def empty_hash
27
+ '{}'
28
+ end
29
+
30
+ def multiline_hash?
31
+ options[:multiline]
32
+ end
33
+
34
+ def multiline_hash
35
+ ["{\n", printable_hash.join(",\n"), "\n#{outdent}}"].join
36
+ end
37
+
38
+ def simple_hash
39
+ "{ #{printable_hash.join(', ')} }"
40
+ end
41
+
42
+ def printable_hash
43
+ data = printable_keys
44
+ width = left_width(data)
45
+
46
+ data.map! do |key, value|
47
+ indented do
48
+ if options[:ruby19_syntax] && symbol?(key)
49
+ ruby19_syntax(key, value, width)
50
+ else
51
+ pre_ruby19_syntax(key, value, width)
52
+ end
53
+ end
54
+ end
55
+
56
+ should_be_limited? ? limited(data, width, hash: true) : data
57
+ end
58
+
59
+ def left_width(keys)
60
+ result = max_key_width(keys)
61
+ result += indentation if options[:indent] > 0
62
+ result
63
+ end
64
+
65
+ def max_key_width(keys)
66
+ keys.map { |key, _value| key.size }.max || 0
67
+ end
68
+
69
+ def printable_keys
70
+ keys = hash.keys
71
+
72
+ keys.sort! { |a, b| a.to_s <=> b.to_s } if options[:sort_keys]
73
+
74
+ keys.map! do |key|
75
+ plain_single_line do
76
+ [inspector.awesome(key), hash[key]]
77
+ end
78
+ end
79
+ end
80
+
81
+ def symbol?(key)
82
+ key[0] == ':'
83
+ end
84
+
85
+ def ruby19_syntax(key, value, width)
86
+ key[0] = ''
87
+ align(key, width - 1) << colorize(': ', :hash) << inspector.awesome(value)
88
+ end
89
+
90
+ def pre_ruby19_syntax(key, value, width)
91
+ align(key, width) << colorize(' => ', :hash) << inspector.awesome(value)
92
+ end
93
+
94
+ def plain_single_line
95
+ plain = options[:plain]
96
+ multiline = options[:multiline]
97
+ options[:plain] = true
98
+ options[:multiline] = false
99
+ yield
100
+ ensure
101
+ options[:plain] = plain
102
+ options[:multiline] = multiline
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'base_formatter'
2
+
3
+ module AmazingPrint
4
+ module Formatters
5
+ class MethodFormatter < BaseFormatter
6
+ attr_reader :method, :inspector, :options
7
+
8
+ def initialize(method, inspector)
9
+ @method = method
10
+ @inspector = inspector
11
+ @options = inspector.options
12
+ end
13
+
14
+ def format
15
+ name, args, owner = method_tuple(method)
16
+
17
+ "#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,82 @@
1
+ require_relative 'base_formatter'
2
+
3
+ module AmazingPrint
4
+ module Formatters
5
+ class ObjectFormatter < BaseFormatter
6
+ attr_reader :object, :variables, :inspector, :options
7
+
8
+ def initialize(object, inspector)
9
+ @object = object
10
+ @variables = object.instance_variables
11
+ @inspector = inspector
12
+ @options = inspector.options
13
+ end
14
+
15
+ def format
16
+ vars = variables.map do |var|
17
+ property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet.
18
+ accessor = if object.respond_to?(:"#{property}=")
19
+ object.respond_to?(property) ? :accessor : :writer
20
+ else
21
+ object.respond_to?(property) ? :reader : nil
22
+ end
23
+ if accessor
24
+ ["attr_#{accessor} :#{property}", var]
25
+ else
26
+ [var.to_s, var]
27
+ end
28
+ end
29
+
30
+ data = (options[:sort_vars] ? vars.sort : vars).map do |declaration, var|
31
+ key = left_aligned do
32
+ align(declaration, declaration.size)
33
+ end
34
+
35
+ unless options[:plain]
36
+ if key =~ /(@\w+)/
37
+ key.sub!(Regexp.last_match(1), colorize(Regexp.last_match(1), :variable))
38
+ else
39
+ key.sub!(/(attr_\w+)\s(\:\w+)/, "#{colorize('\\1', :keyword)} #{colorize('\\2', :method)}")
40
+ end
41
+ end
42
+
43
+ indented do
44
+ key << colorize(' = ', :hash) + inspector.awesome(object.instance_variable_get(var))
45
+ end
46
+ end
47
+
48
+ if options[:multiline]
49
+ "#<#{awesome_instance}\n#{data.join(%(,\n))}\n#{outdent}>"
50
+ else
51
+ "#<#{awesome_instance} #{data.join(', ')}>"
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def valid_instance_var?(variable_name)
58
+ variable_name.to_s.start_with?('@')
59
+ end
60
+
61
+ def awesome_instance
62
+ str = object.send(options[:class_name]).to_s
63
+ # We need to ensure that the original Kernel#format is used here instead of the one defined
64
+ # above.
65
+ # rubocop:disable Style/ColonMethodCall
66
+ if options[:object_id]
67
+ str << Kernel::format(':0x%08x', (object.__id__ * 2))
68
+ end
69
+ # rubocop:enable Style/ColonMethodCall
70
+ str
71
+ end
72
+
73
+ def left_aligned
74
+ current = options[:indent]
75
+ options[:indent] = 0
76
+ yield
77
+ ensure
78
+ options[:indent] = current
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'base_formatter'
2
+
3
+ module AmazingPrint
4
+ module Formatters
5
+ class SimpleFormatter < BaseFormatter
6
+ attr_reader :string, :type, :inspector, :options
7
+
8
+ def initialize(string, type, inspector)
9
+ @string = string
10
+ @type = type
11
+ @inspector = inspector
12
+ @options = inspector.options
13
+ end
14
+
15
+ def format
16
+ colorize(string, type)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'base_formatter'
2
+
3
+ module AmazingPrint
4
+ module Formatters
5
+ class StructFormatter < BaseFormatter
6
+ attr_reader :struct, :variables, :inspector, :options
7
+
8
+ def initialize(struct, inspector)
9
+ @struct = struct
10
+ @variables = struct.members
11
+ @inspector = inspector
12
+ @options = inspector.options
13
+ end
14
+
15
+ def format
16
+ vars = variables.map do |var|
17
+ property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet.
18
+ accessor = if struct.respond_to?(:"#{property}=")
19
+ struct.respond_to?(property) ? :accessor : :writer
20
+ else
21
+ struct.respond_to?(property) ? :reader : nil
22
+ end
23
+ if accessor
24
+ ["attr_#{accessor} :#{property}", var]
25
+ else
26
+ [var.to_s, var]
27
+ end
28
+ end
29
+
30
+ data = vars.sort.map do |declaration, var|
31
+ key = left_aligned do
32
+ align(declaration, declaration.size)
33
+ end
34
+
35
+ unless options[:plain]
36
+ if key =~ /(@\w+)/
37
+ key.sub!(Regexp.last_match(1), colorize(Regexp.last_match(1), :variable))
38
+ else
39
+ key.sub!(/(attr_\w+)\s(\:\w+)/, "#{colorize('\\1', :keyword)} #{colorize('\\2', :method)}")
40
+ end
41
+ end
42
+
43
+ indented do
44
+ key << colorize(' = ', :hash) + inspector.awesome(struct.send(var))
45
+ end
46
+ end
47
+
48
+ if options[:multiline]
49
+ "#<#{awesome_instance}\n#{data.join(%(,\n))}\n#{outdent}>"
50
+ else
51
+ "#<#{awesome_instance} #{data.join(', ')}>"
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def awesome_instance
58
+ # We need to ensure that the original Kernel#format is used here instead of the one defined
59
+ # above.
60
+ # rubocop:disable Style/ColonMethodCall
61
+ Kernel::format("#{struct.class.superclass}:#{struct.class}:0x%08x", (struct.__id__ * 2))
62
+ # rubocop:enable Style/ColonMethodCall
63
+ end
64
+
65
+ def left_aligned
66
+ current = options[:indent]
67
+ options[:indent] = 0
68
+ yield
69
+ ensure
70
+ options[:indent] = current
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,17 @@
1
+ module AmazingPrint
2
+ class Indentator
3
+ attr_reader :shift_width, :indentation
4
+
5
+ def initialize(indentation)
6
+ @indentation = indentation
7
+ @shift_width = indentation.freeze
8
+ end
9
+
10
+ def indent
11
+ @indentation += shift_width
12
+ yield
13
+ ensure
14
+ @indentation -= shift_width
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,175 @@
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_relative 'indentator'
7
+
8
+ module AmazingPrint
9
+ class Inspector
10
+ attr_accessor :options, :indentator
11
+
12
+ AP = :__amazing_print__
13
+
14
+ def initialize(options = {})
15
+ @options = {
16
+ indent: 4, # Number of spaces for indenting.
17
+ index: true, # Display array indices.
18
+ html: false, # Use ANSI color codes rather than HTML.
19
+ multiline: true, # Display in multiple lines.
20
+ plain: false, # Use colors.
21
+ raw: false, # Do not recursively format instance variables.
22
+ sort_keys: false, # Do not sort hash keys.
23
+ sort_vars: true, # Sort instance variables.
24
+ limit: false, # Limit arrays & hashes. Accepts bool or int.
25
+ ruby19_syntax: false, # Use Ruby 1.9 hash syntax in output.
26
+ class_name: :class, # Method used to get Instance class name.
27
+ object_id: true, # Show object_id.
28
+ color: {
29
+ args: :pale,
30
+ array: :white,
31
+ bigdecimal: :blue,
32
+ class: :yellow,
33
+ date: :greenish,
34
+ falseclass: :red,
35
+ fixnum: :blue,
36
+ integer: :blue,
37
+ float: :blue,
38
+ hash: :pale,
39
+ keyword: :cyan,
40
+ method: :purpleish,
41
+ nilclass: :red,
42
+ rational: :blue,
43
+ string: :yellowish,
44
+ struct: :pale,
45
+ symbol: :cyanish,
46
+ time: :greenish,
47
+ trueclass: :green,
48
+ variable: :cyanish
49
+ }
50
+ }
51
+
52
+ # Merge custom defaults and let explicit options parameter override them.
53
+ merge_custom_defaults!
54
+ merge_options!(options)
55
+
56
+ @formatter = AmazingPrint::Formatter.new(self)
57
+ @indentator = AmazingPrint::Indentator.new(@options[:indent].abs)
58
+ Thread.current[AP] ||= []
59
+ end
60
+
61
+ def current_indentation
62
+ indentator.indentation
63
+ end
64
+
65
+ def increase_indentation(&blk)
66
+ indentator.indent(&blk)
67
+ end
68
+
69
+ # Dispatcher that detects data nesting and invokes object-aware formatter.
70
+ #---------------------------------------------------------------------------
71
+ def awesome(object)
72
+ if Thread.current[AP].include?(object.object_id)
73
+ nested(object)
74
+ else
75
+ begin
76
+ Thread.current[AP] << object.object_id
77
+ unnested(object)
78
+ ensure
79
+ Thread.current[AP].pop
80
+ end
81
+ end
82
+ end
83
+
84
+ # Return true if we are to colorize the output.
85
+ #---------------------------------------------------------------------------
86
+ def colorize?
87
+ AmazingPrint.force_colors ||= false
88
+ AmazingPrint.force_colors || (
89
+ if defined? @colorize_STDOUT
90
+ @colorize_STDOUT
91
+ else
92
+ @colorize_STDOUT = STDOUT.tty? && (
93
+ (
94
+ ENV['TERM'] &&
95
+ ENV['TERM'] != 'dumb'
96
+ ) ||
97
+ ENV['ANSICON']
98
+ )
99
+ end
100
+ )
101
+ end
102
+
103
+ private
104
+
105
+ # Format nested data, for example:
106
+ # arr = [1, 2]; arr << arr
107
+ # => [1,2, [...]]
108
+ # hash = { :a => 1 }; hash[:b] = hash
109
+ # => { :a => 1, :b => {...} }
110
+ #---------------------------------------------------------------------------
111
+ def nested(object)
112
+ case printable(object)
113
+ when :array then @formatter.colorize('[...]', :array)
114
+ when :hash then @formatter.colorize('{...}', :hash)
115
+ when :struct then @formatter.colorize('{...}', :struct)
116
+ else @formatter.colorize("...#{object.class}...", :class)
117
+ end
118
+ end
119
+
120
+ #---------------------------------------------------------------------------
121
+ def unnested(object)
122
+ @formatter.format(object, printable(object))
123
+ end
124
+
125
+ # Turn class name into symbol, ex: Hello::World => :hello_world. Classes
126
+ # that inherit from Array, Hash, File, Dir, and Struct are treated as the
127
+ # base class.
128
+ #---------------------------------------------------------------------------
129
+ def printable(object)
130
+ case object
131
+ when Array then :array
132
+ when Hash then :hash
133
+ when File then :file
134
+ when Dir then :dir
135
+ when Struct then :struct
136
+ else object.class.to_s.gsub(/:+/, '_').downcase.to_sym
137
+ end
138
+ end
139
+
140
+ # Update @options by first merging the :color hash and then the remaining
141
+ # keys.
142
+ #---------------------------------------------------------------------------
143
+ def merge_options!(options = {})
144
+ @options[:color].merge!(options.delete(:color) || {})
145
+ @options.merge!(options)
146
+ end
147
+
148
+ # This method needs to be mocked during testing so that it always loads
149
+ # predictable values
150
+ #---------------------------------------------------------------------------
151
+ def load_dotfile
152
+ dotfile = File.join(ENV['HOME'], '.aprc')
153
+ load dotfile if dotfile_readable?(dotfile)
154
+ end
155
+
156
+ def dotfile_readable?(dotfile)
157
+ if @@dotfile_readable.nil? || @@dotfile != dotfile
158
+ @@dotfile_readable = File.readable?(@@dotfile = dotfile)
159
+ end
160
+ @@dotfile_readable
161
+ end
162
+ @@dotfile_readable = @@dotfile = nil
163
+
164
+ # Load ~/.aprc file with custom defaults that override default options.
165
+ #---------------------------------------------------------------------------
166
+ def merge_custom_defaults!
167
+ load_dotfile
168
+ if AmazingPrint.defaults.is_a?(Hash)
169
+ merge_options!(AmazingPrint.defaults)
170
+ end
171
+ rescue StandardError => e
172
+ warn "Could not load '.aprc' from ENV['HOME']: #{e}"
173
+ end
174
+ end
175
+ end