zakuro 0.0.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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +9 -0
  3. data/.gitignore +69 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +14 -0
  6. data/.travis.yml +6 -0
  7. data/Gemfile +19 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +44 -0
  10. data/Rakefile +20 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/images/12/346/234/210/344/273/245/351/231/215/343/201/256/345/205/245/345/256/232/346/260/227.png +0 -0
  14. data/images/12/346/234/210/344/273/245/351/231/215/343/201/256/346/234/210/343/201/256/351/200/262/351/200/200.png +0 -0
  15. data/images/source/description.numbers +0 -0
  16. data/images//345/205/245/345/256/232/346/260/227/343/201/256/350/265/267/347/256/227.png +0 -0
  17. data/images//345/220/204/346/234/210/343/201/256/346/261/202/343/202/201/346/226/271.png +0 -0
  18. data/images//345/244/252/351/231/275/343/201/250/346/234/210.png +0 -0
  19. data/lib/zakuro.rb +9 -0
  20. data/lib/zakuro/condition.rb +239 -0
  21. data/lib/zakuro/cycle/abstract_remainder.rb +457 -0
  22. data/lib/zakuro/cycle/zodiac.rb +103 -0
  23. data/lib/zakuro/era/gengou/set-001-until-south.yaml +375 -0
  24. data/lib/zakuro/era/gengou/set-002-from-north.yaml +166 -0
  25. data/lib/zakuro/era/gengou/set-003-modern.yaml +12 -0
  26. data/lib/zakuro/era/japan.rb +630 -0
  27. data/lib/zakuro/era/western.rb +412 -0
  28. data/lib/zakuro/merchant.rb +57 -0
  29. data/lib/zakuro/output/error.rb +10 -0
  30. data/lib/zakuro/output/logger.rb +64 -0
  31. data/lib/zakuro/output/response.rb +170 -0
  32. data/lib/zakuro/output/result.rb +219 -0
  33. data/lib/zakuro/output/stringifier.rb +62 -0
  34. data/lib/zakuro/version.rb +7 -0
  35. data/lib/zakuro/version/abstract_version.rb +29 -0
  36. data/lib/zakuro/version/genka/genka.rb +19 -0
  37. data/lib/zakuro/version/gihou/gihou.rb +19 -0
  38. data/lib/zakuro/version/gregorio/gregorio.rb +19 -0
  39. data/lib/zakuro/version/houryaku/houryaku.rb +19 -0
  40. data/lib/zakuro/version/joukyou/joukyou.rb +19 -0
  41. data/lib/zakuro/version/kansei/kansei.rb +19 -0
  42. data/lib/zakuro/version/senmyou/README.md +586 -0
  43. data/lib/zakuro/version/senmyou/base/era.rb +81 -0
  44. data/lib/zakuro/version/senmyou/base/gengou.rb +210 -0
  45. data/lib/zakuro/version/senmyou/base/remainder.rb +60 -0
  46. data/lib/zakuro/version/senmyou/base/solar_term.rb +66 -0
  47. data/lib/zakuro/version/senmyou/base/year.rb +58 -0
  48. data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +220 -0
  49. data/lib/zakuro/version/senmyou/monthly/month.rb +112 -0
  50. data/lib/zakuro/version/senmyou/senmyou.rb +34 -0
  51. data/lib/zakuro/version/senmyou/stella/lunar_orbit.rb +332 -0
  52. data/lib/zakuro/version/senmyou/stella/solar_average.rb +192 -0
  53. data/lib/zakuro/version/senmyou/stella/solar_orbit.rb +398 -0
  54. data/lib/zakuro/version/senmyou/stella/winter_solstice.rb +106 -0
  55. data/lib/zakuro/version/senmyou/summary/annual_data.rb +186 -0
  56. data/lib/zakuro/version/senmyou/summary/gengou_data.rb +294 -0
  57. data/lib/zakuro/version/taien/taien.rb +19 -0
  58. data/lib/zakuro/version/tenpou/tenpou.rb +19 -0
  59. data/lib/zakuro/version_factory.rb +59 -0
  60. data/zakuro.gemspec +31 -0
  61. metadata +106 -0
@@ -0,0 +1,412 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ # :nodoc:
6
+ module Zakuro
7
+ #
8
+ # Western 西暦
9
+ #
10
+ module Western
11
+ #
12
+ # Type 日付種別
13
+ #
14
+ module Type
15
+ # @return [Symbol] ユリウス暦
16
+ JULIAN = :julian
17
+ # @return [Symbol] グレゴリオ暦
18
+ GREGORIAN = :gregorian
19
+ # @return [Symbol] ユリウス暦/グレゴリオ暦
20
+ DEFAULT = :default
21
+ end
22
+
23
+ # @return [Hash<Symbol, Integer>] グレゴリオ暦の開始日(ユリウス日)
24
+ DATE_START = {
25
+ # 通年ユリウス暦
26
+ Type::JULIAN => Date::JULIAN,
27
+ # 通年グレゴリオ暦
28
+ Type::GREGORIAN => Date::GREGORIAN,
29
+ # ユリウス暦/グレゴリオ暦
30
+ #
31
+ # Date::ITALY は以下引用の通りにユリウス暦/グレゴリオ暦の改暦が行われるため矛盾はない
32
+ #
33
+ # ユリウス暦で1582年10月4日(わが天正10年9月18日)の翌日を10月15日としてグレゴリオ暦に改暦した。
34
+ # 9月朔まではユリウス暦日に対応させるべきであるが、計算の都合でこの頁からグレゴリオ暦に対応させてある。
35
+ # 念のため相当するユリウス暦日を記すと、天正10年正月朔は1月24日、2月朔は2月23日、3月朔は3月24日、
36
+ # 4月朔は4月23日、5月朔は5月22日、6月朔は6月20日、7月朔は7月20日、8月朔は8月18日、9月朔は9月17日である。
37
+ # 以下必要ならグレゴリオ暦日の10日前を求めればよい。(暦法編第3章のix : 第30表参照)
38
+ # p.393
39
+ #
40
+ # Date::ITALY は改暦による存在しない日付(1582-10-05 ~ 1852-10-14)でエラーが発生する
41
+ #
42
+ # ref: https://github.com/ruby/ruby/blob/487d96c6b1cd7f5d415dba27a9684b30dfa9afed/ext/date/date_core.c#L9237-L9249
43
+ #
44
+ # * A Date object can be created with an optional argument,
45
+ # * the day of calendar reform as a Julian day number, which
46
+ # * should be 2298874 to 2426355 or negative/positive infinity.
47
+ # * The default value is +Date::ITALY+ (2299161=1582-10-15).
48
+ # * See also sample/cal.rb.
49
+ # *
50
+ # * $ ruby sample/cal.rb -c it 10 1582
51
+ # * October 1582
52
+ # * S M Tu W Th F S
53
+ # * 1 2 3 4 15 16
54
+ # * 17 18 19 20 21 22 23
55
+ # * 24 25 26 27 28 29 30
56
+ # * 31
57
+ #
58
+ Type::DEFAULT => Date::ITALY
59
+ }.freeze
60
+
61
+ #
62
+ # 日付種別からRuby標準のグレゴリオ暦開始日を引き当てる
63
+ #
64
+ # @param [Symbol] type 日付種別
65
+ #
66
+ # @return [Integer] Ruby標準のグレゴリオ暦開始日
67
+ #
68
+ def self.to_native_start(type:)
69
+ DATE_START.fetch(type, DATE_START[Type::DEFAULT])
70
+ end
71
+
72
+ #
73
+ # Ruby標準のグレゴリオ暦開始日から日付種別を引き当てる
74
+ #
75
+ # @param [Integer] start Ruby標準のグレゴリオ暦開始日
76
+ #
77
+ # @return [Symbol] 日付種別
78
+ #
79
+ def self.to_type(start:)
80
+ DATE_START.invert.fetch(start, Type::DEFAULT)
81
+ end
82
+
83
+ #
84
+ # Parameter 初期化引数
85
+ #
86
+ class Parameter
87
+ # @return [Integer] 年
88
+ attr_reader :year
89
+ # @return [Integer] 月
90
+ attr_reader :month
91
+ # @return [Integer] 日
92
+ attr_reader :day
93
+ # @return [Integer] Ruby標準のグレゴリオ暦開始日
94
+ attr_reader :start
95
+
96
+ #
97
+ # 初期化
98
+ #
99
+ # @param [Integer] year 年
100
+ # @param [Integer] month 月
101
+ # @param [Integer] day 日
102
+ # @param [Integer] start Ruby標準のグレゴリオ暦開始日
103
+ #
104
+ def initialize(year:, month:, day:, start:)
105
+ @year = year
106
+ @month = month
107
+ @day = day
108
+ @start = start
109
+ end
110
+ end
111
+
112
+ # :reek:TooManyMethods { max_methods: 17 }
113
+
114
+ #
115
+ # Calendar 年月日情報(西暦)
116
+ #
117
+ # このクラスでは以下の機能が求められる。
118
+ # 1. グレゴリオ暦(yyyy, mm, dd) -> 日付オブジェクト
119
+ # 2. ユリウス暦(yyyy, mm, dd) -> 日付オブジェクト
120
+ # 3. 指定なし(yyyy, mm, dd) -> 日付オブジェクト
121
+ # 4. 日付オブジェクト(グレゴリオ暦) -> グレゴリオ暦(yyyy, mm, dd)
122
+ # 5. 日付オブジェクト(ユリウス暦) -> ユリウス暦(yyyy, mm, dd)
123
+ # 6. 日付オブジェクト(指定なし) -> ユリウス暦/グレゴリオ暦(yyyy, mm, dd)
124
+ #
125
+ # * 3の "指定なし" とは、グレゴリオ暦開始日からを1、それ以前を2とする方式である
126
+ # * 6もまた上記に準じて日付を求める
127
+ # * それぞれ日付オブジェクトに変換する目的は、日付の加減算と比較のためである
128
+ #
129
+ # これらの機能はRubyの標準機能であり、特別な実装を要しない
130
+ #
131
+ # 定数 DATE_START のバリエーションで日付オブジェクトを初期化するだけで良い
132
+ #
133
+ class Calendar # rubocop:disable Metrics/ClassLength
134
+ attr_reader :param, :date
135
+
136
+ def validate
137
+ failed = valid_type
138
+
139
+ return failed unless failed.size.zero?
140
+
141
+ valid_date
142
+ end
143
+
144
+ # :reek:TooManyStatements { max_statements: 8 }
145
+
146
+ #
147
+ # データ型を検証する
148
+ #
149
+ # @return [Array<String>] 不正メッセージ
150
+ #
151
+ def valid_type
152
+ failed = []
153
+ year = @param.year
154
+ month = @param.month
155
+ day = @param.day
156
+ failed.push("wrong type. year: #{year}") unless year.is_a?(Integer)
157
+ failed.push("wrong type. month: #{month}") unless month.is_a?(Integer)
158
+ failed.push("wrong type. day: #{day}") unless day.is_a?(Integer)
159
+ failed
160
+ end
161
+
162
+ # :reek:TooManyStatements { max_statements: 7 }
163
+
164
+ #
165
+ # 日付データとして検証する
166
+ #
167
+ # @return [Array<String>] 不正メッセージ
168
+ #
169
+ def valid_date
170
+ failed = []
171
+
172
+ year = @param.year
173
+ month = @param.month
174
+ day = @param.day
175
+ start = @param.start
176
+ unless Date.valid_date?(year, month, day, start)
177
+ failed.push("year: #{year}, month: #{month}, " \
178
+ "day: #{day}, start: #{start}")
179
+ end
180
+ failed
181
+ end
182
+
183
+ #
184
+ # 初期化
185
+ #
186
+ # @param [Integer] year 年
187
+ # @param [Integer] month 月
188
+ # @param [Integer] day 日
189
+ # @param [Symbol] type 日付種別
190
+ #
191
+ def initialize(year: -4712, month: 1, day: 1, type: Type::DEFAULT)
192
+ start = Western.to_native_start(type: type)
193
+ @param = Parameter.new(year: year, month: month, day: day, start: start)
194
+
195
+ failed = validate
196
+ raise ArgumentError, failed.join('\n') unless failed.size.zero?
197
+
198
+ @date = Date.new(year, month, day, start)
199
+ end
200
+
201
+ #
202
+ # 初期化時の日付とは異なる種別に切り替える
203
+ #
204
+ # @example Ruby標準の start_with に相当する
205
+ # > date = Date.new(1582, 10, 15)
206
+ # => #<Date: 1582-10-15 ((2299161j,0s,0n),+0s,2299161j)>
207
+ # > date.new_start(Date::JULIAN)
208
+ # => #<Date: 1582-10-05 ((2299161j,0s,0n),+0s,Infj)>
209
+ #
210
+ # @param [Symbol] type 日付種別
211
+ #
212
+ # @return [Calendar] 年月日情報(西暦)
213
+ #
214
+ def redate(type: Type::DEFAULT)
215
+ start = DATE_START.fetch(type, DATE_START[Type::DEFAULT])
216
+ @date = @date.new_start(start)
217
+ self
218
+ end
219
+
220
+ #
221
+ # 加算する
222
+ #
223
+ # @param [Calendar,Integer] other 年月日情報(西暦),日数
224
+ #
225
+ # @return [Calendar] 年月日情報(西暦)
226
+ #
227
+ def +(other)
228
+ return @date.jd + other.date.jd if other.is_a?(Western::Calendar)
229
+
230
+ @date += other
231
+ self
232
+ end
233
+
234
+ #
235
+ # 減算する
236
+ #
237
+ # @param [Calendar,Integer] other 年月日情報(西暦),日数
238
+ #
239
+ # @return [Calendar] 年月日情報(西暦)
240
+ #
241
+ def -(other)
242
+ return @date.jd - other.date.jd if other.is_a?(Western::Calendar)
243
+
244
+ @date -= other
245
+ self
246
+ end
247
+
248
+ #
249
+ # 大小比較する(>)
250
+ #
251
+ # @param [Calendar] other 年月日情報(西暦)
252
+ #
253
+ # @return [True] より大きい(未来日である)
254
+ # @return [False] 以下(現在日/過去日である)
255
+ #
256
+ def >(other)
257
+ @date > other.date
258
+ end
259
+
260
+ #
261
+ # 大小比較する(>=)
262
+ #
263
+ # @param [Calendar] other 年月日情報(西暦)
264
+ #
265
+ # @return [True] 以上(現在日/未来日である)
266
+ # @return [False] より小さい(過去日である)
267
+ #
268
+ def >=(other)
269
+ @date >= other.date
270
+ end
271
+
272
+ #
273
+ # 大小比較する(<)
274
+ #
275
+ # @param [Calendar] other 年月日情報(西暦)
276
+ #
277
+ # @return [True] より小さい(過去日である)
278
+ # @return [False] 以上(現在日/未来日である)
279
+ #
280
+ def <(other)
281
+ @date < other.date
282
+ end
283
+
284
+ #
285
+ # 大小比較する(<=)
286
+ #
287
+ # @param [Calendar] other 年月日情報(西暦)
288
+ #
289
+ # @return [True] 以下(過去日/現在日である)
290
+ # @return [False] より大きい(未来日である)
291
+ #
292
+ def <=(other)
293
+ @date <= other.date
294
+ end
295
+
296
+ #
297
+ # 大小比較する(==)
298
+ #
299
+ # @param [Calendar] other 年月日情報(西暦)
300
+ #
301
+ # @return [True] 等しい(現在日である)
302
+ # @return [False] 等しくない(過去日/未来日である)
303
+ #
304
+ def ==(other)
305
+ @date == other.date
306
+ end
307
+
308
+ #
309
+ # 年を取得する
310
+ #
311
+ # @return [Integer] 年
312
+ #
313
+ def year
314
+ @date.year
315
+ end
316
+
317
+ #
318
+ # 月を取得する
319
+ #
320
+ # @return [Integer] 月
321
+ #
322
+ def month
323
+ @date.month
324
+ end
325
+
326
+ #
327
+ # 日を取得する
328
+ #
329
+ # @return [Integer] 日
330
+ #
331
+ def day
332
+ @date.day
333
+ end
334
+
335
+ #
336
+ # 次年にする
337
+ #
338
+ # @param [Integer] num 年数
339
+ #
340
+ # @return [Calendar] 年月日情報(西暦)
341
+ #
342
+ def next_year(num: 1)
343
+ @date = @date.next_year(num)
344
+ self
345
+ end
346
+
347
+ #
348
+ # 年月日をフォーマット化する
349
+ #
350
+ # @param [String] form フォーマット
351
+ #
352
+ # @return [String] 年月日情報
353
+ #
354
+ def format(form: '%Y-%m-%d')
355
+ @date.strftime(form)
356
+ end
357
+
358
+ #
359
+ # 年月日情報(西暦)を生成する
360
+ #
361
+ # @param [Date] date Ruby標準日付
362
+ #
363
+ # @return [Calendar] 年月日情報(西暦)
364
+ #
365
+ def self.create(date: Date.new)
366
+ type = Western.to_type(start: date.start)
367
+ Calendar.new(year: date.year, month: date.month,
368
+ day: date.day, type: type)
369
+ end
370
+
371
+ #
372
+ # 年月日情報(西暦)を生成する
373
+ #
374
+ # @param [String] str 日付文字列
375
+ # @param [Symbol] type 日付種別
376
+ #
377
+ # @return [Calendar] 年月日情報(西暦)
378
+ #
379
+ def self.parse(str: '', type: Type::DEFAULT)
380
+ unless Calendar.valid_date_string(str: str, type: type)
381
+ raise ArgumentError, "invalid date string: #{str}"
382
+ end
383
+
384
+ start = DATE_START.fetch(type, DATE_START[Type::DEFAULT])
385
+ date = Date.parse(str, start)
386
+
387
+ Calendar.new(
388
+ year: date.year, month: date.month, day: date.day, type: type
389
+ )
390
+ end
391
+
392
+ #
393
+ # 日付文字列を検証する
394
+ #
395
+ # @param [String] str 日付文字列
396
+ # @param [Symbol] type 日付種別
397
+ #
398
+ # @return [True] 正しい
399
+ # @return [True] 正しくない
400
+ #
401
+ def self.valid_date_string(str: '', type: Type::DEFAULT)
402
+ start = DATE_START.fetch(type, DATE_START[Type::DEFAULT])
403
+ begin
404
+ Date.parse(str, start)
405
+ rescue ArgumentError => _e
406
+ false
407
+ end
408
+ true
409
+ end
410
+ end
411
+ end
412
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './version_factory'
4
+ require_relative './condition'
5
+
6
+ # :nodoc:
7
+ module Zakuro
8
+ #
9
+ # Merchant ざくろ商人
10
+ # 東西の暦を取引する
11
+ #
12
+ class Merchant
13
+ # @return [Hash<Symbol, Object>] 条件
14
+ attr_reader :condition
15
+
16
+ #
17
+ # 初期化
18
+ #
19
+ # @param [Hash<Symbol, Object>] condition 条件
20
+ #
21
+ def initialize(condition: {})
22
+ failed = Condition.validate(hash: condition)
23
+ raise ZakuroError, failed.join('\n') unless failed.empty?
24
+
25
+ @condition = Condition.new(hash: condition)
26
+ end
27
+
28
+ #
29
+ # 条件提示する
30
+ #
31
+ # @param [Hash<Symbol, Object>] condition 条件
32
+ #
33
+ # @return [Merchant] 自インスタンス
34
+ #
35
+ def offer(condition: {})
36
+ failed = Condition.validate(hash: condition)
37
+ raise ZakuroError, failed.join('\n') unless failed.empty?
38
+
39
+ @condition.rewrite(hash: condition)
40
+
41
+ self
42
+ end
43
+
44
+ #
45
+ # 承諾する
46
+ #
47
+ # @return [Result::SingleDay] 和暦日
48
+ #
49
+ def commit
50
+ date = condition.date
51
+ return VersionFactory.to_japan_date(western_date: date) if date
52
+
53
+ # TODO: does not have no patterns now
54
+ {}
55
+ end
56
+ end
57
+ end