fat_period 3.0.0 → 3.2.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +5 -2
- data/.gitignore +1 -0
- data/CHANGELOG.org +16 -0
- data/Gemfile +1 -0
- data/README.md +1291 -0
- data/README.org +937 -96
- data/Rakefile +3 -0
- data/fat_period.gemspec +2 -2
- data/lib/fat_period/date.rb +2 -6
- data/lib/fat_period/period.rb +223 -10
- data/lib/fat_period/version.rb +1 -1
- data/lib/fat_period.rb +21 -6
- metadata +8 -7
data/Rakefile
CHANGED
|
@@ -5,6 +5,9 @@ require 'rspec/core/rake_task'
|
|
|
5
5
|
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
|
7
7
|
|
|
8
|
+
require 'gem_docs'
|
|
9
|
+
GemDocs.install
|
|
10
|
+
|
|
8
11
|
########################################################################
|
|
9
12
|
# Rubocop tasks
|
|
10
13
|
########################################################################
|
data/fat_period.gemspec
CHANGED
|
@@ -21,6 +21,6 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
# spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
22
22
|
spec.require_paths = ['lib']
|
|
23
23
|
|
|
24
|
-
spec.add_dependency 'fat_core', '>=
|
|
25
|
-
spec.add_dependency 'fat_date'
|
|
24
|
+
spec.add_dependency 'fat_core', '>= 7.0'
|
|
25
|
+
spec.add_dependency 'fat_date', '>= 0.3.0'
|
|
26
26
|
end
|
data/lib/fat_period/date.rb
CHANGED
|
@@ -23,9 +23,5 @@ module FatPeriod
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
include FatPeriod::Date
|
|
29
|
-
# @!parse include FatPeriod::Date
|
|
30
|
-
# @!parse extend FatPeriod::Date::ClassMethods
|
|
31
|
-
end
|
|
26
|
+
# Add the period helpers to Ruby's Date class.
|
|
27
|
+
Date.include(FatPeriod::Date)
|
data/lib/fat_period/period.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'fat_date'
|
|
4
|
+
require 'bigdecimal'
|
|
4
5
|
|
|
5
6
|
# The Period class represents a range of Dates and supports a variety of
|
|
6
7
|
# operations on those ranges.
|
|
@@ -185,7 +186,7 @@ class Period
|
|
|
185
186
|
"Period(#{first.iso}..#{last.iso})"
|
|
186
187
|
end
|
|
187
188
|
|
|
188
|
-
# Allow erb documents
|
|
189
|
+
# Allow erb documents to directly interpolate ranges
|
|
189
190
|
def tex_quote
|
|
190
191
|
"#{first.iso}--#{last.iso}"
|
|
191
192
|
end
|
|
@@ -207,11 +208,6 @@ class Period
|
|
|
207
208
|
[first, last] <=> [other.first, other.last]
|
|
208
209
|
end
|
|
209
210
|
|
|
210
|
-
# Comparable does not include this.
|
|
211
|
-
def !=(other)
|
|
212
|
-
!(self == other)
|
|
213
|
-
end
|
|
214
|
-
|
|
215
211
|
# Return the hash value for this Period. Make Period's with identical
|
|
216
212
|
# values test eql? so that they may be used as hash keys.
|
|
217
213
|
#
|
|
@@ -337,38 +333,47 @@ class Period
|
|
|
337
333
|
|
|
338
334
|
# Return a period representing a chunk containing a given Date.
|
|
339
335
|
def self.day_containing(date)
|
|
336
|
+
date = Date.ensure_date(date)
|
|
340
337
|
Period.new(date, date)
|
|
341
338
|
end
|
|
342
339
|
|
|
343
340
|
def self.week_containing(date)
|
|
341
|
+
date = Date.ensure_date(date)
|
|
344
342
|
Period.new(date.beginning_of_week, date.end_of_week)
|
|
345
343
|
end
|
|
346
344
|
|
|
347
345
|
def self.biweek_containing(date)
|
|
346
|
+
date = Date.ensure_date(date)
|
|
348
347
|
Period.new(date.beginning_of_biweek, date.end_of_biweek)
|
|
349
348
|
end
|
|
350
349
|
|
|
351
350
|
def self.semimonth_containing(date)
|
|
351
|
+
date = Date.ensure_date(date)
|
|
352
352
|
Period.new(date.beginning_of_semimonth, date.end_of_semimonth)
|
|
353
353
|
end
|
|
354
354
|
|
|
355
355
|
def self.month_containing(date)
|
|
356
|
+
date = Date.ensure_date(date)
|
|
356
357
|
Period.new(date.beginning_of_month, date.end_of_month)
|
|
357
358
|
end
|
|
358
359
|
|
|
359
360
|
def self.bimonth_containing(date)
|
|
361
|
+
date = Date.ensure_date(date)
|
|
360
362
|
Period.new(date.beginning_of_bimonth, date.end_of_bimonth)
|
|
361
363
|
end
|
|
362
364
|
|
|
363
365
|
def self.quarter_containing(date)
|
|
366
|
+
date = Date.ensure_date(date)
|
|
364
367
|
Period.new(date.beginning_of_quarter, date.end_of_quarter)
|
|
365
368
|
end
|
|
366
369
|
|
|
367
370
|
def self.half_containing(date)
|
|
371
|
+
date = Date.ensure_date(date)
|
|
368
372
|
Period.new(date.beginning_of_half, date.end_of_half)
|
|
369
373
|
end
|
|
370
374
|
|
|
371
375
|
def self.year_containing(date)
|
|
376
|
+
date = Date.ensure_date(date)
|
|
372
377
|
Period.new(date.beginning_of_year, date.end_of_year)
|
|
373
378
|
end
|
|
374
379
|
|
|
@@ -618,8 +623,7 @@ class Period
|
|
|
618
623
|
# @param round_up_last [Boolean] allow the last period in the returned array
|
|
619
624
|
# to extend beyond the end of self.
|
|
620
625
|
# @return [Array<Period>] periods that subdivide self into chunks of size, `size`
|
|
621
|
-
def chunks(size: :month, partial_first: true, partial_last: true,
|
|
622
|
-
round_up_last: false)
|
|
626
|
+
def chunks(size: :month, partial_first: true, partial_last: true, round_up_last: false)
|
|
623
627
|
chunk_size = size.to_sym
|
|
624
628
|
raise ArgumentError, "unknown chunk size '#{chunk_size}'" unless CHUNKS.include?(chunk_size)
|
|
625
629
|
|
|
@@ -809,13 +813,14 @@ class Period
|
|
|
809
813
|
to_range.overlaps?(other.to_range)
|
|
810
814
|
end
|
|
811
815
|
|
|
816
|
+
# @group Coverage
|
|
817
|
+
|
|
812
818
|
# Return whether this Period contains the given date.
|
|
813
819
|
#
|
|
814
820
|
# @param date [Date] date to test
|
|
815
821
|
# @return [Boolean] is the given date within this Period?
|
|
816
822
|
def contains?(date)
|
|
817
|
-
date =
|
|
818
|
-
raise ArgumentError, 'argument must be a Date' unless date.is_a?(Date)
|
|
823
|
+
date = Date.ensure(date)
|
|
819
824
|
|
|
820
825
|
to_range.cover?(date)
|
|
821
826
|
end
|
|
@@ -896,4 +901,212 @@ class Period
|
|
|
896
901
|
to_range.gaps(periods.map(&:to_range))
|
|
897
902
|
.map { |r| Period.new(r.first, r.last) }
|
|
898
903
|
end
|
|
904
|
+
|
|
905
|
+
# Return the fraction of a whole year represented by the part of this Period
|
|
906
|
+
# from its beginning to the given date2, following the day-count convention,
|
|
907
|
+
# convention.
|
|
908
|
+
#
|
|
909
|
+
# This Period is assumed to represent an entire accrual period, for example,
|
|
910
|
+
# a whole month for a loan, or a whole quarter or semi-year for a bond. We
|
|
911
|
+
# infer the annual frequency of payments from the length of this Period.
|
|
912
|
+
#
|
|
913
|
+
# Return the fraction of the year that has elapsed on date2, typically the
|
|
914
|
+
# settlement date.
|
|
915
|
+
#
|
|
916
|
+
# - ~first~ :: is the date on which interest accrual begins
|
|
917
|
+
# - ~date2~ :: is the date when payment of interest is made,
|
|
918
|
+
# - ~last~ :: is the date on which the interest accrual period ends,
|
|
919
|
+
# usually irrelevant unless actual days in period are considered
|
|
920
|
+
#
|
|
921
|
+
# The ~convention~ is the day-count convention to be used.
|
|
922
|
+
#
|
|
923
|
+
# That is, the convention for how interest is calculated between
|
|
924
|
+
# interest payment dates. This has to do with the fraction by which the
|
|
925
|
+
# annual interest or coupon rate is multiplied to pay for a partial
|
|
926
|
+
# period. The numerator is the number of days that have elapsed; The
|
|
927
|
+
# denominator is the number of days in the entire year. These involve
|
|
928
|
+
# assumptions about the number of days in the months that fall within
|
|
929
|
+
# the partial period. They will assume either that every month consists
|
|
930
|
+
# of 30 days, even if the particular period in which the payment occurs
|
|
931
|
+
# contains February, July, and August, or they will take into account
|
|
932
|
+
# the actual number of days in the particular period.
|
|
933
|
+
#
|
|
934
|
+
# | ~convention~ | Description | Source |
|
|
935
|
+
# |--------------+--------------------+------------------------------------|
|
|
936
|
+
# | 0 | 30/360 Bond | ISDA 2006 Section 4.16(f) |
|
|
937
|
+
# | 1 | 30/360 US | ISDA 2006 Section 4.16(f) (Note A) |
|
|
938
|
+
# | 2 | 30E/360 | ISDA 2006 Section 4.16(g) |
|
|
939
|
+
# | 3 | 30E/360 ISDA | ISDA 2006 Section 4.16(h) |
|
|
940
|
+
# | 4 | Actual/actual ICMA | ISDA 2006 Section 4.16(c) |
|
|
941
|
+
# | 5 | Actual/actual ISDA | ISDA 2006 Section 4.16(b) |
|
|
942
|
+
# | 6 | Actual/365 Fixed | ISDA 2006 Section 4.16(d) |
|
|
943
|
+
# | 7 | Actual/360 | ISDA 2006 Section 4.16(e) |
|
|
944
|
+
# | 8 | Actual/364 | |
|
|
945
|
+
# | 9 | Actual/365L | ICMA Rule 251.1(i) |
|
|
946
|
+
# | 10 | Actual/Actual AFB | |
|
|
947
|
+
# | 11 | 1/1 | ISDA 2006 Section 4.16(a) |
|
|
948
|
+
#
|
|
949
|
+
# Source: https://en.wikipedia.org/wiki/Day_count_convention
|
|
950
|
+
#
|
|
951
|
+
# Unlike Period#size, day counts use elapsed days, without adding one.
|
|
952
|
+
# For ICMA, first and last are consecutive coupon boundaries; only regular
|
|
953
|
+
# coupon periods are supported. Settlement must lie within this Period.
|
|
954
|
+
# Actual/365L uses the settlement date to determine its denominator, following
|
|
955
|
+
# the reference above. Convention 11 (1/1) always returns one, even for equal dates.
|
|
956
|
+
# AFB counts whole years backwards, with the February month-end adjustment
|
|
957
|
+
# used by QuantLib, then counts the remaining days (start included, end excluded).
|
|
958
|
+
#
|
|
959
|
+
# @param date2 [Date, String] payment or settlement date within this Period
|
|
960
|
+
# @param convention [Integer] day-count convention, 0 through 11; defaults to 1 (30/360 US)
|
|
961
|
+
# @param eom [Boolean] apply February end-of-month rules for convention 1
|
|
962
|
+
# @param maturity_date [Date, String, nil] final maturity for convention 3
|
|
963
|
+
# @return [BigDecimal] accrued fraction of a year
|
|
964
|
+
def year_fraction(date2, convention: 1, eom: true, maturity_date: nil)
|
|
965
|
+
unless convention.is_a?(Integer) && (0..11).cover?(convention)
|
|
966
|
+
raise ArgumentError, 'convention must be an integer 0..11'
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
date1 = first
|
|
970
|
+
date2 = Date.ensure(date2)
|
|
971
|
+
unless (first..last).cover?(date2)
|
|
972
|
+
raise ArgumentError, 'settlement date must lie within the period'
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
maturity_date = Date.ensure(maturity_date) if maturity_date
|
|
976
|
+
return BigDecimal(1) if convention == 11
|
|
977
|
+
return BigDecimal(0) if date1 == date2
|
|
978
|
+
|
|
979
|
+
if (0..3).cover?(convention)
|
|
980
|
+
# 360-day methods
|
|
981
|
+
y1 = date1.year
|
|
982
|
+
m1 = date1.month
|
|
983
|
+
d1 = date1.day
|
|
984
|
+
y2 = date2.year
|
|
985
|
+
m2 = date2.month
|
|
986
|
+
d2 = date2.day
|
|
987
|
+
case convention
|
|
988
|
+
when 0
|
|
989
|
+
# 30/360 Bond
|
|
990
|
+
d1 = [d1, 30].min
|
|
991
|
+
d2 = d1 > 29 ? [d2, 30].min : d2
|
|
992
|
+
when 1
|
|
993
|
+
# 30/360 US
|
|
994
|
+
if eom && date1.end_of_month? && m1 == 2 && date2.end_of_month? && m2 == 2
|
|
995
|
+
d2 = 30
|
|
996
|
+
end
|
|
997
|
+
if eom && date1.end_of_month? && m1 == 2
|
|
998
|
+
d1 = 30
|
|
999
|
+
end
|
|
1000
|
+
# If D2 is 31 and D1 is 30 or 31, then change D2 to 30.
|
|
1001
|
+
if d2 == 31 && (d1 == 30 || d1 == 31)
|
|
1002
|
+
d2 = 30
|
|
1003
|
+
end
|
|
1004
|
+
# If D1 is 31, then change D1 to 30.
|
|
1005
|
+
if d1 == 31
|
|
1006
|
+
d1 = 30
|
|
1007
|
+
end
|
|
1008
|
+
when 2
|
|
1009
|
+
# 30E/360
|
|
1010
|
+
# If D1 is 31, then change D1 to 30.
|
|
1011
|
+
if d1 == 31
|
|
1012
|
+
d1 = 30
|
|
1013
|
+
end
|
|
1014
|
+
# If D2 is 31, then change D2 to 30.
|
|
1015
|
+
if d2 == 31
|
|
1016
|
+
d2 = 30
|
|
1017
|
+
end
|
|
1018
|
+
when 3
|
|
1019
|
+
# 30E/360 ISDA
|
|
1020
|
+
if date1.end_of_month?
|
|
1021
|
+
d1 = 30
|
|
1022
|
+
end
|
|
1023
|
+
if date2.end_of_month? && !(m2 == 2 && maturity_date && date2 == maturity_date)
|
|
1024
|
+
# If D2 is the last day of the month (unless Date2 is the maturity
|
|
1025
|
+
# date and M2 is February), then change D2 to 30.
|
|
1026
|
+
d2 = 30
|
|
1027
|
+
end
|
|
1028
|
+
end
|
|
1029
|
+
num = 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1)
|
|
1030
|
+
return BigDecimal(num) / 360
|
|
1031
|
+
end
|
|
1032
|
+
|
|
1033
|
+
num = BigDecimal((date2 - date1).to_i)
|
|
1034
|
+
case convention
|
|
1035
|
+
when 4
|
|
1036
|
+
# Actual/actual ICMA: elapsed days in the reference coupon period.
|
|
1037
|
+
num / (freq_per_year(days: (last - first).to_i) * (last - first).to_i)
|
|
1038
|
+
when 5
|
|
1039
|
+
# Actual/actual ISDA: split only the elapsed interval at year boundaries.
|
|
1040
|
+
frac = BigDecimal(0)
|
|
1041
|
+
cursor = date1
|
|
1042
|
+
while cursor < date2
|
|
1043
|
+
boundary = [Date.new(cursor.year + 1, 1, 1), date2].min
|
|
1044
|
+
frac += BigDecimal((boundary - cursor).to_i) / (cursor.leap? ? 366 : 365)
|
|
1045
|
+
cursor = boundary
|
|
1046
|
+
end
|
|
1047
|
+
frac
|
|
1048
|
+
when 6
|
|
1049
|
+
num / 365
|
|
1050
|
+
when 7
|
|
1051
|
+
num / 360
|
|
1052
|
+
when 8
|
|
1053
|
+
num / 364
|
|
1054
|
+
when 9
|
|
1055
|
+
# Actual/365L: annual coupons exclude the start and include the end
|
|
1056
|
+
# when looking for February 29. Other frequencies use the settlement year.
|
|
1057
|
+
leap =
|
|
1058
|
+
if freq_per_year(days: (last - first).to_i) == 1
|
|
1059
|
+
(first.year..date2.year).any? do |year|
|
|
1060
|
+
Date.leap?(year) && first < Date.new(year, 2, 29) && Date.new(year, 2, 29) <= date2
|
|
1061
|
+
end
|
|
1062
|
+
else
|
|
1063
|
+
date2.leap?
|
|
1064
|
+
end
|
|
1065
|
+
num / (leap ? 366 : 365)
|
|
1066
|
+
when 10
|
|
1067
|
+
# Actual/actual AFB: whole years plus the remaining fraction.
|
|
1068
|
+
years = 0
|
|
1069
|
+
remainder_end = date2
|
|
1070
|
+
loop do
|
|
1071
|
+
previous = remainder_end << 12
|
|
1072
|
+
previous += 1 if previous.month == 2 && previous.day == 28 && previous.leap?
|
|
1073
|
+
break if previous < date1
|
|
1074
|
+
|
|
1075
|
+
years += 1
|
|
1076
|
+
remainder_end = previous
|
|
1077
|
+
end
|
|
1078
|
+
leap = (date1.year..remainder_end.year).any? do |year|
|
|
1079
|
+
Date.leap?(year) && date1 <= Date.new(year, 2, 29) && Date.new(year, 2, 29) < remainder_end
|
|
1080
|
+
end
|
|
1081
|
+
years + BigDecimal((remainder_end - date1).to_i) / (leap ? 366 : 365)
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
# Infer payment frequency from the period length, allowing the same tolerance
|
|
1086
|
+
# as chunk_name. Daily periods use the number of days in the starting year.
|
|
1087
|
+
# @param days [Integer] period length; use elapsed days for coupon boundaries
|
|
1088
|
+
def freq_per_year(days: length)
|
|
1089
|
+
case Period.days_to_chunk(days)
|
|
1090
|
+
when :year
|
|
1091
|
+
1
|
|
1092
|
+
when :half
|
|
1093
|
+
2
|
|
1094
|
+
when :quarter
|
|
1095
|
+
4
|
|
1096
|
+
when :bimonth
|
|
1097
|
+
6
|
|
1098
|
+
when :month
|
|
1099
|
+
12
|
|
1100
|
+
when :semimonth
|
|
1101
|
+
24
|
|
1102
|
+
when :biweek
|
|
1103
|
+
26
|
|
1104
|
+
when :week
|
|
1105
|
+
52
|
|
1106
|
+
when :day
|
|
1107
|
+
first.leap? ? 366 : 365
|
|
1108
|
+
else
|
|
1109
|
+
raise ArgumentError, "indeterminate size of period (#{self})"
|
|
1110
|
+
end
|
|
1111
|
+
end
|
|
899
1112
|
end
|
data/lib/fat_period/version.rb
CHANGED
data/lib/fat_period.rb
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'date'
|
|
4
|
-
|
|
5
4
|
require 'active_support'
|
|
6
5
|
|
|
7
|
-
require 'fat_period/version'
|
|
8
|
-
require 'fat_period/date'
|
|
9
|
-
require 'fat_period/period'
|
|
10
|
-
|
|
11
6
|
require 'fat_core/range'
|
|
12
7
|
require 'fat_core/string'
|
|
13
|
-
|
|
14
8
|
require 'fat_date'
|
|
9
|
+
|
|
10
|
+
# Gem Overview (extracted from README.org by gem_docs)
|
|
11
|
+
#
|
|
12
|
+
# * Introduction
|
|
13
|
+
# ~FatPeriod~ provides a Ruby ~Period~ class for dealing with time periods of
|
|
14
|
+
# days, that is ranges whose endpoints are of class ~Date~. It's target is
|
|
15
|
+
# financial applications, but it serves well for any application where periods
|
|
16
|
+
# of time are useful. It builds on the [[https://github.com/ddoherty03/fat_date][fat_date]] gem, which provides
|
|
17
|
+
# enhancements to the ~Date~ class, especially its class method ~Date.spec~ for
|
|
18
|
+
# interpreting a rich set of "specs" as the beginning or end of a variety of
|
|
19
|
+
# calendar-related periods.
|
|
20
|
+
#
|
|
21
|
+
# In addition, set operations are provided for Period, as well as methods for
|
|
22
|
+
# breaking a larger periods into an array of smaller periods of various 'chunk'
|
|
23
|
+
# sizes that correspond to calendar-related periods such as days, weeks, months,
|
|
24
|
+
# and so forth.
|
|
25
|
+
module FatPeriod
|
|
26
|
+
require 'fat_period/version'
|
|
27
|
+
require 'fat_period/date'
|
|
28
|
+
require 'fat_period/period'
|
|
29
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fat_period
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel E. Doherty
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-11-06 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: fat_core
|
|
@@ -15,28 +15,28 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
18
|
+
version: '7.0'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '
|
|
25
|
+
version: '7.0'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: fat_date
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version:
|
|
32
|
+
version: 0.3.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version:
|
|
39
|
+
version: 0.3.0
|
|
40
40
|
email:
|
|
41
41
|
- ded@ddoherty.net
|
|
42
42
|
executables: []
|
|
@@ -51,6 +51,7 @@ files:
|
|
|
51
51
|
- CHANGELOG.org
|
|
52
52
|
- Gemfile
|
|
53
53
|
- LICENSE.txt
|
|
54
|
+
- README.md
|
|
54
55
|
- README.org
|
|
55
56
|
- Rakefile
|
|
56
57
|
- bin/console
|
|
@@ -77,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
77
78
|
- !ruby/object:Gem::Version
|
|
78
79
|
version: '0'
|
|
79
80
|
requirements: []
|
|
80
|
-
rubygems_version: 3.6.
|
|
81
|
+
rubygems_version: 3.6.2
|
|
81
82
|
specification_version: 4
|
|
82
83
|
summary: Implements a Period class as a Range of Dates.
|
|
83
84
|
test_files: []
|