Created
May 31, 2011 14:47
-
-
Save Mon-Ouie/1000627 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# Colors | |
require 'ap' | |
require 'term/ansicolor' | |
# Change some stupid monkey patches | |
class String | |
%w[gray red green yellow blue | |
purple cyan white].each_with_index do |color, i| | |
define_method color do |*| "\033[1;#{30+i}m#{self}\033[0m" end | |
define_method :"#{color}ish" do |*| "\033[0;#{30+i}m#{self}\033[0m" end | |
end | |
include Term::ANSIColor | |
end | |
class Class | |
%w(instance_methods private_instance_methods protected_instance_methods | |
public_instance_methods).each do |name| | |
if method_defined? "original_#{name}" | |
alias_method "#{name}", "original_#{name}" | |
end | |
end | |
end | |
class Object | |
%w(methods private_methods protected_method | |
public_methods singleton_methods).each do |name| | |
if method_defined? "original_#{name}" | |
alias_method "#{name}", "original_#{name}" | |
end | |
end | |
end | |
Pry.print = proc do |output, value| | |
begin | |
output.puts "=> #{value.ai({})}" | |
rescue NoMethodError => e | |
output.puts "=> (unknown #{e})" | |
end | |
end | |
Pry.exception_handler = proc do |output, ex| | |
output.puts "#{ex.class.name.red.bold}: #{ex.message.italic}" | |
output.puts " from #{ex.backtrace.first}" | |
end | |
# Disable pager | |
Pry.pager = false | |
class AwesomePrint | |
class Inspection | |
def initialize(o) | |
@inspect = o | |
end | |
attr_reader :inspect | |
end | |
alias :old_mcd! :merge_custom_defaults! | |
def merge_custom_defaults! | |
colors = { | |
:module => :yellowish, | |
:string => :cyanish, | |
:symbol => :cyan, | |
:array => :pale, | |
:hash => :white, | |
:bignum => :blueish, | |
:bigdecimal => :blueish, | |
:complex => :blueish, | |
:rational => :blueish, | |
} | |
@options[:color].merge!(colors) | |
@options[:indent] = 2 | |
old_mcd! | |
end | |
def awesome_rational(n) | |
awesome_self n, :with => " ≈ #{n.to_f}" | |
end | |
def awesome_custom_inspect(object) | |
object.custom_ai | |
end | |
alias_method :old_printable, :printable unless method_defined? :old_printable | |
def printable(object) | |
if Kernel === object && object.respond_to?(:custom_ai) | |
:custom_inspect | |
else | |
old_printable(object) | |
end | |
end | |
end | |
# Custom commands | |
require 'slop' | |
module LsHelpers | |
def strip_colors_if_needed(str) | |
Pry.color ? str : strip_color(str) | |
end | |
def variables(scope, reg, verbose) | |
var_array = target.eval("#{scope}_variables").grep(reg) | |
if verbose | |
var_hash = {} | |
var_array.each do |name| | |
var_hash[name.to_sym] = target.eval(name.to_s) | |
end | |
var_hash | |
else | |
var_array | |
end | |
end | |
def constant_list(reg, verbose) | |
const_array = target.eval("constants").grep(reg) | |
if verbose | |
const_hash = {} | |
const_array.each do |name| | |
const_hash[name.to_sym] = target.eval("self").const_get(name) | |
end | |
const_hash | |
else | |
const_array | |
end | |
end | |
def method_info(method) | |
args = '' | |
if method.respond_to?(:parameters) && (arg_ary = method.parameters) | |
arg_ary.map!.each_with_index do |(type, name), index| | |
name ||= "arg#{index + 1}" | |
case type | |
when :req then "#{name}" | |
when :opt then "#{name} = ?" | |
when :rest then "*#{name}" | |
when :block then "&#{name}" | |
else name | |
end | |
end | |
args = '(' + arg_ary.join(', ') + ')' | |
elsif method.arity == 0 | |
args = "()" | |
elsif method.arity > 0 | |
n = method.arity | |
args = '(' + (1..n).map { |i| "arg#{i}" }.join(", ") + ')' | |
elsif method.arity < 0 | |
n = -method.arity | |
args = '(' + (1..n).map { |i| "arg#{i}" }.join(", ") + ')' | |
end | |
klass = if method.respond_to? :owner | |
method.owner.name | |
elsif method.inspect =~ /Method: (.*?)#/ | |
$1 | |
end | |
location = if method.respond_to? :source_location | |
file, line = method.source_location | |
"#{file}:#{line}" if file && line | |
end | |
[method.name.to_s, args, klass.to_s, location] | |
end | |
def print_method_list(output, methods, regexp, more, verbose, &block) | |
methods -= Object.instance_methods unless more | |
methods = methods.grep(regexp) | |
data = methods.sort.map do |name| | |
method_info(yield name) | |
end | |
max_name = data.map { |item| item[0].size }.max | |
max_args = data.map { |item| item[1].size }.max | |
max_klass = data.map { |item| item[2].size }.max | |
data.each do |(name, args, klass, location)| | |
str = " #{yellow(name.rjust(max_name))}" | |
str << args.ljust(max_args).blue | |
str << " #{gray(klass.ljust(max_klass))}" | |
str << " (#{location})" if verbose && location | |
output.puts str | |
end | |
end | |
def italic(string) | |
Pry.color ? "\033[#{3}m#{string}\033[0m" : string | |
end | |
def yellow(string) | |
Pry.color ? "\033[1;#{33}m#{string}\033[0m" : string | |
end | |
def gray(string) | |
Pry.color ? "\033[1;#{37}m#{string}\033[0m" : string | |
end | |
end | |
module YriHelpers | |
def wrap_text(text, columns = 80) | |
text = text.dup | |
res = [] | |
while text.length > columns | |
if text[0, columns] =~ /^(.+\s)(\S+)$/ | |
res << $1 | |
text = $2 + text[columns..-1] | |
else | |
res << text[0, columns] | |
text[0...columns] = '' | |
end | |
end | |
res << text | |
res | |
end | |
def signature_for(info) | |
sig = "#{info.name.to_s.cyan}(" + info.parameters.map { |(param, default)| | |
if default | |
"#{param} = #{default}" | |
else | |
param | |
end | |
}.join(", ") + ")" | |
if yield_tag = info.tag("yield") | |
args = yield_tag.types ? yield_tag.types.join(", ") : "" | |
args = "|#{args}| " unless args.empty? | |
sig << " { #{args}... }" | |
end | |
type = (tag = info.tag("return")) ? tag.type : "Object" | |
sig << " # => #{type.yellow}" | |
end | |
def format_parameter(param) | |
types = if param.types | |
param.types.map { |o| o.yellow }.join(', ') | |
else | |
"Object" | |
end | |
default = if param.respond_to? :defaults and param.defaults | |
" (default: #{param.defaults.join(", ")})" | |
end | |
text = (param.text || "").gsub("\n", "\n" + " " * 6) | |
" — (#{types}) #{param.name.bold}#{default} #{text}" | |
end | |
def document_info(info, output) | |
doc = info.docstring.split("\n") | |
doc.each do |line| | |
if line[0, 2] == " " * 2 | |
output.puts CodeRay.scan(line, :ruby).term | |
else | |
output.puts line | |
end | |
end | |
if deprecated = info.tag("deprecated") | |
output.puts | |
output.puts "#{'DEPRECATED:'.red.bold} #{deprecated.text}" | |
end | |
if note = info.tag("note") | |
output.puts | |
output.puts "#{'NOTE:'.red.bold} #{note.text}" | |
end | |
if abstract = info.tag("abstract") | |
output.puts | |
output.puts "#{'Abstract:'.bold} #{abstract.text}" | |
end | |
unless info.tags("param").empty? | |
output.puts | |
output.puts "Parameters: ".italic | |
info.tags("param").each do |param| | |
output.puts format_parameter(param) | |
end | |
end | |
unless info.tags("option").empty? | |
info.tags("option").group_by(&:name).each do |name, opts| | |
output.puts | |
output.puts "Options for #{name.bold}: ".italic | |
opts.each do |opt| | |
output.puts format_parameter(opt.pair) | |
end | |
end | |
end | |
if yield_tag = info.tag("yield") | |
output.puts | |
output.print "#{'Yields:'.bold.italic} " | |
output.puts yield_tag.text.to_s.gsub("\n", "\n ") | |
unless info.tags("yieldparam").empty? | |
output.puts | |
output.puts "Block arguments: ".bold.italic | |
info.tags("yieldparam").each do |param| | |
output.puts format_parameter(param) | |
end | |
end | |
if ret = info.tag("yieldreturn") | |
output.print "Block returns: ".bold.italic | |
output.print "(#{(ret.types || %w[Object]).join(', ')}) " | |
output.puts ret.text.gsub("\n", "\n ") | |
end | |
end | |
unless info.tags("raise").empty? | |
output.puts | |
output.puts "Exceptions: ".bold | |
info.tags("raise").each do |tag| | |
output.print " — #{(tag.types || %w[Object]).join(', ')}: ".italic | |
output.puts tag.text | |
end | |
end | |
if ret = info.tag("return") | |
output.print "Returns: ".bold.italic | |
output.print "(#{(ret.types || %w[Object]).join(', ')}) " | |
output.puts ret.text.to_s.gsub("\n", "\n ") | |
end | |
unless info.tags("example").empty? | |
info.tags("example").each do |ex| | |
output.puts | |
output.puts "Example: #{ex.name.bold}:".italic | |
code = " " + CodeRay.scan(ex.text, :ruby).term.gsub("\n", "\n ") | |
output.puts code | |
end | |
end | |
unless info.tags("see").empty? | |
output.puts | |
output.puts "See also: ".bold | |
info.tags("see").each do |tag| | |
output.puts " — #{tag.text}" | |
end | |
end | |
if author = info.tag("author") | |
output.puts | |
output.puts "#{'Author:'.bold} #{author.text}" | |
end | |
end | |
end | |
class Pry::CommandContext | |
include YriHelpers | |
include LsHelpers | |
end | |
Commands = Pry::CommandSet.new Pry::Commands do | |
alias_command "gist", "gist-method" | |
command "req" do |*args| | |
args.each { |arg| require arg } | |
end | |
command "ls", "Show the list of vars and methods in the current scope. Type `ls --help` for more info." do |*args| | |
p args | |
require 'slop' | |
opts = Slop.parse args do | |
on :v, :verbose, "Show value of variables and constants and locations of methods" | |
on :L, :less, "Only show methods set by the receiver" | |
on :a, :more, "Show all of the methods, including those defined in Object" | |
on :f, :filter, "Regular expression to filter methods and variables", | |
true, :default => "" | |
on :l, :locals, "Show local variables" | |
on :g, :globals, "Show global variables" | |
on :i, 'instance-variables', "Show instance variables" | |
on :k, 'class-variables', "Show class variables" | |
on :c, :constants, "Show constants" | |
on :m, :methods, "Show methods" | |
on :M, 'instance-methods', "Show instance methods" | |
on :h, :help, 'Print this help message', :tail => true | |
end | |
if opts.help? || args.empty? | |
puts opts.help | |
next | |
end | |
regexp = Regexp.new(opts[:filter], 'i') | |
if opts.locals? | |
output.print italic("Local variables: ") | |
output.puts strip_colors_if_needed(variables(:local, regexp, | |
opts.verbose?).ai({})) | |
output.puts | |
end | |
if opts.globals? | |
output.print italic("Global variables: ") | |
output.puts strip_colors_if_needed(variables(:global, regexp, | |
opts.verbose?).ai({})) | |
output.puts | |
end | |
if opts['instance-variables'] | |
output.print italic("Instance variables: ") | |
output.puts strip_colors_if_needed(variables(:instance, regexp, | |
opts.verbose?).ai({})) | |
output.puts | |
end | |
if opts['class-variables'] | |
output.print italic("Class variables: ") | |
if Module === target.eval('self') | |
output.puts strip_colors_if_needed(variables(:class, regexp, | |
opts.verbose?).ai({})) | |
else | |
output.puts "(not a module)" | |
end | |
output.puts | |
end | |
if opts.constants? | |
output.print italic("Constant: ") | |
if Module === target.eval('self') | |
output.puts strip_colors_if_needed(constant_list(regexp, | |
opts.verbose?).ai({})) | |
else | |
output.puts "(not a module)" | |
end | |
output.puts | |
end | |
if opts['instance-methods'] | |
output.print italic("Instance methods: ") | |
if Module === target.eval('self') | |
obj = target.eval("self") | |
output.puts | |
print_method_list(output, obj.instance_methods(!opts.less?), | |
regexp, opts.more?, opts.verbose?) do |name| | |
obj.instance_method(name) | |
end | |
else | |
output.puts "(not a module)" | |
end | |
output.puts | |
end | |
if opts.methods? | |
output.puts italic("Methods: ") | |
obj = target.eval("self") | |
print_method_list(output, obj.methods(!opts.less?), | |
regexp, opts.more?, opts.verbose?) do |name| | |
obj.method(name) | |
end | |
output.puts | |
end | |
end | |
def self.wrap_text(text, columns = 80) | |
text = text.dup | |
res = [] | |
while text.length > columns | |
if text[0, columns] =~ /^(.+\s)(\S+)$/ | |
res << $1 | |
text = $2 + text[columns..-1] | |
else | |
res << text[0, columns] | |
text[0...columns] = '' | |
end | |
end | |
res << text | |
res | |
end | |
def self.signature_for(info) | |
sig = "#{info.name.to_s.cyan}(" + info.parameters.map { |(param, default)| | |
if default | |
"#{param} = #{default}" | |
else | |
param | |
end | |
}.join(", ") + ")" | |
if yield_tag = info.tag("yield") | |
args = yield_tag.types ? yield_tag.types.join(", ") : "" | |
args = "|#{args}| " unless args.empty? | |
sig << " { #{args}... }" | |
end | |
type = (tag = info.tag("return")) ? tag.type : "Object" | |
sig << " # => #{type.yellow}" | |
end | |
def self.format_parameter(param) | |
types = if param.types | |
param.types.map { |o| o.yellow }.join(', ') | |
else | |
"Object" | |
end | |
default = if param.respond_to? :defaults and param.defaults | |
" (default: #{param.defaults.join(", ")})" | |
end | |
text = (param.text || "").gsub("\n", "\n" + " " * 6) | |
" — (#{types}) #{param.name.bold}#{default} #{text}" | |
end | |
def self.document_info(info, output) | |
doc = info.docstring.split("\n") | |
doc.each do |line| | |
if line[0, 2] == " " * 2 | |
output.puts CodeRay.scan(line, :ruby).term | |
else | |
output.puts line | |
end | |
end | |
if deprecated = info.tag("deprecated") | |
output.puts | |
output.puts "#{'DEPRECATED:'.red.bold} #{deprecated.text}" | |
end | |
if note = info.tag("note") | |
output.puts | |
output.puts "#{'NOTE:'.red.bold} #{note.text}" | |
end | |
if abstract = info.tag("abstract") | |
output.puts | |
output.puts "#{'Abstract:'.bold} #{abstract.text}" | |
end | |
unless info.tags("param").empty? | |
output.puts | |
output.puts "Parameters: ".italic | |
info.tags("param").each do |param| | |
output.puts format_parameter(param) | |
end | |
end | |
unless info.tags("option").empty? | |
info.tags("option").group_by(&:name).each do |name, opts| | |
output.puts | |
output.puts "Options for #{name.bold}: ".italic | |
opts.each do |opt| | |
output.puts format_parameter(opt.pair) | |
end | |
end | |
end | |
if yield_tag = info.tag("yield") | |
output.puts | |
output.print "#{'Yields:'.bold.italic} " | |
output.puts yield_tag.text.to_s.gsub("\n", "\n ") | |
unless info.tags("yieldparam").empty? | |
output.puts | |
output.puts "Block arguments: ".bold.italic | |
info.tags("yieldparam").each do |param| | |
output.puts format_parameter(param) | |
end | |
end | |
if ret = info.tag("yieldreturn") | |
output.print "Block returns: ".bold.italic | |
output.print "(#{(ret.types || %w[Object]).join(', ')}) " | |
output.puts ret.text.gsub("\n", "\n ") | |
end | |
end | |
unless info.tags("raise").empty? | |
output.puts | |
output.puts "Exceptions: ".bold | |
info.tags("raise").each do |tag| | |
output.print " — #{(tag.types || %w[Object]).join(', ')}: ".italic | |
output.puts tag.text | |
end | |
end | |
if ret = info.tag("return") | |
output.print "Returns: ".bold.italic | |
output.print "(#{(ret.types || %w[Object]).join(', ')}) " | |
output.puts ret.text.to_s.gsub("\n", "\n ") | |
end | |
unless info.tags("example").empty? | |
info.tags("example").each do |ex| | |
output.puts | |
output.puts "Example: #{ex.name.bold}:".italic | |
code = " " + CodeRay.scan(ex.text, :ruby).term.gsub("\n", "\n ") | |
output.puts code | |
end | |
end | |
unless info.tags("see").empty? | |
output.puts | |
output.puts "See also: ".bold | |
info.tags("see").each do |tag| | |
output.puts " — #{tag.text}" | |
end | |
end | |
if author = info.tag("author") | |
output.puts | |
output.puts "#{'Author:'.bold} #{author.text}" | |
end | |
end | |
command "yri", "Retrieve documentation from YARD" do |*args| | |
opts = Slop.parse! args do | |
on :m, "Use methods" | |
on :M, "Use instance methods" | |
on :s, :source, "Show source code" | |
end | |
method_name = args.shift | |
method = get_method_object(method_name, target, opts.to_hash(true)) | |
unless method | |
output.puts "Could not find the method!" | |
next | |
end | |
info = Pry::MethodInfo.info_for(method) | |
unless info | |
output.puts "Could not find the documentation!" | |
next | |
end | |
output.puts "-" * 80 | |
unless (overloads = info.tags("overload")).empty? | |
overloads.each do |overload| | |
output.puts wrap_text(signature_for(overload)) | |
end | |
else | |
output.puts wrap_text(signature_for(info)) | |
end | |
output.puts "-" * 80 | |
document_info(info, output) | |
info.tags("overload").each do |overload| | |
output.puts | |
output.puts "-" * 80 | |
output.puts "Overload: #{signature_for(overload)}".bold.italic | |
output.puts "-" * 80 | |
document_info(overload, output) | |
end | |
if opts.source? | |
output.puts | |
output.puts "Source code: ".bold.italic | |
source = CodeRay.scan(info.source.to_s, info.source_type).term | |
output.puts " " + source.gsub("\n", "\n ") | |
end | |
end | |
alias_command "ri", "yri" | |
end | |
Pry.commands = Commands | |
# Require current project | |
$: << File.expand_path('.') | |
if File.exist? "lib" | |
$:.unshift File.expand_path("./lib") | |
$:.unshift File.expand_path("./ext") if File.exist? "ext" | |
begin | |
require File.basename(Dir.pwd) | |
rescue LoadError | |
end | |
end | |
if defined? Ray::Matrix | |
class Ray::Matrix | |
def custom_ai | |
res = content.each_slice(4).map { |o| | |
AwesomePrint::Inspection.new(o.inspect) | |
}.ai({}) | |
"#<#{self.class}> #{res}" | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment