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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +43 -0
- data/Rakefile +14 -0
- data/awesome_print_lite.gemspec +27 -0
- data/lib/awesome_print_lite.rb +20 -0
- data/lib/awesome_print_lite/core_ext/array.rb +81 -0
- data/lib/awesome_print_lite/core_ext/class.rb +22 -0
- data/lib/awesome_print_lite/core_ext/kernel.rb +26 -0
- data/lib/awesome_print_lite/core_ext/logger.rb +20 -0
- data/lib/awesome_print_lite/core_ext/method.rb +21 -0
- data/lib/awesome_print_lite/core_ext/object.rb +22 -0
- data/lib/awesome_print_lite/core_ext/string.rb +32 -0
- data/lib/awesome_print_lite/formatter.rb +410 -0
- data/lib/awesome_print_lite/inspector.rb +174 -0
- data/lib/awesome_print_lite/version.rb +3 -0
- data/spec/colors_spec.rb +106 -0
- data/spec/core_ext/string_spec.rb +20 -0
- data/spec/formats_spec.rb +725 -0
- data/spec/methods_spec.rb +459 -0
- data/spec/misc_spec.rb +238 -0
- data/spec/objects_spec.rb +129 -0
- data/spec/spec_helper.rb +55 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -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
|