pry/lib/pry/class_command.rb

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