zakuro 0.0.1 → 0.0.2

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.
@@ -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