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

Merge branch 'master' into wip-config

Conflicts:
	Gemfile
This commit is contained in:
Robert Gleeson 2014-01-26 21:33:35 +01:00
commit 283b85c9a1
8 changed files with 262 additions and 14 deletions

View file

@ -40,6 +40,7 @@
being inferred from context (#877)
* Rename `--installed-plugins` flag to `--plugins`
* Strip ANSI codes from prompt before measuring length for indentation (#493)
* Fix bug in `edit` regarding recognition of file names without suffix.
#### Dev-facing changes
* `rake pry` now accepts switches prefixed with `_` (e.g., `rake pry _v`)

View file

@ -8,9 +8,7 @@ group :development do
gem 'rb-fsevent', :require => 'false'
end
gem 'binding.repl'
if RbConfig::CONFIG['ruby_install_name'] == 'rbx'
platform :rbx do
gem 'rubysl-singleton'
gem 'rubysl-prettyprint'
gem 'rb-readline'

View file

@ -186,7 +186,7 @@ class Pry
end
def probably_a_file?(str)
[".rb", ".c", ".py", ".yml", ".gemspec"].include? File.extname(str) ||
[".rb", ".c", ".py", ".yml", ".gemspec"].include?(File.extname(str)) ||
str =~ /\/|\\/
end

View file

@ -29,34 +29,32 @@ class Pry
private
def greppable
proc do |entity|
entity.tap { |o| o.grep = @grep }
end
def grep(entity)
entity.tap { |o| o.grep = @grep }
end
def globals
greppable.call(Globals.new(@target, @opts))
grep(Globals.new(@target, @opts))
end
def constants
greppable.call(Constants.new(@interrogatee, @target, @no_user_opts, @opts))
grep(Constants.new(@interrogatee, @target, @no_user_opts, @opts))
end
def methods
greppable.call(Methods.new(@interrogatee, @no_user_opts, @opts))
grep(Methods.new(@interrogatee, @no_user_opts, @opts))
end
def self_methods
greppable.call(SelfMethods.new(@interrogatee, @no_user_opts, @opts))
grep(SelfMethods.new(@interrogatee, @no_user_opts, @opts))
end
def instance_vars
greppable.call(InstanceVars.new(@interrogatee, @no_user_opts, @opts))
grep(InstanceVars.new(@interrogatee, @no_user_opts, @opts))
end
def local_names
greppable.call(LocalNames.new(@target, @no_user_opts, @sticky_locals, @args))
grep(LocalNames.new(@target, @no_user_opts, @sticky_locals, @args))
end
def local_vars

View file

@ -0,0 +1,94 @@
class Pry
class Command::WatchExpression < Pry::ClassCommand
require 'pry/commands/watch_expression/expression.rb'
match 'watch'
group 'Context'
description 'Evaluate an expression after every command and display it when its value changes.'
command_options :use_prefix => false
banner <<-'BANNER'
Usage: watch [EXPRESSION]
watch
watch --delete [INDEX]
Evaluate an expression after every command and display it when its value changes.
BANNER
def options(opt)
opt.on :d, :delete,
"Delete the watch expression with the given index. If no index is given; clear all watch expressions.",
:optional_argument => true, :as => Integer
opt.on :l, :list,
"Show all current watch expressions and their values. Calling watch with no expressions or options will also show the watch expressions."
end
def process
case
when opts.present?(:delete)
delete opts[:delete]
when opts.present?(:list) || args.empty?
list
else
add_hook
add_expression(args)
end
end
private
def expressions
Pry.config.watch_expressions ||= []
end
def delete(index)
if index
output.puts "Deleting watch expression ##{index}: #{expressions[index-1]}"
expressions.delete_at(index-1)
else
output.puts "Deleting all watched expressions"
expressions.clear
end
end
def list
if expressions.empty?
output.puts "No watched expressions"
else
Pry::Pager.with_pager(output) do |pager|
pager.puts "Listing all watched expressions:"
pager.puts ""
expressions.each_with_index do |expr, index|
pager.print text.with_line_numbers(expr.to_s, index+1)
end
pager.puts ""
end
end
end
def eval_and_print_changed(output)
expressions.each do |expr|
expr.eval!
if expr.changed?
output.puts "#{text.blue "watch"}: #{expr.to_s}"
end
end
end
def add_expression(arguments)
expressions << Expression.new(target, arg_string)
output.puts "Watching #{Code.new(arg_string)}"
end
def add_hook
hook = [:after_eval, :watch_expression]
unless Pry.hooks.hook_exists?(*hook)
Pry.hooks.add_hook(*hook) do |_, _pry_|
eval_and_print_changed _pry_.output
end
end
end
end
Pry::Commands.add_command(Pry::Command::WatchExpression)
end

View file

@ -0,0 +1,41 @@
class Pry
class Command::WatchExpression
class Expression
attr_reader :target, :source, :value, :previous_value
def initialize(target, source)
@target = target
@source = source
end
def eval!
@previous_value = value
@value = target_eval(target, source)
end
def to_s
"#{print_source} => #{print_value}"
end
def changed?
(value != previous_value)
end
def print_value
Pry::ColorPrinter.pp(value, "")
end
def print_source
Code.new(source).strip
end
private
def target_eval(target, source)
target.eval(source)
rescue => e
e
end
end
end
end

View file

@ -35,6 +35,16 @@ describe "edit" do
FileUtils.rm(@tf_path) if File.exists?(@tf_path)
end
it "should not allow patching any known kind of file" do
["file.rb", "file.c", "file.py", "file.yml", "file.gemspec",
"/tmp/file", "\\\\Temp\\\\file"].each do |file|
proc {
pry_eval "edit -p #{file}"
}.should.raise(NotImplementedError).
message.should =~ /Cannot yet patch false objects!/
end
end
it "should invoke Pry.config.editor with absolutified filenames" do
pry_eval 'edit lib/pry.rb'
@file.should == File.expand_path('lib/pry.rb')

View file

@ -0,0 +1,106 @@
require 'helper'
describe "watch expression" do
# Custom eval that will:
# 1) Create an instance of pry that can use for multiple calls
# 2) Exercise the after_eval hook
# 3) Return the output
def eval(expr)
output = @tester.eval expr
@tester.pry.hooks.exec_hook :after_eval, nil, @tester.pry
output
end
before do
@tester = pry_tester
@tester.pry.hooks.clear :after_eval
eval "watch --delete"
end
it "registers the after_eval hook" do
eval 'watch 1+1'
@tester.pry.hooks.hook_exists?(:after_eval, :watch_expression).should == true
end
it "prints no watched expressions" do
eval('watch').should =~ /No watched expressions/
end
it "watches an expression" do
eval "watch 1+1"
eval('watch').should =~ /=> 2/
end
it "watches a local variable" do
eval 'foo = :bar'
eval 'watch foo'
eval('watch').should =~ /=> :bar/
end
it "prints when an expression changes" do
ReplTester.start do
input 'a = 1'
output '=> 1'
input 'watch a'
output "Watching a\nwatch: a => 1"
input "a = 2"
output "watch: a => 2\n=> 2"
end
end
it "doesn't print when an expresison remains the same" do
ReplTester.start do
input 'a = 1'
output '=> 1'
input 'watch a'
output "Watching a\nwatch: a => 1"
input "a = 1"
output "=> 1"
end
end
it "continues to work if you start a second pry instance" do
ReplTester.start do
input 'a = 1'
output '=> 1'
input 'watch a'
output "Watching a\nwatch: a => 1"
input "a = 2"
output "watch: a => 2\n=> 2"
end
ReplTester.start do
input 'b = 1'
output '=> 1'
input 'watch b'
output "Watching b\nwatch: b => 1"
input "b = 2"
output "watch: b => 2\n=> 2"
end
end
describe "deleting expressions" do
before do
eval 'watch :keeper'
eval 'watch :delete'
eval 'watch -d 2'
end
it "keeps keeper" do
eval('watch').should =~ /keeper/
end
it "deletes delete" do
eval('watch').should.not =~ /delete/
end
end
end