Module: Chemicalml::Convention::Registry

Defined in:
lib/chemicalml/convention/registry.rb

Overview

Lookup table for conventions. Built-in conventions are registered lazily on first access to avoid load-order surprises.

Adding a new convention = creating a subclass of Base that returns its QName and namespace_uri, then registering it here. No switch statements, no if/elsif chains in framework code.

Class Method Summary collapse

Class Method Details

.builtin_qnamesObject



43
44
45
# File 'lib/chemicalml/convention/registry.rb', line 43

def self.builtin_qnames
  load_cache.keys.sort
end

.convention_root?(role) ⇒ Boolean

True if a document with the given Role could carry a convention attribute that Detection would recognise.

Parameters:

  • role (Module)

    a Role::* module.

Returns:

  • (Boolean)


90
91
92
93
94
# File 'lib/chemicalml/convention/registry.rb', line 90

def self.convention_root?(role)
  Detection::CONVENTION_ROOTS.any? { |r| role <= r }
rescue StandardError
  Detection::CONVENTION_ROOTS.include?(role)
end

.detect_and_validate(document) ⇒ Object

Detect the convention from the document's root convention attribute and validate. Raises ArgumentError if the document declares no convention or an unknown one.

Raises:

  • (ArgumentError)


36
37
38
39
40
41
# File 'lib/chemicalml/convention/registry.rb', line 36

def self.detect_and_validate(document)
  qname = Convention::Detection.convention_of(document)
  raise ArgumentError, 'document declares no convention attribute' unless qname

  validate_report(document, qname: qname)
end

.each {|Module| ... } ⇒ Array<Module>, Enumerator

Iterate every registered convention. Yields the convention module. Enumerable-style: returns an Enumerator if no block.

Yields:

  • (Module)

    each convention module.

Returns:

  • (Array<Module>, Enumerator)

    the conventions if a block is given; otherwise an Enumerator.



53
54
55
56
57
# File 'lib/chemicalml/convention/registry.rb', line 53

def self.each(&)
  return to_enum(:each) unless block_given?

  load_cache.values.sort_by(&:qname).each(&)
end

.each_constraint {|convention, constraint| ... } ⇒ Enumerator, Integer

Iterate every constraint across every convention. Yields (convention, constraint_class) pairs. Useful for documentation generation and code introspection.

Yield Parameters:

  • convention (Module)

    the convention module.

  • constraint (Class)

    the constraint class.

Returns:

  • (Enumerator, Integer)

    count if block given; otherwise an Enumerator.



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/chemicalml/convention/registry.rb', line 67

def self.each_constraint(&)
  return to_enum(:each_constraint) unless block_given?

  count = 0
  each do |conv|
    conv.constraints.each do |constraint|
      yield(conv, constraint)
      count += 1
    end
  end
  count
end

.lookup(qname) ⇒ Object



15
16
17
# File 'lib/chemicalml/convention/registry.rb', line 15

def self.lookup(qname)
  load_cache[qname.to_s]
end

.register_custom(mod) ⇒ Module

Register a custom convention at runtime. The convention module must extend Chemicalml::Convention::Base and implement qname and namespace_uri.

Parameters:

  • mod (Module)

    the convention module (must extend Base).

Returns:

  • (Module)

    the registered module.

Raises:

  • (ArgumentError)

    if mod.qname is nil/empty.



103
104
105
106
107
108
109
110
111
112
# File 'lib/chemicalml/convention/registry.rb', line 103

def self.register_custom(mod)
  qname = mod.qname
  raise ArgumentError, 'convention module must return a non-empty qname' if qname.nil? || qname.to_s.empty?

  # Force load_cache to populate (acquires/releases mutex internally),
  # then mutate directly without re-entering the mutex.
  cache = load_cache
  cache[qname.to_s] = mod
  mod
end

.reset!Object



114
115
116
# File 'lib/chemicalml/convention/registry.rb', line 114

def self.reset!
  @mutex.synchronize { @load_cache = nil }
end

.total_constraint_countObject

Total count of registered constraints across all conventions.



81
82
83
# File 'lib/chemicalml/convention/registry.rb', line 81

def self.total_constraint_count
  each.sum(&:constraint_count)
end

.validate(document, qname:) ⇒ Object

Raises:

  • (ArgumentError)


19
20
21
22
23
24
# File 'lib/chemicalml/convention/registry.rb', line 19

def self.validate(document, qname:)
  convention = lookup(qname)
  raise ArgumentError, "unknown convention: #{qname.inspect}" unless convention

  convention.validate(document)
end

.validate_report(document, qname:) ⇒ Object

Raises:

  • (ArgumentError)


26
27
28
29
30
31
# File 'lib/chemicalml/convention/registry.rb', line 26

def self.validate_report(document, qname:)
  convention = lookup(qname)
  raise ArgumentError, "unknown convention: #{qname.inspect}" unless convention

  convention.validate_report(document)
end