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