ziptz 5.1.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b310de1d20cfb9b20cba87249ee230e5baff3efbab063fd7c87b21e7c5e458af
4
- data.tar.gz: 7434225f05490776ced760c84f522b41b7ff2afc903a2cb4c1729c7b5a71d748
3
+ metadata.gz: 8e148a6e535c92aee764520b3741c8c550719d2c430df9c18f84252e233eb17a
4
+ data.tar.gz: 1d56d7416206c48354f30f0b544639d99e86ed68908a9214ee654cdee7cbf70a
5
5
  SHA512:
6
- metadata.gz: ded78e81fcfcad3917c824512de4c0e8eb902ef37f45fc7300610796100e4d367a338fabe1e4aa18b8237012208268bb3c55efc016021099b055ffddcd3ab34c
7
- data.tar.gz: 81050bfeefe7dc5aa8ad492cece4975c8382178037a445f97957005e11f9242f1d6291073650031687fa90fa79df87403587368946b23c33787200789a33a8fe
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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015-2024 Keith Morrison <keithm@infused.org>
1
+ Copyright (c) 2015-2026 Keith Morrison <keithm@infused.org>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ziptz
2
2
  [![Version](http://img.shields.io/gem/v/ziptz.svg?style=flat)](https://rubygems.org/gems/ziptz)
3
- [![Build Status](https://github.com/infused/ziptz/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/infused/ziptz/actions/workflows/build.yml)
3
+ [![Build Status](https://github.com/infused/ziptz/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/infused/ziptz/actions/workflows/build.yml)
4
4
  [![Total Downloads](https://img.shields.io/gem/dt/ziptz.svg)](https://rubygems.org/gems/ziptz/)
5
5
  [![License](https://img.shields.io/github/license/infused/ziptz.svg)](https://github.com/infused/ziptz)
6
6
 
@@ -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.1.x, 3.2.x, 3.3.x
15
+ * Ruby 3.3.x, 3.4.x, 4.0.x
16
16
 
17
17
  ## Installation
18
18
 
@@ -20,13 +20,29 @@ Add the gem to your Gemfile:
20
20
 
21
21
  gem 'ziptz'
22
22
 
23
+ ## Data File Requirement
24
+
25
+ Starting with version 6.0.0, you'll need to supply your own time zone SQLite database file. You can subscribe to the required dataset here:
26
+ [ZIP Code Time Zones Dataset](https://www.infused-data.com/zip-code-time-zones/)
27
+
23
28
  ## Usage
24
29
 
30
+ First, initialize Ziptz with the path to your time zone database file:
31
+
32
+ z = Ziptz.new('/path/to/your/tz.db')
33
+ # or using keyword argument
34
+ z = Ziptz.new(db: '/path/to/your/tz.db')
35
+
25
36
  Get the time zone name for any ZIP code:
26
37
 
27
- z = Ziptz.new
28
38
  z.time_zone_name('97213') #=> "America/Los_Angeles"
29
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
+
30
46
  Get the time zone offset for any ZIP code:
31
47
 
32
48
  z.time_zone_offset('97213') #=> -28800
@@ -41,6 +57,17 @@ Get all the zip codes in a time zone:
41
57
 
42
58
  z.zips('Pacific/Chuuk') #=> ["96942", "96943"]
43
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
+
44
71
 
45
72
  ## Supported Time Zones
46
73
 
@@ -159,7 +186,7 @@ Time zone names now reflect standard tz-database names.
159
186
 
160
187
  ## License
161
188
 
162
- Copyright (c) 2015-2024 Keith Morrison <<keithm@infused.org>>
189
+ Copyright (c) 2015-2026 Keith Morrison <<keithm@infused.org>>
163
190
 
164
191
  Permission is hereby granted, free of charge, to any person
165
192
  obtaining a copy of this software and associated documentation
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Ziptz
4
+ VERSION = '6.2.0'
5
+ end
data/lib/ziptz.rb CHANGED
@@ -1,36 +1,45 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sqlite3'
2
- require 'version'
4
+ require_relative 'ziptz/version'
3
5
 
4
6
  class Ziptz
5
- def self.instance
6
- @instance ||= new
7
+ class ZipNotFound < StandardError; end
8
+
9
+ def initialize(path = nil, db: nil)
10
+ @db_path = path || db
11
+ raise ArgumentError, 'Database path is required' if @db_path.nil? || @db_path.empty?
12
+ raise ArgumentError, 'Database file does not exist' unless File.exist?(@db_path)
7
13
  end
8
14
 
9
15
  def db
10
- @db ||= begin
11
- db = SQLite3::Database.open(tz_data_path)
16
+ connections = Thread.current[:ziptz_db] ||= {}
17
+ connections[@db_path] ||= begin
18
+ db = SQLite3::Database.open(@db_path)
12
19
  db.results_as_hash = true
13
20
  db
14
21
  end
15
22
  end
16
23
 
24
+ def close
25
+ Thread.current[:ziptz_db]&.delete(@db_path)&.close
26
+ nil
27
+ end
28
+
17
29
  def time_zone_name(zip)
18
- time_zone_info(zip)&.dig('time_zone')
30
+ time_zone_info(zip)['time_zone']
19
31
  end
20
32
 
21
33
  def time_zone_offset(zip)
22
- time_zone_info(zip)&.dig('offset')
34
+ time_zone_info(zip)['offset']
23
35
  end
24
36
 
25
37
  def time_zone_uses_dst?(zip)
26
- tz_info = time_zone_info(zip)
27
- return unless tz_info
28
-
29
- tz_info['observes_dst'] == 1
38
+ time_zone_info(zip)['observes_dst'] == 1
30
39
  end
31
40
 
32
41
  def zips(tz_name)
33
- sql = <<-SQL
42
+ sql = <<~SQL
34
43
  select zip_code
35
44
  from zip_codes
36
45
  where time_zone = ?
@@ -43,15 +52,15 @@ class Ziptz
43
52
  "#<#{self.class}:#{object_id}>"
44
53
  end
45
54
 
46
- protected
55
+ private
47
56
 
48
57
  def time_zone_info(zip)
49
- return unless zip
58
+ raise ZipNotFound, "Zip code not found: #{zip.inspect}" if zip.nil?
50
59
 
51
- db.get_first_row('select * from zip_codes where zip_code = ? limit 1', zip[0, 5])
52
- end
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)
62
+ raise ZipNotFound, "Zip code not found: #{zip}" unless result
53
63
 
54
- def tz_data_path
55
- File.join(File.dirname(__FILE__), '..', 'data', 'tz.db')
64
+ result
56
65
  end
57
66
  end
data/ziptz.gemspec CHANGED
@@ -1,6 +1,6 @@
1
- lib = File.expand_path('lib', __dir__)
2
- $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
3
- require 'version'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/ziptz/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = 'ziptz'
@@ -8,16 +8,21 @@ Gem::Specification.new do |s|
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ['Keith Morrison']
10
10
  s.email = 'keithm@infused.org'
11
- s.homepage = 'http://github.com/infused/ziptz'
11
+ s.homepage = 'https://github.com/infused/ziptz'
12
12
  s.summary = 'TimeZone info for any 5-digit US zip code'
13
13
  s.description = 'Get timezone info for all 5-digit US zip codes'
14
14
  s.license = 'MIT'
15
15
 
16
16
  s.rdoc_options = ['--charset=UTF-8']
17
17
  s.extra_rdoc_files = ['README.md', 'LICENSE']
18
- s.files = Dir['README.md', 'LICENSE', '{data,lib,spec}/**/*', 'ziptz.gemspec']
18
+ s.files = Dir['README.md', 'CHANGELOG.md', 'LICENSE', 'lib/**/*', 'ziptz.gemspec']
19
19
  s.require_paths = ['lib']
20
- s.required_ruby_version = '>= 3.1.0'
21
- s.metadata['rubygems_mfa_required'] = 'true'
20
+ s.required_ruby_version = '>= 3.3.0'
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
+ }
22
27
  s.add_dependency 'sqlite3', '~> 2.0'
23
28
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ziptz
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.2
4
+ version: 6.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Morrison
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-11-24 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: sqlite3
@@ -29,23 +28,23 @@ email: keithm@infused.org
29
28
  executables: []
30
29
  extensions: []
31
30
  extra_rdoc_files:
32
- - README.md
33
31
  - LICENSE
32
+ - README.md
34
33
  files:
34
+ - CHANGELOG.md
35
35
  - LICENSE
36
36
  - README.md
37
- - data/tz.db
38
- - lib/version.rb
39
37
  - lib/ziptz.rb
40
- - spec/spec_helper.rb
41
- - spec/ziptz_spec.rb
38
+ - lib/ziptz/version.rb
42
39
  - ziptz.gemspec
43
- homepage: http://github.com/infused/ziptz
40
+ homepage: https://github.com/infused/ziptz
44
41
  licenses:
45
42
  - MIT
46
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
47
47
  rubygems_mfa_required: 'true'
48
- post_install_message:
49
48
  rdoc_options:
50
49
  - "--charset=UTF-8"
51
50
  require_paths:
@@ -54,15 +53,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
54
53
  requirements:
55
54
  - - ">="
56
55
  - !ruby/object:Gem::Version
57
- version: 3.1.0
56
+ version: 3.3.0
58
57
  required_rubygems_version: !ruby/object:Gem::Requirement
59
58
  requirements:
60
59
  - - ">="
61
60
  - !ruby/object:Gem::Version
62
61
  version: '0'
63
62
  requirements: []
64
- rubygems_version: 3.5.9
65
- signing_key:
63
+ rubygems_version: 4.0.16
66
64
  specification_version: 4
67
65
  summary: TimeZone info for any 5-digit US zip code
68
66
  test_files: []
data/data/tz.db DELETED
Binary file
data/lib/version.rb DELETED
@@ -1,3 +0,0 @@
1
- class Ziptz
2
- VERSION = '5.1.2'.freeze
3
- end
data/spec/spec_helper.rb DELETED
@@ -1,8 +0,0 @@
1
- require 'ziptz'
2
- require 'yaml'
3
- require 'rspec'
4
-
5
- RSpec.configure do |config|
6
- config.order = :random
7
- config.disable_monkey_patching!
8
- end
data/spec/ziptz_spec.rb DELETED
@@ -1,119 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ziptz do
4
- let(:ziptz) { described_class.new }
5
-
6
- describe 'when inspected' do
7
- it 'does not show internal instance variables' do
8
- expect(ziptz.inspect).to match(/#<Ziptz:\d+>/)
9
- end
10
- end
11
-
12
- describe '#time_zone_name' do
13
- context 'when given a 5-digit zipcode' do
14
- it 'returns the time zone number' do
15
- expect(ziptz.time_zone_name('97034')).to eq 'America/Los_Angeles'
16
- end
17
- end
18
-
19
- context 'when given a 9-digit zipcode' do
20
- it 'returns the time zone number' do
21
- expect(ziptz.time_zone_name('97034-1234')).to eq 'America/Los_Angeles'
22
- end
23
- end
24
-
25
- context 'when there is no matching zipcode' do
26
- it 'returns nil' do
27
- expect(ziptz.time_zone_name('xyz')).to be_nil
28
- end
29
- end
30
-
31
- context 'when nil is passed' do
32
- it 'returns nil' do
33
- expect(ziptz.time_zone_name(nil)).to be_nil
34
- end
35
- end
36
- end
37
-
38
- describe '#time_zone_uses_dst?' do
39
- context 'when given a valid 5-digit zipcode' do
40
- it 'returns true' do
41
- expect(ziptz.time_zone_uses_dst?('97034')).to eq true
42
- end
43
- end
44
-
45
- context 'when given an invalid 5-digit zipcode' do
46
- it 'returns false' do
47
- expect(ziptz.time_zone_uses_dst?('85004')).to eq false
48
- end
49
- end
50
-
51
- context 'when given a valid 9-digit zipcode' do
52
- it 'returns a true' do
53
- expect(ziptz.time_zone_uses_dst?('97034-1234')).to eq true
54
- end
55
- end
56
-
57
- context 'when given an invalid 9-digit zipcode' do
58
- it 'returns false' do
59
- expect(ziptz.time_zone_uses_dst?('85004-1234')).to eq false
60
- end
61
- end
62
-
63
- context 'when there is no matching zipcode' do
64
- it 'returns nil' do
65
- expect(ziptz.time_zone_uses_dst?('xyz')).to be_nil
66
- end
67
- end
68
- end
69
-
70
- describe '#time_zone_offset' do
71
- context 'when given a 5-digit zipcode' do
72
- it 'returns the time zone number' do
73
- expect(ziptz.time_zone_offset('97034')).to eq(-28_800)
74
- end
75
- end
76
-
77
- context 'when given a 9-digit zipcode' do
78
- it 'returns the time zone number' do
79
- expect(ziptz.time_zone_offset('97034-1234')).to eq(-28_800)
80
- end
81
- end
82
-
83
- context 'when there is no matching zipcode' do
84
- it 'returns nil' do
85
- expect(ziptz.time_zone_offset('xyz')).to be_nil
86
- end
87
- end
88
- end
89
-
90
- describe '#zips' do
91
- context 'when given a time zone' do
92
- it 'returns an array of zip codes' do
93
- expect(ziptz.zips('Pacific/Pago_Pago')).to eq %w[96799]
94
- end
95
-
96
- it 'is case-insensitive' do
97
- expect(ziptz.zips('pacific/pago_pago')).to eq %w[96799]
98
- end
99
-
100
- it 'returns empty array for unknown time zones' do
101
- expect(ziptz.zips('Glark')).to be_empty
102
- end
103
- end
104
- end
105
-
106
- describe '#instance' do
107
- context 'when given a 5 digit zip code' do
108
- it 'matches the behavior of Ziptz.new' do
109
- expect(described_class.instance.time_zone_name('97034')).to eq ziptz.time_zone_name('97034')
110
- end
111
- end
112
-
113
- context 'when called twice' do
114
- it 'returns identical instances' do
115
- expect(described_class.instance.object_id).to eq described_class.instance.object_id
116
- end
117
- end
118
- end
119
- end