Module: JapaneseAddressParser::CacheRegexes
- Defined in:
- lib/japanese_address_parser/cache_regexes.rb,
sig/cache_regexes.rbs
Overview
データ取得・キャッシュ・正規表現パターン生成(cacheRegexes.ts)。
JS の ^/$(m フラグ無し)は文字列先頭/末尾なので、生成パターンでは \A/\z に翻訳する
(working_agreement §3-6)。スレッド安全性は考慮しない(§1-6)。
Defined Under Namespace
Classes: TownAlias
Class Method Summary collapse
-
.cache ⇒ Object
JS: const cache = new LRUCache({ max: currentConfig.cacheSize }) 町字 regex パターンのみ LRU でキャッシュする(working_agreement §1-8)。.
-
.cache_prefectures(data) ⇒ Object
JS: cachePrefectures(data).
-
.fetch_from_cache(key) ⇒ Object
JS: fetchFromCache(key, fetcher).
-
.get_chiban(pref, city, town, api_version) ⇒ Object
JS: getChiban(pref, city, town, apiVersion).
-
.get_city_regex_patterns(pref) ⇒ Object
JS: getCityRegexPatterns(pref).
-
.get_prefecture_regex_patterns(api) ⇒ Object
JS: getPrefectureRegexPatterns(api).
-
.get_prefectures ⇒ Object
JS: getPrefectures().
-
.get_rsdt(pref, city, town, api_version) ⇒ Object
JS: getRsdt(pref, city, town, apiVersion).
-
.get_same_named_prefecture_city_regex_patterns(pref_api) ⇒ Object
JS: getSameNamedPrefectureCityRegexPatterns(prefApi).
-
.get_town_regex_patterns(pref, city, api_version) ⇒ Object
JS: getTownRegexPatterns(pref, city, apiVersion).
-
.get_towns(pref_obj, city_obj, api_version) ⇒ Object
JS: getTowns(prefObj, cityObj, apiVersion).
-
.reset! ⇒ Object
モジュールレベルのキャッシュをすべて破棄する。 JS は test ファイルごとに別プロセスでモジュール状態が新鮮になる(プロセス分離)が、 Ruby/RSpec は 1 プロセス共有のため、
japanese_addresses_apiを切り替える際の明示的な リセット手段を提供する(runtime でデータ源を変えるユーザにも有用。working_agreement §1-6)。.
Instance Method Summary collapse
- #self?.cache ⇒ Object
- #self?.cache_prefectures ⇒ Data::PrefectureApi
- #self?.cached_city_patterns ⇒ Hash[Integer, Array[[Data::SingleCity, String]]]
- #self?.cached_towns ⇒ Hash[String, Data::MachiAzaApi]
- #self?.expand_town_number ⇒ String
- #self?.fetch_from_cache { ... } ⇒ Object
- #self?.fetch_subresource ⇒ String
- #self?.get_chiban ⇒ Array[Data::SingleChiban]
- #self?.get_city_regex_patterns ⇒ Array[[Data::SingleCity, String]]
- #self?.get_prefecture_regex_patterns ⇒ Array[[Data::SinglePrefecture, String]]
- #self?.get_prefectures ⇒ Data::PrefectureApi
- #self?.get_rsdt ⇒ Array[Data::SingleRsdt]
- #self?.get_same_named_prefecture_city_regex_patterns ⇒ Array[[String, String]]
- #self?.get_town_regex_patterns ⇒ Array[[untyped, String]]
- #self?.get_towns ⇒ Data::MachiAzaApi
- #self?.kanji_number_followed_by_cho? ⇒ Boolean
- #self?.parse_subresource ⇒ Array[untyped]
- #self?.point_from ⇒ [Float, Float]?
- #self?.reset! ⇒ nil
- #self?.stable_sort_by {|arg0| ... } ⇒ Object
- #self?.town_pattern_source ⇒ String
- #self?.town_sort_length ⇒ Integer
Class Method Details
.cache ⇒ Object
JS: const cache = new LRUCache({ max: currentConfig.cacheSize }) 町字 regex パターンのみ LRU でキャッシュする(working_agreement §1-8)。
39 40 41 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 39 def cache @cache ||= ::LruRedux::Cache.new(JapaneseAddressParser.config.cache_size) end |
.cache_prefectures(data) ⇒ Object
JS: cachePrefectures(data)
77 78 79 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 77 def cache_prefectures(data) @cached_prefectures = data end |
.fetch_from_cache(key) ⇒ Object
JS: fetchFromCache(key, fetcher)
44 45 46 47 48 49 50 51 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 44 def fetch_from_cache(key) cached = cache[key] return cached unless cached.nil? data = yield cache[key] = data data end |
.get_chiban(pref, city, town, api_version) ⇒ Object
JS: getChiban(pref, city, town, apiVersion)
234 235 236 237 238 239 240 241 242 243 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 234 def get_chiban(pref, city, town, api_version) row = town.csv_ranges&.dig('地番') return [] if row.nil? fetch_from_cache("地番-#{pref.code}-#{city.code}-#{town.machi_aza_name}") do chibans = parse_subresource(fetch_subresource('地番', pref, city, row, api_version)) # JS: [prc_num1, prc_num2, prc_num3].filter(Boolean).join('-') の長さ降順(chiban_to_string と同義)。 stable_sort_by(chibans) { |chiban| -chiban.chiban_to_string.length } end end |
.get_city_regex_patterns(pref) ⇒ Object
JS: getCityRegexPatterns(pref)
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 96 def get_city_regex_patterns(pref) cached = cached_city_patterns[pref.code] return cached unless cached.nil? # JS: cities.sort((a, b) => cityName(a).length - cityName(b).length) # 少ない文字数の地名に対してミスマッチしないよう文字数の昇順に安定ソートする。 cities = stable_sort_by(pref.cities) { |city| city.city_name.length } patterns = cities.map do |city| name = city.city_name pattern = "\\A#{Dict.to_regex_pattern(name)}" if name.match?(/(町|村)\z/) # JS: name.match(/(町|村)$/) # JS: `^${toRegexPattern(name).replace(/(.+?)郡/, '($1郡)?')}` — 郡が省略されてるかも pattern = "\\A#{Dict.to_regex_pattern(name).sub(/(.+?)郡/, '(\1郡)?')}" end [city, pattern] end cached_city_patterns[pref.code] = patterns end |
.get_prefecture_regex_patterns(api) ⇒ Object
JS: getPrefectureRegexPatterns(api)
82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 82 def get_prefecture_regex_patterns(api) cached = @cached_prefecture_patterns return cached if cached @cached_prefecture_patterns = api.data.map do |pref| # JS: pref.pref.replace(/(都|道|府|県)$/, '') — 末尾の都府県が抜けた住所に対応($ → \z) pref_name = pref.pref.sub(/(都|道|府|県)\z/, '') # JS: `^${_pref}(都|道|府|県)?`(^ → \A) [pref, "\\A#{pref_name}(都|道|府|県)?"] end end |
.get_prefectures ⇒ Object
JS: getPrefectures()
68 69 70 71 72 73 74 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 68 def get_prefectures cached = @cached_prefectures return cached unless cached.nil? response = Fetcher.fetch('.json') # ja.json cache_prefectures(Data::PrefectureApi.from_json(response.json)) end |
.get_rsdt(pref, city, town, api_version) ⇒ Object
JS: getRsdt(pref, city, town, apiVersion)
222 223 224 225 226 227 228 229 230 231 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 222 def get_rsdt(pref, city, town, api_version) row = town.csv_ranges&.dig('住居表示') return [] if row.nil? fetch_from_cache("住居表示-#{pref.code}-#{city.code}-#{town.machi_aza_name}") do rsdts = parse_subresource(fetch_subresource('住居表示', pref, city, row, api_version)) # JS: [blk_num, rsdt_num, rsdt_num2].filter(Boolean).join('-') の長さ降順(rsdt_to_string と同義)。 stable_sort_by(rsdts) { |rsdt| -rsdt.rsdt_to_string.length } end end |
.get_same_named_prefecture_city_regex_patterns(pref_api) ⇒ Object
JS: getSameNamedPrefectureCityRegexPatterns(prefApi)
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 196 def get_same_named_prefecture_city_regex_patterns(pref_api) cached = @cached_same_named_prefecture_city_regex_patterns return cached unless cached.nil? pref_list = pref_api.data # JS: pref.pref.replace(/[都|道|府|県]$/, '') — 文字クラス(| も含む)は上流のまま($ → \z) prefs = pref_list.map { |pref| pref.pref.sub(/[都|道|府|県]\z/, '') } # @type var patterns: ::Array[[::String, ::String]] patterns = [] pref_list.each do |pref| pref.cities.each do |city| city_n = city.city_name # 市の名前が別の都道府県名から始まっているケース(例: 福島県石川郡石川町)を考慮する。 prefs.each do |pref_name| # JS: cityN.indexOf(_prefs[j]) === 0 patterns << ["#{pref.pref}#{city_n}", "\\A#{city_n}"] if city_n.start_with?(pref_name) end end end @cached_same_named_prefecture_city_regex_patterns = patterns end |
.get_town_regex_patterns(pref, city, api_version) ⇒ Object
JS: getTownRegexPatterns(pref, city, apiVersion)
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 136 def get_town_regex_patterns(pref, city, api_version) fetch_from_cache("#{pref.code}-#{city.code}") do api = get_towns(pref, city, api_version) pre_towns = api.data town_set = ::Set.new(pre_towns.map(&:machi_aza_name)) # @type var towns: ::Array[Data::SingleMachiAza | TownAlias] towns = [] is_kyoto = city.city == '京都市' # 「○○町」が含まれるケースへの対応。通常は「町」の省略を同義語として許容するが、 # 「○○町」と「○○」が共存するケース・京都・漢数字を含むケースは省略を許容しない。 pre_towns.each do |town| towns << town original_town = town.machi_aza_name next if original_town.index('町').nil? # JS: indexOf('町') === -1 # JS: originalTown.replace(/(?!^町)町/g, '') — 冒頭の「町」は除外(^ → \A) town_abbr = original_town.gsub(/(?!\A町)町/, '') next if is_kyoto next if town_set.include?(town_abbr) next if town_set.include?("大字#{town_abbr}") next if kanji_number_followed_by_cho?(original_town) # エイリアスとして町なしのパターンを登録 towns << TownAlias.new(machiaza_id: town.machiaza_id, point: town.point, oaza_cho: town_abbr, original_town: town) end # JS: towns.sort((a, b) => bLen - aLen)(大字始まりは優先度を下げる)— 文字数の降順に安定ソート towns = stable_sort_by(towns) { |town| -town_sort_length(town) } # 後段の丁目ループは TownAlias を元 VO に剥がさずそのまま追加する(JS と同挙動)。 # @type var patterns: ::Array[[Data::SingleMachiAza | TownAlias, ::String]] patterns = towns.map do |town| pattern = Dict.to_regex_pattern(town_pattern_source(town.machi_aza_name)) # JS: 'originalTown' in town ? town.originalTown : town associated = town.is_a?(TownAlias) ? town.original_town : town [associated, pattern] end # X丁目 の丁目なしの数字だけ許容するため、最後に数字だけ追加する。 towns.each do |town| # JS: machiAzaName(town).match(/([^一二三四五六七八九十]+)([一二三四五六七八九十]+)(丁目?)/) chome_match = town.machi_aza_name.match(/([^一二三四五六七八九十]+)([一二三四五六七八九十]+)(丁目?)/) next unless chome_match chome_name_part = chome_match[1] chome_num = chome_match[2] # JS: toRegexPattern(`^${chomeNamePart}(${chomeNum}|${kan2num(chomeNum)})`)(^ → \A) pattern = Dict.to_regex_pattern("\\A#{chome_name_part}(#{chome_num}|#{Kan2num.call(chome_num)})") patterns << [town, pattern] end patterns end end |
.get_towns(pref_obj, city_obj, api_version) ⇒ Object
JS: getTowns(prefObj, cityObj, apiVersion)
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 119 def get_towns(pref_obj, city_obj, api_version) pref = pref_obj.prefecture_name city = city_obj.city_name cache_key = "#{pref}-#{city}" cached = cached_towns[cache_key] return cached unless cached.nil? # JS: ['', encodeURI(pref), encodeURI(city) + `.json?v=${apiVersion}`].join('/') # 非 ASCII のパーセントエンコードは Fetcher#http_request 側で一括して行う(二重エンコード回避) # ため、ここでは encodeURI せず生の県名・市名を渡す。 input = ['', pref, "#{city}.json?v=#{api_version}"].join('/') response = Fetcher.fetch(input) cached_towns[cache_key] = Data::MachiAzaApi.from_json(response.json) end |
.reset! ⇒ Object
モジュールレベルのキャッシュをすべて破棄する。
JS は test ファイルごとに別プロセスでモジュール状態が新鮮になる(プロセス分離)が、
Ruby/RSpec は 1 プロセス共有のため、japanese_addresses_api を切り替える際の明示的な
リセット手段を提供する(runtime でデータ源を変えるユーザにも有用。working_agreement §1-6)。
57 58 59 60 61 62 63 64 65 |
# File 'lib/japanese_address_parser/cache_regexes.rb', line 57 def reset! @cache = nil @cached_prefectures = nil @cached_prefecture_patterns = nil @cached_same_named_prefecture_city_regex_patterns = nil @cached_city_patterns = nil @cached_towns = nil nil end |
Instance Method Details
#self?.cache ⇒ Object
23 |
# File 'sig/cache_regexes.rbs', line 23
def self?.cache: () -> untyped
|
#self?.cache_prefectures ⇒ Data::PrefectureApi
27 |
# File 'sig/cache_regexes.rbs', line 27
def self?.cache_prefectures: (Data::PrefectureApi data) -> Data::PrefectureApi
|
#self?.cached_city_patterns ⇒ Hash[Integer, Array[[Data::SingleCity, String]]]
39 |
# File 'sig/cache_regexes.rbs', line 39
def self?.cached_city_patterns: () -> Hash[Integer, Array[[Data::SingleCity, String]]]
|
#self?.cached_towns ⇒ Hash[String, Data::MachiAzaApi]
40 |
# File 'sig/cache_regexes.rbs', line 40
def self?.cached_towns: () -> Hash[String, Data::MachiAzaApi]
|
#self?.expand_town_number ⇒ String
45 |
# File 'sig/cache_regexes.rbs', line 45
def self?.expand_town_number: (String match) -> String
|
#self?.fetch_from_cache { ... } ⇒ Object
24 |
# File 'sig/cache_regexes.rbs', line 24
def self?.fetch_from_cache: (String key) { () -> untyped } -> untyped
|
#self?.fetch_subresource ⇒ String
35 |
# File 'sig/cache_regexes.rbs', line 35
def self?.fetch_subresource: (String kind, Data::SinglePrefecture pref, Data::SingleCity city, Hash[String, Integer] row, Integer api_version) -> String
|
#self?.get_chiban ⇒ Array[Data::SingleChiban]
34 |
# File 'sig/cache_regexes.rbs', line 34
def self?.get_chiban: (Data::SinglePrefecture pref, Data::SingleCity city, Data::SingleMachiAza town, Integer api_version) -> Array[Data::SingleChiban]
|
#self?.get_city_regex_patterns ⇒ Array[[Data::SingleCity, String]]
29 |
# File 'sig/cache_regexes.rbs', line 29
def self?.get_city_regex_patterns: (Data::SinglePrefecture pref) -> Array[[Data::SingleCity, String]]
|
#self?.get_prefecture_regex_patterns ⇒ Array[[Data::SinglePrefecture, String]]
28 |
# File 'sig/cache_regexes.rbs', line 28
def self?.get_prefecture_regex_patterns: (Data::PrefectureApi api) -> Array[[Data::SinglePrefecture, String]]
|
#self?.get_prefectures ⇒ Data::PrefectureApi
26 |
# File 'sig/cache_regexes.rbs', line 26
def self?.get_prefectures: () -> Data::PrefectureApi
|
#self?.get_rsdt ⇒ Array[Data::SingleRsdt]
33 |
# File 'sig/cache_regexes.rbs', line 33
def self?.get_rsdt: (Data::SinglePrefecture pref, Data::SingleCity city, Data::SingleMachiAza town, Integer api_version) -> Array[Data::SingleRsdt]
|
#self?.get_same_named_prefecture_city_regex_patterns ⇒ Array[[String, String]]
32 |
# File 'sig/cache_regexes.rbs', line 32
def self?.get_same_named_prefecture_city_regex_patterns: (Data::PrefectureApi pref_api) -> Array[[String, String]]
|
#self?.get_town_regex_patterns ⇒ Array[[untyped, String]]
31 |
# File 'sig/cache_regexes.rbs', line 31
def self?.get_town_regex_patterns: (Data::SinglePrefecture pref, Data::SingleCity city, Integer api_version) -> Array[[untyped, String]]
|
#self?.get_towns ⇒ Data::MachiAzaApi
30 |
# File 'sig/cache_regexes.rbs', line 30
def self?.get_towns: (Data::SinglePrefecture pref_obj, Data::SingleCity city_obj, Integer api_version) -> Data::MachiAzaApi
|
#self?.kanji_number_followed_by_cho? ⇒ Boolean
43 |
# File 'sig/cache_regexes.rbs', line 43
def self?.kanji_number_followed_by_cho?: (String target_town_name) -> bool
|
#self?.parse_subresource ⇒ Array[untyped]
36 |
# File 'sig/cache_regexes.rbs', line 36
def self?.parse_subresource: (String data) -> Array[untyped]
|
#self?.point_from ⇒ [Float, Float]?
37 |
# File 'sig/cache_regexes.rbs', line 37
def self?.point_from: (untyped lng, untyped lat) -> [Float, Float]?
|
#self?.reset! ⇒ nil
25 |
# File 'sig/cache_regexes.rbs', line 25
def self?.reset!: () -> nil
|
#self?.stable_sort_by {|arg0| ... } ⇒ Object
41 |
# File 'sig/cache_regexes.rbs', line 41
def self?.stable_sort_by: (untyped list) { (untyped) -> untyped } -> untyped
|
#self?.town_pattern_source ⇒ String
44 |
# File 'sig/cache_regexes.rbs', line 44
def self?.town_pattern_source: (String name) -> String
|
#self?.town_sort_length ⇒ Integer
42 |
# File 'sig/cache_regexes.rbs', line 42
def self?.town_sort_length: (untyped town) -> Integer
|