mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
Remove parse_options! API
Having classy commands means it's much easier to implement, so we just require those instead.
This commit is contained in:
parent
80d50c9bb4
commit
bb48077241
7 changed files with 143 additions and 143 deletions
|
@ -211,6 +211,13 @@ class Pry
|
|||
# necessary, you can also override {setup} which will be called before {options}, for example to
|
||||
# require any gems your command needs to run, or to set up state.
|
||||
class ClassCommand < Command
|
||||
class << self
|
||||
def banner(arg=nil)
|
||||
@banner = arg if arg
|
||||
@banner || description
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :opts
|
||||
attr_accessor :args
|
||||
|
||||
|
@ -242,6 +249,7 @@ class Pry
|
|||
# Return an instance of Slop that can parse the options that this command accepts.
|
||||
def slop
|
||||
Slop.new do |opt|
|
||||
opt.banner(unindent(self.class.banner))
|
||||
options(opt)
|
||||
opt.on(:h, :help, "Show this message.")
|
||||
end
|
||||
|
@ -274,7 +282,6 @@ class Pry
|
|||
# end
|
||||
def options(opt); end
|
||||
|
||||
|
||||
# The actual body of your command should go here.
|
||||
#
|
||||
# The {opts} mehod can be called to get the options that Slop has passed,
|
||||
|
|
|
@ -115,7 +115,7 @@ class Pry
|
|||
def command_class(name, description="No description.", options={}, &block)
|
||||
options = default_options(name).merge!(options)
|
||||
|
||||
commands[name] = Pry::ClassCommand.subclass(name, description, options, helper_module)
|
||||
commands[name] = Pry::ClassCommand.subclass(name, description, options, helper_module, &block)
|
||||
commands[name].class_eval(&block)
|
||||
commands[name]
|
||||
end
|
||||
|
|
|
@ -3,56 +3,72 @@ class Pry
|
|||
|
||||
Documentation = Pry::CommandSet.new do
|
||||
|
||||
command "ri", "View ri documentation. e.g `ri Array#each`" do |*args|
|
||||
run ".ri", *args
|
||||
command_class "ri", "View ri documentation. e.g `ri Array#each`" do
|
||||
banner <<-BANNER
|
||||
Usage: ri [spec]
|
||||
e.g. ri Array#each
|
||||
|
||||
Relies on the ri executable being available. See also: show-doc.
|
||||
BANNER
|
||||
|
||||
def process
|
||||
run ".ri", *args
|
||||
end
|
||||
end
|
||||
|
||||
command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info. Aliases: \?", :shellwords => false do |*args|
|
||||
opts, meth = parse_options!(args, :method_object) do |opt|
|
||||
opt.banner unindent <<-USAGE
|
||||
Usage: show-doc [OPTIONS] [METH]
|
||||
Show the comments above method METH. Tries instance methods first and then methods by default.
|
||||
e.g show-doc hello_method
|
||||
USAGE
|
||||
command_class "show-doc", "Show the comments above METH. Type `show-doc --help` for more info. Aliases: \?", :shellwords => false do |*args|
|
||||
banner <<-BANNER
|
||||
Usage: show-doc [OPTIONS] [METH]
|
||||
Show the comments above method METH. Tries instance methods first and then methods by default.
|
||||
e.g show-doc hello_method
|
||||
BANNER
|
||||
|
||||
def options(opt)
|
||||
method_options(opt)
|
||||
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
||||
end
|
||||
|
||||
raise Pry::CommandError, "No documentation found." if meth.doc.nil? || meth.doc.empty?
|
||||
def process
|
||||
meth = method_object
|
||||
raise Pry::CommandError, "No documentation found." if meth.doc.nil? || meth.doc.empty?
|
||||
|
||||
doc = process_comment_markup(meth.doc, meth.source_type)
|
||||
output.puts make_header(meth, doc)
|
||||
output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
|
||||
output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
|
||||
output.puts "#{text.bold("Signature:")} #{meth.signature}"
|
||||
output.puts
|
||||
render_output(opts.present?(:flood), false, doc)
|
||||
doc = process_comment_markup(meth.doc, meth.source_type)
|
||||
output.puts make_header(meth, doc)
|
||||
output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
|
||||
output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
|
||||
output.puts "#{text.bold("Signature:")} #{meth.signature}"
|
||||
output.puts
|
||||
render_output(opts.present?(:flood), false, doc)
|
||||
end
|
||||
end
|
||||
|
||||
alias_command "?", "show-doc"
|
||||
|
||||
command "stat", "View method information and set _file_ and _dir_ locals. Type `stat --help` for more info.", :shellwords => false do |*args|
|
||||
target = target()
|
||||
|
||||
opts, meth = parse_options!(args, :method_object) do |opt|
|
||||
opt.banner unindent <<-USAGE
|
||||
command_class "stat", "View method information and set _file_ and _dir_ locals. Type `stat --help` for more info.", :shellwords => false do |*args|
|
||||
banner <<-BANNER
|
||||
Usage: stat [OPTIONS] [METH]
|
||||
Show method information for method METH and set _file_ and _dir_ locals.
|
||||
e.g: stat hello_method
|
||||
USAGE
|
||||
BANNER
|
||||
|
||||
def options(opt)
|
||||
method_options(opt)
|
||||
end
|
||||
|
||||
output.puts unindent <<-EOS
|
||||
Method Information:
|
||||
--
|
||||
Name: #{meth.name}
|
||||
Owner: #{meth.owner ? meth.owner : "Unknown"}
|
||||
Visibility: #{meth.visibility}
|
||||
Type: #{meth.is_a?(::Method) ? "Bound" : "Unbound"}
|
||||
Arity: #{meth.arity}
|
||||
Method Signature: #{meth.signature}
|
||||
Source Location: #{meth.source_location ? meth.source_location.join(":") : "Not found."}
|
||||
EOS
|
||||
def process
|
||||
meth = method_object
|
||||
output.puts unindent <<-EOS
|
||||
Method Information:
|
||||
--
|
||||
Name: #{meth.name}
|
||||
Owner: #{meth.owner ? meth.owner : "Unknown"}
|
||||
Visibility: #{meth.visibility}
|
||||
Type: #{meth.is_a?(::Method) ? "Bound" : "Unbound"}
|
||||
Arity: #{meth.arity}
|
||||
Method Signature: #{meth.signature}
|
||||
Source Location: #{meth.source_location ? meth.source_location.join(":") : "Not found."}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
command_class "gist", "Gist a method or expression history to github. Type `gist --help` for more info.", :requires_gem => "gist", :shellwords => false do
|
||||
|
|
|
@ -5,40 +5,44 @@ class Pry
|
|||
|
||||
Introspection = Pry::CommandSet.new do
|
||||
|
||||
command "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source", :shellwords => false do |*args|
|
||||
opts, meth = parse_options!(args, :method_object) do |opt|
|
||||
opt.banner unindent <<-USAGE
|
||||
Usage: show-method [OPTIONS] [METH]
|
||||
Show the source for method METH. Tries instance methods first and then methods by default.
|
||||
e.g: show-method hello_method
|
||||
USAGE
|
||||
command_class "show-method", "Show the source for METH. Type `show-method --help` for more info. Aliases: $, show-source", :shellwords => false do |*args|
|
||||
banner <<-BANNER
|
||||
Usage: show-method [OPTIONS] [METH]
|
||||
Show the source for method METH. Tries instance methods first and then methods by default.
|
||||
e.g: show-method hello_method
|
||||
BANNER
|
||||
|
||||
def options(opt)
|
||||
method_options(opt)
|
||||
opt.on :l, "line-numbers", "Show line numbers."
|
||||
opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)."
|
||||
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
||||
end
|
||||
|
||||
raise CommandError, "Could not find method source" unless meth.source
|
||||
def process
|
||||
meth = method_object
|
||||
raise CommandError, "Could not find method source" unless meth.source
|
||||
|
||||
output.puts make_header(meth)
|
||||
output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
|
||||
output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
|
||||
output.puts
|
||||
output.puts make_header(meth)
|
||||
output.puts "#{text.bold("Owner:")} #{meth.owner || "N/A"}"
|
||||
output.puts "#{text.bold("Visibility:")} #{meth.visibility}"
|
||||
output.puts
|
||||
|
||||
if Pry.color
|
||||
code = CodeRay.scan(meth.source, meth.source_type).term
|
||||
else
|
||||
code = meth.source
|
||||
if Pry.color
|
||||
code = CodeRay.scan(meth.source, meth.source_type).term
|
||||
else
|
||||
code = meth.source
|
||||
end
|
||||
|
||||
start_line = false
|
||||
if opts.present?(:'base-one')
|
||||
start_line = 1
|
||||
elsif opts.present?(:'line-numbers')
|
||||
start_line = meth.source_line || 1
|
||||
end
|
||||
|
||||
render_output(opts.present?(:flood), start_line, code)
|
||||
end
|
||||
|
||||
start_line = false
|
||||
if opts.present?(:'base-one')
|
||||
start_line = 1
|
||||
elsif opts.present?(:'line-numbers')
|
||||
start_line = meth.source_line || 1
|
||||
end
|
||||
|
||||
render_output(opts.present?(:flood), start_line, code)
|
||||
end
|
||||
|
||||
alias_command "show-source", "show-method"
|
||||
|
@ -199,64 +203,63 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
command "edit-method", "Edit a method. Type `edit-method --help` for more info.", :shellwords => false do |*args|
|
||||
target = target()
|
||||
command_class "edit-method", "Edit a method. Type `edit-method --help` for more info.", :shellwords => false do |*args|
|
||||
|
||||
opts, meth = parse_options!(args, :method_object) do |opt|
|
||||
opt.banner unindent <<-USAGE
|
||||
def options(opt)
|
||||
opt.banner unindent <<-BANNER
|
||||
Usage: edit-method [OPTIONS] [METH]
|
||||
Edit the method METH in an editor.
|
||||
Ensure #{text.bold("Pry.config.editor")} is set to your editor of choice.
|
||||
e.g: edit-method hello_method
|
||||
USAGE
|
||||
|
||||
BANNER
|
||||
method_options(opt)
|
||||
opt.on :n, "no-reload", "Do not automatically reload the method's file after editing."
|
||||
opt.on "no-jump", "Do not fast forward editor to first line of method."
|
||||
opt.on :p, :patch, "Instead of editing the method's file, try to edit in a tempfile and apply as a monkey patch."
|
||||
opt.on :h, :help, "This message." do
|
||||
output.puts opt.help
|
||||
end
|
||||
end
|
||||
|
||||
if !Pry.config.editor
|
||||
raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
|
||||
end
|
||||
|
||||
if opts.present?(:patch) || meth.dynamically_defined?
|
||||
lines = meth.source.lines.to_a
|
||||
|
||||
if ((original_name = meth.original_name) &&
|
||||
lines[0] =~ /^def (?:.*?\.)?#{original_name}(?=[\(\s;]|$)/)
|
||||
lines[0] = "def #{original_name}#{$'}"
|
||||
else
|
||||
raise CommandError, "Pry can only patch methods created with the `def` keyword."
|
||||
def process
|
||||
meth = method_object
|
||||
if !Pry.config.editor
|
||||
raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
|
||||
end
|
||||
|
||||
temp_file do |f|
|
||||
f.puts lines.join
|
||||
f.flush
|
||||
invoke_editor(f.path, 0)
|
||||
if opts.present?(:patch) || meth.dynamically_defined?
|
||||
lines = meth.source.lines.to_a
|
||||
|
||||
if meth.alias?
|
||||
with_method_transaction(original_name, meth.owner) do
|
||||
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
|
||||
Pry.binding_for(meth.owner).eval("alias #{meth.name} #{original_name}")
|
||||
end
|
||||
if ((original_name = meth.original_name) &&
|
||||
lines[0] =~ /^def (?:.*?\.)?#{original_name}(?=[\(\s;]|$)/)
|
||||
lines[0] = "def #{original_name}#{$'}"
|
||||
else
|
||||
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
|
||||
raise CommandError, "Pry can only patch methods created with the `def` keyword."
|
||||
end
|
||||
|
||||
temp_file do |f|
|
||||
f.puts lines.join
|
||||
f.flush
|
||||
invoke_editor(f.path, 0)
|
||||
|
||||
if meth.alias?
|
||||
with_method_transaction(original_name, meth.owner) do
|
||||
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
|
||||
Pry.binding_for(meth.owner).eval("alias #{meth.name} #{original_name}")
|
||||
end
|
||||
else
|
||||
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
next
|
||||
end
|
||||
|
||||
if meth.source_type == :c
|
||||
raise CommandError, "Can't edit a C method."
|
||||
else
|
||||
file, line = meth.source_file, meth.source_line
|
||||
if meth.source_type == :c
|
||||
raise CommandError, "Can't edit a C method."
|
||||
else
|
||||
file, line = meth.source_file, meth.source_line
|
||||
|
||||
invoke_editor(file, opts["no-jump"] ? 0 : line)
|
||||
silence_warnings do
|
||||
load file if !opts.present?(:'no-jump') && !Pry.config.disable_auto_reload
|
||||
invoke_editor(file, opts["no-jump"] ? 0 : line)
|
||||
silence_warnings do
|
||||
load file if !opts.present?(:'no-jump') && !Pry.config.disable_auto_reload
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,8 +33,6 @@ class Pry
|
|||
opt.on :i, "ivars", "Show instance variables (in blue) and class variables (in bright blue)"
|
||||
|
||||
opt.on :G, "grep", "Filter output by regular expression", :optional => false
|
||||
|
||||
opt.on :h, "help", "Show help"
|
||||
end
|
||||
|
||||
def process
|
||||
|
|
|
@ -3,54 +3,20 @@ class Pry
|
|||
module OptionsHelpers
|
||||
module_function
|
||||
|
||||
# Use Slop to parse the arguments given.
|
||||
#
|
||||
# @param [Array] args The options are stripped out by Slop.
|
||||
# @param [*Symbol] extras Extra features you want returned.
|
||||
# @param [&Block] used to add custom arguments to Slop.
|
||||
#
|
||||
# @option [Extra] :method_object Returns a method object.
|
||||
#
|
||||
# @return Slop::Options iff you don't pass any extras.
|
||||
# @return [Array] If you do pass extras, an array is returned where the first argument is the
|
||||
# Slop::Options object, and the remainder are the extras you requested in order.
|
||||
#
|
||||
def parse_options!(args, *extras, &block)
|
||||
opts = Slop.parse!(args) do |opt|
|
||||
extras.each{ |extra| send(:"add_#{extra}_options", opt) }
|
||||
|
||||
yield opt
|
||||
|
||||
opt.on :h, :help, "This message" do
|
||||
output.puts opt.help
|
||||
throw :command_done
|
||||
end
|
||||
end
|
||||
|
||||
if extras.empty?
|
||||
opts
|
||||
else
|
||||
[opts] + extras.map{ |extra| send(:"process_#{extra}_options", args, opts) }
|
||||
end
|
||||
end
|
||||
|
||||
# Add the method object options to an unused Slop instance.
|
||||
def add_method_object_options(opt)
|
||||
# Add method options to the Slop instance
|
||||
def method_options(opt)
|
||||
@method_target = target
|
||||
opt.on :M, "instance-methods", "Operate on instance methods."
|
||||
opt.on :m, :methods, "Operate on methods."
|
||||
opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors."
|
||||
opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors.", :as => :count
|
||||
opt.on :c, :context, "Select object context to run under.", true do |context|
|
||||
@method_target = Pry.binding_for(target.eval(context))
|
||||
end
|
||||
end
|
||||
|
||||
# Add the derived :method_object option to a used Slop instance.
|
||||
def process_method_object_options(args, opts)
|
||||
# TODO: de-hack when we upgrade Slop: https://github.com/injekt/slop/pull/30
|
||||
opts.options[:super].force_argument_value opts.options[:super].count if opts.present?(:super)
|
||||
|
||||
get_method_or_raise(args.empty? ? nil : args.join(" "), @method_target,
|
||||
# Get the method object parsed by the slop instance
|
||||
def method_object
|
||||
@method_object ||= get_method_or_raise(args.empty? ? nil : args.join(" "), @method_target,
|
||||
:super => opts[:super],
|
||||
:instance => opts.present?(:'instance-methods') && !opts.present?(:'methods'),
|
||||
:methods => opts.present?(:'methods') && !opts.present?(:'instance-methods')
|
||||
|
|
|
@ -125,6 +125,16 @@ describe "Pry::Command" do
|
|||
|
||||
mock_command(cmd, %w(--help)).output.should =~ /Total Perspective Vortex/
|
||||
end
|
||||
|
||||
it 'should use the banner provided' do
|
||||
cmd = @set.command_class 'deep-thought', "The second-best computer ever" do
|
||||
banner <<-BANNER
|
||||
Who's merest operational parameters, I am not worthy to compute.
|
||||
BANNER
|
||||
end
|
||||
|
||||
mock_command(cmd, %w(--help)).output.should =~ /Who\'s merest/
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue