From ac683892d10bc88919e51604da5f80e9c706720b Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 19 Oct 2013 20:58:57 -0700 Subject: [PATCH] Add support for BasicObjects to `ls` [Fixes #984] --- lib/pry/commands/ls.rb | 25 ++++++++++++++----------- lib/pry/method.rb | 21 ++++++--------------- spec/commands/ls_spec.rb | 13 +++++++++++++ 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/lib/pry/commands/ls.rb b/lib/pry/commands/ls.rb index a828f9ac..1f4190b8 100644 --- a/lib/pry/commands/ls.rb +++ b/lib/pry/commands/ls.rb @@ -157,11 +157,7 @@ class Pry def below_ceiling(obj) ceiling = if opts.present?(:quiet) [ - if opts.present?(:'instance-methods') - Pry::Method.safe_send(obj, :ancestors)[1] - else - Pry::Method.safe_send(obj.class, :ancestors)[1] - end + Pry::Method.safe_send(module_to_interrogate, :ancestors)[1] ] + Pry.config.ls.ceiling elsif opts.present?(:verbose) [] @@ -178,6 +174,7 @@ class Pry ["-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 @@ -187,6 +184,10 @@ class Pry (Module === object_to_interrogate) end + def module_to_interrogate + interrogating_a_module? ? object_to_interrogate : (class << object_to_interrogate; self.ancestors.first; end) + end + def write_out_globals return unless opts.present?(:globals) @@ -196,9 +197,8 @@ class Pry 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_to_interrogate.class - constants = WrappedModule.new(mod).constants(opts.present?(:verbose)) - output_section("constants", grep[format_constants(mod, constants)]) + constants = WrappedModule.new(module_to_interrogate).constants(opts.present?(:verbose)) + output_section("constants", grep[format_constants(module_to_interrogate, constants)]) end def write_out_methods @@ -226,9 +226,12 @@ class Pry 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) + if Object === object_to_interrogate + ivars = Pry::Method.safe_send(object_to_interrogate, :instance_variables) + else + ivars = [] #TODO: BasicObject support + end + kvars = Pry::Method.safe_send(module_to_interrogate, :class_variables) output_section("instance variables", format_variables(:instance_var, ivars)) + output_section("class variables", format_variables(:class_var, kvars)) end diff --git a/lib/pry/method.rb b/lib/pry/method.rb index a96fe9ed..261f24b3 100644 --- a/lib/pry/method.rb +++ b/lib/pry/method.rb @@ -139,7 +139,11 @@ class Pry # @param [Boolean] include_super Whether to include methods from ancestors. # @return [Array[Pry::Method]] def all_from_class(klass, include_super=true) - all_from_common(klass, :instance_method, include_super) + %w(public protected private).map do |visibility| + safe_send(klass, :"#{visibility}_instance_methods", include_super).map do |method_name| + new(safe_send(klass, :instance_method, method_name), :visibility => visibility.to_sym) + end + end.flatten(1) end # Get all of the methods on an `Object` @@ -147,7 +151,7 @@ class Pry # @param [Boolean] include_super Whether to include methods from ancestors. # @return [Array[Pry::Method]] def all_from_obj(obj, include_super=true) - all_from_common(obj, :method, include_super) + all_from_class(class << obj; self; end, include_super) end # Get every `Class` and `Module`, in order, that will be checked when looking @@ -188,19 +192,6 @@ class Pry private - # See all_from_class and all_from_obj. - # If method_type is :instance_method, obj must be a `Class` or a `Module` - # If method_type is :method, obj can be any `Object` - # - # N.B. we pre-cache the visibility here to avoid O(N²) behaviour in "ls". - def all_from_common(obj, method_type, include_super=true) - %w(public protected private).map do |visibility| - safe_send(obj, :"#{visibility}_#{method_type}s", include_super).map do |method_name| - new(safe_send(obj, method_type, method_name), :visibility => visibility.to_sym) - end - end.flatten(1) - end - # Get the singleton classes of superclasses that could define methods on # the given class object, and any modules they include. # If a module is included at multiple points in the ancestry, only diff --git a/spec/commands/ls_spec.rb b/spec/commands/ls_spec.rb index 474549ad..c1f6126f 100644 --- a/spec/commands/ls_spec.rb +++ b/spec/commands/ls_spec.rb @@ -34,6 +34,19 @@ describe "ls" do end end + describe "BasicObject" do + it "should work on BasicObject" do + pry_eval("ls BasicObject.new").should =~ /BasicObject#methods:.*__id__.*__send__/ + end + + it "should work on subclasses of BasicObject" do + pry_eval( + "class LessBasic < BasicObject; def jaroussky; 5; end; end", + "ls LessBasic.new" + ).should =~ /LessBasic#methods:.*jaroussky/ + end + end + describe "methods" do it "should show public methods by default" do output = pry_eval("ls Class.new{ def goo; end; public :goo }.new")