zakuro 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './era'
4
+
3
5
  # :nodoc:
4
6
  module Zakuro
5
7
  # :nodoc:
@@ -9,18 +11,63 @@ module Zakuro
9
11
  #
10
12
  class Year
11
13
  # @return [Gengou] 元号
12
- attr_reader :gengou
14
+ attr_reader :multi_gengou
13
15
  # @return [Array<Month>] 年内の全ての月
14
16
  attr_reader :months
17
+ # @return [Integer] 年の日数
18
+ attr_reader :total_days
19
+ # @return [Western::Calendar] 元旦
20
+ attr_reader :new_year_date
15
21
 
16
22
  #
17
23
  # 初期化
18
24
  #
19
- # @param [Gengou] gengou 元号
25
+ # @param [Gengou] multi_gengou 元号
26
+ #
27
+ def initialize(multi_gengou: MultiGengou.new, new_year_date: Western::Calendar.new,
28
+ months: [], total_days: 0)
29
+ @multi_gengou = multi_gengou
30
+ @months = months
31
+ @new_year_date = new_year_date
32
+ @total_days = total_days
33
+ end
34
+
35
+ #
36
+ # 年の日数を確定する
37
+ #
38
+ def commit
39
+ @total_days = 0
40
+ months.each do |month|
41
+ @total_days += month.days
42
+ end
43
+
44
+ self
45
+ end
46
+
47
+ #
48
+ # 次年にする
49
+ #
50
+ # @param [Japan::Gengou] first_line 元号(1行目)
51
+ # @param [Japan::Gengou] second_line 元号(2行目)
52
+ #
53
+ # @return [MultiGengou] 自身
54
+ #
55
+ def next_year
56
+ @multi_gengou.next_year
57
+
58
+ @new_year_date += @total_days
59
+ @total_days = 0
60
+
61
+ self
62
+ end
63
+
64
+ #
65
+ # 十干十二支を取得する
66
+ #
67
+ # @return [String] 十干十二支
20
68
  #
21
- def initialize(gengou:)
22
- @gengou = gengou
23
- @months = []
69
+ def zodiac_name
70
+ Era.zodiac_name(western_year: @new_year_date.year)
24
71
  end
25
72
 
26
73
  #
@@ -32,7 +79,6 @@ module Zakuro
32
79
  return if duplicated?(month: month)
33
80
 
34
81
  @months.push(month)
35
- @gengou.add_days(days: month.days)
36
82
 
37
83
  nil
38
84
  end
@@ -96,6 +96,16 @@ module Zakuro
96
96
  @number == other.number && @leaped == other.leaped
97
97
  end
98
98
 
99
+ #
100
+ # 二十四節気が未設定かどうかを検証する
101
+ #
102
+ # @return [True] 設定なし
103
+ # @return [False] 設定あり
104
+ #
105
+ def empty_solar_term?
106
+ @even_term.invalid? && @odd_term.invalid?
107
+ end
108
+
99
109
  #
100
110
  # 文字化する
101
111
  #
@@ -3,7 +3,7 @@
3
3
  require 'date'
4
4
  require_relative '../abstract_version'
5
5
  require_relative '../../era/western'
6
- require_relative 'summary/gengou_data'
6
+ require_relative 'summary/specifier'
7
7
 
8
8
  # :nodoc:
9
9
  module Zakuro
@@ -27,7 +27,7 @@ module Zakuro
27
27
  #
28
28
  def self.to_japan_date(western_date:)
29
29
  date = Western::Calendar.create(date: western_date)
30
- GengouData.get_ancient_date(date: date)
30
+ SingleDaySpecifier.get(date: date)
31
31
  end
32
32
  end
33
33
  end
@@ -17,11 +17,11 @@ module Zakuro
17
17
  # 冬至から数えた1年データの月ごとに二十四節気を割り当てる
18
18
  #
19
19
  # @param [Integer] western_year 西暦年
20
- # @param [Array<Month>] annual_data 1年データ
20
+ # @param [Array<Month>] annual_range 1年データ
21
21
  #
22
22
  # @return [Array<Month>] 1年データ
23
23
  #
24
- def self.set_solar_terms_into_annual_data(western_year:, annual_data:)
24
+ def self.set_solar_terms_into_annual_range(western_year:, annual_range:)
25
25
  # 天正冬至
26
26
  winter_solstice = WinterSolstice.calc(western_year: western_year)
27
27
 
@@ -30,17 +30,17 @@ module Zakuro
30
30
  winter_solstice: winter_solstice
31
31
  )
32
32
 
33
- apply_solar_terms_from_last_winter_solstice(annual_data: annual_data,
33
+ apply_solar_terms_from_last_winter_solstice(annual_range: annual_range,
34
34
  solar_terms: solar_terms)
35
35
 
36
36
  # 前後の二十四節気
37
37
  rest_solar_terms = \
38
38
  collect_solar_terms_before_and_after(solar_terms: solar_terms)
39
39
 
40
- apply_solar_terms_before_and_after(annual_data: annual_data,
40
+ apply_solar_terms_before_and_after(annual_range: annual_range,
41
41
  rest_solar_terms: rest_solar_terms)
42
42
 
43
- annual_data
43
+ annual_range
44
44
  end
45
45
 
46
46
  # :reek:TooManyStatements { max_statements: 6 }
@@ -69,16 +69,21 @@ module Zakuro
69
69
  #
70
70
  # 各月の二十四節気を設定する
71
71
  #
72
- # @param [Array<Month>] annual_data 1年データ
72
+ # @param [Array<Month>] annual_range 1年データ
73
73
  # @param [Array<Remainder>] solar_terms 1年データ内の全二十四節気
74
74
  #
75
- def self.apply_solar_terms_from_last_winter_solstice(annual_data:,
75
+ def self.apply_solar_terms_from_last_winter_solstice(annual_range:,
76
76
  solar_terms:)
77
+
77
78
  c_idx = 0
78
79
  st_idx = 0
79
- while c_idx < annual_data.size && st_idx < solar_terms.size
80
- current_month = annual_data[c_idx]
81
- next_month = annual_data[c_idx + 1]
80
+ month_size = annual_range.size
81
+
82
+ while c_idx < month_size && st_idx < solar_terms.size
83
+ raise StandardError, "month is over. idx: #{c_idx}" if c_idx >= month_size
84
+
85
+ current_month = annual_range[c_idx]
86
+ next_month = annual_range[c_idx + 1]
82
87
  solar_term = solar_terms[st_idx]
83
88
 
84
89
  if in_range_solar_term?(target: solar_term, min: current_month.remainder,
@@ -88,6 +93,13 @@ module Zakuro
88
93
  st_idx += 1
89
94
  next
90
95
  end
96
+
97
+ # 一度も割り当てがない場合は二十四節気を進める
98
+ if current_month.empty_solar_term?
99
+ st_idx += 1
100
+ next
101
+ end
102
+
91
103
  c_idx += 1
92
104
  end
93
105
  end
@@ -120,18 +132,18 @@ module Zakuro
120
132
  #
121
133
  # 1年データ前後の二十四節気を適用する
122
134
  #
123
- # @param [Array<Month>] annual_data 1年データ
135
+ # @param [Array<Month>] annual_range 1年データ
124
136
  # @param [Hash<Integer, Hash<Symbol, Integer>>, Hash<Integer, Hash<Symbol, Remainder>>]
125
137
  # rest_solar_terms 前後
126
138
  #
127
- def self.apply_solar_terms_before_and_after(annual_data:, rest_solar_terms:)
139
+ def self.apply_solar_terms_before_and_after(annual_range:, rest_solar_terms:)
128
140
  rest_solar_terms.each do |key, value|
129
141
  index = value[:index]
130
142
  solar_term = value[:solar_term]
131
- data = annual_data[index]
143
+ data = annual_range[index]
132
144
  next unless in_range_solar_term?(
133
145
  target: solar_term,
134
- min: data.remainder, max: annual_data[index + 1].remainder
146
+ min: data.remainder, max: annual_range[index + 1].remainder
135
147
  )
136
148
 
137
149
  set_solar_term(month: data,
@@ -13,10 +13,10 @@ require_relative '../stella/lunar_orbit'
13
13
  module Zakuro
14
14
  # :nodoc:
15
15
  module Senmyou
16
- # AnnualData 年間データ
17
- module AnnualData
16
+ # AnnualRange 年間データ
17
+ module AnnualRange
18
18
  # @return [Logger] ロガー
19
- LOGGER = Logger.new(location: 'annual_data')
19
+ LOGGER = Logger.new(location: 'annual_range')
20
20
 
21
21
  # :reek:TooManyStatements { max_statements: 6 }
22
22
 
@@ -61,20 +61,20 @@ module Zakuro
61
61
  #
62
62
  # @return [Array<Month>] 1年データ
63
63
  #
64
- def self.collect_annual_data_after_last_november_1st(western_year:)
65
- annual_data = initialized_annual_data(western_year: western_year)
64
+ def self.collect_annual_range_after_last_november_1st(western_year:)
65
+ annual_range = initialized_annual_range(western_year: western_year)
66
66
 
67
- apply_big_and_small_of_the_month(annual_data: annual_data)
67
+ apply_big_and_small_of_the_month(annual_range: annual_range)
68
68
 
69
- SolarAverage.set_solar_terms_into_annual_data(western_year: western_year,
70
- annual_data: annual_data)
69
+ SolarAverage.set_solar_terms_into_annual_range(western_year: western_year,
70
+ annual_range: annual_range)
71
71
 
72
72
  # 月間隔を取得するためだけの末尾要素を削除
73
- annual_data.pop
73
+ annual_range.pop
74
74
 
75
- adjust_leap_month(annual_data: annual_data)
75
+ adjust_leap_month(annual_range: annual_range)
76
76
 
77
- annual_data
77
+ annual_range
78
78
  end
79
79
 
80
80
  #
@@ -112,7 +112,7 @@ module Zakuro
112
112
  #
113
113
  # @return [Array<Month>] 1年データ
114
114
  #
115
- def self.initialized_annual_data(western_year:)
115
+ def self.initialized_annual_range(western_year:)
116
116
  result = []
117
117
  lunar_phase = LunarPhase.new(western_year: western_year)
118
118
 
@@ -133,18 +133,18 @@ module Zakuro
133
133
  end
134
134
  result
135
135
  end
136
- private_class_method :initialized_annual_data
136
+ private_class_method :initialized_annual_range
137
137
 
138
138
  #
139
139
  # 1年データの各月に月の大小を設定する
140
140
  #
141
- # @param [Array<Month>] annual_data 1年データ
141
+ # @param [Array<Month>] annual_range 1年データ
142
142
  #
143
- def self.apply_big_and_small_of_the_month(annual_data:)
144
- size = annual_data.size - 1
143
+ def self.apply_big_and_small_of_the_month(annual_range:)
144
+ size = annual_range.size - 1
145
145
  (0...size).each do |idx|
146
- current_month = annual_data[idx]
147
- next_month = annual_data[idx + 1]
146
+ current_month = annual_range[idx]
147
+ next_month = annual_range[idx + 1]
148
148
  current_month.is_many_days = \
149
149
  current_month.remainder.same_remainder_divided_by_ten?(
150
150
  other: next_month.remainder.day
@@ -159,12 +159,12 @@ module Zakuro
159
159
  # 閏月が存在した場合に以降の月を1つずつ減らす
160
160
  # @example 7,8,9 と続く月の8月が閏の場合、7, 閏7, 8 となる
161
161
  #
162
- # @param [Array<Month>] annual_data 1年データ
162
+ # @param [Array<Month>] annual_range 1年データ
163
163
  #
164
- def self.adjust_leap_month(annual_data:)
164
+ def self.adjust_leap_month(annual_range:)
165
165
  # 閏による月の再調整を行う
166
166
  leaped = false
167
- annual_data.each do |month|
167
+ annual_range.each do |month|
168
168
  if month.even_term.invalid?
169
169
  month.leaped = true
170
170
  leaped = true
@@ -0,0 +1,216 @@
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
+ # :nodoc:
9
+ module Zakuro
10
+ # :nodoc:
11
+ module Senmyou
12
+ # FullRange 完全範囲
13
+ # ある日からある日の範囲を計算可能な年月範囲
14
+ # * 前提として元号年はその元号の開始年から数える
15
+ # * ある日の元号年を求める場合、その元号が含まれる最初の年まで遡る
16
+ # * 元号は一つとは限らない。南北朝などで二つある場合は、古い方の元号から求める
17
+ #
18
+ # NOTE: 割り当てた元号は年初を基準にした元号年である
19
+ # * 元旦を基準にした時の正しい元号を設定している
20
+ # * 引き当てたい日付が元旦ではない場合、その月日に従い元号を再度求める
21
+ # * この再計算が必要になるのは、元号が切り替わる年のみである
22
+ class FullRange
23
+ attr_reader :multi_gengou_roller
24
+ attr_reader :new_year_date
25
+ attr_reader :western_year
26
+
27
+ # @return [Logger] ロガー
28
+ LOGGER = Logger.new(location: 'full_range')
29
+
30
+ def initialize(start_date: Western::Calendar.new, end_date: Western::Calendar.new)
31
+ @multi_gengou_roller = MultiGengouRoller.new(start_date: start_date, end_date: end_date)
32
+ @new_year_date = @multi_gengou_roller.oldest_date.clone
33
+ @western_year = @new_year_date.year
34
+ end
35
+
36
+ #
37
+ # 完全範囲を取得する
38
+ #
39
+ # @return [Array<Year>] 完全範囲
40
+ #
41
+ def get
42
+ years = FullRange.rearranged_years(annual_ranges: annual_ranges)
43
+ years = update_gengou(years: years)
44
+ years
45
+ end
46
+
47
+ # :reek:TooManyStatements { max_statements: 6 }
48
+
49
+ #
50
+ # 完全範囲内の年データを取得する
51
+ #
52
+ # @return [Array<Year>] 年データ(冬至基準)
53
+ #
54
+ def annual_ranges
55
+ oldest_date = @new_year_date
56
+ newest_date = @multi_gengou_roller.newest_date
57
+
58
+ years = []
59
+ ((oldest_date.year)..(newest_date.year + 2)).each do |year|
60
+ years.push(
61
+ AnnualRange.collect_annual_range_after_last_november_1st(
62
+ western_year: year
63
+ )
64
+ )
65
+ end
66
+
67
+ years
68
+ end
69
+
70
+ #
71
+ # 完全範囲内の年データの開始月を変更する
72
+ #
73
+ # @param [Array<Year>] annual_ranges 年データ(冬至基準)
74
+ #
75
+ # @return [Array<Year>] 年データ(元旦基準)
76
+ #
77
+ def self.rearranged_years(annual_ranges:)
78
+ years = []
79
+
80
+ (0..(annual_ranges.size - 2)).each do |index|
81
+ year = rearranged_year(annual_ranges: annual_ranges, index: index)
82
+ years.push(year)
83
+ end
84
+
85
+ years
86
+ end
87
+
88
+ # :reek:TooManyStatements { max_statements: 8 }
89
+
90
+ #
91
+ # 完全範囲内の年データの元号を開始年基準で更新する
92
+ #
93
+ # @param [Array<Year>] years 年データ(元旦基準)
94
+ #
95
+ # @return [Array<Year>] 元号更新済み年データ(元旦基準)
96
+ #
97
+ def update_gengou(years:)
98
+ updated_years = []
99
+
100
+ nearest_end_date = choise_nearest_end_date
101
+
102
+ years.each do |year|
103
+ next_year(years: updated_years, year: year)
104
+
105
+ if @new_year_date > nearest_end_date
106
+ @multi_gengou_roller.transfer
107
+ nearest_end_date = choise_nearest_end_date
108
+ end
109
+ @multi_gengou_roller.next_year
110
+ end
111
+
112
+ updated_years
113
+ end
114
+
115
+ #
116
+ # 当年データを生成する
117
+ #
118
+ def self.push_current_year(annual_range:, year: Year.new)
119
+ annual_range.each do |month|
120
+ next if month.is_last_year
121
+
122
+ year.push(month: month)
123
+ end
124
+
125
+ year
126
+ end
127
+
128
+ #
129
+ # 当年データを生成する
130
+ #
131
+ def self.push_last_year(annual_range:, year: Year.new)
132
+ annual_range.each do |month|
133
+ next unless month.is_last_year
134
+
135
+ year.push(month: month)
136
+ end
137
+
138
+ year
139
+ end
140
+
141
+ #
142
+ # 年データの開始月を変更する
143
+ #
144
+ # @param [Array<Year>] annual_ranges 年データ(冬至基準)
145
+ #
146
+ # @return [Year] 年データ(元旦基準)
147
+ #
148
+ def self.rearranged_year(annual_ranges:, index:)
149
+ current_annual_range = annual_ranges[index]
150
+ next_annual_range = annual_ranges[index + 1]
151
+
152
+ year = push_current_year(annual_range: current_annual_range)
153
+ push_last_year(annual_range: next_annual_range, year: year)
154
+
155
+ year
156
+ end
157
+ private_class_method :rearranged_year
158
+
159
+ private
160
+
161
+ #
162
+ # 元号処理対象の年を進める
163
+ #
164
+ # @param [Array<Year>] years 元号処理済み年データ(元旦基準)
165
+ # @param [Year] year 元号処理前の年(元旦基準)
166
+ #
167
+ def next_year(years:, year:)
168
+ updated_year = update_year(year: year)
169
+
170
+ years.push(updated_year)
171
+
172
+ next_new_year_date(total_days: updated_year.total_days)
173
+
174
+ nil
175
+ end
176
+
177
+ #
178
+ # 年の元号を更新する
179
+ #
180
+ # @param [Year] year 元号処理前の年(元旦基準)
181
+ #
182
+ # @return [Year] 元号処理済の年(元旦基準)
183
+ #
184
+ def update_year(year:)
185
+ multi_gengou = @multi_gengou_roller.multi_gengou.clone
186
+
187
+ updated_year = Year.new(multi_gengou: multi_gengou, new_year_date: @new_year_date.clone,
188
+ months: year.months)
189
+ updated_year.commit
190
+
191
+ updated_year
192
+ end
193
+
194
+ #
195
+ # 次の年に進める
196
+ #
197
+ # @param [Integer] total_days 年の日数
198
+ #
199
+ def next_new_year_date(total_days:)
200
+ @new_year_date += total_days
201
+ @multi_gengou_roller.next(days: total_days)
202
+
203
+ nil
204
+ end
205
+
206
+ #
207
+ # 現在日からみて直近の未来に対する元号の切替前日を求める
208
+ #
209
+ # @return [Western::Calendar] 元号の切替前日
210
+ #
211
+ def choise_nearest_end_date
212
+ @multi_gengou_roller.choise_nearest_end_date
213
+ end
214
+ end
215
+ end
216
+ end