This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Pry
|
||||
# A super-class of Commands with structure.
|
||||
#
|
||||
# This class implements the bare-minimum functionality that a command should
|
||||
# have, namely a --help switch, and then delegates actual processing to its
|
||||
# subclasses.
|
||||
#
|
||||
# Create subclasses using {Pry::CommandSet#create_command}, and override the
|
||||
# `options(opt)` method to set up an instance of Pry::Slop, and the `process`
|
||||
# method to actually run the command. If 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
|
||||
# Ensure that subclasses inherit the options, description and
|
||||
# match from a ClassCommand super class.
|
||||
def inherited(klass)
|
||||
klass.match match
|
||||
klass.description description
|
||||
klass.command_options options
|
||||
end
|
||||
|
||||
def source
|
||||
source_object.source
|
||||
end
|
||||
|
||||
def doc
|
||||
new.help
|
||||
end
|
||||
|
||||
def source_location
|
||||
source_object.source_location
|
||||
end
|
||||
|
||||
def source_file
|
||||
source_object.source_file
|
||||
end
|
||||
alias file source_file
|
||||
|
||||
def source_line
|
||||
source_object.source_line
|
||||
end
|
||||
alias line source_line
|
||||
|
||||
private
|
||||
|
||||
# The object used to extract the source for the command.
|
||||
#
|
||||
# This should be a `Pry::Method(block)` for a command made with `create_command`
|
||||
# and a `Pry::WrappedModule(self)` for a command that's a standard class.
|
||||
# @return [Pry::WrappedModule, Pry::Method]
|
||||
def source_object
|
||||
@source_object ||= if name =~ /^[A-Z]/
|
||||
Pry::WrappedModule(self)
|
||||
else
|
||||
Pry::Method(block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :opts
|
||||
attr_accessor :args
|
||||
|
||||
# Set up `opts` and `args`, and then call `process`.
|
||||
#
|
||||
# This method will display help if necessary.
|
||||
#
|
||||
# @param [Array<String>] args The arguments passed
|
||||
# @return [Object] The return value of `process` or VOID_VALUE
|
||||
def call(*args)
|
||||
setup
|
||||
|
||||
self.opts = slop
|
||||
self.args = opts.parse!(args)
|
||||
|
||||
if opts.present?(:help)
|
||||
output.puts slop.help
|
||||
void
|
||||
else
|
||||
process(*normalize_method_args(method(:process), args))
|
||||
end
|
||||
end
|
||||
|
||||
# Return the help generated by Pry::Slop for this command.
|
||||
def help
|
||||
slop.help
|
||||
end
|
||||
|
||||
# Return an instance of Pry::Slop that can parse either subcommands or the
|
||||
# options that this command accepts.
|
||||
def slop
|
||||
Pry::Slop.new do |opt|
|
||||
opt.banner(unindent(self.class.banner))
|
||||
subcommands(opt)
|
||||
options(opt)
|
||||
opt.on :h, :help, 'Show this message.'
|
||||
end
|
||||
end
|
||||
|
||||
# Generate shell completions
|
||||
# @param [String] search The line typed so far
|
||||
# @return [Array<String>] the words to complete
|
||||
def complete(search)
|
||||
slop.flat_map do |opt|
|
||||
[opt.long && "--#{opt.long} " || opt.short && "-#{opt.short}"]
|
||||
end.compact + super
|
||||
end
|
||||
|
||||
# A method called just before `options(opt)` as part of `call`.
|
||||
#
|
||||
# This method can be used to set up any context your command needs to run,
|
||||
# for example requiring gems, or setting default values for options.
|
||||
#
|
||||
# @example
|
||||
# def setup
|
||||
# require 'gist'
|
||||
# @action = :method
|
||||
# end
|
||||
def setup; end
|
||||
|
||||
# A method to setup Pry::Slop commands so it can parse the subcommands your
|
||||
# command expects. If you need to set up default values, use `setup`
|
||||
# instead.
|
||||
#
|
||||
# @example A minimal example
|
||||
# def subcommands(cmd)
|
||||
# cmd.command :download do |opt|
|
||||
# description 'Downloads a content from a server'
|
||||
#
|
||||
# opt.on :verbose, 'Use verbose output'
|
||||
#
|
||||
# run do |options, arguments|
|
||||
# ContentDownloader.download(options, arguments)
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @example Define the invocation block anywhere you want
|
||||
# def subcommands(cmd)
|
||||
# cmd.command :download do |opt|
|
||||
# description 'Downloads a content from a server'
|
||||
#
|
||||
# opt.on :verbose, 'Use verbose output'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def process
|
||||
# # Perform calculations...
|
||||
# opts.fetch_command(:download).run do |options, arguments|
|
||||
# ContentDownloader.download(options, arguments)
|
||||
# end
|
||||
# # More calculations...
|
||||
# end
|
||||
def subcommands(cmd); end
|
||||
|
||||
# A method to setup Pry::Slop so it can parse the options your command expects.
|
||||
#
|
||||
# @note Please don't do anything side-effecty in the main part of this
|
||||
# method, as it may be called by Pry at any time for introspection reasons.
|
||||
# If you need to set up default values, use `setup` instead.
|
||||
#
|
||||
# @example
|
||||
# def options(opt)
|
||||
# opt.banner "Gists methods or classes"
|
||||
# opt.on(:c, :class, "gist a class") do
|
||||
# @action = :class
|
||||
# end
|
||||
# end
|
||||
def options(opt); end
|
||||
|
||||
# The actual body of your command should go here.
|
||||
#
|
||||
# The `opts` method can be called to get the options that Pry::Slop has passed,
|
||||
# and `args` gives the remaining, unparsed arguments.
|
||||
#
|
||||
# The return value of this method is discarded unless the command was
|
||||
# created with `:keep_retval => true`, in which case it is returned to the
|
||||
# repl.
|
||||
#
|
||||
# @example
|
||||
# def process
|
||||
# if opts.present?(:class)
|
||||
# gist_class
|
||||
# else
|
||||
# gist_method
|
||||
# end
|
||||
# end
|
||||
def process
|
||||
raise CommandError, "command '#{command_name}' not implemented"
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user