summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Gama <hey@vito.io>2023-02-10 16:25:08 -0300
committerVictor Gama <hey@vito.io>2023-02-15 11:43:06 -0300
commita23fa41a5674485600365985bea2a905e5e087df (patch)
treec781122a70e710929731ca811cd3f2d7ea4c0023
parentfc4622fc08d7982847ff583ad691ee4ba47f63f8 (diff)
downloadslop-a23fa41a5674485600365985bea2a905e5e087df.tar.gz
Add optional type validation
-rw-r--r--lib/slop/error.rb12
-rw-r--r--lib/slop/option.rb20
-rwxr-xr-xlib/slop/options.rb4
-rw-r--r--lib/slop/types.rb21
-rw-r--r--test/error_test.rb15
5 files changed, 69 insertions, 3 deletions
diff --git a/lib/slop/error.rb b/lib/slop/error.rb
index ddfa1a7..b83cab3 100644
--- a/lib/slop/error.rb
+++ b/lib/slop/error.rb
@@ -38,4 +38,16 @@ module Slop
# Suppress with the `suppress_errors` config option.
class MissingRequiredOption < Error
end
+
+ # Raised when a given option is provided by the user and does not
+ # match the expected format for that type. This is only raised if
+ # validate_types is set to true.
+ class InvalidOptionValue < Error
+ attr_reader :flag
+
+ def initialize(msg, flag)
+ super(msg)
+ @flag = flag
+ end
+ end
end
diff --git a/lib/slop/option.rb b/lib/slop/option.rb
index 093b37f..3afc93a 100644
--- a/lib/slop/option.rb
+++ b/lib/slop/option.rb
@@ -56,7 +56,11 @@ module Slop
raise Slop::MissingArgument.new("missing argument for #{flag}", flags)
end
else
- @value = call(value)
+ if validate_type? && !valid?(value) && !suppress_errors?
+ raise Slop::InvalidOptionValue.new("invalid value for #{flag}", flags)
+ end
+
+ @value = valid?(value) && call(value)
end
block.call(@value) if block.respond_to?(:call)
@@ -107,6 +111,13 @@ module Slop
config[:required]
end
+ # Returns true if an exception should be raised when this option value can't
+ # be parsed into the desired type or does not conform to the expected type's
+ # format
+ def validate_type?
+ config[:validate_types]
+ end
+
# Returns all flags joined by a comma. Used by the help string.
def flag
flags.join(", ")
@@ -119,6 +130,13 @@ module Slop
key.to_sym
end
+ # Override this if you want to provide a custom validator for a type. This
+ # method must return whether the provided value is valid for the current
+ # argument's type
+ def valid?(value)
+ true
+ end
+
# Returns true if this option should be displayed with dashes transformed into underscores.
def underscore_flags?
config[:underscore_flags]
diff --git a/lib/slop/options.rb b/lib/slop/options.rb
index 17e9501..5e71eac 100755
--- a/lib/slop/options.rb
+++ b/lib/slop/options.rb
@@ -7,6 +7,7 @@ module Slop
type: "null",
banner: true,
underscore_flags: true,
+ validate_types: false,
}
# The Array of Option instances we've created.
@@ -24,6 +25,9 @@ module Slop
# The String banner prefixed to the help string.
attr_accessor :banner
+ # Whether we should validate types of values provided by the user
+ attr_accessor :validate_types
+
def initialize(**config, &block)
@options = []
@separators = []
diff --git a/lib/slop/types.rb b/lib/slop/types.rb
index 83e4a0b..a08537d 100644
--- a/lib/slop/types.rb
+++ b/lib/slop/types.rb
@@ -22,6 +22,13 @@ module Slop
attr_accessor :explicit_value
FALSE_VALUES = [false, 'false', 'no', 'off', '0'].freeze
+ TRUE_VALUES = [true, 'true', 'yes', 'on', '1'].freeze
+ VALID_VALUES = (FALSE_VALUES + TRUE_VALUES).freeze
+
+ def valid?(value)
+ return true if value.is_a?(String) && value.start_with?("--")
+ value.nil? || VALID_VALUES.include?(value)
+ end
def call(value)
self.explicit_value = value
@@ -52,8 +59,14 @@ module Slop
# Cast the option argument to an Integer.
class IntegerOption < Option
+ INT_STRING_REGEXP = /\A[+-]?\d+\z/.freeze
+
+ def valid?(value)
+ value =~ INT_STRING_REGEXP
+ end
+
def call(value)
- value =~ /\A[+-]?\d+\z/ && value.to_i
+ value.to_i
end
end
IntOption = IntegerOption
@@ -62,8 +75,12 @@ module Slop
class FloatOption < Option
FLOAT_STRING_REGEXP = /\A[+-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?\z/.freeze
+ def valid?(value)
+ value =~ FLOAT_STRING_REGEXP
+ end
+
def call(value)
- value =~ FLOAT_STRING_REGEXP && value.to_f
+ value.to_f
end
end
diff --git a/test/error_test.rb b/test/error_test.rb
index d9c71ab..341fa75 100644
--- a/test/error_test.rb
+++ b/test/error_test.rb
@@ -63,3 +63,18 @@ describe Slop::MissingRequiredOption do
opts.parse []
end
end
+
+describe Slop::InvalidOptionValue do
+ it "raises when an option has an invalid value" do
+ opts = Slop::Options.new(validate_types: true)
+ opts.integer "-n", "--number", default: 10
+ assert_raises(Slop::InvalidOptionValue) { opts.parse %w(-n foo) }
+ end
+
+ it "does not raise when errors are suppressed" do
+ opts = Slop::Options.new(validate_types: true, suppress_errors: true)
+ opts.integer "-n", "--number", default: 10
+ r = opts.parse %w(-n foo)
+ assert_equal(10, r[:n])
+ end
+end