InferType
A simple and lightweight Ruby utility that converts strings into their most appropriate Ruby types using a pluggable, priority-based parser system.
- Detects common Ruby types (list below)
- You can specify a smaller list to detect when you call
parse() - You can define custom parsers to detect other types of any kind
- Priority order of detection is configurable
Basic usage
InferType.parse("123")
# => 123 # Integer
InferType.parse("1.5")
# => 1.5 # Float
InferType.parse("hello")
# => "hello" # remains a string as no other type detectedParsers
InferType runs through a series of Parser classes in priority order, which each get a chance to detect and parse the string into the type that they're concerned with, e.g. Integer or Date.
InferType comes with default parsers. It will detect, in order:
- Integer
- Float
- True
- False
- Nil
- Date (if valid)
- Time (if valid)
You can define your own class inheriting from InferType::Parser to detect other types -- see Custom Parsers below.
Restricting Types
You can explicitly control which types are allowed for a parse operation:
# Assuming a parser for BigDecimal has been registered...
InferType.parse("1000", BigDecimal, Date, Time)
# => 0.1e4 # BigDecimal. Integer parser wasn't called.When specifying the types to look for explicitly like this, you are also specifying the priority order that will be used.
Parser Priority
You can modify any parser's priority order with:
InferType.prioritise(DateParser) # move to front
InferType.deprioritise(DateParser) # move to back
# American spellings also work
InferType.prioritize(DateParser, IntegerParser)
# moves both to front in this orderA parser can also be deregistered:
InferType.deregister(IntegerParser)
# integers will no longer be parsedParser Settings
Parsers may expose settings that let you modify how they parse. These are the settings available for built-in parsers (showing their defaults):
Integer
# Allow numbers with leading zeros like "00001" = 1
ALLOW_LEADING_ZERO = true
# Allow leading plus sign like "+2" = 2
ALLOW_LEADING_PLUS = trueFloat
# If false, "1" is NOT considered a Float (must be "1.0" etc.)
ALLOW_INTEGER = true
# Allow exponential notation like 1e3 or 1.5E-2
ALLOW_EXPONENTIAL = true
# Allow special values: NaN, Infinity
ALLOW_SPECIAL_VALUES = falseTrue, False, Nil
# In strict mode, only accept "true", "false", "nil" to mean those respective things
# In relaxed mode, other similar terms are also allowed e.g. "on", "no", "null"
STRICT = true
# If true, case sensitive
CASE_SENSITIVE = falseTime
# If timezone offset is missing from a Time string, assume UTC
# If false, the system's local timezone will be used
DEFAULT_UTC = trueCustom Parsers
Custom parsers must be registered:
InferType.register(BigDecimalParser)
InferType.register(MyCustomIntegerParser)By default a newly registered parser either:
- replaces the parser already registered to deal with that type, in the same priority position; or
- goes to last place in priority order.
A parser must:
- Subclass
InferType::Parser - Declare exactly one class it detects with
detects <Class> - Implement
#parse(str) - Use
failureorsuccess(value)methods to return - If it parses successfully it must return the type of object declared in
detects - Never raise on invalid input
Example
class UUIDParser < InferType::Parser
detects MyCustomUUIDClass
UUID_REGEX = /\A[0-9a-f\-]{36}\z/i
def parse(str)
return failure unless UUID_REGEX.match?(str)
success(MyCustomUUIDClass.new(str))
end
end
InferType.register(UUIDParser)