195 lines
5.6 KiB
Ruby
195 lines
5.6 KiB
Ruby
# 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 invokation 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` mehod 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
|