zakuro 0.0.3 → 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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +85 -43
  3. data/doc/operation.md +25 -0
  4. data/doc/operation/csv/month.csv +202 -0
  5. data/doc/operation/operation.xlsx +0 -0
  6. data/doc/operation/transfer.rb +73 -0
  7. data/lib/zakuro/era/japan/gengou.rb +106 -0
  8. data/lib/zakuro/era/japan/gengou/parser.rb +169 -0
  9. data/lib/zakuro/era/japan/gengou/type.rb +178 -0
  10. data/lib/zakuro/era/japan/gengou/validator.rb +234 -0
  11. data/lib/zakuro/era/japan/reki.rb +91 -0
  12. data/lib/zakuro/era/{gengou → japan/yaml}/set-001-until-south.yaml +0 -0
  13. data/lib/zakuro/era/{gengou → japan/yaml}/set-002-from-north.yaml +0 -0
  14. data/lib/zakuro/era/{gengou → japan/yaml}/set-003-modern.yaml +0 -0
  15. data/lib/zakuro/era/western.rb +1 -1
  16. data/lib/zakuro/operation/month/parser.rb +277 -0
  17. data/lib/zakuro/operation/month/type.rb +452 -0
  18. data/lib/zakuro/operation/month/validator.rb +498 -0
  19. data/lib/zakuro/operation/operation.rb +45 -0
  20. data/lib/zakuro/operation/yaml/month.yaml +6452 -0
  21. data/lib/zakuro/output/error.rb +2 -0
  22. data/lib/zakuro/output/logger.rb +2 -0
  23. data/lib/zakuro/output/response.rb +17 -15
  24. data/lib/zakuro/result/core.rb +52 -0
  25. data/lib/zakuro/result/data.rb +187 -0
  26. data/lib/zakuro/result/operation.rb +86 -0
  27. data/lib/zakuro/result/result.rb +37 -0
  28. data/lib/zakuro/{output → tools}/stringifier.rb +14 -7
  29. data/lib/zakuro/tools/typeof.rb +33 -0
  30. data/lib/zakuro/version.rb +1 -1
  31. data/lib/zakuro/version/senmyou/base/era.rb +1 -1
  32. data/lib/zakuro/version/senmyou/base/multi_gengou.rb +1 -1
  33. data/lib/zakuro/version/senmyou/base/multi_gengou_roller.rb +13 -1
  34. data/lib/zakuro/version/senmyou/base/solar_term.rb +10 -0
  35. data/lib/zakuro/version/senmyou/monthly/first_day.rb +44 -0
  36. data/lib/zakuro/version/senmyou/monthly/initialized_month.rb +48 -0
  37. data/lib/zakuro/version/senmyou/monthly/month.rb +127 -68
  38. data/lib/zakuro/version/senmyou/monthly/month_label.rb +87 -0
  39. data/lib/zakuro/version/senmyou/monthly/operated_month.rb +167 -0
  40. data/lib/zakuro/version/senmyou/{summary → range}/annual_range.rb +20 -23
  41. data/lib/zakuro/version/senmyou/{summary → range}/full_range.rb +102 -2
  42. data/lib/zakuro/version/senmyou/range/operated_range.rb +105 -0
  43. data/lib/zakuro/version/senmyou/range/operated_solar_terms.rb +163 -0
  44. data/lib/zakuro/version/senmyou/senmyou.rb +2 -2
  45. data/lib/zakuro/version/senmyou/{summary/specifier.rb → specifier/single_day_specifier.rb} +13 -14
  46. data/lib/zakuro/version/senmyou/stella/solar_average.rb +3 -7
  47. data/lib/zakuro/version/senmyou/summary/single.rb +71 -0
  48. data/lib/zakuro/version_factory.rb +1 -1
  49. metadata +35 -11
  50. data/lib/zakuro/era/japan.rb +0 -664
  51. data/lib/zakuro/output/result.rb +0 -225
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../western'
4
+ require_relative './type'
5
+ require 'yaml'
6
+
7
+ # :nodoc:
8
+ module Zakuro
9
+ #
10
+ # Japan 和暦
11
+ #
12
+ module Japan
13
+ #
14
+ # Validator yaml解析
15
+ #
16
+ module Validator
17
+ # :reek:TooManyInstanceVariables { max_instance_variables: 5 }
18
+
19
+ #
20
+ # Set 元号セット情報の検証/展開
21
+ #
22
+ class Set
23
+ # @return [String] 元号セットID
24
+ attr_reader :id
25
+ # @return [String] 元号セット名
26
+ attr_reader :name
27
+ # @return [String] 終了日
28
+ attr_reader :end_date
29
+ # @return [Array<Hash<String, String>>] 元号情報
30
+ attr_reader :list
31
+
32
+ #
33
+ # 初期化
34
+ #
35
+ # @param [Hash<String, Object>] hash 元号セット情報
36
+ #
37
+ def initialize(hash:)
38
+ @id = hash['id']
39
+ @name = hash['name']
40
+ @end_date = hash['end_date']
41
+ @list = hash['list']
42
+ end
43
+
44
+ # :reek:TooManyStatements { max_statements: 6 }
45
+
46
+ #
47
+ # 検証する
48
+ #
49
+ # @return [Array<String>] 不正メッセージ
50
+ #
51
+ def validate
52
+ failed = []
53
+ failed.push("invalid id. #{id}") unless id?
54
+
55
+ failed.push("invalid name. #{name}") unless name?
56
+
57
+ failed.push("invalid end_date. #{end_date}") unless western_date?
58
+
59
+ failed |= validate_list
60
+ failed
61
+ end
62
+
63
+ # :reek:NilCheck
64
+
65
+ #
66
+ # IDを検証する
67
+ #
68
+ # @return [True] 正しい
69
+ # @return [False] 正しくない
70
+ #
71
+ def id?
72
+ !(@id.nil? || !@id.is_a?(Integer))
73
+ end
74
+
75
+ #
76
+ # 元号セット名を検証する
77
+ #
78
+ # @return [True] 正しい
79
+ # @return [False] 正しくない
80
+ #
81
+ def name?
82
+ !(@name.nil? || !@name.is_a?(String))
83
+ end
84
+
85
+ #
86
+ # 日付文字列を検証する
87
+ #
88
+ # @return [True] 正しい
89
+ # @return [False] 正しくない
90
+ #
91
+ def western_date?
92
+ Western::Calendar.valid_date_string(str: @end_date)
93
+ end
94
+
95
+ # :reek:NilCheck
96
+
97
+ #
98
+ # 元号情報を検証する
99
+ #
100
+ # @return [True] 正しい
101
+ # @return [False] 正しくない
102
+ #
103
+ def list?
104
+ (!@list.nil? || @list.is_a?(Array))
105
+ end
106
+
107
+ #
108
+ # 元号情報を検証する
109
+ #
110
+ # @return [True] 正しい
111
+ # @return [False] 正しくない
112
+ #
113
+ def validate_list
114
+ return ["invalid list. #{@list.class}"] unless list?
115
+
116
+ failed = []
117
+ list.each_with_index do |li, index|
118
+ failed |= Gengou.new(hash: li, index: index).validate
119
+ end
120
+ failed
121
+ end
122
+ end
123
+
124
+ #
125
+ # Gengou 元号情報
126
+ #
127
+ class Gengou
128
+ # @return [Integer] 要素位置
129
+ attr_reader :index
130
+ # @return [String] 元号名
131
+ attr_reader :name
132
+ # @return [String] 開始日
133
+ attr_reader :start_date
134
+ # @return [String] 元旦
135
+ attr_reader :new_year_date
136
+ # @return [String] 開始年
137
+ attr_reader :start_year
138
+
139
+ #
140
+ # 初期化
141
+ #
142
+ # @param [Hash<String, Strin>] hash 元号情報
143
+ # @param [Integer] index (元号セット内での)元号の要素位置
144
+ #
145
+ def initialize(hash:, index:)
146
+ @index = index
147
+ @name = hash['name']
148
+ @start_date = hash['start_date']
149
+ @new_year_date = hash['new_year_date']
150
+ @start_year = hash['start_year']
151
+ end
152
+
153
+ # :reek:TooManyStatements { max_statements: 7 }
154
+
155
+ #
156
+ # 検証する
157
+ #
158
+ # @return [Array<String>] 不正メッセージ
159
+ #
160
+ def validate
161
+ prefix = "list[#{index}]. "
162
+ failed = []
163
+
164
+ failed.push(prefix + "invalid name. #{@name}") unless name?
165
+
166
+ failed.push(prefix + "invalid start_date. #{@start_date}") unless start_date?
167
+
168
+ failed.push(prefix + "invalid start_year. #{@start_year}") unless year?
169
+
170
+ failed.push(prefix + "invalid new_year_date. #{@new_year_date}") unless new_year_date?
171
+
172
+ failed
173
+ end
174
+
175
+ # :reek:NilCheck
176
+
177
+ #
178
+ # 元号名を検証する
179
+ #
180
+ # @return [True] 正しい
181
+ # @return [False] 正しくない
182
+ #
183
+ def name?
184
+ (!@name.nil? || @name.is_a?(String))
185
+ end
186
+
187
+ #
188
+ # 開始日文字列を検証する
189
+ #
190
+ # @return [True] 正しい
191
+ # @return [False] 正しくない
192
+ #
193
+ def start_date?
194
+ Western::Calendar.valid_date_string(str: @start_date)
195
+ end
196
+
197
+ #
198
+ # 元旦文字列を検証する
199
+ #
200
+ # @return [True] 正しい
201
+ # @return [False] 正しくない
202
+ #
203
+ def new_year_date?
204
+ Western::Calendar.valid_date_string(str: @new_year_date)
205
+ end
206
+
207
+ # :reek:NilCheck
208
+
209
+ #
210
+ # 元号年を検証する
211
+ #
212
+ # @return [True] 正しい
213
+ # @return [False] 正しくない
214
+ #
215
+ def year?
216
+ return true if @start_year.nil?
217
+
218
+ @start_year.is_a?(Integer)
219
+ end
220
+ end
221
+
222
+ #
223
+ # 検証する
224
+ #
225
+ # @param [Hash<String, Object>] yaml_hash yaml取得結果
226
+ #
227
+ # @return [Array<String>] 不正メッセージ
228
+ #
229
+ def self.run(yaml_hash:)
230
+ Set.new(hash: yaml_hash).validate
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../western'
4
+
5
+ # :nodoc:
6
+ module Zakuro
7
+ #
8
+ # Japan 和暦
9
+ #
10
+ module Japan
11
+ #
12
+ # Reki 暦
13
+ #
14
+ module Reki
15
+ #
16
+ # Range 暦(範囲)
17
+ #
18
+ class Range
19
+ # @return [String] 暦のクラス名
20
+ # version 以下を参照
21
+ attr_reader :class_name
22
+ # @return [Western::Calendar] 暦の開始日
23
+ attr_reader :start_date
24
+
25
+ #
26
+ # 初期化
27
+ #
28
+ # @param [String] class_name 暦のクラス名
29
+ # @param [Western::Calendar] start_date 暦の開始日
30
+ #
31
+ def initialize(class_name:, start_date:)
32
+ @class_name = class_name
33
+ @start_date = start_date
34
+ end
35
+ end
36
+
37
+ LIST = [
38
+ Range.new(
39
+ class_name: 'Zakuro::Genka::Gateway',
40
+ start_date: Western::Calendar.new(year: 445, month: 1, day: 24)
41
+ ),
42
+ Range.new(
43
+ class_name: 'Zakuro::Gihou::Gateway',
44
+ start_date: Western::Calendar.new(year: 698, month: 2, day: 16)
45
+ ),
46
+ Range.new(
47
+ class_name: 'Zakuro::Taien::Gateway',
48
+ start_date: Western::Calendar.new(year: 764, month: 2, day: 7)
49
+ ),
50
+ Range.new(
51
+ class_name: 'Zakuro::Senmyou::Gateway',
52
+ start_date: Western::Calendar.new(year: 862, month: 2, day: 3)
53
+ ),
54
+ Range.new(
55
+ class_name: 'Zakuro::Joukyou::Gateway',
56
+ start_date: Western::Calendar.new(year: 1685, month: 2, day: 4)
57
+ ),
58
+ Range.new(
59
+ class_name: 'Zakuro::Houryaku::Gateway',
60
+ start_date: Western::Calendar.new(year: 1755, month: 2, day: 11)
61
+ ),
62
+ Range.new(
63
+ class_name: 'Zakuro::Kansei::Gateway',
64
+ start_date: Western::Calendar.new(year: 1798, month: 2, day: 16)
65
+ ),
66
+ Range.new(
67
+ class_name: 'Zakuro::Tenpou::Gateway',
68
+ start_date: Western::Calendar.new(year: 1844, month: 2, day: 18)
69
+ ),
70
+ Range.new(
71
+ class_name: 'Zakuro::Gregorio::Gateway',
72
+ start_date: Western::Calendar.new(year: 1872, month: 12, day: 9)
73
+ )
74
+ ].freeze
75
+
76
+ #
77
+ # 指定した日付から対象の暦を引き当てる
78
+ #
79
+ # @param [Western::Calendar] date 日付
80
+ #
81
+ # @return [String] 暦のクラス名
82
+ #
83
+ def self.class_name(date: Western::Calendar.new)
84
+ LIST.reverse_each do |range|
85
+ return range.class_name if date >= range.start_date
86
+ end
87
+ raise ArgumentError, "invalid date: #{date.format}"
88
+ end
89
+ end
90
+ end
91
+ end
@@ -109,7 +109,7 @@ module Zakuro
109
109
  end
110
110
  end
111
111
 
112
- # :reek:TooManyMethods { max_methods: 17 }
112
+ # :reek:TooManyMethods { max_methods: 18 }
113
113
 
114
114
  #
115
115
  # Calendar 年月日情報(西暦)
@@ -0,0 +1,277 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require_relative '../../era/western'
5
+ require_relative './validator'
6
+ require_relative './type'
7
+
8
+ # :nodoc:
9
+ module Zakuro
10
+ #
11
+ # Operation 運用
12
+ #
13
+ module Operation
14
+ #
15
+ # TypeParser 型ごと変換
16
+ #
17
+ module TypeParser
18
+ #
19
+ # 無効値かを判定する
20
+ #
21
+ # @param [String] str 文字列
22
+ #
23
+ # @return [True] 無効値
24
+ # @return [False] 有効値
25
+ #
26
+ def self.invalid?(str:)
27
+ str == '-'
28
+ end
29
+
30
+ def self.text(str:)
31
+ return '' if invalid?(str: str)
32
+
33
+ str
34
+ end
35
+
36
+ #
37
+ # 有効行を変換する
38
+ #
39
+ # @param [String] str 文字列
40
+ #
41
+ # @return [True] 有効
42
+ # @return [False] 無効
43
+ #
44
+ def self.modified?(str:)
45
+ str == 'true'
46
+ end
47
+
48
+ #
49
+ # 月を変換する
50
+ #
51
+ # @param [String] str 文字列
52
+ #
53
+ # @return [Integer] 月
54
+ #
55
+ def self.month_number(str:)
56
+ return -1 if invalid?(str: str)
57
+
58
+ str.to_i
59
+ end
60
+
61
+ #
62
+ # 閏有無を変換する
63
+ #
64
+ # @param [String] str 文字列
65
+ #
66
+ # @return [True] 閏あり
67
+ # @return [True] 閏なし/閏設定なし
68
+ #
69
+ def self.month_leaped(str:)
70
+ str == 'true'
71
+ end
72
+
73
+ #
74
+ # 西暦日を変換する
75
+ #
76
+ # @param [String] str 文字列
77
+ #
78
+ # @return [Western::Calendar] 西暦日
79
+ #
80
+ def self.western_date(str:)
81
+ return Western::Calendar.new if invalid?(str: str)
82
+
83
+ Western::Calendar.parse(str: str)
84
+ end
85
+
86
+ #
87
+ # 日(差分)を変換する
88
+ #
89
+ # @param [String] str 文字列
90
+ #
91
+ # @return [Integer] 日(差分)
92
+ #
93
+ def self.days(str:)
94
+ return INVALID_DAY_VALUE if invalid?(str: str)
95
+
96
+ str.to_i
97
+ end
98
+
99
+ def self.solar_term_index(str:)
100
+ return -1 if invalid?(str: str)
101
+
102
+ str.to_i
103
+ end
104
+ end
105
+
106
+ #
107
+ # MonthParser 月情報解析(yaml)
108
+ #
109
+ module MonthParser
110
+ #
111
+ # 実行する
112
+ #
113
+ # @return [Array<MonthHistory>] 変更履歴
114
+ #
115
+ def self.run(filepath:)
116
+ hash = YAML.load_file(filepath)
117
+
118
+ failed = Validator.run(yaml_hash: hash)
119
+
120
+ raise ArgumentError, failed.join("\n") unless failed.empty?
121
+
122
+ load(yaml_hash: hash)
123
+ end
124
+
125
+ #
126
+ # 設定ファイルを読み込む
127
+ #
128
+ # @param [Hash] yaml_hash 設定ファイルテキスト
129
+ #
130
+ # @return [Array<MonthHistory>] 変更履歴
131
+ #
132
+ def self.load(yaml_hash: {})
133
+ annotations = {}
134
+ relations = {}
135
+ histories = create_histories(yaml_hash: yaml_hash, annotations: annotations,
136
+ relations: relations)
137
+
138
+ add_annotations(histories: histories, annotations: annotations, relations: relations)
139
+ end
140
+
141
+ #
142
+ # 変更履歴を読み込む
143
+ #
144
+ # @param [Hash] yaml_hash 設定ファイルテキスト
145
+ # @param [Hash] annotations 注釈(空)
146
+ # @param [Hash] relations 関連ID設定(空)
147
+ #
148
+ # @return [Array<MonthHistory>] 変更履歴
149
+ #
150
+ def self.create_histories(yaml_hash: {}, annotations: {}, relations: {})
151
+ result = []
152
+ yaml_hash.each do |month|
153
+ id = month['id']
154
+ annotations[id] = Annotation.new(
155
+ id: id,
156
+ description: Operation::TypeParser.text(str: month['description']),
157
+ note: Operation::TypeParser.text(str: month['note'])
158
+ )
159
+ relation_id = month['relation_id']
160
+
161
+ relations[id] = relation_id unless Operation::TypeParser.invalid?(str: relation_id)
162
+
163
+ next unless Operation::TypeParser.modified?(str: month['modified'])
164
+
165
+ history = create_history(yaml_hash: month)
166
+ result.push(history)
167
+ end
168
+
169
+ result
170
+ end
171
+ private_class_method :create_histories
172
+
173
+ def self.create_history(yaml_hash: {})
174
+ diffs = MonthDiffsParser.create(yaml_hash: yaml_hash['diffs'])
175
+
176
+ western_date = Operation::TypeParser.western_date(str: yaml_hash['western_date'])
177
+ reference = Reference.new(page: yaml_hash['page'].to_i, number: yaml_hash['number'].to_i,
178
+ japan_date: yaml_hash['japan_date'])
179
+ MonthHistory.new(id: yaml_hash['id'],
180
+ parent_id: yaml_hash['parent_id'],
181
+ reference: reference,
182
+ western_date: western_date,
183
+ diffs: diffs)
184
+ end
185
+ private_class_method :create_history
186
+
187
+ def self.add_annotations(histories: [], annotations: {}, relations: {})
188
+ result = []
189
+ histories.each do |history|
190
+ result.push(
191
+ MonthHistory.new(
192
+ id: history.id, reference: history.reference, western_date: history.western_date,
193
+ annotations: create_history_annnotations(history: history, annotations: annotations,
194
+ relations: relations),
195
+ diffs: history.diffs
196
+ )
197
+ )
198
+ end
199
+
200
+ result
201
+ end
202
+ private_class_method :add_annotations
203
+
204
+ def self.create_history_annnotations(history:, annotations: {}, relations: {})
205
+ history_id = history.id
206
+ history_annotations = []
207
+ [history_id, relations.fetch(history_id, '')].each do |id|
208
+ add_annotation(history_annotations: history_annotations,
209
+ annotations: annotations, id: id)
210
+ end
211
+
212
+ history_annotations
213
+ end
214
+
215
+ def self.add_annotation(history_annotations: [], annotations: {}, id: '')
216
+ annotation = annotations.fetch(id, Annotation.new)
217
+ history_annotations.push(annotation) unless annotation.invalid?
218
+ end
219
+ private_class_method :add_annotation
220
+ end
221
+
222
+ #
223
+ # MonthDiffsParser 月情報(差分)解析
224
+ #
225
+ module MonthDiffsParser
226
+ def self.create(yaml_hash: {})
227
+ Diffs.new(
228
+ month: create_month(yaml_hash: yaml_hash['month']),
229
+ solar_term: create_solar_term(yaml_hash: yaml_hash['solar_term']),
230
+ days: Operation::TypeParser.days(str: yaml_hash['days'])
231
+ )
232
+ end
233
+
234
+ def self.create_solar_term(yaml_hash: {})
235
+ SolarTerm::Direction.new(
236
+ source: create_source_solar_term(yaml_hash: yaml_hash['calc']),
237
+ destination: create_destination_solar_term(yaml_hash: yaml_hash['actual']),
238
+ days: Operation::TypeParser.days(str: yaml_hash['days'])
239
+ )
240
+ end
241
+ private_class_method :create_solar_term
242
+
243
+ def self.create_source_solar_term(yaml_hash: {})
244
+ SolarTerm::Source.new(
245
+ index: Operation::TypeParser.solar_term_index(str: yaml_hash['index']),
246
+ to: Operation::TypeParser.western_date(str: yaml_hash['to']),
247
+ zodiac_name: Operation::TypeParser.text(str: yaml_hash['zodiac_name'])
248
+ )
249
+ end
250
+ private_class_method :create_source_solar_term
251
+
252
+ def self.create_destination_solar_term(yaml_hash: {})
253
+ SolarTerm::Destination.new(
254
+ index: Operation::TypeParser.solar_term_index(str: yaml_hash['index']),
255
+ from: Operation::TypeParser.western_date(str: yaml_hash['from']),
256
+ zodiac_name: Operation::TypeParser.text(str: yaml_hash['zodiac_name'])
257
+ )
258
+ end
259
+ private_class_method :create_destination_solar_term
260
+
261
+ def self.create_month(yaml_hash: {})
262
+ number = yaml_hash['number']
263
+ leaped = yaml_hash['leaped']
264
+ days = yaml_hash['days']
265
+
266
+ Month.new(
267
+ number: Number.new(calc: Operation::TypeParser.month_number(str: number['calc']),
268
+ actual: Operation::TypeParser.month_number(str: number['actual'])),
269
+ leaped: Leaped.new(calc: Operation::TypeParser.month_leaped(str: leaped['calc']),
270
+ actual: Operation::TypeParser.month_leaped(str: leaped['actual'])),
271
+ days: Days.new(calc: days['calc'], actual: days['actual'])
272
+ )
273
+ end
274
+ private_class_method :create_month
275
+ end
276
+ end
277
+ end