1
0
Fork 0
mirror of https://github.com/pry/pry.git synced 2022-11-09 12:35:05 -05:00

Add -m, -c, -f options to whereami command.

-m, the current method in its totality
-c, the current class/module that is the current 'candidate' (monkeypatch)
-f, the entire file
This commit is contained in:
John Mair 2013-02-02 18:02:05 +01:00
parent 97f1be86b2
commit 2561179ba0
2 changed files with 151 additions and 34 deletions

View file

@ -1,16 +1,23 @@
class Pry class Pry
class Command::Whereami < Pry::ClassCommand class Command::Whereami < Pry::ClassCommand
class << self
attr_accessor :method_size_cutoff
end
@method_size_cutoff = 30
match 'whereami' match 'whereami'
description 'Show code surrounding the current context.' description 'Show code surrounding the current context.'
group 'Context' group 'Context'
banner <<-'BANNER' banner <<-'BANNER'
Usage: whereami [-qn] [N] Usage: whereami [-qn] [LINES]
Describe the current location. If you use `binding.pry` inside a method then Describe the current location. If you use `binding.pry` inside a method then
whereami will print out the source for that method. whereami will print out the source for that method.
If a number is passed, then N lines before and after the current line will be If a number is passed, then LINES lines before and after the current line will be
shown instead of the method itself. shown instead of the method itself.
The `-q` flag can be used to suppress error messages in the case that there's The `-q` flag can be used to suppress error messages in the case that there's
@ -25,29 +32,53 @@ class Pry
BANNER BANNER
def setup def setup
@method = Pry::Method.from_binding(target) @file = expand_path(target.eval('__FILE__'))
@file = target.eval('__FILE__')
@line = target.eval('__LINE__') @line = target.eval('__LINE__')
@method = Pry::Method.from_binding(target)
end end
def options(opt) def options(opt)
opt.on :q, :quiet, "Don't display anything in case of an error" opt.on :q, :quiet, "Don't display anything in case of an error"
opt.on :n, :"no-line-numbers", "Do not display line numbers" opt.on :n, :"no-line-numbers", "Do not display line numbers"
opt.on :m, :"method", "Show the complete source for the current method."
opt.on :c, :"class", "Show the complete source for the current class or module."
opt.on :f, :"file", "Show the complete source for the current file."
end end
def code def code
@code ||= if show_method? @code ||= if opts.present?(:m)
Pry::Code.from_method(@method) method_code or raise CommandError, "Cannot find method code."
elsif opts.present?(:c)
class_code or raise CommandError, "Cannot find class code."
elsif opts.present?(:f)
Pry::Code.from_file(@file)
elsif args.any?
code_window
else else
Pry::Code.from_file(@file).around(@line, window_size) default_code
end end
end end
def code?
!!code
rescue MethodSource::SourceNotFoundError
false
end
def bad_option_combination?
[opts.present?(:m), opts.present?(:f),
opts.present?(:c), args.any?].count(true) > 1
end
def location def location
"#{@file} @ line #{@line} #{@method && @method.name_with_owner}" "#{@file} @ line #{@line} #{@method && @method.name_with_owner}"
end end
def process def process
if bad_option_combination?
raise CommandError, "Only one of -m, -c, -f, and LINES may be specified."
end
if nothing_to_do? if nothing_to_do?
return return
elsif internal_binding?(target) elsif internal_binding?(target)
@ -57,9 +88,10 @@ class Pry
set_file_and_dir_locals(@file) set_file_and_dir_locals(@file)
output.puts "\n#{text.bold('From:')} #{location}:\n\n" out = "\n#{text.bold('From:')} #{location}:\n\n" +
output.puts code.with_line_numbers(use_line_numbers?).with_marker(marker) code.with_line_numbers(use_line_numbers?).with_marker(marker) + "\n"
output.puts
stagger_output(out)
end end
private private
@ -88,17 +120,53 @@ class Pry
end end
end end
def show_method? def small_method?
args.empty? && @method && @method.source? && @method.source_range.count < 20 && @method.source_range.count < self.class.method_size_cutoff
# These checks are needed in case of an eval with a binding and file/line
# numbers set to outside the function. As in rails' use of ERB.
@method.source_file == @file && @method.source_range.include?(@line)
end end
def code? def default_code
!!code if method_code && small_method?
rescue MethodSource::SourceNotFoundError method_code
false else
code_window
end
end
def code_window
Pry::Code.from_file(@file).around(@line, window_size)
end
def method_code
return @method_code if @method_code
if valid_method?
@method_code = Pry::Code.from_method(@method)
end
end
def class_code
return @class_code if @class_code
if valid_method?
mod = Pry::WrappedModule(@method.owner)
idx = mod.candidates.find_index { |v| expand_path(v.source_file) == @file }
@class_code = idx && Pry::Code.from_module(mod, idx)
end
end
def valid_method?
@method && @method.source? && expand_path(@method.source_file) == @file &&
@method.source_range.include?(@line)
end
def expand_path(f)
return if !f
if Pry.eval_path == f
f
else
File.expand_path(f)
end
end end
def window_size def window_size

View file

@ -63,7 +63,6 @@ describe "whereami" do
end end
Cor.instance_method(:blimey!).source.should =~ /pry_eval/ Cor.instance_method(:blimey!).source.should =~ /pry_eval/
Cor.new.blimey!.should =~ /Cor#blimey!.*Look at me/m Cor.new.blimey!.should =~ /Cor#blimey!.*Look at me/m
Object.remove_const(:Cor) Object.remove_const(:Cor)
end end
@ -85,21 +84,29 @@ describe "whereami" do
Object.remove_const(:Cor) Object.remove_const(:Cor)
end end
it 'should display a description and and error if reading the file goes wrong' do # Now that we use stagger_output (paging output) we no longer get
class Cor # the "From: " line, as we output everything in one go (not separate output.puts)
def blimey! # and so the user just gets a single `Error: Cannot open
eval <<-END, binding, "not.found.file.erb", 7 # "not.found.file.erb" for reading.`
Pad.tester = pry_tester(binding) # which is good enough IMO. Unfortunately we can't test for it
Pad.tester.eval('whereami') # though, as we don't hook stdout.
END #
end # it 'should display a description and error if reading the file goes wrong' do
end # class Cor
# def blimey!
# eval <<-END, binding, "not.found.file.erb", 7
# Pad.tester = pry_tester(binding)
# Pad.tester.eval('whereami')
# END
# end
# end
proc { Cor.new.blimey! }.should.raise(MethodSource::SourceNotFoundError) # proc { Cor.new.blimey! }.should.raise(MethodSource::SourceNotFoundError)
Pad.tester.last_output.should =~
/From: not.found.file.erb @ line 7 Cor#blimey!:/ # Pad.tester.last_output.should =~
Object.remove_const(:Cor) # /From: not.found.file.erb @ line 7 Cor#blimey!:/
end # Object.remove_const(:Cor)
# end
it 'should show code window (not just method source) if parameter passed to whereami' do it 'should show code window (not just method source) if parameter passed to whereami' do
class Cor class Cor
@ -111,6 +118,48 @@ describe "whereami" do
Object.remove_const(:Cor) Object.remove_const(:Cor)
end end
it 'should show entire method when -m option used' do
old_size, Pry.config.default_window_size = Pry.config.default_window_size, 1
old_cutoff, Pry::Command::Whereami.method_size_cutoff = Pry::Command::Whereami.method_size_cutoff, 1
class Cor
def blimey!
1
2
pry_eval(binding, 'whereami -m').should =~ /def blimey/
end
end
Pry::Command::Whereami.method_size_cutoff, Pry.config.default_window_size = old_cutoff, old_size
Cor.new.blimey!
Object.remove_const(:Cor)
end
it 'should show entire file when -f option used' do
class Cor
def blimey!
1
2
pry_eval(binding, 'whereami -f').should =~ /show entire file when -f option used/
end
end
Cor.new.blimey!
Object.remove_const(:Cor)
end
it 'should show class when -c option used, and locate correct candidate' do
require 'fixtures/whereami_helper'
class Cor
def blimey!
1
2
out = pry_eval(binding, 'whereami -c')
out.should =~ /class Cor/
out.should =~ /blimey/
end
end
Cor.new.blimey!
Object.remove_const(:Cor)
end
it 'should not show line numbers or marker when -n switch is used' do it 'should not show line numbers or marker when -n switch is used' do
class Cor class Cor
def blimey! def blimey!