class Pry::Command::Ls

Constants

BUILTIN_GLOBALS

ruby.runpaint.org/globals, and running “puts global_variables.inspect”.

PSEUDO_GLOBALS

$SAFE and $? are thread-local, the exception stuff only works in a rescue clause, everything else is basically a local variable with a $ in its name.

Attributes

grep[R]
grep_regex[R]
has_user_specified_any_options[R]
object_to_interrogate[R]

Public Instance Methods

options(opt) click to toggle source
# File lib/pry/commands/ls.rb, line 8
def options(opt)
  opt.banner unindent <<-'BANNER'
    Usage: ls [-m|-M|-p|-pM] [-q|-v] [-c|-i] [Object]
           ls [-g] [-l]

    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.

    The colours used are configurable using Pry.config.ls.*_color, and the separator
    is Pry.config.ls.separator.

    Pry.config.ls.ceiling is used to hide methods defined higher up in the
    inheritance chain, this is by default set to [Object, Module, Class] so that
    methods defined on all Objects are omitted. The -v flag can be used to ignore
    this setting and show all methods, while the -q can be used to set the ceiling
    much lower and show only methods defined on the object or its direct class.
  BANNER

  opt.on :m, :methods,   "Show public methods defined on the Object (default)"
  opt.on :M, "instance-methods", "Show methods defined in a Module or Class"
  opt.on :p, :ppp,       "Show public, protected (in yellow) and private (in green) methods"
  opt.on :q, :quiet,     "Show only methods defined on object.singleton_class and object.class"
  opt.on :v, :verbose,   "Show methods and constants on all super-classes (ignores Pry.config.ls.ceiling)"
  opt.on :g, :globals,   "Show global variables, including those builtin to Ruby (in cyan)"
  opt.on :l, :locals,    "Show hash of local vars, sorted by descending size"
  opt.on :c, :constants, "Show constants, highlighting classes (in blue), and exceptions (in purple).\n" +
  " " * 32 +             "Constants that are pending autoload? are also shown (in yellow)"
  opt.on :i, :ivars,     "Show instance variables (in blue) and class variables (in bright blue)"
  opt.on :G, :grep,      "Filter output by regular expression", :argument => true

  if jruby?
    opt.on :J, "all-java", "Show all the aliases for methods from java (default is to show only prettiest)"
  end
end
process() click to toggle source
# File lib/pry/commands/ls.rb, line 46
def process
  @object_to_interrogate = args.empty? ? target_self : target.eval(args.join(" "))

  # exclude -q, -v and --grep because they don't specify what the user wants to see.
  @has_user_specified_any_options = (opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) ||
                                      opts.present?(:globals) || opts.present?(:locals) || opts.present?(:constants) ||
                                      opts.present?(:ivars))

  @grep_regex, @grep = [Regexp.new(opts[:G] || "."), lambda{ |x| x.grep(@grep_regex) }]

  raise_errors_if_arguments_are_weird

  all_output = [
    write_out_globals,
    write_out_constants,
    write_out_methods,
    write_out_self_methods,
    write_out_ivars,
    write_out_local_names,
    write_out_locals,
  ].compact.join("")

  stagger_output(all_output)
end

Private Instance Methods

all_methods(obj, instance_methods=false) click to toggle source

Get all the methods that we'll want to output

# File lib/pry/commands/ls.rb, line 88
def all_methods(obj, instance_methods=false)
  methods = if instance_methods || opts.present?(:'instance-methods')
              Pry::Method.all_from_class(obj)
            else
              Pry::Method.all_from_obj(obj)
            end

  if jruby? && !opts.present?(:J)
    methods = trim_jruby_aliases(methods)
  end

  methods.select{ |method| opts.present?(:ppp) || method.visibility == :public }
end
below_ceiling(obj) click to toggle source

Get a lambda that can be used with .take_while to prevent over-eager traversal of the Object's ancestry graph.

# File lib/pry/commands/ls.rb, line 154
def below_ceiling(obj)
  ceiling = if opts.present?(:quiet)
               [opts.present?(:'instance-methods') ? obj.ancestors[1] : obj.class.ancestors[1]] + Pry.config.ls.ceiling
             elsif opts.present?(:verbose)
               []
             else
               Pry.config.ls.ceiling.dup
             end

  lambda { |klass| !ceiling.include?(klass) }
end
color(type, str) click to toggle source

Color output based on config.ls.*_color

# File lib/pry/commands/ls.rb, line 332
def color(type, str)
  text.send(Pry.config.ls.send(:"#{type}_color"), str)
end
colorized_assignment_style(lhs, rhs, desired_width = 7) click to toggle source
# File lib/pry/commands/ls.rb, line 311
def colorized_assignment_style(lhs, rhs, desired_width = 7)
  colorized_lhs = color(:local_var, lhs)
  color_escape_padding = colorized_lhs.size - lhs.size
  pad = desired_width + color_escape_padding
  "%-#{pad}s = %s" % [color(:local_var, colorized_lhs), rhs]
end
format_constants(mod, constants) click to toggle source
# File lib/pry/commands/ls.rb, line 265
def format_constants(mod, constants)
  constants.sort_by(&:downcase).map do |name|
    if const = (!mod.autoload?(name) && (mod.const_get(name) || true) rescue nil)
      if (const < Exception rescue false)
        color(:exception_constant, name)
      elsif (Module === mod.const_get(name) rescue false)
        color(:class_constant, name)
      else
        color(:constant, name)
      end
    else
      color(:unloaded_constant, name)
    end
  end
end
format_globals(globals) click to toggle source
# File lib/pry/commands/ls.rb, line 281
def format_globals(globals)
  globals.sort_by(&:downcase).map do |name|
    if PSEUDO_GLOBALS.include?(name)
      color(:pseudo_global, name)
    elsif BUILTIN_GLOBALS.include?(name)
      color(:builtin_global, name)
    else
      color(:global_var, name)
    end
  end
end
format_local_names(locals) click to toggle source
# File lib/pry/commands/ls.rb, line 293
def format_local_names(locals)
  locals.sort_by(&:downcase).map do |name|
    if _pry_.sticky_locals.include?(name.to_sym)
      color(:pry_var, name)
    else
      color(:local_var, name)
    end
  end
end
format_locals(name_value_pairs) click to toggle source
# File lib/pry/commands/ls.rb, line 303
def format_locals(name_value_pairs)
  name_value_pairs.sort_by do |name, value|
    value.to_s.size
  end.reverse.map do |name, value|
    colorized_assignment_style(name, format_value(value))
  end
end
format_methods(methods) click to toggle source

Format and colourise a list of methods.

# File lib/pry/commands/ls.rb, line 247
def format_methods(methods)
  methods.sort_by(&:name).map do |method|
    if method.name == 'method_missing'
      color(:method_missing, 'method_missing')
    elsif method.visibility == :private
      color(:private_method, method.name)
    elsif method.visibility == :protected
      color(:protected_method, method.name)
    else
      color(:public_method, method.name)
    end
  end
end
format_value(value) click to toggle source
# File lib/pry/commands/ls.rb, line 318
def format_value(value)
  accumulator = StringIO.new
  Pry.output_with_default_format(accumulator, value, :hashrocket => false)
  accumulator.string
end
format_variables(type, vars) click to toggle source
# File lib/pry/commands/ls.rb, line 261
def format_variables(type, vars)
  vars.sort_by(&:downcase).map{ |var| color(type, var) }
end
interrogating_a_module?() click to toggle source
# File lib/pry/commands/ls.rb, line 178
def interrogating_a_module?
  (Module === object_to_interrogate)
end
output_section(heading, body) click to toggle source

Add a new section to the output. Outputs nothing if the section would be empty.

# File lib/pry/commands/ls.rb, line 325
def output_section(heading, body)
  return "" if body.compact.empty?
  fancy_heading = text.bold(color(:heading, heading))
  Pry::Helpers.tablify_or_one_line(fancy_heading, body)
end
raise_errors_if_arguments_are_weird() click to toggle source
# File lib/pry/commands/ls.rb, line 166
def raise_errors_if_arguments_are_weird
  [
    ["-l does not make sense with a specified Object", :locals,             !args.empty?],
    ["-g does not make sense with a specified Object", :globals,            !args.empty?],
    ["-q does not make sense with -v",                 :quiet,              opts.present?(:verbose)],
    ["-M only makes sense with a Module or a Class",   :'instance-methods', !interrogating_a_module?],
    ["-c only makes sense with a Module or a Class",   :constants,          !args.empty? && !interrogating_a_module?],
  ].each do |message, option, expression|
    raise Pry::CommandError, message if opts.present?(option) && expression
  end
end
resolution_order(obj) click to toggle source
# File lib/pry/commands/ls.rb, line 148
def resolution_order(obj)
  opts.present?(:'instance-methods') ? Pry::Method.instance_resolution_order(obj) : Pry::Method.resolution_order(obj)
end
rubbishness(name) click to toggle source

When removing jruby aliases, we want to keep the alias that is “least rubbish” according to this metric.

# File lib/pry/commands/ls.rb, line 135
def rubbishness(name)
  name.each_char.map{ |x|
    case x
    when /[A-Z]/
      1
    when '?', '=', '!'
      -2
    else
      0
    end
  }.inject(&:+) + (name.size / 100.0)
end
trim_jruby_aliases(methods) click to toggle source

JRuby creates lots of aliases for methods imported from java in an attempt to make life easier for ruby programmers. (e.g. getFooBar becomes get_foo_bar and foo_bar, and maybe foo_bar? if it returns a Boolean). The full transformations are in the assignAliases method of:

https://github.com/jruby/jruby/blob/master/src/org/jruby/javasupport/JavaClass.java

This has the unfortunate side-effect of making the output of ls even more incredibly verbose than it normally would be for these objects; and so we filter out all but the nicest of these aliases here.

TODO: This is a little bit vague, better heuristics could be used.

JRuby also has a lot of scala-specific logic, which we don't copy.
# File lib/pry/commands/ls.rb, line 116
def trim_jruby_aliases(methods)
  grouped = methods.group_by do |m|
    m.name.sub(/\A(is|get|set)(?=[A-Z_])/, '').gsub(/[_?=]/, '').downcase
  end

  grouped.map do |key, values|
    values = values.sort_by do |m|
      rubbishness(m.name)
    end

    found = []
    values.select do |x|
      (!found.any?{ |y| x == y }) && found << x
    end
  end.flatten(1)
end
write_out_constants() click to toggle source
# File lib/pry/commands/ls.rb, line 188
def write_out_constants
  return unless opts.present?(:constants) || (!has_user_specified_any_options && interrogating_a_module?)

  mod = interrogating_a_module? ? object_to_interrogate : Object
  constants = WrappedModule.new(mod).constants(opts.present?(:verbose))
  output_section("constants", grep[format_constants(mod, constants)])
end
write_out_globals() click to toggle source
# File lib/pry/commands/ls.rb, line 182
def write_out_globals
  return unless opts.present?(:globals)

  output_section("global variables", grep[format_globals(target.eval("global_variables"))])
end
write_out_ivars() click to toggle source
# File lib/pry/commands/ls.rb, line 218
def write_out_ivars
  return unless opts.present?(:ivars) || !has_user_specified_any_options

  klass = (interrogating_a_module? ? object_to_interrogate : object_to_interrogate.class)
  ivars = Pry::Method.safe_send(object_to_interrogate, :instance_variables)
  kvars = Pry::Method.safe_send(klass, :class_variables)
  output_section("instance variables", format_variables(:instance_var, ivars)) +
  output_section("class variables", format_variables(:class_var, kvars))
end
write_out_local_names() click to toggle source
# File lib/pry/commands/ls.rb, line 228
def write_out_local_names
  return unless !has_user_specified_any_options && args.empty?

  output_section("locals", format_local_names(grep[target.eval("local_variables")]))
end
write_out_locals() click to toggle source
# File lib/pry/commands/ls.rb, line 234
def write_out_locals
  return unless opts.present?(:locals)

  loc_names = target.eval('local_variables').reject do |e|
    _pry_.sticky_locals.keys.include? e.to_sym
  end
  name_value_pairs = loc_names.map do |name|
    [name, (target.eval name.to_s)]
  end
  format_locals(name_value_pairs).join("")
end
write_out_methods() click to toggle source
# File lib/pry/commands/ls.rb, line 196
def write_out_methods
  return unless opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) || !has_user_specified_any_options

  # methods is a hash {Module/Class => [Pry::Methods]}
  methods = all_methods(object_to_interrogate).group_by(&:owner)

  output = ""
  # reverse the resolution order so that the most useful information appears right by the prompt
  resolution_order(object_to_interrogate).take_while(&below_ceiling(object_to_interrogate)).reverse.each do |klass|
    methods_here = format_methods((methods[klass] || []).select{ |m| m.name =~ grep_regex })
    output << output_section("#{Pry::WrappedModule.new(klass).method_prefix}methods", methods_here)
  end
  output
end
write_out_self_methods() click to toggle source
# File lib/pry/commands/ls.rb, line 211
def write_out_self_methods
  return unless (!has_user_specified_any_options && interrogating_a_module?)

  methods = all_methods(object_to_interrogate, true).select{ |m| m.owner == object_to_interrogate && m.name =~ grep_regex }
  output_section("#{Pry::WrappedModule.new(object_to_interrogate).method_prefix}methods", format_methods(methods))
end