zakuro 0.0.0

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