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,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