zakuro 0.0.0 → 0.1.1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +4 -0
  3. data/.gitignore +7 -1
  4. data/.rubocop.yml +3 -0
  5. data/Gemfile +2 -0
  6. data/Makefile +2 -0
  7. data/README.md +156 -10
  8. data/Rakefile +1 -1
  9. data/doc/gengou.md +315 -0
  10. data/doc/operation.md +25 -0
  11. data/doc/operation/csv/month.csv +202 -0
  12. data/doc/operation/operation.xlsx +0 -0
  13. data/doc/operation/transfer.rb +77 -0
  14. data/lib/zakuro/condition.rb +19 -15
  15. data/lib/zakuro/cycle/abstract_remainder.rb +3 -4
  16. data/lib/zakuro/era/japan/gengou.rb +106 -0
  17. data/lib/zakuro/era/japan/gengou/parser.rb +167 -0
  18. data/lib/zakuro/era/japan/gengou/type.rb +178 -0
  19. data/lib/zakuro/era/japan/gengou/validator.rb +236 -0
  20. data/lib/zakuro/era/japan/reki.rb +91 -0
  21. data/lib/zakuro/era/japan/yaml/set-001-until-south.yaml +1121 -0
  22. data/lib/zakuro/era/japan/yaml/set-002-from-north.yaml +485 -0
  23. data/lib/zakuro/era/japan/yaml/set-003-modern.yaml +28 -0
  24. data/lib/zakuro/era/western.rb +11 -1
  25. data/lib/zakuro/merchant.rb +3 -1
  26. data/lib/zakuro/operation/month/parser.rb +373 -0
  27. data/lib/zakuro/operation/month/type.rb +458 -0
  28. data/lib/zakuro/operation/month/validator.rb +802 -0
  29. data/lib/zakuro/operation/operation.rb +66 -0
  30. data/lib/zakuro/operation/yaml/month.yaml +6452 -0
  31. data/lib/zakuro/output/error.rb +2 -0
  32. data/lib/zakuro/output/logger.rb +2 -0
  33. data/lib/zakuro/output/response.rb +21 -19
  34. data/lib/zakuro/result/core.rb +52 -0
  35. data/lib/zakuro/result/data.rb +187 -0
  36. data/lib/zakuro/result/operation.rb +114 -0
  37. data/lib/zakuro/result/result.rb +37 -0
  38. data/lib/zakuro/{output → tools}/stringifier.rb +16 -9
  39. data/lib/zakuro/tools/typeof.rb +33 -0
  40. data/lib/zakuro/version.rb +1 -1
  41. data/lib/zakuro/version/senmyou/README.md +3 -1
  42. data/lib/zakuro/version/senmyou/base/era.rb +3 -1
  43. data/lib/zakuro/version/senmyou/base/multi_gengou.rb +98 -0
  44. data/lib/zakuro/version/senmyou/base/multi_gengou_roller.rb +217 -0
  45. data/lib/zakuro/version/senmyou/base/remainder.rb +4 -4
  46. data/lib/zakuro/version/senmyou/base/solar_term.rb +20 -0
  47. data/lib/zakuro/version/senmyou/base/year.rb +52 -6
  48. data/lib/zakuro/version/senmyou/monthly/first_day.rb +44 -0
  49. data/lib/zakuro/version/senmyou/monthly/initialized_month.rb +48 -0
  50. data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +1 -1
  51. data/lib/zakuro/version/senmyou/monthly/month.rb +136 -67
  52. data/lib/zakuro/version/senmyou/monthly/month_label.rb +87 -0
  53. data/lib/zakuro/version/senmyou/monthly/operated_month.rb +167 -0
  54. data/lib/zakuro/version/senmyou/{summary/annual_data.rb → range/annual_range.rb} +38 -40
  55. data/lib/zakuro/version/senmyou/range/full_range.rb +324 -0
  56. data/lib/zakuro/version/senmyou/range/operated_range.rb +126 -0
  57. data/lib/zakuro/version/senmyou/range/operated_solar_terms.rb +181 -0
  58. data/lib/zakuro/version/senmyou/senmyou.rb +2 -2
  59. data/lib/zakuro/version/senmyou/specifier/single_day_specifier.rb +102 -0
  60. data/lib/zakuro/version/senmyou/stella/lunar_orbit.rb +1 -1
  61. data/lib/zakuro/version/senmyou/stella/solar_average.rb +54 -32
  62. data/lib/zakuro/version/senmyou/stella/solar_orbit.rb +3 -7
  63. data/lib/zakuro/version/senmyou/summary/single.rb +125 -0
  64. data/lib/zakuro/version_factory.rb +1 -1
  65. metadata +40 -13
  66. data/.travis.yml +0 -6
  67. data/lib/zakuro/era/gengou/set-001-until-south.yaml +0 -375
  68. data/lib/zakuro/era/gengou/set-002-from-north.yaml +0 -166
  69. data/lib/zakuro/era/gengou/set-003-modern.yaml +0 -12
  70. data/lib/zakuro/era/japan.rb +0 -630
  71. data/lib/zakuro/output/result.rb +0 -219
  72. data/lib/zakuro/version/senmyou/base/gengou.rb +0 -210
  73. data/lib/zakuro/version/senmyou/summary/gengou_data.rb +0 -294
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: moduleでMonthly とする(全暦むけに共通化したあと)
4
+
5
+ # :nodoc:
6
+ module Zakuro
7
+ # :nodoc:
8
+ module Senmyou
9
+ #
10
+ # MonthLabel 月表示情報
11
+ #
12
+ class MonthLabel
13
+ # @return [True] 大の月(30日)
14
+ # @return [False] 小の月(29日)
15
+ attr_reader :is_many_days
16
+ # @return [Integer] 月(xx月のxx)
17
+ attr_reader :number
18
+ # @return [True] 閏月
19
+ # @return [False] 平月
20
+ attr_reader :leaped
21
+
22
+ # :reek:ControlParameter and :reek:BooleanParameter
23
+
24
+ #
25
+ # 初期化
26
+ #
27
+ # @param [Integer] number 月(xx月のxx)
28
+ # @param [True, False] is_many_days 月の大小
29
+ # @param [True, False] leaped 閏月/平月
30
+ #
31
+ def initialize(number: -1, is_many_days: false, leaped: false)
32
+ # 月の大小
33
+ @is_many_days = is_many_days
34
+ # 月
35
+ @number = number
36
+ # 閏
37
+ @leaped = leaped
38
+ end
39
+
40
+ #
41
+ # 月の日数を返す
42
+ #
43
+ # @return [Integer] 日数
44
+ #
45
+ def days
46
+ @is_many_days ? 30 : 29
47
+ end
48
+
49
+ #
50
+ # 月の名前(大小)を返す
51
+ #
52
+ # @return [String] 月の名前(大小)
53
+ #
54
+ def days_name
55
+ @is_many_days ? '大' : '小'
56
+ end
57
+
58
+ #
59
+ # 一ヶ月戻す
60
+ #
61
+ # @return [True] 昨年
62
+ # @return [False] 今年
63
+ #
64
+ def back_to_last_month
65
+ @number -= 1
66
+
67
+ return false if @number.positive?
68
+
69
+ @number = 12
70
+
71
+ true
72
+ end
73
+
74
+ #
75
+ # 同一の月情報かを検証する
76
+ #
77
+ # @param [Month] other 他の月情報
78
+ #
79
+ # @return [True] 同一の月
80
+ # @return [False] 異なる月
81
+ #
82
+ def same?(other:)
83
+ @number == other.number && @leaped == other.leaped
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './month'
4
+ require_relative '../../../operation/operation'
5
+
6
+ # :nodoc:
7
+ module Zakuro
8
+ # :nodoc:
9
+ module Senmyou
10
+ #
11
+ # OperatedMonth 月情報(運用)
12
+ #
13
+ class OperatedMonth < Month
14
+ # @return [Operation::MonthHistory] 変更履歴(月)
15
+ attr_reader :history
16
+ # @return [OperatedSolarTerms] 運用時二十四節気
17
+ attr_reader :operated_solar_terms
18
+
19
+ #
20
+ # 初期化
21
+ #
22
+ # @param [MonthLabel] month_label 月表示名
23
+ # @param [FirstDay] first_day 月初日(朔日)
24
+ # @param [Array<SolarTerm>] solar_terms 二十四節気
25
+ # @param [Operation::MonthHistory] history 変更履歴(月)
26
+ #
27
+ def initialize(operated_solar_terms:, month_label: MonthLabel.new, first_day: FirstDay.new, solar_terms: [],
28
+ history: Operation::MonthHistory.new)
29
+ super(month_label: month_label, first_day: first_day, solar_terms: solar_terms)
30
+ @history = history
31
+ @operated_solar_terms = operated_solar_terms
32
+ end
33
+
34
+ #
35
+ # 書き換える
36
+ #
37
+ def rewrite
38
+ rewrite_month
39
+ rewrite_solar_terms
40
+ rewrite_first_day
41
+ end
42
+
43
+ #
44
+ # 月ごとの差分で書き換える
45
+ #
46
+ def rewrite_month
47
+ diff = history.diffs.month
48
+
49
+ @month_label = MonthLabel.new(
50
+ number: rewrite_number(diff: diff.number),
51
+ is_many_days: rewrite_many_days(diff: diff.days),
52
+ leaped: rewrite_leaped(diff: diff.leaped)
53
+ )
54
+ end
55
+
56
+ #
57
+ # 月ごとの差分(月)で書き換える
58
+ #
59
+ # @param [Operation::Number] diff 差分
60
+ #
61
+ # @return [Integer] 月
62
+ #
63
+ def rewrite_number(diff:)
64
+ return month_label.number if diff.invalid?
65
+
66
+ diff.actual
67
+ end
68
+
69
+ #
70
+ # 月ごとの差分(月の大小)で書き換える
71
+ #
72
+ # @param [Operation::Days] diff 差分
73
+ #
74
+ # @return [Integer] 月の大小
75
+ #
76
+ def rewrite_many_days(diff:)
77
+ return month_label.is_many_days if diff.invalid?
78
+
79
+ diff.many_days_actual?
80
+ end
81
+
82
+ #
83
+ # 月ごとの差分(閏有無)で書き換える
84
+ #
85
+ # @param [Operation::Days] diff 差分
86
+ #
87
+ # @return [True] 閏あり
88
+ # @return [False] 閏なし
89
+ #
90
+ def rewrite_leaped(diff:)
91
+ return month_label.leaped if diff.invalid?
92
+
93
+ diff.actual
94
+ end
95
+
96
+ #
97
+ # 二十四節気ごとの差分で書き換える
98
+ #
99
+ def rewrite_solar_terms
100
+ # TODO: リファクタリング
101
+ operated_solar_terms = []
102
+ matched, operated_solar_term = @operated_solar_terms.get(
103
+ western_date: @first_day.western_date
104
+ )
105
+
106
+ return unless matched
107
+
108
+ used = false
109
+ @solar_terms.each do |solar_term|
110
+ if operated_solar_term.index == solar_term.index
111
+ used = true
112
+ next
113
+ end
114
+
115
+ operated_solar_terms.push(solar_term)
116
+ end
117
+
118
+ operated_solar_terms.push(operated_solar_term) unless used
119
+
120
+ @solar_terms = operated_solar_terms
121
+ end
122
+
123
+ #
124
+ # 月初日ごとの差分で書き換える
125
+ #
126
+ def rewrite_first_day
127
+ diffs = @history.diffs
128
+ return if diffs.invalid_days?
129
+
130
+ days = diffs.days
131
+
132
+ @first_day = FirstDay.new(
133
+ western_date: rewrite_western_date(days: days),
134
+ remainder: rewrite_remainder(days: days)
135
+ )
136
+ end
137
+
138
+ #
139
+ # 月初日の大余小余を日差分で書き換える
140
+ #
141
+ # @param [Integer] days 日差分
142
+ #
143
+ # @return [Remainder] 月初日の大余小余
144
+ #
145
+ def rewrite_remainder(days:)
146
+ remainder = @first_day.remainder.clone
147
+ remainder.add!(Remainder.new(day: days, minute: 0, second: 0))
148
+
149
+ remainder
150
+ end
151
+
152
+ #
153
+ # 月初日の西暦日を日差分で書き換える
154
+ #
155
+ # @param [Integer] days 日差分
156
+ #
157
+ # @return [Western::Calendar] 月初日の西暦日
158
+ #
159
+ def rewrite_western_date(days:)
160
+ western_date = @first_day.western_date.clone
161
+ western_date += days
162
+
163
+ western_date
164
+ end
165
+ end
166
+ end
167
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative '../../../output/logger'
4
4
  require_relative '../base/remainder'
5
- require_relative '../monthly/month'
5
+ require_relative '../monthly/initialized_month'
6
6
  require_relative '../base/solar_term'
7
7
  require_relative '../monthly/lunar_phase'
8
8
  require_relative '../stella/solar_orbit'
@@ -13,10 +13,12 @@ require_relative '../stella/lunar_orbit'
13
13
  module Zakuro
14
14
  # :nodoc:
15
15
  module Senmyou
16
- # AnnualData 年間データ
17
- module AnnualData
16
+ #
17
+ # AnnualRange 年間範囲
18
+ #
19
+ module AnnualRange
18
20
  # @return [Logger] ロガー
19
- LOGGER = Logger.new(location: 'annual_data')
21
+ LOGGER = Logger.new(location: 'annual_range')
20
22
 
21
23
  # :reek:TooManyStatements { max_statements: 6 }
22
24
 
@@ -61,20 +63,20 @@ module Zakuro
61
63
  #
62
64
  # @return [Array<Month>] 1年データ
63
65
  #
64
- def self.collect_annual_data_after_last_november_1st(western_year:)
65
- annual_data = initialized_annual_data(western_year: western_year)
66
+ def self.collect_annual_range_after_last_november_1st(western_year:)
67
+ annual_range = initialized_annual_range(western_year: western_year)
66
68
 
67
- apply_big_and_small_of_the_month(annual_data: annual_data)
69
+ apply_big_and_small_of_the_month(annual_range: annual_range)
68
70
 
69
- SolarAverage.set_solar_terms_into_annual_data(western_year: western_year,
70
- annual_data: annual_data)
71
+ SolarAverage.set_solar_terms_into_annual_range(western_year: western_year,
72
+ annual_range: annual_range)
71
73
 
72
74
  # 月間隔を取得するためだけの末尾要素を削除
73
- annual_data.pop
75
+ annual_range.pop
74
76
 
75
- adjust_leap_month(annual_data: annual_data)
77
+ adjust_leap_month(annual_range: annual_range)
76
78
 
77
- annual_data
79
+ annual_range
78
80
  end
79
81
 
80
82
  #
@@ -112,7 +114,7 @@ module Zakuro
112
114
  #
113
115
  # @return [Array<Month>] 1年データ
114
116
  #
115
- def self.initialized_annual_data(western_year:)
117
+ def self.initialized_annual_range(western_year:)
116
118
  result = []
117
119
  lunar_phase = LunarPhase.new(western_year: western_year)
118
120
 
@@ -126,29 +128,28 @@ module Zakuro
126
128
  adjusted = lunar_phase.next_month
127
129
 
128
130
  result.push(
129
- Month.new(is_last_year: is_last_year, number: month,
130
- remainder: adjusted, phase_index: 0)
131
+ InitializedMonth.new(month_label: MonthLabel.new(number: month),
132
+ first_day: FirstDay.new(remainder: adjusted),
133
+ is_last_year: is_last_year, phase_index: 0)
131
134
  )
132
135
  is_last_year = false if month == 12
133
136
  end
134
137
  result
135
138
  end
136
- private_class_method :initialized_annual_data
139
+ private_class_method :initialized_annual_range
137
140
 
138
141
  #
139
142
  # 1年データの各月に月の大小を設定する
140
143
  #
141
- # @param [Array<Month>] annual_data 1年データ
142
- #
143
- def self.apply_big_and_small_of_the_month(annual_data:)
144
- size = annual_data.size - 1
145
- (0...size).each do |idx|
146
- current_month = annual_data[idx]
147
- next_month = annual_data[idx + 1]
148
- current_month.is_many_days = \
149
- current_month.remainder.same_remainder_divided_by_ten?(
150
- other: next_month.remainder.day
151
- )
144
+ # @param [Array<Month>] annual_range 1年データ
145
+ #
146
+ def self.apply_big_and_small_of_the_month(annual_range:)
147
+ annual_range.each_with_index do |range, index|
148
+ # 最後は比較対象がないためスキップする(=計算外の余分な月が最後に必要である)
149
+ next if index == annual_range.size - 1
150
+
151
+ next_month = annual_range[index + 1]
152
+ range.eval_many_days(next_month_day: next_month.remainder.day)
152
153
  end
153
154
  end
154
155
  private_class_method :apply_big_and_small_of_the_month
@@ -159,25 +160,22 @@ module Zakuro
159
160
  # 閏月が存在した場合に以降の月を1つずつ減らす
160
161
  # @example 7,8,9 と続く月の8月が閏の場合、7, 閏7, 8 となる
161
162
  #
162
- # @param [Array<Month>] annual_data 1年データ
163
+ # @param [Array<Month>] annual_range 1年データ
163
164
  #
164
- def self.adjust_leap_month(annual_data:)
165
+ def self.adjust_leap_month(annual_range:)
165
166
  # 閏による月の再調整を行う
166
167
  leaped = false
167
- annual_data.each do |month|
168
- if month.even_term.invalid?
169
- month.leaped = true
170
- leaped = true
171
- end
168
+ annual_range.each_with_index do |month, index|
169
+ month.eval_leaped
170
+ # NOTE: 初回閏月(閏11月)は前回月が存在しないため調整外
171
+ leaped = true if month.leaped? && !index.zero?
172
+
172
173
  next unless leaped
173
174
 
174
175
  # NOTE: 常気法では閏月は2-3年に一度のため、1年に二度発生しない前提
175
- number = month.number - 1
176
- if number <= 0
177
- month.is_last_year = true
178
- number = 12
179
- end
180
- month.number = number
176
+
177
+ # 閏の分だけ1ヶ月ずらす
178
+ month.back_to_last_month
181
179
  end
182
180
  end
183
181
  private_class_method :adjust_leap_month
@@ -0,0 +1,324 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base/multi_gengou_roller'
4
+
5
+ require_relative '../../../era/western'
6
+ require_relative './annual_range'
7
+
8
+ require_relative '../base/year'
9
+
10
+ # :nodoc:
11
+ module Zakuro
12
+ # :nodoc:
13
+ module Senmyou
14
+ # FullRange 完全範囲
15
+ # ある日からある日の範囲を計算可能な年月範囲
16
+ # * 前提として元号年はその元号の開始年から数える
17
+ # * ある日の元号年を求める場合、その元号が含まれる最初の年まで遡る
18
+ # * 元号は一つとは限らない。南北朝などで二つある場合は、古い方の元号から求める
19
+ #
20
+ # NOTE: 割り当てた元号は年初を基準にした元号年である
21
+ # * 元旦を基準にした時の正しい元号を設定している
22
+ # * 引き当てたい日付が元旦ではない場合、その月日に従い元号を再度求める
23
+ # * この再計算が必要になるのは、元号が切り替わる年のみである
24
+ class FullRange
25
+ # @return [Western::Calendar] 開始日
26
+ attr_reader :start_date
27
+ # @return [Western::Calendar] 終了日
28
+ attr_reader :end_date
29
+ # @return [MultiGengouRoller] 改元処理
30
+ attr_reader :multi_gengou_roller
31
+ # @return [Western::Calendar] 最過去の元旦
32
+ attr_reader :new_year_date
33
+ # @return [Integer] 西暦年
34
+ attr_reader :western_year
35
+
36
+ # @return [Logger] ロガー
37
+ LOGGER = Logger.new(location: 'full_range')
38
+
39
+ #
40
+ # 初期化
41
+ #
42
+ # @param [Western::Calendar] start_date 開始日
43
+ # @param [Western::Calendar] end_date 終了日
44
+ #
45
+ def initialize(start_date: Western::Calendar.new, end_date: Western::Calendar.new)
46
+ @start_date = start_date
47
+ @end_date = end_date
48
+ return if invalid?
49
+
50
+ @multi_gengou_roller = MultiGengouRoller.new(start_date: start_date, end_date: end_date)
51
+ @new_year_date = @multi_gengou_roller.oldest_date.clone
52
+ @western_year = @new_year_date.year
53
+ end
54
+
55
+ #
56
+ # 無効か
57
+ #
58
+ # @return [True] 無効
59
+ # @return [False] 有効
60
+ #
61
+ def invalid?
62
+ @start_date.invalid?
63
+ end
64
+
65
+ #
66
+ # 完全範囲を取得する
67
+ #
68
+ # @return [Array<Year>] 完全範囲
69
+ #
70
+ def get
71
+ return [] if invalid?
72
+
73
+ pre_get
74
+
75
+ years = FullRange.rearranged_years(annual_ranges: annual_ranges)
76
+ years = update_gengou(years: years)
77
+ years = update_first_day(years: years)
78
+
79
+ post_get
80
+
81
+ years
82
+ end
83
+
84
+ #
85
+ # 取得前処理
86
+ #
87
+ def pre_get
88
+ # FIXME: 別インスタンス変数を定義する方法は改善したい(ディープコピーにするか、get再取得を廃止するか)
89
+ @new_year_date_ = @new_year_date.clone
90
+ @multi_gengou_roller_ = @multi_gengou_roller.clone
91
+ end
92
+
93
+ #
94
+ # 取得前処理
95
+ #
96
+ # 再取得に備えて、カウントアップした日付を元に戻す
97
+ #
98
+ def post_get
99
+ @new_year_date = @new_year_date_
100
+ @multi_gengou_roller = @multi_gengou_roller_
101
+ end
102
+
103
+ # :reek:TooManyStatements { max_statements: 6 }
104
+
105
+ #
106
+ # 完全範囲内の年データを取得する
107
+ #
108
+ # @return [Array<Year>] 年データ(冬至基準)
109
+ #
110
+ def annual_ranges
111
+ oldest_date = @new_year_date
112
+ newest_date = @multi_gengou_roller.newest_date
113
+
114
+ years = []
115
+ ((oldest_date.year)..(newest_date.year + 2)).each do |year|
116
+ years.push(
117
+ AnnualRange.collect_annual_range_after_last_november_1st(
118
+ western_year: year
119
+ )
120
+ )
121
+ end
122
+
123
+ years
124
+ end
125
+
126
+ #
127
+ # 完全範囲内の年データの開始月を変更する
128
+ #
129
+ # @param [Array<Year>] annual_ranges 年データ(冬至基準)
130
+ #
131
+ # @return [Array<Year>] 年データ(元旦基準)
132
+ #
133
+ def self.rearranged_years(annual_ranges:)
134
+ years = []
135
+
136
+ (0..(annual_ranges.size - 2)).each do |index|
137
+ year = rearranged_year(annual_ranges: annual_ranges, index: index)
138
+ years.push(year)
139
+ end
140
+
141
+ years
142
+ end
143
+
144
+ # :reek:TooManyStatements { max_statements: 8 }
145
+
146
+ #
147
+ # 完全範囲内の年データの元号を開始年基準で更新する
148
+ #
149
+ # @param [Array<Year>] years 年データ(元旦基準)
150
+ #
151
+ # @return [Array<Year>] 元号更新済み年データ(元旦基準)
152
+ #
153
+ def update_gengou(years:)
154
+ updated_years = []
155
+
156
+ nearest_end_date = choise_nearest_end_date
157
+
158
+ years.each do |year|
159
+ next_year(years: updated_years, year: year)
160
+
161
+ if @new_year_date > nearest_end_date
162
+ @multi_gengou_roller.transfer
163
+ nearest_end_date = choise_nearest_end_date
164
+ end
165
+ @multi_gengou_roller.next_year
166
+ end
167
+
168
+ updated_years
169
+ end
170
+
171
+ #
172
+ # 月初日の西暦日を更新する
173
+ #
174
+ # @param [Array<Year>] years 完全範囲(月初日なし)
175
+ #
176
+ # @return [Array<Year>] 完全範囲(月初日あり)
177
+ #
178
+ def update_first_day(years:)
179
+ # TODO: リファクタリング
180
+
181
+ result = []
182
+
183
+ years.each do |year|
184
+ new_year_date = year.new_year_date.clone
185
+ date = new_year_date.clone
186
+
187
+ months = []
188
+ year.months.each do |month|
189
+ first_day = month.first_day
190
+ updated_month = Month.new(
191
+ month_label: month.month_label,
192
+ first_day: FirstDay.new(remainder: first_day.remainder,
193
+ western_date: date),
194
+ solar_terms: month.solar_terms
195
+ )
196
+ months.push(updated_month)
197
+
198
+ date = date.clone + updated_month.days
199
+ end
200
+
201
+ updated_year = Year.new(
202
+ multi_gengou: year.multi_gengou, new_year_date: new_year_date,
203
+ months: months, total_days: year.total_days
204
+ )
205
+
206
+ result.push(updated_year)
207
+ end
208
+
209
+ result
210
+ end
211
+
212
+ #
213
+ # 当年データを生成する
214
+ #
215
+ # @param [Array<Year>] annual_ranges 年データ(冬至基準)
216
+ # @param [Year] year 対象年
217
+ #
218
+ # @return [Year] 当年月ありの対象年
219
+ #
220
+ def self.push_current_year(annual_range:, year: Year.new)
221
+ annual_range.each do |month|
222
+ next if month.is_last_year
223
+
224
+ year.push(month: month)
225
+ end
226
+
227
+ year
228
+ end
229
+
230
+ #
231
+ # 昨年データを生成する
232
+ #
233
+ # @param [Array<Year>] annual_ranges 年データ(冬至基準)
234
+ # @param [Year] year 対象年
235
+ #
236
+ # @return [Year] 昨年月ありの対象年
237
+ #
238
+ def self.push_last_year(annual_range:, year: Year.new)
239
+ annual_range.each do |month|
240
+ next unless month.is_last_year
241
+
242
+ year.push(month: month)
243
+ end
244
+
245
+ year
246
+ end
247
+
248
+ #
249
+ # 年データの開始月を変更する
250
+ #
251
+ # @param [Array<Year>] annual_ranges 年データ(冬至基準)
252
+ # @param [Integer] index 対象年の要素番号
253
+ #
254
+ # @return [Year] 年データ(元旦基準)
255
+ #
256
+ def self.rearranged_year(annual_ranges:, index:)
257
+ current_annual_range = annual_ranges[index]
258
+ next_annual_range = annual_ranges[index + 1]
259
+
260
+ year = push_current_year(annual_range: current_annual_range)
261
+ push_last_year(annual_range: next_annual_range, year: year)
262
+
263
+ year
264
+ end
265
+ private_class_method :rearranged_year
266
+
267
+ private
268
+
269
+ #
270
+ # 元号処理対象の年を進める
271
+ #
272
+ # @param [Array<Year>] years 元号処理済み年データ(元旦基準)
273
+ # @param [Year] year 元号処理前の年(元旦基準)
274
+ #
275
+ def next_year(years:, year:)
276
+ updated_year = update_year(year: year)
277
+
278
+ years.push(updated_year)
279
+
280
+ next_new_year_date(total_days: updated_year.total_days)
281
+
282
+ nil
283
+ end
284
+
285
+ #
286
+ # 年の元号を更新する
287
+ #
288
+ # @param [Year] year 元号処理前の年(元旦基準)
289
+ #
290
+ # @return [Year] 元号処理済の年(元旦基準)
291
+ #
292
+ def update_year(year:)
293
+ multi_gengou = @multi_gengou_roller.multi_gengou.clone
294
+
295
+ updated_year = Year.new(multi_gengou: multi_gengou, new_year_date: @new_year_date.clone,
296
+ months: year.months)
297
+ updated_year.commit
298
+
299
+ updated_year
300
+ end
301
+
302
+ #
303
+ # 次の年に進める
304
+ #
305
+ # @param [Integer] total_days 年の日数
306
+ #
307
+ def next_new_year_date(total_days:)
308
+ @new_year_date += total_days
309
+ @multi_gengou_roller.next(days: total_days)
310
+
311
+ nil
312
+ end
313
+
314
+ #
315
+ # 現在日からみて直近の未来に対する元号の切替前日を求める
316
+ #
317
+ # @return [Western::Calendar] 元号の切替前日
318
+ #
319
+ def choise_nearest_end_date
320
+ @multi_gengou_roller.choise_nearest_end_date
321
+ end
322
+ end
323
+ end
324
+ end