Skip to content

Instantly share code, notes, and snippets.

@Mon-Ouie
Created May 31, 2011 14:47
Show Gist options
  • Save Mon-Ouie/1000627 to your computer and use it in GitHub Desktop.
Save Mon-Ouie/1000627 to your computer and use it in GitHub Desktop.
# -*- 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