kamome 0.1.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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +25 -0
- data/.travis.yml +12 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +72 -0
- data/LICENSE +21 -0
- data/Makefile +12 -0
- data/README.md +139 -0
- data/Rakefile +6 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/kamome.gemspec +47 -0
- data/lib/kamome.rb +74 -0
- data/lib/kamome/configuration.rb +20 -0
- data/lib/kamome/csv_handler.rb +45 -0
- data/lib/kamome/downloader.rb +56 -0
- data/lib/kamome/loader.rb +36 -0
- data/lib/kamome/models/address.rb +83 -0
- data/lib/kamome/models/general.rb +107 -0
- data/lib/kamome/models/jigyosho.rb +106 -0
- data/lib/kamome/operation.rb +79 -0
- data/lib/kamome/transformations/cleaner.rb +19 -0
- data/lib/kamome/transformations/extractor.rb +18 -0
- data/lib/kamome/transformations/general_csv.rb +74 -0
- data/lib/kamome/transformations/jigyosho_csv.rb +81 -0
- data/lib/kamome/version.rb +5 -0
- metadata +188 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kamome
|
4
|
+
class Configuration
|
5
|
+
require 'securerandom'
|
6
|
+
require 'tmpdir'
|
7
|
+
|
8
|
+
attr_accessor :tmp_path
|
9
|
+
attr_accessor :open_uri_options
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@tmp_path = ::File.join(Dir.tmpdir, 'kamome', SecureRandom.hex(8))
|
13
|
+
@open_uri_options = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def working_directory
|
17
|
+
@working_directory ||= ::Pathname.new(@tmp_path.to_s)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kamome/transformations/general_csv'
|
4
|
+
require 'kamome/transformations/jigyosho_csv'
|
5
|
+
require 'csv'
|
6
|
+
|
7
|
+
module Kamome
|
8
|
+
class CsvHandler
|
9
|
+
def initialize(operation)
|
10
|
+
@operation = operation
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(csv_path)
|
14
|
+
::CSV.foreach(csv_path) do |row|
|
15
|
+
obj = transform(row)
|
16
|
+
yield(obj, $INPUT_LINE_NUMBER)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def transform(row)
|
23
|
+
transformer.public_send(transformed_method, row)
|
24
|
+
end
|
25
|
+
|
26
|
+
def transformed_method
|
27
|
+
return :generate_hash if @operation.type_hash?
|
28
|
+
return :generate_detail_model if @operation.type_detail?
|
29
|
+
|
30
|
+
:generate_model
|
31
|
+
end
|
32
|
+
|
33
|
+
def transformer
|
34
|
+
@transformer ||= @operation.genre_jigyosho? ? jigyosho_transformer : general_transformer
|
35
|
+
end
|
36
|
+
|
37
|
+
def jigyosho_transformer
|
38
|
+
::Kamome::Transformations::JigyoshoCsv.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def general_transformer
|
42
|
+
::Kamome::Transformations::GeneralCsv.new
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kamome
|
4
|
+
class Downloader
|
5
|
+
require 'open-uri'
|
6
|
+
require 'securerandom'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'zip'
|
9
|
+
require 'nkf'
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Pathname] CSV file path
|
16
|
+
def run(url:)
|
17
|
+
zip_path = download(url)
|
18
|
+
csv_path = unpack(zip_path)
|
19
|
+
zip_path.delete
|
20
|
+
csv_path
|
21
|
+
rescue StandardError => e
|
22
|
+
raise Kamome::DownloadError, "#{e.class}: #{e.message}"
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# @return [Pathname] downloaded file
|
28
|
+
def download(url)
|
29
|
+
dest = @config.working_directory.join(SecureRandom.hex(8) + '.zip')
|
30
|
+
::FileUtils.mkdir_p(dest.dirname)
|
31
|
+
|
32
|
+
::OpenURI.open_uri(url, @config.open_uri_options) do |response|
|
33
|
+
::File.binwrite(dest, response.read)
|
34
|
+
end
|
35
|
+
dest
|
36
|
+
end
|
37
|
+
|
38
|
+
def unpack(src)
|
39
|
+
# convert encoding Shift_JIS to UTF-8 (and half width Katakana to full width Katakana)
|
40
|
+
content = ::NKF.nkf('-w -Lu', take_csv_entry(src).get_input_stream.read)
|
41
|
+
|
42
|
+
dest = src.sub('.zip', '.csv')
|
43
|
+
::File.binwrite(dest, content)
|
44
|
+
dest
|
45
|
+
end
|
46
|
+
|
47
|
+
def take_csv_entry(src)
|
48
|
+
entry = ::Zip::File.open(src) do |zipfile|
|
49
|
+
zipfile.select { |o| o.name =~ /.*\.csv/i }.first
|
50
|
+
end
|
51
|
+
raise ::Kamome::DownloadError, 'Not found csvfile in zipfile' if entry.nil?
|
52
|
+
|
53
|
+
entry
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kamome/downloader'
|
4
|
+
require 'kamome/csv_handler'
|
5
|
+
|
6
|
+
module Kamome
|
7
|
+
class Loader
|
8
|
+
def initialize(config:)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(operation:, &block)
|
13
|
+
csv_handler = build_csv_handler(operation)
|
14
|
+
|
15
|
+
operation.urls.each do |url|
|
16
|
+
csv_path = download(url)
|
17
|
+
csv_handler.call(csv_path, &block)
|
18
|
+
csv_path.delete
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def download(url)
|
25
|
+
downloader.run(url: url)
|
26
|
+
end
|
27
|
+
|
28
|
+
def downloader
|
29
|
+
@downloader ||= ::Kamome::Downloader.new(@config)
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_csv_handler(operation)
|
33
|
+
::Kamome::CsvHandler.new(operation)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kamome
|
4
|
+
module Models
|
5
|
+
class Address
|
6
|
+
# @!attribute [rw] code
|
7
|
+
# 全国地方公共団体コード
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :code
|
10
|
+
|
11
|
+
# @!attribute [rw] zipcode
|
12
|
+
# 郵便番号(7桁)
|
13
|
+
# @return [String]
|
14
|
+
attr_accessor :zipcode
|
15
|
+
|
16
|
+
# @!attribute [rw] prefecture
|
17
|
+
# 都道府県名
|
18
|
+
# @return [String]
|
19
|
+
attr_accessor :prefecture
|
20
|
+
|
21
|
+
# @!attribute [rw] city
|
22
|
+
# 市区町村
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :city
|
25
|
+
|
26
|
+
# @!attribute [rw] town
|
27
|
+
# 町域
|
28
|
+
# @return [String]
|
29
|
+
attr_accessor :town
|
30
|
+
|
31
|
+
# @!attribute [rw] street
|
32
|
+
# 番地, 建物等
|
33
|
+
# @return [String]
|
34
|
+
attr_accessor :street
|
35
|
+
|
36
|
+
# @!attribute [rw] company_name
|
37
|
+
# 企業名/団体名 等
|
38
|
+
# @return [String]
|
39
|
+
attr_accessor :company_name
|
40
|
+
|
41
|
+
# @!attribute [rw] post_office_box
|
42
|
+
# 私書箱名
|
43
|
+
# @return [String]
|
44
|
+
attr_accessor :post_office_box
|
45
|
+
|
46
|
+
# @!attribute [rw] state
|
47
|
+
# 状態
|
48
|
+
# 0: 変更なし
|
49
|
+
# 1: 変更あり
|
50
|
+
# 2: 削除
|
51
|
+
# @return [Integer]
|
52
|
+
attr_accessor :state
|
53
|
+
|
54
|
+
def initialize(params = {})
|
55
|
+
params.each do |key, value|
|
56
|
+
public_send("#{key}=", value)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def attributes
|
61
|
+
{
|
62
|
+
code: code,
|
63
|
+
zipcode: zipcode,
|
64
|
+
prefecture: prefecture,
|
65
|
+
city: city,
|
66
|
+
town: town,
|
67
|
+
street: street,
|
68
|
+
company_name: company_name,
|
69
|
+
post_office_box: post_office_box,
|
70
|
+
state: state
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def changed?
|
75
|
+
state == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete?
|
79
|
+
state == 2
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kamome
|
4
|
+
module Models
|
5
|
+
# CSV Model: 読み仮名データの促音・拗音を小書きで表記するもの
|
6
|
+
# @see https://www.post.japanpost.jp/zipcode/dl/readme.html
|
7
|
+
class General
|
8
|
+
# @!attribute [rw] code
|
9
|
+
# 全国地方公共団体コード(JIS X0401, X0402), 半角数値
|
10
|
+
# @return [String]
|
11
|
+
attr_accessor :code
|
12
|
+
|
13
|
+
# @!attribute [rw] zipcode
|
14
|
+
# 郵便番号, 半角数値7桁
|
15
|
+
# @return [String]
|
16
|
+
attr_accessor :zipcode
|
17
|
+
|
18
|
+
# @!attribute [rw] prefecture_kana
|
19
|
+
# 都道府県名 カナ
|
20
|
+
# @return [String]
|
21
|
+
attr_accessor :prefecture_kana
|
22
|
+
|
23
|
+
# @!attribute [rw] city_kana
|
24
|
+
# 市区町村名 カナ
|
25
|
+
# @return [String]
|
26
|
+
attr_accessor :city_kana
|
27
|
+
|
28
|
+
# @!attribute [rw] town_kana
|
29
|
+
# 町域名 カナ
|
30
|
+
# @return [String]
|
31
|
+
attr_accessor :town_kana
|
32
|
+
|
33
|
+
# @!attribute [rw] prefecture
|
34
|
+
# 都道府県名 漢字
|
35
|
+
# @return [String]
|
36
|
+
attr_accessor :prefecture
|
37
|
+
|
38
|
+
# @!attribute [rw] city
|
39
|
+
# 市区町村名 漢字
|
40
|
+
# @return [String]
|
41
|
+
attr_accessor :city
|
42
|
+
|
43
|
+
# @!attribute [rw] town
|
44
|
+
# 町域名 漢字
|
45
|
+
# @return [String]
|
46
|
+
attr_accessor :town
|
47
|
+
|
48
|
+
# @!attribute [rw] ambiguous_town
|
49
|
+
# 一町域が二以上の郵便番号で表される場合 true
|
50
|
+
# @return [Boolean]
|
51
|
+
attr_accessor :ambiguous_town
|
52
|
+
|
53
|
+
# @!attribute [rw] ambiguous_street
|
54
|
+
# 小字毎に番地が起番されている町域の場合 true
|
55
|
+
# @return [Boolean]
|
56
|
+
attr_accessor :ambiguous_street
|
57
|
+
|
58
|
+
# @!attribute [rw] required_chome
|
59
|
+
# 丁目を有する町域の場合 true
|
60
|
+
# @return [Boolean]
|
61
|
+
attr_accessor :required_chome
|
62
|
+
|
63
|
+
# @!attribute [rw] ambiguous_zipcode
|
64
|
+
# 一つの郵便番号で二以上の町域を表す場合 true
|
65
|
+
# @return [Boolean]
|
66
|
+
attr_accessor :ambiguous_zipcode
|
67
|
+
|
68
|
+
# @!attribute [rw] state
|
69
|
+
# 更新の表示
|
70
|
+
# 0: 変更なし, 1: 変更あり, 2: 廃止
|
71
|
+
# @return [Integer]
|
72
|
+
attr_accessor :state
|
73
|
+
|
74
|
+
# @!attribute [rw] reason
|
75
|
+
# 変更理由
|
76
|
+
# 0: 変更なし, 1: 市政・区政・町政・分区・政令指定都市施行, 2: 住居表示の実施,
|
77
|
+
# 3: 区画整理, 4: 郵便区調整等, 5: 訂正, 6: 廃止
|
78
|
+
# @return [Integer]
|
79
|
+
attr_accessor :reason
|
80
|
+
|
81
|
+
def initialize(params = {})
|
82
|
+
params.each do |key, value|
|
83
|
+
public_send("#{key}=", value)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def attributes
|
88
|
+
{
|
89
|
+
code: code,
|
90
|
+
zipcode: zipcode,
|
91
|
+
prefecture_kana: prefecture_kana,
|
92
|
+
city_kana: city_kana,
|
93
|
+
town_kana: town_kana,
|
94
|
+
prefecture: prefecture,
|
95
|
+
city: city,
|
96
|
+
town: town,
|
97
|
+
ambiguous_town: ambiguous_town,
|
98
|
+
ambiguous_street: ambiguous_street,
|
99
|
+
required_chome: required_chome,
|
100
|
+
ambiguous_zipcode: ambiguous_zipcode,
|
101
|
+
state: state,
|
102
|
+
reason: reason
|
103
|
+
}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kamome
|
4
|
+
module Models
|
5
|
+
# CSV Model: 大口事業所個別番号データ
|
6
|
+
# @see https://www.post.japanpost.jp/zipcode/dl/jigyosyo/index-zip.html
|
7
|
+
# @see https://www.post.japanpost.jp/zipcode/dl/jigyosyo/readme.html
|
8
|
+
class Jigyosho
|
9
|
+
# @!attribute [rw] code
|
10
|
+
# 大口事業所の所在地のJISコード
|
11
|
+
# @return [String]
|
12
|
+
attr_accessor :code
|
13
|
+
|
14
|
+
# @!attribute [rw] name_kana
|
15
|
+
# 大口事業所名(カナ)
|
16
|
+
# @return [String]
|
17
|
+
attr_accessor :company_name_kana
|
18
|
+
|
19
|
+
# @!attribute [rw] name
|
20
|
+
# 大口事業所名(漢字)
|
21
|
+
# @return [String]
|
22
|
+
attr_accessor :company_name
|
23
|
+
|
24
|
+
# @!attribute [rw] prefecture
|
25
|
+
# 都道府県名(漢字)
|
26
|
+
# @return [String]
|
27
|
+
attr_accessor :prefecture
|
28
|
+
|
29
|
+
# @!attribute [rw] city
|
30
|
+
# 市区町村名(漢字)
|
31
|
+
# @return [String]
|
32
|
+
attr_accessor :city
|
33
|
+
|
34
|
+
# @!attribute [rw] town
|
35
|
+
# 町域名(漢字)
|
36
|
+
# @return [String]
|
37
|
+
attr_accessor :town
|
38
|
+
|
39
|
+
# @!attribute [rw] street
|
40
|
+
# 小字名、丁目、番地等(漢字)
|
41
|
+
# @return [String]
|
42
|
+
attr_accessor :street
|
43
|
+
|
44
|
+
# @!attribute [rw] post_office_box
|
45
|
+
# 私書箱名
|
46
|
+
# @return [String]
|
47
|
+
attr_accessor :post_office_box
|
48
|
+
|
49
|
+
# @!attribute [rw] town
|
50
|
+
# 大口事業所個別番号
|
51
|
+
# @return [String]
|
52
|
+
attr_accessor :zipcode
|
53
|
+
|
54
|
+
# @!attribute [rw] japanpost_office_name
|
55
|
+
# 取扱局
|
56
|
+
# @return [String]
|
57
|
+
attr_accessor :japanpost_office_name
|
58
|
+
|
59
|
+
# @!attribute [rw] post_office_box
|
60
|
+
# 私書箱: true, 大口事業所: false
|
61
|
+
# @return [Boolean]
|
62
|
+
attr_accessor :has_post_office_box
|
63
|
+
|
64
|
+
# @!attribute [rw] required_chome
|
65
|
+
# 複数番号の有無
|
66
|
+
# * 「0」複数番号無し
|
67
|
+
# * 「1」複数番号を設定している場合の個別番号の1
|
68
|
+
# * 「2」複数番号を設定している場合の個別番号の2
|
69
|
+
# * 「3」複数番号を設定している場合の個別番号の3
|
70
|
+
# @return [Integer]
|
71
|
+
attr_accessor :multiple
|
72
|
+
|
73
|
+
# @!attribute [rw] state
|
74
|
+
# 修正コード
|
75
|
+
# * 「0」修正なし
|
76
|
+
# * 「1」新規追加
|
77
|
+
# * 「5」廃止
|
78
|
+
# @return [Integer]
|
79
|
+
attr_accessor :state
|
80
|
+
|
81
|
+
def initialize(params = {})
|
82
|
+
params.each do |key, value|
|
83
|
+
public_send("#{key}=", value)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def attributes
|
88
|
+
{
|
89
|
+
code: code,
|
90
|
+
company_name_kana: company_name_kana,
|
91
|
+
company_name: company_name,
|
92
|
+
prefecture: prefecture,
|
93
|
+
city: city,
|
94
|
+
town: town,
|
95
|
+
street: street,
|
96
|
+
post_office_box: post_office_box,
|
97
|
+
zipcode: zipcode,
|
98
|
+
japanpost_office_name: japanpost_office_name,
|
99
|
+
has_post_office_box: has_post_office_box,
|
100
|
+
multiple: multiple,
|
101
|
+
state: state
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|