lib/fat_period/period.rb in fat_period-1.1.0 vs lib/fat_period/period.rb in fat_period-1.1.1
- old
+ new
@@ -267,17 +267,27 @@
# An Array of the valid Symbols for calendar chunks plus the Symbol :irregular
# for other periods.
CHUNKS = %i[day week biweek semimonth month bimonth quarter
half year irregular].freeze
+ CHUNK_ORDER = {}
+ CHUNKS.each_with_index do |c, i|
+ CHUNK_ORDER[c] = i
+ end
+ CHUNK_ORDER.freeze
+
# An Array of Ranges for the number of days that can be covered by each chunk.
CHUNK_RANGE = {
day: (1..1), week: (7..7), biweek: (14..14), semimonth: (15..16),
month: (28..31), bimonth: (59..62), quarter: (90..92),
half: (180..183), year: (365..366)
}.freeze
+ def self.chunk_cmp(chunk1, chunk2)
+ CHUNK_ORDER[chunk1] <=> CHUNK_ORDER[chunk2]
+ end
+
# Return a period representing a chunk containing a given Date.
def self.day_containing(date)
Period.new(date, date)
end
@@ -311,10 +321,23 @@
def self.year_containing(date)
Period.new(date.beginning_of_year, date.end_of_year)
end
+ def self.chunk_containing(date, chunk)
+ raise ArgumentError, 'chunk is nil' unless chunk
+
+ chunk = chunk.to_sym
+ unless CHUNKS.include?(chunk)
+ raise ArgumentError, "unknown chunk name: #{chunk}"
+ end
+
+ date = Date.ensure_date(date)
+ method = "#{chunk}_containing".to_sym
+ send(method, date)
+ end
+
# Return a Period representing a chunk containing today.
def self.this_day
day_containing(Date.current)
end
@@ -548,32 +571,51 @@
# @param round_up_last [Boolean] allow the last period in the returned array
# to extend beyond the end of self.
# @return [Array<Period>] periods that subdivide self into chunks of size, `size`
def chunks(size: :month, partial_first: false, partial_last: false,
round_up_last: false)
- size = size.to_sym
- unless CHUNKS.include?(size)
- raise ArgumentError, "unknown chunk size '#{size}'"
+ chunk_size = size.to_sym
+ unless CHUNKS.include?(chunk_size)
+ raise ArgumentError, "unknown chunk size '#{chunk_size}'"
end
+ containing_period = Period.chunk_containing(first, chunk_size)
+ return [dup] if self == containing_period
+
+ # Period too small for even a single chunk and is wholly-contained by a
+ # single chunk.
result = []
+ if proper_subset_of?(containing_period)
+ result =
+ if partial_first || partial_last
+ if round_up_last
+ [containing_period]
+ else
+ [dup]
+ end
+ else
+ []
+ end
+ return result
+ end
+
chunk_start = first.dup
- chunk_end = chunk_start.end_of_chunk(size)
- if chunk_start.beginning_of_chunk?(size) || partial_first
+ chunk_end = chunk_start.end_of_chunk(chunk_size)
+ if chunk_start.beginning_of_chunk?(chunk_size) || partial_first
# Keep the first chunk if it's whole or partials allowed
result << Period.new(chunk_start, chunk_end)
chunk_start = chunk_end + 1.day
- chunk_end = chunk_start.end_of_chunk(size)
+ chunk_end = chunk_start.end_of_chunk(chunk_size)
else
# Discard the partial first or move to next whole chunk
chunk_start = chunk_end + 1.day
- chunk_end = chunk_start.end_of_chunk(size)
+ chunk_end = chunk_start.end_of_chunk(chunk_size)
end
# Add Whole chunks
while chunk_end <= last
result << Period.new(chunk_start, chunk_end)
chunk_start = chunk_end + 1.day
- chunk_end = chunk_start.end_of_chunk(size)
+ chunk_end = chunk_start.end_of_chunk(chunk_size)
end
# Possibly append the final chunk to result
if chunk_start < last
if round_up_last
result << Period.new(chunk_start, chunk_end)