Class: Period
- Inherits:
-
Object
- Object
- Period
- Includes:
- Comparable, Enumerable
- Defined in:
- lib/fat_core/period.rb
Instance Attribute Summary collapse
-
#first ⇒ Object
Returns the value of attribute first.
-
#last ⇒ Object
Returns the value of attribute last.
Class Method Summary collapse
- .chunk_sym_to_days(sym) ⇒ Object
-
.chunk_sym_to_max_days(sym) ⇒ Object
The largest number of days possible in each chunk.
- .chunk_syms ⇒ Object
-
.days_to_chunk_sym(days) ⇒ Object
This is only used for inferring statement frequency based on the number of days between statements, so it will not consider all possible chunks, only :year, :quarter, :month, and :week.
-
.parse_spec(from = 'today', to = nil) ⇒ Object
Return a period based on two date specs (see Date.parse_spec), a ”‘from’ and a ‘to’ spec.
Instance Method Summary collapse
- #<=>(other) ⇒ Object
- #==(other) ⇒ Object
-
#chunk_name ⇒ Object
Name for a period not necessarily ending on calendar boundaries.
-
#chunk_sym ⇒ Object
returns the chunk sym represented by the period.
-
#chunks(size: :month, partial_first: false, partial_last: false, round_up_last: false) ⇒ Object
Return an array of Periods wholly-contained within self in chunks of size, defaulting to monthly chunks.
- #contains?(date) ⇒ Boolean
- #difference(other) ⇒ Object (also: #-)
-
#each ⇒ Object
TO_DATE = Period.new(Date::BOT, Date.current) FOREVER = Period.new(Date::BOT, Date::EOT).
- #gaps(periods) ⇒ Object
-
#has_overlaps_within?(periods) ⇒ Boolean
Return whether any of the Periods that are within self overlap one another.
-
#initialize(first, last) ⇒ Period
constructor
A new instance of Period.
- #intersection(other) ⇒ Object (also: #&)
- #length ⇒ Object
- #overlaps?(other) ⇒ Boolean
- #proper_subset_of?(other) ⇒ Boolean
- #proper_superset_of?(other) ⇒ Boolean
-
#size ⇒ Object
Days in period.
- #spanned_by?(periods) ⇒ Boolean
- #subset_of?(other) ⇒ Boolean
- #superset_of?(other) ⇒ Boolean
-
#tex_quote ⇒ Object
Allow erb documents can directly interpolate ranges.
- #to_range ⇒ Object
- #to_s ⇒ Object
- #union(other) ⇒ Object (also: #+)
Methods included from Enumerable
Constructor Details
permalink #initialize(first, last) ⇒ Period
Returns a new instance of Period.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/fat_core/period.rb', line 8 def initialize(first, last) case first when String begin first = Date.parse(first) rescue ArgumentError => ex if ex. =~ /invalid date/ raise ArgumentError, "you gave an invalid date '#{first}'" else raise end end when Date first = first else raise ArgumentError, "use Date or String to initialize Period" end case last when String begin last = Date.parse(last) rescue ArgumentError => ex if ex. =~ /invalid date/ raise ArgumentError, "you gave an invalid date '#{last}'" else raise end end when Date last = last else raise ArgumentError, "use Date or String to initialize Period" end @first = first @last = last if @first > @last raise ArgumentError, "Period's first date is later than its last date" end end |
Instance Attribute Details
permalink #first ⇒ Object
Returns the value of attribute first.
6 7 8 |
# File 'lib/fat_core/period.rb', line 6 def first @first end |
permalink #last ⇒ Object
Returns the value of attribute last.
6 7 8 |
# File 'lib/fat_core/period.rb', line 6 def last @last end |
Class Method Details
permalink .chunk_sym_to_days(sym) ⇒ Object
[View source]
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/fat_core/period.rb', line 101 def self.chunk_sym_to_days(sym) case sym when :day 1 when :week 7 when :biweek 14 when :semimonth 15 when :month 30 when :bimonth 60 when :quarter 90 when :year 365 when :irregular 30 else raise ArgumentError, "unknown chunk sym '#{sym}'" end end |
permalink .chunk_sym_to_max_days(sym) ⇒ Object
The largest number of days possible in each chunk
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/fat_core/period.rb', line 127 def self.chunk_sym_to_max_days(sym) case sym when :semimonth 16 when :month 31 when :bimonth 62 when :quarter 92 when :year 366 else chunk_sym_to_days(sym) end end |
permalink .chunk_syms ⇒ Object
[View source]
96 97 98 99 |
# File 'lib/fat_core/period.rb', line 96 def self.chunk_syms [:day, :week, :biweek, :semimonth, :month, :bimonth, :quarter, :year, :irregular] end |
permalink .days_to_chunk_sym(days) ⇒ Object
This is only used for inferring statement frequency based on the number of days between statements, so it will not consider all possible chunks, only :year, :quarter, :month, and :week. And distinguishing between :semimonth and :biweek is impossible anyway. Since statement dates can bounce around quite a bit in my experience, this is really fuzzy. For example, one of my banks does monthly statements “around” the 10th of the month, but the 10th can get pushed off by holidays, weekends, etc., so a “quarter” here is much broader than the calendar definition. Ditto for the others, but since statements are most likely monthly, we default to :month.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/fat_core/period.rb', line 154 def self.days_to_chunk_sym(days) case days when 356..376 :year when 86..96 :quarter when 26..33 :month when 7 :week when 1 :day else :irregular end end |
permalink .parse_spec(from = 'today', to = nil) ⇒ Object
Return a period based on two date specs (see Date.parse_spec), a ”‘from’ and a ‘to’ spec. If the to-spec is not given or is nil, the from-spec is used for both the from- and to-spec. If no from-spec is given, return today as the period.
54 55 56 57 58 |
# File 'lib/fat_core/period.rb', line 54 def self.parse_spec(from = 'today', to = nil) to ||= from from ||= to Period.new(Date.parse_spec(from, :from), Date.parse_spec(to, :to)) end |
Instance Method Details
permalink #<=>(other) ⇒ Object
[View source]
187 188 189 |
# File 'lib/fat_core/period.rb', line 187 def <=>(other) [first, size] <=> [other.first, other.size] end |
permalink #==(other) ⇒ Object
[View source]
183 184 185 |
# File 'lib/fat_core/period.rb', line 183 def ==(other) first == other.first && last == other.last end |
permalink #chunk_name ⇒ Object
Name for a period not necessarily ending on calendar boundaries. For example, in reporting reconciliation, we want the period from Feb 11, 2014, to March 10, 2014, be called the ‘Month ending March 10, 2014,’ event though the period is not a calendar month. Using the stricter Period#chunk_sym, would not allow such looseness.
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/fat_core/period.rb', line 293 def chunk_name case Period.days_to_chunk_sym(length) when :year 'Year' when :quarter 'Quarter' when :bimonth 'Bi-month' when :month 'Month' when :semimonth 'Semi-month' when :biweek 'Bi-week' when :week 'Week' when :day 'Day' else 'Period' end end |
permalink #chunk_sym ⇒ Object
returns the chunk sym represented by the period
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/fat_core/period.rb', line 259 def chunk_sym if first.beginning_of_year? && last.end_of_year? && (365..366) === last - first + 1 :year elsif first.beginning_of_quarter? && last.end_of_quarter? && (90..92) === last - first + 1 :quarter elsif first.beginning_of_bimonth? && last.end_of_bimonth? && (58..62) === last - first + 1 :bimonth elsif first.beginning_of_month? && last.end_of_month? && (28..31) === last - first + 1 :month elsif first.beginning_of_semimonth? && last.end_of_semimonth && (13..16) === last - first + 1 :semimonth elsif first.beginning_of_biweek? && last.end_of_biweek? && last - first + 1 == 14 :biweek elsif first.beginning_of_week? && last.end_of_week? && last - first + 1 == 7 :week elsif first == last :day else :irregular end end |
permalink #chunks(size: :month, partial_first: false, partial_last: false, round_up_last: false) ⇒ Object
Return an array of Periods wholly-contained within self in chunks of size, defaulting to monthly chunks. Partial chunks at the beginning and end of self are not included unless partial_first or partial_last, respectively, are set true. The last chunk can be made to extend beyond the end of self to make it a whole chunk if round_up_last is set true, in which case, partial_last is ignored.
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
# File 'lib/fat_core/period.rb', line 351 def chunks(size: :month, partial_first: false, partial_last: false, round_up_last: false) size = size.to_sym result = [] chunk_start = first.dup while chunk_start <= last case size when :year unless partial_first until chunk_start.beginning_of_year? chunk_start += 1.day end end chunk_end = chunk_start.end_of_year when :quarter unless partial_first until chunk_start.beginning_of_quarter? chunk_start += 1.day end end chunk_end = chunk_start.end_of_quarter when :bimonth unless partial_first until chunk_start.beginning_of_bimonth? chunk_start += 1.day end end chunk_end = (chunk_start.end_of_month + 1.day).end_of_month when :month unless partial_first until chunk_start.beginning_of_month? chunk_start += 1.day end end chunk_end = chunk_start.end_of_month when :semimonth unless partial_first until chunk_start.beginning_of_semimonth? chunk_start += 1.day end end chunk_end = chunk_start.end_of_semimonth when :biweek unless partial_first until chunk_start.beginning_of_biweek? chunk_start += 1.day end end chunk_end = chunk_start.end_of_biweek when :week unless partial_first until chunk_start.beginning_of_week? chunk_start += 1.day end end chunk_end = chunk_start.end_of_week when :day chunk_end = chunk_start else chunk_end = last end if chunk_end <= last result << Period.new(chunk_start, chunk_end) else if round_up_last result << Period.new(chunk_start, chunk_end) elsif partial_last result << Period.new(chunk_start, last) else break end end chunk_start = result.last.last + 1.day end result end |
permalink #contains?(date) ⇒ Boolean
316 317 318 319 320 321 322 323 324 |
# File 'lib/fat_core/period.rb', line 316 def contains?(date) if date.respond_to?(:to_date) date = date.to_date end unless (date.is_a? Date) raise ArgumentError, "argument must be a Date" end self.to_range.cover?(date) end |
permalink #difference(other) ⇒ Object Also known as: -
[View source]
253 254 255 |
# File 'lib/fat_core/period.rb', line 253 def difference(other) self.to_range.difference(other.to_range) end |
permalink #each ⇒ Object
TO_DATE = Period.new(Date::BOT, Date.current) FOREVER = Period.new(Date::BOT, Date::EOT)
88 89 90 91 92 93 94 |
# File 'lib/fat_core/period.rb', line 88 def each d = first while d <= last yield d d = d + 1.day end end |
permalink #gaps(periods) ⇒ Object
[View source]
340 341 342 343 |
# File 'lib/fat_core/period.rb', line 340 def gaps(periods) to_range.gaps(periods.map { |p| p.to_range }). map { |r| Period.new(r.first, r.last)} end |
permalink #has_overlaps_within?(periods) ⇒ Boolean
Return whether any of the Periods that are within self overlap one another
332 333 334 |
# File 'lib/fat_core/period.rb', line 332 def has_overlaps_within?(periods) self.to_range.has_overlaps_within?(periods.map{ |p| p.to_range}) end |
permalink #intersection(other) ⇒ Object Also known as: &
[View source]
243 244 245 |
# File 'lib/fat_core/period.rb', line 243 def intersection(other) self.to_range.intersection(other.to_range) end |
permalink #length ⇒ Object
[View source]
175 176 177 |
# File 'lib/fat_core/period.rb', line 175 def length size end |
permalink #overlaps?(other) ⇒ Boolean
239 240 241 |
# File 'lib/fat_core/period.rb', line 239 def overlaps?(other) self.to_range.overlaps?(other.to_range) end |
permalink #proper_subset_of?(other) ⇒ Boolean
227 228 229 |
# File 'lib/fat_core/period.rb', line 227 def proper_subset_of?(other) to_range.proper_subset_of?(other.to_range) end |
permalink #proper_superset_of?(other) ⇒ Boolean
235 236 237 |
# File 'lib/fat_core/period.rb', line 235 def proper_superset_of?(other) to_range.proper_superset_of?(other.to_range) end |
permalink #size ⇒ Object
Days in period
215 216 217 |
# File 'lib/fat_core/period.rb', line 215 def size to_range.size end |
permalink #spanned_by?(periods) ⇒ Boolean
336 337 338 |
# File 'lib/fat_core/period.rb', line 336 def spanned_by?(periods) to_range.spanned_by?(periods.map { |p| p.to_range }) end |
permalink #subset_of?(other) ⇒ Boolean
223 224 225 |
# File 'lib/fat_core/period.rb', line 223 def subset_of?(other) to_range.subset_of?(other.to_range) end |
permalink #superset_of?(other) ⇒ Boolean
231 232 233 |
# File 'lib/fat_core/period.rb', line 231 def superset_of?(other) to_range.superset_of?(other.to_range) end |
permalink #tex_quote ⇒ Object
Allow erb documents can directly interpolate ranges
210 211 212 |
# File 'lib/fat_core/period.rb', line 210 def tex_quote "#{first.iso}--#{last.iso}" end |
permalink #to_range ⇒ Object
[View source]
179 180 181 |
# File 'lib/fat_core/period.rb', line 179 def to_range (first..last) end |
permalink #to_s ⇒ Object
[View source]
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/fat_core/period.rb', line 191 def to_s if first.beginning_of_year? && last.end_of_year? && first.year == last.year "#{first.year}" elsif first.beginning_of_quarter? && last.end_of_quarter? && first.year == last.year && first.quarter == last.quarter "#{first.year}-#{first.quarter}Q" elsif first.beginning_of_month? && last.end_of_month? && first.year == last.year && first.month == last.month "#{first.year}-%02d" % first.month else "#{first.iso} to #{last.iso}" end end |
permalink #union(other) ⇒ Object Also known as: +
[View source]
248 249 250 |
# File 'lib/fat_core/period.rb', line 248 def union(other) self.to_range.union(other.to_range) end |