zakuro 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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