ziptz 6.1.0 → 6.2.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/CHANGELOG.md +78 -0
- data/LICENSE +1 -1
- data/README.md +19 -2
- data/lib/{version.rb → ziptz/version.rb} +1 -1
- data/lib/ziptz.rb +15 -8
- data/ziptz.gemspec +9 -6
- metadata +8 -7
- data/spec/fixtures/tz.db +0 -0
- data/spec/spec_helper.rb +0 -10
- data/spec/ziptz_spec.rb +0 -133
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8e148a6e535c92aee764520b3741c8c550719d2c430df9c18f84252e233eb17a
|
|
4
|
+
data.tar.gz: 1d56d7416206c48354f30f0b544639d99e86ed68908a9214ee654cdee7cbf70a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 69974ccd6732bb9043f9c4c7ab5f77ec9d5cc4991b07170b7ea92630f9910a24df9eb7fdc941930f092c188d480b967dfc3e83a99eb1462fd6c1f2e2a4298fe8
|
|
7
|
+
data.tar.gz: 1665d43f017697702ed8d3c4d8468d06e33bd46bc6f3e172fb39a4f342f05bd95b9eb7b3a4da93cdfe581a38ba5e610ee71b11f23473302838eee56361fd503d
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## 6.2.0 - 2026-08-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Automated gem publication via
|
|
13
|
+
[RubyGems trusted publishing](https://guides.rubygems.org/trusted-publishing/):
|
|
14
|
+
pushing a `v*` tag builds and publishes the gem from GitHub Actions.
|
|
15
|
+
- Gemspec metadata links (`source_code_uri`, `changelog_uri`,
|
|
16
|
+
`bug_tracker_uri`) and this changelog.
|
|
17
|
+
- Zip codes may now be passed as Integers; they are zero-padded to 5 digits
|
|
18
|
+
(`z.time_zone_name(601)` looks up `00601`). Previously an Integer raised
|
|
19
|
+
`NoMethodError`.
|
|
20
|
+
- `Ziptz#close` closes the cached SQLite connection for the instance's
|
|
21
|
+
database on the current thread. Closing is idempotent and a new connection
|
|
22
|
+
is opened automatically on the next query.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Database connections are cached per database path, so multiple `Ziptz`
|
|
27
|
+
instances pointing at different databases no longer share a connection.
|
|
28
|
+
- The packaged gem no longer includes the spec suite and its 2.7 MB fixture
|
|
29
|
+
database, shrinking the gem from ~2.7 MB to a few KB.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- CI now enforces RuboCop and runs tests against Ruby 3.3, 3.4, and 4.0.
|
|
34
|
+
- `Ziptz::VERSION` moved from `lib/version.rb` to the conventional
|
|
35
|
+
`lib/ziptz/version.rb`.
|
|
36
|
+
- README documents the supported Rubies (3.3/3.4/4.0); copyright years
|
|
37
|
+
updated through 2026.
|
|
38
|
+
|
|
39
|
+
### Removed
|
|
40
|
+
|
|
41
|
+
- Leftover development dependencies from the long-removed data-import
|
|
42
|
+
pipeline (activerecord, mysql2, tty-spinner).
|
|
43
|
+
|
|
44
|
+
## 6.1.0 - 2026-04-09
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- Unknown, invalid, and nil zip codes now raise `Ziptz::ZipNotFound` instead
|
|
49
|
+
of returning nil.
|
|
50
|
+
|
|
51
|
+
### Removed
|
|
52
|
+
|
|
53
|
+
- Dropped support for Ruby 3.1 and 3.2; Ruby >= 3.3 is now required.
|
|
54
|
+
|
|
55
|
+
## 6.0.0 - 2024-12-27
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- **Breaking:** the gem no longer bundles zip code time zone data. Supply
|
|
60
|
+
your own SQLite database and pass its path to `Ziptz.new`. See the
|
|
61
|
+
[ZIP Code Time Zones Dataset](https://www.infused-data.com/zip-code-time-zones/).
|
|
62
|
+
- Database connections are cached per thread for thread safety.
|
|
63
|
+
|
|
64
|
+
### Removed
|
|
65
|
+
|
|
66
|
+
- The `Ziptz.instance` class method.
|
|
67
|
+
|
|
68
|
+
## 5.1.0 - 2024-04-28
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- sqlite3 dependency updated from `~> 1.6` to `~> 2.0` (#11).
|
|
73
|
+
|
|
74
|
+
## 5.0.0 - 2023-12-28
|
|
75
|
+
|
|
76
|
+
### Removed
|
|
77
|
+
|
|
78
|
+
- Dropped support for Rubies older than 3.1.
|
data/LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Get time zone, daylight saving time, and base offset for any US ZIP code.
|
|
|
12
12
|
|
|
13
13
|
Ziptz is tested to work with the following versions of Ruby:
|
|
14
14
|
|
|
15
|
-
* Ruby 3.
|
|
15
|
+
* Ruby 3.3.x, 3.4.x, 4.0.x
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
@@ -37,6 +37,12 @@ Get the time zone name for any ZIP code:
|
|
|
37
37
|
|
|
38
38
|
z.time_zone_name('97213') #=> "America/Los_Angeles"
|
|
39
39
|
|
|
40
|
+
ZIP codes may be passed as strings or integers. Integers are zero-padded
|
|
41
|
+
to 5 digits, and 9-digit ZIP+4 strings are truncated to their first 5 digits:
|
|
42
|
+
|
|
43
|
+
z.time_zone_name(601) #=> "America/Puerto_Rico" (looks up 00601)
|
|
44
|
+
z.time_zone_name('97213-4704') #=> "America/Los_Angeles"
|
|
45
|
+
|
|
40
46
|
Get the time zone offset for any ZIP code:
|
|
41
47
|
|
|
42
48
|
z.time_zone_offset('97213') #=> -28800
|
|
@@ -51,6 +57,17 @@ Get all the zip codes in a time zone:
|
|
|
51
57
|
|
|
52
58
|
z.zips('Pacific/Chuuk') #=> ["96942", "96943"]
|
|
53
59
|
|
|
60
|
+
Lookups for unknown, invalid, or nil ZIP codes raise `Ziptz::ZipNotFound`
|
|
61
|
+
(since version 6.1.0; earlier versions returned nil):
|
|
62
|
+
|
|
63
|
+
z.time_zone_name('00000') #=> raises Ziptz::ZipNotFound
|
|
64
|
+
|
|
65
|
+
Database connections are opened lazily and cached per thread. Call `close`
|
|
66
|
+
to close the current thread's connection; the next lookup reopens it
|
|
67
|
+
automatically:
|
|
68
|
+
|
|
69
|
+
z.close
|
|
70
|
+
|
|
54
71
|
|
|
55
72
|
## Supported Time Zones
|
|
56
73
|
|
|
@@ -169,7 +186,7 @@ Time zone names now reflect standard tz-database names.
|
|
|
169
186
|
|
|
170
187
|
## License
|
|
171
188
|
|
|
172
|
-
Copyright (c) 2015-
|
|
189
|
+
Copyright (c) 2015-2026 Keith Morrison <<keithm@infused.org>>
|
|
173
190
|
|
|
174
191
|
Permission is hereby granted, free of charge, to any person
|
|
175
192
|
obtaining a copy of this software and associated documentation
|
data/lib/ziptz.rb
CHANGED
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'sqlite3'
|
|
4
|
-
|
|
4
|
+
require_relative 'ziptz/version'
|
|
5
5
|
|
|
6
6
|
class Ziptz
|
|
7
7
|
class ZipNotFound < StandardError; end
|
|
8
8
|
|
|
9
|
-
def initialize(
|
|
10
|
-
@db_path =
|
|
9
|
+
def initialize(path = nil, db: nil)
|
|
10
|
+
@db_path = path || db
|
|
11
11
|
raise ArgumentError, 'Database path is required' if @db_path.nil? || @db_path.empty?
|
|
12
12
|
raise ArgumentError, 'Database file does not exist' unless File.exist?(@db_path)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def db
|
|
16
|
-
Thread.current[:ziptz_db] ||=
|
|
16
|
+
connections = Thread.current[:ziptz_db] ||= {}
|
|
17
|
+
connections[@db_path] ||= begin
|
|
17
18
|
db = SQLite3::Database.open(@db_path)
|
|
18
19
|
db.results_as_hash = true
|
|
19
20
|
db
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
|
|
24
|
+
def close
|
|
25
|
+
Thread.current[:ziptz_db]&.delete(@db_path)&.close
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
def time_zone_name(zip)
|
|
24
|
-
time_zone_info(zip)
|
|
30
|
+
time_zone_info(zip)['time_zone']
|
|
25
31
|
end
|
|
26
32
|
|
|
27
33
|
def time_zone_offset(zip)
|
|
28
|
-
time_zone_info(zip)
|
|
34
|
+
time_zone_info(zip)['offset']
|
|
29
35
|
end
|
|
30
36
|
|
|
31
37
|
def time_zone_uses_dst?(zip)
|
|
@@ -46,12 +52,13 @@ class Ziptz
|
|
|
46
52
|
"#<#{self.class}:#{object_id}>"
|
|
47
53
|
end
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
private
|
|
50
56
|
|
|
51
57
|
def time_zone_info(zip)
|
|
52
58
|
raise ZipNotFound, "Zip code not found: #{zip.inspect}" if zip.nil?
|
|
53
59
|
|
|
54
|
-
|
|
60
|
+
zip_code = zip.is_a?(Integer) ? format('%05d', zip) : zip.to_s[0, 5]
|
|
61
|
+
result = db.get_first_row('select * from zip_codes where zip_code = ? limit 1', zip_code)
|
|
55
62
|
raise ZipNotFound, "Zip code not found: #{zip}" unless result
|
|
56
63
|
|
|
57
64
|
result
|
data/ziptz.gemspec
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
|
5
|
-
require 'version'
|
|
3
|
+
require_relative 'lib/ziptz/version'
|
|
6
4
|
|
|
7
5
|
Gem::Specification.new do |s|
|
|
8
6
|
s.name = 'ziptz'
|
|
@@ -10,16 +8,21 @@ Gem::Specification.new do |s|
|
|
|
10
8
|
s.platform = Gem::Platform::RUBY
|
|
11
9
|
s.authors = ['Keith Morrison']
|
|
12
10
|
s.email = 'keithm@infused.org'
|
|
13
|
-
s.homepage = '
|
|
11
|
+
s.homepage = 'https://github.com/infused/ziptz'
|
|
14
12
|
s.summary = 'TimeZone info for any 5-digit US zip code'
|
|
15
13
|
s.description = 'Get timezone info for all 5-digit US zip codes'
|
|
16
14
|
s.license = 'MIT'
|
|
17
15
|
|
|
18
16
|
s.rdoc_options = ['--charset=UTF-8']
|
|
19
17
|
s.extra_rdoc_files = ['README.md', 'LICENSE']
|
|
20
|
-
s.files = Dir['README.md', 'LICENSE', '
|
|
18
|
+
s.files = Dir['README.md', 'CHANGELOG.md', 'LICENSE', 'lib/**/*', 'ziptz.gemspec']
|
|
21
19
|
s.require_paths = ['lib']
|
|
22
20
|
s.required_ruby_version = '>= 3.3.0'
|
|
23
|
-
s.metadata
|
|
21
|
+
s.metadata = {
|
|
22
|
+
'source_code_uri' => 'https://github.com/infused/ziptz',
|
|
23
|
+
'changelog_uri' => 'https://github.com/infused/ziptz/blob/main/CHANGELOG.md',
|
|
24
|
+
'bug_tracker_uri' => 'https://github.com/infused/ziptz/issues',
|
|
25
|
+
'rubygems_mfa_required' => 'true'
|
|
26
|
+
}
|
|
24
27
|
s.add_dependency 'sqlite3', '~> 2.0'
|
|
25
28
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ziptz
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.
|
|
4
|
+
version: 6.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Keith Morrison
|
|
@@ -31,18 +31,19 @@ extra_rdoc_files:
|
|
|
31
31
|
- LICENSE
|
|
32
32
|
- README.md
|
|
33
33
|
files:
|
|
34
|
+
- CHANGELOG.md
|
|
34
35
|
- LICENSE
|
|
35
36
|
- README.md
|
|
36
|
-
- lib/version.rb
|
|
37
37
|
- lib/ziptz.rb
|
|
38
|
-
-
|
|
39
|
-
- spec/spec_helper.rb
|
|
40
|
-
- spec/ziptz_spec.rb
|
|
38
|
+
- lib/ziptz/version.rb
|
|
41
39
|
- ziptz.gemspec
|
|
42
|
-
homepage:
|
|
40
|
+
homepage: https://github.com/infused/ziptz
|
|
43
41
|
licenses:
|
|
44
42
|
- MIT
|
|
45
43
|
metadata:
|
|
44
|
+
source_code_uri: https://github.com/infused/ziptz
|
|
45
|
+
changelog_uri: https://github.com/infused/ziptz/blob/main/CHANGELOG.md
|
|
46
|
+
bug_tracker_uri: https://github.com/infused/ziptz/issues
|
|
46
47
|
rubygems_mfa_required: 'true'
|
|
47
48
|
rdoc_options:
|
|
48
49
|
- "--charset=UTF-8"
|
|
@@ -59,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
59
60
|
- !ruby/object:Gem::Version
|
|
60
61
|
version: '0'
|
|
61
62
|
requirements: []
|
|
62
|
-
rubygems_version: 4.0.
|
|
63
|
+
rubygems_version: 4.0.16
|
|
63
64
|
specification_version: 4
|
|
64
65
|
summary: TimeZone info for any 5-digit US zip code
|
|
65
66
|
test_files: []
|
data/spec/fixtures/tz.db
DELETED
|
Binary file
|
data/spec/spec_helper.rb
DELETED
data/spec/ziptz_spec.rb
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
RSpec.describe Ziptz do
|
|
6
|
-
let(:db_path) { File.join(File.dirname(__FILE__), 'fixtures', 'tz.db') }
|
|
7
|
-
let(:ziptz) { described_class.new(db_path) }
|
|
8
|
-
|
|
9
|
-
describe 'when inspected' do
|
|
10
|
-
it 'does not show internal instance variables' do
|
|
11
|
-
expect(ziptz.inspect).to match(/#<Ziptz:\d+>/)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
describe '#time_zone_name' do
|
|
16
|
-
context 'when given a 5-digit zipcode' do
|
|
17
|
-
it 'returns the time zone number' do
|
|
18
|
-
expect(ziptz.time_zone_name('97034')).to eq 'America/Los_Angeles'
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
context 'when given a 9-digit zipcode' do
|
|
23
|
-
it 'returns the time zone number' do
|
|
24
|
-
expect(ziptz.time_zone_name('97034-1234')).to eq 'America/Los_Angeles'
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
context 'when there is no matching zipcode' do
|
|
29
|
-
it 'raises ZipNotFound' do
|
|
30
|
-
expect { ziptz.time_zone_name('xyz') }.to raise_error(Ziptz::ZipNotFound)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
context 'when nil is passed' do
|
|
35
|
-
it 'raises ZipNotFound' do
|
|
36
|
-
expect { ziptz.time_zone_name(nil) }.to raise_error(Ziptz::ZipNotFound)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
describe '#time_zone_uses_dst?' do
|
|
42
|
-
context 'when given a valid 5-digit zipcode' do
|
|
43
|
-
it 'returns true' do
|
|
44
|
-
expect(ziptz.time_zone_uses_dst?('97034')).to be true
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
context 'when given an invalid 5-digit zipcode' do
|
|
49
|
-
it 'returns false' do
|
|
50
|
-
expect(ziptz.time_zone_uses_dst?('85004')).to be false
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
context 'when given a valid 9-digit zipcode' do
|
|
55
|
-
it 'returns a true' do
|
|
56
|
-
expect(ziptz.time_zone_uses_dst?('97034-1234')).to be true
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
context 'when given an invalid 9-digit zipcode' do
|
|
61
|
-
it 'returns false' do
|
|
62
|
-
expect(ziptz.time_zone_uses_dst?('85004-1234')).to be false
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
context 'when there is no matching zipcode' do
|
|
67
|
-
it 'raises ZipNotFound' do
|
|
68
|
-
expect { ziptz.time_zone_uses_dst?('xyz') }.to raise_error(Ziptz::ZipNotFound)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
describe '#time_zone_offset' do
|
|
74
|
-
context 'when given a 5-digit zipcode' do
|
|
75
|
-
it 'returns the time zone number' do
|
|
76
|
-
expect(ziptz.time_zone_offset('97034')).to eq(-28_800)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
context 'when given a 9-digit zipcode' do
|
|
81
|
-
it 'returns the time zone number' do
|
|
82
|
-
expect(ziptz.time_zone_offset('97034-1234')).to eq(-28_800)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
context 'when there is no matching zipcode' do
|
|
87
|
-
it 'raises ZipNotFound' do
|
|
88
|
-
expect { ziptz.time_zone_offset('xyz') }.to raise_error(Ziptz::ZipNotFound)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
describe '#zips' do
|
|
94
|
-
context 'when given a time zone' do
|
|
95
|
-
it 'returns an array of zip codes' do
|
|
96
|
-
expect(ziptz.zips('Pacific/Pago_Pago')).to eq %w[96799]
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
it 'is case-insensitive' do
|
|
100
|
-
expect(ziptz.zips('pacific/pago_pago')).to eq %w[96799]
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
it 'returns empty array for unknown time zones' do
|
|
104
|
-
expect(ziptz.zips('Glark')).to be_empty
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
describe 'initialization' do
|
|
110
|
-
it 'accepts database path as first argument' do
|
|
111
|
-
expect { described_class.new(db_path) }.to_not raise_error
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
it 'accepts database path as keyword argument' do
|
|
115
|
-
expect { described_class.new(db: db_path) }.to_not raise_error
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
it 'raises an error when database path is nil' do
|
|
119
|
-
expect { described_class.new }.to raise_error(ArgumentError, 'Database path is required')
|
|
120
|
-
expect { described_class.new(db: nil) }.to raise_error(ArgumentError, 'Database path is required')
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
it 'raises an error when database path is empty' do
|
|
124
|
-
expect { described_class.new('') }.to raise_error(ArgumentError, 'Database path is required')
|
|
125
|
-
expect { described_class.new(db: '') }.to raise_error(ArgumentError, 'Database path is required')
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
it 'raises an error when database file does not exist' do
|
|
129
|
-
expect { described_class.new('nonexistent.db') }.to raise_error(ArgumentError, 'Database file does not exist')
|
|
130
|
-
expect { described_class.new(db: 'nonexistent.db') }.to raise_error(ArgumentError, 'Database file does not exist')
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|