Class: EasyTalk::ValidationAdapters::ActiveModelAdapter

Inherits:
Base
  • Object
show all
Defined in:
lib/easy_talk/validation_adapters/active_model_adapter.rb

Overview

ActiveModel validation adapter.

This is the default adapter that converts JSON Schema constraints into ActiveModel validations. It provides the same validation behavior as the original EasyTalk::ValidationBuilder.

Examples:

Using the ActiveModel adapter (default)

class User
  include EasyTalk::Model

  define_schema do
    property :email, String, format: 'email'
  end
end

user = User.new(email: 'invalid')
user.valid? # => false
user.errors[:email] # => ["must be a valid email address"]

Constant Summary collapse

REGEX_FORMAT_CONFIGS =

Regex-based format validators

{
  'email' => { with: /\A[^@\s]+@[^@\s]+\.[^@\s]+\z/, message: 'must be a valid email address' },
  'uuid' => { with: /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i,
              message: 'must be a valid UUID' }
}.freeze
PARSING_FORMATS =

Formats that require parsing validation (not just regex)

%w[date date-time time uri url].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

This class inherits a constructor from EasyTalk::ValidationAdapters::Base

Class Method Details

.build_schema_validations(klass, schema)

This method returns an undefined value.

Build schema-level validations for object-level constraints. Delegates to ActiveModelSchemaValidation module.

Parameters:

  • klass (Class)

    The model class to apply validations to

  • schema (Hash)

    The full schema hash containing schema-level constraints



90
91
92
# File 'lib/easy_talk/validation_adapters/active_model_adapter.rb', line 90

def self.build_schema_validations(klass, schema)
  ActiveModelSchemaValidation.apply(klass, schema)
end

.resolve_tuple_type_class(type) ⇒ Object

Helper class methods for tuple validation (defined at class level for use in validate blocks) Resolve a Sorbet type to a Ruby class for type checking



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/easy_talk/validation_adapters/active_model_adapter.rb', line 31

def self.resolve_tuple_type_class(type)
  # Handle T.untyped - any value is valid
  return :untyped if type.is_a?(T::Types::Untyped) || type == T.untyped

  # Handle union types (T.any, T.nilable)
  return type.types.flat_map { |t| resolve_tuple_type_class(t) } if type.is_a?(T::Types::Union)

  if type.respond_to?(:raw_type)
    type.raw_type
  elsif type == T::Boolean
    [TrueClass, FalseClass]
  elsif type.is_a?(Class)
    type
  else
    type
  end
end

.type_matches?(value, type_class) ⇒ Boolean

Check if a value matches a type class (supports arrays for union types like Boolean)

Returns:

  • (Boolean)


50
51
52
53
54
55
56
57
58
59
# File 'lib/easy_talk/validation_adapters/active_model_adapter.rb', line 50

def self.type_matches?(value, type_class)
  # :untyped means any value is valid (from empty schema {} in JSON Schema)
  return true if type_class == :untyped

  if type_class.is_a?(Array)
    type_class.any? { |tc| value.is_a?(tc) }
  else
    value.is_a?(type_class)
  end
end

.type_name_for_error(type_class) ⇒ Object

Generate a human-readable type name for error messages



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/easy_talk/validation_adapters/active_model_adapter.rb', line 62

def self.type_name_for_error(type_class)
  return 'unknown' if type_class.nil?

  if type_class.is_a?(Array)
    type_class.map { |tc| tc.respond_to?(:name) ? tc.name : tc.to_s }.join(' or ')
  elsif type_class.respond_to?(:name) && type_class.name
    type_class.name
  else
    type_class.to_s
  end
end

Instance Method Details

#apply_validations

This method returns an undefined value.

Apply validations based on property type and constraints.



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/easy_talk/validation_adapters/active_model_adapter.rb', line 97

def apply_validations
  context = build_validation_context

  apply_presence_validation unless context.skip_presence_validation?
  apply_array_presence_validation if context.array_requires_presence_validation?

  apply_type_validations(context)

  apply_enum_validation if @constraints[:enum]
  apply_const_validation if @constraints[:const]
end