vehicles 0.4.1 → 0.8.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 +4 -4
- data/.rubocop_todo.yml +164 -0
- data/CHANGELOG.md +321 -0
- data/README.md +88 -15
- data/data/PROVENANCE-vehicles.md +12 -0
- data/data/plates/PROVENANCE.md +10 -0
- data/data/plates/_decode/at-districts.yml +287 -0
- data/data/plates/_decode/ch-cantons.yml +110 -0
- data/data/plates/_decode/cn-issuing-offices.yml +463 -0
- data/data/plates/_decode/cn-provinces.yml +614 -0
- data/data/plates/_decode/cz-kraj.yml +159 -0
- data/data/plates/_decode/dk-serial-blocks.yml +327 -0
- data/data/plates/_decode/es-provinces.yml +116 -0
- data/data/plates/_decode/fr-departements.yml +191 -0
- data/data/plates/_decode/gb-age-identifiers.yml +170 -0
- data/data/plates/_decode/gb-memory-tags.yml +202 -0
- data/data/plates/_decode/gr-prefectures.yml +1408 -0
- data/data/plates/_decode/hr-cities.yml +315 -0
- data/data/plates/_decode/ie-counties.yml +227 -0
- data/data/plates/_decode/in-state-codes.yml +169 -0
- data/data/plates/_decode/is-districts-1938.yml +116 -0
- data/data/plates/_decode/it-provinces.yml +348 -0
- data/data/plates/_decode/jp-office-marks.yml +960 -0
- data/data/plates/_decode/jp-use-marks.yml +205 -0
- data/data/plates/_decode/kr-authority-marks.yml +146 -0
- data/data/plates/_decode/kr-use-syllables.yml +194 -0
- data/data/plates/_decode/lu-series-order.yml +638 -0
- data/data/plates/_decode/mx-entity-series.yml +380 -0
- data/data/plates/_decode/my-index-marks.yml +271 -0
- data/data/plates/_decode/no-counties-1913.yml +148 -0
- data/data/plates/_decode/no-districts.yml +901 -0
- data/data/plates/_decode/pl-powiats.yml +567 -0
- data/data/plates/_decode/pt-trailer-services.yml +96 -0
- data/data/plates/_decode/ro-counties.yml +213 -0
- data/data/plates/_decode/se-diplomatic.yml +220 -0
- data/data/plates/_decode/si-regions.yml +123 -0
- data/data/plates/_decode/sk-districts.yml +314 -0
- data/data/plates/_decode/th-registration-elements.yml +208 -0
- data/data/plates/_decode/ua-regions.yml +393 -0
- data/data/plates/_decode/za-licence-marks.yml +215 -0
- data/data/plates/_meta/classes.yml +26 -0
- data/data/plates/_meta/separators.yml +102 -0
- data/data/plates/ad.yml +961 -0
- data/data/plates/ar.yml +762 -0
- data/data/plates/at.yml +1424 -0
- data/data/plates/au-act.yml +472 -0
- data/data/plates/au-nsw.yml +282 -0
- data/data/plates/au-nt.yml +431 -0
- data/data/plates/au-qld.yml +272 -0
- data/data/plates/au-sa.yml +248 -0
- data/data/plates/au-tas.yml +302 -0
- data/data/plates/au-vic.yml +215 -0
- data/data/plates/au-wa.yml +309 -0
- data/data/plates/be.yml +1840 -0
- data/data/plates/br.yml +1152 -0
- data/data/plates/ca-ab.yml +430 -0
- data/data/plates/ca-bc.yml +697 -0
- data/data/plates/ca-mb.yml +499 -0
- data/data/plates/ca-nb.yml +537 -0
- data/data/plates/ca-nl.yml +743 -0
- data/data/plates/ca-ns.yml +808 -0
- data/data/plates/ca-nt.yml +610 -0
- data/data/plates/ca-nu.yml +280 -0
- data/data/plates/ca-on.yml +881 -0
- data/data/plates/ca-pe.yml +592 -0
- data/data/plates/ca-qc.yml +1036 -0
- data/data/plates/ca-sk.yml +256 -0
- data/data/plates/ca-yt.yml +656 -0
- data/data/plates/ch.yml +1273 -0
- data/data/plates/cn.yml +1431 -0
- data/data/plates/cy.yml +688 -0
- data/data/plates/cz.yml +1179 -0
- data/data/plates/de.yml +1107 -0
- data/data/plates/dk.yml +1647 -0
- data/data/plates/ee.yml +1275 -0
- data/data/plates/es.yml +888 -0
- data/data/plates/fi.yml +1271 -0
- data/data/plates/fr.yml +1265 -0
- data/data/plates/gb.yml +1188 -0
- data/data/plates/gr.yml +721 -0
- data/data/plates/hr.yml +860 -0
- data/data/plates/hu.yml +959 -0
- data/data/plates/ie.yml +775 -0
- data/data/plates/in.yml +1172 -0
- data/data/plates/is.yml +667 -0
- data/data/plates/it.yml +1317 -0
- data/data/plates/jp.yml +3650 -0
- data/data/plates/kr.yml +1375 -0
- data/data/plates/li.yml +1010 -0
- data/data/plates/lt.yml +879 -0
- data/data/plates/lu.yml +842 -0
- data/data/plates/lv.yml +924 -0
- data/data/plates/mc.yml +1024 -0
- data/data/plates/mt.yml +854 -0
- data/data/plates/mx.yml +1372 -0
- data/data/plates/my.yml +685 -0
- data/data/plates/nl.yml +1016 -0
- data/data/plates/no.yml +1018 -0
- data/data/plates/nz.yml +1699 -0
- data/data/plates/pl.yml +1296 -0
- data/data/plates/pt.yml +847 -0
- data/data/plates/ro.yml +785 -0
- data/data/plates/se.yml +1091 -0
- data/data/plates/si.yml +1105 -0
- data/data/plates/sk.yml +1439 -0
- data/data/plates/sm.yml +1119 -0
- data/data/plates/th.yml +1150 -0
- data/data/plates/ua.yml +1672 -0
- data/data/plates/us-ak.yml +763 -0
- data/data/plates/us-al.yml +457 -0
- data/data/plates/us-ar.yml +427 -0
- data/data/plates/us-as.yml +454 -0
- data/data/plates/us-az.yml +430 -0
- data/data/plates/us-ca.yml +892 -0
- data/data/plates/us-co.yml +452 -0
- data/data/plates/us-ct.yml +427 -0
- data/data/plates/us-dc.yml +614 -0
- data/data/plates/us-de.yml +551 -0
- data/data/plates/us-fl.yml +741 -0
- data/data/plates/us-ga.yml +644 -0
- data/data/plates/us-gu.yml +658 -0
- data/data/plates/us-hi.yml +585 -0
- data/data/plates/us-ia.yml +438 -0
- data/data/plates/us-id.yml +531 -0
- data/data/plates/us-il.yml +516 -0
- data/data/plates/us-in.yml +324 -0
- data/data/plates/us-ks.yml +351 -0
- data/data/plates/us-ky.yml +770 -0
- data/data/plates/us-la.yml +568 -0
- data/data/plates/us-ma.yml +379 -0
- data/data/plates/us-md.yml +536 -0
- data/data/plates/us-me.yml +445 -0
- data/data/plates/us-mi.yml +408 -0
- data/data/plates/us-mn.yml +411 -0
- data/data/plates/us-mo.yml +356 -0
- data/data/plates/us-mp.yml +402 -0
- data/data/plates/us-ms.yml +432 -0
- data/data/plates/us-mt.yml +619 -0
- data/data/plates/us-nc.yml +602 -0
- data/data/plates/us-nd.yml +419 -0
- data/data/plates/us-ne.yml +483 -0
- data/data/plates/us-nh.yml +394 -0
- data/data/plates/us-nj.yml +547 -0
- data/data/plates/us-nm.yml +574 -0
- data/data/plates/us-nv.yml +655 -0
- data/data/plates/us-ny.yml +592 -0
- data/data/plates/us-oh.yml +404 -0
- data/data/plates/us-ok.yml +513 -0
- data/data/plates/us-or.yml +392 -0
- data/data/plates/us-pa.yml +506 -0
- data/data/plates/us-pr.yml +507 -0
- data/data/plates/us-ri.yml +445 -0
- data/data/plates/us-sc.yml +605 -0
- data/data/plates/us-sd.yml +428 -0
- data/data/plates/us-tn.yml +471 -0
- data/data/plates/us-tx.yml +535 -0
- data/data/plates/us-ut.yml +384 -0
- data/data/plates/us-va.yml +567 -0
- data/data/plates/us-vi.yml +489 -0
- data/data/plates/us-vt.yml +458 -0
- data/data/plates/us-wa.yml +484 -0
- data/data/plates/us-wi.yml +509 -0
- data/data/plates/us-wv.yml +446 -0
- data/data/plates/us-wy.yml +523 -0
- data/data/plates/va.yml +604 -0
- data/data/plates/za.yml +1141 -0
- data/data/vehicles.json +160653 -105090
- data/lib/vehicles/configuration.rb +18 -2
- data/lib/vehicles/dataset.rb +73 -18
- data/lib/vehicles/fuzzy.rb +115 -0
- data/lib/vehicles/http.rb +48 -0
- data/lib/vehicles/make.rb +36 -6
- data/lib/vehicles/mcp_server.rb +5 -5
- data/lib/vehicles/model.rb +42 -6
- data/lib/vehicles/plates/jurisdiction.rb +32 -0
- data/lib/vehicles/plates/series.rb +291 -0
- data/lib/vehicles/plates/template_fill.rb +188 -0
- data/lib/vehicles/plates/templates.rb +162 -0
- data/lib/vehicles/plates.rb +122 -0
- data/lib/vehicles/providers/hosted_provider.rb +49 -58
- data/lib/vehicles/providers/local_provider.rb +4 -3
- data/lib/vehicles/validators/vehicle_make_validator.rb +3 -1
- data/lib/vehicles/validators/vehicle_model_validator.rb +1 -1
- data/lib/vehicles/version.rb +1 -1
- data/lib/vehicles.rb +53 -16
- data/rakelib/data_refresh.rake +109 -0
- data/rakelib/plates_refresh.rake +29 -0
- data/sig/vehicles.rbs +18 -0
- metadata +174 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c9ab45bf3b30e2ab2688becf7e36d4c67a1f40267324cec67b3df7955eb874db
|
|
4
|
+
data.tar.gz: 2fac8f7b9d499000730c0ecb3e4fa98d2555a06ce1c7ce8e5d82a1c730ef9573
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a2ac35c05cbd762cd5f818291c30792c1b8e69c18efe699f5b9408f9a35b23bd2646217f4333ca09ca7ef75c54c464eb2dedfdf4433cb7a9563712d69116c90c
|
|
7
|
+
data.tar.gz: bfcc408a806116de713664e4acf300edc515e9bf0a98075f4fa943520683e13b1b0700fa616635e2cf3cc2e73d08db8f97ba4e3dd606ed726ef0b5d653827076
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config --no-exclude-limit`
|
|
3
|
+
# on 2026-10-10 04:04:37 UTC using RuboCop version 1.91.0.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 5
|
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
11
|
+
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
|
12
|
+
# SupportedStyles: with_first_argument, with_fixed_indentation
|
|
13
|
+
Layout/ArgumentAlignment:
|
|
14
|
+
Exclude:
|
|
15
|
+
- 'lib/vehicles/plates/series.rb'
|
|
16
|
+
- 'test/plates_test.rb'
|
|
17
|
+
|
|
18
|
+
# Offense count: 1
|
|
19
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
20
|
+
# Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, DefLikeMacros, AllowAdjacentOneLineDefs, NumberOfEmptyLines.
|
|
21
|
+
Layout/EmptyLineBetweenDefs:
|
|
22
|
+
Exclude:
|
|
23
|
+
- 'test/plates_test.rb'
|
|
24
|
+
|
|
25
|
+
# Offense count: 1
|
|
26
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
27
|
+
# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
|
|
28
|
+
Layout/ExtraSpacing:
|
|
29
|
+
Exclude:
|
|
30
|
+
- 'lib/vehicles/plates/series.rb'
|
|
31
|
+
|
|
32
|
+
# Offense count: 1
|
|
33
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
34
|
+
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
|
35
|
+
# SupportedStyles: aligned, indented, indented_relative_to_receiver
|
|
36
|
+
Layout/MultilineMethodCallIndentation:
|
|
37
|
+
Exclude:
|
|
38
|
+
- 'lib/vehicles/plates/jurisdiction.rb'
|
|
39
|
+
|
|
40
|
+
# Offense count: 1
|
|
41
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
42
|
+
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
|
43
|
+
# SupportedStyles: aligned, indented
|
|
44
|
+
Layout/MultilineOperationIndentation:
|
|
45
|
+
Exclude:
|
|
46
|
+
- 'lib/vehicles/plates/series.rb'
|
|
47
|
+
|
|
48
|
+
# Offense count: 1
|
|
49
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
50
|
+
# Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator, EnforcedStyleForRationalLiterals.
|
|
51
|
+
# SupportedStylesForExponentOperator: space, no_space
|
|
52
|
+
# SupportedStylesForRationalLiterals: space, no_space
|
|
53
|
+
Layout/SpaceAroundOperators:
|
|
54
|
+
Exclude:
|
|
55
|
+
- 'lib/vehicles/plates/series.rb'
|
|
56
|
+
|
|
57
|
+
# Offense count: 58
|
|
58
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
59
|
+
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets.
|
|
60
|
+
# SupportedStyles: space, no_space, compact
|
|
61
|
+
# SupportedStylesForEmptyBrackets: space, no_space
|
|
62
|
+
Layout/SpaceInsideArrayLiteralBrackets:
|
|
63
|
+
Exclude:
|
|
64
|
+
- 'lib/vehicles/plates.rb'
|
|
65
|
+
- 'lib/vehicles/plates/jurisdiction.rb'
|
|
66
|
+
- 'lib/vehicles/plates/series.rb'
|
|
67
|
+
- 'test/plates_test.rb'
|
|
68
|
+
|
|
69
|
+
# Offense count: 1
|
|
70
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
71
|
+
Lint/RedundantDirGlobSort:
|
|
72
|
+
Exclude:
|
|
73
|
+
- 'lib/vehicles/plates.rb'
|
|
74
|
+
|
|
75
|
+
# Offense count: 4
|
|
76
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
77
|
+
Metrics/AbcSize:
|
|
78
|
+
Exclude:
|
|
79
|
+
- 'lib/vehicles/plates/series.rb'
|
|
80
|
+
|
|
81
|
+
# Offense count: 1
|
|
82
|
+
# Configuration parameters: CountBlocks, CountModifierForms, Max.
|
|
83
|
+
Metrics/BlockNesting:
|
|
84
|
+
Exclude:
|
|
85
|
+
- 'lib/vehicles/plates/series.rb'
|
|
86
|
+
|
|
87
|
+
# Offense count: 1
|
|
88
|
+
# Configuration parameters: CountComments, Max, CountAsOne.
|
|
89
|
+
Metrics/ClassLength:
|
|
90
|
+
Exclude:
|
|
91
|
+
- 'lib/vehicles/mcp_server.rb'
|
|
92
|
+
- 'lib/vehicles/plates/series.rb'
|
|
93
|
+
|
|
94
|
+
# Offense count: 2
|
|
95
|
+
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
96
|
+
Metrics/MethodLength:
|
|
97
|
+
Exclude:
|
|
98
|
+
- 'lib/vehicles/plates/series.rb'
|
|
99
|
+
|
|
100
|
+
# Offense count: 1
|
|
101
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
102
|
+
Minitest/AssertPredicate:
|
|
103
|
+
Exclude:
|
|
104
|
+
- 'test/model_test.rb'
|
|
105
|
+
|
|
106
|
+
# Offense count: 11
|
|
107
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
108
|
+
Minitest/EmptyLineBeforeAssertionMethods:
|
|
109
|
+
Exclude:
|
|
110
|
+
- 'test/model_test.rb'
|
|
111
|
+
- 'test/plates_test.rb'
|
|
112
|
+
|
|
113
|
+
# Offense count: 13
|
|
114
|
+
# Configuration parameters: MinSize.
|
|
115
|
+
Performance/CollectionLiteralInLoop:
|
|
116
|
+
Exclude:
|
|
117
|
+
- 'lib/vehicles/plates/series.rb'
|
|
118
|
+
- 'test/plates_test.rb'
|
|
119
|
+
|
|
120
|
+
# Offense count: 1
|
|
121
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
122
|
+
# Configuration parameters: EnforcedStyle.
|
|
123
|
+
# SupportedStyles: always, always_true, never
|
|
124
|
+
Style/FrozenStringLiteralComment:
|
|
125
|
+
Exclude:
|
|
126
|
+
- '**/*.arb'
|
|
127
|
+
- 'rakelib/plates_refresh.rake'
|
|
128
|
+
|
|
129
|
+
# Offense count: 1
|
|
130
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
131
|
+
Style/NestedTernaryOperator:
|
|
132
|
+
Exclude:
|
|
133
|
+
- 'lib/vehicles/plates/series.rb'
|
|
134
|
+
|
|
135
|
+
# Offense count: 1
|
|
136
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
137
|
+
Style/PerlBackrefs:
|
|
138
|
+
Exclude:
|
|
139
|
+
- 'lib/vehicles/plates/series.rb'
|
|
140
|
+
|
|
141
|
+
# Offense count: 2
|
|
142
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
143
|
+
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
|
|
144
|
+
# SupportedStyles: single_quotes, double_quotes
|
|
145
|
+
Style/StringLiterals:
|
|
146
|
+
Exclude:
|
|
147
|
+
- 'test/plates_test.rb'
|
|
148
|
+
|
|
149
|
+
# Offense count: 3
|
|
150
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
151
|
+
# Configuration parameters: EnforcedStyle.
|
|
152
|
+
# SupportedStyles: single_quotes, double_quotes
|
|
153
|
+
Style/StringLiteralsInInterpolation:
|
|
154
|
+
Exclude:
|
|
155
|
+
- 'lib/vehicles/plates.rb'
|
|
156
|
+
- 'lib/vehicles/plates/series.rb'
|
|
157
|
+
|
|
158
|
+
# Offense count: 1
|
|
159
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
160
|
+
# Configuration parameters: WordRegex.
|
|
161
|
+
# SupportedStyles: percent, brackets
|
|
162
|
+
Style/WordArray:
|
|
163
|
+
EnforcedStyle: percent
|
|
164
|
+
MinSize: 3
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,327 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-11-08
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Plate art without sending the plate.** `Vehicles::Plates.render(registration,
|
|
15
|
+
jurisdiction:, region: nil, label: nil)` draws a registration on its series'
|
|
16
|
+
real VehiclesDB plate as an SVG, and nothing personal leaves the machine: the
|
|
17
|
+
gem picks the series locally (the bundled matcher; the only standard-class
|
|
18
|
+
hit, else the only hit — ambiguous plates such as German `MAB1234` answer
|
|
19
|
+
nil instead of the wrong plate), derives the shape (`NNNN LLL`), fetches the
|
|
20
|
+
BLANK template `GET {api_base_url}/plates/:code/:series_id/template.svg?shape=®ion=`
|
|
21
|
+
and fills it here. No API key is sent (the route is public). Returns nil on
|
|
22
|
+
any failure, never raises.
|
|
23
|
+
- `Vehicles::Plates.template(code:, series:, shape: nil, region: nil)`: the
|
|
24
|
+
blank template, or nil. Client-side fences refuse a shape that is not pure
|
|
25
|
+
N/L classes and separators, so a registration passed by mistake never
|
|
26
|
+
reaches the wire. Cached in-process by default; `config.plate_template_cache`
|
|
27
|
+
takes any `read` / `write(key, value, expires_in:)` store (e.g. `Rails.cache`)
|
|
28
|
+
and `config.plate_template_ttl` (default one day) the lifetime. Failures are
|
|
29
|
+
remembered for five minutes, so an unreachable server costs one timeout per
|
|
30
|
+
template per window, not one per call. Keys carry the template schema and
|
|
31
|
+
gem version.
|
|
32
|
+
- `Vehicles::Plates::TemplateFill`: the reference filler, moved verbatim from
|
|
33
|
+
vehiclesdb-web (`fill`, `metadata`, `groups`, and the shared fit formulas
|
|
34
|
+
`fit_size` / `recentered_baseline` the VehiclesDB renderer will call from
|
|
35
|
+
here), plus `shape_of` and a `label:` option for a localized accessible
|
|
36
|
+
name. Standard library only; the file loads on its own in a gem-less Ruby.
|
|
37
|
+
- Templates are inlined into host pages, so both the fetch and
|
|
38
|
+
`TemplateFill.fill` itself refuse a template carrying anything active or
|
|
39
|
+
external (`<script>`, event handlers including `<svg/onload=…>`,
|
|
40
|
+
`javascript:`, non-`data:` hrefs and `url()`s): `TemplateFill.inert?`.
|
|
41
|
+
- `region:` takes subdivision keys only (`75`, `2A`, `971`, `44-bzh`, `BY`,
|
|
42
|
+
`ZH`, `9`), so a registration passed there by mistake is refused locally
|
|
43
|
+
and never sent.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- The HTTP plumbing (timeout, no silent retry, nil on failure) moved from
|
|
48
|
+
`HostedProvider` into `Vehicles::HTTP`, shared by images and plate
|
|
49
|
+
templates. Behaviour of the images calls is unchanged.
|
|
50
|
+
|
|
51
|
+
## [0.7.9] - 2026-11-08
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- **Hosted images now reach the API.** `HostedProvider` requested
|
|
56
|
+
`https://vehiclesdb.com/v1/vehicles/…/images`, but the VehiclesDB API lives
|
|
57
|
+
under **`/api/v1`**: `/v1/…` is the website's HTML 404, so `Model#image` /
|
|
58
|
+
`Model#images` returned nil for every key since 0.5.0. Requests now go to
|
|
59
|
+
`GET {api_base_url}/api/v1/vehicles/:kind/:make_slug/:model_slug/images`
|
|
60
|
+
(`HostedProvider::API_PREFIX`). `config.api_base_url` is still the origin
|
|
61
|
+
and still overridable (`"http://localhost:3030"` for a local server); a
|
|
62
|
+
trailing slash or a proxy path prefix on it is now kept as written
|
|
63
|
+
instead of being dropped by `URI.join`. Pinned by tests over a real local
|
|
64
|
+
socket: the exact request line, the Bearer header, and nil on a 404 HTML
|
|
65
|
+
page, a 401, a non-JSON 200 and a refused connection.
|
|
66
|
+
- **One hosted request is one request.** Net::HTTP re-sends an idempotent
|
|
67
|
+
GET once after a read timeout, so a slow images response was asked for
|
|
68
|
+
twice: double the latency `api_timeout` promises to cap, and two billed
|
|
69
|
+
calls when the second one is served (seen against a cold local server).
|
|
70
|
+
`max_retries` is now 0; pinned by a socket test that counts connections.
|
|
71
|
+
- **A name that exists as several kinds answers with the car.**
|
|
72
|
+
`Vehicles.model("Toyota", "Land Cruiser")` returned the **bus** (the first
|
|
73
|
+
record of four kinds). Without `kind:`, `Make#model` / `Vehicles.model` /
|
|
74
|
+
`Vehicles.find` now prefer the `:car` record and keep the first record
|
|
75
|
+
when there is no car. Over every model name and slug in the bundled data
|
|
76
|
+
this moves 51 names from bus to car — same make and model, never a
|
|
77
|
+
different one.
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
|
|
81
|
+
- `kind:` on `Vehicles.model` and `Make#model` to pick the kind explicitly:
|
|
82
|
+
`Vehicles.model("Toyota", "Land Cruiser", kind: :bus)`.
|
|
83
|
+
- **Spacing-blind model names.** When no name matches exactly, `Make#model`
|
|
84
|
+
compares letters and digits only, so `"XCeed"` is Kia's `"X Ceed"`, `"A 5"`
|
|
85
|
+
is Audi `"A5"`, `"CX5"` is `"CX-5"`, `"XC 90"` is `"XC90"` — but only when
|
|
86
|
+
that lands on ONE name (never a guess between two), and never partially
|
|
87
|
+
(`"X Cee"` stays nil). The model validator answers the same way: spacing
|
|
88
|
+
is not a typo.
|
|
89
|
+
- **BMW's Spanish/Italian `"Serie N"`** reads as `"N Series"`
|
|
90
|
+
(`Vehicles.model("BMW", "Serie 3")` → 3 Series); a real `"Serie …"` name
|
|
91
|
+
(`"Serie X1"`) still wins.
|
|
92
|
+
- Measured on a Spanish carpooling app's 1,329 free-text vehicles (make/model
|
|
93
|
+
typed or picked in Spanish): 17 more make/model pairs (23 vehicles) now
|
|
94
|
+
resolve, and the 3 Land Cruisers resolve to the car. Internal double
|
|
95
|
+
spaces were already collapsed by `Vehicles.normalize`; now pinned by a test.
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
|
|
99
|
+
- `Model#years` / `Model#segment` no longer spend a request: the API serves
|
|
100
|
+
no endpoint for them yet (the old `/v1/models/:slug` never existed), so
|
|
101
|
+
the hosted provider answers nil without touching the network and the
|
|
102
|
+
chain falls through to the local data, exactly as before. They light up
|
|
103
|
+
when the API ships them. `HostedProvider.reset!` (its per-process cache)
|
|
104
|
+
is gone with it.
|
|
105
|
+
- README: the plates endpoints are `/api/v1/plates/…`.
|
|
106
|
+
|
|
107
|
+
## [0.7.8] - 2026-10-10
|
|
108
|
+
|
|
109
|
+
### Added
|
|
110
|
+
|
|
111
|
+
- **Typo-tolerant make lookup.** `Vehicles.make`, `Vehicles.models` and
|
|
112
|
+
every make-taking helper now fall back to the closest make by edit
|
|
113
|
+
distance when nothing matches exactly: `"marcedes"` → Mercedes-Benz,
|
|
114
|
+
`"volkswagon"` → Volkswagen, `"DeLorean"` → De Lorean. Bounded
|
|
115
|
+
(Levenshtein 1 for 4-5 characters, 2 from 6 up, never under 4), stdlib
|
|
116
|
+
only, and never a guess: when two different makes are equally close
|
|
117
|
+
(`"Acra"`: Acura / Acma) the answer is `nil`. Exact, alias and slug
|
|
118
|
+
matches always win; `Vehicles.find` runs its exact pass over every
|
|
119
|
+
make/model split before retrying a misspelled make, so no answer that
|
|
120
|
+
resolved in 0.7.7 changes. Opt out per call with `fuzzy: false`
|
|
121
|
+
(`make`, `models`, `model`, `model_options`, `find`). Guards: optimal
|
|
122
|
+
string alignment (an adjacent swap is one edit — `"telsa"` ties Tesla/
|
|
123
|
+
Temsa → nil, never Temsa); a candidate never has fewer words than the
|
|
124
|
+
query (`"Volvo V 60"` cannot become Volvo "60"); every word keeps its
|
|
125
|
+
first letter (`"citroen e"` is not Citroën DS); the configured
|
|
126
|
+
`other_label` is never fuzzy-matched. Verified: 0 changed / 0 lost
|
|
127
|
+
answers over 37,050 `find` and 65,871 web-resolver-style queries.
|
|
128
|
+
- `Model#country_ranks` / `Model#rank_in(country)` — the model's rank
|
|
129
|
+
among all models of its kind in that country (dataset key
|
|
130
|
+
`country_ranks`, from `catalog/` `popularity.by_country[cc].rank`).
|
|
131
|
+
- `Model#mass_decile` — per-kind registration-mass decile (1 = heaviest),
|
|
132
|
+
the dataset's `popularity.mass_decile` (2026.10.1+, pipeline#255 /
|
|
133
|
+
ruling R3); nil-safe on older snapshots (the bundled 2026.10.0 has none).
|
|
134
|
+
`global_decile` stays what it is — a presence average.
|
|
135
|
+
`top_models(by: :mass_decile)` ranks by it (records without it are
|
|
136
|
+
excluded, so it is `[]` on 2026.10.0 data); `by:` defaults to
|
|
137
|
+
`:global_decile`; anything else raises ArgumentError. With `country:`
|
|
138
|
+
the country's rank still sorts first (the decile breaks ties).
|
|
139
|
+
`Model#to_h` gains `:mass_decile`.
|
|
140
|
+
- `rake "data:refresh[<tag>]"` — refreshes `data/vehicles.json` from a
|
|
141
|
+
dataset release tag and writes `data/PROVENANCE-vehicles.md`; fills
|
|
142
|
+
`country_ranks` from the same tag's catalog until the projection ships
|
|
143
|
+
the key natively (then it asserts equality instead).
|
|
144
|
+
|
|
145
|
+
### Changed
|
|
146
|
+
|
|
147
|
+
- **`top_models(country:)` orders by that country's own rank.** Until now a
|
|
148
|
+
country-filtered list kept the GLOBAL order (`global_decile`, a
|
|
149
|
+
presence-weighted average across countries), so the UK top-10 read in
|
|
150
|
+
everybody else's order. Models available there without a rank there
|
|
151
|
+
follow in the old order; data without `country_ranks` degrades to the
|
|
152
|
+
0.7.7 order. Ranks are per kind — pass `kind:` for a clean ranking.
|
|
153
|
+
- Bundled dataset refreshed 2026.07.4 → **2026.10.0** (14,997 models, 15
|
|
154
|
+
countries; `dist/vehicles.json` at tag v2026.10.0 + `country_ranks`).
|
|
155
|
+
- The make and model validators stay EXACT (`fuzzy: false`): a typo never
|
|
156
|
+
validates as a stored make.
|
|
157
|
+
|
|
158
|
+
- Fuzzy matching is for human-typed names only: Symbols, input containing
|
|
159
|
+
`/`, `_`, `+` or `\` (ids, paths), hyphen-edged strings and single-case
|
|
160
|
+
hyphenated slugs (`marcedes-benz`, `MARCEDES-BENZ`) resolve exactly or
|
|
161
|
+
not at all; the MCP server's tools are exact-only.
|
|
162
|
+
- CI: the 111 rubocop offenses inherited from main are frozen (110 in a
|
|
163
|
+
generated `.rubocop_todo.yml`, plus `plates/series.rb` in `.rubocop.yml`'s
|
|
164
|
+
own ClassLength Exclude, which overrides the todo) — no code changes — so
|
|
165
|
+
the Lint job is green again; new code is fully linted.
|
|
166
|
+
|
|
167
|
+
### Upgrade notes
|
|
168
|
+
|
|
169
|
+
- Apps that route or 404 on `Vehicles.make(param)`: slug-shaped params
|
|
170
|
+
(`marcedes-benz`, anything with `/`, `_`, `+`, a Symbol) never fuzz, but
|
|
171
|
+
a single-word param still does (`/makes/marcedes` → param `"marcedes"` →
|
|
172
|
+
Mercedes-Benz). If a misspelled URL must 404 (or 301 to the canonical
|
|
173
|
+
slug), call `Vehicles.make(param, fuzzy: false)` there.
|
|
174
|
+
|
|
175
|
+
## [0.7.7] - 2026-08-03
|
|
176
|
+
|
|
177
|
+
### Changed
|
|
178
|
+
|
|
179
|
+
- Plates dataset refreshed — the overnight swarm passes' settlements
|
|
180
|
+
land: the Cypriot centre date mark, Brazil's square-dot printed form
|
|
181
|
+
and photographed moto split, San Marino's structured legend/sigla
|
|
182
|
+
fields, Ukraine's statutory line counts, California's pixel-sampled
|
|
183
|
+
colours and corner-sticker guides, the Texas exempt restatement,
|
|
184
|
+
Korea's corporate characters block, Thailand's seven-photo
|
|
185
|
+
cross-check, and China's two-row trailer + NEV dedicated-mark flips
|
|
186
|
+
(#288-#290).
|
|
187
|
+
|
|
188
|
+
## [0.7.5] - 2026-08-03
|
|
189
|
+
|
|
190
|
+
### Added
|
|
191
|
+
|
|
192
|
+
- `Plates.decode_table(name)` — the _decode lookups (district/office/
|
|
193
|
+
use-mark tables) exposed to consumers, enabling serial-driven
|
|
194
|
+
subregion resolution (renderers picking the right Land arms from a
|
|
195
|
+
district prefix).
|
|
196
|
+
|
|
197
|
+
## [0.7.4] - 2026-08-03
|
|
198
|
+
|
|
199
|
+
### Added
|
|
200
|
+
|
|
201
|
+
- South Korea (21 series + hangul decode tables) — corpus: 124
|
|
202
|
+
jurisdictions / 1,381 series.
|
|
203
|
+
|
|
204
|
+
## [0.7.3] - 2026-08-03
|
|
205
|
+
|
|
206
|
+
### Fixed
|
|
207
|
+
|
|
208
|
+
- Pattern-language literal escapes: ca-nb-truck-2003 introduced "\L"
|
|
209
|
+
(a literal L, vs the any-letter placeholder). New Series#display_pattern
|
|
210
|
+
resolves escapes for display and slot walks; the round-trip test
|
|
211
|
+
substitutes placeholders escape-aware. Escape convention flagged to the
|
|
212
|
+
data maintainers for a ruling.
|
|
213
|
+
|
|
214
|
+
## [0.7.2] - 2026-08-03
|
|
215
|
+
|
|
216
|
+
### Added
|
|
217
|
+
|
|
218
|
+
- The L3 wave: 28 jurisdiction files across five continents (jp cn in
|
|
219
|
+
th my br mx ar nz za ua + Australia's 8 states + Canada's 13
|
|
220
|
+
provinces/territories), 415 series and 10 more decode tables incl.
|
|
221
|
+
Japan's 138-mark statutory office table. Corpus now: 123
|
|
222
|
+
jurisdictions / 1,360 series / 34 decode tables.
|
|
223
|
+
|
|
224
|
+
## [0.7.1] - 2026-08-02
|
|
225
|
+
|
|
226
|
+
### Added
|
|
227
|
+
|
|
228
|
+
- Plates corpus refreshed to 91 jurisdictions (the EU/EEA wave-2 landing:
|
|
229
|
+
ie dk no is pt lu pl cz sk hu ro si hr ee lv lt gr cy mt + microstates)
|
|
230
|
+
with 22 decode tables.
|
|
231
|
+
|
|
232
|
+
## [0.7.0] - 2026-08-02
|
|
233
|
+
|
|
234
|
+
### Added
|
|
235
|
+
|
|
236
|
+
- The FULL plates corpus ships in the gem: 67 jurisdictions / 606 series
|
|
237
|
+
(the 8-country L1 EU wave, all 50 US states + DC + 5 territories, and
|
|
238
|
+
the redated pilots) + 10 decode tables — up from the 4 pilot files.
|
|
239
|
+
The art tier stays in the data repo; the gem bundles format data.
|
|
240
|
+
|
|
241
|
+
## [0.6.4] - 2026-08-02
|
|
242
|
+
|
|
243
|
+
### Changed
|
|
244
|
+
|
|
245
|
+
- Bundled plates data refreshed from the redate pass: es-provincial is now
|
|
246
|
+
1971-2000 pinned to Decreto 2046/1971 at both ends (was a 1999-2000
|
|
247
|
+
instrument window), plus the 1900-1971 Spanish numeric era, the German
|
|
248
|
+
1956-2000 DIN era, 11 German and 10 Florida period corrections — all
|
|
249
|
+
cited to gazette primaries.
|
|
250
|
+
- `approximate_start?` covers the two new honesty vocabularies
|
|
251
|
+
(instrument-in-force-upper-bound, secondary-locator-unverified), so
|
|
252
|
+
upper-bounded and uncited-secondary starts render with the "~".
|
|
253
|
+
|
|
254
|
+
## [0.6.3] - 2026-08-02
|
|
255
|
+
|
|
256
|
+
### Changed
|
|
257
|
+
|
|
258
|
+
- Plate period labels read naturally: open series say "2000 → today", and
|
|
259
|
+
instrument-dated starts mark approximation as "~1999" instead of the
|
|
260
|
+
cryptic "≤1999". New `Series#approximate_start?` so displays can explain
|
|
261
|
+
the tilde ("documented from this year; the format may be older").
|
|
262
|
+
|
|
263
|
+
## [0.6.2] - 2026-08-02
|
|
264
|
+
|
|
265
|
+
### Fixed
|
|
266
|
+
|
|
267
|
+
- `Plates::Series#format_serial` reconstructed variable-length serials by
|
|
268
|
+
walking the fixed display pattern, misplacing separators ("M1234LA" came
|
|
269
|
+
back as "M1-234L-A" instead of "M-1234-LA"). The pattern walk now applies
|
|
270
|
+
only when the serial exactly fills the pattern; length-mismatched serials
|
|
271
|
+
reconstruct from the regex segmented at its separators (new
|
|
272
|
+
`Series.segment_separators`, riding the dataset separator contract), and
|
|
273
|
+
a serial neither path can place comes back untouched rather than
|
|
274
|
+
mis-punctuated.
|
|
275
|
+
|
|
276
|
+
### Changed
|
|
277
|
+
|
|
278
|
+
- `Plates::Series#period_label` no longer presents instrument-dated starts
|
|
279
|
+
as the series era: rows whose `period_evidence` is `instrument-in-force`
|
|
280
|
+
or `instrument-window` label as "≤1999–2000" ("began by", not "began
|
|
281
|
+
in"). New `Series#period_evidence`, `#issued_regexp`,
|
|
282
|
+
`#issued_separators` readers for consumers mirroring the reconstruction.
|
|
283
|
+
|
|
284
|
+
## [0.6.1] - 2026-08-01
|
|
285
|
+
|
|
286
|
+
### Added
|
|
287
|
+
|
|
288
|
+
- `Model#former_ids` — the full canonical ids a record absorbed through the
|
|
289
|
+
dataset's append-only migration contract (e.g. `car/alfa-romeo/159sw`).
|
|
290
|
+
The field was already in the bundled snapshot; the reader now surfaces it,
|
|
291
|
+
so integrators can migrate stored ids without re-parsing the raw JSON.
|
|
292
|
+
Also included in `Model#to_h`.
|
|
293
|
+
|
|
294
|
+
## [0.6.0] - 2026-07-27
|
|
295
|
+
|
|
296
|
+
License plates become a first-class citizen: the PRD-PLATES registration-mark
|
|
297
|
+
dataset ships in the gem, bundled and offline like everything else.
|
|
298
|
+
|
|
299
|
+
### Added
|
|
300
|
+
- `Vehicles.plate(input, jurisdiction:)` — two-tier plate validation:
|
|
301
|
+
exact as-issued, then separator-forgiving ("1234XYZ" == "1234 XYZ" ==
|
|
302
|
+
"1234-xyz") with `Match#suggestion` returning the as-issued formatting.
|
|
303
|
+
Leniency forgives punctuation, never the alphabet — strict regexes encode
|
|
304
|
+
what each authority really issues. `Match#strict?` separates
|
|
305
|
+
authority-alphabet hits from recall-only catch-alls (export plates etc.).
|
|
306
|
+
- `Vehicles.plates` / `Vehicles.plates(:nl)` — the full series data:
|
|
307
|
+
73 series across NL/ES/DE/US-FL (gate L0, NL corpus-proven), each with
|
|
308
|
+
pattern, period, class, categories, sourced design facts and citations.
|
|
309
|
+
- Bundled data under `data/plates/` (CC-BY, pinned upstream commit in
|
|
310
|
+
`data/plates/PROVENANCE.md`).
|
|
311
|
+
|
|
312
|
+
The hosted images API is **live** — this release points the wired-up provider
|
|
313
|
+
seam at the real thing.
|
|
314
|
+
|
|
315
|
+
### Added
|
|
316
|
+
- `Model#image(color:, size:)` returns a rendered variant URL from the live
|
|
317
|
+
VehiclesDB images API (`:sm` 320×180, `:md` 640×360, `:lg` 1280×720, webp).
|
|
318
|
+
Mint a key at <https://vehiclesdb.com/settings/api-keys> and set
|
|
319
|
+
`config.api_key`; without a key it stays nil, as always.
|
|
320
|
+
- `Model#images(color:)` returns the full payload: every variant with
|
|
321
|
+
dimensions, the rendered palette for the model, served-vs-requested color
|
|
322
|
+
(un-rendered colors fall back honestly instead of 404ing), provenance.
|
|
323
|
+
|
|
324
|
+
### Changed
|
|
325
|
+
- `config.api_base_url` default is now `https://vehiclesdb.com` (the live API
|
|
326
|
+
origin; endpoint paths carry `/v1`). It must be an ORIGIN — no path suffix.
|
|
327
|
+
- `Model#image` accepts `year:` but does not send it: `year`/`trim` are
|
|
328
|
+
reserved filters server-side (the API 422s on them by contract) until
|
|
329
|
+
year-accurate renders ship.
|
|
330
|
+
|
|
10
331
|
## [0.4.1] - 2026-07-26
|
|
11
332
|
|
|
12
333
|
Data-only refresh to VehiclesDB dataset **2026.07.4** — the July correction
|