Class: Lutaml::Model::AdapterResolver

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

Overview

Single authority for adapter resolution: (format, type_name) → adapter class.

Consolidates adapter metadata, loading, validation, and auto-detection that was previously spread across Config, Configuration, and FormatRegistry.

Resolution chain (in order):

1. Thread-local AdapterScope override
2. Explicitly configured type (from Config.xml_adapter_type =)
3. Lazy auto-detected type (cached after first probe)
4. Default from format metadata
5. Raise FormatAdapterNotSpecifiedError

Examples:

Configure an adapter

AdapterResolver.set_adapter_type(:xml, :nokogiri)

Resolve an adapter

adapter_class = AdapterResolver.adapter_for(:xml)

Per-operation override

adapter_class = AdapterResolver.resolved_adapter_class(:xml, :ox)

Class Method Summary collapse

Class Method Details

.adapter_for(format) ⇒ Class?

Resolve the adapter class for a format using the full resolution chain.

Parameters:

  • format (Symbol)

    the format name (:xml, :json, etc.)

Returns:

  • (Class, nil)

    the adapter class or nil



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/lutaml/model/adapter_resolver.rb', line 34

def adapter_for(format)
  # 1. Thread-local scope override
  scope_override = AdapterScope.override_for(format)
  if scope_override
    return resolved_adapter_class(format, scope_override)
  end

  # 2. Explicitly configured type
  configured = configured_type(format)
  if configured
    adapter = resolved[format]
    return adapter if adapter
  end

  # 3. Lazy auto-detection (cached)
  detected = detected_types[format]
  if detected.nil? && !detected_formats.key?(format)
    result = detect_adapter_for(format)
    if result
      detected_formats[format] = true
      detected_types[format] = result
      return load_and_cache(format, result)
    end
    detected_formats[format] = true
  elsif detected
    return load_and_cache(format, detected)
  end

  # 4. Default from metadata
  default = .dig(format, :default)
  if default
    return load_and_cache(format, default)
  end

  # 5. No adapter available
  nil
end

.configured_type(format) ⇒ Symbol?

Get the configured type name for a format.

Parameters:

  • format (Symbol)

    the format name

Returns:

  • (Symbol, nil)

    the type name or nil



144
145
146
# File 'lib/lutaml/model/adapter_resolver.rb', line 144

def configured_type(format)
  configured_types[format]
end

.register_fixed(format, adapter_class, adapter_name) ⇒ void

This method returns an undefined value.

Register a fixed adapter class for a format with a single adapter.

Used for key-value formats (json, yaml, hash, etc.) that have exactly one adapter. Creates metadata so validation works.

Parameters:

  • format (Symbol)

    the format name

  • adapter_class (Class)

    the adapter class

  • adapter_name (Symbol)

    the adapter type name (e.g., :standard)



131
132
133
134
135
136
137
138
# File 'lib/lutaml/model/adapter_resolver.rb', line 131

def register_fixed(format, adapter_class, adapter_name)
  [format] = {
    available: [adapter_name],
    default: adapter_name,
  }
  resolved[format] = adapter_class
  configured_types[format] = adapter_name
end

.register_metadata(format, options) ⇒ void

This method returns an undefined value.

Register adapter metadata for a format (available adapters, default).

Called by FormatRegistry.register for formats with selectable adapters.

Parameters:

  • format (Symbol)

    the format name

  • options (Hash)

    { available: […], default: :name }



118
119
120
# File 'lib/lutaml/model/adapter_resolver.rb', line 118

def (format, options)
  [format] = options
end

.reset!void

This method returns an undefined value.

Clear all state (for testing reset).



153
154
155
156
157
158
159
# File 'lib/lutaml/model/adapter_resolver.rb', line 153

def reset!
  @metadata = nil
  @configured_types = nil
  @resolved = nil
  @detected_types = nil
  @detected_formats = nil
end

.resolved_adapter_class(format, type_name) ⇒ Class

Load and resolve an adapter class by type name. Used for per-operation overrides (from_xml adapter: :ox).

Parameters:

  • format (Symbol)

    the format name

  • type_name (Symbol, String)

    the adapter type name

Returns:

  • (Class)

    the adapter class



103
104
105
106
107
# File 'lib/lutaml/model/adapter_resolver.rb', line 103

def resolved_adapter_class(format, type_name)
  type_name = type_name.to_sym
  validate!(format, type_name)
  load_adapter(format, type_name)
end

.set_adapter_class(format, adapter_class) ⇒ void

This method returns an undefined value.

Store a pre-resolved adapter class for a format.

Used by FormatRegistry.register for key-value formats that have a fixed adapter class (not selectable by type name).

Parameters:

  • format (Symbol)

    the format name

  • adapter_class (Class)

    the adapter class



92
93
94
95
# File 'lib/lutaml/model/adapter_resolver.rb', line 92

def set_adapter_class(format, adapter_class)
  resolved[format] = adapter_class
  configured_types[format] = :__fixed__
end

.set_adapter_type(format, type_name) ⇒ Class

Set the adapter type for a format (validates and loads).

Parameters:

  • format (Symbol)

    the format name

  • type_name (Symbol)

    the adapter type name (:nokogiri, :ox, etc.)

Returns:

  • (Class)

    the loaded adapter class



77
78
79
80
81
82
# File 'lib/lutaml/model/adapter_resolver.rb', line 77

def set_adapter_type(format, type_name)
  type_name = type_name.to_sym
  validate!(format, type_name)
  configured_types[format] = type_name
  resolved[format] = load_adapter(format, type_name)
end