iata 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +24 -0
- data/README.adoc +142 -0
- data/lib/iata/coordinates.rb +45 -0
- data/lib/iata/data/airports.json +81467 -0
- data/lib/iata/data/fetcher.rb +140 -0
- data/lib/iata/data.rb +7 -0
- data/lib/iata/entry.rb +43 -0
- data/lib/iata/loader.rb +64 -0
- data/lib/iata/registry.rb +136 -0
- data/lib/iata/version.rb +5 -0
- data/lib/iata.rb +43 -0
- metadata +87 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 176d98285f415c8a930e02e73de40009fcf0d9fd9fae998bbb54fc48de8d908f
|
|
4
|
+
data.tar.gz: 247d5d264d9304aa94392b7a067ec04862f55f7e2a9db50e6310bd4cf811535a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e67416a8025bd8f6aa0de9d72aad336d7ad0190d6cb2fb5c2d7beb198182838ad573536923c4643ef132591118fc87af8386c79c15340a2237c698e89cfa9138
|
|
7
|
+
data.tar.gz: 18d0ac1d2a114631aaf0eb7c3378f60ed5b7b4eb992274883626e4a70ce5d4604dfa36e06dde3a54e644aefe766887f0ff7d2d69a3479880990480277ff8066e
|
data/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Ribose Inc.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
19
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
20
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
21
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
22
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
23
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
24
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.adoc
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
= iata
|
|
2
|
+
:toc: macro
|
|
3
|
+
:homepage: https://github.com/metanorma/iata
|
|
4
|
+
|
|
5
|
+
`iata` is a Ruby gem that exposes the IATA (International Air Transport
|
|
6
|
+
Association) airport code list as a queryable in-memory registry.
|
|
7
|
+
|
|
8
|
+
The dataset is sourced from Wikidata (property P238, "IATA airport code") and
|
|
9
|
+
ships inside the gem as a JSON file so the registry works offline. Loading is
|
|
10
|
+
lazy — the first call to `Iata.registry` parses the bundled JSON once.
|
|
11
|
+
|
|
12
|
+
== Installation
|
|
13
|
+
|
|
14
|
+
Ruby 3.1 or newer is required.
|
|
15
|
+
|
|
16
|
+
Add to your Gemfile:
|
|
17
|
+
|
|
18
|
+
[source,ruby]
|
|
19
|
+
----
|
|
20
|
+
gem 'iata'
|
|
21
|
+
----
|
|
22
|
+
|
|
23
|
+
Or install directly:
|
|
24
|
+
|
|
25
|
+
[source,sh]
|
|
26
|
+
----
|
|
27
|
+
gem install iata
|
|
28
|
+
----
|
|
29
|
+
|
|
30
|
+
== Usage
|
|
31
|
+
|
|
32
|
+
[source,ruby]
|
|
33
|
+
----
|
|
34
|
+
require 'iata'
|
|
35
|
+
|
|
36
|
+
# Lookup by 3-letter IATA code (case-insensitive)
|
|
37
|
+
Iata.find('PVG').name # => "Shanghai Pudong International Airport"
|
|
38
|
+
Iata['HKG'] # => #<Iata::Entry code="HKG" name="Hong Kong International Airport">
|
|
39
|
+
|
|
40
|
+
# Filters — single value or array (any-of)
|
|
41
|
+
Iata.where(country: 'CN').count # => ~200 Chinese airports
|
|
42
|
+
Iata.where(country: %w[CN HK]).count # => airports in China or Hong Kong
|
|
43
|
+
|
|
44
|
+
# Search by name (Regexp substring or case-insensitive String)
|
|
45
|
+
Iata.where(name: /international/i).count
|
|
46
|
+
Iata.where(name: 'narita').map(&:code) # => ["NRT"]
|
|
47
|
+
|
|
48
|
+
# Country listing
|
|
49
|
+
Iata.countries # => ["AE", "AR", "AT", ..., "ZW"] (200+ codes)
|
|
50
|
+
Iata.counts_by_country.first(5)
|
|
51
|
+
----
|
|
52
|
+
|
|
53
|
+
=== What's in an Entry
|
|
54
|
+
|
|
55
|
+
Each `Iata::Entry` exposes the fields the JSON-LD wire format populates:
|
|
56
|
+
|
|
57
|
+
[cols="1,2", options="header"]
|
|
58
|
+
|===
|
|
59
|
+
|Attribute|Description
|
|
60
|
+
|`code`|3-letter IATA airport code
|
|
61
|
+
|`name`|English-language name
|
|
62
|
+
|`wikidata_id`|Wikidata entity ID (Q-number) for cross-referencing
|
|
63
|
+
|`country_iso2`|ISO 3166-1 alpha-2 country code
|
|
64
|
+
|`country_name`|Display name for the country (from Wikidata)
|
|
65
|
+
|`latitude`, `longitude`|WGS-84 decimal degrees
|
|
66
|
+
|===
|
|
67
|
+
|
|
68
|
+
[source,ruby]
|
|
69
|
+
----
|
|
70
|
+
entry = Iata.find('PVG')
|
|
71
|
+
|
|
72
|
+
entry.country # => "CN"
|
|
73
|
+
entry.country_name # => "China"
|
|
74
|
+
entry.coordinates # => #<Iata::Coordinates lat=31.1434 lon=121.8052>
|
|
75
|
+
entry.coordinates.distance_to(Iata.find('HKG').coordinates) # => ~1255 km
|
|
76
|
+
----
|
|
77
|
+
|
|
78
|
+
== Data refresh
|
|
79
|
+
|
|
80
|
+
Wikidata updates daily; new airports are added as they receive IATA codes.
|
|
81
|
+
|
|
82
|
+
The gem ships two workflows to keep the bundled data fresh:
|
|
83
|
+
|
|
84
|
+
=== `check-upstream` (scheduled, weekly)
|
|
85
|
+
|
|
86
|
+
`.github/workflows/check-upstream.yml` runs every Monday and queries
|
|
87
|
+
Wikidata for the current IATA airport count. If it differs from the bundled
|
|
88
|
+
count, the workflow opens a `data-update` issue with a refresh link.
|
|
89
|
+
|
|
90
|
+
=== `update-data` (manual dispatch)
|
|
91
|
+
|
|
92
|
+
`.github/workflows/update-data.yml` is what a maintainer runs after the
|
|
93
|
+
weekly check flags drift. It re-queries Wikidata, commits the refreshed
|
|
94
|
+
`lib/iata/data/airports.json` to a branch, and opens a PR. Merging the PR
|
|
95
|
+
does not, by itself, publish a new gem — to ship a new version, trigger
|
|
96
|
+
the `release` workflow with `next_version=patch`.
|
|
97
|
+
|
|
98
|
+
End-to-end refresh flow:
|
|
99
|
+
|
|
100
|
+
. `check-upstream` opens issue: "Wikidata IATA count N (bundled: M)"
|
|
101
|
+
. Maintainer runs `update-data` workflow
|
|
102
|
+
. Workflow opens PR with refreshed `airports.json`
|
|
103
|
+
. Maintainer merges the PR
|
|
104
|
+
. Maintainer triggers `release` workflow with `next_version=patch`
|
|
105
|
+
|
|
106
|
+
Manual local equivalent:
|
|
107
|
+
|
|
108
|
+
[source,sh]
|
|
109
|
+
----
|
|
110
|
+
bundle exec rake iata:fetch # refresh bundled airports.json
|
|
111
|
+
----
|
|
112
|
+
|
|
113
|
+
== Cross-referencing with Wikidata
|
|
114
|
+
|
|
115
|
+
Each `Entry` carries its Wikidata Q-number so you can link out to the
|
|
116
|
+
authoritative record:
|
|
117
|
+
|
|
118
|
+
[source,ruby]
|
|
119
|
+
----
|
|
120
|
+
entry = Iata.find('PVG')
|
|
121
|
+
entry.wikidata_id # => "Q86792"
|
|
122
|
+
# https://www.wikidata.org/wiki/Q86792
|
|
123
|
+
----
|
|
124
|
+
|
|
125
|
+
== Development
|
|
126
|
+
|
|
127
|
+
[source,sh]
|
|
128
|
+
----
|
|
129
|
+
bundle install # install dev deps
|
|
130
|
+
bundle exec rake # spec + rubocop
|
|
131
|
+
bundle exec rake iata:fetch # refresh bundled dataset
|
|
132
|
+
----
|
|
133
|
+
|
|
134
|
+
== Data attribution
|
|
135
|
+
|
|
136
|
+
Bundled data is sourced from Wikidata (CC0). The IATA organisation does not
|
|
137
|
+
publish its code list under an open license; the Wikidata community
|
|
138
|
+
maintains IATA airport codes as structured data derived from public sources.
|
|
139
|
+
|
|
140
|
+
== License
|
|
141
|
+
|
|
142
|
+
BSD-2-Clause. See link:LICENSE[].
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Iata
|
|
4
|
+
# Geographic coordinates (WGS-84) for an IATA airport entry.
|
|
5
|
+
class Coordinates
|
|
6
|
+
attr_reader :latitude, :longitude
|
|
7
|
+
|
|
8
|
+
def initialize(latitude: nil, longitude: nil)
|
|
9
|
+
@latitude = latitude&.to_f
|
|
10
|
+
@longitude = longitude&.to_f
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_a
|
|
14
|
+
[latitude, longitude].compact
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ==(other)
|
|
18
|
+
other.is_a?(Coordinates) &&
|
|
19
|
+
latitude == other.latitude &&
|
|
20
|
+
longitude == other.longitude
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_s
|
|
24
|
+
return '' if latitude.nil? || longitude.nil?
|
|
25
|
+
|
|
26
|
+
format('%<lat>.4f %<lon>.4f', lat: latitude, lon: longitude)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Great-circle distance in kilometres to another Coordinates, using
|
|
30
|
+
# the haversine formula. Returns nil if either side lacks coordinates.
|
|
31
|
+
def distance_to(other)
|
|
32
|
+
return nil if latitude.nil? || longitude.nil? ||
|
|
33
|
+
other.latitude.nil? || other.longitude.nil?
|
|
34
|
+
|
|
35
|
+
earth_radius_km = 6371.0
|
|
36
|
+
d_lat = (other.latitude - latitude) * (Math::PI / 180)
|
|
37
|
+
d_lon = (other.longitude - longitude) * (Math::PI / 180)
|
|
38
|
+
a = (Math.sin(d_lat / 2)**2) +
|
|
39
|
+
(Math.cos(latitude * (Math::PI / 180)) *
|
|
40
|
+
Math.cos(other.latitude * (Math::PI / 180)) *
|
|
41
|
+
(Math.sin(d_lon / 2)**2))
|
|
42
|
+
2 * earth_radius_km * Math.asin(Math.sqrt(a))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|