Skip to content

Adapter contract

Sources::Base, Sources::Definition, and the registry: what a source adapter declares, the one method it must write, and the hooks it may override. The worked walkthrough — reading a publisher’s file, choosing a parser, cutting a fixture — is Add a sanctions source; this page is the contract alone. Full signatures are in the generated API documentation for Sources::Base and Sources::Definition.

The registry is duck-typed: an adapter registers by answering .key and .new, and nothing below requires subclassing Sources::Base.

Declarations (Definition, extended into every adapter class)

Section titled “Declarations (Definition, extended into every adapter class)”

Each reads back with no argument. jurisdiction, authority, format, url, licence_notice, licence_url and floor resolve up the superclass chain, so adapters sharing a publisher can share a base declaring them once. key does not: it is looked up on the exact class only, so a subclass never silently inherits its parent’s key.

DeclarationTypeRequiredInheritedNotes
keySymbolYesNoLowercase snake_case, /\A[a-z][a-z0-9_]*\z/. Never inherited — the registry’s, a stored snapshot’s, and the payload cache’s name for this list
jurisdictionSymbolYesYesNot validated against a country list — an internal watchlist’s jurisdiction is whatever its owner says
authorityStringYesYesThe body behind the list, spelled the way it spells itself
formatSymbolNoYesInformational; not dispatched on. A source with no published file — built from a database — declares none
url(name, address)StringOne url, or an overridden #retrieveYesDeclares a file with two arguments, reads one back with a name, returns the primary (first declared) with none
licence_noticeStringNoYesA dated summary of what the publisher says about reuse — not legal advice
licence_urlStringNoYesMust be an http(s) URL
floor(name, value)NumericNoYes, mergedA lower bound a Doctor check is held to when there is no prior snapshot to compare against. A subclass’s floor of the same name replaces its parent’s

A declaration violated at the class body raises Sources::DeclarationError — see the error hierarchy — at load time, which is where a typo in an adapter is cheapest to see.

MethodRequiredGivenReturnsDefault
#parse(raw)YesThe bytes for a single-file source, or a Hash[Symbol, String] keyed by declared file name for a multi-file oneArray[Entity]Raises UnsupportedError
#retrieve(force: false)No—Hash[Symbol, untyped] of file name to bytes, or nil when every file is unchangedFetches every declared url over HTTP, conditionally, through the payload cache
#column_shapes(raw)NoWhat #parse is givenArray[Parsers::ColumnShape::Tally][] — override for a source over a headerless, positionally-columned file (see Sources::Ofac)
#source_versionNo—String or nilThe most recent fetch’s Last-Modified header. Override when the publisher’s document carries its own version marker, so an examiner sees the string the publisher itself uses
.published_remarks(remarks)No (inherited, not overridden)A record’s remarksString or nilStrips this adapter’s own Remarks.build additions back off, leaving only what the publisher wrote

#sync and #snapshot are not overridden by an adapter — they are the fixed orchestration every source shares: #sync calls #retrieve then #snapshot, and #snapshot wraps whatever #parse returns in a checksummed Snapshot, stamping the failing source’s key onto any ActiveSanction::Error that escapes.

MethodReturnsNotes
.register(source)The registered sourceRaises Sources::DuplicateKey if a different class already claims the key. Registering the same class twice is a no-op
.[](key)The adapter class or instance registered under keyRaises Sources::UnknownSource, naming what is registered, rather than returning nil
.registered?(key)Boolean—
.allEvery registered adapter, sorted by key—
.keysEvery registered key, sorted—
.enabled(configured = config.sources)The adapters a sync should runEvery registered source when configured is nil; raises Sources::UnknownSource at the start of a run for an unresolvable key, rather than partway through
.unregister(key)What was registered there, or nilThe supported way to replace a built-in adapter: unregister, then register a patched one

A source is registrable by answering .key and .new — Sources::Base is the convenient way to write one, not a requirement the registry checks for.