awesome_print 1.6.1 → 1.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +4 -0
  3. data/Appraisals +45 -22
  4. data/{CHANGELOG → CHANGELOG.md} +83 -18
  5. data/CONTRIBUTING.md +45 -4
  6. data/Gemfile.lock +28 -22
  7. data/LICENSE +16 -19
  8. data/README.md +97 -92
  9. data/Rakefile +5 -5
  10. data/awesome_print.gemspec +33 -0
  11. data/init.rb +1 -0
  12. data/lib/ap.rb +2 -2
  13. data/lib/awesome_print/colorize.rb +24 -0
  14. data/lib/awesome_print/core_ext/{array.rb → awesome_method_array.rb} +16 -18
  15. data/lib/awesome_print/core_ext/class.rb +3 -2
  16. data/lib/awesome_print/core_ext/kernel.rb +1 -1
  17. data/lib/awesome_print/core_ext/logger.rb +1 -1
  18. data/lib/awesome_print/core_ext/method.rb +2 -2
  19. data/lib/awesome_print/core_ext/object.rb +3 -2
  20. data/lib/awesome_print/core_ext/string.rb +3 -3
  21. data/lib/awesome_print/custom_defaults.rb +57 -0
  22. data/lib/awesome_print/ext/action_view.rb +8 -4
  23. data/lib/awesome_print/ext/active_record.rb +45 -12
  24. data/lib/awesome_print/ext/active_support.rb +1 -1
  25. data/lib/awesome_print/ext/mongo_mapper.rb +16 -13
  26. data/lib/awesome_print/ext/mongoid.rb +8 -6
  27. data/lib/awesome_print/ext/nobrainer.rb +52 -0
  28. data/lib/awesome_print/ext/nokogiri.rb +4 -4
  29. data/lib/awesome_print/ext/ostruct.rb +1 -1
  30. data/lib/awesome_print/ext/ripple.rb +5 -6
  31. data/lib/awesome_print/ext/sequel.rb +7 -6
  32. data/lib/awesome_print/formatter.rb +54 -327
  33. data/lib/awesome_print/formatters/array_formatter.rb +139 -0
  34. data/lib/awesome_print/formatters/base_formatter.rb +140 -0
  35. data/lib/awesome_print/formatters/class_formatter.rb +25 -0
  36. data/lib/awesome_print/formatters/dir_formatter.rb +22 -0
  37. data/lib/awesome_print/formatters/file_formatter.rb +22 -0
  38. data/lib/awesome_print/formatters/hash_formatter.rb +106 -0
  39. data/lib/awesome_print/formatters/method_formatter.rb +22 -0
  40. data/lib/awesome_print/formatters/object_formatter.rb +78 -0
  41. data/lib/awesome_print/formatters/simple_formatter.rb +21 -0
  42. data/lib/awesome_print/formatters/struct_formatter.rb +71 -0
  43. data/lib/awesome_print/formatters.rb +15 -0
  44. data/lib/awesome_print/indentator.rb +18 -0
  45. data/lib/awesome_print/inspector.rb +92 -94
  46. data/lib/awesome_print/version.rb +2 -2
  47. data/lib/awesome_print.rb +19 -18
  48. data/spec/active_record_helper.rb +24 -28
  49. data/spec/colors_spec.rb +31 -31
  50. data/spec/core_ext/logger_spec.rb +43 -0
  51. data/spec/core_ext/string_spec.rb +20 -0
  52. data/spec/ext/action_view_spec.rb +21 -0
  53. data/spec/ext/active_record_spec.rb +260 -0
  54. data/spec/ext/active_support_spec.rb +30 -0
  55. data/spec/ext/mongo_mapper_spec.rb +261 -0
  56. data/spec/ext/mongoid_spec.rb +67 -0
  57. data/spec/ext/nobrainer_spec.rb +59 -0
  58. data/spec/ext/nokogiri_spec.rb +46 -0
  59. data/spec/ext/ostruct_spec.rb +22 -0
  60. data/spec/ext/ripple_spec.rb +48 -0
  61. data/spec/formats_spec.rb +251 -184
  62. data/spec/methods_spec.rb +126 -130
  63. data/spec/misc_spec.rb +98 -93
  64. data/spec/objects_spec.rb +162 -27
  65. data/spec/spec_helper.rb +72 -38
  66. data/spec/support/active_record_data/3_2_diana.txt +24 -0
  67. data/spec/support/active_record_data/3_2_diana_legacy.txt +24 -0
  68. data/spec/support/active_record_data/3_2_multi.txt +50 -0
  69. data/spec/support/active_record_data/3_2_multi_legacy.txt +50 -0
  70. data/spec/support/active_record_data/4_0_diana.txt +98 -0
  71. data/spec/support/active_record_data/4_0_multi.txt +198 -0
  72. data/spec/support/active_record_data/4_1_diana.txt +97 -0
  73. data/spec/support/active_record_data/4_1_multi.txt +196 -0
  74. data/spec/support/active_record_data/4_2_diana.txt +109 -0
  75. data/spec/support/active_record_data/4_2_diana_legacy.txt +109 -0
  76. data/spec/support/active_record_data/4_2_multi.txt +220 -0
  77. data/spec/support/active_record_data/4_2_multi_legacy.txt +220 -0
  78. data/spec/support/active_record_data/5_0_diana.txt +105 -0
  79. data/spec/support/active_record_data/5_0_multi.txt +212 -0
  80. data/spec/support/active_record_data/5_1_diana.txt +104 -0
  81. data/spec/support/active_record_data/5_1_multi.txt +210 -0
  82. data/spec/support/active_record_data/5_2_diana.txt +104 -0
  83. data/spec/support/active_record_data/5_2_multi.txt +210 -0
  84. data/spec/support/active_record_data/6_0_diana.txt +104 -0
  85. data/spec/support/active_record_data/6_0_multi.txt +210 -0
  86. data/spec/support/active_record_data/6_1_diana.txt +109 -0
  87. data/spec/support/active_record_data/6_1_multi.txt +220 -0
  88. data/spec/support/active_record_data.rb +20 -0
  89. data/spec/support/ext_verifier.rb +42 -0
  90. data/spec/support/mongoid_versions.rb +26 -0
  91. data/spec/support/rails_versions.rb +55 -0
  92. metadata +104 -15
  93. data/lib/awesome_print/ext/no_brainer.rb +0 -58
@@ -1,21 +1,21 @@
1
- # Copyright (c) 2010-2013 Michael Dvorkin
1
+ # Copyright (c) 2010-2016 Michael Dvorkin and contributors
2
2
  #
3
3
  # Awesome Print is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
5
5
  #------------------------------------------------------------------------------
6
- autoload :CGI, "cgi"
7
- require "shellwords"
6
+ require 'awesome_print/formatters'
8
7
 
9
8
  module AwesomePrint
10
9
  class Formatter
10
+ include Colorize
11
11
 
12
- CORE = [ :array, :bigdecimal, :class, :dir, :file, :hash, :method, :rational, :set, :struct, :unboundmethod ]
13
- DEFAULT_LIMIT_SIZE = 7
12
+ attr_reader :inspector, :options
13
+
14
+ CORE_FORMATTERS = [:array, :bigdecimal, :class, :dir, :file, :hash, :method, :rational, :set, :struct, :unboundmethod]
14
15
 
15
16
  def initialize(inspector)
16
17
  @inspector = inspector
17
18
  @options = inspector.options
18
- @indentation = @options[:indent].abs
19
19
  end
20
20
 
21
21
  # Main entry point to format an object.
@@ -34,28 +34,9 @@ module AwesomePrint
34
34
  # directory for custom formatters that ship with awesome_print.
35
35
  #------------------------------------------------------------------------------
36
36
  def cast(object, type)
37
- CORE.grep(type)[0] || :self
38
- end
39
-
40
- # Pick the color and apply it to the given string as necessary.
41
- #------------------------------------------------------------------------------
42
- def colorize(str, type)
43
- str = CGI.escapeHTML(str) if @options[:html]
44
- if @options[:plain] || !@options[:color][type] || !@inspector.colorize?
45
- str
46
- #
47
- # Check if the string color method is defined by awesome_print and accepts
48
- # html parameter or it has been overriden by some gem such as colorize.
49
- #
50
- elsif str.method(@options[:color][type]).arity == -1 # Accepts html parameter.
51
- str.send(@options[:color][type], @options[:html])
52
- else
53
- str = %Q|<kbd style="color:#{@options[:color][type]}">#{str}</kbd>| if @options[:html]
54
- str.send(@options[:color][type])
55
- end
37
+ CORE_FORMATTERS.include?(type) ? type : :self
56
38
  end
57
39
 
58
-
59
40
  private
60
41
 
61
42
  # Catch all method to format an arbitrary object.
@@ -63,345 +44,91 @@ module AwesomePrint
63
44
  def awesome_self(object, type)
64
45
  if @options[:raw] && object.instance_variables.any?
65
46
  awesome_object(object)
66
- elsif object.respond_to?(:to_hash)
67
- awesome_hash(object.to_hash)
68
- else
69
- colorize(object.inspect.to_s, type)
70
- end
71
- end
72
-
73
- # Format an array.
74
- #------------------------------------------------------------------------------
75
- def awesome_array(a)
76
- return "[]" if a == []
77
-
78
- if a.instance_variable_defined?('@__awesome_methods__')
79
- methods_array(a)
80
- elsif @options[:multiline]
81
- width = (a.size - 1).to_s.size
82
-
83
- data = a.inject([]) do |arr, item|
84
- index = indent
85
- index << colorize("[#{arr.size.to_s.rjust(width)}] ", :array) if @options[:index]
86
- indented do
87
- arr << (index << @inspector.awesome(item))
88
- end
89
- end
90
-
91
- data = limited(data, width) if should_be_limited?
92
- "[\n" << data.join(",\n") << "\n#{outdent}]"
93
- else
94
- "[ " << a.map{ |item| @inspector.awesome(item) }.join(", ") << " ]"
95
- end
96
- end
97
-
98
- # Format a hash. If @options[:indent] if negative left align hash keys.
99
- #------------------------------------------------------------------------------
100
- def awesome_hash(h)
101
- return "{}" if h == {}
102
-
103
- keys = @options[:sort_keys] ? h.keys.sort { |a, b| a.to_s <=> b.to_s } : h.keys
104
- data = keys.map do |key|
105
- plain_single_line do
106
- [ @inspector.awesome(key), h[key] ]
107
- end
108
- end
109
-
110
- width = data.map { |key, | key.size }.max || 0
111
- width += @indentation if @options[:indent] > 0
112
-
113
- data = data.map do |key, value|
114
- indented do
115
- align(key, width) << colorize(" => ", :hash) << @inspector.awesome(value)
116
- end
117
- end
118
-
119
- data = limited(data, width, :hash => true) if should_be_limited?
120
- if @options[:multiline]
121
- "{\n" << data.join(",\n") << "\n#{outdent}}"
47
+ elsif (hash = convert_to_hash(object))
48
+ awesome_hash(hash)
122
49
  else
123
- "{ #{data.join(', ')} }"
50
+ awesome_simple(object.inspect.to_s, type, @inspector)
124
51
  end
125
52
  end
126
53
 
127
- # Format an object.
128
- #------------------------------------------------------------------------------
129
- def awesome_object(o)
130
- vars = o.instance_variables.map do |var|
131
- property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet.
132
- accessor = if o.respond_to?(:"#{property}=")
133
- o.respond_to?(property) ? :accessor : :writer
134
- else
135
- o.respond_to?(property) ? :reader : nil
136
- end
137
- if accessor
138
- [ "attr_#{accessor} :#{property}", var ]
139
- else
140
- [ var.to_s, var ]
141
- end
142
- end
143
-
144
- data = vars.sort.map do |declaration, var|
145
- key = left_aligned do
146
- align(declaration, declaration.size)
147
- end
148
-
149
- unless @options[:plain]
150
- if key =~ /(@\w+)/
151
- key.sub!($1, colorize($1, :variable))
152
- else
153
- key.sub!(/(attr_\w+)\s(\:\w+)/, "#{colorize('\\1', :keyword)} #{colorize('\\2', :method)}")
154
- end
155
- end
156
- indented do
157
- key << colorize(" = ", :hash) + @inspector.awesome(o.instance_variable_get(var))
158
- end
159
- end
160
- if @options[:multiline]
161
- "#<#{awesome_instance(o)}\n#{data.join(%Q/,\n/)}\n#{outdent}>"
162
- else
163
- "#<#{awesome_instance(o)} #{data.join(', ')}>"
164
- end
54
+ def awesome_bigdecimal(n)
55
+ o = n.to_s('F')
56
+ type = :bigdecimal
57
+ awesome_simple(o, type, @inspector)
165
58
  end
166
59
 
167
- # Format a set.
168
- #------------------------------------------------------------------------------
169
- def awesome_set(s)
170
- awesome_array(s.to_a)
60
+ def awesome_rational(n)
61
+ o = n.to_s
62
+ type = :rational
63
+ awesome_simple(o, type, @inspector)
171
64
  end
172
65
 
173
- # Format a Struct.
174
- #------------------------------------------------------------------------------
175
- def awesome_struct(s)
176
- #
177
- # The code is slightly uglier because of Ruby 1.8.6 quirks:
178
- # awesome_hash(Hash[s.members.zip(s.values)]) <-- ArgumentError: odd number of arguments for Hash)
179
- # awesome_hash(Hash[*s.members.zip(s.values).flatten]) <-- s.members returns strings, not symbols.
180
- #
181
- hash = {}
182
- s.each_pair { |key, value| hash[key] = value }
183
- awesome_hash(hash)
66
+ def awesome_simple(o, type, inspector = @inspector)
67
+ AwesomePrint::Formatters::SimpleFormatter.new(o, type, inspector).format
184
68
  end
185
69
 
186
- # Format Class object.
187
- #------------------------------------------------------------------------------
188
- def awesome_class(c)
189
- if superclass = c.superclass # <-- Assign and test if nil.
190
- colorize("#{c.inspect} < #{superclass}", :class)
191
- else
192
- colorize(c.inspect, :class)
193
- end
70
+ def awesome_array(a)
71
+ Formatters::ArrayFormatter.new(a, @inspector).format
194
72
  end
195
73
 
196
- # Format File object.
197
- #------------------------------------------------------------------------------
198
- def awesome_file(f)
199
- ls = File.directory?(f) ? `ls -adlF #{f.path.shellescape}` : `ls -alF #{f.path.shellescape}`
200
- colorize(ls.empty? ? f.inspect : "#{f.inspect}\n#{ls.chop}", :file)
74
+ def awesome_set(s)
75
+ Formatters::ArrayFormatter.new(s.to_a, @inspector).format
201
76
  end
202
77
 
203
- # Format Dir object.
204
- #------------------------------------------------------------------------------
205
- def awesome_dir(d)
206
- ls = `ls -alF #{d.path.shellescape}`
207
- colorize(ls.empty? ? d.inspect : "#{d.inspect}\n#{ls.chop}", :dir)
78
+ def awesome_hash(h)
79
+ Formatters::HashFormatter.new(h, @inspector).format
208
80
  end
209
81
 
210
- # Format BigDecimal object.
211
- #------------------------------------------------------------------------------
212
- def awesome_bigdecimal(n)
213
- colorize(n.to_s("F"), :bigdecimal)
82
+ def awesome_object(o)
83
+ Formatters::ObjectFormatter.new(o, @inspector).format
214
84
  end
215
85
 
216
- # Format Rational object.
217
- #------------------------------------------------------------------------------
218
- def awesome_rational(n)
219
- colorize(n.to_s, :rational)
86
+ def awesome_struct(s)
87
+ Formatters::StructFormatter.new(s, @inspector).format
220
88
  end
221
89
 
222
- # Format a method.
223
- #------------------------------------------------------------------------------
224
90
  def awesome_method(m)
225
- name, args, owner = method_tuple(m)
226
- "#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
91
+ Formatters::MethodFormatter.new(m, @inspector).format
227
92
  end
228
93
  alias :awesome_unboundmethod :awesome_method
229
94
 
230
- # Format object instance.
231
- #------------------------------------------------------------------------------
232
- def awesome_instance(o)
233
- "#{o.class}:0x%08x" % (o.__id__ * 2)
234
- end
235
-
236
- # Format object.methods array.
237
- #------------------------------------------------------------------------------
238
- def methods_array(a)
239
- a.sort! { |x, y| x.to_s <=> y.to_s } # Can't simply a.sort! because of o.methods << [ :blah ]
240
- object = a.instance_variable_get('@__awesome_methods__')
241
- tuples = a.map do |name|
242
- if name.is_a?(Symbol) || name.is_a?(String) # Ignore garbage, ex. 42.methods << [ :blah ]
243
- tuple = if object.respond_to?(name, true) # Is this a regular method?
244
- the_method = object.method(name) rescue nil # Avoid potential ArgumentError if object#method is overridden.
245
- if the_method && the_method.respond_to?(:arity) # Is this original object#method?
246
- method_tuple(the_method) # Yes, we are good.
247
- end
248
- elsif object.respond_to?(:instance_method) # Is this an unbound method?
249
- method_tuple(object.instance_method(name)) rescue nil # Rescue to avoid NameError when the method is not
250
- end # available (ex. File.lchmod on Ubuntu 12).
251
- end
252
- tuple || [ name.to_s, '(?)', '?' ] # Return WTF default if all the above fails.
253
- end
254
-
255
- width = (tuples.size - 1).to_s.size
256
- name_width = tuples.map { |item| item[0].size }.max || 0
257
- args_width = tuples.map { |item| item[1].size }.max || 0
258
-
259
- data = tuples.inject([]) do |arr, item|
260
- index = indent
261
- index << "[#{arr.size.to_s.rjust(width)}]" if @options[:index]
262
- indented do
263
- arr << "#{index} #{colorize(item[0].rjust(name_width), :method)}#{colorize(item[1].ljust(args_width), :args)} #{colorize(item[2], :class)}"
264
- end
265
- end
266
-
267
- "[\n" << data.join("\n") << "\n#{outdent}]"
95
+ def awesome_class(c)
96
+ Formatters::ClassFormatter.new(c, @inspector).format
268
97
  end
269
98
 
270
- # Return [ name, arguments, owner ] tuple for a given method.
271
- #------------------------------------------------------------------------------
272
- def method_tuple(method)
273
- if method.respond_to?(:parameters) # Ruby 1.9.2+
274
- # See http://ruby.runpaint.org/methods#method-objects-parameters
275
- args = method.parameters.inject([]) do |arr, (type, name)|
276
- name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
277
- arr << case type
278
- when :req then name.to_s
279
- when :opt, :rest then "*#{name}"
280
- when :block then "&#{name}"
281
- else '?'
282
- end
283
- end
284
- else # See http://ruby-doc.org/core/classes/Method.html#M001902
285
- args = (1..method.arity.abs).map { |i| "arg#{i}" }
286
- args[-1] = "*#{args[-1]}" if method.arity < 0
287
- end
288
-
289
- # method.to_s formats to handle:
290
- #
291
- # #<Method: Fixnum#zero?>
292
- # #<Method: Fixnum(Integer)#years>
293
- # #<Method: User(#<Module:0x00000103207c00>)#_username>
294
- # #<Method: User(id: integer, username: string).table_name>
295
- # #<Method: User(id: integer, username: string)(ActiveRecord::Base).current>
296
- # #<UnboundMethod: Hello#world>
297
- #
298
- if method.to_s =~ /(Unbound)*Method: (.*)[#\.]/
299
- unbound, klass = $1 && '(unbound)', $2
300
- if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class?
301
- klass.sub!($1, '') # Yes, strip the fields leaving class name only.
302
- end
303
- owner = "#{klass}#{unbound}".gsub('(', ' (')
304
- end
305
-
306
- [ method.name.to_s, "(#{args.join(', ')})", owner.to_s ]
99
+ def awesome_file(f)
100
+ Formatters::FileFormatter.new(f, @inspector).format
307
101
  end
308
102
 
309
- # Format hash keys as plain strings regardless of underlying data type.
310
- #------------------------------------------------------------------------------
311
- def plain_single_line
312
- plain, multiline = @options[:plain], @options[:multiline]
313
- @options[:plain], @options[:multiline] = true, false
314
- yield
315
- ensure
316
- @options[:plain], @options[:multiline] = plain, multiline
103
+ def awesome_dir(d)
104
+ Formatters::DirFormatter.new(d, @inspector).format
317
105
  end
318
106
 
319
107
  # Utility methods.
320
108
  #------------------------------------------------------------------------------
321
- def align(value, width)
322
- if @options[:multiline]
323
- if @options[:indent] > 0
324
- value.rjust(width)
325
- elsif @options[:indent] == 0
326
- indent + value.ljust(width)
327
- else
328
- indent[0, @indentation + @options[:indent]] + value.ljust(width)
329
- end
330
- else
331
- value
332
- end
333
- end
334
109
 
335
- def indented
336
- @indentation += @options[:indent].abs
337
- yield
338
- ensure
339
- @indentation -= @options[:indent].abs
110
+ # A class (ex. `Net::HTTP.Get`) might have `attr_reader :method` accessor
111
+ # which causes `object.method(:to_hash)` throw `ArgumentError (wrong number
112
+ # of arguments (given 1, expected 0))`. The following tries to avoid that.
113
+ def has_method_accessor?(object)
114
+ !object.method(:method)
115
+ rescue ArgumentError
116
+ true
340
117
  end
341
118
 
342
- def left_aligned
343
- current, @options[:indent] = @options[:indent], 0
344
- yield
345
- ensure
346
- @options[:indent] = current
347
- end
119
+ def convert_to_hash(object)
120
+ return nil if has_method_accessor?(object)
121
+ return nil if !object.respond_to?(:to_hash) || object.method(:to_hash).arity != 0
348
122
 
349
- def indent
350
- ' ' * @indentation
351
- end
123
+ # ActionController::Parameters will raise if they are not yet permitted
124
+ # and we try to convert to hash.
125
+ # https://api.rubyonrails.org/classes/ActionController/Parameters.html
126
+ return nil if object.respond_to?(:permitted?) && !object.permitted?
352
127
 
353
- def outdent
354
- ' ' * (@indentation - @options[:indent].abs)
355
- end
356
-
357
- # To support limited output, for example:
358
- #
359
- # ap ('a'..'z').to_a, :limit => 3
360
- # [
361
- # [ 0] "a",
362
- # [ 1] .. [24],
363
- # [25] "z"
364
- # ]
365
- #
366
- # ap (1..100).to_a, :limit => true # Default limit is 7.
367
- # [
368
- # [ 0] 1,
369
- # [ 1] 2,
370
- # [ 2] 3,
371
- # [ 3] .. [96],
372
- # [97] 98,
373
- # [98] 99,
374
- # [99] 100
375
- # ]
376
- #------------------------------------------------------------------------------
377
- def should_be_limited?
378
- @options[:limit] == true or (@options[:limit].is_a?(Fixnum) and @options[:limit] > 0)
379
- end
380
-
381
- def get_limit_size
382
- @options[:limit] == true ? DEFAULT_LIMIT_SIZE : @options[:limit]
383
- end
128
+ hash = object.to_hash
129
+ return nil if !hash.respond_to?(:keys) || !hash.respond_to?(:[])
384
130
 
385
- def limited(data, width, is_hash = false)
386
- limit = get_limit_size
387
- if data.length <= limit
388
- data
389
- else
390
- # Calculate how many elements to be displayed above and below the separator.
391
- head = limit / 2
392
- tail = head - (limit - 1) % 2
393
-
394
- # Add the proper elements to the temp array and format the separator.
395
- temp = data[0, head] + [ nil ] + data[-tail, tail]
396
-
397
- if is_hash
398
- temp[head] = "#{indent}#{data[head].strip} .. #{data[data.length - tail - 1].strip}"
399
- else
400
- temp[head] = "#{indent}[#{head.to_s.rjust(width)}] .. [#{data.length - tail - 1}]"
401
- end
402
-
403
- temp
404
- end
131
+ hash
405
132
  end
406
133
  end
407
134
  end
@@ -0,0 +1,139 @@
1
+ require_relative 'base_formatter'
2
+
3
+ module AwesomePrint
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 = unless should_be_limited?
40
+ generate_printable_array
41
+ else
42
+ limited(generate_printable_array, width(array))
43
+ end
44
+
45
+ %Q([\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
+ return 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