awesome_print 0.4.0 → 1.0.2
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.
- data/.gitignore +22 -0
- data/CHANGELOG +18 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +26 -0
- data/README.md +64 -16
- data/Rakefile +2 -46
- data/lib/ap.rb +3 -17
- data/lib/{ap → awesome_print}/core_ext/class.rb +7 -2
- data/lib/{ap → awesome_print}/core_ext/kernel.rb +2 -2
- data/lib/awesome_print/core_ext/logger.rb +20 -0
- data/lib/{ap → awesome_print}/core_ext/object.rb +7 -2
- data/lib/{ap → awesome_print}/core_ext/string.rb +8 -5
- data/lib/awesome_print/ext/action_view.rb +18 -0
- data/lib/awesome_print/ext/active_record.rb +64 -0
- data/lib/awesome_print/ext/active_support.rb +47 -0
- data/lib/awesome_print/ext/mongo_mapper.rb +38 -0
- data/lib/awesome_print/ext/mongoid.rb +65 -0
- data/lib/awesome_print/ext/nokogiri.rb +45 -0
- data/lib/awesome_print/formatter.rb +384 -0
- data/lib/awesome_print/inspector.rb +140 -0
- data/{rails/init.rb → lib/awesome_print/version.rb} +5 -4
- data/lib/awesome_print.rb +16 -12
- data/spec/colors_spec.rb +106 -0
- data/spec/{awesome_print_spec.rb → formats_spec.rb} +187 -37
- data/spec/methods_spec.rb +30 -0
- data/spec/objects_spec.rb +79 -0
- data/spec/spec_helper.rb +1 -1
- metadata +49 -53
- data/VERSION +0 -1
- data/init.rb +0 -1
- data/lib/ap/awesome_print.rb +0 -352
- data/lib/ap/core_ext/logger.rb +0 -18
- data/lib/ap/mixin/action_view.rb +0 -17
- data/lib/ap/mixin/active_record.rb +0 -54
- data/lib/ap/mixin/active_support.rb +0 -46
- data/lib/ap/mixin/mongo_mapper.rb +0 -54
- data/spec/action_view_spec.rb +0 -25
- data/spec/active_record_spec.rb +0 -136
- data/spec/colorization_spec.rb +0 -84
- data/spec/logger_spec.rb +0 -43
- data/spec/mongo_mapper_spec.rb +0 -63
- data/spec/string_spec.rb +0 -20
- /data/lib/{ap → awesome_print}/core_ext/array.rb +0 -0
- /data/lib/{ap → awesome_print}/core_ext/method.rb +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Copyright (c) 2010-2011 Michael Dvorkin
|
|
2
|
+
#
|
|
3
|
+
# Awesome Print is freely distributable under the terms of MIT license.
|
|
4
|
+
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
|
5
|
+
#------------------------------------------------------------------------------
|
|
6
|
+
module AwesomePrint
|
|
7
|
+
module Nokogiri
|
|
8
|
+
|
|
9
|
+
def self.included(base)
|
|
10
|
+
base.send :alias_method, :cast_without_nokogiri, :cast
|
|
11
|
+
base.send :alias_method, :cast, :cast_with_nokogiri
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add Nokogiri XML Node and NodeSet names to the dispatcher pipeline.
|
|
15
|
+
#------------------------------------------------------------------------------
|
|
16
|
+
def cast_with_nokogiri(object, type)
|
|
17
|
+
cast = cast_without_nokogiri(object, type)
|
|
18
|
+
if (defined?(::Nokogiri::XML::Node) && object.is_a?(::Nokogiri::XML::Node)) ||
|
|
19
|
+
(defined?(::Nokogiri::XML::NodeSet) && object.is_a?(::Nokogiri::XML::NodeSet))
|
|
20
|
+
cast = :nokogiri_xml_node
|
|
21
|
+
end
|
|
22
|
+
cast
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#------------------------------------------------------------------------------
|
|
26
|
+
def awesome_nokogiri_xml_node(object)
|
|
27
|
+
if object.is_a?(::Nokogiri::XML::NodeSet) && object.empty?
|
|
28
|
+
return "[]"
|
|
29
|
+
end
|
|
30
|
+
xml = object.to_xml(:indent => 2)
|
|
31
|
+
#
|
|
32
|
+
# Colorize tag, id/class name, and contents.
|
|
33
|
+
#
|
|
34
|
+
xml.gsub!(/(<)(\/?[A-Za-z1-9]+)/) { |tag| "#{$1}#{colorize($2, :keyword)}" }
|
|
35
|
+
xml.gsub!(/(id|class)="[^"]+"/i) { |id| colorize(id, :class) }
|
|
36
|
+
xml.gsub!(/>([^<]+)</) do |contents|
|
|
37
|
+
contents = colorize($1, :trueclass) if contents && !contents.empty?
|
|
38
|
+
">#{contents}<"
|
|
39
|
+
end
|
|
40
|
+
xml
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
AwesomePrint::Formatter.send(:include, AwesomePrint::Nokogiri)
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
# Copyright (c) 2010-2011 Michael Dvorkin
|
|
2
|
+
#
|
|
3
|
+
# Awesome Print 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 "cgi"
|
|
7
|
+
require "shellwords"
|
|
8
|
+
|
|
9
|
+
module AwesomePrint
|
|
10
|
+
class Formatter
|
|
11
|
+
|
|
12
|
+
CORE = [ :array, :hash, :class, :file, :dir, :bigdecimal, :rational, :struct, :method, :unboundmethod ]
|
|
13
|
+
DEFAULT_LIMIT_SIZE = 7
|
|
14
|
+
|
|
15
|
+
def initialize(inspector)
|
|
16
|
+
@inspector = inspector
|
|
17
|
+
@options = inspector.options
|
|
18
|
+
@indentation = @options[:indent].abs
|
|
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
|
+
@options[:html] ? "<pre>#{awesome}</pre>" : awesome
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Hook this when adding custom formatters. Check out lib/awesome_print/ext
|
|
34
|
+
# directory for custom formatters that ship with awesome_print.
|
|
35
|
+
#------------------------------------------------------------------------------
|
|
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(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
|
+
private
|
|
53
|
+
|
|
54
|
+
# Catch all method to format an arbitrary object.
|
|
55
|
+
#------------------------------------------------------------------------------
|
|
56
|
+
def awesome_self(object, type)
|
|
57
|
+
return awesome_object(object) if object.instance_variables.any?
|
|
58
|
+
colorize(object.inspect.to_s, type)
|
|
59
|
+
end
|
|
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}]"
|
|
81
|
+
else
|
|
82
|
+
"[ " << a.map{ |item| @inspector.awesome(item) }.join(", ") << " ]"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Format a hash. If @options[:indent] if negative left align hash keys.
|
|
87
|
+
#------------------------------------------------------------------------------
|
|
88
|
+
def awesome_hash(h)
|
|
89
|
+
return "{}" if h == {}
|
|
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
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Format an object.
|
|
116
|
+
#------------------------------------------------------------------------------
|
|
117
|
+
def awesome_object(o)
|
|
118
|
+
vars = o.instance_variables.map do |var|
|
|
119
|
+
property = var[1..-1].to_sym
|
|
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
|
|
136
|
+
|
|
137
|
+
unless @options[:plain]
|
|
138
|
+
if key =~ /(@\w+)/
|
|
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
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Format a Struct.
|
|
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)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Format Class object.
|
|
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
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Format File object.
|
|
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)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Format Dir object.
|
|
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)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Format BigDecimal and Rational objects by convering them to Float.
|
|
193
|
+
#------------------------------------------------------------------------------
|
|
194
|
+
def awesome_bigdecimal(n)
|
|
195
|
+
colorize(n.to_f.inspect, :bigdecimal)
|
|
196
|
+
end
|
|
197
|
+
alias :awesome_rational :awesome_bigdecimal
|
|
198
|
+
|
|
199
|
+
# Format a method.
|
|
200
|
+
#------------------------------------------------------------------------------
|
|
201
|
+
def awesome_method(m)
|
|
202
|
+
name, args, owner = method_tuple(m)
|
|
203
|
+
"#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
|
|
204
|
+
end
|
|
205
|
+
alias :awesome_unboundmethod :awesome_method
|
|
206
|
+
|
|
207
|
+
# Format object instance.
|
|
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}]"
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Return [ name, arguments, owner ] tuple for a given method.
|
|
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 ]
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Format hash keys as plain strings regardless of underlying data type.
|
|
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
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Utility methods.
|
|
297
|
+
#------------------------------------------------------------------------------
|
|
298
|
+
def align(value, width)
|
|
299
|
+
if @options[:multiline]
|
|
300
|
+
if @options[:indent] > 0
|
|
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
|
|
309
|
+
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
|
+
|
|
334
|
+
# To support limited output, for example:
|
|
335
|
+
#
|
|
336
|
+
# ap ('a'..'z').to_a, :limit => 3
|
|
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
|
|
379
|
+
|
|
380
|
+
temp
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Copyright (c) 2010-2011 Michael Dvorkin
|
|
2
|
+
#
|
|
3
|
+
# Awesome Print is freely distributable under the terms of MIT license.
|
|
4
|
+
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
|
5
|
+
#------------------------------------------------------------------------------
|
|
6
|
+
module AwesomePrint
|
|
7
|
+
|
|
8
|
+
class << self # Class accessors for custom defaults.
|
|
9
|
+
attr_accessor :defaults, :force_colors
|
|
10
|
+
|
|
11
|
+
# Class accessor to force colorized output (ex. forked subprocess where TERM
|
|
12
|
+
# might be dumb).
|
|
13
|
+
#------------------------------------------------------------------------------
|
|
14
|
+
def force_colors!(value = true)
|
|
15
|
+
@force_colors = value
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class Inspector
|
|
20
|
+
attr_accessor :options
|
|
21
|
+
|
|
22
|
+
AP = :__awesome_print__
|
|
23
|
+
|
|
24
|
+
def initialize(options = {})
|
|
25
|
+
@options = {
|
|
26
|
+
:indent => 4, # Indent using 4 spaces.
|
|
27
|
+
:index => true, # Display array indices.
|
|
28
|
+
:html => false, # Use ANSI color codes rather than HTML.
|
|
29
|
+
:multiline => true, # Display in multiple lines.
|
|
30
|
+
:plain => false, # Use colors.
|
|
31
|
+
:sort_keys => false, # Do not sort hash keys.
|
|
32
|
+
:limit => false, # Limit large output for arrays and hashes. Set to a boolean or integer.
|
|
33
|
+
:color => {
|
|
34
|
+
:args => :pale,
|
|
35
|
+
:array => :white,
|
|
36
|
+
:bigdecimal => :blue,
|
|
37
|
+
:class => :yellow,
|
|
38
|
+
:date => :greenish,
|
|
39
|
+
:falseclass => :red,
|
|
40
|
+
:fixnum => :blue,
|
|
41
|
+
:float => :blue,
|
|
42
|
+
:hash => :pale,
|
|
43
|
+
:keyword => :cyan,
|
|
44
|
+
:method => :purpleish,
|
|
45
|
+
:nilclass => :red,
|
|
46
|
+
:string => :yellowish,
|
|
47
|
+
:struct => :pale,
|
|
48
|
+
:symbol => :cyanish,
|
|
49
|
+
:time => :greenish,
|
|
50
|
+
:trueclass => :green,
|
|
51
|
+
:variable => :cyanish
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Merge custom defaults and let explicit options parameter override them.
|
|
56
|
+
merge_custom_defaults!
|
|
57
|
+
merge_options!(options)
|
|
58
|
+
|
|
59
|
+
@formatter = AwesomePrint::Formatter.new(self)
|
|
60
|
+
Thread.current[AP] ||= []
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Dispatcher that detects data nesting and invokes object-aware formatter.
|
|
64
|
+
#------------------------------------------------------------------------------
|
|
65
|
+
def awesome(object)
|
|
66
|
+
if Thread.current[AP].include?(object.object_id)
|
|
67
|
+
nested(object)
|
|
68
|
+
else
|
|
69
|
+
begin
|
|
70
|
+
Thread.current[AP] << object.object_id
|
|
71
|
+
unnested(object)
|
|
72
|
+
ensure
|
|
73
|
+
Thread.current[AP].pop
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Return true if we are to colorize the output.
|
|
79
|
+
#------------------------------------------------------------------------------
|
|
80
|
+
def colorize?
|
|
81
|
+
AwesomePrint.force_colors ||= false
|
|
82
|
+
AwesomePrint.force_colors || (STDOUT.tty? && ((ENV['TERM'] && ENV['TERM'] != 'dumb') || ENV['ANSICON']))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
# Format nested data, for example:
|
|
88
|
+
# arr = [1, 2]; arr << arr
|
|
89
|
+
# => [1,2, [...]]
|
|
90
|
+
# hash = { :a => 1 }; hash[:b] = hash
|
|
91
|
+
# => { :a => 1, :b => {...} }
|
|
92
|
+
#------------------------------------------------------------------------------
|
|
93
|
+
def nested(object)
|
|
94
|
+
case printable(object)
|
|
95
|
+
when :array then @formatter.colorize("[...]", :array)
|
|
96
|
+
when :hash then @formatter.colorize("{...}", :hash)
|
|
97
|
+
when :struct then @formatter.colorize("{...}", :struct)
|
|
98
|
+
else @formatter.colorize("...#{object.class}...", :class)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
#------------------------------------------------------------------------------
|
|
103
|
+
def unnested(object)
|
|
104
|
+
@formatter.format(object, printable(object))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Turn class name into symbol, ex: Hello::World => :hello_world. Classes that
|
|
108
|
+
# inherit from Array, Hash, File, Dir, and Struct are treated as the base class.
|
|
109
|
+
#------------------------------------------------------------------------------
|
|
110
|
+
def printable(object)
|
|
111
|
+
case object
|
|
112
|
+
when Array then :array
|
|
113
|
+
when Hash then :hash
|
|
114
|
+
when File then :file
|
|
115
|
+
when Dir then :dir
|
|
116
|
+
when Struct then :struct
|
|
117
|
+
else object.class.to_s.gsub(/:+/, "_").downcase.to_sym
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Update @options by first merging the :color hash and then the remaining keys.
|
|
122
|
+
#------------------------------------------------------------------------------
|
|
123
|
+
def merge_options!(options = {})
|
|
124
|
+
@options[:color].merge!(options.delete(:color) || {})
|
|
125
|
+
@options.merge!(options)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Load ~/.aprc file with custom defaults that override default options.
|
|
129
|
+
#------------------------------------------------------------------------------
|
|
130
|
+
def merge_custom_defaults!
|
|
131
|
+
dotfile = File.join(ENV["HOME"], ".aprc")
|
|
132
|
+
if File.readable?(dotfile)
|
|
133
|
+
load dotfile
|
|
134
|
+
merge_options!(AwesomePrint.defaults)
|
|
135
|
+
end
|
|
136
|
+
rescue => e
|
|
137
|
+
$stderr.puts "Could not load #{dotfile}: #{e}"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -3,7 +3,8 @@
|
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
module AwesomePrint
|
|
7
|
+
def self.version
|
|
8
|
+
'1.0.2'
|
|
9
|
+
end
|
|
10
|
+
end
|
data/lib/awesome_print.rb
CHANGED
|
@@ -4,23 +4,27 @@
|
|
|
4
4
|
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
|
5
5
|
#------------------------------------------------------------------------------
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# gem 'awesome_print', '>= 0.4.0'
|
|
7
|
+
# AwesomePrint might be loaded implicitly through ~/.irbrc so do nothing
|
|
8
|
+
# for subsequent requires.
|
|
11
9
|
#
|
|
12
10
|
unless defined?(AwesomePrint)
|
|
13
11
|
%w(array string method object class kernel).each do |file|
|
|
14
|
-
require File.dirname(__FILE__) + "/
|
|
12
|
+
require File.dirname(__FILE__) + "/awesome_print/core_ext/#{file}"
|
|
15
13
|
end
|
|
16
14
|
|
|
17
|
-
require File.dirname(__FILE__) + "/
|
|
18
|
-
require File.dirname(__FILE__) + "/
|
|
19
|
-
require File.dirname(__FILE__) + "/
|
|
15
|
+
require File.dirname(__FILE__) + "/awesome_print/inspector"
|
|
16
|
+
require File.dirname(__FILE__) + "/awesome_print/formatter"
|
|
17
|
+
require File.dirname(__FILE__) + "/awesome_print/version"
|
|
18
|
+
require File.dirname(__FILE__) + "/awesome_print/core_ext/logger" if defined?(Logger)
|
|
20
19
|
|
|
21
|
-
# Load the following under normal
|
|
20
|
+
# Load the following under normal circumstances as well as in Rails
|
|
22
21
|
# console when required from ~/.irbrc.
|
|
23
|
-
require File.dirname(__FILE__) + "/
|
|
24
|
-
require File.dirname(__FILE__) + "/
|
|
25
|
-
|
|
22
|
+
require File.dirname(__FILE__) + "/awesome_print/ext/active_record" if defined?(ActiveRecord) || (defined?(IRB) && ENV['RAILS_ENV'])
|
|
23
|
+
require File.dirname(__FILE__) + "/awesome_print/ext/active_support" if defined?(ActiveSupport) || (defined?(IRB) && ENV['RAILS_ENV'])
|
|
24
|
+
|
|
25
|
+
# Load remaining extensions.
|
|
26
|
+
require File.dirname(__FILE__) + "/awesome_print/ext/action_view" if defined?(ActionView::Base)
|
|
27
|
+
require File.dirname(__FILE__) + "/awesome_print/ext/mongo_mapper" if defined?(MongoMapper)
|
|
28
|
+
require File.dirname(__FILE__) + "/awesome_print/ext/mongoid" if defined?(Mongoid)
|
|
29
|
+
require File.dirname(__FILE__) + "/awesome_print/ext/nokogiri" if defined?(Nokogiri)
|
|
26
30
|
end
|