class Pry::Slop

rubocop:disable Metrics/ClassLength

def [](key)

Returns the Object value for this option, or nil.

key - The Symbol or String option short or long flag.

Fetch an options argument value.
def [](key)
  option = fetch_option(key)
  option.value if option
end

def add_callback(label, &block)

Returns nothing.

label - The Symbol identifier to attach this callback.

Add a callback.
def add_callback(label, &block)
  (@callbacks[label] ||= []) << block
end

def autocreate(items, index)

Returns nothing.

index - The current Integer index for the item we're processing.
items - The Array of items we're parsing.

Autocreate an option on the fly. See the :autocreate Slop config option.
def autocreate(items, index)
  flag = items[index]
  return if fetch_option(flag) || @trash.include?(index)
  option = build_option(Array(flag))
  argument = items[index + 1]
  option.config[:argument] = (argument && argument !~ /\A--?/)
  option.config[:autocreated] = true
  options << option
end

def banner(banner = nil)

Returns the banner String.

banner - The String to set the banner.

Get or set the banner.
def banner(banner = nil)
  config[:banner] = banner if banner
  config[:banner]
end

def banner=(banner)

banner - The String to set the banner.

Set the banner.
def banner=(banner)
  config[:banner] = banner
end

def build_option(objects, &block)

Returns a new instance of Slop::Option.

objects - An Array of objects used to build this option.

Build an option from a list of objects.
def build_option(objects, &block)
  config = {}
  config[:argument] = true if @config[:arguments]
  config[:optional_argument] = true if @config[:optional_arguments]
  if objects.last.is_a?(Hash)
    config.merge!(objects.last)
    objects.pop
  end
  short = extract_short_flag(objects, config)
  long  = extract_long_flag(objects, config)
  desc  = objects[0].respond_to?(:to_str) ? objects.shift : nil
  Option.new(self, short, long, desc, config, &block)
end

def clean(object)

Returns the newly cleaned String with leading -- characters removed.

object - The Object we want to cast to a String and clean.

Remove any leading -- characters from a string.
def clean(object)
  object.to_s.sub(/\A--?/, '')
end

def command(command, options = {}, &block)

Returns a new instance of Slop mapped to this command.

options - A Hash of configuration options (see Slop::new)
command - The Symbol or String used to identify this command.

Add a new command.
def command(command, options = {}, &block)
  @commands[command.to_s] = Pry::Slop.new(options, &block)
end

def commands_to_help

def commands_to_help
  padding = 0
  @commands.each { |c, _| padding = c.size if c.size > padding }
  @commands.map do |cmd, opts|
    "  #{cmd}#{' ' * (padding - cmd.size)}   #{opts.description}"
  end.join("\n")
end

def description(desc = nil)

Returns the description String.

desc - The String to set the description.

Get or set the description (used for commands).
def description(desc = nil)
  config[:description] = desc if desc
  config[:description]
end

def description=(desc)

desc - The String to set the description.

Set the description (used for commands).
def description=(desc)
  config[:description] = desc
end

def each(&block)

Enumerable interface. Yields each Slop::Option.
def each(&block)
  options.each(&block)
end

def execute_multiple_switches(option, argument, index)

Returns nothing.

index - The index of the current item being processed.
argument - The argument to this option. (Split into multiple Options).
option - The first Option object.

method is only executed if the multiple_switches argument is true.
Execute a `-abc` type option where a, b and c are all options. This
def execute_multiple_switches(option, argument, index)
  execute_option(option, nil, index)
  argument.split('').each do |key|
    next unless (opt = fetch_option(key))
    opt.count += 1
    execute_option(opt, nil, index, key)
  end
end

def execute_option(option, argument, index, item = nil)

Returns nothing.

item - The optional String item we're processing.
index - The current Integer index of the object we're processing.
argument - The argument Object to assign to this option.
option - The Slop::Option object found by #process_item.

Execute an option, firing off callbacks and assigning arguments.
def execute_option(option, argument, index, item = nil)
  unless option
    if config[:multiple_switches] && strict?
      raise InvalidOptionError, "Unknown option -#{item}"
    end
    return
  end
  if argument
    unless item && item.end_with?("=#{argument}")
      @trash << index + 1 unless option.argument_in_value
    end
    option.value = argument
  else
    option.value = option.count > 0
  end
  if option.match? && !argument.match(option.config[:match])
    raise InvalidArgumentError, "#{argument} is an invalid argument"
  end
  option.call(option.value)
end

def extract_long_flag(objects, config)

config - The Hash of configuration options built in #build_option.
objects - The Array of objects passed from #build_option.

Extract the long flag from an item.
def extract_long_flag(objects, config)
  flag = objects.first.to_s
  return unless flag =~ /\A(?:--?)?[a-zA-Z][a-zA-Z0-9_-]+\=?\??\z/
  config[:argument] ||= true if flag.end_with?('=')
  config[:optional_argument] = true if flag.end_with?('=?')
  objects.shift
  clean(flag).sub(/\=\??\z/, '')
end

def extract_option(flag)

Returns an Array of [option, argument].

flag - The flag key used to extract an option.

Extract an option from a flag.
def extract_option(flag)
  option = fetch_option(flag)
  option ||= fetch_option(flag.downcase) if config[:ignore_case]
  option ||= fetch_option(flag.gsub(/([^-])-/, '\1_'))
  unless option
    case flag
    when /\A--?([^=]+)=(.+)\z/, /\A-([a-zA-Z])(.+)\z/, /\A--no-(.+)\z/
      option = fetch_option(Regexp.last_match(1))
      argument = Regexp.last_match(2) || false
      option.argument_in_value = true if option
    end
  end
  [option, argument]
end

def extract_short_flag(objects, config)

config - The Hash of configuration options built in #build_option.
objects - The Array of objects passed from #build_option.

Extract the short flag from an item.
def extract_short_flag(objects, config)
  flag = clean(objects.first)
  if flag.size == 2 && flag.end_with?('=')
    config[:argument] ||= true
    flag.chop!
  end
  return unless flag.size == 1
  objects.shift
  flag
end

def fetch_command(command)

opts.fetch_command(:foo).verbose? #=> true
# ruby run.rb foo -v

end
on :v, :verbose, 'Enable verbose mode'
opts.command :foo do

Examples:

command - The String or Symbol name of the command.

Fetch a Slop object associated with this command.
def fetch_command(command)
  @commands[command.to_s]
end

def fetch_option(key)

Returns an Option or nil if none were found.

opt.accepts_optional_argument? #=> true
opt.class #=> Slop::Option
opt = opts.fetch_option(:foo)
opts.on(:foo, 'Something fooey', :argument => :optional)

Examples:

key - The Symbol or String option key.

Fetch a Slop::Option object.
def fetch_option(key)
  options.find { |option| [option.long, option.short].include?(clean(key)) }
end

def initialize(config = {}, &block)

block - An optional block used to specify options.
config - A Hash of configuration options.

Create a new instance of Slop and optionally build options via a block.
def initialize(config = {}, &block)
  @config = DEFAULT_OPTIONS.merge(config)
  @options = []
  @commands = {}
  @trash = []
  @triggered_options = []
  @unknown_options = []
  @callbacks = {}
  @separators = {}
  @runner = nil
  if block_given?
    block.arity == 1 ? yield(self) : instance_eval(&block)
  end
  return unless config[:help]
  on('-h', '--help', 'Display this help message.', tail: true) do
    warn help
  end
end

def method_missing(method, *args, &block)

with a ? character it will instead call super().
Returns true if this option is present. If this method does not end

opts.other? #=> false
opts.verbose? #=> true
opts.parse %( --verbose )

Examples:

Convenience method for present?(:option).
def method_missing(method, *args, &block)
  meth = method.to_s
  if meth.end_with?('?')
    meth = meth.chop
    present?(meth) || present?(meth.tr('_', '-'))
  else
    super
  end
end

def missing

Returns an Array of Strings representing missing options.

opts.missing #=> ['password']
opts.parse %w[ --name Lee ]

end
on :p, :password=
on :n, :name=
opts = Slop.new do

Examples:

Fetch a list of options which were missing from the parsed list.
def missing
  (options - @triggered_options).map(&:key)
end

def on(*objects, &block)

Returns the created instance of Slop::Option.

on :v, :verbose, 'Enable verbose mode'
on '-u', '--username=', 'Your username'

Examples:

objects - An Array with an optional Hash as the last element.

Add an Option.
def on(*objects, &block)
  option = build_option(objects, &block)
  options << option
  option
end

def optspec(string, config = {})

Returns a new instance of Slop.

opts.fetch_option(:name).description #=> "Your name"

SPEC
p,passcode= Your secret pass code
A,auth Sign in with auth
a,age= Your age
n,name= Your name
---
ruby foo.rb [options]
opts = Slop.optspec(<<-SPEC)

Examples:

config - A Hash of configuration options to pass to Slop.new
string - The optspec String

options.
unable to pass any advanced options to the on() method when creating
than programatically. Do note though that with this method, you're
This allows you to design your options via a simple String rather

Build a Slop object from a option specification.
def optspec(string, config = {})
  config[:banner], optspec = string.split(/^--+$/, 2) if string[/^--+$/]
  lines = optspec.split("\n").reject(&:empty?)
  opts  = Slop.new(config)
  lines.each do |line|
    opt, description = line.split(' ', 2)
    short, long = opt.split(',').map { |s| s.sub(/\A--?/, '') }
    opt = opts.on(short, long, description)
    if long && long.end_with?('=')
      long.sub!(/\=$/, '')
      opt.config[:argument] = true
    end
  end
  opts
end

def parse(items = ARGV, config = {}, &block)

Returns a new instance of Slop.

end
on '-n', '--name', 'Your username', :argument => true
Slop.parse(ARGV, :help => true) do

Examples:

block - An optional block used to add options.
config - The Hash of configuration options to send to Slop.new().
items - The Array of items to extract options from (default: ARGV).
def parse(items = ARGV, config = {}, &block)
  parse! items.dup, config, &block
end

def parse(items = ARGV, &block)

Returns an Array of original items.

block - An optional block which when used will yield non options.
items - The Array of items to extract options from (default: ARGV).

Parse a list of items, executing and gathering options along the way.
def parse(items = ARGV, &block)
  parse! items.dup, &block
  items
end

def parse!(items = ARGV, config = {}, &block)

Returns a new instance of Slop.

block - An optional block used to add options.
config - The Hash of configuration options to send to Slop.new().
items - The Array of items to extract options from (default: ARGV).
def parse!(items = ARGV, config = {}, &block)
  if items.is_a?(Hash) && config.empty?
    config = items
    items = ARGV
  end
  slop = Pry::Slop.new config, &block
  slop.parse! items
  slop
end

def parse!(items = ARGV, &block)

Returns an Array of original items with options removed.

block - An optional block which when used will yield non options.
items - The Array of items to extract options from (default: ARGV).

from the original Array.
unlike parse() this method will remove any options and option arguments
Parse a list of items, executing and gathering options along the way.
def parse!(items = ARGV, &block)
  if items.empty? && @callbacks[:empty]
    @callbacks[:empty].each { |cb| cb.call(self) }
    return items
  end
  if (cmd = @commands[items[0]])
    return cmd.parse! items[1..-1]
  end
  items.each_with_index do |item, index|
    @trash << index && break if item == '--'
    autocreate(items, index) if config[:autocreate]
    process_item(items, index, &block) unless @trash.include?(index)
  end
  items.reject!.with_index { |_item, index| @trash.include?(index) }
  missing_options = options.select { |opt| opt.required? && opt.count < 1 }
  if missing_options.any?
    raise MissingOptionError,
          "Missing required option(s): #{missing_options.map(&:key).join(', ')}"
  end
  if @unknown_options.any?
    raise InvalidOptionError, "Unknown options #{@unknown_options.join(', ')}"
  end
  if @triggered_options.empty? && @callbacks[:no_options]
    @callbacks[:no_options].each { |cb| cb.call(self) }
  end
  @runner.call(self, items) if @runner.respond_to?(:call)
  items
end

def present?(*keys)

Returns true if all of the keys are present in the parsed arguments.

opts.present?(:bar) #=> false
opts.present?(:foo) #=> true
opts.parse %w( --foo )

Examples:

Check for an options presence.
def present?(*keys)
  keys.all? { |key| (opt = fetch_option(key)) && opt.count > 0 }
end

def process_item(items, index, &block)

Returns nothing.

block - An optional block which when passed will yield non options.
index - The current Integer index of the item we want to process.
items - The Array of items to process.

callbacks, assign any option arguments, and do some sanity checks.
Process a list item, figure out if it's an option, execute any
def process_item(items, index, &block)
  return unless (item = items[index])
  option, argument = extract_option(item) if item.start_with?('-')
  if option
    option.count += 1 unless item.start_with?('--no-')
    option.count += 1 if option.key[0, 3] == "no-"
    @trash << index
    @triggered_options << option
    if option.expects_argument?
      argument ||= items.at(index + 1)
      if !argument || argument =~ /\A--?[a-zA-Z][a-zA-Z0-9_-]*\z/
        raise MissingArgumentError, "#{option.key} expects an argument"
      end
      execute_option(option, argument, index, item)
    elsif option.accepts_optional_argument?
      argument ||= items.at(index + 1)
      if argument && argument =~ /\A([^\-?]|-\d)+/
        execute_option(option, argument, index, item)
      else
        option.call(nil)
      end
    elsif config[:multiple_switches] && argument
      execute_multiple_switches(option, argument, index)
    else
      option.value = option.count > 0
      option.call(nil)
    end
  else
    @unknown_options << item if strict? && item =~ /\A--?/
    yield(item) if block && !@trash.include?(index)
  end
end

def respond_to_missing?(method_name, include_all = false)

Returns true if this option key exists in our list of options.

Override this method so we can check if an option? method exists.
def respond_to_missing?(method_name, include_all = false)
  options.any? { |o| o.key == method_name.to_s.chop } || super
end

def run(callable = nil, &block)

end
end
puts "Arguments: #{args.inspect}" if opts.verbose?
run do |opts, args|

on :v, :verbose
Slop.parse do

Example:

An Array of unparsed arguments
yields - The instance of Slop parsing these options

callable - An object responding to a call method.

Specify code to be executed when these options are parsed.
def run(callable = nil, &block)
  @runner = callable || block
  return if @runner.respond_to?(:call)
  raise ArgumentError, "You must specify a callable object or a block to #run"
end

def separator(text)

text - The String text to print.

Add string separators between options.
def separator(text)
  if @separators[options.size]
    @separators[options.size] << "\n#{text}"
  else
    @separators[options.size] = text
  end
end

def strict?

Returns true if strict mode is enabled, false otherwise.

Is strict mode enabled?
def strict?
  config[:strict]
end

def to_hash(include_commands = false)

include_commands - If true, merge options from all sub-commands.

Returns a new Hash with option flags as keys and option values as values.
def to_hash(include_commands = false)
  hash = Hash[options.map { |opt| [opt.key.to_sym, opt.value] }]
  if include_commands
    @commands.each { |cmd, opts| hash.merge!(cmd.to_sym => opts.to_hash) }
  end
  hash
end

def to_s

Returns the banner followed by available option help strings.

Print a handy Slop help string.
def to_s
  heads  = options.reject(&:tail?)
  tails  = (options - heads)
  opts = (heads + tails).select(&:help).map(&:to_s)
  optstr = opts.each_with_index.map do |o, i|
    (str = @separators[i + 1]) ? [o, str].join("\n") : o
  end.join("\n")
  if @commands.any?
    optstr << "\n" unless optstr.empty?
    optstr << "\nAvailable commands:\n\n"
    optstr << commands_to_help
    optstr << "\n\nSee `<command> --help` for more information on a specific command."
  end
  banner = config[:banner]
  banner ||= "Usage: #{File.basename($PROGRAM_NAME, '.*')}" \
             "#{' [command]' if @commands.any?} [options]"
  if banner
    "#{banner}\n#{@separators[0] ? "#{@separators[0]}\n" : ''}#{optstr}"
  else
    optstr
  end
end