Class: Treaty::Attribute::Option::Validators::FormatValidator
- Defined in:
- lib/treaty/attribute/option/validators/format_validator.rb
Overview
Validates that string attribute value matches a specific format.
## Supported Formats
-
‘:uuid` - Universally unique identifier
-
‘:email` - Email address (RFC 2822 compliant)
-
‘:password` - Password (8-16 chars, must contain digit, lowercase, and uppercase)
-
‘:duration` - ActiveSupport::Duration compatible string (e.g., “1 day”, “2 hours”)
-
‘:date` - ISO 8601 date string (e.g., “2025-01-15”)
-
‘:datetime` - ISO 8601 datetime string (e.g., “2025-01-15T10:30:00Z”)
-
‘:time` - Time string (e.g., “10:30:00”, “10:30 AM”)
-
‘:boolean` - Boolean string (“true”, “false”, “0”, “1”)
## Usage Examples
Simple mode:
string :email, format: :email
string :started_on, format: :date
Advanced mode:
string :email, format: { is: :email }
string :started_on, format: { is: :date, message: "Invalid date format" }
string :started_on, format: { is: :date, message: ->(attribute:, value:, **) { "#{attribute} has invalid date: #{value}" } } # rubocop:disable Layout/LineLength
## Validation Rules
-
Only works with ‘:string` type attributes
-
Raises Treaty::Exceptions::Validation if used with non-string types
-
Skips validation for nil values (handled by RequiredValidator)
-
Each format has a pattern and/or validator for flexible validation
## Extensibility
To add new formats, extend DEFAULT_FORMATS hash with format definition:
DEFAULT_FORMATS[:custom_format] = {
pattern: /regex/,
validator: ->(value) { custom_validation_logic }
}
Constant Summary collapse
- UUID_PATTERN =
UUID format regex (8-4-4-4-12 hexadecimal pattern)
/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i- PASSWORD_PATTERN =
Password format regex (8-16 chars, at least one digit, lowercase, and uppercase)
/\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,16}\z/- BOOLEAN_PATTERN =
Boolean string format regex (accepts “true”, “false”, “0”, “1” case-insensitive)
/\A(true|false|0|1)\z/i- DEFAULT_FORMATS =
Default format definitions with patterns and validators Each format can have:
-
pattern: Regex for pattern matching
-
validator: Lambda for custom validation logic
-
{ uuid: { pattern: UUID_PATTERN, validator: nil }, email: { pattern: URI::MailTo::EMAIL_REGEXP, validator: nil }, password: { pattern: PASSWORD_PATTERN, validator: nil }, duration: { pattern: nil, validator: lambda do |value| ActiveSupport::Duration.parse(value) true rescue StandardError false end }, date: { pattern: nil, validator: lambda do |value| Date.parse(value) true rescue ArgumentError, TypeError false end }, datetime: { pattern: nil, validator: lambda do |value| DateTime.parse(value) true rescue ArgumentError, TypeError false end }, time: { pattern: nil, validator: lambda do |value| Time.parse(value) true rescue ArgumentError, TypeError false end }, boolean: { pattern: BOOLEAN_PATTERN, validator: nil } }.freeze
Instance Method Summary collapse
-
#validate_schema! ⇒ void
Validates that format is only used with string type attributes and that the format name is valid.
-
#validate_value!(value) ⇒ void
Validates that the value matches the specified format Skips validation for nil values (handled by RequiredValidator).
Methods inherited from Base
#initialize, #target_name, #transform_value, #transforms_name?
Constructor Details
This class inherits a constructor from Treaty::Attribute::Option::Base
Instance Method Details
#validate_schema! ⇒ void
This method returns an undefined value.
Validates that format is only used with string type attributes and that the format name is valid
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/treaty/attribute/option/validators/format_validator.rb', line 120 def validate_schema! # rubocop:disable Metrics/MethodLength # Format option only works with string types unless @attribute_type == :string raise Treaty::Exceptions::Validation, I18n.t( "treaty.attributes.validators.format.type_mismatch", attribute: @attribute_name, type: @attribute_type ) end format_name = option_value # Validate that format name exists return if formats.key?(format_name) raise Treaty::Exceptions::Validation, I18n.t( "treaty.attributes.validators.format.unknown_format", attribute: @attribute_name, format_name:, allowed: formats.keys.join(", ") ) end |
#validate_value!(value) ⇒ void
This method returns an undefined value.
Validates that the value matches the specified format Skips validation for nil values (handled by RequiredValidator)
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/treaty/attribute/option/validators/format_validator.rb', line 151 def validate_value!(value) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity return if value.nil? # Format validation doesn't check for nil, required does. format_name = option_value format_definition = formats[format_name] # Allow blank values (empty strings should be caught by required validator) return if value.to_s.strip.empty? # Apply pattern matching if defined if format_definition.fetch(:pattern) return if value.match?(format_definition.fetch(:pattern)) # Pattern failed, and no validator - raise error unless format_definition.fetch(:validator) attributes = { attribute: @attribute_name, value:, format_name: } = (**attributes) || (**attributes) raise Treaty::Exceptions::Validation, end end # Apply validator if defined return unless format_definition.fetch(:validator) return if format_definition.fetch(:validator).call(value) attributes = { attribute: @attribute_name, value:, format_name: } = (**attributes) || (**attributes) raise Treaty::Exceptions::Validation, end |