vin-validator 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +3 -0
- data/README.adoc +91 -0
- data/lib/vin-validator.rb +3 -0
- data/lib/vin_validator/api.rb +123 -0
- data/lib/vin_validator/knowledge.rb +185 -0
- data/lib/vin_validator/maker.rb +32 -0
- data/lib/vin_validator/result.rb +19 -0
- data/lib/vin_validator/version.rb +1 -1
- data/lib/vin_validator/wmi.rb +42 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 193d68f8bb903729653960bb77273c2f0dab49f57edf19e48770fdf78b977a04
|
4
|
+
data.tar.gz: 575d2afa32ab7a72c90b7e01a1096edea9a0a3047336b0b586fc007263f5cf6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f03ba1c8d5bd92694bc0f7e8ad6b015ea779e2d81f1b7176bb3926536bf79fe36d13942de8c7d702da214aaea01ebd3a59905d8c48fb72a9ca2f36c6ca0a0b3e
|
7
|
+
data.tar.gz: 8a91f767a64965beba8e112fde759edc90141e2b496ec80602943050495e2b713aff6274dd0f5bc790440e65217767e7f073066f5f3d5bd0b566b40805af3113
|
data/CHANGELOG.adoc
ADDED
data/README.adoc
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
= Vin-Validator
|
2
|
+
|
3
|
+
Gem for gathering info on VINs, optionally using link:https://vpic.nhtsa.dot.gov/api/[NHTSA's API]
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
[source,ruby]
|
10
|
+
----
|
11
|
+
gem 'vin-validator', require: false
|
12
|
+
----
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle install
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install vin-validator
|
21
|
+
|
22
|
+
== Usage
|
23
|
+
|
24
|
+
[source,ruby]
|
25
|
+
----
|
26
|
+
just_a_vin = 'AA5325L1588827'
|
27
|
+
other_vins = %w[13N153201K1533942 1E9AA5325L1588827 1RND48A27GR039983 1RND53A33KR049282]
|
28
|
+
|
29
|
+
VinValidator::Knowledge.vin_info(just_a_vin).fetch(just_a_vin)
|
30
|
+
|
31
|
+
VinValidator::Knowledge.vin_info(just_a_vin, true).fetch(just_a_vin)
|
32
|
+
|
33
|
+
VinValidator::Knowledge.vin_info(other_vins)
|
34
|
+
|
35
|
+
VinValidator::Knowledge.vin_info(other_vins, true)
|
36
|
+
----
|
37
|
+
|
38
|
+
Every call to ``VinValidator::Knowledge::vin_info`` will return a hash.
|
39
|
+
Each key in the result is one of the VINs provided, and each value is another hash.
|
40
|
+
|
41
|
+
Value hash:
|
42
|
+
|
43
|
+
|===
|
44
|
+
|Key |Value
|
45
|
+
|
46
|
+
|``:errors``
|
47
|
+
|``Array<VinValidator::Result>``
|
48
|
+
|
49
|
+
|``:nhtsa_errors``
|
50
|
+
|``Array<VinValidator::Result>``
|
51
|
+
|
52
|
+
|``:vin``
|
53
|
+
|``VinValidator::Result``
|
54
|
+
|
55
|
+
|``:make``
|
56
|
+
|``Array<VinValidator::Result>``
|
57
|
+
|
58
|
+
|``:manufacturer``
|
59
|
+
|``VinValidator::Result``
|
60
|
+
|
61
|
+
|``:model``
|
62
|
+
|``VinValidator::Result``
|
63
|
+
|
64
|
+
|``:year``
|
65
|
+
|``VinValidator::Result``
|
66
|
+
|
67
|
+
|``:body_type``
|
68
|
+
|``VinValidator::Result``
|
69
|
+
|
70
|
+
|``:trailer_type``
|
71
|
+
|``VinValidator::Result``
|
72
|
+
|
73
|
+
|``:vehicle_type``
|
74
|
+
|``VinValidator::Result``
|
75
|
+
|
76
|
+
|``:gvw``
|
77
|
+
|``VinValidator::Result``
|
78
|
+
|
79
|
+
|``:suggested_vin``
|
80
|
+
|``VinValidator::Result``
|
81
|
+
|===
|
82
|
+
|
83
|
+
``VinValidator::Result`` has 3 attributes: ``vin``, ``type``, and ``value``.
|
84
|
+
|
85
|
+
* ``vin`` - The vin the result belongs to
|
86
|
+
* ``type`` - The type of result (``error``, ``make``, ``year``, etc)
|
87
|
+
* ``value`` - The value of the result
|
88
|
+
|
89
|
+
== Changelog
|
90
|
+
|
91
|
+
See xref:./CHANGELOG.adoc[CHANGELOG] see changes
|
data/lib/vin-validator.rb
CHANGED
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VinValidator
|
4
|
+
class Api
|
5
|
+
class << self
|
6
|
+
# Fetches info about vins. GET request if single VIN is passed in.
|
7
|
+
# More details can be found at +https://vpic.nhtsa.dot.gov/api/Home+
|
8
|
+
#
|
9
|
+
# @param vins [Array<String>, String] vins to check
|
10
|
+
#
|
11
|
+
# @return [Hash]
|
12
|
+
#
|
13
|
+
def vin_info(vins)
|
14
|
+
check_nhtsa = block_given? ? yield : true
|
15
|
+
return {} unless check_nhtsa
|
16
|
+
|
17
|
+
vins_to_check = [vins].flatten.compact.uniq
|
18
|
+
|
19
|
+
api_results =
|
20
|
+
if vins_to_check.size == 1
|
21
|
+
# 1E9AA5325L1588827
|
22
|
+
[single_vin_info(vins_to_check.first)]
|
23
|
+
else
|
24
|
+
# 13N153201K1533942
|
25
|
+
# 1E9AA5325L1588827
|
26
|
+
# 1RND48A27GR039983
|
27
|
+
# 1RND53A33KR049282
|
28
|
+
multiple_vin_infos(vins_to_check)
|
29
|
+
end
|
30
|
+
|
31
|
+
results = {}
|
32
|
+
api_results.each do |result|
|
33
|
+
result[:Results].each do |details|
|
34
|
+
results[details[:VIN]] = details
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# '1R1F24822YK501231' => {
|
39
|
+
# ...
|
40
|
+
# "TrailerBodyType": "",
|
41
|
+
# ...
|
42
|
+
# "VIN": "1R1F24822YK501231",
|
43
|
+
# ...
|
44
|
+
# }
|
45
|
+
|
46
|
+
return results
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# @param vin [String]
|
52
|
+
#
|
53
|
+
# @return [Hash] info about given vin
|
54
|
+
#
|
55
|
+
def single_vin_info(vin)
|
56
|
+
parse_request(build_get_request(vin))
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param vins [Array<String>]
|
60
|
+
#
|
61
|
+
# @return [Array<Hash>] info about given vins
|
62
|
+
#
|
63
|
+
def multiple_vin_infos(vins)
|
64
|
+
vins.each_slice(50).map do |vin_list|
|
65
|
+
parse_request(build_post_request(vin_list))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Stirng]
|
70
|
+
#
|
71
|
+
def root_api_url
|
72
|
+
'https://vpic.nhtsa.dot.gov/api/vehicles'
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param vin [String]
|
76
|
+
#
|
77
|
+
# @return [Hash]
|
78
|
+
#
|
79
|
+
def build_get_request(vin)
|
80
|
+
url = "#{root_api_url}/DecodeVinValues/#{vin}?format=json"
|
81
|
+
uri = URI(url)
|
82
|
+
|
83
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
84
|
+
http.use_ssl = true
|
85
|
+
# Use 5 instead of 60 (default) seconds for NHTSA
|
86
|
+
http.read_timeout = 5
|
87
|
+
|
88
|
+
request = Net::HTTP::Get.new(uri)
|
89
|
+
|
90
|
+
return { http: http, request: request }
|
91
|
+
end
|
92
|
+
|
93
|
+
# @param vins [Array<String>]
|
94
|
+
#
|
95
|
+
# @return [Hash]
|
96
|
+
#
|
97
|
+
def build_post_request(vins)
|
98
|
+
url = "#{root_api_url}/DecodeVINValuesBatch"
|
99
|
+
uri = URI(url)
|
100
|
+
|
101
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
102
|
+
http.use_ssl = true
|
103
|
+
# Use 5 instead of 60 (default) seconds for NHTSA
|
104
|
+
http.read_timeout = 5
|
105
|
+
|
106
|
+
request = Net::HTTP::Post.new(uri)
|
107
|
+
request.set_form_data({ data: vins.join(';'), format: 'JSON' })
|
108
|
+
|
109
|
+
return { http: http, request: request }
|
110
|
+
end
|
111
|
+
|
112
|
+
# Sends and parses the request
|
113
|
+
#
|
114
|
+
# @return [Hash<Symbol>]
|
115
|
+
#
|
116
|
+
def parse_request(http_request)
|
117
|
+
response = http_request.fetch(:http).request(http_request.fetch(:request))
|
118
|
+
|
119
|
+
return JSON.parse(response.body, { symbolize_names: true })
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './result'
|
4
|
+
require_relative './maker'
|
5
|
+
require_relative './wmi'
|
6
|
+
require_relative './api'
|
7
|
+
|
8
|
+
module VinValidator
|
9
|
+
class Knowledge
|
10
|
+
class << self
|
11
|
+
# Gathers/builds info for each vin provided
|
12
|
+
#
|
13
|
+
# @param vins [String, Array<String>]
|
14
|
+
# @param hit_nhtsa [Boolean] if `true`, query NHTSA. default: `false`
|
15
|
+
#
|
16
|
+
# @return [Hash]
|
17
|
+
#
|
18
|
+
def vin_info(vins, hit_nhtsa = false, &block)
|
19
|
+
results = hit_nhtsa ? VinValidator::Api.vin_info(vins, &block) : {}
|
20
|
+
|
21
|
+
Array(vins).to_h do |vin|
|
22
|
+
vin_results = results.fetch(vin, {})
|
23
|
+
[vin, build_results(vin, vin_results)]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Does the basic checksum and valid character checking
|
30
|
+
#
|
31
|
+
# @param vin [String, Array<String>] the vin characters to check
|
32
|
+
#
|
33
|
+
# @return [Array<String>] the errors
|
34
|
+
#
|
35
|
+
def simple_vin_check(vin)
|
36
|
+
return ['Vin is not equal to 17 characters.'] if vin.length != 17
|
37
|
+
|
38
|
+
vin =
|
39
|
+
if vin.is_a?(Array)
|
40
|
+
vin.map(&:upcase)
|
41
|
+
else
|
42
|
+
vin.upcase.split('')
|
43
|
+
end
|
44
|
+
|
45
|
+
vin_errors = []
|
46
|
+
|
47
|
+
if vin.join('') !~ /^[a-z0-9]{17}$/i
|
48
|
+
vin_errors << 'Only numbers and letters are allowed in VINs'
|
49
|
+
end
|
50
|
+
|
51
|
+
# rubocop:disable Style/EachForSimpleLoop
|
52
|
+
(0..7).each do |slot|
|
53
|
+
# rubocop:enable Style/EachForSimpleLoop
|
54
|
+
# For 1-8, can't have 'I', 'O', or 'Q'
|
55
|
+
if /[ioq]/i =~ vin[slot].to_s
|
56
|
+
vin_errors << "'I', 'O', and 'Q' are not allowed in slot #{slot + 1}."
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
unless /[0-9x]/i =~ vin[8].to_s # For 9, only 0-9 and 'X' are allowed
|
61
|
+
vin_errors << "Only 0-9 and 'X' are allowed in slot 9."
|
62
|
+
end
|
63
|
+
|
64
|
+
if /[iquz0]/i =~ vin[9].to_s # For 10, can't have 'I', 'O', 'Q', 'U', 'Z', '0'
|
65
|
+
vin_errors << "'I', 'O', 'Q', 'U', 'Z', and 0 are not allowed in slot 10."
|
66
|
+
end
|
67
|
+
|
68
|
+
(10..13).each do |slot|
|
69
|
+
# For 11-14, can't have 'I', 'O', 'Q'
|
70
|
+
if /[ioq]/i =~ vin[slot].to_s
|
71
|
+
vin_errors << "'I', 'O', or 'Q' not allowed in slot #{slot + 1}."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# For 15-17, only 0-9
|
76
|
+
(14..16).each do |slot|
|
77
|
+
unless /[0-9]/i =~ vin[slot].to_s
|
78
|
+
vin_errors << "Only 0-9 allowed in slot #{slot + 1}."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
vin_errors << 'Check digit is incorrect.' unless get_check_digit(vin) == vin[8]
|
83
|
+
vin_errors
|
84
|
+
end
|
85
|
+
|
86
|
+
# Calculates the character's value. From wikipedia
|
87
|
+
#
|
88
|
+
# @return [Number, Nil]
|
89
|
+
#
|
90
|
+
def transliterate(c)
|
91
|
+
'0123456789.ABCDEFGH..JKLMN.P.R..STUVWXYZ'.index(c) % 10
|
92
|
+
rescue
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
|
96
|
+
# Calculates the expected check digit for the given vin
|
97
|
+
#
|
98
|
+
# @param vin [String]
|
99
|
+
#
|
100
|
+
# @return [String]
|
101
|
+
#
|
102
|
+
def get_check_digit(vin)
|
103
|
+
map = '0123456789X'
|
104
|
+
weights = '8765432X098765432'
|
105
|
+
sum = 0
|
106
|
+
(0..16).each do |i|
|
107
|
+
value_weight = transliterate(vin[i])
|
108
|
+
return nil if value_weight.nil?
|
109
|
+
|
110
|
+
sum += value_weight * map.index(weights[i])
|
111
|
+
end
|
112
|
+
return map[sum % 11]
|
113
|
+
end
|
114
|
+
|
115
|
+
# Combines T2 and NHTSA's results. Will attempt to create `VinValidator::Result`s
|
116
|
+
#
|
117
|
+
# @return [Hash]
|
118
|
+
#
|
119
|
+
def build_results(vin, vin_nhtsa_results)
|
120
|
+
vin_results =
|
121
|
+
begin
|
122
|
+
parse_nhtsa_results(vin, vin_nhtsa_results)
|
123
|
+
rescue
|
124
|
+
{ errors: [] }
|
125
|
+
end
|
126
|
+
|
127
|
+
simple_errors = simple_vin_check(vin)
|
128
|
+
vin_results[:errors] += simple_errors.map do |err|
|
129
|
+
VinValidator::Result.new(vin: vin, type: :error, value: err)
|
130
|
+
end
|
131
|
+
|
132
|
+
reset_vin = !vin_results.has_key?(:vin) || vin_results.dig(:vin).nil?
|
133
|
+
reset_vin ||= vin_results.dig(:vin).value.nil?
|
134
|
+
reset_vin ||= vin_results.dig(:vin).value.empty?
|
135
|
+
|
136
|
+
if reset_vin
|
137
|
+
vin_results[:vin] = VinValidator::Result.new(vin: vin, type: :vin, value: vin)
|
138
|
+
end
|
139
|
+
|
140
|
+
reset_make = !vin_results.has_key?(:make)
|
141
|
+
reset_make ||= vin_results.dig(:make, 0).nil?
|
142
|
+
reset_make ||= vin_results.dig(:make, 0).value.nil?
|
143
|
+
reset_make ||= vin_results.dig(:make, 0).value.empty?
|
144
|
+
|
145
|
+
if reset_make
|
146
|
+
vin_results[:make] =
|
147
|
+
VinValidator::Wmi.where(wmi: vin.strip.split('')[0..2].join).map do |wmi|
|
148
|
+
VinValidator::Result.new(vin: vin, type: :make, value: wmi.maker.name)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
return vin_results
|
153
|
+
end
|
154
|
+
|
155
|
+
# @param vin [String] vin to validate
|
156
|
+
# @param results [Hash] NHTSA results
|
157
|
+
#
|
158
|
+
# @return [Hash] errors and addtl info
|
159
|
+
#
|
160
|
+
def parse_nhtsa_results(vin, results)
|
161
|
+
return { errors: [] } if results.empty?
|
162
|
+
|
163
|
+
errors = []
|
164
|
+
errors += results[:ErrorText].split('; ') unless results[:ErrorCode] == '0'
|
165
|
+
errors += Array(results[:AdditionalErrorText])
|
166
|
+
|
167
|
+
return {
|
168
|
+
errors: [],
|
169
|
+
# `nhtsa_errors` because they find too many errors that shouldn't trigger
|
170
|
+
nhtsa_errors: errors.map { |err| VinValidator::Result.new(vin: vin, value: err, type: :error) },
|
171
|
+
vin: VinValidator::Result.new(vin: vin, value: results[:VIN], type: :vin),
|
172
|
+
make: Array(VinValidator::Result.new(vin: vin, value: results[:Make], type: :make)),
|
173
|
+
manufacturer: VinValidator::Result.new(vin: vin, value: results[:Manufacturer], type: :manufacturer),
|
174
|
+
model: VinValidator::Result.new(vin: vin, value: results[:Model], type: :model),
|
175
|
+
year: VinValidator::Result.new(vin: vin, value: results[:ModelYear], type: :year),
|
176
|
+
body_type: VinValidator::Result.new(vin: vin, value: results[:TrailerBodyType], type: :body_type),
|
177
|
+
trailer_type: VinValidator::Result.new(vin: vin, value: results[:TrailerType], type: :trailer_type),
|
178
|
+
vehicle_type: VinValidator::Result.new(vin: vin, value: results[:VehicleType], type: :vehicle_type),
|
179
|
+
gvw: VinValidator::Result.new(vin: vin, value: results[:GVWR], type: :gvw),
|
180
|
+
suggested_vin: VinValidator::Result.new(vin: vin, value: results[:SuggestedVIN], type: :suggested_vin)
|
181
|
+
}
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VinValidator
|
4
|
+
class Maker
|
5
|
+
class << self
|
6
|
+
def all
|
7
|
+
return @all if defined?(@all)
|
8
|
+
|
9
|
+
@all = JSON.parse(File.read('makers.json'), { symbolize_names: true }).to_h { |id, v| [id.to_s, new(**v)] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(id)
|
13
|
+
all.fetch(id.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def where(wmi:)
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Integer]
|
22
|
+
attr_accessor :id
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :name
|
25
|
+
|
26
|
+
# :nodoc:
|
27
|
+
def initialize(id:, name:)
|
28
|
+
@id = id
|
29
|
+
@name = name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VinValidator
|
4
|
+
class Result
|
5
|
+
# @return [String]
|
6
|
+
attr_accessor :vin
|
7
|
+
# @return [String]
|
8
|
+
attr_accessor :type
|
9
|
+
# @return [String]
|
10
|
+
attr_accessor :value
|
11
|
+
|
12
|
+
# :nodoc:
|
13
|
+
def initialize(vin:, type:, value:)
|
14
|
+
@vin = vin
|
15
|
+
@type = type
|
16
|
+
@value = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VinValidator
|
4
|
+
class Wmi
|
5
|
+
class << self
|
6
|
+
def all
|
7
|
+
return @all if defined?(@all)
|
8
|
+
|
9
|
+
@all = JSON.parse(File.read('wmis.json'), { symbolize_names: true }).to_h { |id, v| [id.to_s, new(**v)] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(id)
|
13
|
+
all.fetch(id.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def where(wmi:)
|
17
|
+
all.values.select { |w| w.wmi == wmi }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Integer]
|
22
|
+
attr_accessor :id
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :wmi
|
25
|
+
# @return [String, Nil]
|
26
|
+
attr_accessor :wmi_suffix
|
27
|
+
# @return [Integer]
|
28
|
+
attr_accessor :maker_id
|
29
|
+
|
30
|
+
# :nodoc:
|
31
|
+
def initialize(id:, wmi:, maker_id:, wmi_suffix: nil)
|
32
|
+
@id = id
|
33
|
+
@maker_id = maker_id
|
34
|
+
@wmi = wmi
|
35
|
+
@wmi_suffix = wmi_suffix
|
36
|
+
end
|
37
|
+
|
38
|
+
def maker
|
39
|
+
@maker ||= VinValidator::Maker.find(maker_id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vin-validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brands Insurance
|
@@ -31,9 +31,16 @@ executables: []
|
|
31
31
|
extensions: []
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
|
+
- CHANGELOG.adoc
|
34
35
|
- LICENSE
|
36
|
+
- README.adoc
|
35
37
|
- lib/vin-validator.rb
|
38
|
+
- lib/vin_validator/api.rb
|
39
|
+
- lib/vin_validator/knowledge.rb
|
40
|
+
- lib/vin_validator/maker.rb
|
41
|
+
- lib/vin_validator/result.rb
|
36
42
|
- lib/vin_validator/version.rb
|
43
|
+
- lib/vin_validator/wmi.rb
|
37
44
|
homepage: https://github.com/BrandsInsurance/vin-validator/
|
38
45
|
licenses:
|
39
46
|
- MIT
|
@@ -57,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
64
|
- !ruby/object:Gem::Version
|
58
65
|
version: '0'
|
59
66
|
requirements: []
|
60
|
-
rubygems_version: 3.
|
67
|
+
rubygems_version: 3.4.10
|
61
68
|
signing_key:
|
62
69
|
specification_version: 4
|
63
70
|
summary: Shared vin validator API for BrandsInsurance
|