Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Copyright (c) 2018 eth-p
- # ----------------------------------------------------------------------------------------------------------------------
- # Argument:
- # A command line argument.
- # This is used to describe and validate arguments.
- class Argument
- # ----- Types -----
- # A string argument.
- # Accepts any non-empty value.
- STRING = {
- :name => :string,
- :default => nil,
- :parse => lambda { |value| value },
- :validate => lambda { |value| true }
- }
- # A switch argument.
- # Accepts no value.
- SWITCH = {
- :name => :switch,
- :default => false,
- :parse => lambda { |value| value == "true" || value == "yes" || value == nil },
- :validate => lambda { |value| value == "true" || value == "yes" || value == "false" || value == "no" || value == nil }
- }
- # A boolean argument.
- # Accepts "true"/"yes", "false"/"no", or an empty value (true).
- BOOLEAN = {
- :name => :boolean,
- :default => false,
- :parse => lambda { |value| value == "true" || value == "yes" || value == nil },
- :validate => lambda { |value| value == "true" || value == "yes" || value == "false" || value == "no" || value == nil }
- }
- # An integer argument.
- # Accepts any valid integral number.
- INTEGER = {
- :name => :integer,
- :default => nil,
- :parse => lambda { |value| Integer(value, 10) },
- :validate => lambda { |value| Integer(value, 10) && true rescue false }
- }
- # A number argument.
- # Accepts any valid floating-point or integral number.
- NUMBER = {
- :name => :number,
- :default => nil,
- :parse => lambda { |value| Float(value) },
- :validate => lambda { |value| Float(value) && true rescue false }
- }
- # A custom argument.
- # The validation function (:validate) must be provided.
- CUSTOM = {
- :name => :custom,
- :default => nil,
- :parse => nil,
- :validate => nil
- }
- # ----- Fields -----
- attr_reader :name
- attr_reader :type
- attr_reader :default
- attr_reader :description
- attr_reader :aliases
- # ----- Constructor -----
- # Creates a new Argument object.
- #
- # Arguments can either be options (e.g. "--option"/"-o"), switches (e.g. "--help"), or arguments (e.g. "file.txt")
- # The type is determined by the name and type parameters.
- #
- # Available attributes:
- # * [Lambda(String)->Boolean] :validate - Validates the argument.
- # * [Lambda(String)->any] :parse - Parses the argument.
- # * [String|nil] :default - The default value of the argument.
- # * [String] :description - The description for the argument.
- # * [String|String[]] :aliases - Aliases for the argument.
- #
- # @param [String] name The argument name.
- # @param [Hash] type The argument type. See the class constants.
- # @param [Hash] attributes The argument attributes.
- #
- # @see Argument::STRING
- # @see Argument::BOOLEAN
- # @see Argument::INTEGER
- # @see Argument::NUMBER
- # @see Argument::CUSTOM
- public
- def initialize(name, type, attributes = nil)
- # Validate name.
- raise ArgumentError, "invalid argument name" unless name.is_a? String
- raise ArgumentError, "invalid argument name" unless name =~ /^(?:(?:\.\.\.)|(?:--[a-z0-9][a-z0-9\-]+)|(?:-[a-zA-Z0-9])|(?:[a-z0-9][a-z0-9\-]*))$/
- # Validate type.
- if name.start_with? "-"
- case type when STRING, BOOLEAN, SWITCH, INTEGER, NUMBER, CUSTOM; else
- raise ArgumentError, "invalid argument type"
- end
- else
- case type when STRING, BOOLEAN, INTEGER, NUMBER; else
- raise ArgumentError, "invalid argument type for non-option argument"
- end
- end
- # Fields.
- @name = name
- @type = type
- @default = type[:default]
- @description = "[no description provided]"
- @fn_validate = type[:validate]
- @fn_parse = type[:parse]
- @aliases = []
- # Attributes.
- if attributes != nil
- raise ArgumentError, "invalid attributes" unless attributes.is_a? Hash
- # Attribute: validate.
- if attributes.has_key? :validate
- @fn_validate = attributes.delete(:validate)
- raise ArgumentError, "invalid validate function" unless @fn_validate.respond_to? :call
- end
- # Attribute: parse.
- if attributes.has_key? :parse
- @fn_parse = attributes.delete(:parse)
- raise ArgumentError, "invalid parse function" unless @fn_validate.respond_to? :call
- end
- # Attribute: default.
- if attributes.has_key? :default
- raise ArgumentError, "catch-all argument cannot have a default value" unless name != "..."
- @default = attributes.delete(:default)
- if @default != nil
- @default = @default.to_s
- raise ArgumentError, "invalid default value" unless @fn_validate.call @default.to_s
- end
- end
- # Attribute: aliases.
- if attributes.has_key? :aliases
- raise ArgumentError, "value arguments cannot have aliases" unless name.start_with? "-"
- @aliases = attributes.delete(:aliases)
- @aliases.each do |name|
- raise ArgumentError, "invalid alias name" unless name.is_a? String
- raise ArgumentError, "invalid alias name" unless name =~ /^(?:(?:--[a-z0-9][a-z0-9\-]+)|(?:-[a-zA-Z0-9])|(?:[a-z0-9][a-z0-9\-]*))$/
- end
- end
- # Attribute: description.
- if attributes.has_key? :description
- @description = attributes.delete(:description).to_s
- end
- end
- # Validate attributes.
- raise ArgumentError, "missing validate function" unless @fn_validate != nil
- raise ArgumentError, "missing parse function" unless @fn_parse != nil
- raise ArgumentError, "unknown attribute: #{attributes.first[0]}" unless attributes.length == 0
- end
- # ----- Methods -----
- # Validates the argument.
- #
- # @param [String] string The string to validate.
- # @return [Boolean] True if the string is valid for the argument type.
- public
- def validate(string)
- return @fn_validate.call(string)
- end
- # Parses the argument.
- #
- # @param [String] string The string to parse.
- # @return [mixed]
- public
- def parse(string)
- return @fn_parse.call(string)
- end
- # Checks if the argument is an option (key/value) argument.
- # Examples:
- # * "--help"
- # * "-k val"
- #
- # @return [Boolean]
- public
- def is_option?
- return @name.start_with? "-"
- end
- # Checks if the argument is a value argument.
- # Examples:
- # * "file"
- #
- # @return [Boolean]
- public
- def is_argument?
- return ! (@name.start_with? "-")
- end
- end
Add Comment
Please, Sign In to add comment