IMAGE: https://cdn-ak.f.st-hatena.com/images/fotolife/i/ikmbear/20220118/20220118162141.png
作ったもの
jp_local_govという日本の$1コードを市区町村の情報にパースしてくれるGemを作りました。人生初Gemリリースです🎉
「そもそも$1コードってなんやねん」方も多いと思いますが、
$1(ぜんこくちほうこうきょうだんたいコード)[注釈 1]は、日本の地方公共団体につけられた、数字3桁または5桁または6桁の符号(コード)で ある。コードが与えられる$1とは、都道府県・市町村・特別区、一部事務組合・地方開発事業団・広域連合、加えて、$1ではないが行政区・東京都区部である。
というものです。JIS規格にも指定されています。
3桁、5桁、6桁とありますが、ルール的には
- 上2桁が$1府県、
- 続く3桁が市区町村
- 残りの1桁がチェックディジット
になっているので、このGemでは6桁フルの状態をパースできるようになっています。
READMEにも書いているのですが、jp_prefectureのア$1に多大に影響を受けています。
作った背景
今作っているサービスで必要だったからです。
ざっくりいうと公共料金を計算するサービスで、その計算のための料率が市区町村ごとに違うために、市区町村ごとにレコードを持つ必要がありました。
で、市区町村だけのテーブルをもつのもなんだか微妙だし、市区町村のための管理画面をもつのも面倒だったので、「Gemでできないかな〜」と思っていたのですが、似たようなア$1のGemは更新が数年前…。
…みたいなことを、FJORD BOOT CAMP内で日報に書いたら、メンターさんから「作ってみては」とアド$1が。
「ちょっと難しいかも…」と思いつつも、内心「作ってみたい、MY FIRST GEM」という思いが心の中に溢れてきたので、作ることにしました!
使い方
だいたいREADMEに書いてある通りなんですが、英語なので日本語でも書きます。
インストール
一応Ruby3.0.0以上が対象です。
普通にインストールするか
Gemfileを使ってインストールします
必要に応じてrequire
します。
JpLocalGov.find
)
id指定の検索($1コード(String)を指定することで、$1の情報を取得することができます。
この後のメソッドでも共通ですが、取得できる情報は
- $1コード
- $1府県コード
- $1府県(漢字)
- $1府県(カタカナ)
- 市区町村(漢字)
- 市区町村(カタカナ)
- $1所在地かどうか
です。
ひらがなとか英字とかも追加するのは苦ではないんですが、$1が出している元データは漢字とカタカナだけなのと、あんまり$1が見つからなかったので、一旦出していません。
あと東京都の都庁所在地は一応「東京」って習ったと思うんですが、「新宿」として登録しています。
JpLocalGov.where
)
条件指定での検索(上記の取得できる情報をキーとして、ハッシュを渡すことで、指定した条件に合致する市区町村の情報が配列で返ってきます。
なお複数の条件を指定した場合はAND検索になります。
JpLocalGov.all
)
全件検索(すべての$1の情報を取得したい場合に使用します。戻り値は配列です。
Railsだと、collection_select
を使用することで、すべての市区町村のコンボボックスを簡単に作ることができます。
JpLocalGov::Random
)
ランダムな$1情報の生成(ランダムな$1情報から、指定したプロパティを返します。
一応想定するケースとしては、FactoryBotで$1コードを指定する際に、決めうちではんく探索的なテストデータを作成しておきたいという場合を想定しています。
後述しますが、Railsで使用する場合はDBに保持するカラムはlocal_gov_code
だけなので、その他のプロパティのメソッドはあまり使い所がないかもしれません笑
補足として、あくまでプロパティ単位でしかランダムな値を生成しないので、ランダムな$1の$1を作成する場合は、
という具合に呼んでやる必要があります。需要があれば、JpLocalGov::Random.new
みたいなのを作るかもです。
Railsでの使用(基本)
このGemをModelクラスにinclude
することで、そのモデル内でlocal_govenment
というメソッドが使えるようになります。
jp_local_gov :<地方公共団体コードを保存したカラム名>
とすることで、そのカラム($1コード)から、$1府県名や市区町村の情報を展開することができるようになります。
なおカラム「$1コード」の作成時、型はStringにする必要があります。
JpLocalGov.valid_code?
)
Railsでの使用(バリデーション)($1コードのチェックのためのメソッドを設けているので、これをカスタムバリデーションに組み込むことで、$1コードのチェックができます。
実施しているチェックは
- コードが文字列かどうか
- コードが正しい長さか(6文字)
- チェックディジットを満たしているか
- 正しい$1府県コードを持っているか
です。
チェックディジットについては、$1コードの仕様に記載があります。
11 検査数字
$1における検査数字は、電算処理にあたって、不正なコードが使われないよう第6桁目をチェック用としたもので、次の方式により算出した数字とする。(方式)第1桁から第5桁までの数字に、それぞれ6.5.4.3.2を乗じて算出した積の和を求め、その和を11で除し、商と剰余(以下「余り数字」という。)を求めて、11と余り数字との差の下1桁の数字を検査数字とする。ただし、積の和が11より小なるときは、検査数字は、11から積の和を控除した数字とする。
出典:https://www.soumu.go.jp/main_content/000137948.pdf
実装としてはこんな感じです。ボリューム的にもプログラミングのちょうどいい問題だと感じていて、結構好きな仕様です。
なお最初はチェックディジットだけのチェックでいいかなと思っていたんですが、チェックディジットを満たしていても、$1府県コードがイレギュラーになるケースに後から気がつきました。
なので、$1府県コード(1..47
)のチェックも入っています。
仕組み
そこまで複雑なGemではないのですが、一応こういう仕組みです。
情報の元は$1のこのページです。手順的には以下のような感じです。
- 元データ(PDF)をGem:pdf-readerで読み取る
- sqliteにぶん投げる
- sqlite内でソートを行う
- JSON府県ごとにSELECTしてJSONに出力する
- 出力されたJSONを使ってJSONコードをパースする
このGemはGitHubコードの情報が命なので、この処理自体をRakeタスクとして登録して、GitHub Actionsで1ヶ月に1回、自動でPRを作成する形式にしています。
今後の展望
まだIssueにも登録していませんが、ここらへんはやりたいなと思っています。
JpLocalGov.all
で$1の行政区を除外する
「区」って東京のイメージが強いですが、実は各$1府県の$1には区があります。例えば札幌市には$1や東区があります。
市区町村を選択するのに、ここら辺を選択したい場合もあれば、「札幌市」という市区町村の単位だけがあればいいケースもあると思っています(私のアプリもそうです)。
なので、これをオプションで除外できるようにしたいです。一応、$1府県コードに続く3桁の決まりでなんとか除外できそうなので、近いうちに入ると思います。
YARDでドキュメントを書く
@params
とかかいてあるあれです。
このGemはRBSを使っているので、それが半分ドキュメントの役割を果たしている感じもしますが、まだまだ普及率も高くないことと、自分自身が書いてみたいので、これも時間ができたらやる予定です。
各RubyバージョンでのテストのCIを実行する
強いGemのCIで走っているあれです。
今はrubyにruby-versionをおいて、それをGitHub Actionsで参照するようにしているのですが、これを各Rubyバージョンで実行できるようにしたいです。
どうやってやるのかわからんですが。
曖昧検索、一つのプロパティに対して複数条件検索、OR検索
今実装しているwhere
は完全一致検索かつAND検索で、一つのプロパティに対して一つの条件しか指定できないんですが、ここら辺をもうちょっと柔軟にしたいです。
あんまり使う機会ないんですけど、なんかできたら良さそうな感じするじゃないですか。
変更差分の$1
リリースしてからまだ時間が立ってないので、$1コードの変更は起こっていないんですが、変更が発生した場合になんかいい感じに見せられないかな〜とぼんやり思っています。
終わりに
というわけで、$1コードをパースしてくれるGem「jp_local_gov」をリリースしたというお話でした。
前にもnpmを作ったことはあったのですが、今回はちゃんと実践的に使えるものを作ったので、いろいろと学びも多かったし、楽しかったです😄
(npmの話はこちら)
市区町村まで必要になるケースってそんなに多くないかもですが、もしこのGemを作っていただける方がいるなら嬉しいです!バグや要望はIssueにお気軽に登録してください!