thai_geodata 0.1.0 → 0.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/README.md +67 -44
- data/lib/thai_geodata/data/geography.json +96670 -0
- data/lib/thai_geodata/version.rb +1 -1
- data/lib/thai_geodata.rb +94 -13
- data/test/test_thai_geodata.rb +55 -2
- data/thai_geodata.gemspec +1 -0
- metadata +17 -2
data/lib/thai_geodata/version.rb
CHANGED
data/lib/thai_geodata.rb
CHANGED
|
@@ -3,24 +3,105 @@
|
|
|
3
3
|
require 'json'
|
|
4
4
|
require_relative 'thai_geodata/version'
|
|
5
5
|
|
|
6
|
-
# ThaiGeodata provides in-memory lookup of Thailand’s provinces, districts
|
|
7
|
-
# and
|
|
6
|
+
# ThaiGeodata provides in-memory lookup of Thailand’s provinces, districts,
|
|
7
|
+
# subdistricts, and combined geography records (with postal codes) from static JSON data.
|
|
8
8
|
module ThaiGeodata
|
|
9
9
|
DATA_PATH = File.join(__dir__, 'thai_geodata', 'data')
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
class << self
|
|
12
|
+
# Raw data loaders
|
|
13
|
+
def provinces
|
|
14
|
+
@provinces ||= load_json('provinces.json')
|
|
15
|
+
end
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
def districts
|
|
18
|
+
@districts ||= load_json('districts.json')
|
|
19
|
+
end
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
def subdistricts
|
|
22
|
+
@subdistricts ||= load_json('subdistricts.json')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def geography
|
|
26
|
+
@geography ||= load_json('geography.json')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Lookup helpers
|
|
30
|
+
|
|
31
|
+
# Find a province by code (Integer or String), or Thai/English name
|
|
32
|
+
def find_province(code_or_name)
|
|
33
|
+
provinces.find do |p|
|
|
34
|
+
match_code_or_name?(p, 'provinceCode', 'provinceNameTh', 'provinceNameEn', code_or_name)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Find a district by code (Integer or String), or Thai/English name
|
|
39
|
+
def find_district(code_or_name)
|
|
40
|
+
districts.find do |d|
|
|
41
|
+
match_code_or_name?(d, 'districtCode', 'districtNameTh', 'districtNameEn', code_or_name)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Find a subdistrict by code (Integer or String), or Thai/English name
|
|
46
|
+
def find_subdistrict(code_or_name)
|
|
47
|
+
subdistricts.find do |s|
|
|
48
|
+
match_code_or_name?(s, 'subdistrictCode', 'subdistrictNameTh', 'subdistrictNameEn', code_or_name)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# List all districts for a given province (code or name)
|
|
53
|
+
def districts_for_province(province_code_or_name)
|
|
54
|
+
prov = find_province(province_code_or_name)
|
|
55
|
+
return [] unless prov
|
|
56
|
+
|
|
57
|
+
districts.select { |d| d['provinceCode'] == prov['provinceCode'] }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# List all subdistricts for a given district (code or name)
|
|
61
|
+
def subdistricts_for_district(district_code_or_name)
|
|
62
|
+
dist = find_district(district_code_or_name)
|
|
63
|
+
return [] unless dist
|
|
64
|
+
|
|
65
|
+
subdistricts.select { |s| s['districtCode'] == dist['districtCode'] }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Get the postal code for a given subdistrict (code or name)
|
|
69
|
+
def postal_code_for_subdistrict(code_or_name)
|
|
70
|
+
sub = find_subdistrict(code_or_name)
|
|
71
|
+
sub ? sub['postalCode'] : nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Get a full path (province, district, subdistrict) for a subdistrict
|
|
75
|
+
def location_path_for_subdistrict(code_or_name)
|
|
76
|
+
sub = find_subdistrict(code_or_name)
|
|
77
|
+
return nil unless sub
|
|
78
|
+
|
|
79
|
+
dist = find_district(sub['districtCode'])
|
|
80
|
+
prov = find_province(sub['provinceCode'])
|
|
81
|
+
|
|
82
|
+
{
|
|
83
|
+
province: prov ? prov['provinceNameTh'] : nil,
|
|
84
|
+
district: dist ? dist['districtNameTh'] : nil,
|
|
85
|
+
subdistrict: sub['subdistrictNameTh']
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# Load JSON file from DATA_PATH
|
|
92
|
+
def load_json(filename)
|
|
93
|
+
path = File.join(DATA_PATH, filename)
|
|
94
|
+
JSON.parse(File.read(path))
|
|
95
|
+
end
|
|
22
96
|
|
|
23
|
-
|
|
24
|
-
|
|
97
|
+
# Helper to match by numeric code or localized/English names
|
|
98
|
+
def match_code_or_name?(hash, code_key, th_key, en_key, code_or_name)
|
|
99
|
+
if code_or_name.to_s =~ /^\d+$/
|
|
100
|
+
hash[code_key] == code_or_name.to_i
|
|
101
|
+
else
|
|
102
|
+
hash[th_key] == code_or_name || hash[en_key].casecmp(code_or_name.to_s).zero?
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
private :match_code_or_name?
|
|
25
106
|
end
|
|
26
107
|
end
|
data/test/test_thai_geodata.rb
CHANGED
|
@@ -1,10 +1,63 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'minitest/autorun'
|
|
4
|
-
|
|
4
|
+
require 'thai_geodata'
|
|
5
5
|
|
|
6
6
|
class ThaiGeodataTest < Minitest::Test
|
|
7
7
|
def test_provinces_loaded
|
|
8
|
-
|
|
8
|
+
refute_empty ThaiGeodata.provinces
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_find_province_by_code
|
|
12
|
+
bangkok = ThaiGeodata.find_province(10)
|
|
13
|
+
assert_equal 'กรุงเทพมหานคร', bangkok['provinceNameTh']
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_find_province_by_name_en
|
|
17
|
+
cm = ThaiGeodata.find_province('Chiang Mai')
|
|
18
|
+
assert_equal 50, cm['provinceCode']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_find_district_by_code
|
|
22
|
+
dist = ThaiGeodata.find_district(1001)
|
|
23
|
+
assert_equal 'พระนคร', dist['districtNameTh']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_find_subdistrict_by_code
|
|
27
|
+
sub = ThaiGeodata.find_subdistrict(100_101)
|
|
28
|
+
assert_equal 'พระบรมมหาราชวัง', sub['subdistrictNameTh']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_districts_for_province
|
|
32
|
+
dists = ThaiGeodata.districts_for_province('Bangkok')
|
|
33
|
+
assert dists.any?
|
|
34
|
+
assert_equal(dists, ThaiGeodata.districts.select { |d| d['provinceCode'] == 10 })
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_subdistricts_for_district
|
|
38
|
+
subs = ThaiGeodata.subdistricts_for_district(1001)
|
|
39
|
+
assert subs.any?
|
|
40
|
+
assert_equal(subs, ThaiGeodata.subdistricts.select { |s| s['districtCode'] == 1001 })
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_postal_code_for_subdistrict
|
|
44
|
+
assert_equal 10_200, ThaiGeodata.postal_code_for_subdistrict(100_101)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_location_path_for_subdistrict
|
|
48
|
+
path = ThaiGeodata.location_path_for_subdistrict(100_101)
|
|
49
|
+
expected = {
|
|
50
|
+
province: 'กรุงเทพมหานคร',
|
|
51
|
+
district: 'พระนคร',
|
|
52
|
+
subdistrict: 'พระบรมมหาราชวัง'
|
|
53
|
+
}
|
|
54
|
+
assert_equal expected, path
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_geography_loaded
|
|
58
|
+
refute_empty ThaiGeodata.geography
|
|
59
|
+
first = ThaiGeodata.geography.first
|
|
60
|
+
assert first.key?('provinceCode')
|
|
61
|
+
assert first.key?('postalCode')
|
|
9
62
|
end
|
|
10
63
|
end
|
data/thai_geodata.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: thai_geodata
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Your Name
|
|
@@ -9,7 +9,21 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2025-06-15 00:00:00.000000000 Z
|
|
12
|
-
dependencies:
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: minitest
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.0'
|
|
13
27
|
description: A Ruby gem wrapping the MIT-licensed Thailand Geography JSON dataset,
|
|
14
28
|
with lookup helpers.
|
|
15
29
|
email:
|
|
@@ -25,6 +39,7 @@ files:
|
|
|
25
39
|
- Rakefile
|
|
26
40
|
- lib/thai_geodata.rb
|
|
27
41
|
- lib/thai_geodata/data/districts.json
|
|
42
|
+
- lib/thai_geodata/data/geography.json
|
|
28
43
|
- lib/thai_geodata/data/provinces.json
|
|
29
44
|
- lib/thai_geodata/data/subdistricts.json
|
|
30
45
|
- lib/thai_geodata/version.rb
|