2011-05-01 10:25:37 +00:00
|
|
|
class Pry
|
|
|
|
module DefaultCommands
|
|
|
|
|
2011-05-07 05:32:05 +00:00
|
|
|
Ls = Pry::CommandSet.new do
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-06-15 13:38:23 +00:00
|
|
|
helpers do
|
2011-10-08 07:53:27 +00:00
|
|
|
# Get all the methods that we'll want to output
|
|
|
|
def all_methods(obj, opts)
|
|
|
|
opts.M? ? Pry::Method.all_from_class(obj) : Pry::Method.all_from_obj(obj)
|
|
|
|
end
|
|
|
|
|
|
|
|
def singleton_class(obj); class << obj; self; end end
|
|
|
|
|
|
|
|
def resolution_order(obj, opts)
|
|
|
|
opts.M? ? Pry::Method.instance_resolution_order(obj) : Pry::Method.resolution_order(obj)
|
2011-06-20 08:27:41 +00:00
|
|
|
end
|
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
# Get the name of the klass for pretty display in the title column of ls -m
|
|
|
|
# as there can only ever be one singleton class of a non-class, we just call
|
|
|
|
# that "self".
|
|
|
|
def class_name(klass)
|
|
|
|
if klass == klass.ancestors.first
|
|
|
|
(klass.name || "") == "" ? klass.to_s : klass.name
|
|
|
|
elsif klass.ancestors.include?(Module)
|
|
|
|
begin
|
|
|
|
"#{class_name(ObjectSpace.each_object(klass).detect{ |x| singleton_class(x) == klass })}.self"
|
|
|
|
rescue # ObjectSpace is not enabled by default in jruby
|
|
|
|
klass.to_s.sub(/#<(Module|Class):(.*)>/, '\2.self')
|
|
|
|
end
|
2011-06-15 13:38:23 +00:00
|
|
|
else
|
2011-10-08 07:53:27 +00:00
|
|
|
"self"
|
2011-06-15 13:38:23 +00:00
|
|
|
end
|
|
|
|
end
|
2011-08-09 10:29:05 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
# Get a lambda that can be used with .take_while to prevent over-eager
|
|
|
|
# traversal of the Object's ancestry graph.
|
|
|
|
def below_ceiling(obj, opts)
|
|
|
|
ceiling = if opts.q?
|
|
|
|
[opts.M? ? obj.ancestors[1] : obj.class.ancestors[1]] + [Object, Module, Class]
|
|
|
|
elsif opts.v?
|
|
|
|
[]
|
|
|
|
else
|
|
|
|
[Module, Object, Class] #TODO: make configurable
|
|
|
|
end
|
|
|
|
|
|
|
|
# We always want to show *something*, so if this object is actually a base type,
|
|
|
|
# then we'll show the class itself, but none of its ancestors nor modules.
|
|
|
|
ceiling.map!{ |klass| (obj.class == klass || obj == klass) ? klass.ancestors[1] : klass }
|
|
|
|
|
|
|
|
lambda { |klass| !ceiling.include?(klass) }
|
|
|
|
end
|
|
|
|
|
|
|
|
# Format and colourise a list of methods.
|
|
|
|
def format_methods(methods)
|
|
|
|
methods.sort_by(&:name).map do |method|
|
|
|
|
if method.name == 'method_missing'
|
|
|
|
text.red('method_missing') # This should stand out!
|
|
|
|
elsif method.visibility == :private
|
|
|
|
text.blue(method.name) # TODO: make colours configurable
|
|
|
|
elsif method.visibility == :protected
|
|
|
|
text.purple(method.name)
|
|
|
|
else
|
|
|
|
method.name
|
|
|
|
end
|
|
|
|
end.join(" ")
|
|
|
|
end
|
|
|
|
|
|
|
|
def output_variables(type, vars)
|
|
|
|
vars = vars.sort_by(&:downcase).join(" ")
|
|
|
|
output_section(type, text.send(ls_color_map[type], vars)) if vars.strip != ""
|
|
|
|
end
|
|
|
|
|
|
|
|
def format_constants(mod, constants)
|
|
|
|
constants.sort_by(&:downcase).map do |name|
|
|
|
|
if const = (mod.const_get(name) rescue nil)
|
|
|
|
if (const < Exception rescue false)
|
|
|
|
text.purple(name)
|
|
|
|
elsif (Module === mod.const_get(name) rescue false)
|
|
|
|
text.blue(name)
|
|
|
|
else
|
|
|
|
name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end.compact.join(" ")
|
|
|
|
end
|
|
|
|
|
|
|
|
# Add a new section to the output. Outputs nothing if the section would be empty.
|
|
|
|
def output_section(heading, body)
|
|
|
|
output.puts "#{text.bold(heading)}: #{body}" if body.strip != ""
|
|
|
|
end
|
|
|
|
|
2011-08-09 10:29:05 +00:00
|
|
|
def ls_color_map
|
|
|
|
{
|
2011-09-07 15:39:22 +00:00
|
|
|
"local variables" => Pry.config.ls.local_var_color,
|
|
|
|
"instance variables" => Pry.config.ls.instance_var_color,
|
|
|
|
"class variables" => Pry.config.ls.class_var_color,
|
|
|
|
"global variables" => Pry.config.ls.global_var_color,
|
|
|
|
"public methods" => Pry.config.ls.method_color,
|
|
|
|
"private methods" => Pry.config.ls.method_color,
|
|
|
|
"protected methods" => Pry.config.ls.method_color,
|
|
|
|
"constants" => Pry.config.ls.constant_color
|
2011-08-09 10:29:05 +00:00
|
|
|
}
|
|
|
|
end
|
2011-06-15 13:38:23 +00:00
|
|
|
end
|
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
command "ls", "Show the list of vars and methods in the current scope. Type `ls --help` for more info.",
|
|
|
|
:shellwords => false, :interpolate => false do |*args|
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
# have we been passed any options about what to show (exclude q and v because they're just tweaks)
|
|
|
|
has_opts = args.first && args.any?{ |arg| arg.start_with?("-") && arg.tr("-qv", "") != "" }
|
2011-10-01 23:57:39 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
opts = Slop.parse!(args, :strict => true) do |opt|
|
|
|
|
opt.banner unindent <<-USAGE
|
|
|
|
Usage: ls [-m|-M] [-p] [-q|-v] [-g] [-l] [-c] [-i] [Object]
|
2011-10-01 23:57:39 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
ls shows you which methods, constants and variables are accessible to Pry. By default it shows you
|
|
|
|
the local variables defined in the current shell, and any public methods or instance variables defined
|
|
|
|
on the current object.
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
The -c flag lists constants, either in the top-level if given no argument or in the namespace that you
|
|
|
|
specify. Exceptions are coloured purple, other Classes are blue and anything else is black.
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
The -m flag lists methods defined on an object, while the -M flag lists methods defined in a class. In
|
|
|
|
both cases the -p flag shows private methods (in blue) and protected methods (in purple).
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
The -v flag can be used to show all methods and constants. By default methods and constants available
|
|
|
|
on all objects are not shown. The -q flag removes more methods, only displaying those
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
USAGE
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
opt.on :m, "methods", "Show public methods defined on the Object"
|
|
|
|
opt.on :M, "module", "Show methods defined in a Module or Class"
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
opt.on :p, "ppp", "Show public, protected and private methods (by default only public methods are shown)"
|
|
|
|
opt.on :q, "quiet", "Show only methods defined on object.singleton_class and object.class (See Pry.config.ls_ceiling)"
|
|
|
|
opt.on :v, "verbose", "Show methods on all super-classes (ignores Pry.config.ls_ceiling)"
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
opt.on :g, "globals", "Show globals"
|
|
|
|
opt.on :l, "locals", "Show locals"
|
|
|
|
opt.on :c, "constants", "Show constants"
|
|
|
|
opt.on :i, "ivars", "Show instance and class variables"
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
opt.on :h, "help", "Show help"
|
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
next output.puts(opts) if opts.h?
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
obj = args.empty? ? target_self : target.eval(args.join(" "))
|
|
|
|
show_methods = opts.m? || opts.M? || opts.p? || !has_opts
|
|
|
|
show_constants = opts.c? || (!has_opts && Module === obj || TOPLEVEL_BINDING.eval('self') == obj)
|
|
|
|
show_ivars = opts.i? || !has_opts
|
|
|
|
show_locals = opts.l? || (!has_opts && args.empty?)
|
2011-06-15 13:38:23 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
raise Pry::CommandError, "-l does not make sense with a specified Object" if opts.l? && !args.empty?
|
|
|
|
raise Pry::CommandError, "-g does not make sense with a specified Object" if opts.g? && !args.empty?
|
|
|
|
raise Pry::CommandError, "-q does not make sense with -v" if opts.q? && opts.v?
|
|
|
|
raise Pry::CommandError, "-M only makes sense with a Module or a Class" if opts.M? && !(Module === obj)
|
|
|
|
raise Pry::CommandError, "-c only makes sense with a Module or a Class" if opts.c? && !args.empty? && !(Module === obj)
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
if opts.g?
|
|
|
|
output_variables("global variables", target.eval("global_variables"))
|
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
if show_constants
|
|
|
|
mod = Module === obj ? obj : Object
|
|
|
|
constants = mod.constants
|
|
|
|
constants -= (mod.ancestors - [mod]).map(&:constants).flatten unless opts.v?
|
|
|
|
output_section("Constants", format_constants(mod, constants))
|
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
if show_methods
|
|
|
|
# methods is a hash {Module/Class => [Pry::Methods]}
|
|
|
|
methods = all_methods(obj, opts).select{ |method| opts.p? || method.visibility == :public }.group_by(&:owner)
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
# reverse the resolution order so that the most useful information appears right by the prompt
|
|
|
|
resolution_order(obj, opts).take_while(&below_ceiling(obj, opts)).reverse.each do |klass|
|
|
|
|
output_section "#{class_name(klass)} methods", format_methods(methods[klass] || [])
|
2011-05-01 10:25:37 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
if show_ivars
|
2011-10-08 07:58:44 +00:00
|
|
|
output_variables("instance variables", obj.__send__(:instance_variables))
|
|
|
|
output_variables("class variables", (Module === obj ? obj : obj.class).__send__(:class_variables))
|
2011-10-08 07:53:27 +00:00
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
|
2011-10-08 07:53:27 +00:00
|
|
|
if show_locals
|
|
|
|
output_variables("local variables", target.eval("local_variables"))
|
|
|
|
end
|
|
|
|
end
|
2011-05-01 10:25:37 +00:00
|
|
|
end
|
|
|
|
end
|
2011-05-19 15:53:44 +00:00
|
|
|
end
|