My script needs to accept only 'plain' integers, and raise an argument error in any other cases (letters, special symbols, floats, multiple arguments). Unfortunately, when the passed arguments is a representation for a hexadecimal like 0b1111 the script interprets it as an integer and accepts it.
Here is my script:
begin
price = Integer ARGV[0]
rescue
raise ArgumentError "the entered value has to be an integer"
end
if ARGV.length > 1
raise ArgumentError, "wrong number of arguments (given #{ARGV.length}, expected 1)"
end
if price < 8
raise ArgumentError, "the entered value has to be at least 8"
end
if price.match?(/[A-Za-z]/)
raise ArgumentError "the entered value has to be an integer"
end
Basically the solution I'm trying is the last block:
if price.match?(/[A-Za-z]/)
raise ArgumentError "the entered value has to be an integer"
end
This gives me an error: undefined method `match?' for 2:Integer (NoMethodError)
If I understand correctly match? only works with strings, but because of the first block the variable price is converted to an integer.
How could I fix my code and would price.match?(/[A-Za-z]/) even solve my problem or do I need a completely different approach?
The desired result:
Input: 0b1111
output: ArgumentError "the entered value has to be an integer
CodePudding user response:
You can use exception: false
key for Integer
method
Integer(nil, exception: false)
# => nil
Integer("blablabla", exception: false)
# => nil
Integer("9.3", exception: false)
# => nil
Integer("9", exception: false)
# => 9
There is also base
(second) arg in this method
Integer("0b1111", exception: false)
# => 15
Integer("0b1111", 10, exception: false)
# => nil
Integer("9.3", 10, exception: false)
# => nil
Integer("9", 10, exception: false)
# => 9
Finally you can use it such way
price = Integer(ARGV[0], 10, exception: false)
raise ArgumentError("the entered value has to be an integer") if price.nil?
CodePudding user response:
After this line
price = Integer(ARGV[0])
the input is already transformed into an integer if a transformation is possible as defined in the example in the documentation of Kernel#Integer
.
If you want to ensure only strings that contain pure integer values are transformed then you will need to check the format of the input string first. For example, with a Regexp like this
ARGV[0].match?(/\A\d \z/)
that returns true
when the input only contains digits.
Just replace the first block in your script with
unless ARGV[0].match?(/\A\d \z/)
raise ArgumentError "the entered value has to be an integer"
end
price = Integer(ARGV[0])
# ...
To simplify testing the preconditions I would change it to
unless ARGV&.size != 1
raise ArgumentError, "wrong number of arguments (given #{ARGV&.size || 0}, expected 1)"
end
unless ARGV[0].match?(/\A\d \z/)
raise ArgumentError "the entered value has to be an integer with at least 8 digits"
end
price = Integer(ARGV[0])
if price < 8
raise ArgumentError, "the entered value has to be at least 8"
end