Class: Timely::TemporalPatterns::Pattern
- Inherits:
-
Object
- Object
- Timely::TemporalPatterns::Pattern
- Defined in:
- lib/timely/temporal_patterns/pattern.rb
Instance Attribute Summary collapse
-
#frequency ⇒ Object
readonly
Returns the value of attribute frequency.
-
#intervals ⇒ Object
readonly
Returns the value of attribute intervals.
Instance Method Summary collapse
- #<=>(other) ⇒ Object
-
#datetimes ⇒ Object
Convert each interval to a list of datetimes.
- #first_datetime ⇒ Object
-
#initialize(ranges, frequency) ⇒ Pattern
constructor
A new instance of Pattern.
-
#join(other) ⇒ Object
Join with other IF same frequency AND same number of intervals.
- #last_datetime ⇒ Object
- #match?(datetimes) ⇒ Boolean
- #ranges ⇒ Object
- #surrounding_interval ⇒ Object (also: #interval)
- #to_s ⇒ Object
Constructor Details
#initialize(ranges, frequency) ⇒ Pattern
Returns a new instance of Pattern.
8 9 10 11 12 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 8 def initialize(ranges, frequency) @intervals = Array.wrap(ranges).map { |r| Interval.new(r.first, r.last) }.sort_by(&:first_datetime) @frequency = Frequency.new(frequency) fix_frequency end |
Instance Attribute Details
#frequency ⇒ Object (readonly)
Returns the value of attribute frequency.
6 7 8 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 6 def frequency @frequency end |
#intervals ⇒ Object (readonly)
Returns the value of attribute intervals.
6 7 8 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 6 def intervals @intervals end |
Instance Method Details
#<=>(other) ⇒ Object
57 58 59 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 57 def <=>(other) self.intervals.count <=> other.intervals.count end |
#datetimes ⇒ Object
Convert each interval to a list of datetimes
15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 15 def datetimes intervals.map do |interval| datetimes = [] datetime = interval.first_datetime while datetime <= interval.last_datetime datetimes << datetime datetime = datetime + frequency.duration end datetimes end end |
#first_datetime ⇒ Object
31 32 33 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 31 def first_datetime surrounding_interval.first_datetime end |
#join(other) ⇒ Object
Join with other IF same frequency AND same number of intervals
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 62 def join(other) return nil unless self.frequency == other.frequency = self.datetimes.map { |datetimes_within_an_interval| back_one = datetimes_within_an_interval.first - frequency.duration forward_one = datetimes_within_an_interval.last + frequency.duration [back_one] + datetimes_within_an_interval + [forward_one] } joint_ranges = [] # Look for overlaps, where an overlap may be 'off by 1' -- hence the 'expanded_datetimes' # ...but start with other and join to each of it's intervals. # # Remember that 'pattern.datetimes' returns a list of datetimes per interval other.datetimes.each do |other_datetimes_within_an_interval| joinable_datetimes = .find { || other_datetimes_within_an_interval.any? { |d| .include?(d) } } break unless joinable_datetimes # Joint ranges should be those that overlap # # This is buggy, because joinable_datetimes is a list of datetimes per interval that overlap # Excluding the first doesn't make sense # # Instead, we should exclude the first AND last for each element within joinable_datetimes joint_datetimes = (other_datetimes_within_an_interval + joinable_datetimes[1...-1]).sort joint_ranges << (joint_datetimes.first..joint_datetimes.last) end # This seems to be trying to say "Only join when we got one for each interval of self" # ...it also seems too restrictive... # # What if other includes multiple intervals of self? # Then we don't need same number of intervals # # Also might be wrong in other ways, it's tricky to tell if joint_ranges.size == self.intervals.size Pattern.new(joint_ranges, frequency.duration) end end |
#last_datetime ⇒ Object
35 36 37 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 35 def last_datetime surrounding_interval.last_datetime end |
#match?(datetimes) ⇒ Boolean
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 44 def match?(datetimes) datetimes = Array.wrap(datetimes).map(&:to_datetime) intervals.each do |interval| current_datetime = interval.first_datetime while current_datetime <= interval.last_datetime datetimes.delete_if { |datetime| datetime == current_datetime } return true if datetimes.empty? current_datetime = current_datetime + frequency.duration end end false end |
#ranges ⇒ Object
27 28 29 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 27 def ranges intervals.map { |i| (i.first_datetime..i.last_datetime) } end |
#surrounding_interval ⇒ Object Also known as: interval
39 40 41 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 39 def surrounding_interval Interval.surrounding(intervals) end |
#to_s ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/timely/temporal_patterns/pattern.rb', line 109 def to_s single_date_intervals, multiple_dates_intervals = intervals.partition { |i| i.first_datetime == i.last_datetime} patterns_strings = if multiple_dates_intervals.empty? single_date_intervals.map(&:to_s) else interval_surrounding_multiple_dates = Interval.surrounding(multiple_dates_intervals) multiple_dates_intervals_string = case frequency.unit when :years "every #{multiple_dates_intervals.map { |i| "#{i.first_datetime.day.ordinalize} of #{i.first_datetime.strftime('%B')}" }.uniq.to_sentence} #{interval_surrounding_multiple_dates}" when :months "every #{multiple_dates_intervals.map { |i| i.first_datetime.day.ordinalize }.uniq.to_sentence} of the month #{interval_surrounding_multiple_dates}" when :weeks weekdays = multiple_dates_intervals.map { |i| i.first_datetime.strftime('%A') }.uniq if weekdays.count == 7 "every day #{interval_surrounding_multiple_dates}" else "every #{weekdays.to_sentence} #{interval_surrounding_multiple_dates}" end when :days if multiple_dates_intervals.any? { |i| i.first_datetime != i.first_datetime.beginning_of_day } "every day at #{multiple_dates_intervals.map { |i| i.first_datetime.strftime("%I:%M %p") }.to_sentence} #{interval_surrounding_multiple_dates}" else "every day #{interval_surrounding_multiple_dates}" end else "#{frequency} #{multiple_dates_intervals.map(&:to_s).to_sentence}" end [multiple_dates_intervals_string] + single_date_intervals.map(&:to_s) end patterns_strings.to_sentence end |