awesome_print_lite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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