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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99ccb43a3ef0091206a4e6a7445c48333886f0a26cfd9a1764397e0c5ec46516
4
- data.tar.gz: b2a878137e3861323aaf59f12c0f5f44052b5ed064bc2f519b7247aaca916027
3
+ metadata.gz: d31bdc07c2c1c97fe6e2f3f6de9bd94545f75cd69629a0ecc49171d369d7fee6
4
+ data.tar.gz: afc63731709c038bd56171d50a30ddb8a06253f5fc51e86d2b3f7d36c0540c05
5
5
  SHA512:
6
- metadata.gz: c7c2b0995cb72a450f91ab1c7d37e8c1d0ebb439358a09572e467d4786dd0edca211c904d9194ef42f3e6563ba1719b32041c645d0d25bd2f85c663607e58840
7
- data.tar.gz: 0a3c8914e5d5fc681ef7b83b2062746b382f0281c0ae75475120acb3227d8d2d7349e1c2f0c2769f62e6f8f6130733430f4d2b25db3ce27780989bf9326f4bba
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
- car.years # => 1974..2024 production years
446
- car.segment # => :hatchback / :hot_hatch editorial segment
447
- car.image # => "https://cdn.vehiclesdb.com/volkswagen/golf.webp"
448
- car.image(year: 2020) # year-accurate photo
449
- car.image(year: 2020, color: :silver)
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)