Guest User

Untitled

a guest
Jun 21st, 2018
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.04 KB | None | 0 0
  1. # Copyright (c) 2018 eth-p
  2. # ----------------------------------------------------------------------------------------------------------------------
  3. # Argument:
  4.  
  5. # A command line argument.
  6. # This is used to describe and validate arguments.
  7. class Argument
  8.  
  9. # ----- Types -----
  10.  
  11. # A string argument.
  12. # Accepts any non-empty value.
  13. STRING = {
  14. :name => :string,
  15. :default => nil,
  16. :parse => lambda { |value| value },
  17. :validate => lambda { |value| true }
  18. }
  19.  
  20. # A switch argument.
  21. # Accepts no value.
  22. SWITCH = {
  23. :name => :switch,
  24. :default => false,
  25. :parse => lambda { |value| value == "true" || value == "yes" || value == nil },
  26. :validate => lambda { |value| value == "true" || value == "yes" || value == "false" || value == "no" || value == nil }
  27. }
  28.  
  29. # A boolean argument.
  30. # Accepts "true"/"yes", "false"/"no", or an empty value (true).
  31. BOOLEAN = {
  32. :name => :boolean,
  33. :default => false,
  34. :parse => lambda { |value| value == "true" || value == "yes" || value == nil },
  35. :validate => lambda { |value| value == "true" || value == "yes" || value == "false" || value == "no" || value == nil }
  36. }
  37.  
  38. # An integer argument.
  39. # Accepts any valid integral number.
  40. INTEGER = {
  41. :name => :integer,
  42. :default => nil,
  43. :parse => lambda { |value| Integer(value, 10) },
  44. :validate => lambda { |value| Integer(value, 10) && true rescue false }
  45. }
  46.  
  47. # A number argument.
  48. # Accepts any valid floating-point or integral number.
  49. NUMBER = {
  50. :name => :number,
  51. :default => nil,
  52. :parse => lambda { |value| Float(value) },
  53. :validate => lambda { |value| Float(value) && true rescue false }
  54. }
  55.  
  56. # A custom argument.
  57. # The validation function (:validate) must be provided.
  58. CUSTOM = {
  59. :name => :custom,
  60. :default => nil,
  61. :parse => nil,
  62. :validate => nil
  63. }
  64.  
  65.  
  66. # ----- Fields -----
  67.  
  68. attr_reader :name
  69. attr_reader :type
  70. attr_reader :default
  71. attr_reader :description
  72. attr_reader :aliases
  73.  
  74.  
  75. # ----- Constructor -----
  76.  
  77. # Creates a new Argument object.
  78. #
  79. # Arguments can either be options (e.g. "--option"/"-o"), switches (e.g. "--help"), or arguments (e.g. "file.txt")
  80. # The type is determined by the name and type parameters.
  81. #
  82. # Available attributes:
  83. # * [Lambda(String)->Boolean] :validate - Validates the argument.
  84. # * [Lambda(String)->any] :parse - Parses the argument.
  85. # * [String|nil] :default - The default value of the argument.
  86. # * [String] :description - The description for the argument.
  87. # * [String|String[]] :aliases - Aliases for the argument.
  88. #
  89. # @param [String] name The argument name.
  90. # @param [Hash] type The argument type. See the class constants.
  91. # @param [Hash] attributes The argument attributes.
  92. #
  93. # @see Argument::STRING
  94. # @see Argument::BOOLEAN
  95. # @see Argument::INTEGER
  96. # @see Argument::NUMBER
  97. # @see Argument::CUSTOM
  98. public
  99. def initialize(name, type, attributes = nil)
  100. # Validate name.
  101. raise ArgumentError, "invalid argument name" unless name.is_a? String
  102. raise ArgumentError, "invalid argument name" unless name =~ /^(?:(?:\.\.\.)|(?:--[a-z0-9][a-z0-9\-]+)|(?:-[a-zA-Z0-9])|(?:[a-z0-9][a-z0-9\-]*))$/
  103.  
  104. # Validate type.
  105. if name.start_with? "-"
  106. case type when STRING, BOOLEAN, SWITCH, INTEGER, NUMBER, CUSTOM; else
  107. raise ArgumentError, "invalid argument type"
  108. end
  109. else
  110. case type when STRING, BOOLEAN, INTEGER, NUMBER; else
  111. raise ArgumentError, "invalid argument type for non-option argument"
  112. end
  113. end
  114.  
  115. # Fields.
  116. @name = name
  117. @type = type
  118. @default = type[:default]
  119. @description = "[no description provided]"
  120. @fn_validate = type[:validate]
  121. @fn_parse = type[:parse]
  122. @aliases = []
  123.  
  124. # Attributes.
  125. if attributes != nil
  126. raise ArgumentError, "invalid attributes" unless attributes.is_a? Hash
  127.  
  128. # Attribute: validate.
  129. if attributes.has_key? :validate
  130. @fn_validate = attributes.delete(:validate)
  131. raise ArgumentError, "invalid validate function" unless @fn_validate.respond_to? :call
  132. end
  133.  
  134. # Attribute: parse.
  135. if attributes.has_key? :parse
  136. @fn_parse = attributes.delete(:parse)
  137. raise ArgumentError, "invalid parse function" unless @fn_validate.respond_to? :call
  138. end
  139.  
  140. # Attribute: default.
  141. if attributes.has_key? :default
  142. raise ArgumentError, "catch-all argument cannot have a default value" unless name != "..."
  143.  
  144. @default = attributes.delete(:default)
  145. if @default != nil
  146. @default = @default.to_s
  147. raise ArgumentError, "invalid default value" unless @fn_validate.call @default.to_s
  148. end
  149. end
  150.  
  151. # Attribute: aliases.
  152. if attributes.has_key? :aliases
  153. raise ArgumentError, "value arguments cannot have aliases" unless name.start_with? "-"
  154.  
  155. @aliases = attributes.delete(:aliases)
  156. @aliases.each do |name|
  157. raise ArgumentError, "invalid alias name" unless name.is_a? String
  158. raise ArgumentError, "invalid alias name" unless name =~ /^(?:(?:--[a-z0-9][a-z0-9\-]+)|(?:-[a-zA-Z0-9])|(?:[a-z0-9][a-z0-9\-]*))$/
  159. end
  160. end
  161.  
  162. # Attribute: description.
  163. if attributes.has_key? :description
  164. @description = attributes.delete(:description).to_s
  165. end
  166. end
  167.  
  168. # Validate attributes.
  169. raise ArgumentError, "missing validate function" unless @fn_validate != nil
  170. raise ArgumentError, "missing parse function" unless @fn_parse != nil
  171. raise ArgumentError, "unknown attribute: #{attributes.first[0]}" unless attributes.length == 0
  172. end
  173.  
  174.  
  175. # ----- Methods -----
  176.  
  177. # Validates the argument.
  178. #
  179. # @param [String] string The string to validate.
  180. # @return [Boolean] True if the string is valid for the argument type.
  181. public
  182. def validate(string)
  183. return @fn_validate.call(string)
  184. end
  185.  
  186. # Parses the argument.
  187. #
  188. # @param [String] string The string to parse.
  189. # @return [mixed]
  190. public
  191. def parse(string)
  192. return @fn_parse.call(string)
  193. end
  194.  
  195. # Checks if the argument is an option (key/value) argument.
  196. # Examples:
  197. # * "--help"
  198. # * "-k val"
  199. #
  200. # @return [Boolean]
  201. public
  202. def is_option?
  203. return @name.start_with? "-"
  204. end
  205.  
  206. # Checks if the argument is a value argument.
  207. # Examples:
  208. # * "file"
  209. #
  210. # @return [Boolean]
  211. public
  212. def is_argument?
  213. return ! (@name.start_with? "-")
  214. end
  215.  
  216. end
Add Comment
Please, Sign In to add comment