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:
parent
97f1be86b2
commit
2561179ba0
2 changed files with 151 additions and 34 deletions
|
@ -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
|
||||||
|
|
|
@ -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!
|
||||||
|
|
Loading…
Reference in a new issue