mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
Merge remote-tracking branch 'upstream/dev'
* upstream/dev: (185 commits) removed unnecessary pry_command? method from command_processor.rb. And removed #clear singleton method on val and eval_string, converted to #replace removed deprecated has_rdoc= call tiny refactor to repl_prologue in pry_instance.rb Simplify Pry::CommandSet#each. experimental command 'play' added CommandSet#list_commands, convenience method for repl exploration of command sets CommandSet is Enumerable. added tests for help and show-command commands, and by proxy testing :listing functionality and regex commands fixed spelling mistakes in comments removed all instances of old opts[:arg_string] changed formatting for uninstalled command message (added bold) changed 'rake pry' to invoke executable instead of starting pry session in Rakefile Revert "Made Pry able to cd into procs" added tests for updated CommandContext#run method Made Pry able to cd into procs Pry.config.history.file now has File.expand_path() applied before being saved reordered plugin/history loading so that plugins are loaded before history removed some unnecessary helper methods added reload-method experimental command, removed rue- experimental command, in experimental.rb added hist --show option + tests ... Conflicts: Rakefile lib/pry/commands.rb
This commit is contained in:
commit
438fe17fcb
41 changed files with 3680 additions and 2511 deletions
|
@ -441,11 +441,11 @@ help that can be accessed via typing `command_name --help`. A command
|
|||
will typically say in its description if the `--help` option is
|
||||
avaiable.
|
||||
|
||||
### Use Pry as your Rails 3 Console
|
||||
### Use Pry as your Rails Console
|
||||
|
||||
This is currently a hack, but follow the gist kindly provided by
|
||||
MyArtChannel: [https://gist.github.com/941174](https://gist.github.com/941174)
|
||||
pry -r./config/environment
|
||||
|
||||
MyArtChannel has kindly provided a hack to replace the `rails console` command in Rails 3: [https://gist.github.com/941174](https://gist.github.com/941174) This is not recommended for code bases with multiple developers, as they may not all want to use Pry.
|
||||
|
||||
### Other Features and limitations
|
||||
|
||||
|
@ -486,13 +486,13 @@ invoke any of these methods directly depending on exactly what aspect of the fun
|
|||
|
||||
#### Limitations:
|
||||
|
||||
* Some Pry commands (e.g `show-command`) do not work in Ruby 1.8.
|
||||
* Some Pry commands (e.g `show-command`) do not work in Ruby 1.8
|
||||
MRI. But many other commands do work in Ruby 1.8 MRI, e.g
|
||||
`show-method`, due to a functional 1.8 source_location implementation.
|
||||
* JRuby not officially supported due to currently too many quirks and
|
||||
strange behaviour. Nonetheless most functionality should still work
|
||||
OK in JRuby. Full JRuby support coming in a future version.
|
||||
* `method_source` functionality does not work in JRuby with Ruby 1.8
|
||||
* Color support does not work in JRuby with Ruby 1.9 (due to a
|
||||
limitation in JRuby's regex).
|
||||
* Tab completion is currently a bit broken/limited this will have a
|
||||
major overhaul in a future version.
|
||||
|
||||
|
|
18
Rakefile
18
Rakefile
|
@ -5,36 +5,35 @@ $:.unshift 'lib'
|
|||
require 'pry/version'
|
||||
|
||||
CLOBBER.include("**/*~", "**/*#*", "**/*.log")
|
||||
CLEAN.include("**/*#*", "**/*#*.*", "**/*_flymake*.*", "**/*_flymake", "**/*.rbc")
|
||||
CLEAN.include("**/*#*", "**/*#*.*", "**/*_flymake*.*", "**/*_flymake",
|
||||
"**/*.rbc", "**/.#*.*")
|
||||
|
||||
def apply_spec_defaults(s)
|
||||
s.name = "pry"
|
||||
s.summary = "attach an irb-like session to any object at runtime"
|
||||
s.summary = "an IRB alternative and runtime developer console"
|
||||
s.version = Pry::VERSION
|
||||
s.date = Time.now.strftime '%Y-%m-%d'
|
||||
s.author = "John Mair (banisterfiend)"
|
||||
s.email = 'jrmair@gmail.com'
|
||||
s.description = s.summary
|
||||
s.homepage = "http://banisterfiend.wordpress.com"
|
||||
s.has_rdoc = 'yard'
|
||||
s.executables = ["pry"]
|
||||
s.files = `git ls-files`.split("\n")
|
||||
s.test_files = `git ls-files -- test/*`.split("\n")
|
||||
s.add_dependency("ruby_parser",">=2.0.5")
|
||||
s.add_dependency("coderay",">=0.9.8")
|
||||
s.add_dependency("slop",">=1.5.5")
|
||||
s.add_dependency("slop","~>1.6.0")
|
||||
s.add_dependency("method_source",">=0.4.0")
|
||||
s.add_development_dependency("bacon",">=1.1.0")
|
||||
end
|
||||
|
||||
task :test do
|
||||
sh "bacon -Itest -rubygems test/test.rb"
|
||||
sh "bacon -Itest -rubygems -a"
|
||||
end
|
||||
|
||||
desc "run pry"
|
||||
task :pry do
|
||||
require 'pry'
|
||||
binding.pry
|
||||
load 'bin/pry'
|
||||
end
|
||||
|
||||
desc "show pry version"
|
||||
|
@ -57,7 +56,7 @@ namespace :ruby do
|
|||
task :gemspec do
|
||||
File.open("#{spec.name}-#{spec.version}.gemspec", "w") do |f|
|
||||
f << spec.to_ruby
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -88,7 +87,6 @@ namespace :jruby do
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
desc "build all platform gems at once"
|
||||
task :gems => [:clean, :rmgems, "ruby:gem", "jruby:gem", "mswin32:gem", "mingw32:gem"]
|
||||
|
||||
|
@ -97,7 +95,7 @@ task :rmgems => ["ruby:clobber_package"]
|
|||
|
||||
desc "build and push latest gems"
|
||||
task :pushgems => :gems do
|
||||
chdir("#{direc}/pkg") do
|
||||
chdir("#{File.dirname(__FILE__)}/pkg") do
|
||||
Dir["*.gem"].each do |gemfile|
|
||||
sh "gem push #{gemfile}"
|
||||
end
|
||||
|
|
30
TODO
30
TODO
|
@ -1,13 +1,39 @@
|
|||
|
||||
ROADMAP
|
||||
|
||||
FUTURE
|
||||
* allows pipes (|) for commands
|
||||
--------
|
||||
* Pry server and Pry client for SLIME style remote repl connectinos.
|
||||
* i18n support
|
||||
|
||||
0.9.0
|
||||
Major features
|
||||
--------------
|
||||
* Restructure command system and helpers (almost complete)
|
||||
* Delete unnecessary commands, add a couple of new ones (e.g amend-line)
|
||||
* Readline history
|
||||
* Plugin support
|
||||
* Support Rubinius core methods
|
||||
* in[] and out[] arrays
|
||||
* Improve test coverage (test some commands, etc)
|
||||
|
||||
Minor changes
|
||||
-------------
|
||||
* improve edit-method support for various editors
|
||||
* ensure all commands have appropriate error handing and informative error messages
|
||||
* show-doc should include signature of method
|
||||
|
||||
Optional
|
||||
--------
|
||||
* multi-line readline support
|
||||
|
||||
|
||||
0.8.0
|
||||
* allow #{} interpolation of all commands
|
||||
* update documentation! new commands and features and change in behaviour of `run`
|
||||
* add ; at end of line to suppress return value output
|
||||
* Remove message spam (before/after hooks)
|
||||
* stop commands returning a value
|
||||
* stop commands returning a value
|
||||
* use `redo` in the r() method when encounter a command
|
||||
* shell functionality should just use system(), but redirect in and
|
||||
out to Pry.input and Pry.output by reassining $stdin and $stdout
|
||||
|
|
11
bin/pry
11
bin/pry
|
@ -3,6 +3,8 @@
|
|||
# (C) John Mair (banisterfiend)
|
||||
# MIT license
|
||||
|
||||
$0 = 'pry'
|
||||
|
||||
begin
|
||||
require 'pry'
|
||||
rescue LoadError
|
||||
|
@ -48,15 +50,8 @@ end
|
|||
# invoked via cli
|
||||
Pry.cli = true
|
||||
|
||||
Pry::Commands.instance_eval do
|
||||
command "reset", "Reset the REPL to a clean state." do
|
||||
output.puts "Pry reset."
|
||||
exec("pry")
|
||||
end
|
||||
end
|
||||
|
||||
# load ~/.pryrc, if not suppressed with -f option
|
||||
Pry.should_load_rc = !opts.f?
|
||||
Pry.config.should_load_rc = !opts.f?
|
||||
|
||||
# create the actual context
|
||||
context = Pry.binding_for(eval(opts[:context]))
|
||||
|
|
70
lib/pry.rb
70
lib/pry.rb
|
@ -1,6 +1,65 @@
|
|||
# (C) John Mair (banisterfiend) 2011
|
||||
# MIT License
|
||||
|
||||
class Pry
|
||||
# The default hooks - display messages when beginning and ending Pry sessions.
|
||||
DEFAULT_HOOKS = {
|
||||
:before_session => proc do |out, target|
|
||||
# ensure we're actually in a method
|
||||
meth_name = target.eval('__method__')
|
||||
file = target.eval('__FILE__')
|
||||
|
||||
# /unknown/ for rbx
|
||||
if file !~ /(\(.*\))|<.*>/ && file !~ /__unknown__/ && file != "" && file != "-e"
|
||||
Pry.run_command "whereami 5", :output => out, :show_output => true, :context => target, :commands => Pry::Commands
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
# The default prints
|
||||
DEFAULT_PRINT = proc do |output, value|
|
||||
if Pry.color
|
||||
output.puts "=> #{CodeRay.scan(Pry.view(value), :ruby).term}"
|
||||
else
|
||||
output.puts "=> #{Pry.view(value)}"
|
||||
end
|
||||
end
|
||||
|
||||
# Will only show the first line of the backtrace
|
||||
DEFAULT_EXCEPTION_HANDLER = proc do |output, exception|
|
||||
output.puts "#{exception.class}: #{exception.message}"
|
||||
output.puts "from #{exception.backtrace.first}"
|
||||
end
|
||||
|
||||
# The default prompt; includes the target and nesting level
|
||||
DEFAULT_PROMPT = [
|
||||
proc { |target_self, nest_level|
|
||||
if nest_level == 0
|
||||
"pry(#{Pry.view_clip(target_self)})> "
|
||||
else
|
||||
"pry(#{Pry.view_clip(target_self)}):#{Pry.view_clip(nest_level)}> "
|
||||
end
|
||||
},
|
||||
|
||||
proc { |target_self, nest_level|
|
||||
if nest_level == 0
|
||||
"pry(#{Pry.view_clip(target_self)})* "
|
||||
else
|
||||
"pry(#{Pry.view_clip(target_self)}):#{Pry.view_clip(nest_level)}* "
|
||||
end
|
||||
}
|
||||
]
|
||||
|
||||
# A simple prompt - doesn't display target or nesting level
|
||||
SIMPLE_PROMPT = [proc { ">> " }, proc { ">* " }]
|
||||
|
||||
SHELL_PROMPT = [
|
||||
proc { |target_self, _| "pry #{Pry.view_clip(target_self)}:#{Dir.pwd} $ " },
|
||||
proc { |target_self, _| "pry #{Pry.view_clip(target_self)}:#{Dir.pwd} * " }
|
||||
]
|
||||
|
||||
end
|
||||
|
||||
require "method_source"
|
||||
require 'shellwords'
|
||||
require "readline"
|
||||
|
@ -20,20 +79,13 @@ if RUBY_PLATFORM =~ /mswin/ || RUBY_PLATFORM =~ /mingw/
|
|||
end
|
||||
|
||||
require "pry/version"
|
||||
require "pry/hooks"
|
||||
require "pry/print"
|
||||
require "pry/helpers"
|
||||
require "pry/command_set"
|
||||
require "pry/commands"
|
||||
require "pry/command_context"
|
||||
require "pry/prompts"
|
||||
require "pry/custom_completions"
|
||||
require "pry/completion"
|
||||
require "pry/plugins"
|
||||
require "pry/core_extensions"
|
||||
require "pry/pry_class"
|
||||
require "pry/pry_instance"
|
||||
|
||||
# TEMPORARY HACK FOR BUG IN JRUBY 1.9 REGEX (which kills CodeRay)
|
||||
if RUBY_VERSION =~ /1.9/ && RUBY_ENGINE =~ /jruby/
|
||||
Pry.color = false
|
||||
end
|
||||
require "pry/pry_instance"
|
|
@ -4,25 +4,26 @@ class Pry
|
|||
class CommandContext
|
||||
attr_accessor :output
|
||||
attr_accessor :target
|
||||
attr_accessor :captures
|
||||
attr_accessor :eval_string
|
||||
attr_accessor :arg_string
|
||||
attr_accessor :opts
|
||||
attr_accessor :command_set
|
||||
attr_accessor :command_processor
|
||||
|
||||
def run(name, *args)
|
||||
if name.start_with? "."
|
||||
cmd = name[1..-1]
|
||||
command_processor.
|
||||
execute_system_command([name, Shellwords.join(args)].join(' '),
|
||||
target)
|
||||
else
|
||||
command_set.run_command(self, name, *args)
|
||||
end
|
||||
def run(command_string, *args)
|
||||
complete_string = "#{command_string} #{args.join(" ")}"
|
||||
command_processor.process_commands(complete_string, eval_string, target)
|
||||
end
|
||||
|
||||
def commands
|
||||
command_set.commands
|
||||
end
|
||||
|
||||
def text
|
||||
Pry::Helpers::Text
|
||||
end
|
||||
|
||||
include Pry::Helpers::BaseHelpers
|
||||
include Pry::Helpers::CommandHelpers
|
||||
end
|
||||
|
|
|
@ -2,9 +2,6 @@ require 'forwardable'
|
|||
|
||||
class Pry
|
||||
class CommandProcessor
|
||||
SYSTEM_COMMAND_DELIMITER = "."
|
||||
SYSTEM_COMMAND_REGEX = /^#{Regexp.escape(SYSTEM_COMMAND_DELIMITER)}(.*)/
|
||||
|
||||
extend Forwardable
|
||||
|
||||
attr_accessor :pry_instance
|
||||
|
@ -19,22 +16,16 @@ class Pry
|
|||
# @param [String] val The string passed in from the Pry prompt.
|
||||
# @return [Boolean] Whether the string is a valid command.
|
||||
def valid_command?(val)
|
||||
system_command?(val) || pry_command?(val)
|
||||
!!(command_matched(val)[0])
|
||||
end
|
||||
|
||||
# Is the string a valid system command?
|
||||
# @param [String] val The string passed in from the Pry prompt.
|
||||
# @return [Boolean] Whether the string is a valid system command.
|
||||
def system_command?(val)
|
||||
!!(SYSTEM_COMMAND_REGEX =~ val)
|
||||
end
|
||||
|
||||
# Is the string a valid pry command?
|
||||
# A Pry command is a command that is not a system command.
|
||||
# @param [String] val The string passed in from the Pry prompt.
|
||||
# @return [Boolean] Whether the string is a valid Pry command.
|
||||
def pry_command?(val)
|
||||
!!command_matched(val).first
|
||||
def convert_to_regex(obj)
|
||||
case obj
|
||||
when String
|
||||
Regexp.escape(obj)
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
|
||||
# Revaluate the string (str) and perform interpolation.
|
||||
|
@ -49,41 +40,6 @@ class Pry
|
|||
target.eval(dumped_str)
|
||||
end
|
||||
|
||||
# Execute a given system command.
|
||||
# The commands first have interpolation applied against the
|
||||
# `target` context.
|
||||
# All system command are forwarded to a shell. Note that the `cd`
|
||||
# command is special-cased and is converted internallly to a `Dir.chdir`
|
||||
# @param [String] val The system command to execute.
|
||||
# @param [Binding] target The context in which to perform string interpolation.
|
||||
def execute_system_command(val, target)
|
||||
SYSTEM_COMMAND_REGEX =~ val
|
||||
cmd = interpolate_string($1, target)
|
||||
|
||||
if cmd =~ /^cd\s+(.+)/i
|
||||
begin
|
||||
@@cd_history ||= []
|
||||
if $1 == "-"
|
||||
dest = @@cd_history.pop || Dir.pwd
|
||||
else
|
||||
dest = File.expand_path($1)
|
||||
end
|
||||
|
||||
@@cd_history << Dir.pwd
|
||||
Dir.chdir(dest)
|
||||
rescue Errno::ENOENT
|
||||
output.puts "No such directory: #{dest}"
|
||||
end
|
||||
else
|
||||
if !system(cmd)
|
||||
output.puts "Error: there was a problem executing system command: #{cmd}"
|
||||
end
|
||||
end
|
||||
|
||||
# Tick, tock, im getting rid of this shit soon.
|
||||
val.replace("")
|
||||
end
|
||||
|
||||
# Determine whether a Pry command was matched and return command data
|
||||
# and argument string.
|
||||
# This method should not need to be invoked directly.
|
||||
|
@ -91,10 +47,10 @@ class Pry
|
|||
# @return [Array] The command data and arg string pair
|
||||
def command_matched(val)
|
||||
_, cmd_data = commands.commands.find do |name, cmd_data|
|
||||
/^#{Regexp.escape(name)}(?!\S)(?:\s+(.+))?/ =~ val
|
||||
/^#{convert_to_regex(name)}(?!\S)/ =~ val
|
||||
end
|
||||
|
||||
[cmd_data, $1]
|
||||
[cmd_data, (Regexp.last_match ? Regexp.last_match.captures : nil), (Regexp.last_match ? Regexp.last_match.end(0) : nil)]
|
||||
end
|
||||
|
||||
# Process Pry commands. Pry commands are not Ruby methods and are evaluated
|
||||
|
@ -107,30 +63,25 @@ class Pry
|
|||
# multi-line input.
|
||||
# @param [Binding] target The receiver of the commands.
|
||||
def process_commands(val, eval_string, target)
|
||||
def val.clear() replace("") end
|
||||
def eval_string.clear() replace("") end
|
||||
|
||||
if system_command?(val)
|
||||
execute_system_command(val, target)
|
||||
return
|
||||
end
|
||||
command, captures, pos = command_matched(val)
|
||||
|
||||
# no command was matched, so return to caller
|
||||
return if !pry_command?(val)
|
||||
return if !command
|
||||
|
||||
val.replace interpolate_string(val, target)
|
||||
command, args_string = command_matched(val)
|
||||
|
||||
args = args_string ? Shellwords.shellwords(args_string) : []
|
||||
val.replace interpolate_string(val, target) if command.options[:interpolate]
|
||||
arg_string = val[pos..-1].strip
|
||||
args = arg_string ? Shellwords.shellwords(arg_string) : []
|
||||
|
||||
options = {
|
||||
:val => val,
|
||||
:arg_string => arg_string,
|
||||
:eval_string => eval_string,
|
||||
:nesting => nesting,
|
||||
:commands => commands.commands
|
||||
:commands => commands.commands,
|
||||
:captures => captures
|
||||
}
|
||||
|
||||
execute_command(target, command.name, options, *args)
|
||||
execute_command(target, command.name, options, *(captures + args))
|
||||
end
|
||||
|
||||
# Execute a Pry command.
|
||||
|
@ -146,6 +97,9 @@ class Pry
|
|||
context.opts = options
|
||||
context.target = target
|
||||
context.output = output
|
||||
context.captures = options[:captures]
|
||||
context.eval_string = options[:eval_string]
|
||||
context.arg_string = options[:arg_string]
|
||||
context.command_set = commands
|
||||
|
||||
context.command_processor = self
|
||||
|
@ -153,7 +107,7 @@ class Pry
|
|||
ret = commands.run_command(context, command, *args)
|
||||
|
||||
# Tick, tock, im getting rid of this shit soon.
|
||||
options[:val].clear
|
||||
options[:val].replace("")
|
||||
|
||||
ret
|
||||
end
|
||||
|
|
|
@ -5,32 +5,44 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
# This class used to create sets of commands. Commands can be impoted from
|
||||
# This class is used to create sets of commands. Commands can be imported from
|
||||
# different sets, aliased, removed, etc.
|
||||
class CommandSet
|
||||
class Command < Struct.new(:name, :description, :options, :block)
|
||||
|
||||
def call(context, *args)
|
||||
if stub_block = options[:stub_info]
|
||||
context.instance_eval(&stub_block)
|
||||
else
|
||||
ret = context.instance_exec(*args, &block)
|
||||
ret = context.instance_exec(*correct_arg_arity(block.arity, args), &block)
|
||||
ret if options[:keep_retval]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def correct_arg_arity(arity, args)
|
||||
case arity <=> 0
|
||||
when -1
|
||||
args
|
||||
when 1, 0
|
||||
# Keep 1.8 happy
|
||||
args.values_at 0..(arity - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include Enumerable
|
||||
include Pry::Helpers::BaseHelpers
|
||||
|
||||
attr_reader :commands
|
||||
attr_reader :name
|
||||
attr_reader :helper_module
|
||||
|
||||
# @param [Symbol] name Name of the command set
|
||||
# @param [Array<CommandSet>] imported_sets Sets which will be imported
|
||||
# automatically
|
||||
# @yield Optional block run to define commands
|
||||
def initialize(name, *imported_sets, &block)
|
||||
@name = name
|
||||
@commands = {}
|
||||
def initialize(*imported_sets, &block)
|
||||
@commands = {}
|
||||
@helper_module = Module.new
|
||||
|
||||
define_default_commands
|
||||
import(*imported_sets)
|
||||
|
@ -39,19 +51,29 @@ class Pry
|
|||
end
|
||||
|
||||
# Defines a new Pry command.
|
||||
# @param [String, Array] names The name of the command (or array of
|
||||
# command name aliases).
|
||||
# @param [String, Regexp] name The name of the command. Can be
|
||||
# Regexp as well as String.
|
||||
# @param [String] description A description of the command.
|
||||
# @param [Hash] options The optional configuration parameters.
|
||||
# @option options [Boolean] :keep_retval Whether or not to use return value
|
||||
# of the block for return of `command` or just to return `nil`
|
||||
# (the default).
|
||||
# @option options [Array<String>] :requires_gem Whether the command has
|
||||
# any gem dependencies, if it does and dependencies not met then
|
||||
# command is disabled and a stub proc giving instructions to
|
||||
# install command is provided.
|
||||
# @option options [Boolean] :interpolate Whether string #{} based
|
||||
# interpolation is applied to the command arguments before
|
||||
# executing the command. Defaults to true.
|
||||
# @option options [String] :listing The listing name of the
|
||||
# command. That is the name by which the command is looked up by
|
||||
# help and by show-command. Necessary for regex based commands.
|
||||
# @yield The action to perform. The parameters in the block
|
||||
# determines the parameters the command will receive. All
|
||||
# parameters passed into the block will be strings. Successive
|
||||
# command parameters are separated by whitespace at the Pry prompt.
|
||||
# @example
|
||||
# MyCommands = Pry::CommandSet.new :mine do
|
||||
# MyCommands = Pry::CommandSet.new do
|
||||
# command "greet", "Greet somebody" do |name|
|
||||
# puts "Good afternoon #{name.capitalize}!"
|
||||
# end
|
||||
|
@ -63,29 +85,49 @@ class Pry
|
|||
# # Good afternoon John!
|
||||
# # pry(main)> help greet
|
||||
# # Greet somebody
|
||||
def command(names, description="No description.", options={}, &block)
|
||||
first_name = Array(names).first
|
||||
# @example Regexp command
|
||||
# MyCommands = Pry::CommandSet.new do
|
||||
# command /number-(\d+)/, "number-N regex command", :listing => "number" do |num, name|
|
||||
# puts "hello #{name}, nice number: #{num}"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # From pry:
|
||||
# # pry(main)> _pry_.commands = MyCommands
|
||||
# # pry(main)> number-10 john
|
||||
# # hello john, nice number: 10
|
||||
# # pry(main)> help number
|
||||
# # number-N regex command
|
||||
def command(name, description="No description.", options={}, &block)
|
||||
|
||||
options = {:requires_gem => []}.merge(options)
|
||||
options = {
|
||||
:requires_gem => [],
|
||||
:keep_retval => false,
|
||||
:argument_required => false,
|
||||
:interpolate => true,
|
||||
:listing => name
|
||||
}.merge!(options)
|
||||
|
||||
unless command_dependencies_met? options
|
||||
gems_needed = Array(options[:requires_gem])
|
||||
gems_not_installed = gems_needed.select { |g| !gem_installed?(g) }
|
||||
|
||||
options[:stub_info] = proc do
|
||||
output.puts "\n#{first_name} requires the following gems to be installed: #{(gems_needed.join(", "))}"
|
||||
output.puts "Command not available due to dependency on gems: `#{gems_not_installed.join(", ")}` not being met."
|
||||
output.puts "Type `install #{first_name}` to install the required gems and activate this command."
|
||||
output.puts "\nThe command '#{name}' is #{Helpers::Text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}"
|
||||
output.puts "-"
|
||||
output.puts "Type `install #{name}` to install the required gems and activate this command."
|
||||
end
|
||||
end
|
||||
|
||||
Array(names).each do |name|
|
||||
commands[name] = Command.new(name, description, options, block)
|
||||
end
|
||||
commands[name] = Command.new(name, description, options, block)
|
||||
end
|
||||
|
||||
def each &block
|
||||
@commands.each(&block)
|
||||
end
|
||||
|
||||
# Removes some commands from the set
|
||||
# @param [Arary<String>] names name of the commands to remove
|
||||
# @param [Array<String>] names name of the commands to remove
|
||||
def delete(*names)
|
||||
names.each { |name| commands.delete name }
|
||||
end
|
||||
|
@ -94,20 +136,24 @@ class Pry
|
|||
# @param [Array<CommandSet>] sets Command sets, all of the commands of which
|
||||
# will be imported.
|
||||
def import(*sets)
|
||||
sets.each { |set| commands.merge! set.commands }
|
||||
sets.each do |set|
|
||||
commands.merge! set.commands
|
||||
helper_module.send :include, set.helper_module
|
||||
end
|
||||
end
|
||||
|
||||
# Imports some commands from a set
|
||||
# @param [CommandSet] set Set to import commands from
|
||||
# @param [Array<String>] names Commands to import
|
||||
def import_from(set, *names)
|
||||
helper_module.send :include, set.helper_module
|
||||
names.each { |name| commands[name] = set.commands[name] }
|
||||
end
|
||||
|
||||
# Aliases a command
|
||||
# @param [String] new_name New name of the command.
|
||||
# @param [String] old_name Old name of the command.
|
||||
# @pasam [String, nil] desc New description of the command.
|
||||
# @param [String, nil] desc New description of the command.
|
||||
def alias_command(new_name, old_name, desc = nil)
|
||||
commands[new_name] = commands[old_name].dup
|
||||
commands[new_name].name = new_name
|
||||
|
@ -121,11 +167,18 @@ class Pry
|
|||
# @param [Array<Object>] args Arguments passed to the command
|
||||
# @raise [NoCommandError] If the command is not defined in this set
|
||||
def run_command(context, name, *args)
|
||||
if command = commands[name]
|
||||
command.call(context, *args)
|
||||
else
|
||||
context.extend helper_module
|
||||
command = commands[name]
|
||||
|
||||
if command.nil?
|
||||
raise NoCommandError.new(name, self)
|
||||
end
|
||||
|
||||
if command.options[:argument_required] && args.empty?
|
||||
puts "The command '#{command.name}' requires an argument."
|
||||
else
|
||||
command.call context, *args
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the description for a command (replacing the old
|
||||
|
@ -133,15 +186,38 @@ class Pry
|
|||
# @param [String] name The command name.
|
||||
# @param [String] description The command description.
|
||||
# @example
|
||||
# MyCommands = Pry::CommandSet.new :test do
|
||||
# MyCommands = Pry::CommandSet.new do
|
||||
# desc "help", "help description"
|
||||
# end
|
||||
def desc(name, description)
|
||||
commands[name].description = description
|
||||
end
|
||||
|
||||
# Defines helpers methods for this command sets.
|
||||
# Those helpers are only defined in this command set.
|
||||
#
|
||||
# @yield A block defining helper methods
|
||||
# @example
|
||||
# helpers do
|
||||
# def hello
|
||||
# puts "Hello!"
|
||||
# end
|
||||
#
|
||||
# include OtherModule
|
||||
# end
|
||||
def helpers(&block)
|
||||
helper_module.class_eval(&block)
|
||||
end
|
||||
|
||||
|
||||
# @return [Array] The list of commands provided by the command set.
|
||||
def list_commands
|
||||
commands.keys
|
||||
end
|
||||
|
||||
private
|
||||
def define_default_commands
|
||||
|
||||
command "help", "This menu." do |cmd|
|
||||
if !cmd
|
||||
output.puts
|
||||
|
@ -149,13 +225,13 @@ class Pry
|
|||
|
||||
commands.each do |key, command|
|
||||
if command.description && !command.description.empty?
|
||||
help_text << "#{key}".ljust(18) + command.description + "\n"
|
||||
help_text << "#{command.options[:listing]}".ljust(18) + command.description + "\n"
|
||||
end
|
||||
end
|
||||
|
||||
stagger_output(help_text)
|
||||
else
|
||||
if command = commands[cmd]
|
||||
if command = find_command(cmd)
|
||||
output.puts command.description
|
||||
else
|
||||
output.puts "No info for command: #{cmd}"
|
||||
|
@ -164,7 +240,8 @@ class Pry
|
|||
end
|
||||
|
||||
command "install", "Install a disabled command." do |name|
|
||||
stub_info = commands[name].options[:stub_info]
|
||||
command = find_command(name)
|
||||
stub_info = command.options[:stub_info]
|
||||
|
||||
if !stub_info
|
||||
output.puts "Not a command stub. Nothing to do."
|
||||
|
@ -172,7 +249,7 @@ class Pry
|
|||
end
|
||||
|
||||
output.puts "Attempting to install `#{name}` command..."
|
||||
gems_to_install = Array(commands[name].options[:requires_gem])
|
||||
gems_to_install = Array(command.options[:requires_gem])
|
||||
|
||||
gem_install_failed = false
|
||||
gems_to_install.each do |g|
|
||||
|
@ -190,7 +267,17 @@ class Pry
|
|||
next if gem_install_failed
|
||||
|
||||
Gem.refresh
|
||||
commands[name].options.delete :stub_info
|
||||
gems_to_install.each do |g|
|
||||
begin
|
||||
require g
|
||||
rescue LoadError
|
||||
output.puts "Required Gem: `#{g}` installed but not found?!. Aborting command installation."
|
||||
gem_install_failed = true
|
||||
end
|
||||
end
|
||||
next if gem_install_failed
|
||||
|
||||
command.options.delete :stub_info
|
||||
output.puts "Installation of `#{name}` successful! Type `help #{name}` for information"
|
||||
end
|
||||
end
|
||||
|
|
1004
lib/pry/commands.rb
1004
lib/pry/commands.rb
File diff suppressed because it is too large
Load diff
|
@ -14,28 +14,29 @@ class Pry
|
|||
Readline.completion_append_character = nil
|
||||
|
||||
ReservedWords = [
|
||||
"BEGIN", "END",
|
||||
"alias", "and",
|
||||
"begin", "break",
|
||||
"case", "class",
|
||||
"def", "defined", "do",
|
||||
"else", "elsif", "end", "ensure",
|
||||
"false", "for",
|
||||
"if", "in",
|
||||
"module",
|
||||
"next", "nil", "not",
|
||||
"or",
|
||||
"redo", "rescue", "retry", "return",
|
||||
"self", "super",
|
||||
"then", "true",
|
||||
"undef", "unless", "until",
|
||||
"when", "while",
|
||||
"yield",
|
||||
]
|
||||
"BEGIN", "END",
|
||||
"alias", "and",
|
||||
"begin", "break",
|
||||
"case", "class",
|
||||
"def", "defined", "do",
|
||||
"else", "elsif", "end", "ensure",
|
||||
"false", "for",
|
||||
"if", "in",
|
||||
"module",
|
||||
"next", "nil", "not",
|
||||
"or",
|
||||
"redo", "rescue", "retry", "return",
|
||||
"self", "super",
|
||||
"then", "true",
|
||||
"undef", "unless", "until",
|
||||
"when", "while",
|
||||
"yield" ]
|
||||
|
||||
Operators = ["%", "&", "*", "**", "+", "-", "/",
|
||||
"<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
|
||||
"[]", "[]=", "^", "!", "!=", "!~"]
|
||||
Operators = [
|
||||
"%", "&", "*", "**", "+", "-", "/",
|
||||
"<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
|
||||
"[]", "[]=", "^", "!", "!=", "!~"
|
||||
]
|
||||
|
||||
# Return a new completion proc for use by Readline.
|
||||
# @param [Binding] target The current binding context.
|
||||
|
@ -188,13 +189,13 @@ class Pry
|
|||
|
||||
def self.select_message(receiver, message, candidates)
|
||||
candidates.grep(/^#{message}/).collect do |e|
|
||||
case e
|
||||
when /^[a-zA-Z_]/
|
||||
receiver + "." + e
|
||||
when /^[0-9]/
|
||||
when *Operators
|
||||
#receiver + " " + e
|
||||
end
|
||||
case e
|
||||
when /^[a-zA-Z_]/
|
||||
receiver + "." + e
|
||||
when /^[0-9]/
|
||||
when *Operators
|
||||
#receiver + " " + e
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
86
lib/pry/config.rb
Normal file
86
lib/pry/config.rb
Normal file
|
@ -0,0 +1,86 @@
|
|||
require 'ostruct'
|
||||
|
||||
class Pry
|
||||
class Config < OpenStruct
|
||||
|
||||
# Get/Set the object to use for input by default by all Pry instances.
|
||||
# @return [#readline] The object to use for input by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :input
|
||||
|
||||
# Get/Set the object to use for output by default by all Pry instances.
|
||||
# @return [#puts] The object to use for output by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :output
|
||||
|
||||
# Get/Set the object to use for commands by default by all Pry instances.
|
||||
# @return [Pry::CommandBase] The object to use for commands by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :commands
|
||||
|
||||
# Get/Set the Proc to use for printing by default by all Pry
|
||||
# instances.
|
||||
# This is the 'print' component of the REPL.
|
||||
# @return [Proc] The Proc to use for printing by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :print
|
||||
|
||||
# @return [Proc] The Proc to use for printing exceptions by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :exception_handler
|
||||
|
||||
# Get/Set the Hash that defines Pry hooks used by default by all Pry
|
||||
# instances.
|
||||
# @return [Hash] The hooks used by default by all Pry instances.
|
||||
# @example
|
||||
# Pry.hooks :before_session => proc { puts "hello" },
|
||||
# :after_session => proc { puts "goodbye" }
|
||||
attr_accessor :hooks
|
||||
|
||||
# Get the array of Procs to be used for the prompts by default by
|
||||
# all Pry instances.
|
||||
# @return [Array<Proc>] The array of Procs to be used for the
|
||||
# prompts by default by all Pry instances.
|
||||
attr_accessor :prompt
|
||||
|
||||
# The default editor to use. Defaults to $EDITOR or nano if
|
||||
# $EDITOR is not defined.
|
||||
# If `editor` is a String then that string is used as the shell
|
||||
# command to invoke the editor. If `editor` is callable (e.g a
|
||||
# Proc) then `file` and `line` are passed in as parameters and the
|
||||
# return value of that callable invocation is used as the exact
|
||||
# shell command to invoke the editor.
|
||||
# @example String
|
||||
# Pry.editor = "emacsclient"
|
||||
# @example Callable
|
||||
# Pry.editor = proc { |file, line| "emacsclient #{file} +#{line}" }
|
||||
# @return [String, #call]
|
||||
attr_accessor :editor
|
||||
|
||||
# @return [Boolean] Toggle Pry color on and off.
|
||||
attr_accessor :color
|
||||
|
||||
# @return [Boolean] Toggle paging on and off.
|
||||
attr_accessor :pager
|
||||
|
||||
# Determines whether the rc file (~/.pryrc) should be loaded.
|
||||
# @return [Boolean]
|
||||
attr_accessor :should_load_rc
|
||||
|
||||
# Determines whether plugins should be loaded.
|
||||
# @return [Boolean]
|
||||
attr_accessor :should_load_plugins
|
||||
|
||||
# Config option for history.
|
||||
# sub-options include hist.file, hist.load, and hist.save
|
||||
# hist.file is the file to save/load history too, e.g
|
||||
# Pry.config.history.file = "~/.pry_history".
|
||||
# hist.load is a boolean that determines whether history will be
|
||||
# loaded from hist.file at session start.
|
||||
# hist.save is a boolean that determines whether history will be
|
||||
# saved to hist.file at session end.
|
||||
# @return [OpenStruct]
|
||||
attr_accessor :history
|
||||
end
|
||||
end
|
||||
|
37
lib/pry/default_commands/basic.rb
Normal file
37
lib/pry/default_commands/basic.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
Basic = Pry::CommandSet.new do
|
||||
command "toggle-color", "Toggle syntax highlighting." do
|
||||
Pry.color = !Pry.color
|
||||
output.puts "Syntax highlighting #{Pry.color ? "on" : "off"}"
|
||||
end
|
||||
|
||||
command "simple-prompt", "Toggle the simple prompt." do
|
||||
case Pry.active_instance.prompt
|
||||
when Pry::SIMPLE_PROMPT
|
||||
Pry.active_instance.pop_prompt
|
||||
else
|
||||
Pry.active_instance.push_prompt Pry::SIMPLE_PROMPT
|
||||
end
|
||||
end
|
||||
|
||||
command "version", "Show Pry version." do
|
||||
output.puts "Pry version: #{Pry::VERSION} on Ruby #{RUBY_VERSION}."
|
||||
end
|
||||
|
||||
command "import", "Import a command set" do |command_set_name|
|
||||
next output.puts "Provide a command set name" if command_set.nil?
|
||||
|
||||
set = target.eval(arg_string)
|
||||
Pry.active_instance.commands.import set
|
||||
end
|
||||
|
||||
command "reset", "Reset the REPL to a clean state." do
|
||||
output.puts "Pry reset."
|
||||
exec "pry"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
127
lib/pry/default_commands/context.rb
Normal file
127
lib/pry/default_commands/context.rb
Normal file
|
@ -0,0 +1,127 @@
|
|||
require "pry/default_commands/ls"
|
||||
|
||||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
Context = Pry::CommandSet.new do
|
||||
import Ls
|
||||
|
||||
command "cd", "Start a Pry session on VAR (use `cd ..` to go back and `cd /` to return to Pry top-level)", :keep_retval => true do |obj|
|
||||
case obj
|
||||
when nil
|
||||
output.puts "Must provide an object."
|
||||
next
|
||||
when ".."
|
||||
throw(:breakout, opts[:nesting].level)
|
||||
when "/"
|
||||
throw(:breakout, 1) if opts[:nesting].level > 0
|
||||
next
|
||||
when "::"
|
||||
TOPLEVEL_BINDING.pry
|
||||
next
|
||||
else
|
||||
Pry.start target.eval(arg_string)
|
||||
end
|
||||
end
|
||||
|
||||
command "nesting", "Show nesting information." do
|
||||
nesting = opts[:nesting]
|
||||
|
||||
output.puts "Nesting status:"
|
||||
output.puts "--"
|
||||
nesting.each do |level, obj|
|
||||
if level == 0
|
||||
output.puts "#{level}. #{Pry.view_clip(obj)} (Pry top level)"
|
||||
else
|
||||
output.puts "#{level}. #{Pry.view_clip(obj)}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
command "jump-to", "Jump to a Pry session further up the stack, exiting all sessions below." do |break_level|
|
||||
break_level = break_level.to_i
|
||||
nesting = opts[:nesting]
|
||||
|
||||
case break_level
|
||||
when nesting.level
|
||||
output.puts "Already at nesting level #{nesting.level}"
|
||||
when (0...nesting.level)
|
||||
throw(:breakout, break_level + 1)
|
||||
else
|
||||
max_nest_level = nesting.level - 1
|
||||
output.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}."
|
||||
end
|
||||
end
|
||||
|
||||
command "exit", "End the current Pry session. Accepts optional return value. Aliases: quit, back" do
|
||||
throw(:breakout, [opts[:nesting].level, target.eval(arg_string)])
|
||||
end
|
||||
|
||||
alias_command "quit", "exit", ""
|
||||
alias_command "back", "exit", ""
|
||||
|
||||
command "exit-all", "End all nested Pry sessions. Accepts optional return value. Aliases: !!@" do
|
||||
throw(:breakout, [0, target.eval(arg_string)])
|
||||
end
|
||||
|
||||
alias_command "!!@", "exit-all", ""
|
||||
|
||||
command "exit-program", "End the current program. Aliases: quit-program, !!!" do
|
||||
exit
|
||||
end
|
||||
|
||||
alias_command "quit-program", "exit-program", ""
|
||||
alias_command "!!!", "exit-program", ""
|
||||
|
||||
command "!pry", "Start a Pry session on current self; this even works mid-expression." do
|
||||
target.pry
|
||||
end
|
||||
|
||||
command "whereami", "Show the code context for the session. (whereami <n> shows <n> extra lines of code around the invocation line. Default: 5)" do |num|
|
||||
file = target.eval('__FILE__')
|
||||
line_num = target.eval('__LINE__')
|
||||
klass = target.eval('self.class')
|
||||
|
||||
if num
|
||||
i_num = num.to_i
|
||||
else
|
||||
i_num = 5
|
||||
end
|
||||
|
||||
meth_name = meth_name_from_binding(target)
|
||||
meth_name = "N/A" if !meth_name
|
||||
|
||||
if file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e"
|
||||
output.puts "Cannot find local context. Did you use `binding.pry` ?"
|
||||
next
|
||||
end
|
||||
|
||||
set_file_and_dir_locals(file)
|
||||
output.puts "\n#{text.bold('From:')} #{file} @ line #{line_num} in #{klass}##{meth_name}:\n\n"
|
||||
|
||||
# This method inspired by http://rubygems.org/gems/ir_b
|
||||
File.open(file).each_with_index do |line, index|
|
||||
line_n = index + 1
|
||||
next unless line_n > (line_num - i_num - 1)
|
||||
break if line_n > (line_num + i_num)
|
||||
if line_n == line_num
|
||||
code =" =>#{line_n.to_s.rjust(3)}: #{line.chomp}"
|
||||
if Pry.color
|
||||
code = CodeRay.scan(code, :ruby).term
|
||||
end
|
||||
output.puts code
|
||||
code
|
||||
else
|
||||
code = "#{line_n.to_s.rjust(6)}: #{line.chomp}"
|
||||
if Pry.color
|
||||
code = CodeRay.scan(code, :ruby).term
|
||||
end
|
||||
output.puts code
|
||||
code
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
146
lib/pry/default_commands/documentation.rb
Normal file
146
lib/pry/default_commands/documentation.rb
Normal file
|
@ -0,0 +1,146 @@
|
|||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
Documentation = Pry::CommandSet.new do
|
||||
|
||||
command "ri", "View ri documentation. e.g `ri Array#each`" do |*args|
|
||||
run ".ri", *args
|
||||
end
|
||||
|
||||
command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info. Aliases: \?" do |*args|
|
||||
target = target()
|
||||
|
||||
opts = Slop.parse!(args) do |opt|
|
||||
opt.banner = "Usage: show-doc [OPTIONS] [METH]\n" \
|
||||
"Show the comments above method METH. Tries instance methods first and then methods by default.\n" \
|
||||
"e.g show-doc hello_method"
|
||||
|
||||
opt.on :M, "instance-methods", "Operate on instance methods."
|
||||
opt.on :m, :methods, "Operate on methods."
|
||||
opt.on :c, :context, "Select object context to run under.", true do |context|
|
||||
target = Pry.binding_for(target.eval(context))
|
||||
end
|
||||
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
||||
opt.on :h, :help, "This message." do
|
||||
output.puts opt
|
||||
end
|
||||
end
|
||||
|
||||
next if opts.help?
|
||||
|
||||
meth_name = args.shift
|
||||
if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
|
||||
output.puts "Invalid method name: #{meth_name}. Type `show-doc --help` for help"
|
||||
next
|
||||
end
|
||||
|
||||
doc, code_type = doc_and_code_type_for(meth)
|
||||
next if !doc
|
||||
|
||||
next output.puts("No documentation found.") if doc.empty?
|
||||
doc = process_comment_markup(doc, code_type)
|
||||
output.puts make_header(meth, code_type, doc)
|
||||
render_output(opts.flood?, false, doc)
|
||||
doc
|
||||
end
|
||||
|
||||
alias_command "?", "show-doc", ""
|
||||
|
||||
|
||||
command "stat", "View method information and set _file_ and _dir_ locals. Type `stat --help` for more info." do |*args|
|
||||
target = target()
|
||||
|
||||
opts = Slop.parse!(args) do |opt|
|
||||
opt.banner "Usage: stat [OPTIONS] [METH]\n" \
|
||||
"Show method information for method METH and set _file_ and _dir_ locals." \
|
||||
"e.g: stat hello_method"
|
||||
|
||||
opt.on :M, "instance-methods", "Operate on instance methods."
|
||||
opt.on :m, :methods, "Operate on methods."
|
||||
opt.on :c, :context, "Select object context to run under.", true do |context|
|
||||
target = Pry.binding_for(target.eval(context))
|
||||
end
|
||||
opt.on :h, :help, "This message" do
|
||||
output.puts opt
|
||||
end
|
||||
end
|
||||
|
||||
next if opts.help?
|
||||
|
||||
meth_name = args.shift
|
||||
if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
|
||||
output.puts "Invalid method name: #{meth_name}. Type `stat --help` for help"
|
||||
next
|
||||
end
|
||||
|
||||
code, code_type = code_and_code_type_for(meth)
|
||||
next if !code
|
||||
doc, code_type = doc_and_code_type_for(meth)
|
||||
|
||||
output.puts make_header(meth, code_type, code)
|
||||
output.puts text.bold("Method Name: ") + meth_name
|
||||
output.puts text.bold("Method Owner: ") + (meth.owner.to_s ? meth.owner.to_s : "Unknown")
|
||||
output.puts text.bold("Method Language: ") + code_type.to_s.capitalize
|
||||
output.puts text.bold("Method Type: ") + (meth.is_a?(Method) ? "Bound" : "Unbound")
|
||||
output.puts text.bold("Method Arity: ") + meth.arity.to_s
|
||||
|
||||
name_map = { :req => "Required:", :opt => "Optional:", :rest => "Rest:" }
|
||||
if meth.respond_to?(:parameters)
|
||||
output.puts text.bold("Method Parameters: ") + meth.parameters.group_by(&:first).
|
||||
map { |k, v| "#{name_map[k]} #{v.map { |kk, vv| vv ? vv.to_s : "noname" }.join(", ")}" }.join(". ")
|
||||
end
|
||||
output.puts text.bold("Comment length: ") + (doc.empty? ? 'No comment.' : (doc.lines.count.to_s + ' lines.'))
|
||||
end
|
||||
|
||||
command "gist-method", "Gist a method to github. Type `gist-method --help` for more info.", :requires_gem => "gist" do |*args|
|
||||
require 'gist'
|
||||
|
||||
target = target()
|
||||
|
||||
opts = Slop.parse!(args) do |opt|
|
||||
opt.banner "Usage: gist-method [OPTIONS] [METH]\n" \
|
||||
"Gist the method (doc or source) to github.\n" \
|
||||
"Ensure the `gist` gem is properly working before use. http://github.com/defunkt/gist for instructions.\n" \
|
||||
"e.g: gist -m my_method\n" \
|
||||
"e.g: gist -d my_method\n"
|
||||
|
||||
opt.on :m, :method, "Gist a method's source."
|
||||
opt.on :d, :doc, "Gist a method's documentation."
|
||||
opt.on :p, :private, "Create a private gist (default: true)", :default => true
|
||||
opt.on :h, :help, "This message" do
|
||||
output.puts opt
|
||||
end
|
||||
end
|
||||
|
||||
next if opts.help?
|
||||
|
||||
# This needs to be extracted into its own method as it's shared
|
||||
# by show-method and show-doc and stat commands
|
||||
meth_name = args.shift
|
||||
if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
|
||||
output.puts "Invalid method name: #{meth_name}. Type `gist-method --help` for help"
|
||||
next
|
||||
end
|
||||
|
||||
type_map = { :ruby => "rb", :c => "c", :plain => "plain" }
|
||||
if !opts.doc?
|
||||
content, code_type = code_and_code_type_for(meth)
|
||||
else
|
||||
content, code_type = doc_and_code_type_for(meth)
|
||||
text.no_color do
|
||||
content = process_comment_markup(content, code_type)
|
||||
end
|
||||
code_type = :plain
|
||||
end
|
||||
|
||||
link = Gist.write([:extension => ".#{type_map[code_type]}",
|
||||
:input => content],
|
||||
opts.p?)
|
||||
|
||||
output.puts "Gist created at #{link}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
52
lib/pry/default_commands/easter_eggs.rb
Normal file
52
lib/pry/default_commands/easter_eggs.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
EasterEggs = Pry::CommandSet.new do
|
||||
|
||||
command "east-coker", "" do
|
||||
text = %{
|
||||
--
|
||||
Now the light falls
|
||||
Across the open field, leaving the deep lane
|
||||
Shuttered with branches, dark in the afternoon,
|
||||
Where you lean against a bank while a van passes,
|
||||
And the deep lane insists on the direction
|
||||
Into the village, in the electric heat
|
||||
Hypnotised. In a warm haze the sultry light
|
||||
Is absorbed, not refracted, by grey stone.
|
||||
The dahlias sleep in the empty silence.
|
||||
Wait for the early owl.
|
||||
-- T.S Eliot
|
||||
}
|
||||
output.puts text
|
||||
text
|
||||
end
|
||||
|
||||
command "cohen-poem", "" do
|
||||
text = %{
|
||||
--
|
||||
When this American woman,
|
||||
whose thighs are bound in casual red cloth,
|
||||
comes thundering past my sitting place
|
||||
like a forest-burning Mongol tribe,
|
||||
the city is ravished
|
||||
and brittle buildings of a hundred years
|
||||
splash into the street;
|
||||
and my eyes are burnt
|
||||
for the embroidered Chinese girls,
|
||||
already old,
|
||||
and so small between the thin pines
|
||||
on these enormous landscapes,
|
||||
that if you turn your head
|
||||
they are lost for hours.
|
||||
-- Leonard Cohen
|
||||
}
|
||||
output.puts text
|
||||
text
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
46
lib/pry/default_commands/gems.rb
Normal file
46
lib/pry/default_commands/gems.rb
Normal file
|
@ -0,0 +1,46 @@
|
|||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
Gems = Pry::CommandSet.new do
|
||||
|
||||
command "gem-install", "Install a gem and refresh the gem cache.", :argument_required => true do |gem|
|
||||
begin
|
||||
destination = File.writable?(Gem.dir) ? Gem.dir : Gem.user_dir
|
||||
installer = Gem::DependencyInstaller.new :install_dir => destination
|
||||
installer.install gem
|
||||
rescue Errno::EACCES
|
||||
output.puts "Insufficient permissions to install `#{text.green gem}`"
|
||||
rescue Gem::GemNotFoundException
|
||||
output.puts "Gem `#{text.green gem}` not found."
|
||||
else
|
||||
Gem.refresh
|
||||
output.puts "Gem `#{text.green gem}` installed."
|
||||
end
|
||||
end
|
||||
|
||||
command "gem-cd", "Change working directory to specified gem's directory.", :argument_required => true do |gem|
|
||||
spec = Gem.source_index.find_name(gem).sort { |a,b| Gem::Version.new(b.version) <=> Gem::Version.new(a.version) }.first
|
||||
spec ? Dir.chdir(spec.full_gem_path) : output.puts("Gem `#{gem}` not found.")
|
||||
end
|
||||
|
||||
|
||||
command "gem-list", "List/search installed gems. (Optional parameter: a regexp to limit the search)" do |pattern|
|
||||
pattern = Regexp.new pattern.to_s, Regexp::IGNORECASE
|
||||
gems = Gem.source_index.find_name(pattern).group_by(&:name)
|
||||
|
||||
gems.each do |gem, specs|
|
||||
specs.sort! do |a,b|
|
||||
Gem::Version.new(b.version) <=> Gem::Version.new(a.version)
|
||||
end
|
||||
|
||||
versions = specs.map.with_index do |spec, index|
|
||||
index == 0 ? text.bright_green(spec.version.to_s) : text.green(spec.version.to_s)
|
||||
end
|
||||
|
||||
output.puts "#{text.white gem} (#{versions.join ', '})"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
114
lib/pry/default_commands/input.rb
Normal file
114
lib/pry/default_commands/input.rb
Normal file
|
@ -0,0 +1,114 @@
|
|||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
Input = Pry::CommandSet.new do
|
||||
|
||||
command "!", "Clear the input buffer. Useful if the parsing process goes wrong and you get stuck in the read loop." do
|
||||
output.puts "Input buffer cleared!"
|
||||
eval_string.replace("")
|
||||
end
|
||||
|
||||
command "show-input", "Show the current eval_string" do
|
||||
render_output(false, 0, Pry.color ? CodeRay.scan(eval_string, :ruby).term : eval_string)
|
||||
end
|
||||
|
||||
command /amend-line-?(\d+)?/, "Experimental amend-line, where the N in amend-line-N represents line to replace. Aliases: %N",
|
||||
:interpolate => false, :listing => "amend-line-N" do |line_number, replacement_line|
|
||||
replacement_line = "" if !replacement_line
|
||||
input_array = eval_string.each_line.to_a
|
||||
line_num = line_number ? line_number.to_i : input_array.size - 1
|
||||
input_array[line_num] = arg_string + "\n"
|
||||
eval_string.replace input_array.join
|
||||
end
|
||||
|
||||
alias_command /%(\d+)?/, /amend-line-?(\d+)?/, ""
|
||||
|
||||
command "hist", "Show and replay Readline history. Type `hist --help` for more info." do |*args|
|
||||
Slop.parse(args) do |opt|
|
||||
history = Readline::HISTORY.to_a
|
||||
opt.banner "Usage: hist [--replay START..END] [--clear] [--grep PATTERN] [--head N] [--tail N] [--help]\n"
|
||||
|
||||
opt.on :g, :grep, 'A pattern to match against the history.', true do |pattern|
|
||||
pattern = Regexp.new arg_string.split(/ /)[1]
|
||||
history.pop
|
||||
|
||||
history.map!.with_index do |element, index|
|
||||
if element =~ pattern
|
||||
"#{text.blue index}: #{element}"
|
||||
end
|
||||
end
|
||||
|
||||
stagger_output history.compact.join "\n"
|
||||
end
|
||||
|
||||
opt.on :head, 'Display the first N items of history', :optional => true, :as => Integer do |limit|
|
||||
unless opt.grep?
|
||||
limit ||= 10
|
||||
list = history.first limit
|
||||
lines = text.with_line_numbers list.join("\n"), 0
|
||||
stagger_output lines
|
||||
end
|
||||
end
|
||||
|
||||
opt.on :t, :tail, 'Display the last N items of history', :optional => true, :as => Integer do |limit|
|
||||
unless opt.grep?
|
||||
limit ||= 10
|
||||
offset = history.size-limit
|
||||
offset = offset < 0 ? 0 : offset
|
||||
|
||||
list = history.last limit
|
||||
lines = text.with_line_numbers list.join("\n"), offset
|
||||
stagger_output lines
|
||||
end
|
||||
end
|
||||
|
||||
opt.on :s, :show, 'Show the history corresponding to the history line (or range of lines).', true, :as => Range do |range|
|
||||
unless opt.grep?
|
||||
start_line = range.is_a?(Range) ? range.first : range
|
||||
lines = text.with_line_numbers Array(history[range]).join("\n"), start_line
|
||||
stagger_output lines
|
||||
end
|
||||
end
|
||||
|
||||
opt.on :e, :exclude, 'Exclude pry commands from the history.' do
|
||||
unless opt.grep?
|
||||
history.map!.with_index do |element, index|
|
||||
unless command_processor.valid_command? element
|
||||
"#{text.blue index}: #{element}"
|
||||
end
|
||||
end
|
||||
stagger_output history.compact.join "\n"
|
||||
end
|
||||
end
|
||||
|
||||
opt.on :r, :replay, 'The line (or range of lines) to replay.', true, :as => Range do |range|
|
||||
unless opt.grep?
|
||||
actions = Array(history[range]).join("\n") + "\n"
|
||||
Pry.active_instance.input = StringIO.new(actions)
|
||||
end
|
||||
end
|
||||
|
||||
opt.on :c, :clear, 'Clear the history' do
|
||||
unless opt.grep?
|
||||
Readline::HISTORY.shift until Readline::HISTORY.empty?
|
||||
output.puts 'History cleared.'
|
||||
end
|
||||
end
|
||||
|
||||
opt.on :h, :help, 'Show this message.', :tail => true do
|
||||
unless opt.grep?
|
||||
output.puts opt.help
|
||||
end
|
||||
end
|
||||
|
||||
opt.on_empty do
|
||||
lines = text.with_line_numbers history.join("\n"), 0
|
||||
stagger_output lines
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
180
lib/pry/default_commands/introspection.rb
Normal file
180
lib/pry/default_commands/introspection.rb
Normal file
|
@ -0,0 +1,180 @@
|
|||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
Introspection = Pry::CommandSet.new do
|
||||
|
||||
command "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source" do |*args|
|
||||
target = target()
|
||||
|
||||
opts = Slop.parse!(args) do |opt|
|
||||
opt.banner "Usage: show-method [OPTIONS] [METH]\n" \
|
||||
"Show the source for method METH. Tries instance methods first and then methods by default.\n" \
|
||||
"e.g: show-method hello_method"
|
||||
|
||||
opt.on :l, "line-numbers", "Show line numbers."
|
||||
opt.on :M, "instance-methods", "Operate on instance methods."
|
||||
opt.on :m, :methods, "Operate on methods."
|
||||
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
||||
opt.on :c, :context, "Select object context to run under.", true do |context|
|
||||
target = Pry.binding_for(target.eval(context))
|
||||
end
|
||||
opt.on :h, :help, "This message." do
|
||||
output.puts opt
|
||||
end
|
||||
end
|
||||
|
||||
next if opts.help?
|
||||
|
||||
meth_name = args.shift
|
||||
if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
|
||||
output.puts "Invalid method name: #{meth_name}. Type `show-method --help` for help"
|
||||
next
|
||||
end
|
||||
|
||||
code, code_type = code_and_code_type_for(meth)
|
||||
next if !code
|
||||
|
||||
output.puts make_header(meth, code_type, code)
|
||||
if Pry.color
|
||||
code = CodeRay.scan(code, code_type).term
|
||||
end
|
||||
|
||||
start_line = false
|
||||
if opts.l?
|
||||
start_line = meth.source_location ? meth.source_location.last : 1
|
||||
end
|
||||
|
||||
render_output(opts.flood?, start_line, code)
|
||||
code
|
||||
end
|
||||
|
||||
alias_command "show-source", "show-method", ""
|
||||
alias_command "$", "show-method", ""
|
||||
|
||||
command "show-command", "Show the source for CMD. Type `show-command --help` for more info." do |*args|
|
||||
target = target()
|
||||
|
||||
opts = Slop.parse!(args) do |opt|
|
||||
opt.banner = "Usage: show-command [OPTIONS] [CMD]\n" \
|
||||
"Show the source for command CMD.\n" \
|
||||
"e.g: show-command show-method"
|
||||
|
||||
opt.on :l, "line-numbers", "Show line numbers."
|
||||
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
||||
opt.on :h, :help, "This message." do
|
||||
output.puts opt
|
||||
end
|
||||
end
|
||||
|
||||
next if opts.help?
|
||||
|
||||
command_name = args.shift
|
||||
if !command_name
|
||||
output.puts "You must provide a command name."
|
||||
next
|
||||
end
|
||||
|
||||
if find_command(command_name)
|
||||
block = find_command(command_name).block
|
||||
|
||||
code, _ = code_and_code_type_for(block)
|
||||
next if !code
|
||||
|
||||
output.puts make_header(block, :ruby, code)
|
||||
|
||||
if Pry.color
|
||||
code = CodeRay.scan(code, :ruby).term
|
||||
end
|
||||
|
||||
start_line = false
|
||||
if opts.l?
|
||||
start_line = block.source_location ? block.source_location.last : 1
|
||||
end
|
||||
|
||||
render_output(opts.flood?, opts.l? ? block.source_location.last : false, code)
|
||||
code
|
||||
else
|
||||
output.puts "No such command: #{command_name}."
|
||||
end
|
||||
end
|
||||
|
||||
command "edit-method", "Edit a method. Type `edit-method --help` for more info." do |*args|
|
||||
target = target()
|
||||
|
||||
opts = Slop.parse!(args) do |opt|
|
||||
opt.banner "Usage: edit-method [OPTIONS] [METH]\n" \
|
||||
"Edit the method METH in an editor.\n" \
|
||||
"Ensure #{text.bold("Pry.editor")} is set to your editor of choice.\n" \
|
||||
"e.g: edit-method hello_method"
|
||||
|
||||
opt.on :M, "instance-methods", "Operate on instance methods."
|
||||
opt.on :m, :methods, "Operate on methods."
|
||||
opt.on "no-reload", "Do not automatically reload the method's file after editting."
|
||||
opt.on :n, "no-jump", "Do not fast forward editor to first line of method."
|
||||
opt.on :c, :context, "Select object context to run under.", true do |context|
|
||||
target = Pry.binding_for(target.eval(context))
|
||||
end
|
||||
opt.on :h, :help, "This message." do
|
||||
output.puts opt
|
||||
end
|
||||
end
|
||||
|
||||
next if opts.help?
|
||||
|
||||
meth_name = args.shift
|
||||
if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
|
||||
output.puts "Invalid method name: #{meth_name}."
|
||||
next
|
||||
end
|
||||
|
||||
next output.puts "Error: No editor set!\nEnsure that #{text.bold("Pry.editor")} is set to your editor of choice." if !Pry.editor
|
||||
|
||||
if is_a_c_method?(meth)
|
||||
output.puts "Error: Can't edit a C method."
|
||||
elsif is_a_dynamically_defined_method?(meth)
|
||||
output.puts "Error: Can't edit an eval method."
|
||||
|
||||
# editor is invoked here
|
||||
else
|
||||
file, line = meth.source_location
|
||||
set_file_and_dir_locals(file)
|
||||
|
||||
if Pry.editor.respond_to?(:call)
|
||||
editor_invocation = Pry.editor.call(file, line)
|
||||
else
|
||||
# only use start line if -n option is not used
|
||||
start_line_syntax = opts.n? ? "" : start_line_for_editor(line)
|
||||
editor_invocation = "#{Pry.editor} #{start_line_syntax} #{file}"
|
||||
end
|
||||
|
||||
run ".#{editor_invocation}"
|
||||
silence_warnings do
|
||||
load file if !opts["no-reload"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
helpers do
|
||||
|
||||
def start_line_for_editor(line_number)
|
||||
case Pry.editor
|
||||
when /^[gm]?vi/, /^emacs/, /^nano/, /^pico/, /^gedit/, /^kate/
|
||||
"+#{line_number}"
|
||||
when /^mate/, /^geany/
|
||||
"-l #{line_number}"
|
||||
else
|
||||
if RUBY_PLATFORM =~ /mswin|mingw/
|
||||
""
|
||||
else
|
||||
"+#{line_number}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
199
lib/pry/default_commands/ls.rb
Normal file
199
lib/pry/default_commands/ls.rb
Normal file
|
@ -0,0 +1,199 @@
|
|||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
Ls = Pry::CommandSet.new do
|
||||
|
||||
command "ls", "Show the list of vars and methods in the current scope. Type `ls --help` for more info." do |*args|
|
||||
options = {}
|
||||
# Set target local to the default -- note that we can set a different target for
|
||||
# ls if we like: e.g ls my_var
|
||||
target = target()
|
||||
|
||||
OptionParser.new do |opts|
|
||||
opts.banner = %{Usage: ls [OPTIONS] [VAR]\n\
|
||||
List information about VAR (the current context by default).
|
||||
Shows local and instance variables by default.
|
||||
--
|
||||
}
|
||||
opts.on("-g", "--globals", "Display global variables.") do
|
||||
options[:g] = true
|
||||
end
|
||||
|
||||
opts.on("-c", "--constants", "Display constants.") do
|
||||
options[:c] = true
|
||||
end
|
||||
|
||||
opts.on("-l", "--locals", "Display locals.") do
|
||||
options[:l] = true
|
||||
end
|
||||
|
||||
opts.on("-i", "--ivars", "Display instance variables.") do
|
||||
options[:i] = true
|
||||
end
|
||||
|
||||
opts.on("-k", "--class-vars", "Display class variables.") do
|
||||
options[:k] = true
|
||||
end
|
||||
|
||||
opts.on("-m", "--methods", "Display methods (public methods by default).") do
|
||||
options[:m] = true
|
||||
end
|
||||
|
||||
opts.on("-M", "--instance-methods", "Display instance methods (only relevant to classes and modules).") do
|
||||
options[:M] = true
|
||||
end
|
||||
|
||||
opts.on("-P", "--public", "Display public methods (with -m).") do
|
||||
options[:P] = true
|
||||
end
|
||||
|
||||
opts.on("-r", "--protected", "Display protected methods (with -m).") do
|
||||
options[:r] = true
|
||||
end
|
||||
|
||||
opts.on("-p", "--private", "Display private methods (with -m).") do
|
||||
options[:p] = true
|
||||
end
|
||||
|
||||
opts.on("-j", "--just-singletons", "Display just the singleton methods (with -m).") do
|
||||
options[:j] = true
|
||||
end
|
||||
|
||||
opts.on("-s", "--super", "Include superclass entries (relevant to constant and methods options).") do
|
||||
options[:s] = true
|
||||
end
|
||||
|
||||
opts.on("-a", "--all", "Display all types of entries.") do
|
||||
options[:a] = true
|
||||
end
|
||||
|
||||
opts.on("-v", "--verbose", "Verbose ouput.") do
|
||||
options[:v] = true
|
||||
end
|
||||
|
||||
opts.on("-f", "--flood", "Do not use a pager to view text longer than one screen.") do
|
||||
options[:f] = true
|
||||
end
|
||||
|
||||
opts.on("--grep REG", "Regular expression to be used.") do |reg|
|
||||
options[:grep] = Regexp.new(reg)
|
||||
end
|
||||
|
||||
opts.on_tail("-h", "--help", "Show this message.") do
|
||||
output.puts opts
|
||||
options[:h] = true
|
||||
end
|
||||
end.order(args) do |new_target|
|
||||
target = Pry.binding_for(target.eval("#{new_target}")) if !options[:h]
|
||||
end
|
||||
|
||||
# exit if we've displayed help
|
||||
next if options[:h]
|
||||
|
||||
# default is locals/ivars/class vars.
|
||||
# Only occurs when no options or when only option is verbose
|
||||
options.merge!({
|
||||
:l => true,
|
||||
:i => true,
|
||||
:k => true
|
||||
}) if options.empty? || (options.size == 1 && options[:v]) || (options.size == 1 && options[:grep])
|
||||
|
||||
options[:grep] = // if !options[:grep]
|
||||
|
||||
|
||||
# Display public methods by default if -m or -M switch is used.
|
||||
options[:P] = true if (options[:m] || options[:M]) && !(options[:p] || options[:r] || options[:j])
|
||||
|
||||
info = {}
|
||||
target_self = target.eval('self')
|
||||
|
||||
# ensure we have a real boolean and not a `nil` (important when
|
||||
# interpolating in the string)
|
||||
options[:s] = !!options[:s]
|
||||
|
||||
# Numbers (e.g 0, 1, 2) are for ordering the hash values in Ruby 1.8
|
||||
i = -1
|
||||
|
||||
# Start collecting the entries selected by the user
|
||||
info["local variables"] = [Array(target.eval("local_variables")).sort, i += 1] if options[:l] || options[:a]
|
||||
info["instance variables"] = [Array(target.eval("instance_variables")).sort, i += 1] if options[:i] || options[:a]
|
||||
|
||||
info["class variables"] = [if target_self.is_a?(Module)
|
||||
Array(target.eval("class_variables")).sort
|
||||
else
|
||||
Array(target.eval("self.class.class_variables")).sort
|
||||
end, i += 1] if options[:k] || options[:a]
|
||||
|
||||
info["global variables"] = [Array(target.eval("global_variables")).sort, i += 1] if options[:g] || options[:a]
|
||||
|
||||
info["public methods"] = [Array(target.eval("public_methods(#{options[:s]})")).uniq.sort, i += 1] if (options[:m] && options[:P]) || options[:a]
|
||||
|
||||
info["protected methods"] = [Array(target.eval("protected_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:r]) || options[:a]
|
||||
|
||||
info["private methods"] = [Array(target.eval("private_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:p]) || options[:a]
|
||||
|
||||
info["just singleton methods"] = [Array(target.eval("methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:j]) || options[:a]
|
||||
|
||||
info["public instance methods"] = [Array(target.eval("public_instance_methods(#{options[:s]})")).uniq.sort, i += 1] if target_self.is_a?(Module) && ((options[:M] && options[:P]) || options[:a])
|
||||
|
||||
info["protected instance methods"] = [Array(target.eval("protected_instance_methods(#{options[:s]})")).uniq.sort, i += 1] if target_self.is_a?(Module) && ((options[:M] && options[:r]) || options[:a])
|
||||
|
||||
info["private instance methods"] = [Array(target.eval("private_instance_methods(#{options[:s]})")).uniq.sort, i += 1] if target_self.is_a?(Module) && ((options[:M] && options[:p]) || options[:a])
|
||||
|
||||
# dealing with 1.8/1.9 compatibility issues :/
|
||||
csuper = options[:s]
|
||||
if Module.method(:constants).arity == 0
|
||||
csuper = nil
|
||||
end
|
||||
|
||||
info["constants"] = [Array(target_self.is_a?(Module) ? target.eval("constants(#{csuper})") :
|
||||
target.eval("self.class.constants(#{csuper})")).uniq.sort, i += 1] if options[:c] || options[:a]
|
||||
|
||||
text = ""
|
||||
|
||||
# verbose output?
|
||||
if options[:v]
|
||||
# verbose
|
||||
|
||||
info.sort_by { |k, v| v.last }.each do |k, v|
|
||||
if !v.first.empty?
|
||||
text << "#{k}:\n--\n"
|
||||
filtered_list = v.first.grep options[:grep]
|
||||
if Pry.color
|
||||
text << CodeRay.scan(Pry.view(filtered_list), :ruby).term + "\n"
|
||||
else
|
||||
text << Pry.view(filtered_list) + "\n"
|
||||
end
|
||||
text << "\n\n"
|
||||
end
|
||||
end
|
||||
|
||||
if !options[:f]
|
||||
stagger_output(text)
|
||||
else
|
||||
output.puts text
|
||||
end
|
||||
|
||||
# plain
|
||||
else
|
||||
list = info.values.sort_by(&:last).map(&:first).inject(&:+)
|
||||
list = list.grep(options[:grep]) if list
|
||||
list.uniq! if list
|
||||
if Pry.color
|
||||
text << CodeRay.scan(Pry.view(list), :ruby).term + "\n"
|
||||
else
|
||||
text << Pry.view(list) + "\n"
|
||||
end
|
||||
if !options[:f]
|
||||
stagger_output(text)
|
||||
else
|
||||
output.puts text
|
||||
end
|
||||
list
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
81
lib/pry/default_commands/shell.rb
Normal file
81
lib/pry/default_commands/shell.rb
Normal file
|
@ -0,0 +1,81 @@
|
|||
class Pry
|
||||
module DefaultCommands
|
||||
|
||||
Shell = Pry::CommandSet.new do
|
||||
|
||||
command /\.(.*)/, "All text following a '.' is forwarded to the shell.", :listing => ".<shell command>" do |cmd|
|
||||
if cmd =~ /^cd\s+(.+)/i
|
||||
begin
|
||||
Dir.chdir File.expand_path($1)
|
||||
rescue Errno::ENOENT
|
||||
output.puts "No such directory: #{dest}"
|
||||
end
|
||||
|
||||
else
|
||||
if !system(cmd)
|
||||
output.puts "Error: there was a problem executing system command: #{cmd}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
command "shell-mode", "Toggle shell mode. Bring in pwd prompt and file completion." do
|
||||
case Pry.active_instance.prompt
|
||||
when Pry::SHELL_PROMPT
|
||||
Pry.active_instance.pop_prompt
|
||||
Pry.active_instance.custom_completions = Pry::DEFAULT_CUSTOM_COMPLETIONS
|
||||
else
|
||||
Pry.active_instance.push_prompt Pry::SHELL_PROMPT
|
||||
Pry.active_instance.custom_completions = Pry::FILE_COMPLETIONS
|
||||
Readline.completion_proc = Pry::InputCompleter.build_completion_proc target,
|
||||
Pry.active_instance.instance_eval(&Pry::FILE_COMPLETIONS)
|
||||
end
|
||||
end
|
||||
|
||||
alias_command "file-mode", "shell-mode", ""
|
||||
|
||||
command "cat", "Show output of file FILE. Type `cat --help` for more information." do |*args|
|
||||
start_line = 0
|
||||
end_line = -1
|
||||
|
||||
opts = Slop.parse!(args) do |opt|
|
||||
opt.on :s, :start, "Start line (defaults to start of file)Line 1 is the first line.", true, :as => Integer do |line|
|
||||
start_line = line - 1
|
||||
end
|
||||
|
||||
opt.on :e, :end, "End line (defaults to end of file). Line -1 is the last line", true, :as => Integer do |line|
|
||||
end_line = line - 1
|
||||
end
|
||||
|
||||
opt.on :l, "line-numbers", "Show line numbers."
|
||||
opt.on :t, :type, "The specific file type for syntax higlighting (e.g ruby, python)", true, :as => Symbol
|
||||
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
||||
opt.on :h, :help, "This message." do
|
||||
output.puts opt
|
||||
end
|
||||
end
|
||||
|
||||
next if opts.help?
|
||||
|
||||
file_name = args.shift
|
||||
if !file_name
|
||||
output.puts "Must provide a file name."
|
||||
next
|
||||
end
|
||||
|
||||
contents, normalized_start_line, _ = read_between_the_lines(file_name, start_line, end_line)
|
||||
|
||||
if Pry.color
|
||||
contents = syntax_highlight_by_file_type_or_specified(contents, file_name, opts[:type])
|
||||
end
|
||||
|
||||
set_file_and_dir_locals(file_name)
|
||||
render_output(opts.flood?, opts.l? ? normalized_start_line + 1 : false, contents)
|
||||
contents
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
48
lib/pry/extended_commands/experimental.rb
Normal file
48
lib/pry/extended_commands/experimental.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
class Pry
|
||||
module ExtendedCommands
|
||||
|
||||
Experimental = Pry::CommandSet.new do
|
||||
|
||||
|
||||
command "reload-method", "Reload the source specifically for a method", :requires_gem => "method_reload" do |meth_name|
|
||||
if (meth = get_method_object(meth_name, target, {})).nil?
|
||||
output.puts "Invalid method name: #{meth_name}."
|
||||
next
|
||||
end
|
||||
|
||||
meth.reload
|
||||
end
|
||||
|
||||
command "play", "Play a string as input" do |*args|
|
||||
Slop.parse!(args) do |opt|
|
||||
opt.banner "Usage: play-method [--replay START..END] [--clear] [--grep PATTERN] [--help]\n"
|
||||
|
||||
opt.on :l, :lines, 'The line (or range of lines) to replay.', true, :as => Range
|
||||
opt.on :m, :method, 'Play a method.', true do |meth_name|
|
||||
if (meth = get_method_object(meth_name, target, {})).nil?
|
||||
output.puts "Invalid method name: #{meth_name}."
|
||||
next
|
||||
end
|
||||
code, code_type = code_and_code_type_for(meth)
|
||||
next if !code
|
||||
|
||||
range = opt.l? ? opt[:l] : (0..-1)
|
||||
|
||||
Pry.active_instance.input = StringIO.new(code[range])
|
||||
end
|
||||
|
||||
opt.on :f, "file", 'The line (or range of lines) to replay.', true do |file_name|
|
||||
text = File.read File.expand_path(file_name)
|
||||
range = opt.l? ? opt[:l] : (0..-1)
|
||||
|
||||
Pry.active_instance.input = StringIO.new(text[range])
|
||||
end
|
||||
|
||||
opt.on :h, :help, "This message." do
|
||||
output.puts opt
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
22
lib/pry/extended_commands/user_command_api.rb
Normal file
22
lib/pry/extended_commands/user_command_api.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
class Pry
|
||||
module ExtendedCommands
|
||||
|
||||
UserCommandAPI = Pry::CommandSet.new do
|
||||
|
||||
command "define-command", "To honor Mon-Ouie" do |arg|
|
||||
next output.puts("Provide an arg!") if arg.nil?
|
||||
|
||||
prime_string = "command #{arg_string}\n"
|
||||
command_string = Pry.active_instance.r(target, prime_string)
|
||||
|
||||
eval_string.replace <<-HERE
|
||||
_pry_.commands.instance_eval do
|
||||
#{command_string}
|
||||
end
|
||||
HERE
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,2 +1,3 @@
|
|||
require "pry/helpers/base_helpers"
|
||||
require "pry/helpers/command_helpers"
|
||||
require "pry/helpers/text"
|
||||
|
|
|
@ -2,9 +2,26 @@ class Pry
|
|||
module Helpers
|
||||
|
||||
module BaseHelpers
|
||||
module_function
|
||||
module_function
|
||||
|
||||
def gem_installed?(gem_name)
|
||||
def silence_warnings
|
||||
old_verbose = $VERBOSE
|
||||
$VERBOSE = nil
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
$VERBOSE = old_verbose
|
||||
end
|
||||
end
|
||||
|
||||
def find_command(name)
|
||||
command_match = commands.find { |_, command| command.options[:listing] == name }
|
||||
|
||||
return command_match.last if command_match
|
||||
nil
|
||||
end
|
||||
|
||||
def gem_installed?(gem_name)
|
||||
require 'rubygems'
|
||||
Gem::Specification.respond_to?(:find_all_by_name) ? !Gem::Specification.find_all_by_name(gem_name).empty? : Gem.source_index.find_name(gem_name).first
|
||||
end
|
||||
|
@ -16,12 +33,22 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
def set_file_and_dir_locals(file_name)
|
||||
return if !target
|
||||
$_file_temp = File.expand_path(file_name)
|
||||
$_dir_temp = File.dirname($_file_temp)
|
||||
target.eval("_file_ = $_file_temp")
|
||||
target.eval("_dir_ = $_dir_temp")
|
||||
end
|
||||
|
||||
def stub_proc(name, options)
|
||||
gems_needed = Array(options[:requires_gem])
|
||||
gems_not_installed = gems_needed.select { |g| !gem_installed?(g) }
|
||||
proc do
|
||||
output.puts "\n#{name} requires the following gems to be installed: #{(gems_needed.join(", "))}"
|
||||
output.puts "\nThe command '#{name}' requires the following gems to be installed: #{(gems_needed.join(", "))}"
|
||||
output.puts "-"
|
||||
output.puts "Command not available due to dependency on gems: `#{gems_not_installed.join(", ")}` not being met."
|
||||
output.puts "-"
|
||||
output.puts "Type `install #{name}` to install the required gems and activate this command."
|
||||
end
|
||||
end
|
||||
|
@ -36,103 +63,6 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Color helpers:
|
||||
# gray, red, green, yellow, blue, purple, cyan, white,
|
||||
# and bright_red, bright_green, etc...
|
||||
#
|
||||
# ANSI color codes:
|
||||
# \033 => escape
|
||||
# 30 => color base
|
||||
# 1 => bright
|
||||
# 0 => normal
|
||||
#
|
||||
|
||||
COLORS = {
|
||||
"black" => 0,
|
||||
"red" => 1,
|
||||
"green" => 2,
|
||||
"yellow" => 3,
|
||||
"blue" => 4,
|
||||
"purple" => 5,
|
||||
"magenta" => 5,
|
||||
"cyan" => 6,
|
||||
"white" => 7
|
||||
}
|
||||
|
||||
COLORS.each do |color, i|
|
||||
define_method color do |str|
|
||||
Pry.color ? "\033[0;#{30+i}m#{str}\033[0m" : str
|
||||
end
|
||||
|
||||
define_method "bright_#{color}" do |str|
|
||||
Pry.color ? "\033[1;#{30+i}m#{str}\033[0m" : str
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :grey, :bright_black
|
||||
alias_method :gray, :bright_black
|
||||
|
||||
require 'set'
|
||||
VALID_COLORS = Set.new(
|
||||
COLORS.keys +
|
||||
COLORS.keys.map{|k| "bright_#{k}" } +
|
||||
["grey", "gray"]
|
||||
)
|
||||
|
||||
def bold(text)
|
||||
Pry.color ? "\e[1m#{text}\e[0m" : text
|
||||
end
|
||||
|
||||
#
|
||||
# Colorize a string that has "color tags".
|
||||
#
|
||||
# Examples:
|
||||
# puts colorize("<light_green><magenta>*</magenta> Hey mom! I am <light_blue>SO</light_blue> colored right now.</light_green>")
|
||||
#
|
||||
def colorize(string)
|
||||
stack = []
|
||||
|
||||
# split the string into tags and literal strings
|
||||
tokens = string.split(/(<\/?[\w\d_]+>)/)
|
||||
tokens.delete_if { |token| token.size == 0 }
|
||||
|
||||
result = ""
|
||||
|
||||
tokens.each do |token|
|
||||
|
||||
# token is an opening tag!
|
||||
|
||||
if /<([\w\d_]+)>/ =~ token and VALID_COLORS.include?($1) #valid_tag?($1)
|
||||
stack.push $1
|
||||
|
||||
# token is a closing tag!
|
||||
|
||||
elsif /<\/([\w\d_]+)>/ =~ token and VALID_COLORS.include?($1) # valid_tag?($1)
|
||||
|
||||
# if this color is on the stack somwehere...
|
||||
if pos = stack.rindex($1)
|
||||
# close the tag by removing it from the stack
|
||||
stack.delete_at pos
|
||||
else
|
||||
raise "Error: tried to close an unopened color tag -- #{token}"
|
||||
end
|
||||
|
||||
# token is a literal string!
|
||||
|
||||
else
|
||||
|
||||
color = (stack.last || "white")
|
||||
#color = BBS_COLOR_TABLE[color.to_i] if color =~ /^\d+$/
|
||||
result << send(color, token) # colorize the result
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def highlight(string, regexp, highlight_color=:bright_yellow)
|
||||
highlighted = string.gsub(regexp) { |match| "<#{highlight_color}>#{match}</#{highlight_color}>" }
|
||||
end
|
||||
|
|
|
@ -23,31 +23,10 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
def set_file_and_dir_locals(file_name)
|
||||
return if !target
|
||||
$_file_temp = File.expand_path(file_name)
|
||||
$_dir_temp = File.dirname($_file_temp)
|
||||
target.eval("_file_ = $_file_temp")
|
||||
target.eval("_dir_ = $_dir_temp")
|
||||
end
|
||||
|
||||
def add_line_numbers(lines, start_line)
|
||||
line_array = lines.each_line.to_a
|
||||
line_array.each_with_index.map do |line, idx|
|
||||
adjusted_index = idx + start_line
|
||||
if Pry.color
|
||||
cindex = CodeRay.scan("#{adjusted_index}", :ruby).term
|
||||
"#{cindex}: #{line}"
|
||||
else
|
||||
"#{idx}: #{line}"
|
||||
end
|
||||
end.join
|
||||
end
|
||||
|
||||
# if start_line is not false then add line numbers starting with start_line
|
||||
def render_output(should_flood, start_line, doc)
|
||||
if start_line
|
||||
doc = add_line_numbers(doc, start_line)
|
||||
doc = Pry::Helpers::Text.with_line_numbers doc, start_line
|
||||
end
|
||||
|
||||
if should_flood
|
||||
|
@ -57,52 +36,18 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
def editor_with_start_line(line_number)
|
||||
case Pry.editor
|
||||
when /^[gm]?vi/, /^emacs/, /^nano/, /^pico/, /^gedit/, /^kate/
|
||||
"#{Pry.editor} +#{line_number}"
|
||||
when /^mate/
|
||||
"#{Pry.editor} -l#{line_number}"
|
||||
else
|
||||
if RUBY_PLATFORM =~ /mswin|mingw/
|
||||
Pry.editor
|
||||
else
|
||||
"#{Pry.editor} +#{line_number}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def is_a_dynamically_defined_method?(meth)
|
||||
file, _ = meth.source_location
|
||||
!!(file =~ /(\(.*\))|<.*>/)
|
||||
end
|
||||
|
||||
def check_for_dynamically_defined_method(meth)
|
||||
if is_a_dynamically_defined_method?(meth)
|
||||
raise "Cannot retrieve source for dynamically defined method."
|
||||
end
|
||||
end
|
||||
|
||||
def check_for_dynamically_defined_method(meth)
|
||||
file, _ = meth.source_location
|
||||
if file =~ /(\(.*\))|<.*>/
|
||||
if file =~ /(\(.*\))|<.*>/ && file != Pry.eval_path
|
||||
raise "Cannot retrieve source for dynamically defined method."
|
||||
end
|
||||
end
|
||||
|
||||
def remove_first_word(text)
|
||||
text.split.drop(1).join(' ')
|
||||
end
|
||||
|
||||
# turn off color for duration of block
|
||||
def no_color(&block)
|
||||
old_color_state = Pry.color
|
||||
Pry.color = false
|
||||
yield
|
||||
ensure
|
||||
Pry.color = old_color_state
|
||||
end
|
||||
|
||||
def code_and_code_type_for(meth)
|
||||
case code_type = code_type_for(meth)
|
||||
when nil
|
||||
|
@ -111,7 +56,14 @@ class Pry
|
|||
code = Pry::MethodInfo.info_for(meth).source
|
||||
code = strip_comments_from_c_code(code)
|
||||
when :ruby
|
||||
code = strip_leading_whitespace(meth.source)
|
||||
if meth.source_location.first == Pry.eval_path
|
||||
|
||||
start_line = meth.source_location.last
|
||||
p = Pry.new(:input => StringIO.new(Pry.line_buffer[start_line..-1].join)).r(target)
|
||||
code = strip_leading_whitespace(p)
|
||||
else
|
||||
code = strip_leading_whitespace(meth.source)
|
||||
end
|
||||
set_file_and_dir_locals(meth.source_location.first)
|
||||
end
|
||||
|
||||
|
@ -134,36 +86,48 @@ class Pry
|
|||
end
|
||||
|
||||
def get_method_object(meth_name, target, options)
|
||||
if meth_name
|
||||
if meth_name =~ /(\S+)\#(\S+)\Z/
|
||||
context, meth_name = $1, $2
|
||||
target = Pry.binding_for(target.eval(context))
|
||||
options["instance-methods"] = true
|
||||
options[:methods] = false
|
||||
elsif meth_name =~ /(\S+)\.(\S+)\Z/
|
||||
context, meth_name = $1, $2
|
||||
target = Pry.binding_for(target.eval(context))
|
||||
options["instance-methods"] = false
|
||||
options[:methods] = true
|
||||
end
|
||||
else
|
||||
meth_name = meth_name_from_binding(target)
|
||||
end
|
||||
|
||||
if !meth_name
|
||||
return nil
|
||||
end
|
||||
|
||||
if options[:M]
|
||||
target.eval("instance_method(:#{meth_name})")
|
||||
elsif options[:m]
|
||||
target.eval("method(:#{meth_name})")
|
||||
if options["instance-methods"]
|
||||
target.eval("instance_method(:#{meth_name})") rescue nil
|
||||
elsif options[:methods]
|
||||
target.eval("method(:#{meth_name})") rescue nil
|
||||
else
|
||||
begin
|
||||
target.eval("instance_method(:#{meth_name})")
|
||||
rescue
|
||||
begin
|
||||
target.eval("method(:#{meth_name})")
|
||||
rescue
|
||||
return nil
|
||||
end
|
||||
target.eval("method(:#{meth_name})") rescue nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_header(meth, code_type, content)
|
||||
num_lines = "Number of lines: #{bold(content.each_line.count.to_s)}"
|
||||
num_lines = "Number of lines: #{Pry::Helpers::Text.bold(content.each_line.count.to_s)}"
|
||||
case code_type
|
||||
when :ruby
|
||||
file, line = meth.source_location
|
||||
"\n#{bold('From:')} #{file} @ line #{line}:\n#{num_lines}\n\n"
|
||||
"\n#{Pry::Helpers::Text.bold('From:')} #{file} @ line #{line}:\n#{num_lines}\n\n"
|
||||
else
|
||||
file = Pry::MethodInfo.info_for(meth).file
|
||||
"\n#{bold('From:')} #{file} in Ruby Core (C Method):\n#{num_lines}\n\n"
|
||||
"\n#{Pry::Helpers::Text.bold('From:')} #{file} in Ruby Core (C Method):\n#{num_lines}\n\n"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -172,7 +136,7 @@ class Pry
|
|||
end
|
||||
|
||||
def should_use_pry_doc?(meth)
|
||||
Pry.has_pry_doc && is_a_c_method?(meth)
|
||||
Pry.config.has_pry_doc && is_a_c_method?(meth)
|
||||
end
|
||||
|
||||
def code_type_for(meth)
|
||||
|
@ -243,16 +207,11 @@ class Pry
|
|||
normalized_line_number(end_line, lines_array.size)]
|
||||
end
|
||||
|
||||
# documentation related helpers
|
||||
def strip_color_codes(str)
|
||||
str.gsub(/\e\[.*?(\d)+m/, '')
|
||||
end
|
||||
|
||||
def process_rdoc(comment, code_type)
|
||||
comment = comment.dup
|
||||
comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
|
||||
gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
|
||||
gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[34m#{$1}\e[0m" : $1 }.
|
||||
gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[1m#{$1}\e[0m": $1 }.
|
||||
gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[1m#{$1}\e[0m" : $1 }.
|
||||
gsub(/\B\+(\w*?)\+\B/) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
|
||||
gsub(/((?:^[ \t]+.+(?:\n+|\Z))+)/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
|
||||
gsub(/`(?:\s*\n)?(.*?)\s*`/) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }
|
||||
|
@ -262,7 +221,7 @@ class Pry
|
|||
in_tag_block = nil
|
||||
output = comment.lines.map do |v|
|
||||
if in_tag_block && v !~ /^\S/
|
||||
strip_color_codes(strip_color_codes(v))
|
||||
Pry::Helpers::Text.strip_color Pry::Helpers::Text.strip_color(v)
|
||||
elsif in_tag_block
|
||||
in_tag_block = false
|
||||
v
|
||||
|
@ -299,7 +258,7 @@ class Pry
|
|||
end
|
||||
|
||||
def strip_comments_from_c_code(code)
|
||||
code.sub /\A\s*\/\*.*?\*\/\s*/m, ''
|
||||
code.sub(/\A\s*\/\*.*?\*\/\s*/m, '')
|
||||
end
|
||||
|
||||
def prompt(message, options="Yn")
|
||||
|
|
83
lib/pry/helpers/text.rb
Normal file
83
lib/pry/helpers/text.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
class Pry
|
||||
module Helpers
|
||||
|
||||
# The methods defined on {Text} are available to custom commands via {Pry::CommandContext#text}.
|
||||
module Text
|
||||
|
||||
COLORS =
|
||||
{
|
||||
"black" => 0,
|
||||
"red" => 1,
|
||||
"green" => 2,
|
||||
"yellow" => 3,
|
||||
"blue" => 4,
|
||||
"purple" => 5,
|
||||
"magenta" => 5,
|
||||
"cyan" => 6,
|
||||
"white" => 7
|
||||
}
|
||||
|
||||
class << self
|
||||
|
||||
COLORS.each_pair do |color, value|
|
||||
define_method color do |text|
|
||||
Pry.color ? "\033[0;#{30+value}m#{text}\033[0m" : text.to_s
|
||||
end
|
||||
|
||||
define_method "bright_#{color}" do |text|
|
||||
Pry.color ? "\033[1;#{30+value}m#{text}\033[0m" : text.to_s
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :grey, :bright_black
|
||||
alias_method :gray, :bright_black
|
||||
|
||||
|
||||
# Remove any color codes from _text_.
|
||||
#
|
||||
# @param [String, #to_s] text
|
||||
# @return [String] _text_ stripped of any color codes.
|
||||
def strip_color text
|
||||
text.to_s.gsub(/\e\[.*?(\d)+m/ , '')
|
||||
end
|
||||
|
||||
# Returns _text_ as bold text for use on a terminal.
|
||||
# _Pry.color_ must be true for this method to perform any transformations.
|
||||
#
|
||||
# @param [String, #to_s] text
|
||||
# @return [String] _text_
|
||||
def bold text
|
||||
Pry.color ? "\e[1m#{text}\e[0m" : text.to_s
|
||||
end
|
||||
|
||||
# Executes _block_ with _Pry.color_ set to false.
|
||||
#
|
||||
# @param [Proc]
|
||||
# @return [void]
|
||||
def no_color &block
|
||||
boolean = Pry.color
|
||||
Pry.color = false
|
||||
yield
|
||||
ensure
|
||||
Pry.color = boolean
|
||||
end
|
||||
|
||||
# Returns _text_ in a numbered list, beginning at _offset_.
|
||||
#
|
||||
# @param [#each_line] text
|
||||
# @param [Fixnum] offset
|
||||
# @return [String]
|
||||
def with_line_numbers text, offset
|
||||
lines = text.each_line.to_a
|
||||
lines.each_with_index.map do |line, index|
|
||||
adjusted_index = index + offset
|
||||
"#{self.blue adjusted_index}: #{line}"
|
||||
end.join
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
class Pry
|
||||
|
||||
# The default hooks - display messages when beginning and ending Pry sessions.
|
||||
DEFAULT_HOOKS = {
|
||||
|
||||
:before_session => proc do |out, target|
|
||||
# ensure we're actually in a method
|
||||
meth_name = target.eval('__method__')
|
||||
file = target.eval('__FILE__')
|
||||
|
||||
# /unknown/ for rbx
|
||||
if file !~ /(\(.*\))|<.*>/ && file !~ /__unknown__/ && file != "" && file != "-e"
|
||||
Pry.run_command "whereami 5", :output => out, :show_output => true, :context => target, :commands => Pry::Commands
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
79
lib/pry/plugins.rb
Normal file
79
lib/pry/plugins.rb
Normal file
|
@ -0,0 +1,79 @@
|
|||
class Pry
|
||||
class PluginManager
|
||||
|
||||
PRY_PLUGIN_PREFIX = /^pry-/
|
||||
|
||||
PluginNotFound = Class.new(LoadError)
|
||||
|
||||
class Plugin
|
||||
attr_accessor :name, :gem_name, :enabled, :active
|
||||
|
||||
def initialize(name, gem_name, enabled)
|
||||
@name, @gem_name, @enabled = name, gem_name, enabled
|
||||
end
|
||||
|
||||
# Disable a plugin.
|
||||
def disable!
|
||||
self.enabled = false
|
||||
end
|
||||
|
||||
# Enable a plugin.
|
||||
def enable!
|
||||
self.enabled = true
|
||||
end
|
||||
|
||||
# Activate the plugin (require the gem).
|
||||
def activate!
|
||||
begin
|
||||
require gem_name
|
||||
rescue LoadError
|
||||
raise PluginNotFound, "The plugin '#{gem_name}' was not found!"
|
||||
end
|
||||
self.active = true
|
||||
self.enabled = true
|
||||
end
|
||||
|
||||
alias active? active
|
||||
alias enabled? enabled
|
||||
end
|
||||
|
||||
def initialize
|
||||
@plugins = []
|
||||
end
|
||||
|
||||
# Find all installed Pry plugins and store them in an internal array.
|
||||
def locate_plugins
|
||||
Gem.refresh
|
||||
Gem.source_index.find_name('').each do |gem|
|
||||
next if gem.name !~ PRY_PLUGIN_PREFIX
|
||||
plugin_name = gem.name.split('-', 2).last
|
||||
@plugins << Plugin.new(plugin_name, gem.name, true) if !gem_located?(gem.name)
|
||||
end
|
||||
@plugins
|
||||
end
|
||||
|
||||
# @return [Hash] A hash with all plugin names (minus the 'pry-') as
|
||||
# keys and Plugin objects as values.
|
||||
def plugins
|
||||
h = {}
|
||||
@plugins.each do |plugin|
|
||||
h[plugin.name] = plugin
|
||||
end
|
||||
h
|
||||
end
|
||||
|
||||
# Require all enabled plugins, disabled plugins are skipped.
|
||||
def load_plugins
|
||||
@plugins.each do |plugin|
|
||||
plugin.activate! if plugin.enabled?
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def gem_located?(gem_name)
|
||||
@plugins.any? { |plugin| plugin.gem_name == gem_name }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
class Pry
|
||||
DEFAULT_PRINT = proc do |output, value|
|
||||
if Pry.color
|
||||
output.puts "=> #{CodeRay.scan(Pry.view(value), :ruby).term}"
|
||||
else
|
||||
output.puts "=> #{Pry.view(value)}"
|
||||
end
|
||||
end
|
||||
|
||||
# Will only show the first line of the backtrace
|
||||
DEFAULT_EXCEPTION_HANDLER = proc do |output, exception|
|
||||
output.puts "#{exception.class}: #{exception.message}"
|
||||
output.puts "from #{exception.backtrace.first}"
|
||||
end
|
||||
end
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
class Pry
|
||||
|
||||
|
||||
# The default prompt; includes the target and nesting level
|
||||
DEFAULT_PROMPT = [
|
||||
proc do |target_self, nest_level|
|
||||
|
||||
if nest_level == 0
|
||||
"pry(#{Pry.view_clip(target_self)})> "
|
||||
else
|
||||
"pry(#{Pry.view_clip(target_self)}):#{Pry.view_clip(nest_level)}> "
|
||||
end
|
||||
end,
|
||||
|
||||
proc do |target_self, nest_level|
|
||||
if nest_level == 0
|
||||
"pry(#{Pry.view_clip(target_self)})* "
|
||||
else
|
||||
"pry(#{Pry.view_clip(target_self)}):#{Pry.view_clip(nest_level)}* "
|
||||
end
|
||||
end
|
||||
]
|
||||
|
||||
# A simple prompt - doesn't display target or nesting level
|
||||
SIMPLE_PROMPT = [proc { ">> " }, proc { ">* " }]
|
||||
|
||||
SHELL_PROMPT = [
|
||||
proc { |target_self, _| "pry #{Pry.view_clip(target_self)}:#{Dir.pwd} $ " },
|
||||
proc { |target_self, _| "pry #{Pry.view_clip(target_self)}:#{Dir.pwd} * " }
|
||||
]
|
||||
end
|
|
@ -1,3 +1,7 @@
|
|||
require 'ostruct'
|
||||
require 'forwardable'
|
||||
require 'pry/config'
|
||||
|
||||
# @author John Mair (banisterfiend)
|
||||
class Pry
|
||||
|
||||
|
@ -6,6 +10,13 @@ class Pry
|
|||
|
||||
# class accessors
|
||||
class << self
|
||||
extend Forwardable
|
||||
|
||||
# convenience method
|
||||
def self.delegate_accessors(delagatee, *names)
|
||||
def_delegators delagatee, *names
|
||||
def_delegators delagatee, *names.map { |v| "#{v}=" }
|
||||
end
|
||||
|
||||
# Get nesting data.
|
||||
# This method should not need to be accessed directly.
|
||||
|
@ -27,41 +38,6 @@ class Pry
|
|||
# @return [Pry] The active Pry instance.
|
||||
attr_accessor :active_instance
|
||||
|
||||
# Get/Set the object to use for input by default by all Pry instances.
|
||||
# @return [#readline] The object to use for input by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :input
|
||||
|
||||
# Get/Set the object to use for output by default by all Pry instances.
|
||||
# @return [#puts] The object to use for output by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :output
|
||||
|
||||
# Get/Set the object to use for commands by default by all Pry instances.
|
||||
# @return [Pry::CommandBase] The object to use for commands by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :commands
|
||||
|
||||
# Get/Set the Proc to use for printing by default by all Pry
|
||||
# instances.
|
||||
# This is the 'print' component of the REPL.
|
||||
# @return [Proc] The Proc to use for printing by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :print
|
||||
|
||||
# @return [Proc] The Proc to use for printing exceptions by default by all
|
||||
# Pry instances.
|
||||
attr_accessor :exception_handler
|
||||
|
||||
# Get/Set the Hash that defines Pry hooks used by default by all Pry
|
||||
# instances.
|
||||
# @return [Hash] The hooks used by default by all Pry instances.
|
||||
# @example
|
||||
# Pry.hooks :before_session => proc { puts "hello" },
|
||||
# :after_session => proc { puts "goodbye" }
|
||||
attr_accessor :hooks
|
||||
|
||||
|
||||
# Get/Set the Proc that defines extra Readline completions (on top
|
||||
# of the ones defined for IRB).
|
||||
# @return [Proc] The Proc that defines extra Readline completions (on top
|
||||
|
@ -69,40 +45,31 @@ class Pry
|
|||
# Pry.custom_completions = proc { Dir.entries('.') }
|
||||
attr_accessor :custom_completions
|
||||
|
||||
# Get the array of Procs to be used for the prompts by default by
|
||||
# all Pry instances.
|
||||
# @return [Array<Proc>] The array of Procs to be used for the
|
||||
# prompts by default by all Pry instances.
|
||||
attr_accessor :prompt
|
||||
|
||||
# Value returned by last executed Pry command.
|
||||
# @return [Object] The command value
|
||||
attr_accessor :cmd_ret_value
|
||||
|
||||
# Determines whether colored output is enabled.
|
||||
# @return [Boolean]
|
||||
attr_accessor :color
|
||||
# @return [Fixnum] The current input line.
|
||||
attr_accessor :current_line
|
||||
|
||||
# Determines whether paging (of long blocks of text) is enabled.
|
||||
# @return [Boolean]
|
||||
attr_accessor :pager
|
||||
# @return [Array] The Array of evaluated expressions.
|
||||
attr_accessor :line_buffer
|
||||
|
||||
# Determines whether the rc file (~/.pryrc) should be loaded.
|
||||
# @return [Boolean]
|
||||
attr_accessor :should_load_rc
|
||||
# @return [String] The __FILE__ for the `eval()`. Should be "(pry)"
|
||||
# by default.
|
||||
attr_accessor :eval_path
|
||||
|
||||
# Set to true if Pry is invoked from command line using `pry` executable
|
||||
# @return [Boolean]
|
||||
# @return [OpenStruct] Return Pry's config object.
|
||||
attr_accessor :config
|
||||
|
||||
# @return [Boolean] Whether Pry was activated from the command line.
|
||||
attr_accessor :cli
|
||||
|
||||
# Set to true if the pry-doc extension is loaded.
|
||||
# @return [Boolean]
|
||||
attr_accessor :has_pry_doc
|
||||
# plugin forwardables
|
||||
def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins
|
||||
|
||||
# The default editor to use. Defaults to $EDITOR or nano if
|
||||
# $EDITOR is not defined.
|
||||
# @return [String]
|
||||
attr_accessor :editor
|
||||
delegate_accessors :@config, :input, :output, :commands, :prompt, :print, :exception_handler,
|
||||
:hooks, :color, :pager, :editor
|
||||
end
|
||||
|
||||
# Load the rc files given in the `Pry::RC_FILES` array.
|
||||
|
@ -124,9 +91,15 @@ class Pry
|
|||
# @example
|
||||
# Pry.start(Object.new, :input => MyInput.new)
|
||||
def self.start(target=TOPLEVEL_BINDING, options={})
|
||||
if should_load_rc && !@rc_loaded
|
||||
load_rc
|
||||
@rc_loaded = true
|
||||
if initial_session?
|
||||
# note these have to be loaded here rather than in pry_instance as
|
||||
# we only want them loaded once per entire Pry lifetime, not
|
||||
# multiple times per each new session (i.e in debugging)
|
||||
load_rc if Pry.config.should_load_rc
|
||||
load_plugins if Pry.config.should_load_plugins
|
||||
load_history if Pry.config.history.load
|
||||
|
||||
@initial_session = false
|
||||
end
|
||||
|
||||
new(options).repl(target)
|
||||
|
@ -137,12 +110,7 @@ class Pry
|
|||
# @param obj The object to view.
|
||||
# @return [String] The string representation of `obj`.
|
||||
def self.view(obj)
|
||||
case obj
|
||||
when String, Hash, Array, Symbol, Exception, nil
|
||||
obj.inspect
|
||||
else
|
||||
obj.to_s
|
||||
end
|
||||
obj.inspect
|
||||
|
||||
rescue NoMethodError
|
||||
"unknown"
|
||||
|
@ -161,10 +129,20 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
# Load Readline history if required.
|
||||
def self.load_history
|
||||
history_file = File.expand_path(Pry.config.history.file)
|
||||
Readline::HISTORY.push(*File.readlines(history_file).map(&:chomp)) if File.exists?(history_file)
|
||||
end
|
||||
|
||||
# @return [Boolean] Whether this is the first time a Pry session has
|
||||
# been started since loading the Pry class.
|
||||
def self.initial_session?
|
||||
@initial_session
|
||||
end
|
||||
|
||||
# Run a Pry command from outside a session. The commands available are
|
||||
# those referenced by `Pry.commands` (the default command set).
|
||||
# Command output is suppresed by default, this is because the return
|
||||
# value (if there is one) is likely to be more useful.
|
||||
# @param [String] arg_string The Pry command (including arguments,
|
||||
# if any).
|
||||
# @param [Hash] options Optional named parameters.
|
||||
|
@ -172,35 +150,24 @@ class Pry
|
|||
# @option options [Object, Binding] :context The object context to run the
|
||||
# command under. Defaults to `TOPLEVEL_BINDING` (main).
|
||||
# @option options [Boolean] :show_output Whether to show command
|
||||
# output. Defaults to false.
|
||||
# output. Defaults to true.
|
||||
# @example Run at top-level with no output.
|
||||
# Pry.run_command "ls"
|
||||
# @example Run under Pry class, returning only public methods.
|
||||
# Pry.run_command "ls -m", :context => Pry
|
||||
# @example Display command output.
|
||||
# Pry.run_command "ls -av", :show_output => true
|
||||
def self.run_command(arg_string, options={})
|
||||
name, arg_string = arg_string.split(/\s+/, 2)
|
||||
arg_string = "" if !arg_string
|
||||
|
||||
def self.run_command(command_string, options={})
|
||||
options = {
|
||||
:context => TOPLEVEL_BINDING,
|
||||
:show_output => false,
|
||||
:show_output => true,
|
||||
:output => Pry.output,
|
||||
:commands => Pry.commands
|
||||
}.merge!(options)
|
||||
|
||||
null_output = StringIO.new
|
||||
output = options[:show_output] ? options[:output] : StringIO.new
|
||||
|
||||
context = CommandContext.new
|
||||
commands = options[:commands]
|
||||
|
||||
context.opts = {}
|
||||
context.output = options[:show_output] ? options[:output] : null_output
|
||||
context.target = Pry.binding_for(options[:context])
|
||||
context.command_set = commands
|
||||
|
||||
commands.run_command(context, name, *Shellwords.shellwords(arg_string))
|
||||
Pry.new(:output => output, :input => StringIO.new(command_string), :commands => options[:commands]).rep(options[:context])
|
||||
end
|
||||
|
||||
def self.default_editor_for_platform
|
||||
|
@ -211,25 +178,47 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
# Set all the configurable options back to their default values
|
||||
def self.reset_defaults
|
||||
@input = Readline
|
||||
@output = $stdout
|
||||
@commands = Pry::Commands
|
||||
@prompt = DEFAULT_PROMPT
|
||||
@print = DEFAULT_PRINT
|
||||
@exception_handler = DEFAULT_EXCEPTION_HANDLER
|
||||
@hooks = DEFAULT_HOOKS
|
||||
@custom_completions = DEFAULT_CUSTOM_COMPLETIONS
|
||||
@color = true
|
||||
@pager = true
|
||||
@should_load_rc = true
|
||||
@rc_loaded = false
|
||||
@cli = false
|
||||
@editor = default_editor_for_platform
|
||||
def self.set_config_defaults
|
||||
config.input = Readline
|
||||
config.output = $stdout
|
||||
config.commands = Pry::Commands
|
||||
config.prompt = DEFAULT_PROMPT
|
||||
config.print = DEFAULT_PRINT
|
||||
config.exception_handler = DEFAULT_EXCEPTION_HANDLER
|
||||
config.hooks = DEFAULT_HOOKS
|
||||
config.color = true
|
||||
config.pager = true
|
||||
config.editor = default_editor_for_platform
|
||||
config.should_load_rc = true
|
||||
config.should_load_plugins = true
|
||||
|
||||
config.history ||= OpenStruct.new
|
||||
config.history.save = true
|
||||
config.history.load = true
|
||||
config.history.file = File.expand_path("~/.pry_history")
|
||||
end
|
||||
|
||||
self.reset_defaults
|
||||
# Set all the configurable options back to their default values
|
||||
def self.reset_defaults
|
||||
set_config_defaults
|
||||
|
||||
@initial_session = true
|
||||
|
||||
self.custom_completions = DEFAULT_CUSTOM_COMPLETIONS
|
||||
self.cli = false
|
||||
self.current_line = 0
|
||||
self.line_buffer = []
|
||||
self.eval_path = "(pry)"
|
||||
end
|
||||
|
||||
# Basic initialization.
|
||||
def self.init
|
||||
@plugin_manager ||= PluginManager.new
|
||||
|
||||
self.config ||= Config.new
|
||||
reset_defaults
|
||||
locate_plugins
|
||||
end
|
||||
|
||||
@nesting = []
|
||||
def @nesting.level
|
||||
|
@ -260,3 +249,5 @@ class Pry
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Pry.init
|
||||
|
|
|
@ -2,12 +2,13 @@ require "pry/command_processor.rb"
|
|||
|
||||
class Pry
|
||||
|
||||
# The list of configuration options.
|
||||
CONFIG_OPTIONS = [:input, :output, :commands, :print,
|
||||
:exception_handler, :prompt, :hooks,
|
||||
:custom_completions]
|
||||
|
||||
attr_accessor *CONFIG_OPTIONS
|
||||
attr_accessor :input
|
||||
attr_accessor :output
|
||||
attr_accessor :commands
|
||||
attr_accessor :print
|
||||
attr_accessor :exception_handler
|
||||
attr_accessor :hooks
|
||||
attr_accessor :custom_completions
|
||||
|
||||
# Returns the target binding for the session. Note that altering this
|
||||
# attribute will not change the target binding.
|
||||
|
@ -24,18 +25,44 @@ class Pry
|
|||
# @option options [Proc] :print The Proc to use for the 'print'
|
||||
# component of the REPL. (see print.rb)
|
||||
def initialize(options={})
|
||||
defaults = {}
|
||||
attributes = [
|
||||
:input, :output, :commands, :print,
|
||||
:exception_handler, :hooks, :custom_completions,
|
||||
:prompt
|
||||
]
|
||||
|
||||
default_options = {}
|
||||
CONFIG_OPTIONS.each { |v| default_options[v] = Pry.send(v) }
|
||||
default_options.merge!(options)
|
||||
attributes.each do |attribute|
|
||||
defaults[attribute] = Pry.send attribute
|
||||
end
|
||||
|
||||
CONFIG_OPTIONS.each do |key|
|
||||
instance_variable_set("@#{key}", default_options[key])
|
||||
defaults.merge!(options).each_key do |key|
|
||||
send "#{key}=", defaults[key]
|
||||
end
|
||||
|
||||
@command_processor = CommandProcessor.new(self)
|
||||
end
|
||||
|
||||
# The current prompt.
|
||||
# This is the prompt at the top of the prompt stack.
|
||||
#
|
||||
# @example
|
||||
# self.prompt = Pry::SIMPLE_PROMPT
|
||||
# self.prompt # => Pry::SIMPLE_PROMPT
|
||||
#
|
||||
# @return [Array<Proc>] Current prompt.
|
||||
def prompt
|
||||
prompt_stack.last
|
||||
end
|
||||
|
||||
def prompt=(new_prompt)
|
||||
if prompt_stack.empty?
|
||||
push_prompt new_prompt
|
||||
else
|
||||
prompt_stack[-1] = new_prompt
|
||||
end
|
||||
end
|
||||
|
||||
# Get nesting data.
|
||||
# This method should not need to be accessed directly.
|
||||
# @return [Array] The unparsed nesting information.
|
||||
|
@ -50,6 +77,11 @@ class Pry
|
|||
self.class.nesting = v
|
||||
end
|
||||
|
||||
# @return [Boolean] Whether top-level session has ended.
|
||||
def finished_top_level_session?
|
||||
nesting.empty?
|
||||
end
|
||||
|
||||
# Return parent of current Pry session.
|
||||
# @return [Pry] The parent of the current Pry session.
|
||||
def parent
|
||||
|
@ -71,8 +103,8 @@ class Pry
|
|||
Pry.active_instance = self
|
||||
|
||||
# Make sure special locals exist
|
||||
target.eval("_pry_ = ::Pry.active_instance")
|
||||
target.eval("_ = ::Pry.last_result")
|
||||
set_active_instance(target)
|
||||
set_last_result(Pry.last_result, target)
|
||||
self.session_target = target
|
||||
end
|
||||
|
||||
|
@ -91,6 +123,8 @@ class Pry
|
|||
throw :breakout, break_data
|
||||
end
|
||||
|
||||
save_history if Pry.config.history.save && finished_top_level_session?
|
||||
|
||||
return_value
|
||||
end
|
||||
|
||||
|
@ -151,22 +185,19 @@ class Pry
|
|||
Readline.completion_proc = Pry::InputCompleter.build_completion_proc target, instance_eval(&custom_completions)
|
||||
end
|
||||
|
||||
# save the pry instance to active_instance
|
||||
Pry.active_instance = self
|
||||
target.eval("_pry_ = ::Pry.active_instance")
|
||||
|
||||
@last_result_is_exception = false
|
||||
set_active_instance(target)
|
||||
expr = r(target)
|
||||
|
||||
# eval the expression and save to last_result
|
||||
# Do not want __FILE__, __LINE__ here because we need to distinguish
|
||||
# (eval) methods for show-method and friends.
|
||||
# This also sets the `_` local for the session.
|
||||
set_last_result(target.eval(r(target)), target)
|
||||
Pry.line_buffer.push(*expr.each_line)
|
||||
set_last_result(target.eval(expr, Pry.eval_path, Pry.current_line), target)
|
||||
rescue SystemExit => e
|
||||
exit
|
||||
rescue Exception => e
|
||||
@last_result_is_exception = true
|
||||
set_last_exception(e, target)
|
||||
ensure
|
||||
Pry.current_line += expr.each_line.count if expr
|
||||
end
|
||||
|
||||
# Perform a read.
|
||||
|
@ -175,18 +206,19 @@ class Pry
|
|||
# Ruby expression is received.
|
||||
# Pry commands are also accepted here and operate on the target.
|
||||
# @param [Object, Binding] target The receiver of the read.
|
||||
# @param [String] eval_string Optionally Prime `eval_string` with a start value.
|
||||
# @return [String] The Ruby expression.
|
||||
# @example
|
||||
# Pry.new.r(Object.new)
|
||||
def r(target=TOPLEVEL_BINDING)
|
||||
def r(target=TOPLEVEL_BINDING, eval_string="")
|
||||
target = Pry.binding_for(target)
|
||||
@suppress_output = false
|
||||
eval_string = ""
|
||||
|
||||
val = ""
|
||||
loop do
|
||||
val = retrieve_line(eval_string, target)
|
||||
process_line(val, eval_string, target)
|
||||
|
||||
break if valid_expression?(eval_string)
|
||||
end
|
||||
|
||||
|
@ -195,7 +227,7 @@ class Pry
|
|||
eval_string
|
||||
end
|
||||
|
||||
# FIXME should delete this method? it's exposing an implementation detail!
|
||||
# Output the result or pass to an exception handler (if result is an exception).
|
||||
def show_result(result)
|
||||
if last_result_is_exception?
|
||||
exception_handler.call output, result
|
||||
|
@ -264,6 +296,14 @@ class Pry
|
|||
target.eval("_ex_ = ::Pry.last_exception")
|
||||
end
|
||||
|
||||
# Set the active instance for a session.
|
||||
# This method should not need to be invoked directly.
|
||||
# @param [Binding] target The binding to set `_ex_` on.
|
||||
def set_active_instance(target)
|
||||
Pry.active_instance = self
|
||||
target.eval("_pry_ = ::Pry.active_instance")
|
||||
end
|
||||
|
||||
# @return [Boolean] True if the last result is an exception that was raised,
|
||||
# as opposed to simply an instance of Exception (like the result of
|
||||
# Exception.new)
|
||||
|
@ -291,7 +331,7 @@ class Pry
|
|||
end
|
||||
|
||||
rescue EOFError
|
||||
self.input = Readline
|
||||
self.input = Pry.input
|
||||
""
|
||||
end
|
||||
end
|
||||
|
@ -305,6 +345,14 @@ class Pry
|
|||
!@suppress_output || last_result_is_exception?
|
||||
end
|
||||
|
||||
# Save readline history to a file.
|
||||
def save_history
|
||||
history_file = File.expand_path(Pry.config.history.file)
|
||||
File.open(history_file, 'w') do |f|
|
||||
f.write Readline::HISTORY.to_a.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the appropriate prompt to use.
|
||||
# This method should not need to be invoked directly.
|
||||
# @param [Boolean] first_line Whether this is the first line of input
|
||||
|
@ -320,6 +368,39 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
# the array that the prompt stack is stored in
|
||||
def prompt_stack
|
||||
@prompt_stack ||= Array.new
|
||||
end
|
||||
private :prompt_stack
|
||||
|
||||
# Pushes the current prompt onto a stack that it can be restored from later.
|
||||
# Use this if you wish to temporarily change the prompt.
|
||||
# @param [Array<Proc>] new_prompt
|
||||
# @return [Array<Proc>] new_prompt
|
||||
# @example
|
||||
# new_prompt = [ proc { '>' }, proc { '>>' } ]
|
||||
# push_prompt(new_prompt) # => new_prompt
|
||||
def push_prompt(new_prompt)
|
||||
prompt_stack.push new_prompt
|
||||
end
|
||||
|
||||
# Pops the current prompt off of the prompt stack.
|
||||
# If the prompt you are popping is the last prompt, it will not be popped.
|
||||
# Use this to restore the previous prompt.
|
||||
# @return [Array<Proc>] Prompt being popped.
|
||||
# @example
|
||||
# prompt1 = [ proc { '>' }, proc { '>>' } ]
|
||||
# prompt2 = [ proc { '$' }, proc { '>' } ]
|
||||
# pry = Pry.new :prompt => prompt1
|
||||
# pry.push_prompt(prompt2)
|
||||
# pry.pop_prompt # => prompt2
|
||||
# pry.pop_prompt # => prompt1
|
||||
# pry.pop_prompt # => prompt1
|
||||
def pop_prompt
|
||||
prompt_stack.size > 1 ? prompt_stack.pop : prompt
|
||||
end
|
||||
|
||||
if RUBY_VERSION =~ /1.9/ && RUBY_ENGINE == "ruby"
|
||||
require 'ripper'
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
class Pry
|
||||
VERSION = "0.8.3"
|
||||
VERSION = "0.9.0pre1"
|
||||
end
|
||||
|
|
106
test/helper.rb
Normal file
106
test/helper.rb
Normal file
|
@ -0,0 +1,106 @@
|
|||
unless Object.const_defined? 'Pry'
|
||||
$:.unshift File.expand_path '../../lib', __FILE__
|
||||
require 'pry'
|
||||
end
|
||||
|
||||
require 'bacon'
|
||||
|
||||
# Ensure we do not execute any rc files
|
||||
Pry::RC_FILES.clear
|
||||
|
||||
# in case the tests call reset_defaults, ensure we reset them to
|
||||
# amended (test friendly) values
|
||||
class << Pry
|
||||
alias_method :orig_reset_defaults, :reset_defaults
|
||||
def reset_defaults
|
||||
orig_reset_defaults
|
||||
|
||||
Pry.color = false
|
||||
Pry.pager = false
|
||||
Pry.config.should_load_rc = false
|
||||
Pry.config.history.load = false
|
||||
Pry.config.history.save = false
|
||||
end
|
||||
end
|
||||
|
||||
Pry.reset_defaults
|
||||
|
||||
# sample doc
|
||||
def sample_method
|
||||
:sample
|
||||
end
|
||||
|
||||
def redirect_pry_io(new_in, new_out)
|
||||
old_in = Pry.input
|
||||
old_out = Pry.output
|
||||
|
||||
Pry.input = new_in
|
||||
Pry.output = new_out
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
Pry.input = old_in
|
||||
Pry.output = old_out
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_global_pry_input(new_io)
|
||||
old_io = Pry.input
|
||||
Pry.input = new_io
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
Pry.input = old_io
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_global_pry_output(new_io)
|
||||
old_io = Pry.output
|
||||
Pry.output = new_io
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
Pry.output = old_io
|
||||
end
|
||||
end
|
||||
|
||||
class Module
|
||||
public :remove_const
|
||||
public :remove_method
|
||||
end
|
||||
|
||||
|
||||
class InputTester
|
||||
def initialize(*actions)
|
||||
@orig_actions = actions.dup
|
||||
@actions = actions
|
||||
end
|
||||
|
||||
def readline(*)
|
||||
@actions.shift
|
||||
end
|
||||
|
||||
def rewind
|
||||
@actions = @orig_actions.dup
|
||||
end
|
||||
end
|
||||
|
||||
class Pry
|
||||
|
||||
# null output class - doesn't write anywwhere.
|
||||
class NullOutput
|
||||
def self.puts(*) end
|
||||
def self.string(*) end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
CommandTester = Pry::CommandSet.new do
|
||||
command "command1", "command 1 test" do
|
||||
output.puts "command1"
|
||||
end
|
||||
|
||||
command "command2", "command 2 test" do |arg|
|
||||
output.puts arg
|
||||
end
|
||||
end
|
928
test/test.rb
928
test/test.rb
|
@ -1,928 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
puts "Ruby Version #{RUBY_VERSION}"
|
||||
puts "Testing Pry #{Pry::VERSION}"
|
||||
puts "With method_source version #{MethodSource::VERSION}"
|
||||
puts "--"
|
||||
|
||||
describe Pry do
|
||||
describe "open a Pry session on an object" do
|
||||
describe "rep" do
|
||||
before do
|
||||
class Hello
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
Object.send(:remove_const, :Hello)
|
||||
end
|
||||
|
||||
# bug fix for https://github.com/banister/pry/issues/93
|
||||
it 'should not leak pry constants into Object namespace' do
|
||||
input_string = "VERSION == ::Pry::VERSION"
|
||||
str_output = StringIO.new
|
||||
o = Object.new
|
||||
pry_tester = Pry.new(:input => StringIO.new(input_string),
|
||||
:output => str_output,
|
||||
:exception_handler => proc { |_, exception| @excep = exception },
|
||||
:print => proc {}
|
||||
).rep(o)
|
||||
|
||||
@excep.is_a?(NameError).should == true
|
||||
end
|
||||
|
||||
it 'should set an ivar on an object' do
|
||||
input_string = "@x = 10"
|
||||
input = InputTester.new(input_string)
|
||||
o = Object.new
|
||||
|
||||
pry_tester = Pry.new(:input => input, :output => Pry::NullOutput)
|
||||
pry_tester.rep(o)
|
||||
o.instance_variable_get(:@x).should == 10
|
||||
end
|
||||
|
||||
it 'should make self evaluate to the receiver of the rep session' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("self"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should =~ /#{o.to_s}/
|
||||
end
|
||||
|
||||
it 'should work with multi-line input' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("x = ", "1 + 4"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should =~ /5/
|
||||
end
|
||||
|
||||
it 'should define a nested class under Hello and not on top-level or Pry' do
|
||||
pry_tester = Pry.new(:input => InputTester.new("class Nested", "end"), :output => Pry::NullOutput)
|
||||
pry_tester.rep(Hello)
|
||||
Hello.const_defined?(:Nested).should == true
|
||||
end
|
||||
|
||||
it 'should suppress output if input ends in a ";" and is an Exception object (single line)' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("Exception.new;"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should == ""
|
||||
end
|
||||
|
||||
it 'should suppress output if input ends in a ";" (single line)' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("x = 5;"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should == ""
|
||||
end
|
||||
|
||||
|
||||
it 'should suppress output if input ends in a ";" (multi-line)' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("def self.blah", ":test", "end;"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should == ""
|
||||
end
|
||||
|
||||
it 'should be able to evaluate exceptions normally' do
|
||||
o = Exception.new
|
||||
str_output = StringIO.new
|
||||
|
||||
was_called = false
|
||||
pry_tester = Pry.new(:input => InputTester.new("self"),
|
||||
:output => str_output,
|
||||
:exception_handler => proc { was_called = true })
|
||||
|
||||
pry_tester.rep(o)
|
||||
was_called.should == false
|
||||
end
|
||||
|
||||
it 'should notice when exceptions are raised' do
|
||||
o = Exception.new
|
||||
str_output = StringIO.new
|
||||
|
||||
was_called = false
|
||||
pry_tester = Pry.new(:input => InputTester.new("raise self"),
|
||||
:output => str_output,
|
||||
:exception_handler => proc { was_called = true })
|
||||
|
||||
pry_tester.rep(o)
|
||||
was_called.should == true
|
||||
end
|
||||
end
|
||||
|
||||
describe "repl" do
|
||||
describe "basic functionality" do
|
||||
it 'should set an ivar on an object and exit the repl' do
|
||||
input_strings = ["@x = 10", "exit"]
|
||||
input = InputTester.new(*input_strings)
|
||||
|
||||
o = Object.new
|
||||
|
||||
pry_tester = Pry.start(o, :input => input, :output => Pry::NullOutput)
|
||||
|
||||
o.instance_variable_get(:@x).should == 10
|
||||
end
|
||||
end
|
||||
|
||||
describe "test loading rc files" do
|
||||
after do
|
||||
Pry::RC_FILES.clear
|
||||
Pry.should_load_rc = false
|
||||
end
|
||||
|
||||
it "should run the rc file only once" do
|
||||
Pry.should_load_rc = true
|
||||
Pry::RC_FILES << File.expand_path("../testrc", __FILE__)
|
||||
|
||||
Pry.start(self, :input => StringIO.new("exit\n"), :output => Pry::NullOutput)
|
||||
TEST_RC.should == [0]
|
||||
|
||||
Pry.start(self, :input => StringIO.new("exit\n"), :output => Pry::NullOutput)
|
||||
TEST_RC.should == [0]
|
||||
|
||||
Object.remove_const(:TEST_RC)
|
||||
end
|
||||
|
||||
it "should not run the rc file at all if Pry.should_load_rc is false" do
|
||||
Pry.should_load_rc = false
|
||||
Pry.start(self, :input => StringIO.new("exit\n"), :output => Pry::NullOutput)
|
||||
Object.const_defined?(:TEST_RC).should == false
|
||||
end
|
||||
|
||||
it "should not load the rc file if #repl method invoked" do
|
||||
Pry.should_load_rc = true
|
||||
Pry.new(:input => StringIO.new("exit\n"), :output => Pry::NullOutput).repl(self)
|
||||
Object.const_defined?(:TEST_RC).should == false
|
||||
Pry.should_load_rc = false
|
||||
end
|
||||
end
|
||||
|
||||
describe "nesting" do
|
||||
after do
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
|
||||
it 'should nest properly' do
|
||||
Pry.input = InputTester.new("pry", "pry", "pry", "\"nest:\#\{Pry.nesting.level\}\"", "exit_all")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
|
||||
o = Object.new
|
||||
|
||||
pry_tester = o.pry
|
||||
str_output.string.should =~ /nest:3/
|
||||
end
|
||||
end
|
||||
|
||||
describe "defining methods" do
|
||||
it 'should define a method on the singleton class of an object when performing "def meth;end" inside the object' do
|
||||
[Object.new, {}, []].each do |val|
|
||||
str_input = StringIO.new("def hello;end")
|
||||
Pry.new(:input => str_input, :output => StringIO.new).rep(val)
|
||||
|
||||
val.methods(false).map(&:to_sym).include?(:hello).should == true
|
||||
end
|
||||
end
|
||||
|
||||
it 'should define an instance method on the module when performing "def meth;end" inside the module' do
|
||||
str_input = StringIO.new("def hello;end")
|
||||
hello = Module.new
|
||||
Pry.new(:input => str_input, :output => StringIO.new).rep(hello)
|
||||
hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true
|
||||
end
|
||||
|
||||
it 'should define an instance method on the class when performing "def meth;end" inside the class' do
|
||||
str_input = StringIO.new("def hello;end")
|
||||
hello = Class.new
|
||||
Pry.new(:input => str_input, :output => StringIO.new).rep(hello)
|
||||
hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true
|
||||
end
|
||||
|
||||
it 'should define a method on the class of an object when performing "def meth;end" inside an immediate value or Numeric' do
|
||||
# should include float in here, but test fails for some reason
|
||||
# on 1.8.7, no idea why!
|
||||
[:test, 0, true, false, nil].each do |val|
|
||||
str_input = StringIO.new("def hello;end")
|
||||
Pry.new(:input => str_input, :output => StringIO.new).rep(val)
|
||||
val.class.instance_methods(false).map(&:to_sym).include?(:hello).should == true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
describe "commands" do
|
||||
it 'should run a command with no parameter' do
|
||||
pry_tester = Pry.new
|
||||
pry_tester.commands = CommandTester
|
||||
pry_tester.input = InputTester.new("command1", "exit_all")
|
||||
pry_tester.commands = CommandTester
|
||||
|
||||
str_output = StringIO.new
|
||||
pry_tester.output = str_output
|
||||
|
||||
pry_tester.rep
|
||||
|
||||
str_output.string.should =~ /command1/
|
||||
end
|
||||
|
||||
it 'should run a command with one parameter' do
|
||||
pry_tester = Pry.new
|
||||
pry_tester.commands = CommandTester
|
||||
pry_tester.input = InputTester.new("command2 horsey", "exit_all")
|
||||
pry_tester.commands = CommandTester
|
||||
|
||||
str_output = StringIO.new
|
||||
pry_tester.output = str_output
|
||||
|
||||
pry_tester.rep
|
||||
|
||||
str_output.string.should =~ /horsey/
|
||||
end
|
||||
end
|
||||
|
||||
describe "Object#pry" do
|
||||
|
||||
after do
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
|
||||
it "should start a pry session on the receiver (first form)" do
|
||||
Pry.input = InputTester.new("self", "exit")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
|
||||
20.pry
|
||||
|
||||
str_output.string.should =~ /20/
|
||||
end
|
||||
|
||||
it "should start a pry session on the receiver (second form)" do
|
||||
Pry.input = InputTester.new("self", "exit")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
|
||||
pry 20
|
||||
|
||||
str_output.string.should =~ /20/
|
||||
end
|
||||
|
||||
it "should error if more than one argument is passed to Object#pry" do
|
||||
lambda { pry(20, :input => Readline) }.should.raise ArgumentError
|
||||
end
|
||||
end
|
||||
|
||||
describe "Pry.binding_for" do
|
||||
it 'should return TOPLEVEL_BINDING if parameter self is main' do
|
||||
_main_ = lambda { TOPLEVEL_BINDING.eval('self') }
|
||||
Pry.binding_for(_main_.call).is_a?(Binding).should == true
|
||||
Pry.binding_for(_main_.call).should == TOPLEVEL_BINDING
|
||||
Pry.binding_for(_main_.call).should == Pry.binding_for(_main_.call)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "test Pry defaults" do
|
||||
|
||||
after do
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
|
||||
describe "input" do
|
||||
|
||||
after do
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
|
||||
it 'should set the input default, and the default should be overridable' do
|
||||
Pry.input = InputTester.new("5")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
Pry.new.rep
|
||||
str_output.string.should =~ /5/
|
||||
|
||||
Pry.new(:input => InputTester.new("6")).rep
|
||||
str_output.string.should =~ /6/
|
||||
end
|
||||
|
||||
it 'should pass in the prompt if readline arity is 1' do
|
||||
Pry.prompt = proc { "A" }
|
||||
|
||||
arity_one_input = Class.new do
|
||||
attr_accessor :prompt
|
||||
def readline(prompt)
|
||||
@prompt = prompt
|
||||
"exit"
|
||||
end
|
||||
end.new
|
||||
|
||||
Pry.start(self, :input => arity_one_input, :output => Pry::NullOutput)
|
||||
arity_one_input.prompt.should == Pry.prompt.call
|
||||
end
|
||||
|
||||
it 'should not pass in the prompt if the arity is 0' do
|
||||
Pry.prompt = proc { "A" }
|
||||
|
||||
arity_zero_input = Class.new do
|
||||
def readline
|
||||
"exit"
|
||||
end
|
||||
end.new
|
||||
|
||||
lambda { Pry.start(self, :input => arity_zero_input, :output => Pry::NullOutput) }.should.not.raise Exception
|
||||
end
|
||||
|
||||
it 'should not pass in the prompt if the arity is -1' do
|
||||
Pry.prompt = proc { "A" }
|
||||
|
||||
arity_multi_input = Class.new do
|
||||
attr_accessor :prompt
|
||||
|
||||
def readline(*args)
|
||||
@prompt = args.first
|
||||
"exit"
|
||||
end
|
||||
end.new
|
||||
|
||||
Pry.start(self, :input => arity_multi_input, :output => Pry::NullOutput)
|
||||
arity_multi_input.prompt.should == nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
it 'should set the output default, and the default should be overridable' do
|
||||
Pry.input = InputTester.new("5", "6", "7")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
|
||||
Pry.new.rep
|
||||
str_output.string.should =~ /5/
|
||||
|
||||
Pry.new.rep
|
||||
str_output.string.should =~ /5\n.*6/
|
||||
|
||||
str_output2 = StringIO.new
|
||||
Pry.new(:output => str_output2).rep
|
||||
str_output2.string.should.not =~ /5\n.*6/
|
||||
str_output2.string.should =~ /7/
|
||||
end
|
||||
|
||||
describe "Pry.run_command" do
|
||||
before do
|
||||
class RCTest
|
||||
def a() end
|
||||
B = 20
|
||||
@x = 10
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
Object.remove_const(:RCTest)
|
||||
end
|
||||
|
||||
it "should execute command in the appropriate object context" do
|
||||
result = Pry.run_command "ls", :context => RCTest
|
||||
result.map(&:to_sym).should == [:@x]
|
||||
end
|
||||
|
||||
it "should execute command with parameters in the appropriate object context" do
|
||||
result = Pry.run_command "ls -M", :context => RCTest
|
||||
result.map(&:to_sym).should == [:a]
|
||||
end
|
||||
|
||||
it "should execute command and show output with :show_output => true flag" do
|
||||
str = StringIO.new
|
||||
Pry.output = str
|
||||
result = Pry.run_command "ls -afv", :context => RCTest, :show_output => true
|
||||
str.string.should =~ /global variables/
|
||||
Pry.output = $stdout
|
||||
end
|
||||
|
||||
it "should execute command with multiple parameters" do
|
||||
result = Pry.run_command "ls -c -M RCTest"
|
||||
result.map(&:to_sym).should == [:a, :B]
|
||||
end
|
||||
end
|
||||
|
||||
describe "commands" do
|
||||
it 'should interpolate ruby code into commands' do
|
||||
klass = Class.new(Pry::CommandBase) do
|
||||
command "hello", "", :keep_retval => true do |arg|
|
||||
arg
|
||||
end
|
||||
end
|
||||
|
||||
$test_interpolation = "bing"
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => StringIO.new("hello #{$test_interpolation}"), :output => str_output, :commands => klass).rep
|
||||
str_output.string.should =~ /bing/
|
||||
$test_interpolation = nil
|
||||
end
|
||||
|
||||
it 'should create a comand in a nested context and that command should be accessible from the parent' do
|
||||
str_input = StringIO.new("@x=nil\ncd 7\n_pry_.commands.instance_eval {\ncommand('bing') { |arg| run arg }\n}\ncd ..\nbing ls\nexit")
|
||||
str_output = StringIO.new
|
||||
Pry.input = str_input
|
||||
obj = Object.new
|
||||
Pry.new(:output => str_output).repl(obj)
|
||||
Pry.input = Readline
|
||||
str_output.string.should =~ /@x/
|
||||
end
|
||||
|
||||
it 'should define a command that keeps its return value' do
|
||||
class Command68 < Pry::CommandBase
|
||||
command "hello", "", :keep_retval => true do
|
||||
:kept_hello
|
||||
end
|
||||
end
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => Command68).rep
|
||||
str_output.string.should =~ /:kept_hello/
|
||||
str_output.string.should =~ /=>/
|
||||
|
||||
Object.remove_const(:Command68)
|
||||
end
|
||||
|
||||
it 'should define a command that does NOT keep its return value' do
|
||||
class Command68 < Pry::CommandBase
|
||||
command "hello", "", :keep_retval => false do
|
||||
:kept_hello
|
||||
end
|
||||
end
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => Command68).rep
|
||||
(str_output.string =~ /:kept_hello/).should == nil
|
||||
str_output.string !~ /=>/
|
||||
|
||||
Object.remove_const(:Command68)
|
||||
end
|
||||
|
||||
it 'should set the commands default, and the default should be overridable' do
|
||||
class Command0 < Pry::CommandBase
|
||||
command "hello" do
|
||||
output.puts "hello world"
|
||||
end
|
||||
end
|
||||
|
||||
Pry.commands = Command0
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("hello"), :output => str_output).rep
|
||||
str_output.string.should =~ /hello world/
|
||||
|
||||
class Command1 < Pry::CommandBase
|
||||
command "goodbye", "" do
|
||||
output.puts "goodbye world"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
|
||||
Pry.new(:input => InputTester.new("goodbye"), :output => str_output, :commands => Command1).rep
|
||||
str_output.string.should =~ /goodbye world/
|
||||
|
||||
Object.remove_const(:Command0)
|
||||
Object.remove_const(:Command1)
|
||||
end
|
||||
|
||||
it 'should inherit "help" command from Pry::CommandBase' do
|
||||
class Command2 < Pry::CommandBase
|
||||
command "h", "h command" do
|
||||
end
|
||||
end
|
||||
|
||||
Command2.commands.keys.size.should == 3
|
||||
Command2.commands.keys.include?("help").should == true
|
||||
Command2.commands.keys.include?("install").should == true
|
||||
Command2.commands.keys.include?("h").should == true
|
||||
|
||||
Object.remove_const(:Command2)
|
||||
end
|
||||
|
||||
it 'should inherit commands from Pry::Commands' do
|
||||
class Command3 < Pry::Commands
|
||||
command "v" do
|
||||
end
|
||||
end
|
||||
|
||||
Command3.commands.include?("nesting").should == true
|
||||
Command3.commands.include?("jump-to").should == true
|
||||
Command3.commands.include?("cd").should == true
|
||||
Command3.commands.include?("v").should == true
|
||||
|
||||
Object.remove_const(:Command3)
|
||||
end
|
||||
|
||||
it 'should alias a command with another command' do
|
||||
class Command6 < Pry::CommandBase
|
||||
alias_command "help2", "help"
|
||||
end
|
||||
|
||||
Command6.commands["help2"].should == Command6.commands["help"]
|
||||
# str_output = StringIO.new
|
||||
# Pry.new(:input => InputTester.new("run_v"), :output => str_output, :commands => Command3).rep
|
||||
# str_output.string.should =~ /v command/
|
||||
|
||||
Object.remove_const(:Command6)
|
||||
end
|
||||
|
||||
it 'should change description of a command using desc' do
|
||||
|
||||
class Command7 < Pry::Commands
|
||||
end
|
||||
|
||||
orig = Command7.commands["help"][:description]
|
||||
|
||||
class Command7
|
||||
desc "help", "blah"
|
||||
end
|
||||
|
||||
Command7.commands["help"][:description].should.not == orig
|
||||
Command7.commands["help"][:description].should == "blah"
|
||||
|
||||
Object.remove_const(:Command7)
|
||||
end
|
||||
|
||||
it 'should run a command from within a command' do
|
||||
class Command01 < Pry::Commands
|
||||
command "v" do
|
||||
output.puts "v command"
|
||||
end
|
||||
|
||||
command "run_v" do
|
||||
run "v"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("run_v"), :output => str_output, :commands => Command01).rep
|
||||
str_output.string.should =~ /v command/
|
||||
|
||||
Object.remove_const(:Command01)
|
||||
end
|
||||
|
||||
it 'should enable an inherited method to access opts and output and target, due to instance_exec' do
|
||||
class Command3 < Pry::Commands
|
||||
command "v" do
|
||||
output.puts "#{target.eval('self')}"
|
||||
end
|
||||
end
|
||||
|
||||
class Command4 < Command3
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:print => proc {}, :input => InputTester.new("v"),
|
||||
:output => str_output, :commands => Command4).rep("john")
|
||||
|
||||
str_output.string.rstrip.should == "john"
|
||||
|
||||
Object.remove_const(:Command3)
|
||||
Object.remove_const(:Command4)
|
||||
end
|
||||
|
||||
it 'should import commands from another command object' do
|
||||
Object.remove_const(:Command77) if Object.const_defined?(:Command77)
|
||||
|
||||
class Command77 < Pry::CommandBase
|
||||
import_from Pry::Commands, "status", "jump-to"
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:print => proc {}, :input => InputTester.new("status"),
|
||||
:output => str_output, :commands => Command77).rep("john")
|
||||
str_output.string.should =~ /Status:/
|
||||
|
||||
Object.remove_const(:Command77)
|
||||
end
|
||||
|
||||
it 'should delete some inherited commands when using delete method' do
|
||||
class Command3 < Pry::Commands
|
||||
command "v" do
|
||||
end
|
||||
|
||||
delete "show_doc", "show_method"
|
||||
delete "ls"
|
||||
end
|
||||
|
||||
Command3.commands.include?("nesting").should == true
|
||||
Command3.commands.include?("jump-to").should == true
|
||||
Command3.commands.include?("cd").should == true
|
||||
Command3.commands.include?("v").should == true
|
||||
Command3.commands.include?("show_doc").should == false
|
||||
Command3.commands.include?("show_method").should == false
|
||||
Command3.commands.include?("ls").should == false
|
||||
|
||||
Object.remove_const(:Command3)
|
||||
end
|
||||
|
||||
it 'should override some inherited commands' do
|
||||
class Command3 < Pry::Commands
|
||||
command "jump-to" do
|
||||
output.puts "jump-to the music"
|
||||
end
|
||||
|
||||
command "help" do
|
||||
output.puts "help to the music"
|
||||
end
|
||||
end
|
||||
|
||||
# suppress evaluation output
|
||||
Pry.print = proc {}
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("jump-to"), :output => str_output, :commands => Command3).rep
|
||||
str_output.string.rstrip.should == "jump-to the music"
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("help"), :output => str_output, :commands => Command3).rep
|
||||
str_output.string.rstrip.should == "help to the music"
|
||||
|
||||
Object.remove_const(:Command3)
|
||||
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
end
|
||||
|
||||
it "should set the print default, and the default should be overridable" do
|
||||
new_print = proc { |out, value| out.puts value }
|
||||
Pry.print = new_print
|
||||
|
||||
Pry.new.print.should == Pry.print
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("\"test\""), :output => str_output).rep
|
||||
str_output.string.should == "test\n"
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("\"test\""), :output => str_output,
|
||||
:print => proc { |out, value| out.puts value.reverse }).rep
|
||||
str_output.string.should == "tset\n"
|
||||
|
||||
Pry.new.print.should == Pry.print
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("\"test\""), :output => str_output).rep
|
||||
str_output.string.should == "test\n"
|
||||
end
|
||||
|
||||
describe "pry return values" do
|
||||
it 'should return the target object' do
|
||||
Pry.start(self, :input => StringIO.new("exit"), :output => Pry::NullOutput).should == self
|
||||
end
|
||||
|
||||
it 'should return the parameter given to exit' do
|
||||
Pry.start(self, :input => StringIO.new("exit 10"), :output => Pry::NullOutput).should == 10
|
||||
end
|
||||
|
||||
it 'should return the parameter (multi word string) given to exit' do
|
||||
Pry.start(self, :input => StringIO.new("exit \"john mair\""), :output => Pry::NullOutput).should == "john mair"
|
||||
end
|
||||
|
||||
it 'should return the parameter (function call) given to exit' do
|
||||
Pry.start(self, :input => StringIO.new("exit 'abc'.reverse"), :output => Pry::NullOutput).should == 'cba'
|
||||
end
|
||||
|
||||
it 'should return the parameter (self) given to exit' do
|
||||
Pry.start("carl", :input => StringIO.new("exit self"), :output => Pry::NullOutput).should == "carl"
|
||||
end
|
||||
end
|
||||
|
||||
describe "prompts" do
|
||||
it 'should set the prompt default, and the default should be overridable (single prompt)' do
|
||||
new_prompt = proc { "test prompt> " }
|
||||
Pry.prompt = new_prompt
|
||||
|
||||
Pry.new.prompt.should == Pry.prompt
|
||||
Pry.new.select_prompt(true, 0).should == "test prompt> "
|
||||
Pry.new.select_prompt(false, 0).should == "test prompt> "
|
||||
|
||||
new_prompt = proc { "A" }
|
||||
pry_tester = Pry.new(:prompt => new_prompt)
|
||||
pry_tester.prompt.should == new_prompt
|
||||
pry_tester.select_prompt(true, 0).should == "A"
|
||||
pry_tester.select_prompt(false, 0).should == "A"
|
||||
|
||||
Pry.new.prompt.should == Pry.prompt
|
||||
Pry.new.select_prompt(true, 0).should == "test prompt> "
|
||||
Pry.new.select_prompt(false, 0).should == "test prompt> "
|
||||
end
|
||||
|
||||
it 'should set the prompt default, and the default should be overridable (multi prompt)' do
|
||||
new_prompt = [proc { "test prompt> " }, proc { "test prompt* " }]
|
||||
Pry.prompt = new_prompt
|
||||
|
||||
Pry.new.prompt.should == Pry.prompt
|
||||
Pry.new.select_prompt(true, 0).should == "test prompt> "
|
||||
Pry.new.select_prompt(false, 0).should == "test prompt* "
|
||||
|
||||
new_prompt = [proc { "A" }, proc { "B" }]
|
||||
pry_tester = Pry.new(:prompt => new_prompt)
|
||||
pry_tester.prompt.should == new_prompt
|
||||
pry_tester.select_prompt(true, 0).should == "A"
|
||||
pry_tester.select_prompt(false, 0).should == "B"
|
||||
|
||||
Pry.new.prompt.should == Pry.prompt
|
||||
Pry.new.select_prompt(true, 0).should == "test prompt> "
|
||||
Pry.new.select_prompt(false, 0).should == "test prompt* "
|
||||
end
|
||||
end
|
||||
|
||||
it 'should set the hooks default, and the default should be overridable' do
|
||||
Pry.input = InputTester.new("exit")
|
||||
Pry.hooks = {
|
||||
:before_session => proc { |out,_| out.puts "HELLO" },
|
||||
:after_session => proc { |out,_| out.puts "BYE" }
|
||||
}
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:output => str_output).repl
|
||||
str_output.string.should =~ /HELLO/
|
||||
str_output.string.should =~ /BYE/
|
||||
|
||||
Pry.input.rewind
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:output => str_output,
|
||||
:hooks => {
|
||||
:before_session => proc { |out,_| out.puts "MORNING" },
|
||||
:after_session => proc { |out,_| out.puts "EVENING" }
|
||||
}
|
||||
).repl
|
||||
|
||||
str_output.string.should =~ /MORNING/
|
||||
str_output.string.should =~ /EVENING/
|
||||
|
||||
# try below with just defining one hook
|
||||
Pry.input.rewind
|
||||
str_output = StringIO.new
|
||||
Pry.new(:output => str_output,
|
||||
:hooks => {
|
||||
:before_session => proc { |out,_| out.puts "OPEN" }
|
||||
}
|
||||
).repl
|
||||
|
||||
str_output.string.should =~ /OPEN/
|
||||
|
||||
Pry.input.rewind
|
||||
str_output = StringIO.new
|
||||
Pry.new(:output => str_output,
|
||||
:hooks => {
|
||||
:after_session => proc { |out,_| out.puts "CLOSE" }
|
||||
}
|
||||
).repl
|
||||
|
||||
str_output.string.should =~ /CLOSE/
|
||||
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Pry::CommandSet do
|
||||
before do
|
||||
@set = Pry::CommandSet.new(:some_name)
|
||||
end
|
||||
|
||||
it 'should use the name specified at creation' do
|
||||
@set.name.should == :some_name
|
||||
end
|
||||
|
||||
it 'should call the block used for the command when it is called' do
|
||||
run = false
|
||||
@set.command 'foo' do
|
||||
run = true
|
||||
end
|
||||
|
||||
@set.run_command nil, 'foo'
|
||||
run.should == true
|
||||
end
|
||||
|
||||
it 'should pass arguments of the command to the block' do
|
||||
@set.command 'foo' do |*args|
|
||||
args.should == [1, 2, 3]
|
||||
end
|
||||
|
||||
@set.run_command nil, 'foo', 1, 2, 3
|
||||
end
|
||||
|
||||
it 'should use the first argument as self' do
|
||||
@set.command 'foo' do
|
||||
self.should == true
|
||||
end
|
||||
|
||||
@set.run_command true, 'foo'
|
||||
end
|
||||
|
||||
it 'should raise an error when calling an undefined comand' do
|
||||
@set.command('foo') {}
|
||||
lambda {
|
||||
@set.run_command nil, 'bar'
|
||||
}.should.raise(Pry::NoCommandError)
|
||||
end
|
||||
|
||||
it 'should be able to remove its own commands' do
|
||||
@set.command('foo') {}
|
||||
@set.delete 'foo'
|
||||
|
||||
lambda {
|
||||
@set.run_command nil, 'foo'
|
||||
}.should.raise(Pry::NoCommandError)
|
||||
end
|
||||
|
||||
it 'should be able to import some commands from other sets' do
|
||||
run = false
|
||||
|
||||
other_set = Pry::CommandSet.new :foo do
|
||||
command('foo') { run = true }
|
||||
command('bar') {}
|
||||
end
|
||||
|
||||
@set.import_from(other_set, 'foo')
|
||||
|
||||
@set.run_command nil, 'foo'
|
||||
run.should == true
|
||||
|
||||
lambda {
|
||||
@set.run_command nil, 'bar'
|
||||
}.should.raise(Pry::NoCommandError)
|
||||
end
|
||||
|
||||
it 'should be able to import a whole set' do
|
||||
run = []
|
||||
|
||||
other_set = Pry::CommandSet.new :foo do
|
||||
command('foo') { run << true }
|
||||
command('bar') { run << true }
|
||||
end
|
||||
|
||||
@set.import other_set
|
||||
|
||||
@set.run_command nil, 'foo'
|
||||
@set.run_command nil, 'bar'
|
||||
run.should == [true, true]
|
||||
end
|
||||
|
||||
it 'should be able to import sets at creation' do
|
||||
run = false
|
||||
@set.command('foo') { run = true }
|
||||
|
||||
Pry::CommandSet.new(:other, @set).run_command nil, 'foo'
|
||||
run.should == true
|
||||
end
|
||||
|
||||
it 'should set the descriptions of commands' do
|
||||
@set.command('foo', 'some stuff') {}
|
||||
@set.commands['foo'].description.should == 'some stuff'
|
||||
end
|
||||
|
||||
it 'should be able to alias method' do
|
||||
run = false
|
||||
@set.command('foo', 'stuff') { run = true }
|
||||
|
||||
@set.alias_command 'bar', 'foo'
|
||||
@set.commands['bar'].name.should == 'bar'
|
||||
@set.commands['bar'].description.should == 'stuff'
|
||||
|
||||
@set.run_command nil, 'bar'
|
||||
run.should == true
|
||||
end
|
||||
|
||||
it 'should be able to change the descritpions of methods' do
|
||||
@set.command('foo', 'bar') {}
|
||||
@set.desc 'foo', 'baz'
|
||||
|
||||
@set.commands['foo'].description.should == 'baz'
|
||||
end
|
||||
|
||||
it 'should return nil for commands by default' do
|
||||
@set.command('foo') { 3 }
|
||||
@set.run_command(nil, 'foo').should == nil
|
||||
end
|
||||
|
||||
it 'should be able to keep return values' do
|
||||
@set.command('foo', '', :keep_retval => true) { 3 }
|
||||
@set.run_command(nil, 'foo').should == 3
|
||||
end
|
||||
end
|
77
test/test_command_helpers.rb
Normal file
77
test/test_command_helpers.rb
Normal file
|
@ -0,0 +1,77 @@
|
|||
require 'helper'
|
||||
|
||||
describe Pry::Helpers::CommandHelpers do
|
||||
before do
|
||||
@helper = Pry::Helpers::CommandHelpers
|
||||
end
|
||||
|
||||
describe "get_method_object" do
|
||||
it 'should look up instance methods if no methods available and no options provided' do
|
||||
klass = Class.new { def hello; end }
|
||||
meth = @helper.get_method_object(:hello, Pry.binding_for(klass), {})
|
||||
meth.should == klass.instance_method(:hello)
|
||||
end
|
||||
|
||||
it 'should look up methods if no instance methods available and no options provided' do
|
||||
klass = Class.new { def self.hello; end }
|
||||
meth = @helper.get_method_object(:hello, Pry.binding_for(klass), {})
|
||||
meth.should == klass.method(:hello)
|
||||
end
|
||||
|
||||
it 'should look up instance methods first even if methods available and no options provided' do
|
||||
klass = Class.new { def hello; end; def self.hello; end }
|
||||
meth = @helper.get_method_object(:hello, Pry.binding_for(klass), {})
|
||||
meth.should == klass.instance_method(:hello)
|
||||
end
|
||||
|
||||
it 'should look up instance methods if "instance-methods" option provided' do
|
||||
klass = Class.new { def hello; end; def self.hello; end }
|
||||
meth = @helper.get_method_object(:hello, Pry.binding_for(klass), {"instance-methods" => true})
|
||||
meth.should == klass.instance_method(:hello)
|
||||
end
|
||||
|
||||
it 'should look up methods if :methods option provided' do
|
||||
klass = Class.new { def hello; end; def self.hello; end }
|
||||
meth = @helper.get_method_object(:hello, Pry.binding_for(klass), {:methods => true})
|
||||
meth.should == klass.method(:hello)
|
||||
end
|
||||
|
||||
it 'should look up instance methods using the Class#method syntax' do
|
||||
klass = Class.new { def hello; end; def self.hello; end }
|
||||
meth = @helper.get_method_object("klass#hello", Pry.binding_for(binding), {})
|
||||
meth.should == klass.instance_method(:hello)
|
||||
end
|
||||
|
||||
it 'should look up methods using the object.method syntax' do
|
||||
klass = Class.new { def hello; end; def self.hello; end }
|
||||
meth = @helper.get_method_object("klass.hello", Pry.binding_for(binding), {})
|
||||
meth.should == klass.method(:hello)
|
||||
end
|
||||
|
||||
it 'should NOT look up instance methods using the Class#method syntax if no instance methods defined' do
|
||||
klass = Class.new { def self.hello; end }
|
||||
meth = @helper.get_method_object("klass#hello", Pry.binding_for(binding), {})
|
||||
meth.should == nil
|
||||
end
|
||||
|
||||
it 'should NOT look up methods using the object.method syntax if no methods defined' do
|
||||
klass = Class.new { def hello; end }
|
||||
meth = @helper.get_method_object("klass.hello", Pry.binding_for(binding), {})
|
||||
meth.should == nil
|
||||
end
|
||||
|
||||
it 'should look up methods using klass.new.method syntax' do
|
||||
klass = Class.new { def hello; :hello; end }
|
||||
meth = @helper.get_method_object("klass.new.hello", Pry.binding_for(binding), {})
|
||||
meth.name.to_sym.should == :hello
|
||||
end
|
||||
|
||||
it 'should look up instance methods using klass.meth#method syntax' do
|
||||
klass = Class.new { def self.meth; Class.new; end }
|
||||
meth = @helper.get_method_object("klass.meth#initialize", Pry.binding_for(binding), {})
|
||||
meth.name.to_sym.should == :initialize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
99
test/test_command_processor.rb
Normal file
99
test/test_command_processor.rb
Normal file
|
@ -0,0 +1,99 @@
|
|||
require 'helper'
|
||||
|
||||
describe "Pry::CommandProcessor" do
|
||||
|
||||
before do
|
||||
@pry = Pry.new
|
||||
@pry.commands = Pry::CommandSet.new
|
||||
@command_processor = Pry::CommandProcessor.new(@pry)
|
||||
end
|
||||
|
||||
after do
|
||||
@pry.commands = Pry::CommandSet.new
|
||||
end
|
||||
|
||||
it 'should correctly match a simple string command' do
|
||||
@pry.commands.command("test-command") {}
|
||||
command, captures, pos = @command_processor.command_matched "test-command"
|
||||
|
||||
command.name.should == "test-command"
|
||||
captures.should == []
|
||||
pos.should == "test-command".length
|
||||
end
|
||||
|
||||
it 'should correctly match a simple string command with parameters' do
|
||||
@pry.commands.command("test-command") { |arg|}
|
||||
command, captures, pos = @command_processor.command_matched "test-command hello"
|
||||
|
||||
command.name.should == "test-command"
|
||||
captures.should == []
|
||||
pos.should == "test-command".length
|
||||
end
|
||||
|
||||
it 'should not match when the relevant command does not exist' do
|
||||
command, captures, pos = @command_processor.command_matched "test-command"
|
||||
|
||||
command.should == nil
|
||||
captures.should == nil
|
||||
end
|
||||
|
||||
it 'should correctly match a regex command' do
|
||||
@pry.commands.command(/rue(.?)/) { }
|
||||
command, captures, pos = @command_processor.command_matched "rue hello"
|
||||
|
||||
command.name.should == /rue(.?)/
|
||||
captures.should == [""]
|
||||
pos.should == 3
|
||||
end
|
||||
|
||||
it 'should correctly match a regex command and extract the capture groups' do
|
||||
@pry.commands.command(/rue(.?)/) { }
|
||||
command, captures, pos = @command_processor.command_matched "rue5 hello"
|
||||
|
||||
command.name.should == /rue(.?)/
|
||||
captures.should == ["5"]
|
||||
pos.should == 4
|
||||
end
|
||||
|
||||
it 'should correctly match a string command with spaces in its name' do
|
||||
@pry.commands.command("test command") {}
|
||||
command, captures, pos = @command_processor.command_matched "test command"
|
||||
|
||||
command.name.should == "test command"
|
||||
captures.should == []
|
||||
pos.should == command.name.length
|
||||
end
|
||||
|
||||
it 'should correctly match a string command with spaces in its name with parameters' do
|
||||
@pry.commands.command("test command") {}
|
||||
command, captures, pos = @command_processor.command_matched "test command param1 param2"
|
||||
|
||||
command.name.should == "test command"
|
||||
captures.should == []
|
||||
pos.should == command.name.length
|
||||
end
|
||||
|
||||
it 'should correctly match a regex command with spaces in its name' do
|
||||
regex_command_name = /test\s+(.+)\s+command/
|
||||
@pry.commands.command(regex_command_name) {}
|
||||
|
||||
sample_text = "test friendship command"
|
||||
command, captures, pos = @command_processor.command_matched sample_text
|
||||
|
||||
command.name.should == regex_command_name
|
||||
captures.should == ["friendship"]
|
||||
pos.should == sample_text.size
|
||||
end
|
||||
|
||||
it 'should correctly match a complex regex command' do
|
||||
regex_command_name = /\.(.*)/
|
||||
@pry.commands.command(regex_command_name) {}
|
||||
|
||||
sample_text = ".cd ~/pry"
|
||||
command, captures, pos = @command_processor.command_matched sample_text
|
||||
|
||||
command.name.should == regex_command_name
|
||||
captures.should == ["cd ~/pry"]
|
||||
pos.should == sample_text.size
|
||||
end
|
||||
end
|
190
test/test_command_set.rb
Normal file
190
test/test_command_set.rb
Normal file
|
@ -0,0 +1,190 @@
|
|||
require 'helper'
|
||||
|
||||
describe Pry::CommandSet do
|
||||
before do
|
||||
@set = Pry::CommandSet.new
|
||||
end
|
||||
|
||||
it 'should call the block used for the command when it is called' do
|
||||
run = false
|
||||
@set.command 'foo' do
|
||||
run = true
|
||||
end
|
||||
|
||||
@set.run_command nil, 'foo'
|
||||
run.should == true
|
||||
end
|
||||
|
||||
it 'should pass arguments of the command to the block' do
|
||||
@set.command 'foo' do |*args|
|
||||
args.should == [1, 2, 3]
|
||||
end
|
||||
|
||||
@set.run_command nil, 'foo', 1, 2, 3
|
||||
end
|
||||
|
||||
it 'should use the first argument as self' do
|
||||
@set.command 'foo' do
|
||||
self.should == true
|
||||
end
|
||||
|
||||
@set.run_command true, 'foo'
|
||||
end
|
||||
|
||||
it 'should raise an error when calling an undefined command' do
|
||||
@set.command('foo') {}
|
||||
lambda {
|
||||
@set.run_command nil, 'bar'
|
||||
}.should.raise(Pry::NoCommandError)
|
||||
end
|
||||
|
||||
it 'should be able to remove its own commands' do
|
||||
@set.command('foo') {}
|
||||
@set.delete 'foo'
|
||||
|
||||
lambda {
|
||||
@set.run_command nil, 'foo'
|
||||
}.should.raise(Pry::NoCommandError)
|
||||
end
|
||||
|
||||
it 'should be able to import some commands from other sets' do
|
||||
run = false
|
||||
|
||||
other_set = Pry::CommandSet.new do
|
||||
command('foo') { run = true }
|
||||
command('bar') {}
|
||||
end
|
||||
|
||||
@set.import_from(other_set, 'foo')
|
||||
|
||||
@set.run_command nil, 'foo'
|
||||
run.should == true
|
||||
|
||||
lambda {
|
||||
@set.run_command nil, 'bar'
|
||||
}.should.raise(Pry::NoCommandError)
|
||||
end
|
||||
|
||||
it 'should be able to import a whole set' do
|
||||
run = []
|
||||
|
||||
other_set = Pry::CommandSet.new do
|
||||
command('foo') { run << true }
|
||||
command('bar') { run << true }
|
||||
end
|
||||
|
||||
@set.import other_set
|
||||
|
||||
@set.run_command nil, 'foo'
|
||||
@set.run_command nil, 'bar'
|
||||
run.should == [true, true]
|
||||
end
|
||||
|
||||
it 'should be able to import sets at creation' do
|
||||
run = false
|
||||
@set.command('foo') { run = true }
|
||||
|
||||
Pry::CommandSet.new(@set).run_command nil, 'foo'
|
||||
run.should == true
|
||||
end
|
||||
|
||||
it 'should set the descriptions of commands' do
|
||||
@set.command('foo', 'some stuff') {}
|
||||
@set.commands['foo'].description.should == 'some stuff'
|
||||
end
|
||||
|
||||
it 'should be able to alias method' do
|
||||
run = false
|
||||
@set.command('foo', 'stuff') { run = true }
|
||||
|
||||
@set.alias_command 'bar', 'foo'
|
||||
@set.commands['bar'].name.should == 'bar'
|
||||
@set.commands['bar'].description.should == 'stuff'
|
||||
|
||||
@set.run_command nil, 'bar'
|
||||
run.should == true
|
||||
end
|
||||
|
||||
it 'should be able to change the descritpions of methods' do
|
||||
@set.command('foo', 'bar') {}
|
||||
@set.desc 'foo', 'baz'
|
||||
|
||||
@set.commands['foo'].description.should == 'baz'
|
||||
end
|
||||
|
||||
it 'should return nil for commands by default' do
|
||||
@set.command('foo') { 3 }
|
||||
@set.run_command(nil, 'foo').should == nil
|
||||
end
|
||||
|
||||
it 'should be able to keep return values' do
|
||||
@set.command('foo', '', :keep_retval => true) { 3 }
|
||||
@set.run_command(nil, 'foo').should == 3
|
||||
end
|
||||
|
||||
it 'should be able to have its own helpers' do
|
||||
@set.command('foo') do
|
||||
should.respond_to :my_helper
|
||||
end
|
||||
|
||||
@set.helpers do
|
||||
def my_helper; end
|
||||
end
|
||||
|
||||
@set.run_command(Pry::CommandContext.new, 'foo')
|
||||
Pry::CommandContext.new.should.not.respond_to :my_helper
|
||||
end
|
||||
|
||||
it 'should not recreate a new helper module when helpers is called' do
|
||||
@set.command('foo') do
|
||||
should.respond_to :my_helper
|
||||
should.respond_to :my_other_helper
|
||||
end
|
||||
|
||||
@set.helpers do
|
||||
def my_helper; end
|
||||
end
|
||||
|
||||
@set.helpers do
|
||||
def my_other_helper; end
|
||||
end
|
||||
|
||||
@set.run_command(Pry::CommandContext.new, 'foo')
|
||||
end
|
||||
|
||||
it 'should import helpers from imported sets' do
|
||||
imported_set = Pry::CommandSet.new do
|
||||
helpers do
|
||||
def imported_helper_method; end
|
||||
end
|
||||
end
|
||||
|
||||
@set.import imported_set
|
||||
@set.command('foo') { should.respond_to :imported_helper_method }
|
||||
@set.run_command(Pry::CommandContext.new, 'foo')
|
||||
end
|
||||
|
||||
it 'should import helpers even if only some commands are imported' do
|
||||
imported_set = Pry::CommandSet.new do
|
||||
helpers do
|
||||
def imported_helper_method; end
|
||||
end
|
||||
|
||||
command('bar') {}
|
||||
end
|
||||
|
||||
@set.import_from imported_set, 'bar'
|
||||
@set.command('foo') { should.respond_to :imported_helper_method }
|
||||
@set.run_command(Pry::CommandContext.new, 'foo')
|
||||
end
|
||||
|
||||
it 'should provide a :listing for a command that defaults to its name' do
|
||||
@set.command 'foo', "" do;end
|
||||
@set.commands['foo'].options[:listing].should == 'foo'
|
||||
end
|
||||
|
||||
it 'should provide a :listing for a command that differs from its name' do
|
||||
@set.command 'foo', "", :listing => 'bar' do;end
|
||||
@set.commands['foo'].options[:listing].should == 'bar'
|
||||
end
|
||||
end
|
400
test/test_default_commands.rb
Normal file
400
test/test_default_commands.rb
Normal file
|
@ -0,0 +1,400 @@
|
|||
require 'helper'
|
||||
|
||||
describe "Pry::Commands" do
|
||||
|
||||
after do
|
||||
$obj = nil
|
||||
end
|
||||
|
||||
describe "hist" do
|
||||
push_first_hist_line = lambda do |hist, line|
|
||||
hist.push line
|
||||
end
|
||||
|
||||
before do
|
||||
Readline::HISTORY.shift until Readline::HISTORY.empty?
|
||||
@hist = Readline::HISTORY
|
||||
end
|
||||
|
||||
it 'should display the correct history' do
|
||||
push_first_hist_line.call(@hist, "'bug in 1.8 means this line is ignored'")
|
||||
@hist.push "hello"
|
||||
@hist.push "world"
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hist", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
str_output.string.should =~ /hello\n.*world/
|
||||
end
|
||||
|
||||
it 'should replay history correctly (single item)' do
|
||||
push_first_hist_line.call(@hist, ":hello")
|
||||
@hist.push ":blah"
|
||||
@hist.push ":bucket"
|
||||
@hist.push ":ostrich"
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hist --replay -1", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
str_output.string.should =~ /ostrich/
|
||||
end
|
||||
|
||||
it 'should replay a range of history correctly (range of items)' do
|
||||
push_first_hist_line.call(@hist, "'bug in 1.8 means this line is ignored'")
|
||||
@hist.push ":hello"
|
||||
@hist.push ":carl"
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hist --replay 0..2", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
str_output.string.should =~ /:hello\n.*:carl/
|
||||
end
|
||||
|
||||
it 'should grep for correct lines in history' do
|
||||
push_first_hist_line.call(@hist, "apple")
|
||||
@hist.push "abby"
|
||||
@hist.push "box"
|
||||
@hist.push "button"
|
||||
@hist.push "pepper"
|
||||
@hist.push "orange"
|
||||
@hist.push "grape"
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hist --grep o", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
|
||||
str_output.string.should =~ /\d:.*?box\n\d:.*?button\n\d:.*?orange/
|
||||
end
|
||||
|
||||
it 'should return last N lines in history with --tail switch' do
|
||||
push_first_hist_line.call(@hist, "0")
|
||||
("a".."z").each do |v|
|
||||
@hist.push v
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hist --tail 3", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
|
||||
str_output.string.each_line.count.should == 3
|
||||
str_output.string.should =~ /x\n\d+:.*y\n\d+:.*z/
|
||||
end
|
||||
|
||||
# strangeness in this test is due to bug in Readline::HISTORY not
|
||||
# always registering first line of input
|
||||
it 'should return first N lines in history with --head switch' do
|
||||
push_first_hist_line.call(@hist, "0")
|
||||
("a".."z").each do |v|
|
||||
@hist.push v
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hist --head 4", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
|
||||
str_output.string.each_line.count.should == 4
|
||||
str_output.string.should =~ /a\n\d+:.*b\n\d+:.*c/
|
||||
end
|
||||
|
||||
# strangeness in this test is due to bug in Readline::HISTORY not
|
||||
# always registering first line of input
|
||||
it 'should show lines between lines A and B with the --show switch' do
|
||||
push_first_hist_line.call(@hist, "0")
|
||||
("a".."z").each do |v|
|
||||
@hist.push v
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hist --show 1..4", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
|
||||
str_output.string.each_line.count.should == 4
|
||||
str_output.string.should =~ /b\n\d+:.*c\n\d+:.*d/
|
||||
end
|
||||
end
|
||||
|
||||
describe "show-method" do
|
||||
it 'should output a method\'s source' do
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("show-method sample_method", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
|
||||
str_output.string.should =~ /def sample/
|
||||
end
|
||||
|
||||
it 'should output a method\'s source with line numbers' do
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("show-method -l sample_method", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
|
||||
str_output.string.should =~ /\d+: def sample/
|
||||
end
|
||||
|
||||
it 'should output a method\'s source if inside method without needing to use method name' do
|
||||
$str_output = StringIO.new
|
||||
|
||||
o = Object.new
|
||||
def o.sample
|
||||
redirect_pry_io(InputTester.new("show-method", "exit-all"), $str_output) do
|
||||
binding.pry
|
||||
end
|
||||
end
|
||||
o.sample
|
||||
|
||||
$str_output.string.should =~ /def o.sample/
|
||||
$str_output = nil
|
||||
end
|
||||
|
||||
it 'should output a method\'s source if inside method without needing to use method name, and using the -l switch' do
|
||||
$str_output = StringIO.new
|
||||
|
||||
o = Object.new
|
||||
def o.sample
|
||||
redirect_pry_io(InputTester.new("show-method -l", "exit-all"), $str_output) do
|
||||
binding.pry
|
||||
end
|
||||
end
|
||||
o.sample
|
||||
|
||||
$str_output.string.should =~ /\d+: def o.sample/
|
||||
$str_output = nil
|
||||
end
|
||||
|
||||
# dynamically defined method source retrieval is only supported in
|
||||
# 1.9 - where Method#source_location is native
|
||||
if RUBY_VERSION =~ /1.9/
|
||||
it 'should output a method\'s source for a method defined inside pry' do
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("def dyna_method", ":testing", "end", "show-method dyna_method"), str_output) do
|
||||
TOPLEVEL_BINDING.pry
|
||||
end
|
||||
|
||||
str_output.string.should =~ /def dyna_method/
|
||||
Object.remove_method :dyna_method
|
||||
end
|
||||
|
||||
it 'should output a method\'s source for a method defined inside pry, even if exceptions raised before hand' do
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("bad code", "123", "bad code 2", "1 + 2", "def dyna_method", ":testing", "end", "show-method dyna_method"), str_output) do
|
||||
TOPLEVEL_BINDING.pry
|
||||
end
|
||||
|
||||
str_output.string.should =~ /def dyna_method/
|
||||
Object.remove_method :dyna_method
|
||||
end
|
||||
|
||||
it 'should output an instance method\'s source for a method defined inside pry' do
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("class A", "def yo", "end", "end", "show-method A#yo"), str_output) do
|
||||
TOPLEVEL_BINDING.pry
|
||||
end
|
||||
|
||||
str_output.string.should =~ /def yo/
|
||||
Object.remove_const :A
|
||||
end
|
||||
|
||||
it 'should output an instance method\'s source for a method defined inside pry using define_method' do
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("class A", "define_method(:yup) {}", "end", "end", "show-method A#yup"), str_output) do
|
||||
TOPLEVEL_BINDING.pry
|
||||
end
|
||||
|
||||
str_output.string.should =~ /define_method\(:yup\)/
|
||||
Object.remove_const :A
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "show-doc" do
|
||||
it 'should output a method\'s documentation' do
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("show-doc sample_method", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
|
||||
str_output.string.should =~ /sample doc/
|
||||
end
|
||||
|
||||
it 'should output a method\'s documentation if inside method without needing to use method name' do
|
||||
$str_output = StringIO.new
|
||||
|
||||
o = Object.new
|
||||
def o.sample
|
||||
redirect_pry_io(InputTester.new("show-doc", "exit-all"), $str_output) do
|
||||
binding.pry
|
||||
end
|
||||
end
|
||||
o.sample
|
||||
|
||||
$str_output.string.should =~ /sample doc/
|
||||
$str_output = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "cd" do
|
||||
it 'should cd into simple input' do
|
||||
b = Pry.binding_for(Object.new)
|
||||
b.eval("x = :mon_ouie")
|
||||
|
||||
redirect_pry_io(InputTester.new("cd x", "$obj = self", "exit-all"), StringIO.new) do
|
||||
b.pry
|
||||
end
|
||||
|
||||
$obj.should == :mon_ouie
|
||||
end
|
||||
|
||||
it 'should break out of session with cd ..' do
|
||||
b = Pry.binding_for(:outer)
|
||||
b.eval("x = :inner")
|
||||
|
||||
redirect_pry_io(InputTester.new("cd x", "$inner = self;", "cd ..", "$outer = self", "exit-all"), StringIO.new) do
|
||||
b.pry
|
||||
end
|
||||
$inner.should == :inner
|
||||
$outer.should == :outer
|
||||
end
|
||||
|
||||
it 'should break out to outer-most session with cd /' do
|
||||
b = Pry.binding_for(:outer)
|
||||
b.eval("x = :inner")
|
||||
|
||||
redirect_pry_io(InputTester.new("cd x", "$inner = self;", "cd 5", "$five = self", "cd /", "$outer = self", "exit-all"), StringIO.new) do
|
||||
b.pry
|
||||
end
|
||||
$inner.should == :inner
|
||||
$five.should == 5
|
||||
$outer.should == :outer
|
||||
end
|
||||
|
||||
it 'should start a session on TOPLEVEL_BINDING with cd ::' do
|
||||
b = Pry.binding_for(:outer)
|
||||
|
||||
redirect_pry_io(InputTester.new("cd ::", "$obj = self", "exit-all"), StringIO.new) do
|
||||
5.pry
|
||||
end
|
||||
$obj.should == TOPLEVEL_BINDING.eval('self')
|
||||
end
|
||||
|
||||
it 'should cd into complex input (with spaces)' do
|
||||
o = Object.new
|
||||
def o.hello(x, y, z)
|
||||
:mon_ouie
|
||||
end
|
||||
|
||||
redirect_pry_io(InputTester.new("cd hello 1, 2, 3", "$obj = self", "exit-all"), StringIO.new) do
|
||||
o.pry
|
||||
end
|
||||
$obj.should == :mon_ouie
|
||||
end
|
||||
end
|
||||
|
||||
# show-command only works in implementations that support Proc#source_location
|
||||
if Proc.method_defined?(:source_location)
|
||||
describe "show-command" do
|
||||
it 'should show source for an ordinary command' do
|
||||
set = Pry::CommandSet.new do
|
||||
import_from Pry::Commands, "show-command"
|
||||
command "foo" do
|
||||
:body_of_foo
|
||||
end
|
||||
end
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("show-command foo"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
str_output.string.should =~ /:body_of_foo/
|
||||
end
|
||||
|
||||
it 'should show source for a command with spaces in its name' do
|
||||
set = Pry::CommandSet.new do
|
||||
import_from Pry::Commands, "show-command"
|
||||
command "foo bar" do
|
||||
:body_of_foo_bar
|
||||
end
|
||||
end
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("show-command \"foo bar\""), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
str_output.string.should =~ /:body_of_foo_bar/
|
||||
end
|
||||
|
||||
it 'should show source for a command by listing name' do
|
||||
set = Pry::CommandSet.new do
|
||||
import_from Pry::Commands, "show-command"
|
||||
command /foo(.*)/, "", :listing => "bar" do
|
||||
:body_of_foo_regex
|
||||
end
|
||||
end
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("show-command bar"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
str_output.string.should =~ /:body_of_foo_regex/
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "help" do
|
||||
it 'should display help for a specific command' do
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("help ls", "exit-all"), str_output) do
|
||||
pry
|
||||
end
|
||||
str_output.string.each_line.count.should == 1
|
||||
str_output.string.should =~ /ls --help/
|
||||
end
|
||||
|
||||
it 'should display help for a regex command with a "listing"' do
|
||||
set = Pry::CommandSet.new do
|
||||
command /bar(.*)/, "Test listing", :listing => "foo" do
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("help foo"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
str_output.string.each_line.count.should == 1
|
||||
str_output.string.should =~ /Test listing/
|
||||
end
|
||||
|
||||
it 'should display help for a command with a spaces in its name' do
|
||||
set = Pry::CommandSet.new do
|
||||
command "command with spaces", "description of a command with spaces" do
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("help \"command with spaces\""), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
str_output.string.each_line.count.should == 1
|
||||
str_output.string.should =~ /description of a command with spaces/
|
||||
end
|
||||
|
||||
it 'should display help for all commands with a description' do
|
||||
set = Pry::CommandSet.new do
|
||||
command /bar(.*)/, "Test listing", :listing => "foo" do; end
|
||||
command "b", "description for b", :listing => "foo" do; end
|
||||
command "c" do;end
|
||||
command "d", "" do;end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("help"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
str_output.string.should =~ /Test listing/
|
||||
str_output.string.should =~ /description for b/
|
||||
str_output.string.should =~ /No description/
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,58 +0,0 @@
|
|||
unless Object.const_defined? 'Pry'
|
||||
$:.unshift File.expand_path '../../lib', __FILE__
|
||||
require 'pry'
|
||||
end
|
||||
|
||||
require 'bacon'
|
||||
|
||||
# Ensure we do not execute any rc files
|
||||
Pry::RC_FILES.clear
|
||||
Pry.color = false
|
||||
Pry.should_load_rc = false
|
||||
|
||||
class Module
|
||||
public :remove_const
|
||||
end
|
||||
|
||||
class << Pry
|
||||
alias_method :orig_reset_defaults, :reset_defaults
|
||||
def reset_defaults
|
||||
orig_reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
end
|
||||
|
||||
class InputTester
|
||||
def initialize(*actions)
|
||||
@orig_actions = actions.dup
|
||||
@actions = actions
|
||||
end
|
||||
|
||||
def readline(*)
|
||||
@actions.shift
|
||||
end
|
||||
|
||||
def rewind
|
||||
@actions = @orig_actions.dup
|
||||
end
|
||||
end
|
||||
|
||||
class Pry
|
||||
|
||||
# null output class - doesn't write anywwhere.
|
||||
class NullOutput
|
||||
def self.puts(*) end
|
||||
def self.string(*) end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
CommandTester = Pry::CommandSet.new :test do
|
||||
command "command1", "command 1 test" do
|
||||
output.puts "command1"
|
||||
end
|
||||
|
||||
command "command2", "command 2 test" do |arg|
|
||||
output.puts arg
|
||||
end
|
||||
end
|
925
test/test_pry.rb
Normal file
925
test/test_pry.rb
Normal file
|
@ -0,0 +1,925 @@
|
|||
require 'helper'
|
||||
|
||||
puts "Ruby Version #{RUBY_VERSION}"
|
||||
puts "Testing Pry #{Pry::VERSION}"
|
||||
puts "With method_source version #{MethodSource::VERSION}"
|
||||
puts "--"
|
||||
|
||||
describe Pry do
|
||||
describe "open a Pry session on an object" do
|
||||
describe "rep" do
|
||||
before do
|
||||
class Hello
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
Object.send(:remove_const, :Hello)
|
||||
end
|
||||
|
||||
# bug fix for https://github.com/banister/pry/issues/93
|
||||
it 'should not leak pry constants into Object namespace' do
|
||||
input_string = "CommandContext"
|
||||
str_output = StringIO.new
|
||||
o = Object.new
|
||||
pry_tester = Pry.new(:input => StringIO.new(input_string),
|
||||
:output => str_output,
|
||||
:exception_handler => proc { |_, exception| @excep = exception },
|
||||
:print => proc {}
|
||||
).rep(o)
|
||||
|
||||
@excep.is_a?(NameError).should == true
|
||||
end
|
||||
|
||||
it 'should set an ivar on an object' do
|
||||
input_string = "@x = 10"
|
||||
input = InputTester.new(input_string)
|
||||
o = Object.new
|
||||
|
||||
pry_tester = Pry.new(:input => input, :output => Pry::NullOutput)
|
||||
pry_tester.rep(o)
|
||||
o.instance_variable_get(:@x).should == 10
|
||||
end
|
||||
|
||||
it 'should make self evaluate to the receiver of the rep session' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("self"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should =~ /#{o.to_s}/
|
||||
end
|
||||
|
||||
it 'should work with multi-line input' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("x = ", "1 + 4"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should =~ /5/
|
||||
end
|
||||
|
||||
it 'should define a nested class under Hello and not on top-level or Pry' do
|
||||
pry_tester = Pry.new(:input => InputTester.new("class Nested", "end"), :output => Pry::NullOutput)
|
||||
pry_tester.rep(Hello)
|
||||
Hello.const_defined?(:Nested).should == true
|
||||
end
|
||||
|
||||
it 'should suppress output if input ends in a ";" and is an Exception object (single line)' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("Exception.new;"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should == ""
|
||||
end
|
||||
|
||||
it 'should suppress output if input ends in a ";" (single line)' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("x = 5;"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should == ""
|
||||
end
|
||||
|
||||
|
||||
it 'should suppress output if input ends in a ";" (multi-line)' do
|
||||
o = Object.new
|
||||
str_output = StringIO.new
|
||||
|
||||
pry_tester = Pry.new(:input => InputTester.new("def self.blah", ":test", "end;"), :output => str_output)
|
||||
pry_tester.rep(o)
|
||||
str_output.string.should == ""
|
||||
end
|
||||
|
||||
it 'should be able to evaluate exceptions normally' do
|
||||
o = Exception.new
|
||||
str_output = StringIO.new
|
||||
|
||||
was_called = false
|
||||
pry_tester = Pry.new(:input => InputTester.new("self"),
|
||||
:output => str_output,
|
||||
:exception_handler => proc { was_called = true })
|
||||
|
||||
pry_tester.rep(o)
|
||||
was_called.should == false
|
||||
end
|
||||
|
||||
it 'should notice when exceptions are raised' do
|
||||
o = Exception.new
|
||||
str_output = StringIO.new
|
||||
|
||||
was_called = false
|
||||
pry_tester = Pry.new(:input => InputTester.new("raise self"),
|
||||
:output => str_output,
|
||||
:exception_handler => proc { was_called = true })
|
||||
|
||||
pry_tester.rep(o)
|
||||
was_called.should == true
|
||||
end
|
||||
end
|
||||
|
||||
describe "repl" do
|
||||
describe "basic functionality" do
|
||||
it 'should set an ivar on an object and exit the repl' do
|
||||
input_strings = ["@x = 10", "exit"]
|
||||
input = InputTester.new(*input_strings)
|
||||
|
||||
o = Object.new
|
||||
|
||||
pry_tester = Pry.start(o, :input => input, :output => Pry::NullOutput)
|
||||
|
||||
o.instance_variable_get(:@x).should == 10
|
||||
end
|
||||
end
|
||||
|
||||
describe "test loading rc files" do
|
||||
|
||||
before do
|
||||
Pry.instance_variable_set(:@initial_session, true)
|
||||
end
|
||||
|
||||
after do
|
||||
Pry::RC_FILES.clear
|
||||
Pry.config.should_load_rc = false
|
||||
end
|
||||
|
||||
it "should run the rc file only once" do
|
||||
Pry.config.should_load_rc = true
|
||||
Pry::RC_FILES << File.expand_path("../testrc", __FILE__)
|
||||
|
||||
Pry.start(self, :input => StringIO.new("exit\n"), :output => Pry::NullOutput)
|
||||
TEST_RC.should == [0]
|
||||
|
||||
Pry.start(self, :input => StringIO.new("exit\n"), :output => Pry::NullOutput)
|
||||
TEST_RC.should == [0]
|
||||
|
||||
Object.remove_const(:TEST_RC)
|
||||
end
|
||||
|
||||
it "should not run the rc file at all if Pry.config.should_load_rc is false" do
|
||||
Pry.config.should_load_rc = false
|
||||
Pry.start(self, :input => StringIO.new("exit\n"), :output => Pry::NullOutput)
|
||||
Object.const_defined?(:TEST_RC).should == false
|
||||
end
|
||||
|
||||
it "should not load the rc file if #repl method invoked" do
|
||||
Pry.config.should_load_rc = true
|
||||
Pry.new(:input => StringIO.new("exit\n"), :output => Pry::NullOutput).repl(self)
|
||||
Object.const_defined?(:TEST_RC).should == false
|
||||
Pry.config.should_load_rc = false
|
||||
end
|
||||
end
|
||||
|
||||
describe "nesting" do
|
||||
after do
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
|
||||
it 'should nest properly' do
|
||||
Pry.input = InputTester.new("pry", "pry", "pry", "\"nest:\#\{Pry.nesting.level\}\"", "exit_all")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
|
||||
o = Object.new
|
||||
|
||||
pry_tester = o.pry
|
||||
str_output.string.should =~ /nest:3/
|
||||
end
|
||||
end
|
||||
|
||||
describe "defining methods" do
|
||||
it 'should define a method on the singleton class of an object when performing "def meth;end" inside the object' do
|
||||
[Object.new, {}, []].each do |val|
|
||||
str_input = StringIO.new("def hello;end")
|
||||
Pry.new(:input => str_input, :output => StringIO.new).rep(val)
|
||||
|
||||
val.methods(false).map(&:to_sym).include?(:hello).should == true
|
||||
end
|
||||
end
|
||||
|
||||
it 'should define an instance method on the module when performing "def meth;end" inside the module' do
|
||||
str_input = StringIO.new("def hello;end")
|
||||
hello = Module.new
|
||||
Pry.new(:input => str_input, :output => StringIO.new).rep(hello)
|
||||
hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true
|
||||
end
|
||||
|
||||
it 'should define an instance method on the class when performing "def meth;end" inside the class' do
|
||||
str_input = StringIO.new("def hello;end")
|
||||
hello = Class.new
|
||||
Pry.new(:input => str_input, :output => StringIO.new).rep(hello)
|
||||
hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true
|
||||
end
|
||||
|
||||
it 'should define a method on the class of an object when performing "def meth;end" inside an immediate value or Numeric' do
|
||||
# should include float in here, but test fails for some reason
|
||||
# on 1.8.7, no idea why!
|
||||
[:test, 0, true, false, nil].each do |val|
|
||||
str_input = StringIO.new("def hello;end")
|
||||
Pry.new(:input => str_input, :output => StringIO.new).rep(val)
|
||||
val.class.instance_methods(false).map(&:to_sym).include?(:hello).should == true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "commands" do
|
||||
it 'should run a command with no parameter' do
|
||||
pry_tester = Pry.new
|
||||
pry_tester.commands = CommandTester
|
||||
pry_tester.input = InputTester.new("command1", "exit_all")
|
||||
pry_tester.commands = CommandTester
|
||||
|
||||
str_output = StringIO.new
|
||||
pry_tester.output = str_output
|
||||
|
||||
pry_tester.rep
|
||||
|
||||
str_output.string.should =~ /command1/
|
||||
end
|
||||
|
||||
it 'should run a command with one parameter' do
|
||||
pry_tester = Pry.new
|
||||
pry_tester.commands = CommandTester
|
||||
pry_tester.input = InputTester.new("command2 horsey", "exit_all")
|
||||
pry_tester.commands = CommandTester
|
||||
|
||||
str_output = StringIO.new
|
||||
pry_tester.output = str_output
|
||||
|
||||
pry_tester.rep
|
||||
|
||||
str_output.string.should =~ /horsey/
|
||||
end
|
||||
end
|
||||
|
||||
describe "Object#pry" do
|
||||
|
||||
after do
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
|
||||
it "should start a pry session on the receiver (first form)" do
|
||||
Pry.input = InputTester.new("self", "exit")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
|
||||
20.pry
|
||||
|
||||
str_output.string.should =~ /20/
|
||||
end
|
||||
|
||||
it "should start a pry session on the receiver (second form)" do
|
||||
Pry.input = InputTester.new("self", "exit")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
|
||||
pry 20
|
||||
|
||||
str_output.string.should =~ /20/
|
||||
end
|
||||
|
||||
it "should error if more than one argument is passed to Object#pry" do
|
||||
lambda { pry(20, :input => Readline) }.should.raise ArgumentError
|
||||
end
|
||||
end
|
||||
|
||||
describe "Pry.binding_for" do
|
||||
it 'should return TOPLEVEL_BINDING if parameter self is main' do
|
||||
_main_ = lambda { TOPLEVEL_BINDING.eval('self') }
|
||||
Pry.binding_for(_main_.call).is_a?(Binding).should == true
|
||||
Pry.binding_for(_main_.call).should == TOPLEVEL_BINDING
|
||||
Pry.binding_for(_main_.call).should == Pry.binding_for(_main_.call)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "test Pry defaults" do
|
||||
|
||||
after do
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
|
||||
describe "input" do
|
||||
|
||||
after do
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
|
||||
it 'should set the input default, and the default should be overridable' do
|
||||
Pry.input = InputTester.new("5")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
Pry.new.rep
|
||||
str_output.string.should =~ /5/
|
||||
|
||||
Pry.new(:input => InputTester.new("6")).rep
|
||||
str_output.string.should =~ /6/
|
||||
end
|
||||
|
||||
it 'should pass in the prompt if readline arity is 1' do
|
||||
Pry.prompt = proc { "A" }
|
||||
|
||||
arity_one_input = Class.new do
|
||||
attr_accessor :prompt
|
||||
def readline(prompt)
|
||||
@prompt = prompt
|
||||
"exit"
|
||||
end
|
||||
end.new
|
||||
|
||||
Pry.start(self, :input => arity_one_input, :output => Pry::NullOutput)
|
||||
arity_one_input.prompt.should == Pry.prompt.call
|
||||
end
|
||||
|
||||
it 'should not pass in the prompt if the arity is 0' do
|
||||
Pry.prompt = proc { "A" }
|
||||
|
||||
arity_zero_input = Class.new do
|
||||
def readline
|
||||
"exit"
|
||||
end
|
||||
end.new
|
||||
|
||||
lambda { Pry.start(self, :input => arity_zero_input, :output => Pry::NullOutput) }.should.not.raise Exception
|
||||
end
|
||||
|
||||
it 'should not pass in the prompt if the arity is -1' do
|
||||
Pry.prompt = proc { "A" }
|
||||
|
||||
arity_multi_input = Class.new do
|
||||
attr_accessor :prompt
|
||||
|
||||
def readline(*args)
|
||||
@prompt = args.first
|
||||
"exit"
|
||||
end
|
||||
end.new
|
||||
|
||||
Pry.start(self, :input => arity_multi_input, :output => Pry::NullOutput)
|
||||
arity_multi_input.prompt.should == nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
it 'should set the output default, and the default should be overridable' do
|
||||
Pry.input = InputTester.new("5", "6", "7")
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.output = str_output
|
||||
|
||||
Pry.new.rep
|
||||
str_output.string.should =~ /5/
|
||||
|
||||
Pry.new.rep
|
||||
str_output.string.should =~ /5\n.*6/
|
||||
|
||||
str_output2 = StringIO.new
|
||||
Pry.new(:output => str_output2).rep
|
||||
str_output2.string.should.not =~ /5\n.*6/
|
||||
str_output2.string.should =~ /7/
|
||||
end
|
||||
|
||||
describe "commands" do
|
||||
it 'should interpolate ruby code into commands' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command "hello", "", :keep_retval => true do |arg|
|
||||
arg
|
||||
end
|
||||
end
|
||||
|
||||
$test_interpolation = "bing"
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => StringIO.new('hello #{$test_interpolation}'), :output => str_output, :commands => klass).rep
|
||||
str_output.string.should =~ /bing/
|
||||
$test_interpolation = nil
|
||||
end
|
||||
|
||||
it 'should NOT interpolate ruby code into commands if :interpolate => false' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command "hello", "", :keep_retval => true, :interpolate => false do |arg|
|
||||
arg
|
||||
end
|
||||
end
|
||||
|
||||
$test_interpolation = "bing"
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => StringIO.new('hello #{$test_interpolation}'), :output => str_output, :commands => klass).rep
|
||||
str_output.string.should =~ /test_interpolation/
|
||||
$test_interpolation = nil
|
||||
end
|
||||
|
||||
it 'should create a command with a space in its name' do
|
||||
set = Pry::CommandSet.new do
|
||||
command "hello baby", "" do
|
||||
output.puts "hello baby command"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hello baby", "exit-all"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
|
||||
str_output.string.should =~ /hello baby command/
|
||||
end
|
||||
|
||||
it 'should create a command with a space in its name and pass an argument' do
|
||||
set = Pry::CommandSet.new do
|
||||
command "hello baby", "" do |arg|
|
||||
output.puts "hello baby command #{arg}"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hello baby john"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
|
||||
str_output.string.should =~ /hello baby command john/
|
||||
end
|
||||
|
||||
it 'should create a regex command and be able to invoke it' do
|
||||
set = Pry::CommandSet.new do
|
||||
command /hello(.)/, "" do
|
||||
c = captures.first
|
||||
output.puts "hello#{c}"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hello1"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
|
||||
str_output.string.should =~ /hello1/
|
||||
end
|
||||
|
||||
it 'should create a regex command and pass captures into the args list before regular arguments' do
|
||||
set = Pry::CommandSet.new do
|
||||
command /hello(.)/, "" do |c1, a1|
|
||||
output.puts "hello #{c1} #{a1}"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hello1 baby"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
|
||||
str_output.string.should =~ /hello 1 baby/
|
||||
end
|
||||
|
||||
it 'if a regex capture is missing it should be nil' do
|
||||
set = Pry::CommandSet.new do
|
||||
command /hello(.)?/, "" do |c1, a1|
|
||||
output.puts "hello #{c1.inspect} #{a1}"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("hello baby"), str_output) do
|
||||
Pry.new(:commands => set).rep
|
||||
end
|
||||
|
||||
str_output.string.should =~ /hello nil baby/
|
||||
end
|
||||
|
||||
it 'should create a command in a nested context and that command should be accessible from the parent' do
|
||||
redirect_pry_io(StringIO.new, StringIO.new) do
|
||||
str_input = StringIO.new("@x=nil\ncd 7\n_pry_.commands.instance_eval {\ncommand('bing') { |arg| run arg }\n}\ncd ..\nbing ls\nexit")
|
||||
str_output = StringIO.new
|
||||
Pry.input = str_input
|
||||
obj = Object.new
|
||||
Pry.new(:output => str_output).repl(obj)
|
||||
Pry.input = Readline
|
||||
str_output.string.should =~ /@x/
|
||||
end
|
||||
end
|
||||
|
||||
it 'should define a command that keeps its return value' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command "hello", "", :keep_retval => true do
|
||||
:kept_hello
|
||||
end
|
||||
end
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => klass).rep
|
||||
str_output.string.should =~ /:kept_hello/
|
||||
str_output.string.should =~ /=>/
|
||||
end
|
||||
|
||||
it 'should define a command that does NOT keep its return value' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command "hello", "", :keep_retval => false do
|
||||
:kept_hello
|
||||
end
|
||||
end
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => klass).rep
|
||||
(str_output.string =~ /:kept_hello/).should == nil
|
||||
str_output.string !~ /=>/
|
||||
end
|
||||
|
||||
it 'should set the commands default, and the default should be overridable' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command "hello" do
|
||||
output.puts "hello world"
|
||||
end
|
||||
end
|
||||
|
||||
Pry.commands = klass
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("hello"), :output => str_output).rep
|
||||
str_output.string.should =~ /hello world/
|
||||
|
||||
other_klass = Pry::CommandSet.new do
|
||||
command "goodbye", "" do
|
||||
output.puts "goodbye world"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
|
||||
Pry.new(:input => InputTester.new("goodbye"), :output => str_output, :commands => other_klass).rep
|
||||
str_output.string.should =~ /goodbye world/
|
||||
end
|
||||
|
||||
it 'should inherit "help" command from Pry::CommandBase' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command "h", "h command" do
|
||||
end
|
||||
end
|
||||
|
||||
klass.commands.keys.size.should == 3
|
||||
klass.commands.keys.include?("help").should == true
|
||||
klass.commands.keys.include?("install").should == true
|
||||
klass.commands.keys.include?("h").should == true
|
||||
end
|
||||
|
||||
it 'should inherit commands from Pry::Commands' do
|
||||
klass = Pry::CommandSet.new Pry::Commands do
|
||||
command "v" do
|
||||
end
|
||||
end
|
||||
|
||||
klass.commands.include?("nesting").should == true
|
||||
klass.commands.include?("jump-to").should == true
|
||||
klass.commands.include?("cd").should == true
|
||||
klass.commands.include?("v").should == true
|
||||
end
|
||||
|
||||
it 'should alias a command with another command' do
|
||||
klass = Pry::CommandSet.new do
|
||||
alias_command "help2", "help"
|
||||
end
|
||||
klass.commands["help2"].block.should == klass.commands["help"].block
|
||||
end
|
||||
|
||||
it 'should change description of a command using desc' do
|
||||
klass = Pry::CommandSet.new do; end
|
||||
orig = klass.commands["help"].description
|
||||
klass.instance_eval do
|
||||
desc "help", "blah"
|
||||
end
|
||||
klass.commands["help"].description.should.not == orig
|
||||
klass.commands["help"].description.should == "blah"
|
||||
end
|
||||
|
||||
it 'should run a command from within a command' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command "v" do
|
||||
output.puts "v command"
|
||||
end
|
||||
|
||||
command "run_v" do
|
||||
run "v"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("run_v"), :output => str_output, :commands => klass).rep
|
||||
str_output.string.should =~ /v command/
|
||||
end
|
||||
|
||||
it 'should run a regex command from within a command' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command /v(.*)?/ do |arg|
|
||||
output.puts "v #{arg}"
|
||||
end
|
||||
|
||||
command "run_v" do
|
||||
run "vbaby"
|
||||
end
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new("run_v"), str_output) do
|
||||
Pry.new(:commands => klass).rep
|
||||
end
|
||||
|
||||
str_output.string.should =~ /v baby/
|
||||
end
|
||||
|
||||
it 'should run a command from within a command with arguments' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command /v(\w+)/ do |arg1, arg2|
|
||||
output.puts "v #{arg1} #{arg2}"
|
||||
end
|
||||
|
||||
command "run_v_explicit_parameter" do
|
||||
run "vbaby", "param"
|
||||
end
|
||||
|
||||
command "run_v_embedded_parameter" do
|
||||
run "vbaby param"
|
||||
end
|
||||
end
|
||||
|
||||
["run_v_explicit_parameter", "run_v_embedded_parameter"].each do |cmd|
|
||||
str_output = StringIO.new
|
||||
redirect_pry_io(InputTester.new(cmd), str_output) do
|
||||
Pry.new(:commands => klass).rep
|
||||
end
|
||||
str_output.string.should =~ /v baby param/
|
||||
end
|
||||
end
|
||||
|
||||
it 'should enable an inherited method to access opts and output and target, due to instance_exec' do
|
||||
klass = Pry::CommandSet.new do
|
||||
command "v" do
|
||||
output.puts "#{target.eval('self')}"
|
||||
end
|
||||
end
|
||||
|
||||
child_klass = Pry::CommandSet.new klass do
|
||||
end
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:print => proc {}, :input => InputTester.new("v"),
|
||||
:output => str_output, :commands => child_klass).rep("john")
|
||||
|
||||
str_output.string.rstrip.should == "john"
|
||||
end
|
||||
|
||||
it 'should import commands from another command object' do
|
||||
klass = Pry::CommandSet.new do
|
||||
import_from Pry::Commands, "ls", "jump-to"
|
||||
end
|
||||
|
||||
klass.commands.include?("ls").should == true
|
||||
klass.commands.include?("jump-to").should == true
|
||||
end
|
||||
|
||||
it 'should delete some inherited commands when using delete method' do
|
||||
klass = Pry::CommandSet.new Pry::Commands do
|
||||
command "v" do
|
||||
end
|
||||
|
||||
delete "show-doc", "show-method"
|
||||
delete "ls"
|
||||
end
|
||||
|
||||
klass.commands.include?("nesting").should == true
|
||||
klass.commands.include?("jump-to").should == true
|
||||
klass.commands.include?("cd").should == true
|
||||
klass.commands.include?("v").should == true
|
||||
klass.commands.include?("show-doc").should == false
|
||||
klass.commands.include?("show-method").should == false
|
||||
klass.commands.include?("ls").should == false
|
||||
end
|
||||
|
||||
it 'should override some inherited commands' do
|
||||
klass = Pry::CommandSet.new Pry::Commands do
|
||||
command "jump-to" do
|
||||
output.puts "jump-to the music"
|
||||
end
|
||||
|
||||
command "help" do
|
||||
output.puts "help to the music"
|
||||
end
|
||||
end
|
||||
|
||||
# suppress evaluation output
|
||||
Pry.print = proc {}
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("jump-to"), :output => str_output, :commands => klass).rep
|
||||
str_output.string.rstrip.should == "jump-to the music"
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("help"), :output => str_output, :commands => klass).rep
|
||||
str_output.string.rstrip.should == "help to the music"
|
||||
|
||||
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
end
|
||||
|
||||
it "should set the print default, and the default should be overridable" do
|
||||
new_print = proc { |out, value| out.puts value }
|
||||
Pry.print = new_print
|
||||
|
||||
Pry.new.print.should == Pry.print
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("\"test\""), :output => str_output).rep
|
||||
str_output.string.should == "test\n"
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("\"test\""), :output => str_output,
|
||||
:print => proc { |out, value| out.puts value.reverse }).rep
|
||||
str_output.string.should == "tset\n"
|
||||
|
||||
Pry.new.print.should == Pry.print
|
||||
str_output = StringIO.new
|
||||
Pry.new(:input => InputTester.new("\"test\""), :output => str_output).rep
|
||||
str_output.string.should == "test\n"
|
||||
end
|
||||
|
||||
describe "pry return values" do
|
||||
it 'should return the target object' do
|
||||
Pry.start(self, :input => StringIO.new("exit"), :output => Pry::NullOutput).should == self
|
||||
end
|
||||
|
||||
it 'should return the parameter given to exit' do
|
||||
Pry.start(self, :input => StringIO.new("exit 10"), :output => Pry::NullOutput).should == 10
|
||||
end
|
||||
|
||||
it 'should return the parameter (multi word string) given to exit' do
|
||||
Pry.start(self, :input => StringIO.new("exit \"john mair\""), :output => Pry::NullOutput).should == "john mair"
|
||||
end
|
||||
|
||||
it 'should return the parameter (function call) given to exit' do
|
||||
Pry.start(self, :input => StringIO.new("exit 'abc'.reverse"), :output => Pry::NullOutput).should == 'cba'
|
||||
end
|
||||
|
||||
it 'should return the parameter (self) given to exit' do
|
||||
Pry.start("carl", :input => StringIO.new("exit self"), :output => Pry::NullOutput).should == "carl"
|
||||
end
|
||||
end
|
||||
|
||||
describe "prompts" do
|
||||
it 'should set the prompt default, and the default should be overridable (single prompt)' do
|
||||
new_prompt = proc { "test prompt> " }
|
||||
Pry.prompt = new_prompt
|
||||
|
||||
Pry.new.prompt.should == Pry.prompt
|
||||
Pry.new.select_prompt(true, 0).should == "test prompt> "
|
||||
Pry.new.select_prompt(false, 0).should == "test prompt> "
|
||||
|
||||
new_prompt = proc { "A" }
|
||||
pry_tester = Pry.new(:prompt => new_prompt)
|
||||
pry_tester.prompt.should == new_prompt
|
||||
pry_tester.select_prompt(true, 0).should == "A"
|
||||
pry_tester.select_prompt(false, 0).should == "A"
|
||||
|
||||
Pry.new.prompt.should == Pry.prompt
|
||||
Pry.new.select_prompt(true, 0).should == "test prompt> "
|
||||
Pry.new.select_prompt(false, 0).should == "test prompt> "
|
||||
end
|
||||
|
||||
it 'should set the prompt default, and the default should be overridable (multi prompt)' do
|
||||
new_prompt = [proc { "test prompt> " }, proc { "test prompt* " }]
|
||||
Pry.prompt = new_prompt
|
||||
|
||||
Pry.new.prompt.should == Pry.prompt
|
||||
Pry.new.select_prompt(true, 0).should == "test prompt> "
|
||||
Pry.new.select_prompt(false, 0).should == "test prompt* "
|
||||
|
||||
new_prompt = [proc { "A" }, proc { "B" }]
|
||||
pry_tester = Pry.new(:prompt => new_prompt)
|
||||
pry_tester.prompt.should == new_prompt
|
||||
pry_tester.select_prompt(true, 0).should == "A"
|
||||
pry_tester.select_prompt(false, 0).should == "B"
|
||||
|
||||
Pry.new.prompt.should == Pry.prompt
|
||||
Pry.new.select_prompt(true, 0).should == "test prompt> "
|
||||
Pry.new.select_prompt(false, 0).should == "test prompt* "
|
||||
end
|
||||
|
||||
describe 'storing and restoring the prompt' do
|
||||
before do
|
||||
make = lambda do |name,i|
|
||||
prompt = [ proc { "#{i}>" } , proc { "#{i+1}>" } ]
|
||||
(class << prompt; self; end).send(:define_method, :inspect) { "<Prompt-#{name}>" }
|
||||
prompt
|
||||
end
|
||||
@a , @b , @c = make[:a,0] , make[:b,1] , make[:c,2]
|
||||
@pry = Pry.new :prompt => @a
|
||||
end
|
||||
it 'should have a prompt stack' do
|
||||
@pry.push_prompt @b
|
||||
@pry.push_prompt @c
|
||||
@pry.prompt.should == @c
|
||||
@pry.pop_prompt
|
||||
@pry.prompt.should == @b
|
||||
@pry.pop_prompt
|
||||
@pry.prompt.should == @a
|
||||
end
|
||||
|
||||
it 'should restore overridden prompts when returning from file-mode' do
|
||||
pry = Pry.new :input => InputTester.new('shell-mode', 'shell-mode'),
|
||||
:prompt => [ proc { 'P>' } ] * 2
|
||||
pry.select_prompt(true, 0).should == "P>"
|
||||
pry.re
|
||||
pry.select_prompt(true, 0).should =~ /\Apry .* \$ \z/
|
||||
pry.re
|
||||
pry.select_prompt(true, 0).should == "P>"
|
||||
end
|
||||
|
||||
it '#pop_prompt should return the popped prompt' do
|
||||
@pry.push_prompt @b
|
||||
@pry.push_prompt @c
|
||||
@pry.pop_prompt.should == @c
|
||||
@pry.pop_prompt.should == @b
|
||||
end
|
||||
|
||||
it 'should not pop the last prompt' do
|
||||
@pry.push_prompt @b
|
||||
@pry.pop_prompt.should == @b
|
||||
@pry.pop_prompt.should == @a
|
||||
@pry.pop_prompt.should == @a
|
||||
@pry.prompt.should == @a
|
||||
end
|
||||
|
||||
describe '#prompt= should replace the current prompt with the new prompt' do
|
||||
it 'when only one prompt on the stack' do
|
||||
@pry.prompt = @b
|
||||
@pry.prompt.should == @b
|
||||
@pry.pop_prompt.should == @b
|
||||
@pry.pop_prompt.should == @b
|
||||
end
|
||||
it 'when several prompts on the stack' do
|
||||
@pry.push_prompt @b
|
||||
@pry.prompt = @c
|
||||
@pry.pop_prompt.should == @c
|
||||
@pry.pop_prompt.should == @a
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'should set the hooks default, and the default should be overridable' do
|
||||
Pry.input = InputTester.new("exit")
|
||||
Pry.hooks = {
|
||||
:before_session => proc { |out,_| out.puts "HELLO" },
|
||||
:after_session => proc { |out,_| out.puts "BYE" }
|
||||
}
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:output => str_output).repl
|
||||
str_output.string.should =~ /HELLO/
|
||||
str_output.string.should =~ /BYE/
|
||||
|
||||
Pry.input.rewind
|
||||
|
||||
str_output = StringIO.new
|
||||
Pry.new(:output => str_output,
|
||||
:hooks => {
|
||||
:before_session => proc { |out,_| out.puts "MORNING" },
|
||||
:after_session => proc { |out,_| out.puts "EVENING" }
|
||||
}
|
||||
).repl
|
||||
|
||||
str_output.string.should =~ /MORNING/
|
||||
str_output.string.should =~ /EVENING/
|
||||
|
||||
# try below with just defining one hook
|
||||
Pry.input.rewind
|
||||
str_output = StringIO.new
|
||||
Pry.new(:output => str_output,
|
||||
:hooks => {
|
||||
:before_session => proc { |out,_| out.puts "OPEN" }
|
||||
}
|
||||
).repl
|
||||
|
||||
str_output.string.should =~ /OPEN/
|
||||
|
||||
Pry.input.rewind
|
||||
str_output = StringIO.new
|
||||
Pry.new(:output => str_output,
|
||||
:hooks => {
|
||||
:after_session => proc { |out,_| out.puts "CLOSE" }
|
||||
}
|
||||
).repl
|
||||
|
||||
str_output.string.should =~ /CLOSE/
|
||||
|
||||
Pry.reset_defaults
|
||||
Pry.color = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue