awesome_print_lite 0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7f3400fae6f84fbf525f275d9833ded8c13f369b
4
+ data.tar.gz: 01c1f2e67c6aa05b2252b64face23bb9e32fc9cb
5
+ SHA512:
6
+ metadata.gz: 160a8cb0ff782da5316bf8f29ed769ad87f020a3c7ded6e0905dd5d0f1bfdbc800bf0a302cf266bab10b2b1cc504dccb1a7ae4967a35b0cc072bc09cf72eb727
7
+ data.tar.gz: 1a97e0ae4cc6e329c7d14c48cbdf6d9a74ed563d51c68f77ad848f2a6525f957f4da37f407f71ffd0590964586c1c495c9894d5316cfc8f075483baccce50650
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in awesome_print_lite.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Forrest Chang
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+ # AwesomePrintLite
2
+
3
+ This gem exists to provide basic
4
+ https://github.com/michaeldv/awesome_print (from which large portions
5
+ of code were taken) type functionality for opalrb.org apps,
6
+ particularly opal-irb, as such I've named it awesome_print_lite. It
7
+ need not limited to opal apps only, though I'm not sure why one would
8
+ use it over awesome_print if not using it in opal.
9
+
10
+ As such, this is basically a port of awesome_print to run on oapl
11
+
12
+ ## Porting Consideratinos
13
+ - Mutable strings not supported in Opal
14
+ - Now Thread in Opal
15
+ - No access to filesystem, and similar
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'awesome_print_lite'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install awesome_print_lite
32
+
33
+ ## Usage
34
+
35
+ TODO: Write usage instructions here
36
+
37
+ ## Contributing
38
+
39
+ 1. Fork it ( https://github.com/[my-github-username]/awesome_print_lite/fork )
40
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
41
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
42
+ 4. Push to the branch (`git push origin my-new-feature`)
43
+ 5. Create a new Pull Request
@@ -0,0 +1,14 @@
1
+ require 'opal'
2
+ require 'opal-rspec'
3
+ require 'opal/sprockets/environment'
4
+ require 'awesome_print_lite'
5
+ require 'opal/rspec/rake_task'
6
+ Opal::RSpec::RakeTask.new(:default)
7
+
8
+
9
+ require "bundler/gem_tasks"
10
+ desc "Run allspecs"
11
+ task :spec do
12
+ # Run plain rspec command without RSpec::Core::RakeTask overrides.
13
+ exec "rspec -c spec"
14
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'awesome_print_lite/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "awesome_print_lite"
8
+ spec.version = AwesomePrintLite::VERSION
9
+ spec.authors = ["Forrest Chang"]
10
+ spec.email = ["fkc_email-ruby@hedgeye.com"]
11
+ spec.summary = %q{Subset of Awesome print functionality for Opal.}
12
+ spec.description = %q{Subset of Awesome print functionality for Opal.}
13
+ spec.homepage = "https://github.com/fkchang/awesome_print_lite"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "opal"
25
+ spec.add_development_dependency "opal-rspec"
26
+
27
+ end
@@ -0,0 +1,20 @@
1
+ require "awesome_print_lite/version"
2
+ require "awesome_print_lite/inspector"
3
+ require "awesome_print_lite/formatter"
4
+
5
+ require 'awesome_print_lite/core_ext/array'
6
+ require 'awesome_print_lite/core_ext/string'
7
+ require 'awesome_print_lite/core_ext/method'
8
+ require 'awesome_print_lite/core_ext/object'
9
+ require 'awesome_print_lite/core_ext/class'
10
+ require 'awesome_print_lite/core_ext/kernel'
11
+
12
+
13
+ module AwesomePrintLite
14
+ # Your code goes here...
15
+ end
16
+
17
+ if RUBY_ENGINE != 'opal'
18
+ require "opal"
19
+ Opal.append_path File.expand_path('..', __FILE__)
20
+ end
@@ -0,0 +1,81 @@
1
+ # Copyright (c) 2010-2013 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
+ #
7
+ # The following makes it possible to invoke awesome_print while performing
8
+ # operations on method arrays, ex:
9
+ #
10
+ # ap [].methods - Object.methods
11
+ # ap ''.methods.grep(/!|\?/)
12
+ #
13
+ # If you could think of a better way please let me know :-)
14
+ #
15
+ class Array #:nodoc:
16
+ [ :-, :& ].each do |operator|
17
+ original_operator = instance_method(operator)
18
+
19
+ define_method operator do |*args|
20
+ arr = original_operator.bind(self).call(*args)
21
+ if self.instance_variable_defined?('@__awesome_methods__')
22
+ arr.instance_variable_set('@__awesome_methods__', self.instance_variable_get('@__awesome_methods__'))
23
+ arr.sort! { |a, b| a.to_s <=> b.to_s } # Need the block since Ruby 1.8.x can't sort arrays of symbols.
24
+ end
25
+ arr
26
+ end
27
+ end
28
+ #
29
+ # Intercepting Array#grep needs a special treatment since grep accepts
30
+ # an optional block.
31
+ #
32
+ alias :original_grep :grep
33
+ def grep(pattern, &blk)
34
+ #
35
+ # The following looks rather insane and I've sent numerous hours trying
36
+ # to figure it out. The problem is that if grep gets called with the
37
+ # block, for example:
38
+ #
39
+ # [].methods.grep(/(.+?)_by/) { $1.to_sym }
40
+ #
41
+ # ...then simple:
42
+ #
43
+ # original_grep(pattern, &blk)
44
+ #
45
+ # doesn't set $1 within the grep block which causes nil.to_sym failure.
46
+ # The workaround below has been tested with Ruby 1.8.7/Rails 2.3.8 and
47
+ # Ruby 1.9.2/Rails 3.0.0. For more info see the following thread dating
48
+ # back to 2003 when Ruby 1.8.0 was as fresh off the grill as Ruby 1.9.2
49
+ # is in 2010 :-)
50
+ #
51
+ # http://www.justskins.com/forums/bug-when-rerouting-string-52852.html
52
+ #
53
+ # BTW, if you figure out a better way of intercepting Array#grep please
54
+ # let me know: twitter.com/mid -- or just say hi so I know you've read
55
+ # the comment :-)
56
+ #
57
+ arr = unless blk
58
+ original_grep(pattern)
59
+ else
60
+ original_grep(pattern) do |match|
61
+ #
62
+ # The binding can only be used with Ruby-defined methods, therefore
63
+ # we must rescue potential "ArgumentError: Can't create Binding from
64
+ # C level Proc" error.
65
+ #
66
+ # For example, the following raises ArgumentError since #succ method
67
+ # is defined in C.
68
+ #
69
+ # [ 0, 1, 2, 3, 4 ].grep(1..2, &:succ)
70
+ #
71
+ eval("%Q/#{match.to_s.gsub('/', '\/')}/ =~ #{pattern.inspect}", blk.binding) rescue ArgumentError
72
+ yield match
73
+ end
74
+ end
75
+ if self.instance_variable_defined?('@__awesome_methods__')
76
+ arr.instance_variable_set('@__awesome_methods__', self.instance_variable_get('@__awesome_methods__'))
77
+ arr.reject! { |item| !(item.is_a?(Symbol) || item.is_a?(String)) } # grep block might return crap.
78
+ end
79
+ arr
80
+ end
81
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2010-2013 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
+ class Class #:nodoc:
7
+ #
8
+ # Intercept methods below to inject @__awesome_print__ instance variable
9
+ # so we know it is the *methods* array when formatting an array.
10
+ #
11
+ # Remaining public/private etc. '_methods' are handled in core_ext/object.rb.
12
+ #
13
+ %w(instance_methods private_instance_methods public_instance_methods).each do |name|
14
+ original_method = instance_method(name)
15
+
16
+ define_method name do |*args|
17
+ methods = original_method.bind(self).call(*args)
18
+ methods.instance_variable_set('@__awesome_methods__', self)
19
+ methods
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2010-2013 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 Kernel
7
+
8
+ def ai(options = {})
9
+ ap = AwesomePrintLite::Inspector.new(options)
10
+ awesome = ap.awesome self
11
+ if options[:html]
12
+ awesome = "<pre>#{awesome}</pre>"
13
+ awesome = awesome.html_safe if defined? ActiveSupport
14
+ end
15
+ awesome
16
+ end
17
+ alias :awesome_inspect :ai
18
+
19
+ def ap(object, options = {})
20
+ puts object.ai(options)
21
+ object unless AwesomePrintLite.console?
22
+ end
23
+ alias :awesome_print :ap
24
+
25
+ module_function :ap
26
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright (c) 2010-2013 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 AwesomePrintLite
7
+ module Logger
8
+
9
+ # Add ap method to logger
10
+ #------------------------------------------------------------------------------
11
+ def ap(object, level = nil)
12
+ level ||= AwesomePrintLite.defaults[:log_level] if AwesomePrintLite.defaults
13
+ level ||= :debug
14
+ send level, object.ai
15
+ end
16
+ end
17
+ end
18
+
19
+ Logger.send(:include, AwesomePrintLite::Logger)
20
+ ActiveSupport::BufferedLogger.send(:include, AwesomePrintLite::Logger) if defined?(ActiveSupport::BufferedLogger)
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2010-2013 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
+ #
7
+ # Method#name was intorduced in Ruby 1.8.7 so we define it here as necessary.
8
+ #
9
+ unless nil.method(:class).respond_to?(:name)
10
+ class Method
11
+ def name
12
+ inspect.split(/[#.>]/)[-1]
13
+ end
14
+ end
15
+
16
+ class UnboundMethod
17
+ def name
18
+ inspect.split(/[#.>]/)[-1]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2010-2013 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
+ class Object #:nodoc:
7
+ #
8
+ # Intercept methods below to inject @__awesome_print__ instance variable
9
+ # so we know it is the *methods* array when formatting an array.
10
+ #
11
+ # Remaining instance '_methods' are handled in core_ext/class.rb.
12
+ #
13
+ %w(methods private_methods).each do |name|
14
+ original_method = instance_method(name)
15
+
16
+ define_method name do |*args|
17
+ methods = original_method.bind(self).call(*args)
18
+ methods.instance_variable_set('@__awesome_methods__', self)
19
+ methods
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ # Copyright (c) 2010-2013 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
+ class String
7
+ #
8
+ # ANSI color codes:
9
+ # \e => escape
10
+ # 30 => color base
11
+ # 1 => bright
12
+ # 0 => normal
13
+ #
14
+ # For HTML coloring we use <kbd> tag instead of <span> to require monospace
15
+ # font. Note that beloved <tt> has been removed from HTML5.
16
+ #
17
+ %w(gray red green yellow blue purple cyan white).zip(
18
+ %w(black darkred darkgreen brown navy darkmagenta darkcyan slategray)).each_with_index do |(color, shade), i|
19
+ define_method color do |*html|
20
+ # JS/opal can't deal the escapes and interpolation
21
+ html[0] ? %Q|<kbd style="color:#{color}">#{self}</kbd>| : "\e[1;" + "#{30+i}m#{self}"+ "\e[0m"
22
+ end
23
+
24
+ define_method "#{color}ish" do |*html|
25
+ html[0] ? %Q|<kbd style="color:#{shade}">#{self}</kbd>| : "\e[0;" + "#{30+i}m#{self}" + "\e[0m"
26
+ end
27
+ end
28
+
29
+ alias :black :grayish
30
+ alias :pale :whiteish
31
+
32
+ end
@@ -0,0 +1,410 @@
1
+ # Copyright (c) 2010-2013 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
+ autoload :CGI, "cgi"
7
+ # require "shellwords"
8
+
9
+ module AwesomePrintLite
10
+ class Formatter
11
+
12
+ CORE = [ :array, :class, :dir, :file, :hash, :method, :rational, :set, :struct, :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
+ 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(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
56
+ end
57
+
58
+
59
+ private
60
+
61
+ # Catch all method to format an arbitrary object.
62
+ #------------------------------------------------------------------------------
63
+ def awesome_self(object, type)
64
+ # alert "#{object.inspect} #{object.instance_variables}"
65
+ # `console.log(#{object.instance_variables})`
66
+ if @options[:raw] && instance_variables_opal(object).any?
67
+ return awesome_object(object)
68
+ elsif hash = convert_to_hash(object)
69
+ awesome_hash(hash)
70
+ else
71
+ colorize(object.inspect.to_s, type)
72
+ end
73
+ end
74
+
75
+ # because we put instance variables on everything in opal
76
+ def instance_variables_opal(object)
77
+ object.instance_variables - %w(@0 @1 @2 @3 @4 @5 @6 @7 @8 @9 @encoding)
78
+ end
79
+
80
+ # Format an array.
81
+ #------------------------------------------------------------------------------
82
+ def awesome_array(a)
83
+ return "[]" if a == []
84
+
85
+ if a.instance_variable_defined?('@__awesome_methods__')
86
+ methods_array(a)
87
+ elsif @options[:multiline]
88
+ width = (a.size - 1).to_s.size
89
+
90
+ data = a.inject([]) do |arr, item|
91
+ index = indent
92
+ index += colorize("[#{arr.size.to_s.rjust(width)}] ", :array) if @options[:index]
93
+ indented do
94
+ index += @inspector.awesome(item)
95
+ arr << index
96
+ end
97
+ end
98
+ data = limited(data, width) if should_be_limited?
99
+ "[\n" + data.join(",\n") + "\n#{outdent}]"
100
+ else
101
+ "[ " + a.map{ |item| @inspector.awesome(item) }.join(", ") + " ]"
102
+ end
103
+ end
104
+
105
+ # Format a hash. If @options[:indent] if negative left align hash keys.
106
+ #------------------------------------------------------------------------------
107
+ def awesome_hash(h)
108
+ return "{}" if h == {}
109
+
110
+ keys = @options[:sort_keys] ? h.keys.sort { |a, b| a.to_s <=> b.to_s } : h.keys
111
+ data = keys.map do |key|
112
+ plain_single_line do
113
+ [ @inspector.awesome(key), h[key] ]
114
+ end
115
+ end
116
+
117
+ width = data.map { |key, | key.size }.max || 0
118
+ width += @indentation if @options[:indent] > 0
119
+
120
+ data = data.map do |key, value|
121
+ indented do
122
+ align(key, width) + colorize(" => ", :hash) + @inspector.awesome(value)
123
+ end
124
+ end
125
+
126
+ data = limited(data, width, :hash => true) if should_be_limited?
127
+ if @options[:multiline]
128
+ "{\n" + data.join(",\n") + "\n#{outdent}}"
129
+ else
130
+ "{ #{data.join(', ')} }"
131
+ end
132
+ end
133
+
134
+ # Format an object.
135
+ #------------------------------------------------------------------------------
136
+ def awesome_object(o)
137
+ vars = instance_variables_opal(o).map do |var|
138
+ property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet.
139
+ accessor = if o.respond_to?(:"#{property}=")
140
+ o.respond_to?(property) ? :accessor : :writer
141
+ else
142
+ o.respond_to?(property) ? :reader : nil
143
+ end
144
+ if accessor
145
+ [ "attr_#{accessor} :#{property}", var ]
146
+ else
147
+ [ var.to_s, var ]
148
+ end
149
+ end
150
+
151
+ data = vars.sort.map do |declaration, var|
152
+ key = left_aligned do
153
+ align(declaration, declaration.size)
154
+ end
155
+
156
+ unless @options[:plain]
157
+ if key =~ /(@\w+)/
158
+ key = key.sub($1, colorize($1, :variable))
159
+ else
160
+ key = key.sub(/(attr_\w+)\s(\:\w+)/, "#{colorize('\\1', :keyword)} #{colorize('\\2', :method)}")
161
+ end
162
+ end
163
+ indented do
164
+ key + colorize(" = ", :hash) + @inspector.awesome(o.instance_variable_get(var))
165
+ end
166
+ end
167
+ if @options[:multiline]
168
+ "#<#{awesome_instance(o)}\n#{data.join(%Q/,\n/)}\n#{outdent}>"
169
+ else
170
+ "#<#{awesome_instance(o)} #{data.join(', ')}>"
171
+ end
172
+ end
173
+
174
+ # Format a set.
175
+ #------------------------------------------------------------------------------
176
+ def awesome_set(s)
177
+ awesome_array(s.to_a)
178
+ end
179
+
180
+ # Format a Struct.
181
+ #------------------------------------------------------------------------------
182
+ def awesome_struct(s)
183
+ #
184
+ # The code is slightly uglier because of Ruby 1.8.6 quirks:
185
+ # awesome_hash(Hash[s.members.zip(s.values)]) <-- ArgumentError: odd number of arguments for Hash)
186
+ # awesome_hash(Hash[*s.members.zip(s.values).flatten]) <-- s.members returns strings, not symbols.
187
+ #
188
+ hash = {}
189
+ s.each_pair { |key, value| hash[key] = value }
190
+ awesome_hash(hash)
191
+ end
192
+
193
+ # Format Class object.
194
+ #------------------------------------------------------------------------------
195
+ def awesome_class(c)
196
+ if superclass = c.superclass # <-- Assign and test if nil.
197
+ colorize("#{c.inspect} < #{superclass}", :class)
198
+ else
199
+ colorize(c.inspect, :class)
200
+ end
201
+ end
202
+
203
+ # Format Rational object.
204
+ #------------------------------------------------------------------------------
205
+ def awesome_rational(n)
206
+ colorize(n.to_s, :rational)
207
+ end
208
+
209
+ # Format a method.
210
+ #------------------------------------------------------------------------------
211
+ def awesome_method(m)
212
+ name, args, owner = method_tuple(m)
213
+ "#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
214
+ end
215
+ alias :awesome_unboundmethod :awesome_method
216
+
217
+ # Format object instance.
218
+ #------------------------------------------------------------------------------
219
+ def awesome_instance(o)
220
+ "#{o.class}:0x%08x" % (o.__id__ * 2)
221
+ end
222
+
223
+ # Format object.methods array.
224
+ #------------------------------------------------------------------------------
225
+ def methods_array(a)
226
+ a.sort! { |x, y| x.to_s <=> y.to_s } # Can't simply a.sort! because of o.methods << [ :blah ]
227
+ object = a.instance_variable_get('@__awesome_methods__')
228
+ tuples = a.map do |name|
229
+ if name.is_a?(Symbol) || name.is_a?(String) # Ignore garbage, ex. 42.methods << [ :blah ]
230
+ tuple = if object.respond_to?(name, true) # Is this a regular method?
231
+ the_method = object.method(name) rescue nil # Avoid potential ArgumentError if object#method is overridden.
232
+ if the_method && the_method.respond_to?(:arity) # Is this original object#method?
233
+ method_tuple(the_method) # Yes, we are good.
234
+ end
235
+ elsif object.respond_to?(:instance_method) # Is this an unbound method?
236
+ method_tuple(object.instance_method(name)) rescue nil # Rescue to avoid NameError when the method is not
237
+ end # available (ex. File.lchmod on Ubuntu 12).
238
+ end
239
+ tuple || [ name.to_s, '(?)', '?' ] # Return WTF default if all the above fails.
240
+ end
241
+
242
+ width = (tuples.size - 1).to_s.size
243
+ name_width = tuples.map { |item| item[0].size }.max || 0
244
+ args_width = tuples.map { |item| item[1].size }.max || 0
245
+
246
+ data = tuples.inject([]) do |arr, item|
247
+ index = indent
248
+ index += "[#{arr.size.to_s.rjust(width)}]" if @options[:index]
249
+ indented do
250
+ arr << "#{index} #{colorize(item[0].rjust(name_width), :method)}#{colorize(item[1].ljust(args_width), :args)} #{colorize(item[2], :class)}"
251
+ end
252
+ end
253
+
254
+ "[\n" + data.join("\n") + "\n#{outdent}]"
255
+ end
256
+
257
+ # Return [ name, arguments, owner ] tuple for a given method.
258
+ #------------------------------------------------------------------------------
259
+ def method_tuple(method)
260
+ if method.respond_to?(:parameters) # Ruby 1.9.2+
261
+ # See http://ruby.runpaint.org/methods#method-objects-parameters
262
+ args = method.parameters.inject([]) do |arr, (type, name)|
263
+ name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
264
+ arr << case type
265
+ when :req then name.to_s
266
+ when :opt, :rest then "*#{name}"
267
+ when :block then "&#{name}"
268
+ else '?'
269
+ end
270
+ end
271
+ else # See http://ruby-doc.org/core/classes/Method.html#M001902
272
+ args = (1..method.arity.abs).map { |i| "arg#{i}" }
273
+ args[-1] = "*#{args[-1]}" if method.arity < 0
274
+ end
275
+
276
+ # method.to_s formats to handle:
277
+ #
278
+ # #<Method: Fixnum#zero?>
279
+ # #<Method: Fixnum(Integer)#years>
280
+ # #<Method: User(#<Module:0x00000103207c00>)#_username>
281
+ # #<Method: User(id: integer, username: string).table_name>
282
+ # #<Method: User(id: integer, username: string)(ActiveRecord::Base).current>
283
+ # #<UnboundMethod: Hello#world>
284
+ #
285
+ if method.to_s =~ /(Unbound)*Method: (.*)[#\.]/
286
+ unbound, klass = $1 && '(unbound)', $2
287
+ if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class?
288
+ klass.sub!($1, '') # Yes, strip the fields leaving class name only.
289
+ end
290
+ owner = "#{klass}#{unbound}".gsub('(', ' (')
291
+ end
292
+
293
+ [ method.name.to_s, "(#{args.join(', ')})", owner.to_s ]
294
+ end
295
+
296
+ # Format hash keys as plain strings regardless of underlying data type.
297
+ #------------------------------------------------------------------------------
298
+ def plain_single_line
299
+ plain, multiline = @options[:plain], @options[:multiline]
300
+ @options[:plain], @options[:multiline] = true, false
301
+ yield
302
+ ensure
303
+ @options[:plain], @options[:multiline] = plain, multiline
304
+ end
305
+
306
+ # Utility methods.
307
+ #------------------------------------------------------------------------------
308
+ def convert_to_hash(object)
309
+ if ! object.respond_to?(:to_hash)
310
+ return nil
311
+ end
312
+ if object.method(:to_hash).arity != 0
313
+ return nil
314
+ end
315
+
316
+ hash = object.to_hash
317
+ if ! hash.respond_to?(:keys) || ! hash.respond_to?('[]')
318
+ return nil
319
+ end
320
+
321
+ return hash
322
+ end
323
+
324
+ def align(value, width)
325
+ if @options[:multiline]
326
+ if @options[:indent] > 0
327
+ value.rjust(width)
328
+ elsif @options[:indent] == 0
329
+ indent + value.ljust(width)
330
+ else
331
+ indent[0, @indentation + @options[:indent]] + value.ljust(width)
332
+ end
333
+ else
334
+ value
335
+ end
336
+ end
337
+
338
+ def indented
339
+ @indentation += @options[:indent].abs
340
+ yield
341
+ ensure
342
+ @indentation -= @options[:indent].abs
343
+ end
344
+
345
+ def left_aligned
346
+ current, @options[:indent] = @options[:indent], 0
347
+ yield
348
+ ensure
349
+ @options[:indent] = current
350
+ end
351
+
352
+ def indent
353
+ ' ' * @indentation
354
+ end
355
+
356
+ def outdent
357
+ ' ' * (@indentation - @options[:indent].abs)
358
+ end
359
+
360
+ # To support limited output, for example:
361
+ #
362
+ # ap ('a'..'z').to_a, :limit => 3
363
+ # [
364
+ # [ 0] "a",
365
+ # [ 1] .. [24],
366
+ # [25] "z"
367
+ # ]
368
+ #
369
+ # ap (1..100).to_a, :limit => true # Default limit is 7.
370
+ # [
371
+ # [ 0] 1,
372
+ # [ 1] 2,
373
+ # [ 2] 3,
374
+ # [ 3] .. [96],
375
+ # [97] 98,
376
+ # [98] 99,
377
+ # [99] 100
378
+ # ]
379
+ #------------------------------------------------------------------------------
380
+ def should_be_limited?
381
+ @options[:limit] == true or (@options[:limit].is_a?(Fixnum) and @options[:limit] > 0)
382
+ end
383
+
384
+ def get_limit_size
385
+ @options[:limit] == true ? DEFAULT_LIMIT_SIZE : @options[:limit]
386
+ end
387
+
388
+ def limited(data, width, is_hash = false)
389
+ limit = get_limit_size
390
+ if data.length <= limit
391
+ data
392
+ else
393
+ # Calculate how many elements to be displayed above and below the separator.
394
+ head = limit / 2
395
+ tail = head - (limit - 1) % 2
396
+
397
+ # Add the proper elements to the temp array and format the separator.
398
+ temp = data[0, head] + [ nil ] + data[-tail, tail]
399
+
400
+ if is_hash
401
+ temp[head] = "#{indent}#{data[head].strip} .. #{data[data.length - tail - 1].strip}"
402
+ else
403
+ temp[head] = "#{indent}[#{head.to_s.rjust(width)}] .. [#{data.length - tail - 1}]"
404
+ end
405
+
406
+ temp
407
+ end
408
+ end
409
+ end
410
+ end