vehicles 0.4.1 → 0.6.1
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 +4 -4
- data/CHANGELOG.md +47 -0
- data/README.md +33 -5
- data/data/plates/PROVENANCE.md +9 -0
- data/data/plates/_decode/es-provinces.yml +116 -0
- data/data/plates/_meta/classes.yml +25 -0
- data/data/plates/de.yml +672 -0
- data/data/plates/es.yml +692 -0
- data/data/plates/nl.yml +972 -0
- data/data/plates/us-fl.yml +518 -0
- data/lib/vehicles/configuration.rb +4 -2
- data/lib/vehicles/model.rb +23 -6
- data/lib/vehicles/plates/jurisdiction.rb +32 -0
- data/lib/vehicles/plates/series.rb +137 -0
- data/lib/vehicles/plates.rb +110 -0
- data/lib/vehicles/providers/hosted_provider.rb +26 -8
- data/lib/vehicles/providers/local_provider.rb +4 -3
- data/lib/vehicles/version.rb +1 -1
- data/lib/vehicles.rb +21 -0
- metadata +12 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d31bdc07c2c1c97fe6e2f3f6de9bd94545f75cd69629a0ecc49171d369d7fee6
|
|
4
|
+
data.tar.gz: afc63731709c038bd56171d50a30ddb8a06253f5fc51e86d2b3f7d36c0540c05
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e0b37318a2131f1c35ecaaca88e72d4d967d9ad134c8777a6f0c2dda0d4105792c7eb2bd749ba0891a94dbac2761b60c947004376b478a3bb66f78e6f01bf2b
|
|
7
|
+
data.tar.gz: 6a215001415080252d699ee3a202043c9685f6286a8763896db3371a81f9458ab01afcb58ca253e2f8a4cac652782564050246fc493911854c4c3756154a089d
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,53 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.1] - 2026-08-01
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `Model#former_ids` — the full canonical ids a record absorbed through the
|
|
15
|
+
dataset's append-only migration contract (e.g. `car/alfa-romeo/159sw`).
|
|
16
|
+
The field was already in the bundled snapshot; the reader now surfaces it,
|
|
17
|
+
so integrators can migrate stored ids without re-parsing the raw JSON.
|
|
18
|
+
Also included in `Model#to_h`.
|
|
19
|
+
|
|
20
|
+
## [0.6.0] - 2026-07-27
|
|
21
|
+
|
|
22
|
+
License plates become a first-class citizen: the PRD-PLATES registration-mark
|
|
23
|
+
dataset ships in the gem, bundled and offline like everything else.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- `Vehicles.plate(input, jurisdiction:)` — two-tier plate validation:
|
|
27
|
+
exact as-issued, then separator-forgiving ("1234XYZ" == "1234 XYZ" ==
|
|
28
|
+
"1234-xyz") with `Match#suggestion` returning the as-issued formatting.
|
|
29
|
+
Leniency forgives punctuation, never the alphabet — strict regexes encode
|
|
30
|
+
what each authority really issues. `Match#strict?` separates
|
|
31
|
+
authority-alphabet hits from recall-only catch-alls (export plates etc.).
|
|
32
|
+
- `Vehicles.plates` / `Vehicles.plates(:nl)` — the full series data:
|
|
33
|
+
73 series across NL/ES/DE/US-FL (gate L0, NL corpus-proven), each with
|
|
34
|
+
pattern, period, class, categories, sourced design facts and citations.
|
|
35
|
+
- Bundled data under `data/plates/` (CC-BY, pinned upstream commit in
|
|
36
|
+
`data/plates/PROVENANCE.md`).
|
|
37
|
+
|
|
38
|
+
The hosted images API is **live** — this release points the wired-up provider
|
|
39
|
+
seam at the real thing.
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
- `Model#image(color:, size:)` returns a rendered variant URL from the live
|
|
43
|
+
VehiclesDB images API (`:sm` 320×180, `:md` 640×360, `:lg` 1280×720, webp).
|
|
44
|
+
Mint a key at <https://vehiclesdb.com/settings/api-keys> and set
|
|
45
|
+
`config.api_key`; without a key it stays nil, as always.
|
|
46
|
+
- `Model#images(color:)` returns the full payload: every variant with
|
|
47
|
+
dimensions, the rendered palette for the model, served-vs-requested color
|
|
48
|
+
(un-rendered colors fall back honestly instead of 404ing), provenance.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
- `config.api_base_url` default is now `https://vehiclesdb.com` (the live API
|
|
52
|
+
origin; endpoint paths carry `/v1`). It must be an ORIGIN — no path suffix.
|
|
53
|
+
- `Model#image` accepts `year:` but does not send it: `year`/`trim` are
|
|
54
|
+
reserved filters server-side (the API 422s on them by contract) until
|
|
55
|
+
year-accurate renders ship.
|
|
56
|
+
|
|
10
57
|
## [0.4.1] - 2026-07-26
|
|
11
58
|
|
|
12
59
|
Data-only refresh to VehiclesDB dataset **2026.07.4** — the July correction
|
data/README.md
CHANGED
|
@@ -432,6 +432,25 @@ Vehicles.makes(region: :eu) # fine — a global snapshot covers the EU
|
|
|
432
432
|
Vehicles.region # => :global
|
|
433
433
|
```
|
|
434
434
|
|
|
435
|
+
## License plates
|
|
436
|
+
|
|
437
|
+
The gem bundles the VehiclesDB **registration-mark dataset** (PRD-PLATES): every plate series per jurisdiction, researched to the issuing authority's own documents — formats, eras, alphabets, designs. Ask it whether a typed registration is real:
|
|
438
|
+
|
|
439
|
+
```ruby
|
|
440
|
+
Vehicles.plate("12-GB-BD", jurisdiction: :nl).valid? # => true — exact, as issued
|
|
441
|
+
Vehicles.plate("12gbbd", jurisdiction: :nl).suggestion # => "12-GB-BD" (did you mean)
|
|
442
|
+
Vehicles.plate("12-AB-CD", jurisdiction: :nl).strict? # => false — vowels aren't issued
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Matching is **two-tier**: exact as-issued first, then a separator-forgiving tier — `"1234XYZ"`, `"1234 xyz"` and `"1234-XYZ"` all resolve to the same serial, with `suggestion` giving the formatting the plate actually wears. Leniency forgives punctuation, **never the alphabet**: the strict regexes encode what the authority really issues (the Dutch vowel purge, the Spanish consonant-triplet rule…). `Match#strict?` separates authority-alphabet hits from recall-only catch-alls (export plates accept any current shape, by law).
|
|
446
|
+
|
|
447
|
+
```ruby
|
|
448
|
+
Vehicles.plates # => every jurisdiction
|
|
449
|
+
Vehicles.plates(:es).series # => 18 series: formats, periods, sourced designs
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Pilot coverage (gate L0): 🇳🇱 🇪🇸 🇩🇪 + US-Florida, 73 series, corpus-proven in NL. Same posture as everything else here: bundled, offline, forgiving in, honest out.
|
|
453
|
+
|
|
435
454
|
## 🔓 More with VehiclesDB
|
|
436
455
|
|
|
437
456
|
`vehicles` is the free, open-source SDK for [**VehiclesDB**](https://vehiclesdb.com) — a hosted API for richer vehicle data. The gem is **fully standalone and always will be**; pointing it at VehiclesDB is purely additive. Drop in an API key and the same objects you already use light up with more:
|
|
@@ -442,11 +461,20 @@ Vehicles.configure do |config|
|
|
|
442
461
|
end
|
|
443
462
|
|
|
444
463
|
car = Vehicles.find("vw golf")
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
car.image
|
|
449
|
-
car.image(
|
|
464
|
+
|
|
465
|
+
# Rendered vehicle imagery — LIVE today. Mint a key at
|
|
466
|
+
# https://vehiclesdb.com/settings/api-keys
|
|
467
|
+
car.image # => "https://vehiclesdb.com/…/md.webp" (640×360)
|
|
468
|
+
car.image(size: :lg) # :sm 320×180 · :md 640×360 · :lg 1280×720
|
|
469
|
+
car.image(color: "red") # color-accurate; un-rendered colors fall back honestly
|
|
470
|
+
car.images(color: "red") # the full payload: every variant + dimensions,
|
|
471
|
+
# rendered palette, served-vs-requested color
|
|
472
|
+
# color slugs are the gem's own canon — Vehicles.colors — so a stored
|
|
473
|
+
# dropdown value maps 1:1 to the rendered imagery.
|
|
474
|
+
|
|
475
|
+
# Enrichment — the wired-up seam; ships next. nil until then, same objects.
|
|
476
|
+
car.years # => 1974..2024 production years
|
|
477
|
+
car.segment # => :hatchback / :hot_hatch editorial segment
|
|
450
478
|
```
|
|
451
479
|
|
|
452
480
|
Under the hood this is a simple **provider** model: a `LocalProvider` (the bundled data) is always available, and a `HostedProvider` activates only when an API key is configured. Calls prefer the hosted data when it's there and **fall back to the local data otherwise — never raising, never blocking** your request:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Bundled plates dataset (PRD-PLATES L0)
|
|
2
|
+
|
|
3
|
+
Copy of `plates/` from the public data repo, refreshed on gem releases:
|
|
4
|
+
|
|
5
|
+
- **Source**: https://github.com/vehiclesdb/vehiclesdb `plates/`
|
|
6
|
+
- **Commit**: `69c8dab39424cf50ff8d1a526216551c8a9cb12f`
|
|
7
|
+
- **License**: CC-BY 4.0 (see the data repo's LICENSE + ATTRIBUTION.md)
|
|
8
|
+
|
|
9
|
+
Refresh: copy the source tree over this directory and update the commit line.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# plates/_decode/es-provinces.yml — Spanish province contraseñas.
|
|
2
|
+
#
|
|
3
|
+
# THE SOURCE FINDING: this table is PRIMARY, not Wikipedia. The EU research
|
|
4
|
+
# dossier recorded that "Wikipedia supplies the full code table" for the
|
|
5
|
+
# pre-2000 Spanish provincial system. It is in fact enacted law: Reglamento
|
|
6
|
+
# General de Vehículos (RD 2822/1998) ANEXO XVIII, section
|
|
7
|
+
# "II. Contraseñas de las placas — A. Siglas de provincias", which lists all
|
|
8
|
+
# 52 codes. Every row below is that table, verbatim, in its own order
|
|
9
|
+
# (alphabetical by province name as the BOE prints it).
|
|
10
|
+
#
|
|
11
|
+
# Referenced by: es-provincial (plates/es.yml) via region_encoding.
|
|
12
|
+
#
|
|
13
|
+
# PERIOD DISCIPLINE (PRD-PLATES §2.4 — "province codes changed over time"):
|
|
14
|
+
# these codes are the set in force in the CONSOLIDATED Anexo XVIII, and they
|
|
15
|
+
# use the CURRENT official province names (Illes Balears, Girona, Lleida,
|
|
16
|
+
# Ourense, A Coruña). Historic contraseñas that predate the RGV and appear on
|
|
17
|
+
# older plates — PM for Baleares, GE for Gerona, OR for Orense, and the
|
|
18
|
+
# pre-1982 forms — are NOT in this primary and are NOT invented here; they are
|
|
19
|
+
# a recorded gap for gate L1/L4. A decode of a physical plate older than the
|
|
20
|
+
# RGV must therefore be treated as unresolved rather than mapped through this
|
|
21
|
+
# table.
|
|
22
|
+
jurisdiction: es
|
|
23
|
+
topic: provinces
|
|
24
|
+
authority:
|
|
25
|
+
name: Reglamento General de Vehículos (RD 2822/1998), Anexo XVIII II.A
|
|
26
|
+
url: "https://www.boe.es/buscar/act.php?id=BOE-A-1999-1826"
|
|
27
|
+
sources:
|
|
28
|
+
- "https://www.boe.es/buscar/pdf/1999/BOE-A-1999-1826-consolidado.pdf # Anexo XVIII, II. Contraseñas de las placas, A. Siglas de provincias — all 52 rows"
|
|
29
|
+
- "https://www.boe.es/buscar/doc.php?id=BOE-A-1999-1826 # original enacted text (in force 26-07-1999), same section"
|
|
30
|
+
period: { start: 1999 }
|
|
31
|
+
period_evidence: instrument-in-force
|
|
32
|
+
period_note: >-
|
|
33
|
+
The contraseñas long predate RD 2822/1998; 1999 is the date of the instrument
|
|
34
|
+
that ENACTS the list read here, not the date the codes came into use. Codes
|
|
35
|
+
remain decodable indefinitely because provincial plates stay valid: RD
|
|
36
|
+
2822/1998 disposición transitoria preserves them, and the Orden of 15-09-2000
|
|
37
|
+
only stopped ISSUING them (in force 17-09-2000).
|
|
38
|
+
|
|
39
|
+
# Ambiguity notes a parse API must carry:
|
|
40
|
+
# * CC decodes to CÁCERES here AND is the consular series prefix
|
|
41
|
+
# (Anexo XVIII I.B.a).3). Disambiguate on group structure, not prefix:
|
|
42
|
+
# provincial = 4 digits + 1-2 letters; consular = two digit groups.
|
|
43
|
+
# * C (A Coruña) vs CA (Cádiz) vs CC (Cáceres) vs CE (Ceuta) vs CO (Córdoba)
|
|
44
|
+
# vs CR (Ciudad Real) vs CS (Castellón) vs CU (Cuenca): the code is
|
|
45
|
+
# MAXIMAL-MUNCH — always take the longest matching code before the digits.
|
|
46
|
+
# * S (Cantabria) vs SA / SE / SG / SO / SS: same rule.
|
|
47
|
+
# * L (Lleida) vs LE / LO / LU: same rule.
|
|
48
|
+
# * O (Asturias) vs OU (Ourense): same rule.
|
|
49
|
+
# * Z (Zaragoza) vs ZA (Zamora): same rule.
|
|
50
|
+
# * Ceuta (CE) and Melilla (ML) are autonomous cities, not provinces; the
|
|
51
|
+
# BOE table lists them under the same heading.
|
|
52
|
+
maximal_munch: true
|
|
53
|
+
|
|
54
|
+
codes:
|
|
55
|
+
- { code: VI, name: "Álava" }
|
|
56
|
+
- { code: AB, name: "Albacete" }
|
|
57
|
+
- { code: A, name: "Alicante" }
|
|
58
|
+
- { code: AL, name: "Almería" }
|
|
59
|
+
- { code: O, name: "Asturias" }
|
|
60
|
+
- { code: AV, name: "Ávila" }
|
|
61
|
+
- { code: BA, name: "Badajoz" }
|
|
62
|
+
- { code: B, name: "Barcelona" }
|
|
63
|
+
- { code: BU, name: "Burgos" }
|
|
64
|
+
- { code: CC, name: "Cáceres" }
|
|
65
|
+
- { code: CA, name: "Cádiz" }
|
|
66
|
+
- { code: S, name: "Cantabria" }
|
|
67
|
+
- { code: CS, name: "Castellón" }
|
|
68
|
+
- { code: CR, name: "Ciudad Real" }
|
|
69
|
+
- { code: CO, name: "Córdoba" }
|
|
70
|
+
- { code: C, name: "A Coruña" }
|
|
71
|
+
- { code: CU, name: "Cuenca" }
|
|
72
|
+
- { code: GI, name: "Girona" }
|
|
73
|
+
- { code: GR, name: "Granada" }
|
|
74
|
+
- { code: GU, name: "Guadalajara" }
|
|
75
|
+
- { code: SS, name: "Guipúzcoa" }
|
|
76
|
+
- { code: H, name: "Huelva" }
|
|
77
|
+
- { code: HU, name: "Huesca" }
|
|
78
|
+
- { code: IB, name: "Illes Balears" }
|
|
79
|
+
- { code: J, name: "Jaén" }
|
|
80
|
+
- { code: LE, name: "León" }
|
|
81
|
+
- { code: L, name: "Lleida" }
|
|
82
|
+
- { code: LU, name: "Lugo" }
|
|
83
|
+
- { code: M, name: "Madrid" }
|
|
84
|
+
- { code: MA, name: "Málaga" }
|
|
85
|
+
- { code: MU, name: "Murcia" }
|
|
86
|
+
- { code: NA, name: "Navarra" }
|
|
87
|
+
- { code: OU, name: "Ourense" }
|
|
88
|
+
- { code: P, name: "Palencia" }
|
|
89
|
+
- { code: GC, name: "Las Palmas" }
|
|
90
|
+
- { code: PO, name: "Pontevedra" }
|
|
91
|
+
- { code: LO, name: "La Rioja" }
|
|
92
|
+
- { code: SA, name: "Salamanca" }
|
|
93
|
+
- { code: TF, name: "Santa Cruz de Tenerife" }
|
|
94
|
+
- { code: SG, name: "Segovia" }
|
|
95
|
+
- { code: SE, name: "Sevilla" }
|
|
96
|
+
- { code: SO, name: "Soria" }
|
|
97
|
+
- { code: T, name: "Tarragona" }
|
|
98
|
+
- { code: TE, name: "Teruel" }
|
|
99
|
+
- { code: TO, name: "Toledo" }
|
|
100
|
+
- { code: V, name: "Valencia" }
|
|
101
|
+
- { code: VA, name: "Valladolid" }
|
|
102
|
+
- { code: BI, name: "Vizcaya" }
|
|
103
|
+
- { code: ZA, name: "Zamora" }
|
|
104
|
+
- { code: Z, name: "Zaragoza" }
|
|
105
|
+
- { code: CE, name: "Ceuta", kind: autonomous-city }
|
|
106
|
+
- { code: ML, name: "Melilla", kind: autonomous-city }
|
|
107
|
+
|
|
108
|
+
# State and NATO contraseñas from the SAME Anexo XVIII section (II.B) are
|
|
109
|
+
# modelled as series in plates/es.yml (es-military-1999, es-nato-fae-1999,
|
|
110
|
+
# es-government-1999, es-police-1999) rather than as decode rows, because they
|
|
111
|
+
# are issuance series in their own right and not a geographic decode.
|
|
112
|
+
state_codes_see_also:
|
|
113
|
+
- "plates/es.yml#es-military-1999 # ET Ejército de Tierra, FN Armada, EA Ejército del Aire"
|
|
114
|
+
- "plates/es.yml#es-government-1999 # MF Fomento, MMA Medio Ambiente, PME Parque Móvil del Estado"
|
|
115
|
+
- "plates/es.yml#es-police-1999 # CNP Cuerpo Nacional de Policía, PGC Guardia Civil"
|
|
116
|
+
- "plates/es.yml#es-nato-fae-1999 # FAE NATO international military headquarters in Spain"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# The controlled vocabulary of plate classes (PRD-PLATES §2.3). A class is a
|
|
2
|
+
# LEGAL/ADMINISTRATIVE issuance category, not a design variant. A
|
|
3
|
+
# jurisdiction's variant becomes its OWN SERIES iff format OR design OR
|
|
4
|
+
# period differs from the standard series; a color-only variant of the same
|
|
5
|
+
# format+period is a sub-entry on the standard series. Grow this file by PR
|
|
6
|
+
# with a definition — never ad hoc in data files.
|
|
7
|
+
standard: the default series issued to private road vehicles
|
|
8
|
+
motorcycle: reduced-size series for motorcycles where format/design differs
|
|
9
|
+
moped: insurance/registration plates for mopeds (NL/DE small plates)
|
|
10
|
+
trailer: trailers and semi-trailers where separately serialized
|
|
11
|
+
diplomatic: diplomatic corps (embassy) issuance, usually its own decode
|
|
12
|
+
consular: consular corps where distinct from diplomatic
|
|
13
|
+
temporary: short-validity plates (transit, awaiting registration)
|
|
14
|
+
export: plates for vehicles leaving the jurisdiction permanently
|
|
15
|
+
dealer: trade/garage plates bound to a business, not a vehicle
|
|
16
|
+
historic: vintage/oldtimer regimes (German H, ES historico)
|
|
17
|
+
taxi: for-hire vehicles where separately serialized or colored
|
|
18
|
+
government: civil government fleets with distinct series
|
|
19
|
+
military: armed-forces registration systems
|
|
20
|
+
police: police fleets where distinct from government
|
|
21
|
+
electric: EV-distinct plates or suffixes (German E, CN green plates)
|
|
22
|
+
seasonal: validity-window plates (German Saisonkennzeichen)
|
|
23
|
+
agricultural: farm vehicles/equipment where separately serialized
|
|
24
|
+
personalized: owner-chosen serials inside an official frame
|
|
25
|
+
specialty: optional-design programs on standard serials (US state programs)
|