Skip to content

Commit

Permalink
Merge pull request #43 from chocoby/issue24-search
Browse files Browse the repository at this point in the history
文字列による検索は項目を指定して検索する
  • Loading branch information
chocoby committed Feb 9, 2021
2 parents 284ed92 + bde5c00 commit 9af2ffa
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 220 deletions.
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ require 'jp_prefecture'
都道府県コードを渡すと、都道府県コードから都道府県を検索します:

```ruby
pref = JpPrefecture::Prefecture.find 13
pref = JpPrefecture::Prefecture.find(13)
# => #<JpPrefecture::Prefecture:0x007fceb11927d8 @code=13, @name="東京都", @name_e="Tokyo", @name_h="とうきょうと", @name_k="トウキョウト", @zips=[1000000..2080035], @area="関東">
pref.code
# => 13
Expand All @@ -62,18 +62,27 @@ pref.type
以下のように書くことも可能です:

```ruby
JpPrefecture::Prefecture.find code: 13
JpPrefecture::Prefecture.find(code: 13)
```

### 都道府県名から都道府県を検索

前方一致で都道府県を検索します:

```ruby
JpPrefecture::Prefecture.find name: "東京都"
JpPrefecture::Prefecture.find name: "Tokyo"
JpPrefecture::Prefecture.find name: "tokyo"
JpPrefecture::Prefecture.find name: "トウキョウト"
JpPrefecture::Prefecture.find name: "とうきょうと"
JpPrefecture::Prefecture.find name: "東京"
# 漢字表記
JpPrefecture::Prefecture.find(name: "東京都")
JpPrefecture::Prefecture.find(name: "東京")

# 英語表記
JpPrefecture::Prefecture.find(name_e: "Tokyo")
JpPrefecture::Prefecture.find(name_e: "tokyo")

# ひらがな表記
JpPrefecture::Prefecture.find(name_h: "とうきょうと")

# カタカナ表記
JpPrefecture::Prefecture.find(name_k: "トウキョウト")
```

### 都道府県の一覧を取得
Expand Down Expand Up @@ -153,7 +162,7 @@ end
custom_mapping_path = "..." # /path/to/mapping_data

JpPrefecture.setup do |config|
config.mapping_data = YAML.load_file custom_mapping_path
config.mapping_data = YAML.load_file(custom_mapping_path)
end
```

Expand Down
27 changes: 18 additions & 9 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ require 'jp_prefecture'
Provide prefecture code to search prefecture's data

```ruby
pref = JpPrefecture::Prefecture.find 13
pref = JpPrefecture::Prefecture.find(13)
# => #<JpPrefecture::Prefecture:0x007fceb11927d8 @code=13, @name="東京都", @name_e="Tokyo", @name_h="とうきょうと", @name_k="トウキョウト", @zips=[1000000..2080035], @area="関東">
pref.code
# => 13
Expand All @@ -59,18 +59,27 @@ pref.type
or

```ruby
JpPrefecture::Prefecture.find code: 13
JpPrefecture::Prefecture.find(code: 13)
```

### Search by Prefecture Name

Search for a prefecture by forward match.

```ruby
JpPrefecture::Prefecture.find name: "東京都"
JpPrefecture::Prefecture.find name: "Tokyo"
JpPrefecture::Prefecture.find name: "tokyo"
JpPrefecture::Prefecture.find name: "トウキョウト"
JpPrefecture::Prefecture.find name: "とうきょうと"
JpPrefecture::Prefecture.find name: "東京"
# Kanji
JpPrefecture::Prefecture.find(name: "東京都")
JpPrefecture::Prefecture.find(name: "東京")

# English
JpPrefecture::Prefecture.find(name_e: "Tokyo")
JpPrefecture::Prefecture.find(name_e: "tokyo")

# Hiragana
JpPrefecture::Prefecture.find(name_h: "とうきょうと")

# Kakatana
JpPrefecture::Prefecture.find(name_k: "トウキョウト")
```

### All Prefectures
Expand Down Expand Up @@ -150,7 +159,7 @@ Customize mapping data with `custom_mapping_path`.
custom_mapping_path = "..." # /path/to/mapping_data

JpPrefecture.setup do |config|
config.mapping_data = YAML.load_file custom_mapping_path
config.mapping_data = YAML.load_file(custom_mapping_path)
end
```

Expand Down
104 changes: 42 additions & 62 deletions lib/jp_prefecture/prefecture.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

require 'jp_prefecture/prefecture/finder'
require 'jp_prefecture/mapping'
require 'jp_prefecture/zip_mapping'

Expand Down Expand Up @@ -40,55 +41,6 @@ def self.build(code, name, name_e, name_h = nil, name_k = nil, area = nil)
pref
end

# 都道府県を検索
#
# @example
# # 都道府県コードから検索
# JpPrefecture::Prefecture.find(1)
# JpPrefecture::Prefecture.find(code: 1)
#
# # 都道府県名から検索
# JpPrefecture::Prefecture.find(name: '北海道')
#
# # 都道府県名から検索(前方一致)
# JpPrefecture::Prefecture.find(name: '東京')
#
# # 英語表記の都道府県名から検索
# JpPrefecture::Prefecture.find(name: 'Hokkaido')
# JpPrefecture::Prefecture.find(name: 'hokkaido')
#
# @param args [Integer] 都道府県コード
# @param [Hash] args 検索条件
# @option args [Integer] :code 都道府県コード
# @option args [String] :name 都道府県名/英語/ひらがな/カタカナ表記の都道府県名
# @option args [Integer] :zip 郵便番号
# @return [JpPrefecture::Prefecture] 都道府県が見つかった場合は都道府県クラス
# @return [nil] 都道府県が見つからない場合は nil
def self.find(args)
return if args.nil?

code = if args.is_a?(Integer) || args.is_a?(String)
args.to_i
else
case args.keys[0]
when :name
find_code_by_name(args[:name])
when :code
args[:code].to_i
when :zip
ZipMapping.code_for_zip(args[:zip].to_i)
end
end

names = Mapping.data[code]

return unless names

build(code,
names[:name], names[:name_e],
names[:name_h], names[:name_k], names[:area])
end

# すべての都道府県クラスを返す
#
# @example
Expand All @@ -111,23 +63,51 @@ def self.all
end
end

# 名前から都道府県コードを前方一致で検索
# 都道府県を検索
#
# 文字列は前方一致で検索する
#
# @example
# # 都道府県コードを検索
# JpPrefecture::Prefecture.find(1)
# JpPrefecture::Prefecture.find(code: 1)
#
# # 都道府県名を検索
# JpPrefecture::Prefecture.find(name: '北海道')
# JpPrefecture::Prefecture.find(name: '東京')
#
# # 英語表記の都道府県名を検索
# JpPrefecture::Prefecture.find(name_e: 'Hokkaido')
# JpPrefecture::Prefecture.find(name_e: 'hokkaido')
#
# @param name [String] 検索する都道府県名
# @return [Integer] 見つかった場合は都道府県コード
# @return [nil] 見つからない場合は nil
def self.find_code_by_name(name)
return nil if name.nil? || name.empty?
# # ひらがな表記の都道府県名を検索
# JpPrefecture::Prefecture.find(name_h: 'ほっかいどう')
#
# # カタカナ表記の都道府県名を検索
# JpPrefecture::Prefecture.find(name_k: 'ホッカイドウ')
#
# # すべての項目を検索
# JpPrefecture::Prefecture.find(all_fields: '東')
#
# @param args [Integer] 都道府県コード
# @param args [Hash<Symbol, Integer>] :code 都道府県コード
# @param args [Hash<Symbol, String>] :name 漢字表記/:name_e 英語表記/:name_h ひらがな表記/:name_k カタカナ表記
# @param args [Hash<Symbol, Integer>] :zip 郵便番号
# @param args [Hash<Symbol, (String, Integer)>] :all_fields マッピングに定義しているすべてのフィールドから検索
# @return [JpPrefecture::Prefecture] 都道府県が見つかった場合は都道府県クラス
# @return [nil] 都道府県が見つからない場合は nil
def self.find(args)
return if args.nil?

name = name.downcase
case args
when Integer, String
JpPrefecture::Prefecture::Finder.new.find(field: nil, value: args)
when Hash
search_field = args.keys.first
search_value = args.values.first

Mapping.data.each do |m|
m[1].each_value do |v|
return m[0] if v.start_with?(name)
end
JpPrefecture::Prefecture::Finder.new.find(field: search_field, value: search_value)
end

nil
end
end
end
81 changes: 81 additions & 0 deletions lib/jp_prefecture/prefecture/finder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# frozen_string_literal: true

require 'jp_prefecture/mapping'
require 'jp_prefecture/zip_mapping'

module JpPrefecture
class Prefecture
# 都道府県の検索を行うクラス
class Finder
def initialize
@mapping = Mapping.data
end

# 指定した項目を検索
#
# @param field [Symbol] 検索する項目。nil の場合は都道府県コードとして扱う
# @param value [String, Integer] 検索する内容
# @return [JpPrefecture::Prefecture] 都道府県が見つかった場合は都道府県クラス
# @return [nil] 都道府県が見つからない場合は nil
def find(field:, value:)
code = find_code(field, value)
prefecture = @mapping[code]
return unless prefecture

JpPrefecture::Prefecture.build(
code,
prefecture[:name],
prefecture[:name_e],
prefecture[:name_h],
prefecture[:name_k],
prefecture[:area]
)
end

private

# @param field [Symbol] 検索する項目
# @param value [String, Integer] 検索する内容
# @return [Integer] 見つかった場合は都道府県コード
# @return [nil] 見つからない場合は nil
def find_code(field, value)
return value.to_i if field.nil?

case field
when :all_fields
find_code_by_name_from_all_fields(value)
when :name, :name_h, :name_k, :name_e
find_code_by_name(field, value)
when :code
value.to_i
when :zip
ZipMapping.code_for_zip(value.to_i)
end
end

# すべての項目を前方一致で検索
def find_code_by_name_from_all_fields(value)
return if value.nil? || value.empty?

value = value.downcase

@mapping.each do |m|
m[1].each_value do |v|
return m[0] if v.start_with?(value)
end
end
end

# 指定した項目を前方一致で検索
def find_code_by_name(field, value)
return if value.nil? || value.empty?

value = value.downcase

@mapping.each do |m|
return m[0] if m[1][field].start_with?(value)
end
end
end
end
end
72 changes: 72 additions & 0 deletions spec/prefecture/finder_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# frozen_string_literal: true

require 'spec_helper'

describe JpPrefecture::Prefecture::Finder do
describe '#find' do
shared_examples '都道府県が見つかる' do |field, value, expected_result|
let(:result) { JpPrefecture::Prefecture::Finder.new.find(field: field, value: value) }
it { expect(result.name).to eq(expected_result) }
end

shared_examples '都道府県が見つからない' do |field, value|
let(:result) { JpPrefecture::Prefecture::Finder.new.find(field: field, value: value) }
it { expect(result).to be_nil }
end

describe 'field に all_fields (すべての項目) を指定する' do
# area の「東北」が最初にマッチする
it_behaves_like '都道府県が見つかる', :all_fields, '東', '青森県'
it_behaves_like '都道府県が見つからない', :all_fields, '饂飩'
end

describe 'field に name (漢字表記) を指定する' do
it_behaves_like '都道府県が見つかる', :name, '北海道', '北海道'
it_behaves_like '都道府県が見つかる', :name, '東京', '東京都'
it_behaves_like '都道府県が見つかる', :name, '京都', '京都府'
it_behaves_like '都道府県が見つからない', :name, '饂飩'
end

describe 'field に name_e (英語表記) を指定する' do
it_behaves_like '都道府県が見つかる', :name_e, 'HOKKAIDO', '北海道'
it_behaves_like '都道府県が見つかる', :name_e, 'Hokkaido', '北海道'
it_behaves_like '都道府県が見つかる', :name_e, 'hokkaido', '北海道'
it_behaves_like '都道府県が見つからない', :name_e, 'Udon'
end

describe 'field に name_h (ひらがな表記) を指定する' do
it_behaves_like '都道府県が見つかる', :name_h, 'ほっかいどう', '北海道'
it_behaves_like '都道府県が見つかる', :name_h, 'ほっかい', '北海道'
it_behaves_like '都道府県が見つからない', :name_h, 'うどん'
end

describe 'field に name_k (カタカナ表記) を指定する' do
it_behaves_like '都道府県が見つかる', :name_k, 'ホッカイドウ', '北海道'
it_behaves_like '都道府県が見つかる', :name_k, 'ホッカイ', '北海道'
it_behaves_like '都道府県が見つからない', :name_k, 'ウドン'
end

describe 'field に code (都道府県コード) を指定する' do
it_behaves_like '都道府県が見つかる', :code, 1, '北海道'
it_behaves_like '都道府県が見つかる', :code, '1', '北海道'
it_behaves_like '都道府県が見つかる', :code, '01', '北海道'
it_behaves_like '都道府県が見つからない', :code, 999
it_behaves_like '都道府県が見つからない', :code, '999'
end

describe 'field に zip (郵便番号) を指定する' do
it_behaves_like '都道府県が見つかる', :zip, 10_000, '北海道'
it_behaves_like '都道府県が見つかる', :zip, '010000', '北海道'
it_behaves_like '都道府県が見つからない', :zip, 999_999
it_behaves_like '都道府県が見つからない', :zip, '999999'
end

describe 'field を指定しない' do
it_behaves_like '都道府県が見つかる', nil, 1, '北海道'
it_behaves_like '都道府県が見つかる', nil, '1', '北海道'
it_behaves_like '都道府県が見つかる', nil, '01', '北海道'
it_behaves_like '都道府県が見つからない', nil, 999
it_behaves_like '都道府県が見つからない', nil, '999'
end
end
end
Loading

0 comments on commit 9af2ffa

Please sign in to comment.