amazing_print 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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