awesome_print 1.0.0 → 1.1.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.
@@ -1,9 +1,9 @@
1
- # Copyright (c) 2010-2011 Michael Dvorkin
1
+ # Copyright (c) 2010-2012 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
- require "cgi"
6
+ autoload :CGI, "cgi"
7
7
  require "shellwords"
8
8
 
9
9
  module AwesomePrint
@@ -25,12 +25,13 @@ module AwesomePrint
25
25
  awesome = if core_class != :self
26
26
  send(:"awesome_#{core_class}", object) # Core formatters.
27
27
  else
28
- awesome_self(object, type) # Catch all that falls back on object.inspect.
28
+ awesome_self(object, type) # Catch all that falls back to object.inspect.
29
29
  end
30
30
  @options[:html] ? "<pre>#{awesome}</pre>" : awesome
31
31
  end
32
32
 
33
- # Hook this when adding custom formatters.
33
+ # Hook this when adding custom formatters. Check out lib/awesome_print/ext
34
+ # directory for custom formatters that ship with awesome_print.
34
35
  #------------------------------------------------------------------------------
35
36
  def cast(object, type)
36
37
  CORE.grep(type)[0] || :self
@@ -38,12 +39,19 @@ module AwesomePrint
38
39
 
39
40
  # Pick the color and apply it to the given string as necessary.
40
41
  #------------------------------------------------------------------------------
41
- def colorize(s, type)
42
- s = CGI.escapeHTML(s) if @options[:html]
42
+ def colorize(str, type)
43
+ str = CGI.escapeHTML(str) if @options[:html]
43
44
  if @options[:plain] || !@options[:color][type] || !@inspector.colorize?
44
- s
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])
45
52
  else
46
- s.send(@options[:color][type], @options[:html])
53
+ str = %Q|<kbd style="color:#{@options[:color][type]}">#{str}</kbd>| if @options[:html]
54
+ str.send(@options[:color][type])
47
55
  end
48
56
  end
49
57
 
@@ -53,8 +61,11 @@ module AwesomePrint
53
61
  # Catch all method to format an arbitrary object.
54
62
  #------------------------------------------------------------------------------
55
63
  def awesome_self(object, type)
56
- return awesome_object(object) if object.instance_variables.any?
57
- colorize(object.inspect.to_s, type)
64
+ if @options[:raw] && object.instance_variables.any?
65
+ awesome_object(object)
66
+ else
67
+ colorize(object.inspect.to_s, type)
68
+ end
58
69
  end
59
70
 
60
71
  # Format an array.
@@ -188,12 +199,17 @@ module AwesomePrint
188
199
  colorize(ls.empty? ? d.inspect : "#{d.inspect}\n#{ls.chop}", :dir)
189
200
  end
190
201
 
191
- # Format BigDecimal and Rational objects by convering them to Float.
202
+ # Format BigDecimal object.
192
203
  #------------------------------------------------------------------------------
193
204
  def awesome_bigdecimal(n)
194
- colorize(n.to_f.inspect, :bigdecimal)
205
+ colorize(n.to_s("F"), :bigdecimal)
206
+ end
207
+
208
+ # Format Rational object.
209
+ #------------------------------------------------------------------------------
210
+ def awesome_rational(n)
211
+ colorize(n.to_s, :rational)
195
212
  end
196
- alias :awesome_rational :awesome_bigdecimal
197
213
 
198
214
  # Format a method.
199
215
  #------------------------------------------------------------------------------
@@ -212,17 +228,20 @@ module AwesomePrint
212
228
  # Format object.methods array.
213
229
  #------------------------------------------------------------------------------
214
230
  def methods_array(a)
231
+ a.sort! { |x, y| x.to_s <=> y.to_s } # Can't simply a.sort! because of o.methods << [ :blah ]
215
232
  object = a.instance_variable_get('@__awesome_methods__')
216
233
  tuples = a.map do |name|
217
- tuple = if object.respond_to?(name, true) # Is this a regular method?
218
- the_method = object.method(name) rescue nil # Avoid potential ArgumentError if object#method is overridden.
219
- if the_method && the_method.respond_to?(:arity) # Is this original object#method?
220
- method_tuple(the_method) # Yes, we are good.
234
+ if name.is_a?(Symbol) || name.is_a?(String) # Ignore garbage, ex. 42.methods << [ :blah ]
235
+ tuple = if object.respond_to?(name, true) # Is this a regular method?
236
+ the_method = object.method(name) rescue nil # Avoid potential ArgumentError if object#method is overridden.
237
+ if the_method && the_method.respond_to?(:arity) # Is this original object#method?
238
+ method_tuple(the_method) # Yes, we are good.
239
+ end
240
+ elsif object.respond_to?(:instance_method) # Is this an unbound method?
241
+ method_tuple(object.instance_method(name))
221
242
  end
222
- elsif object.respond_to?(:instance_method) # Is this an unbound method?
223
- method_tuple(object.instance_method(name))
224
243
  end
225
- tuple || [ name.to_s, '(?)', '' ] # Return WTF default if all the above fails.
244
+ tuple || [ name.to_s, '(?)', '?' ] # Return WTF default if all the above fails.
226
245
  end
227
246
 
228
247
  width = (tuples.size - 1).to_s.size
@@ -259,14 +278,27 @@ module AwesomePrint
259
278
  args[-1] = "*#{args[-1]}" if method.arity < 0
260
279
  end
261
280
 
262
- if method.to_s =~ /(Unbound)*Method: (.*?)[#\.]/
263
- owner = "#{$2}#{$1 ? '(unbound)' : ''}".gsub('(', ' (')
281
+ # method.to_s formats to handle:
282
+ #
283
+ # #<Method: Fixnum#zero?>
284
+ # #<Method: Fixnum(Integer)#years>
285
+ # #<Method: User(#<Module:0x00000103207c00>)#_username>
286
+ # #<Method: User(id: integer, username: string).table_name>
287
+ # #<Method: User(id: integer, username: string)(ActiveRecord::Base).current>
288
+ # #<UnboundMethod: Hello#world>
289
+ #
290
+ if method.to_s =~ /(Unbound)*Method: (.*)[#\.]/
291
+ unbound, klass = $1 && '(unbound)', $2
292
+ if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class?
293
+ klass.sub!($1, '') # Yes, strip the fields leaving class name only.
294
+ end
295
+ owner = "#{klass}#{unbound}".gsub('(', ' (')
264
296
  end
265
297
 
266
298
  [ method.name.to_s, "(#{args.join(', ')})", owner.to_s ]
267
299
  end
268
300
 
269
- # Format hash keys as plain string regardless of underlying data type.
301
+ # Format hash keys as plain strings regardless of underlying data type.
270
302
  #------------------------------------------------------------------------------
271
303
  def plain_single_line
272
304
  plain, multiline = @options[:plain], @options[:multiline]
@@ -314,7 +346,25 @@ module AwesomePrint
314
346
  ' ' * (@indentation - @options[:indent].abs)
315
347
  end
316
348
 
317
- # To support limited output.
349
+ # To support limited output, for example:
350
+ #
351
+ # ap ('a'..'z').to_a, :limit => 3
352
+ # [
353
+ # [ 0] "a",
354
+ # [ 1] .. [24],
355
+ # [25] "z"
356
+ # ]
357
+ #
358
+ # ap (1..100).to_a, :limit => true # Default limit is 7.
359
+ # [
360
+ # [ 0] 1,
361
+ # [ 1] 2,
362
+ # [ 2] 3,
363
+ # [ 3] .. [96],
364
+ # [97] 98,
365
+ # [98] 99,
366
+ # [99] 100
367
+ # ]
318
368
  #------------------------------------------------------------------------------
319
369
  def should_be_limited?
320
370
  @options[:limit] == true or (@options[:limit].is_a?(Fixnum) and @options[:limit] > 0)
@@ -345,6 +395,5 @@ module AwesomePrint
345
395
  temp
346
396
  end
347
397
  end
348
-
349
398
  end
350
399
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2010-2011 Michael Dvorkin
1
+ # Copyright (c) 2010-2012 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
@@ -14,6 +14,37 @@ module AwesomePrint
14
14
  def force_colors!(value = true)
15
15
  @force_colors = value
16
16
  end
17
+
18
+ def console?
19
+ !!(defined?(IRB) || defined?(Pry))
20
+ end
21
+
22
+ def rails_console?
23
+ console? && !!(defined?(Rails::Console) || ENV["RAILS_ENV"])
24
+ end
25
+
26
+ def irb!
27
+ return unless defined?(IRB)
28
+ unless IRB.version.include?("DietRB")
29
+ IRB::Irb.class_eval do
30
+ def output_value
31
+ ap @context.last_value
32
+ end
33
+ end
34
+ else # MacRuby
35
+ IRB.formatter = Class.new(IRB::Formatter) do
36
+ def inspect_object(object)
37
+ object.ai
38
+ end
39
+ end.new
40
+ end
41
+ end
42
+
43
+ def pry!
44
+ if defined?(Pry)
45
+ Pry.print = proc { |output, value| output.puts value.ai }
46
+ end
47
+ end
17
48
  end
18
49
 
19
50
  class Inspector
@@ -28,6 +59,7 @@ module AwesomePrint
28
59
  :html => false, # Use ANSI color codes rather than HTML.
29
60
  :multiline => true, # Display in multiple lines.
30
61
  :plain => false, # Use colors.
62
+ :raw => false, # Do not recursively format object instance variables.
31
63
  :sort_keys => false, # Do not sort hash keys.
32
64
  :limit => false, # Limit large output for arrays and hashes. Set to a boolean or integer.
33
65
  :color => {
@@ -43,6 +75,7 @@ module AwesomePrint
43
75
  :keyword => :cyan,
44
76
  :method => :purpleish,
45
77
  :nilclass => :red,
78
+ :rational => :blue,
46
79
  :string => :yellowish,
47
80
  :struct => :pale,
48
81
  :symbol => :cyanish,
@@ -129,10 +162,8 @@ module AwesomePrint
129
162
  #------------------------------------------------------------------------------
130
163
  def merge_custom_defaults!
131
164
  dotfile = File.join(ENV["HOME"], ".aprc")
132
- if File.readable?(dotfile)
133
- load dotfile
134
- merge_options!(AwesomePrint.defaults)
135
- end
165
+ load dotfile if File.readable?(dotfile)
166
+ merge_options!(AwesomePrint.defaults) if AwesomePrint.defaults.is_a?(Hash)
136
167
  rescue => e
137
168
  $stderr.puts "Could not load #{dotfile}: #{e}"
138
169
  end
@@ -1,10 +1,10 @@
1
- # Copyright (c) 2010-2011 Michael Dvorkin
1
+ # Copyright (c) 2010-2012 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
6
  module AwesomePrint
7
7
  def self.version
8
- '1.0.0'
8
+ '1.1.0'
9
9
  end
10
10
  end
data/lib/awesome_print.rb CHANGED
@@ -1,13 +1,13 @@
1
- # Copyright (c) 2010-2011 Michael Dvorkin
1
+ # Copyright (c) 2010-2012 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
6
  #
7
- # AwesomePrint might be loaded implicitly through ~/.irbrc so do nothing
8
- # for subsequent requires.
7
+ # AwesomePrint might be loaded implicitly through ~/.irbrc or ~/.pryrc
8
+ # so do nothing for subsequent requires.
9
9
  #
10
- unless defined?(AwesomePrint)
10
+ unless defined?(AwesomePrint::Inspector)
11
11
  %w(array string method object class kernel).each do |file|
12
12
  require File.dirname(__FILE__) + "/awesome_print/core_ext/#{file}"
13
13
  end
@@ -16,14 +16,16 @@ unless defined?(AwesomePrint)
16
16
  require File.dirname(__FILE__) + "/awesome_print/formatter"
17
17
  require File.dirname(__FILE__) + "/awesome_print/version"
18
18
  require File.dirname(__FILE__) + "/awesome_print/core_ext/logger" if defined?(Logger)
19
-
19
+ #
20
20
  # Load the following under normal circumstances as well as in Rails
21
- # console when required from ~/.irbrc.
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
-
21
+ # console when required from ~/.irbrc or ~/.pryrc.
22
+ #
23
+ require File.dirname(__FILE__) + "/awesome_print/ext/active_record" if defined?(ActiveRecord) || AwesomePrint.rails_console?
24
+ require File.dirname(__FILE__) + "/awesome_print/ext/active_support" if defined?(ActiveSupport) || AwesomePrint.rails_console?
25
+ #
25
26
  # Load remaining extensions.
26
- require File.dirname(__FILE__) + "/awesome_print/ext/action_view" if defined?(ActionView)
27
+ #
28
+ require File.dirname(__FILE__) + "/awesome_print/ext/action_view" if defined?(ActionView::Base)
27
29
  require File.dirname(__FILE__) + "/awesome_print/ext/mongo_mapper" if defined?(MongoMapper)
28
30
  require File.dirname(__FILE__) + "/awesome_print/ext/mongoid" if defined?(Mongoid)
29
31
  require File.dirname(__FILE__) + "/awesome_print/ext/nokogiri" if defined?(Nokogiri)
data/spec/formats_spec.rb CHANGED
@@ -479,14 +479,24 @@ EOS
479
479
 
480
480
  #------------------------------------------------------------------------------
481
481
  describe "BigDecimal and Rational" do
482
- it "should present BigDecimal object as Float scalar" do
483
- big = BigDecimal("2010.4")
484
- big.ai(:plain => true).should == "2010.4"
485
- end
486
-
487
- it "should present Rational object as Float scalar" do
488
- rat = Rational(2010, 2)
489
- rat.ai(:plain => true).should == "1005.0"
482
+ it "should present BigDecimal object with arbitrary precision" do
483
+ big = BigDecimal("201020102010201020102010201020102010.4")
484
+ big.ai(:plain => true).should == "201020102010201020102010201020102010.4"
485
+ end
486
+
487
+ it "should present Rational object with arbitrary precision" do
488
+ rat = Rational(201020102010201020102010201020102010, 2)
489
+ out = rat.ai(:plain => true)
490
+ #
491
+ # Ruby 1.9 slightly changed the format of Rational#to_s, see
492
+ # http://techtime.getharvest.com/blog/harvest-is-now-on-ruby-1-dot-9-3 and
493
+ # http://www.ruby-forum.com/topic/189397
494
+ #
495
+ if RUBY_VERSION < "1.9"
496
+ out.should == "100510051005100510051005100510051005"
497
+ else
498
+ out.should == "100510051005100510051005100510051005/1"
499
+ end
490
500
  end
491
501
  end
492
502
 
@@ -501,7 +511,6 @@ EOS
501
511
  end
502
512
  end
503
513
 
504
-
505
514
  #------------------------------------------------------------------------------
506
515
  describe "Struct" do
507
516
  before do
@@ -573,80 +582,6 @@ EOS
573
582
  end
574
583
  end
575
584
 
576
-
577
- #------------------------------------------------------------------------------
578
- describe "Misc" do
579
- it "handle weird objects that return nil on inspect" do
580
- weird = Class.new do
581
- def inspect
582
- nil
583
- end
584
- end
585
- weird.new.ai(:plain => true).should == ''
586
- end
587
-
588
- it "handle frozen object.inspect" do
589
- weird = Class.new do
590
- def inspect
591
- "ice".freeze
592
- end
593
- end
594
- weird.new.ai(:plain => false).should == "ice"
595
- end
596
-
597
- # See https://github.com/michaeldv/awesome_print/issues/35
598
- it "handle array grep when pattern contains / chapacter" do
599
- hash = { "1/x" => 1, "2//x" => :"2" }
600
- grepped = hash.keys.grep(/^(\d+)\//) { $1 }
601
- grepped.ai(:plain => true, :multiline => false).should == '[ "1", "2" ]'
602
- end
603
-
604
- it "returns value passed as a parameter" do
605
- object = rand
606
- self.stub!(:puts)
607
- (ap object).should == object
608
- end
609
-
610
- # Require different file name this time (lib/ap.rb vs. lib/awesome_print).
611
- it "several require 'awesome_print' should do no harm" do
612
- require File.expand_path(File.dirname(__FILE__) + '/../lib/ap')
613
- lambda { rand.ai }.should_not raise_error
614
- end
615
- end
616
-
617
- describe "HTML output" do
618
- it "wraps ap output with plain <pre> tag" do
619
- markup = rand
620
- markup.ai(:html => true, :plain => true).should == "<pre>#{markup}</pre>"
621
- end
622
-
623
- it "wraps ap output with <pre> tag with colorized <kbd>" do
624
- markup = rand
625
- markup.ai(:html => true).should == %Q|<pre><kbd style="color:blue">#{markup}</kbd></pre>|
626
- end
627
-
628
- it "wraps multiline ap output with <pre> tag with colorized <kbd>" do
629
- markup = [ 1, :two, "three" ]
630
- markup.ai(:html => true).should == <<-EOS.strip
631
- <pre>[
632
- <kbd style="color:white">[0] </kbd><pre><kbd style="color:blue">1</kbd></pre>,
633
- <kbd style="color:white">[1] </kbd><pre><kbd style="color:darkcyan">:two</kbd></pre>,
634
- <kbd style="color:white">[2] </kbd><pre><kbd style="color:brown">&quot;three&quot;</kbd></pre>
635
- ]</pre>
636
- EOS
637
- end
638
-
639
- it "encodes HTML entities (plain)" do
640
- markup = ' &<hello>'
641
- markup.ai(:html => true, :plain => true).should == '<pre>&quot; &amp;&lt;hello&gt;&quot;</pre>'
642
- end
643
-
644
- it "encodes HTML entities (color)" do
645
- markup = ' &<hello>'
646
- markup.ai(:html => true).should == '<pre><kbd style="color:brown">&quot; &amp;&lt;hello&gt;&quot;</kbd></pre>'
647
- end
648
- end
649
-
650
585
  #------------------------------------------------------------------------------
651
586
  describe "Inherited from standard Ruby classes" do
652
587
  after do
data/spec/methods_spec.rb CHANGED
@@ -155,9 +155,10 @@ describe "Object methods" do
155
155
  def m1; end
156
156
  def m2; end
157
157
  end
158
+
158
159
  out = Hello.new.private_methods.ai(:plain => true).split("\n").grep(/m\d/)
159
- out.first.should =~ /^\s+\[\d+\]\s+m1\(\)\s+Hello$/
160
- out.last.should =~ /^\s+\[\d+\]\s+m2\(\)\s+Hello$/
160
+ out.first.should =~ /^\s+\[\s*\d+\]\s+m1\(\)\s+Hello$/
161
+ out.last.should =~ /^\s+\[\s*\d+\]\s+m2\(\)\s+Hello$/
161
162
  end
162
163
 
163
164
  it "no index: should handle object.private_methods" do
@@ -167,9 +168,9 @@ describe "Object methods" do
167
168
  end
168
169
  out = Hello.new.private_methods.ai(:plain => true).split("\n").grep(/m\d/)
169
170
  if RUBY_VERSION < '1.9.2'
170
- out.first.should =~ /^\s+\[\d+\]\s+m3\(arg1, arg2\)\s+Hello$/
171
+ out.first.should =~ /^\s+\[\s*\d+\]\s+m3\(arg1, arg2\)\s+Hello$/
171
172
  else
172
- out.first.should =~ /^\s+\[\d+\]\s+m3\(a, b\)\s+Hello$/
173
+ out.first.should =~ /^\s+\[\s*\d+\]\s+m3\(a, b\)\s+Hello$/
173
174
  end
174
175
  end
175
176
  end
@@ -183,8 +184,8 @@ describe "Object methods" do
183
184
  end
184
185
  end
185
186
  out = Hello.singleton_methods.ai(:plain => true).split("\n").grep(/m\d/)
186
- out.first.should =~ /^\s+\[\d+\]\s+m1\(\)\s+Hello$/
187
- out.last.should =~ /^\s+\[\d+\]\s+m2\(\)\s+Hello$/
187
+ out.first.should =~ /^\s+\[\s*\d+\]\s+m1\(\)\s+Hello$/
188
+ out.last.should =~ /^\s+\[\s*\d+\]\s+m2\(\)\s+Hello$/
188
189
  end
189
190
 
190
191
  it "no index: should handle object.singleton_methods" do
@@ -266,8 +267,8 @@ describe "Class methods" do
266
267
  def m2; end
267
268
  end
268
269
  out = Hello.protected_instance_methods.ai(:plain => true).split("\n").grep(/m\d/)
269
- out.first.should =~ /^\s+\[\d+\]\s+m1\(\)\s+Hello\s\(unbound\)$/
270
- out.last.should =~ /^\s+\[\d+\]\s+m2\(\)\s+Hello\s\(unbound\)$/
270
+ out.first.should =~ /^\s+\[\s*\d+\]\s+m1\(\)\s+Hello\s\(unbound\)$/
271
+ out.last.should =~ /^\s+\[\s*\d+\]\s+m2\(\)\s+Hello\s\(unbound\)$/
271
272
  end
272
273
 
273
274
  it "no index: should handle class.protected_instance_methods" do
@@ -410,7 +411,7 @@ describe "Methods arrays" do
410
411
  def self.m_two; end
411
412
  end
412
413
 
413
- out = Hello.methods.grep(/^m_(.+)$/) { $1.to_sym }
414
+ out = Hello.methods.sort.grep(/^m_(.+)$/) { $1.to_sym }
414
415
  out.should == [:one, :two]
415
416
  end
416
417
 
@@ -445,4 +446,14 @@ describe "Methods arrays" do
445
446
  hello = Hello.new
446
447
  (hello.send(:his) - hello.send(:her)).sort_by { |x| x.to_s }.should == [ :him, :his ]
447
448
  end
449
+
450
+ it "appending garbage to methods array should not raise error" do
451
+ arr = 42.methods << [ :wtf ]
452
+ arr.ai(:plain => true).should_not raise_error(TypeError)
453
+ if RUBY_VERSION < '1.9.2'
454
+ arr.ai(:plain => true).should =~ /\s+wtf\(\?\)\s+\?/ # [ :wtf ].to_s => "wtf"
455
+ else
456
+ arr.ai(:plain => true).should =~ /\s+\[:wtf\]\(\?\)\s+\?/ # [ :wtf ].to_s => [:wtf]
457
+ end
458
+ end
448
459
  end