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)

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:

  • type (Class)

    The resolved type

  • context (TypeContext)

    The context with substitutions

Returns:

  • (Class)

    The type (possibly substituted)



157
158
159
160
161
162
163
164
165
166
# File 'lib/lutaml/model/type_resolver.rb', line 157

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

  context.substitutions.each do |sub|
    substituted = sub.apply(type)
    return substituted if substituted
  end

  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:

Returns:

  • (Array<Symbol>)

    All available type names



172
173
174
175
176
177
178
179
180
181
182
# File 'lib/lutaml/model/type_resolver.rb', line 172

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:

  • name (Symbol, String, Class)

    The type name or class to check

  • context (TypeContext)

    The resolution context

Returns:

  • (Boolean)

    true if type can be resolved



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:

  • name (Symbol, String, Class)

    The type name or class to resolve

  • context (TypeContext)

    The resolution context

Returns:

  • (Class)

    The resolved type class

Raises:



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:

  • type_name (Symbol)

    The type name to resolve

  • fallback_context (TypeContext)

    The fallback context

Returns:

  • (Class, nil)

    The resolved type or nil



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:

  • name (Symbol, String, Class)

    The type name or class to resolve

  • context (TypeContext)

    The resolution context

Returns:

  • (Class, nil)

    The resolved type class or nil



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