Class: Lutaml::Model::TypeResolver Private

Inherits:
Object
  • Object
show all
Defined in:
lib/lutaml/model/type_resolver.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

TypeResolver performs stateless type resolution.

This is an INTERNAL class. Users should use Register and GlobalRegister.

Responsibility: Resolve type names to classes using pure logic

This class:

  • Is STATELESS - no instance variables, all methods are class methods
  • Contains the single place for type resolution algorithm
  • Resolution chain: primary registry → substitutions → fallback contexts
  • NO caching, NO global state access
  • Easy to test in isolation

Examples:

Basic resolution

context = TypeContext.default
TypeResolver.resolve(:string, context)  #=> Lutaml::Model::Type::String
TypeResolver.resolve(:unknown, context) #=> raises UnknownTypeError

Resolution with fallbacks

custom_registry = TypeRegistry.new
custom_registry.register(:custom, MyCustomType)
context = TypeContext.derived(
  id: :my_app,
  registry: custom_registry,
  fallback_to: [TypeContext.default]
)
TypeResolver.resolve(:custom, context)  #=> MyCustomType
TypeResolver.resolve(:string, context)  #=> Lutaml::Model::Type::String (from fallback)

API:

  • private

Class Method Summary collapse

Class Method Details

.apply_substitutions(type, context) ⇒ Class

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Apply substitutions to a resolved type.

Parameters:

  • The resolved type

  • The context with substitutions

Returns:

  • The type (possibly substituted)

API:

  • private



157
158
159
160
161
# File 'lib/lutaml/model/type_resolver.rb', line 157

def self.apply_substitutions(type, context)
  return type if context.nil? || context.substitutions.empty?

  context.substitution_hash[type] || type
end

.available_type_names(context) ⇒ Array<Symbol>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get all available type names from context and fallbacks.

Parameters:

  • The resolution context

Returns:

  • All available type names

API:

  • private



167
168
169
170
171
172
173
174
175
176
177
# File 'lib/lutaml/model/type_resolver.rb', line 167

def self.available_type_names(context)
  names = context.registry.names.dup

  if context.has_fallbacks?
    context.fallback_contexts.each do |fallback|
      names.concat(fallback.registry.names)
    end
  end

  names.uniq.sort
end

.resolvable?(name, context) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if a type can be resolved without raising an exception.

Examples:

TypeResolver.resolvable?(:string, context)  #=> true
TypeResolver.resolvable?(:unknown, context) #=> false

Parameters:

  • The type name or class to check

  • The resolution context

Returns:

  • true if type can be resolved

API:

  • private



109
110
111
112
113
114
# File 'lib/lutaml/model/type_resolver.rb', line 109

def self.resolvable?(name, context)
  resolve(name, context)
  true
rescue UnknownTypeError
  false
end

.resolve(name, context) ⇒ Class

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Resolve a type name to a class using the given context.

Resolution order:

  1. If name is already a Class, return it (pass-through)
  2. Check primary registry
  3. Check substitutions (apply if matching)
  4. Check fallback contexts in order
  5. Raise UnknownTypeError if not found anywhere

Examples:

TypeResolver.resolve(:string, context)  #=> Lutaml::Model::Type::String
TypeResolver.resolve(MyClass, context)  #=> MyClass (pass-through)

Parameters:

  • The type name or class to resolve

  • The resolution context

Returns:

  • The resolved type class

Raises:

  • If type cannot be resolved

API:

  • private



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/lutaml/model/type_resolver.rb', line 54

def self.resolve(name, context)
  # Apply substitutions even if already a class
  # This is important for type substitution (e.g., Glaze -> RegisterGlaze)
  if name.is_a?(Class)
    return apply_substitutions(name, context)
  end

  # Normalize name to symbol
  type_name = name.to_sym

  # 1. Check primary registry
  type = context.lookup_local(type_name)
  return apply_substitutions(type, context) if type

  # 2. Check fallback contexts in order
  if context.has_fallbacks?
    context.fallback_contexts.each do |fallback_context|
      type = resolve_from_fallback(type_name, fallback_context)
      return apply_substitutions(type, context) if type
    end
  end

  # 3. Fall back to legacy Type module's internal registry
  # This maintains backward compatibility with Type.register()
  type = Type.lookup_ignoring_fallback(type_name)
  return apply_substitutions(type, context) if type

  # 4. Try Type.const_get for CamelCase type names (e.g., "Decimal" -> Type::Decimal)
  # This maintains backward compatibility with old Register behavior
  if name.is_a?(String)
    begin
      type = Lutaml::Model::Type.const_get(name)
      return apply_substitutions(type, context) if type
    rescue NameError
      # Not a constant in Type module, continue to error
    end
  end

  # 5. Type not found - raise error
  raise UnknownTypeError.new(
    type_name,
    context_id: context.id,
    available_types: available_type_names(context),
  )
end

.resolve_from_fallback(type_name, fallback_context) ⇒ Class?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Resolve from a fallback context (recursive).

Parameters:

  • The type name to resolve

  • The fallback context

Returns:

  • The resolved type or nil

API:

  • private



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/lutaml/model/type_resolver.rb', line 136

def self.resolve_from_fallback(type_name, fallback_context)
  # Check the fallback's local registry
  type = fallback_context.lookup_local(type_name)
  return type if type

  # Recursively check fallback's fallbacks
  if fallback_context.has_fallbacks?
    fallback_context.fallback_contexts.each do |nested_fallback|
      type = resolve_from_fallback(type_name, nested_fallback)
      return type if type
    end
  end

  nil
end

.resolve_or_nil(name, context) ⇒ Class?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Try to resolve a type, returning nil if not found.

Examples:

TypeResolver.resolve_or_nil(:string, context)  #=> Lutaml::Model::Type::String
TypeResolver.resolve_or_nil(:unknown, context) #=> nil

Parameters:

  • The type name or class to resolve

  • The resolution context

Returns:

  • The resolved type class or nil

API:

  • private



125
126
127
128
129
# File 'lib/lutaml/model/type_resolver.rb', line 125

def self.resolve_or_nil(name, context)
  resolve(name, context)
rescue UnknownTypeError
  nil
end