zakuro 0.0.0 → 0.1.1

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