Class: Unlocodes::Registry

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Enumerable
Defined in:
lib/unlocodes/registry.rb

Overview

In-memory, lazily-indexed registry over a set of Entry instances.

The Registry owns three concerns end-to-end:

1. Loading — turning the bundled JSON-LD file into Entry instances.
2. Indexing — building fast lookups by code, country, function.
3. Querying — the public find/where/countries surface.

Loading and indexing are private; callers (and tests) cross the seam at the query methods. The bundled dataset is parsed once per Registry instance; construct a new Registry from a different source via Registry.from_entries or Registry.load_file.

Constant Summary collapse

FUNCTION_DIGIT_TO_LETTER =

UN/LOCODE function digit (used in unlcdf:1..unlcdf:9 references in the JSON-LD) → letter per the UN/LOCODE manual.

{
  '1' => 'B', # sea port
  '2' => 'R', # rail terminal
  '3' => 'T', # road terminal
  '4' => 'A', # airport
  '5' => 'P', # postal exchange office
  '6' => 'I', # inland water transport
  '7' => 'F', # ferry port
  '8' => 'V', # pipeline
  '9' => 'O'  # other / border crossing
}.freeze
UNLOCODE_TYPE_SUFFIX =
'UNLOCODE'
SCALAR_FILTERS =

Map of #where filter keys to the Entry attribute they read. Limited to attributes the JSON-LD vocabulary actually populates — status / iata / name_without_diacritics are NOT in the vocab, so they're intentionally absent here.

{
  code: :code,
  country: :country,
  subdivision: :subdivision
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(entries = []) ⇒ Registry

Returns a new instance of Registry.



54
55
56
# File 'lib/unlocodes/registry.rb', line 54

def initialize(entries = [])
  @entries = entries.freeze
end

Instance Attribute Details

#entriesObject (readonly)

Returns the value of attribute entries.



40
41
42
# File 'lib/unlocodes/registry.rb', line 40

def entries
  @entries
end

Class Method Details

.from_entries(entries) ⇒ Registry

Build a registry from an existing list of entries.

Parameters:

Returns:



79
80
81
# File 'lib/unlocodes/registry.rb', line 79

def from_entries(entries)
  new(entries)
end

.load_defaultRegistry

Load the bundled dataset shipped inside the gem.

Returns:



65
66
67
# File 'lib/unlocodes/registry.rb', line 65

def load_default
  load_file(default_data_path)
end

.load_file(path) ⇒ Registry

Load a specific JSON-LD file from disk.

Parameters:

  • path (String)

Returns:



72
73
74
# File 'lib/unlocodes/registry.rb', line 72

def load_file(path)
  from_entries(parse_json(File.read(path)))
end

.parse_hash(data) ⇒ Array<Unlocodes::Entry>

Parse a pre-parsed JSON-LD hash into Entry instances.

Parameters:

  • data (Hash)

Returns:



93
94
95
# File 'lib/unlocodes/registry.rb', line 93

def parse_hash(data)
  extract_graph(data).filter_map { |node| build_entry(node) if unlocode_node?(node) }
end

.parse_json(json) ⇒ Array<Unlocodes::Entry>

Parse a JSON-LD string into Entry instances.

Parameters:

  • json (String)

Returns:



86
87
88
# File 'lib/unlocodes/registry.rb', line 86

def parse_json(json)
  parse_hash(JSON.parse(json, symbolize_names: false))
end

Instance Method Details

#by_country(country_code) ⇒ Object



216
217
218
# File 'lib/unlocodes/registry.rb', line 216

def by_country(country_code)
  by_country_index[country_code.to_s.upcase] || []
end

#by_function(letter) ⇒ Object



220
221
222
# File 'lib/unlocodes/registry.rb', line 220

def by_function(letter)
  by_function_index[letter.to_s.upcase] || []
end

#countriesArray<String>

All distinct country codes present in the registry, sorted.

Returns:

  • (Array<String>)


206
207
208
# File 'lib/unlocodes/registry.rb', line 206

def countries
  entries.map(&:country).compact.uniq.sort
end

#counts_by_countryHash{String=>Integer}

Count of entries per country code.

Returns:

  • (Hash{String=>Integer})


212
213
214
# File 'lib/unlocodes/registry.rb', line 212

def counts_by_country
  entries.each_with_object(Hash.new(0)) { |e, h| h[e.country] += 1 if e.country }
end

#eachObject



58
59
60
# File 'lib/unlocodes/registry.rb', line 58

def each(&)
  @entries.each(&)
end

#find(code) ⇒ Unlocodes::Entry? Also known as: []

Exact-code lookup.

Parameters:

  • code (String)

    5-char LOCODE (case-insensitive)

Returns:



182
183
184
185
186
# File 'lib/unlocodes/registry.rb', line 182

def find(code)
  return nil if code.nil?

  by_code[code.to_s.upcase]
end

#where(filters) ⇒ Array<Unlocodes::Entry>

Filter entries by one or more predicates. Scalar filters accept either a single value or an array (any-of). name accepts a String (case-insensitive equality) or a Regexp.

Examples:

registry.where(country: 'CN')
registry.where(country: %w[CN HK], function: 'B')
registry.where(name: /shanghai/i)

Returns:



200
201
202
# File 'lib/unlocodes/registry.rb', line 200

def where(filters)
  filters.reduce(entries) { |scope, (key, value)| apply_filter(scope, key, value) }
end