mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
Upgrade to Slop v3
This commit is contained in:
parent
493c085888
commit
6bd1627022
4 changed files with 810 additions and 928 deletions
1366
lib/pry/slop.rb
1366
lib/pry/slop.rb
File diff suppressed because it is too large
Load diff
177
lib/pry/slop/commands.rb
Normal file
177
lib/pry/slop/commands.rb
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
class Pry
|
||||||
|
class Slop
|
||||||
|
class Commands
|
||||||
|
include Enumerable
|
||||||
|
|
||||||
|
attr_reader :config, :commands
|
||||||
|
attr_writer :banner
|
||||||
|
|
||||||
|
# Create a new instance of Slop::Commands and optionally build
|
||||||
|
# Slop instances via a block. Any configuration options used in
|
||||||
|
# this method will be the default configuration options sent to
|
||||||
|
# each Slop object created.
|
||||||
|
#
|
||||||
|
# config - An optional configuration Hash.
|
||||||
|
# block - Optional block used to define commands.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# commands = Slop::Commands.new do
|
||||||
|
# on :new do
|
||||||
|
# on '-o', '--outdir=', 'The output directory'
|
||||||
|
# on '-v', '--verbose', 'Enable verbose mode'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# on :generate do
|
||||||
|
# on '--assets', 'Generate assets', :default => true
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# global do
|
||||||
|
# on '-D', '--debug', 'Enable debug mode', :default => false
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# commands[:new].class #=> Slop
|
||||||
|
# commands.parse
|
||||||
|
#
|
||||||
|
def initialize(config = {}, &block)
|
||||||
|
@config = config
|
||||||
|
@commands = {}
|
||||||
|
@banner = nil
|
||||||
|
|
||||||
|
if block_given?
|
||||||
|
block.arity == 1 ? yield(self) : instance_eval(&block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Optionally set the banner for this command help output.
|
||||||
|
#
|
||||||
|
# banner - The String text to set the banner.
|
||||||
|
#
|
||||||
|
# Returns the String banner if one is set.
|
||||||
|
def banner(banner = nil)
|
||||||
|
@banner = banner if banner
|
||||||
|
@banner
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add a Slop instance for a specific command.
|
||||||
|
#
|
||||||
|
# command - A String or Symbol key used to identify this command.
|
||||||
|
# config - A Hash of configuration options to pass to Slop.
|
||||||
|
# block - An optional block used to pass options to Slop.
|
||||||
|
#
|
||||||
|
# Returns the newly created Slop instance mapped to command.
|
||||||
|
def on(command, config = {}, &block)
|
||||||
|
commands[command.to_s] = Slop.new(@config.merge(config), &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add a Slop instance used when no other commands exist.
|
||||||
|
#
|
||||||
|
# config - A Hash of configuration options to pass to Slop.
|
||||||
|
# block - An optional block used to pass options to Slop.
|
||||||
|
#
|
||||||
|
# Returns the newly created Slop instance mapped to default.
|
||||||
|
def default(config = {}, &block)
|
||||||
|
on('default', config, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add a global Slop instance.
|
||||||
|
#
|
||||||
|
# config - A Hash of configuration options to pass to Slop.
|
||||||
|
# block - An optional block used to pass options to Slop.
|
||||||
|
#
|
||||||
|
# Returns the newly created Slop instance mapped to global.
|
||||||
|
def global(config = {}, &block)
|
||||||
|
on('global', config, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Fetch the instance of Slop tied to a command.
|
||||||
|
#
|
||||||
|
# key - The String or Symbol key used to locate this command.
|
||||||
|
#
|
||||||
|
# Returns the Slop instance if this key is found, nil otherwise.
|
||||||
|
def [](key)
|
||||||
|
commands[key.to_s]
|
||||||
|
end
|
||||||
|
alias get []
|
||||||
|
|
||||||
|
# Parse a list of items.
|
||||||
|
#
|
||||||
|
# items - The Array of items to parse.
|
||||||
|
#
|
||||||
|
# Returns the original Array of items.
|
||||||
|
def parse(items = ARGV)
|
||||||
|
parse_items(items)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Enumerable interface.
|
||||||
|
def each(&block)
|
||||||
|
@commands.each(&block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse a list of items, removing any options or option arguments found.
|
||||||
|
#
|
||||||
|
# items - The Array of items to parse.
|
||||||
|
#
|
||||||
|
# Returns the original Array of items with options removed.
|
||||||
|
def parse!(items = ARGV)
|
||||||
|
parse_items(items, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a nested Hash with Slop options and values. See Slop#to_hash.
|
||||||
|
def to_hash
|
||||||
|
Hash[commands.map { |k, v| [k.to_sym, v.to_hash] }]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the help String.
|
||||||
|
def to_s
|
||||||
|
defaults = commands.delete('default')
|
||||||
|
globals = commands.delete('global')
|
||||||
|
helps = commands.reject { |_, v| v.options.none? }
|
||||||
|
helps.merge!('Global options' => globals.to_s) if globals
|
||||||
|
helps.merge!('Other options' => defaults.to_s) if defaults
|
||||||
|
banner = @banner ? "#{@banner}\n" : ""
|
||||||
|
banner + helps.map { |key, opts| " #{key}\n#{opts}" }.join("\n\n")
|
||||||
|
end
|
||||||
|
alias help to_s
|
||||||
|
|
||||||
|
# Returns the inspection String.
|
||||||
|
def inspect
|
||||||
|
"#<Slop::Commands #{config.inspect} #{commands.values.map(&:inspect)}>"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Parse a list of items.
|
||||||
|
#
|
||||||
|
# items - The Array of items to parse.
|
||||||
|
# bang - When true, #parse! will be called instead of #parse.
|
||||||
|
#
|
||||||
|
# Returns the Array of items (with options removed if bang == true).
|
||||||
|
def parse_items(items, bang = false)
|
||||||
|
if opts = commands[items[0].to_s]
|
||||||
|
items.shift
|
||||||
|
bang ? opts.parse!(items) : opts.parse(items)
|
||||||
|
execute_global_opts(items, bang)
|
||||||
|
else
|
||||||
|
if opts = commands['default']
|
||||||
|
bang ? opts.parse!(items) : opts.parse(items)
|
||||||
|
else
|
||||||
|
if config[:strict] && items[0]
|
||||||
|
raise InvalidCommandError, "Unknown command `#{items[0]}`"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
execute_global_opts(items, bang)
|
||||||
|
end
|
||||||
|
items
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_global_opts(items, bang)
|
||||||
|
if global_opts = commands['global']
|
||||||
|
bang ? global_opts.parse!(items) : global_opts.parse(items)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
192
lib/pry/slop/option.rb
Normal file
192
lib/pry/slop/option.rb
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
class Pry
|
||||||
|
class Slop
|
||||||
|
class Option
|
||||||
|
|
||||||
|
# The default Hash of configuration options this class uses.
|
||||||
|
DEFAULT_OPTIONS = {
|
||||||
|
:argument => false,
|
||||||
|
:optional_argument => false,
|
||||||
|
:tail => false,
|
||||||
|
:default => nil,
|
||||||
|
:callback => nil,
|
||||||
|
:delimiter => ',',
|
||||||
|
:limit => 0,
|
||||||
|
:match => nil,
|
||||||
|
:optional => true,
|
||||||
|
:required => false,
|
||||||
|
:as => String,
|
||||||
|
:autocreated => false
|
||||||
|
}
|
||||||
|
|
||||||
|
attr_reader :short, :long, :description, :config, :types
|
||||||
|
attr_accessor :count
|
||||||
|
attr_writer :value
|
||||||
|
|
||||||
|
# Incapsulate internal option information, mainly used to store
|
||||||
|
# option specific configuration data, most of the meat of this
|
||||||
|
# class is found in the #value method.
|
||||||
|
#
|
||||||
|
# slop - The instance of Slop tied to this Option.
|
||||||
|
# short - The String or Symbol short flag.
|
||||||
|
# long - The String or Symbol long flag.
|
||||||
|
# description - The String description text.
|
||||||
|
# config - A Hash of configuration options.
|
||||||
|
# block - An optional block used as a callback.
|
||||||
|
def initialize(slop, short, long, description, config = {}, &block)
|
||||||
|
@slop = slop
|
||||||
|
@short = short
|
||||||
|
@long = long
|
||||||
|
@description = description
|
||||||
|
@config = DEFAULT_OPTIONS.merge(config)
|
||||||
|
@count = 0
|
||||||
|
@callback = block_given? ? block : config[:callback]
|
||||||
|
|
||||||
|
@types = {
|
||||||
|
:string => proc { |v| v.to_s },
|
||||||
|
:symbol => proc { |v| v.to_sym },
|
||||||
|
:integer => proc { |v| value_to_integer(v) },
|
||||||
|
:float => proc { |v| value_to_float(v) },
|
||||||
|
:array => proc { |v| v.split(@config[:delimiter], @config[:limit]) },
|
||||||
|
:range => proc { |v| value_to_range(v) },
|
||||||
|
:count => proc { |v| @count }
|
||||||
|
}
|
||||||
|
|
||||||
|
if long && long.size > @slop.config[:longest_flag]
|
||||||
|
@slop.config[:longest_flag] = long.size
|
||||||
|
end
|
||||||
|
|
||||||
|
@config.each_key do |key|
|
||||||
|
self.class.send(:define_method, "#{key}?") { !!@config[key] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if this option expects an argument.
|
||||||
|
def expects_argument?
|
||||||
|
config[:argument] && config[:argument] != :optional
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if this option accepts an optional argument.
|
||||||
|
def accepts_optional_argument?
|
||||||
|
config[:optional_argument] || config[:argument] == :optional
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the String flag of this option. Preferring the long flag.
|
||||||
|
def key
|
||||||
|
long || short
|
||||||
|
end
|
||||||
|
|
||||||
|
# Call this options callback if one exists, and it responds to call().
|
||||||
|
#
|
||||||
|
# Returns nothing.
|
||||||
|
def call(*objects)
|
||||||
|
@callback.call(*objects) if @callback.respond_to?(:call)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Fetch the argument value for this option.
|
||||||
|
#
|
||||||
|
# Returns the Object once any type conversions have taken place.
|
||||||
|
def value
|
||||||
|
value = @value.nil? ? config[:default] : @value
|
||||||
|
|
||||||
|
if [true, false, nil].include?(value) && config[:as].to_s != 'count'
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
type = config[:as]
|
||||||
|
if type.respond_to?(:call)
|
||||||
|
type.call(value)
|
||||||
|
else
|
||||||
|
if callable = types[type.to_s.downcase.to_sym]
|
||||||
|
callable.call(value)
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the help String for this option.
|
||||||
|
def to_s
|
||||||
|
return config[:help] if config[:help].respond_to?(:to_str)
|
||||||
|
|
||||||
|
out = " "
|
||||||
|
out += short ? "-#{short}, " : ' ' * 4
|
||||||
|
|
||||||
|
if long
|
||||||
|
out += "--#{long}"
|
||||||
|
size = long.size
|
||||||
|
diff = @slop.config[:longest_flag] - size
|
||||||
|
out += " " * (diff + 6)
|
||||||
|
else
|
||||||
|
out += " " * (@slop.config[:longest_flag] + 8)
|
||||||
|
end
|
||||||
|
|
||||||
|
"#{out}#{description}"
|
||||||
|
end
|
||||||
|
alias help to_s
|
||||||
|
|
||||||
|
# Returns the String inspection text.
|
||||||
|
def inspect
|
||||||
|
"#<Slop::Option [-#{short} | --#{long}" +
|
||||||
|
"#{'=' if expects_argument?}#{'=?' if accepts_optional_argument?}]" +
|
||||||
|
" (#{description}) #{config.inspect}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Convert an object to an Integer if possible.
|
||||||
|
#
|
||||||
|
# value - The Object we want to convert to an integer.
|
||||||
|
#
|
||||||
|
# Returns the Integer value if possible to convert, else a zero.
|
||||||
|
def value_to_integer(value)
|
||||||
|
if @slop.strict?
|
||||||
|
begin
|
||||||
|
Integer(value.to_s, 10)
|
||||||
|
rescue ArgumentError
|
||||||
|
raise InvalidArgumentError, "#{value} could not be coerced into Integer"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value.to_s.to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Convert an object to a Float if possible.
|
||||||
|
#
|
||||||
|
# value - The Object we want to convert to a float.
|
||||||
|
#
|
||||||
|
# Returns the Float value if possible to convert, else a zero.
|
||||||
|
def value_to_float(value)
|
||||||
|
if @slop.strict?
|
||||||
|
begin
|
||||||
|
Float(value.to_s)
|
||||||
|
rescue ArgumentError
|
||||||
|
raise InvalidArgumentError, "#{value} could not be coerced into Float"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value.to_s.to_f
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Convert an object to a Range if possible.
|
||||||
|
#
|
||||||
|
# value - The Object we want to convert to a range.
|
||||||
|
#
|
||||||
|
# Returns the Range value if one could be found, else the original object.
|
||||||
|
def value_to_range(value)
|
||||||
|
case value.to_s
|
||||||
|
when /\A(\-?\d+)\z/
|
||||||
|
Range.new($1.to_i, $1.to_i)
|
||||||
|
when /\A(-?\d+?)(\.\.\.?|-|,)(-?\d+)\z/
|
||||||
|
Range.new($1.to_i, $3.to_i, $2 == '...')
|
||||||
|
else
|
||||||
|
if @slop.strict?
|
||||||
|
raise InvalidArgumentError, "#{value} could not be coerced into Range"
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -22,14 +22,12 @@ Gem::Specification.new do |s|
|
||||||
|
|
||||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||||
s.add_runtime_dependency(%q<coderay>, ["~> 1.0.5"])
|
s.add_runtime_dependency(%q<coderay>, ["~> 1.0.5"])
|
||||||
s.add_runtime_dependency(%q<slop>, ["< 3", ">= 2.4.4"])
|
|
||||||
s.add_runtime_dependency(%q<method_source>, ["~> 0.7.1"])
|
s.add_runtime_dependency(%q<method_source>, ["~> 0.7.1"])
|
||||||
s.add_development_dependency(%q<bacon>, ["~> 1.1"])
|
s.add_development_dependency(%q<bacon>, ["~> 1.1"])
|
||||||
s.add_development_dependency(%q<open4>, ["~> 1.3"])
|
s.add_development_dependency(%q<open4>, ["~> 1.3"])
|
||||||
s.add_development_dependency(%q<rake>, ["~> 0.9"])
|
s.add_development_dependency(%q<rake>, ["~> 0.9"])
|
||||||
else
|
else
|
||||||
s.add_dependency(%q<coderay>, ["~> 1.0.5"])
|
s.add_dependency(%q<coderay>, ["~> 1.0.5"])
|
||||||
s.add_dependency(%q<slop>, ["< 3", ">= 2.4.4"])
|
|
||||||
s.add_dependency(%q<method_source>, ["~> 0.7.1"])
|
s.add_dependency(%q<method_source>, ["~> 0.7.1"])
|
||||||
s.add_dependency(%q<bacon>, ["~> 1.1"])
|
s.add_dependency(%q<bacon>, ["~> 1.1"])
|
||||||
s.add_dependency(%q<open4>, ["~> 1.3"])
|
s.add_dependency(%q<open4>, ["~> 1.3"])
|
||||||
|
@ -37,7 +35,6 @@ Gem::Specification.new do |s|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
s.add_dependency(%q<coderay>, ["~> 1.0.5"])
|
s.add_dependency(%q<coderay>, ["~> 1.0.5"])
|
||||||
s.add_dependency(%q<slop>, ["< 3", ">= 2.4.4"])
|
|
||||||
s.add_dependency(%q<method_source>, ["~> 0.7.1"])
|
s.add_dependency(%q<method_source>, ["~> 0.7.1"])
|
||||||
s.add_dependency(%q<bacon>, ["~> 1.1"])
|
s.add_dependency(%q<bacon>, ["~> 1.1"])
|
||||||
s.add_dependency(%q<open4>, ["~> 1.3"])
|
s.add_dependency(%q<open4>, ["~> 1.3"])
|
||||||
|
|
Loading…
Reference in a new issue