fiscal_year 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2a44c87e166920493e3723924cdf5c0a20cbdca0f148fb87e32a69aee645267
4
- data.tar.gz: c6a17528d17f0cb3de8143a01227b06c7e8e527eee3a7ccc5677b637b7b3c41a
3
+ metadata.gz: 9f35e4820f8a076879f9e461f172479e79899b71b71e4933fb8598b8c91b0dd7
4
+ data.tar.gz: 7616d720fff1de8d186b6809dfc2c465be1dfee8637808f3d8c490c15b253327
5
5
  SHA512:
6
- metadata.gz: 5ade0c96554bc2670317108bb74851ccfd485cf4932709eafe479de937db7fab43c864a8372d895b99d774cebe6bb08520191e5015ca4ef38eb1a85a19f3d8f4
7
- data.tar.gz: ca421f4b2fa6fd74c319bab2eb739203391f3c71d0fcd592e78018a62900e72edfcc838e7480e1d2a80af1256266c9863e014ec2873f6e8169e1a52dfbe8d1c8
6
+ metadata.gz: 69d7ffc53eb33c6a65fabd20bd0b8757f40b71d11ce63a6a5754bb3af5312ad0641642a1701fc88820a7fd2764dfe29a140c045d0d524e4557d30304458c5ad5
7
+ data.tar.gz: d8c1ada946d9fd2e0ca21818e6885903fa99203a847c016759019828ca602ebf15cb03b8d94653c1801ff9a5c0ed942fa4c2afa224675563a875ad24fcf16e97
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.6
2
+ TargetRubyVersion: 3.1
3
3
  Exclude:
4
4
  - 'Steepfile'
5
5
  - 'vendor/**/*'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.7.0] - 2024-07-11
2
+ - add YARD comment.
3
+ - fix `FiscalYear::YearToDate.quarter_range_by` logic.
4
+
5
+ ## [0.6.0] - 2024-05-15
6
+ - [BREAK] Ruby 3.0.x, 2.7.x and 2.6.x has no longer support.
7
+ - add `FiscalYear.range_by` method
8
+
1
9
  ## [0.5.0] - 2024-03-18
2
10
  - [BREAK] rename and move `FiscalYear::Half.normalize_year_by_month` to `FiscalYear.increase_year_by_month`
3
11
  - add `FiscalYear.decrease_year_by_month` method
@@ -3,6 +3,7 @@
3
3
  module FiscalYear
4
4
  class Half
5
5
  class << self
6
+ # @return [Array<Integer>] the first half of the fiscal year.
6
7
  def first
7
8
  first = FiscalYear.halfs.first
8
9
  return first if first.is_a? Array
@@ -10,6 +11,7 @@ module FiscalYear
10
11
  []
11
12
  end
12
13
 
14
+ # @return [Array<Integer>] the second half of the fiscal year.
13
15
  def second
14
16
  second = FiscalYear.halfs.second
15
17
  return second if second.is_a? Array
@@ -17,14 +19,20 @@ module FiscalYear
17
19
  []
18
20
  end
19
21
 
22
+ # @param month [Integer] the month
23
+ # @return [Boolean] true if the month is in the first half of the fiscal year.
20
24
  def first?(month)
21
25
  FiscalYear.halfs.first.include?(month)
22
26
  end
23
27
 
28
+ # @param month [Integer] the month
29
+ # @return [Boolean] true if the month is in the second half of the fiscal year.
24
30
  def second?(month)
25
31
  !first?(month)
26
32
  end
27
33
 
34
+ # @param year [Integer] the calendar year
35
+ # @return [Range<Date>] the range of the first half of the fiscal year.
28
36
  def first_range_by(year)
29
37
  # care Date#parse 2 digit year auto complete.
30
38
  # 99 + 1 = 100, but expect 2000 this context.
@@ -37,6 +45,8 @@ module FiscalYear
37
45
  Date.parse("#{year}/#{first.first}/01")..Date.parse("#{end_year}/#{end_month}/01").end_of_month
38
46
  end
39
47
 
48
+ # @param year [Integer] the calendar year
49
+ # @return [Range<Date>] the range of the second half of the fiscal year.
40
50
  def second_range_by(year)
41
51
  # care Date#parse 2 digit year auto complete.
42
52
  # 99 + 1 = 100, but expect 2000 this context.
@@ -51,6 +61,8 @@ module FiscalYear
51
61
  Date.parse("#{start_year}/#{first_month}/01")..Date.parse("#{end_year}/#{end_month}/01").end_of_month
52
62
  end
53
63
 
64
+ # @param date [Date] the date
65
+ # @return [Range<Date>] the range of the half of the fiscal year by the date.
54
66
  def range_by(date)
55
67
  month = date.month
56
68
  year = date.year
@@ -60,6 +72,8 @@ module FiscalYear
60
72
  first?(month) ? first_range_by(year) : second_range_by(year)
61
73
  end
62
74
 
75
+ # @param half [Array<Integer>] the half of the fiscal year
76
+ # @return [Boolean] true if the any month of half are crossed calendar year.
63
77
  def cross_year_in_half?(half)
64
78
  FiscalYear.cross_year? && half.any? { |month| month == 12 }
65
79
  end
@@ -3,28 +3,49 @@
3
3
  module FiscalYear
4
4
  class Quarter
5
5
  class << self
6
+ # @!method first
7
+ # @return [Array<Integer>] the first quarter of the fiscal year.
8
+
9
+ # @!method second
10
+ # @return [Array<Integer>] the second quarter of the fiscal year.
11
+
12
+ # @!method third
13
+ # @return [Array<Integer>] the third quarter of the fiscal year.
14
+
15
+ # @!method fourth
16
+ # @return [Array<Integer>] the fourth quarter of the fiscal year.
6
17
  %i[first second third fourth].each do |method_name|
7
18
  define_method(method_name) do
8
19
  FiscalYear.quarters.public_send(method_name)
9
20
  end
10
21
  end
11
22
 
23
+ # @param month [Integer] the month
24
+ # @return [Boolean] true if the month is in the first quarter of the fiscal year.
12
25
  def first?(month)
13
26
  FiscalYear.quarters.first.include?(month)
14
27
  end
15
28
 
29
+ # @param month [Integer] the month
30
+ # @return [Boolean] true if the month is in the second quarter of the fiscal year.
16
31
  def second?(month)
17
32
  FiscalYear.quarters.second.include?(month)
18
33
  end
19
34
 
35
+ # @param month [Integer] the month
36
+ # @return [Boolean] true if the month is in the third quarter of the fiscal year.
20
37
  def third?(month)
21
38
  FiscalYear.quarters.third.include?(month)
22
39
  end
23
40
 
41
+ # @param month [Integer] the month
42
+ # @return [Boolean] true if the month is in the fourth quarter of the fiscal year.
24
43
  def fourth?(month)
25
44
  FiscalYear.quarters.fourth.include?(month)
26
45
  end
27
46
 
47
+ # @param month [Integer] the month
48
+ # @return [Array<Integer>] the quarter month by the month.
28
49
  def months(month)
29
50
  months = FiscalYear.quarters.find { |a| a.include?(month) }
30
51
  raise ::StandardError if months.nil?
@@ -32,6 +53,8 @@ module FiscalYear
32
53
  months
33
54
  end
34
55
 
56
+ # @param date [Date] the date
57
+ # @return [Range<Date>] the range of the quarter by the date.
35
58
  def range_by(date)
36
59
  year = date.year
37
60
  this_quarter = months(date.month)
@@ -40,12 +63,16 @@ module FiscalYear
40
63
  Date.parse("#{year}/#{this_quarter.first}/01")..Date.parse("#{last_year}/#{this_quarter.last}/01").end_of_month
41
64
  end
42
65
 
66
+ # @param month [Integer] the month
67
+ # @return [Integer] the quarter number by the month.
43
68
  def quarter_num(month)
44
69
  rindex = FiscalYear.quarters.rindex(months(month))
45
70
 
46
71
  rindex.nil? ? 0 : (rindex + 1)
47
72
  end
48
73
 
74
+ # @param quarter [Array<Integer>] the quarter
75
+ # @return [Boolean] true if the quarter is crossed calendar year.
49
76
  def cross_year_in_quarter?(quarter)
50
77
  FiscalYear.cross_year? && quarter.any? { |month| month == 12 }
51
78
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FiscalYear
4
- VERSION = "0.5.0"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -3,6 +3,14 @@
3
3
  module FiscalYear
4
4
  class YearToDate
5
5
  class << self
6
+ # @param date [Date] the date
7
+ # @return [Range<Date>] the range of the year to date.
8
+ # @example
9
+ # FiscalYear::YearToDate.range_by(Date.parse("2021-08-01"))
10
+ # => Thu, 01 Apr 2021..Tue, 31 Aug 2021
11
+ #
12
+ # FiscalYear::YearToDate.range_by(Date.parse("2021-01-01"))
13
+ # => Wed, 01 Apr 2020..Sun, 31 Jan 2021
6
14
  def range_by(date)
7
15
  year = date.year
8
16
  month = date.month
@@ -14,48 +22,60 @@ module FiscalYear
14
22
  end
15
23
  end
16
24
 
17
- # TODO: fit to Abc size
18
- def year_month_pairs(date) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
25
+ # @param date [Date] the date
26
+ # @return [Array<Array<Integer>, Array<Integer>>] the passed year and month pairs.
27
+ # @example
28
+ # FiscalYear::YearToDate.year_month_pairs(Date.parse("2021-08-01"))
29
+ # => [[2021, 4], [2021, 5], [2021, 6], [2021, 7], [2021, 8]]
30
+ #
31
+ # FiscalYear::YearToDate.year_month_pairs(Date.parse("2021-01-01"))
32
+ # => [
33
+ # [2020, 4], [2020, 5], [2020, 6], [2020, 7], [2020, 8], [2020, 9],
34
+ # [2020, 10], [2020, 11], [2020, 12], [2021, 1]
35
+ # ]
36
+ def year_month_pairs(date)
19
37
  month = date.month
20
38
  month_index = FiscalYear.months.index(month)
21
39
  months = FiscalYear.months[(0..month_index)]
22
40
  raise StandardError if months.nil?
23
41
 
24
- pair = []
25
- [date.year].product(months).each do |e|
26
- pair << if FiscalYear.cross_year_month?(month)
27
- (FiscalYear.cross_year_month?(e.second) ? e : [e.first - 1, e.second])
28
- else
29
- e
30
- end
42
+ [date.year].product(months).map do |e|
43
+ [FiscalYear.decrease_year_by_month(e.first, e.second), e.second]
31
44
  end
32
-
33
- pair
34
45
  end
35
46
 
36
- # TODO: fit to Abc size
37
- def half_range_by(date) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
47
+ # @param date [Date] the date
48
+ # @return [Range<Date>] the range of the half year to date.
49
+ # @example
50
+ # FiscalYear::YearToDate.half_range_by(Date.parse("2021-08-01"))
51
+ # => Thu, 01 Apr 2021..Tue, 31 Aug 2021
52
+ #
53
+ # FiscalYear::YearToDate.half_range_by(Date.parse("2021-01-01"))
54
+ # => Thu, 01 Oct 2020..Sun, 31 Jan 2021
55
+ def half_range_by(date)
38
56
  year = date.year
39
57
  month = date.month
40
58
 
41
- if Half.first?(month)
42
- return (Date.parse("#{FiscalYear.cross_year_month?(month) ? year - 1 : year}/#{Half.first.first}/01")..
43
- date.end_of_month.to_date
44
- )
45
- end
59
+ beginning_year =
60
+ if Half.first?(month)
61
+ FiscalYear.cross_year_month?(month) ? year - 1 : year
62
+ else
63
+ Half.cross_year_in_half?(Half.second) ? FiscalYear.decrease_year_by_month(year, month) : year
64
+ end
46
65
 
47
- Date.parse(
48
- "#{
49
- if FiscalYear::Half.cross_year_in_half?(Half.second) &&
50
- FiscalYear.cross_year_month?(month)
51
- year - 1
52
- else
53
- year
54
- end
55
- }/#{Half.second.first}"
56
- )..date.end_of_month.to_date
66
+ half_method = Half.first?(month) ? :first : :second
67
+
68
+ Date.parse("#{beginning_year}/#{Half.public_send(half_method).first}/01")..date.end_of_month.to_date
57
69
  end
58
70
 
71
+ # @param date [Date] the date
72
+ # @return [Range<Date>] the range of the quarter to date.
73
+ # @example
74
+ # FiscalYear::YearToDate.quarter_range_by(Date.parse("2021-08-01"))
75
+ # => Thu, 01 Jul 2021..Tue, 31 Aug 2021
76
+ #
77
+ # FiscalYear::YearToDate.quarter_range_by(Date.parse("2021-01-01"))
78
+ # => Wed, 01 Jan 2020..Sun, 31 Jan 2021
59
79
  def quarter_range_by(date)
60
80
  year = date.year
61
81
  month = date.month
@@ -66,10 +86,10 @@ module FiscalYear
66
86
 
67
87
  quarter = Quarter.public_send(quarter_method)
68
88
 
69
- (
70
- Date.parse("#{FiscalYear.cross_year_month?(month) ? year - 1 : year}/#{quarter.first}/01")..
71
- date.end_of_month.to_date
72
- )
89
+ beginning_year =
90
+ Quarter.cross_year_in_quarter?(quarter) ? FiscalYear.decrease_year_by_month(year, month) : year
91
+
92
+ Date.parse("#{beginning_year}/#{quarter.first}/01")..date.end_of_month.to_date
73
93
  end
74
94
  end
75
95
  end
data/lib/fiscal_year.rb CHANGED
@@ -14,24 +14,40 @@ module FiscalYear
14
14
  # @type ivar @config: FiscalYear::Config
15
15
  @config ||= FiscalYear::Config.new
16
16
  class << self
17
+ # @return [FiscalYear::Config]
17
18
  attr_reader :config
18
19
 
20
+ # configure start month of fiscal year.
21
+ #
22
+ # @yieldparam config [FiscalYear::Config]
23
+ # @example
24
+ # FiscalYear.configure do |config|
25
+ # config.start_month = 6
26
+ # end
19
27
  def configure
20
28
  yield(@config) if block_given?
21
29
  end
22
30
 
31
+ # If the fiscal year start from 4, the month 1, 2, 3 are crossed year.
32
+ #
33
+ # @param month [Integer] the month to check, 1-12.
34
+ # @return [Boolean] true if the month is crossed year on calendar year.
35
+ # Determines if the month passed is beyond the year, By relative to the beginning month of the fiscal year.
23
36
  def cross_year_month?(month)
24
37
  cross_year_months.include?(month)
25
38
  end
26
39
 
40
+ # @return [Boolean] true if the fiscal year is crossed year.
27
41
  def cross_year?
28
42
  months.rindex(1) != 0
29
43
  end
30
44
 
45
+ # @return [Array<Integer>] the months of the fiscal year.
31
46
  def months
32
47
  (1..12).to_a.tap { |arr| arr.concat(arr.shift(@config.start_month - 1)) }
33
48
  end
34
49
 
50
+ # @return [Array<Integer>] the months of the crossed year.
35
51
  def cross_year_months
36
52
  return [] if @config.start_month == 1
37
53
 
@@ -43,16 +59,25 @@ module FiscalYear
43
59
  m
44
60
  end
45
61
 
62
+ # @return [Array(Array<Integer>, Array<Integer>)] the first half and the second half of the fiscal year.
46
63
  def halfs
47
64
  # @type self: singleton(FiscalYear)
48
65
  months.in_groups(2)
49
66
  end
50
67
 
68
+ # @return [Array(Array<Integer>, Array<Integer>, Array<Integer>, Array<Integer>)] the quarters of the fiscal year.
51
69
  def quarters
52
70
  # @type self: singleton(FiscalYear)
53
71
  months.in_groups(4)
54
72
  end
55
73
 
74
+ # increate the calendar year by month, if the month is crossed year.
75
+ #
76
+ # for example, in case of the fiscal year start from 4, you want to obtain calendar year of the month 1, 2, 3.
77
+ #
78
+ # @param year [Integer] the calendar year
79
+ # @param month [Integer] the month
80
+ # @return [Integer] year
56
81
  def increase_year_by_month(year, month)
57
82
  if FiscalYear.cross_year_month?(month)
58
83
  year + 1
@@ -61,6 +86,13 @@ module FiscalYear
61
86
  end
62
87
  end
63
88
 
89
+ # decrease the calendar year by month, if the month is crossed year.
90
+ #
91
+ # for example, in case of the fiscal year start from 4, you want to obtain fiscal year from the month 1, 2, 3.
92
+ #
93
+ # @param year [Integer] the calendar year
94
+ # @param month [Integer] the month
95
+ # @return [Integer] year
64
96
  def decrease_year_by_month(year, month)
65
97
  if FiscalYear.cross_year_month?(month)
66
98
  year - 1
@@ -68,5 +100,15 @@ module FiscalYear
68
100
  year
69
101
  end
70
102
  end
103
+
104
+ # @param date [Date] the date
105
+ # @return [Range<Date>] the range of the fiscal year between beginning and end by the date.
106
+ def range_by(date)
107
+ year = date.year
108
+ month = date.month
109
+ normalized_year = decrease_year_by_month(year, month)
110
+
111
+ FiscalYear::Half.first_range_by(normalized_year).first..FiscalYear::Half.second_range_by(normalized_year).last
112
+ end
71
113
  end
72
114
  end
@@ -1,5 +1,6 @@
1
1
  module FiscalYear
2
2
  class Config
3
3
  attr_reader start_month: Integer
4
+ def initialize: -> Integer
4
5
  end
5
6
  end
data/sig/fiscal_year.rbs CHANGED
@@ -12,4 +12,5 @@ module FiscalYear
12
12
  def self.quarters: () -> [Array[Integer], Array[Integer], Array[Integer], Array[Integer]]
13
13
  def self.increase_year_by_month: (Integer, Integer) -> Integer
14
14
  def self.decrease_year_by_month: (Integer, Integer) -> Integer
15
+ def self.range_by: (Date) -> Range
15
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fiscal_year
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tsubasa Kawajiri
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-18 00:00:00.000000000 Z
11
+ date: 2024-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -70,7 +70,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - ">="
72
72
  - !ruby/object:Gem::Version
73
- version: 2.6.0
73
+ version: 3.1.0
74
74
  required_rubygems_version: !ruby/object:Gem::Requirement
75
75
  requirements:
76
76
  - - ">="