mirror of
https://github.com/awesome-print/awesome_print
synced 2023-03-27 23:22:34 -04:00
Display object.methods in human readable format
This commit is contained in:
parent
14e4fd5e7d
commit
5f78c06a05
5 changed files with 156 additions and 11 deletions
|
@ -4,6 +4,8 @@
|
|||
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
||||
#------------------------------------------------------------------------------
|
||||
require File.dirname(__FILE__) + "/ap/core_ext/string"
|
||||
require File.dirname(__FILE__) + "/ap/core_ext/object"
|
||||
require File.dirname(__FILE__) + "/ap/core_ext/class"
|
||||
require File.dirname(__FILE__) + "/ap/core_ext/kernel"
|
||||
require File.dirname(__FILE__) + "/ap/awesome_print"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ require "shellwords"
|
|||
|
||||
class AwesomePrint
|
||||
AP = :__awesome_print__
|
||||
CORE = [ :array, :hash, :class, :file, :dir, :bigdecimal, :rational, :struct, :method ]
|
||||
CORE = [ :array, :hash, :class, :file, :dir, :bigdecimal, :rational, :struct, :method, :unboundmethod ]
|
||||
|
||||
def initialize(options = {})
|
||||
@options = {
|
||||
|
@ -50,7 +50,9 @@ class AwesomePrint
|
|||
def awesome_array(a)
|
||||
return "[]" if a == []
|
||||
|
||||
if @options[:multiline]
|
||||
if a.instance_variable_defined?('@__awesome_methods__')
|
||||
methods_array(a)
|
||||
elsif @options[:multiline]
|
||||
width = (a.size - 1).to_s.size
|
||||
data = a.inject([]) do |arr, item|
|
||||
index = if @options[:index]
|
||||
|
@ -143,8 +145,9 @@ class AwesomePrint
|
|||
#------------------------------------------------------------------------------
|
||||
def awesome_method(m)
|
||||
name, args, owner = method_tuple(m)
|
||||
"#{colorize(owner, :class)}##{colorize(name, :method)}(#{colorize(args, :args)})"
|
||||
"#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
|
||||
end
|
||||
alias :awesome_unboundmethod :awesome_method
|
||||
|
||||
# Catch all method to format an arbitrary object.
|
||||
#------------------------------------------------------------------------------
|
||||
|
@ -167,6 +170,38 @@ class AwesomePrint
|
|||
end
|
||||
end
|
||||
|
||||
# Format object.methods array.
|
||||
#------------------------------------------------------------------------------
|
||||
def methods_array(a)
|
||||
object = a.instance_variable_get('@__awesome_methods__')
|
||||
tuples = a.map do |name|
|
||||
if object.respond_to?(name, true) # Regular method?
|
||||
method_tuple(object.method(name))
|
||||
elsif object.respond_to?(:instance_method) # Unbound method?
|
||||
method_tuple(object.instance_method(name))
|
||||
else # WTF method.
|
||||
[ name.to_s, '(?)', '' ]
|
||||
end
|
||||
end
|
||||
|
||||
width = (tuples.size - 1).to_s.size
|
||||
name_width = tuples.map { |item| item[0].size }.max || 0
|
||||
args_width = tuples.map { |item| item[1].size }.max || 0
|
||||
|
||||
data = tuples.inject([]) do |arr, item|
|
||||
index = if @options[:index]
|
||||
"#{indent}[#{arr.size.to_s.rjust(width)}]"
|
||||
else
|
||||
indent
|
||||
end
|
||||
indented do
|
||||
arr << "#{index} #{colorize(item[0].rjust(name_width), :method)}#{colorize(item[1].ljust(args_width), :args)} #{colorize(item[2], :class)}"
|
||||
end
|
||||
end
|
||||
|
||||
"[\n" << data.join("\n") << "\n#{outdent}]"
|
||||
end
|
||||
|
||||
# Format nested data, for example:
|
||||
# arr = [1, 2]; arr << arr
|
||||
# => [1,2, [...]]
|
||||
|
@ -208,14 +243,16 @@ class AwesomePrint
|
|||
end
|
||||
end
|
||||
|
||||
# Return [ name, argument, owner ] tuple for a given method.
|
||||
# Return [ name, arguments, owner ] tuple for a given method.
|
||||
#------------------------------------------------------------------------------
|
||||
def method_tuple(method)
|
||||
args = method.arity.abs.times.map { |i| "arg#{i+1}" }.join(', ')
|
||||
args << ', ...' if method.arity < 0
|
||||
owner = $1.sub('(', ' (') if method.to_s =~ /Method: (.*?)#/
|
||||
if method.to_s =~ /(Unbound)*Method: (.*?)[#\.]/
|
||||
owner = "#{$2}#{$1 ? '(unbound)' : ''}".gsub('(', ' (')
|
||||
end
|
||||
|
||||
[ method.name, args, owner || 'self' ]
|
||||
[ method.name, "(#{args})", owner.to_s ]
|
||||
end
|
||||
|
||||
# Format hash keys as plain string regardless of underlying data type.
|
||||
|
|
15
lib/ap/core_ext/class.rb
Normal file
15
lib/ap/core_ext/class.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2010 Michael Dvorkin
|
||||
#
|
||||
# Awesome Print is freely distributable under the terms of MIT license.
|
||||
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
||||
#------------------------------------------------------------------------------
|
||||
class Class
|
||||
methods.grep(/instance_methods$/) do |name|
|
||||
define_method name do |*args|
|
||||
methods = super(*args)
|
||||
# And now the evil part :-)
|
||||
methods.instance_variable_set('@__awesome_methods__', self)
|
||||
methods.sort!
|
||||
end
|
||||
end
|
||||
end
|
16
lib/ap/core_ext/object.rb
Normal file
16
lib/ap/core_ext/object.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Copyright (c) 2010 Michael Dvorkin
|
||||
#
|
||||
# Awesome Print is freely distributable under the terms of MIT license.
|
||||
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
||||
#------------------------------------------------------------------------------
|
||||
class Object
|
||||
methods.grep(/methods$/) do |name|
|
||||
next if name.to_s.include? 'instance' # Instance methods are trapped in Class.
|
||||
define_method name do |*args|
|
||||
methods = super(*args)
|
||||
# And now the evil part :-)
|
||||
methods.instance_variable_set('@__awesome_methods__', self)
|
||||
methods.sort!
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,7 +8,7 @@ describe "Single method" do
|
|||
|
||||
it "color: should handle a method with no arguments" do
|
||||
method = ''.method(:upcase)
|
||||
method.ai.should == "\e[1;33mString\e[0m#\e[1;35mupcase\e[0m(\e[0;37m\e[0m)"
|
||||
method.ai.should == "\e[1;33mString\e[0m#\e[1;35mupcase\e[0m\e[0;37m()\e[0m"
|
||||
end
|
||||
|
||||
it "plain: should handle a method with one argument" do
|
||||
|
@ -18,7 +18,7 @@ describe "Single method" do
|
|||
|
||||
it "color: should handle a method with one argument" do
|
||||
method = ''.method(:match)
|
||||
method.ai.should == "\e[1;33mString\e[0m#\e[1;35mmatch\e[0m(\e[0;37marg1\e[0m)"
|
||||
method.ai.should == "\e[1;33mString\e[0m#\e[1;35mmatch\e[0m\e[0;37m(arg1)\e[0m"
|
||||
end
|
||||
|
||||
it "plain: should handle a method with two arguments" do
|
||||
|
@ -28,7 +28,7 @@ describe "Single method" do
|
|||
|
||||
it "color: should handle a method with two arguments" do
|
||||
method = ''.method(:tr)
|
||||
method.ai.should == "\e[1;33mString\e[0m#\e[1;35mtr\e[0m(\e[0;37marg1, arg2\e[0m)"
|
||||
method.ai.should == "\e[1;33mString\e[0m#\e[1;35mtr\e[0m\e[0;37m(arg1, arg2)\e[0m"
|
||||
end
|
||||
|
||||
it "plain: should handle a method with multiple arguments" do
|
||||
|
@ -38,7 +38,7 @@ describe "Single method" do
|
|||
|
||||
it "color: should handle a method with multiple arguments" do
|
||||
method = ''.method(:split)
|
||||
method.ai.should == "\e[1;33mString\e[0m#\e[1;35msplit\e[0m(\e[0;37marg1, ...\e[0m)"
|
||||
method.ai.should == "\e[1;33mString\e[0m#\e[1;35msplit\e[0m\e[0;37m(arg1, ...)\e[0m"
|
||||
end
|
||||
|
||||
it "plain: should handle a method defined in mixin" do
|
||||
|
@ -48,6 +48,81 @@ describe "Single method" do
|
|||
|
||||
it "color: should handle a method defined in mixin" do
|
||||
method = ''.method(:grep)
|
||||
method.ai.should == "\e[1;33mString (Enumerable)\e[0m#\e[1;35mgrep\e[0m(\e[0;37marg1\e[0m)"
|
||||
method.ai.should == "\e[1;33mString (Enumerable)\e[0m#\e[1;35mgrep\e[0m\e[0;37m(arg1)\e[0m"
|
||||
end
|
||||
|
||||
it "plain: should handle an unbound method" do
|
||||
class Hello
|
||||
def world; end
|
||||
end
|
||||
method = Hello.instance_method(:world)
|
||||
method.ai(:plain => true).should == 'Hello (unbound)#world()'
|
||||
Object.instance_eval{ remove_const :Hello }
|
||||
end
|
||||
|
||||
it "color: should handle an unbound method" do
|
||||
class Hello
|
||||
def world(a,b); end
|
||||
end
|
||||
method = Hello.instance_method(:world)
|
||||
method.ai.should == "\e[1;33mHello (unbound)\e[0m#\e[1;35mworld\e[0m\e[0;37m(arg1, arg2)\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
describe "object.methods" do
|
||||
it "index: should handle object.methods" do
|
||||
out = nil.methods.ai(:plain => true).grep(/is_a\?/).first
|
||||
out.should =~ /^\s+\[\s*\d+\]\s+is_a\?\(arg1\)\s+NilClass \(Kernel\)\n$/
|
||||
end
|
||||
|
||||
it "no index: should handle object.methods" do
|
||||
out = nil.methods.ai(:plain => true, :index => false).grep(/is_a\?/).first
|
||||
out.should =~ /^\s+is_a\?\(arg1\)\s+NilClass \(Kernel\)\n$/
|
||||
end
|
||||
end
|
||||
|
||||
describe "object.public_methods" do
|
||||
it "index: should handle object.public_methods" do
|
||||
out = nil.public_methods.ai(:plain => true).grep(/is_a\?/).first
|
||||
out.should =~ /^\s+\[\s*\d+\]\s+is_a\?\(arg1\)\s+NilClass \(Kernel\)\n$/
|
||||
end
|
||||
|
||||
it "no index: should handle object.public_methods" do
|
||||
out = nil.public_methods.ai(:plain => true, :index => false).grep(/is_a\?/).first
|
||||
out.should =~ /^\s+is_a\?\(arg1\)\s+NilClass \(Kernel\)\n$/
|
||||
end
|
||||
end
|
||||
|
||||
describe "object.private_methods" do
|
||||
it "index: should handle object.private_methods" do
|
||||
out = nil.private_methods.ai(:plain => true).grep(/sleep/).first
|
||||
out.should =~ /^\s+\[\s*\d+\]\s+sleep\(arg1,\s\.{3}\)\s+NilClass \(Kernel\)\n$/
|
||||
end
|
||||
|
||||
it "no index: should handle object.private_methods" do
|
||||
out = nil.private_methods.ai(:plain => true, :index => false).grep(/sleep/).first
|
||||
out.should =~ /^\s+sleep\(arg1,\s\.{3}\)\s+NilClass \(Kernel\)\n$/
|
||||
end
|
||||
end
|
||||
|
||||
describe "object.protected_methods" do
|
||||
it "index: should handle object.protected_methods" do
|
||||
class Hello
|
||||
protected
|
||||
def one; end
|
||||
def two; end
|
||||
end
|
||||
Hello.new.protected_methods.ai(:plain => true).should == "[\n [0] one() Hello\n [1] two() Hello\n]"
|
||||
Object.instance_eval{ remove_const :Hello }
|
||||
end
|
||||
|
||||
it "index: should handle object.protected_methods" do
|
||||
class Hello
|
||||
protected
|
||||
def world(a,b); end
|
||||
end
|
||||
Hello.new.protected_methods.ai(:plain => true, :index => false).should == "[\n world(arg1, arg2) Hello\n]"
|
||||
Object.instance_eval{ remove_const :Hello }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue