# frozen_string_literal: true 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 }.freeze attr_reader :short, :long, :description, :config, :types attr_accessor :count, :argument_in_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] @value = nil @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) }, range: proc { |v| value_to_range(v) }, count: proc { @count } } if long && long.size > @slop.config[:longest_flag] @slop.config[:longest_flag] = long.size end @config.each_key do |key| predicate = :"#{key}?" unless self.class.method_defined?(predicate) self.class.__send__(:define_method, predicate) { !@config.key?(key) } end 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 # Set the new argument value for this option. # # We use this setter method to handle concatenating lists. That is, # when an array type is specified and used more than once, values from # both options will be grouped together and flattened into a single array. def value=(new_value) if config[:as].to_s.casecmp('array') == 0 @value ||= [] if new_value.respond_to?(:split) @value.concat new_value.split(config[:delimiter], config[:limit]) end else @value = new_value end 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 return value if [true, false, nil].include?(value) && config[:as].to_s != 'count' type = config[:as] if type.respond_to?(:call) type.call(value) elsif (callable = types[type.to_s.downcase.to_sym]) callable.call(value) else value end end # Returns the help String for this option. def to_s return config[:help] if config[:help].respond_to?(:to_str) 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 "#