Class: Tempr::DateTimeRange::SubRangeIterator

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Tempr::DateTimeRange
Defined in:
lib/tempr/date_time_range.rb

Overview

Iterators are defined by

  • ‘range`: base range (required)

  • ‘step`: repetition length (default = 1)

  • ‘adjust_range`: proc that adjusts base range before iteration (optional)

  • ‘offset`: proc that adjusts start of adjusted range prior to iteration (optional)

  • ‘increment`: proc that defines scale of each step (required)

  • ‘span`: proc that defines duration of each returned subrange (required)

  • ‘except`: proc(s) that don’t yield subrange if true of current step date (but don’t stop iteration)

  • ‘limit`: stop iteration after self.limit steps (yields)

TODO:

  • ‘until`: proc that stops iteration if true of current step date

Note that SubRangeIterator is coupled to DateTimeRange since it itself includes DateTimeRange (for chaining); However, otherwise it could be used just as well on other (e.g. numeric) ranges

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Tempr::DateTimeRange

#Apr, #April, #Aug, #August, #Dec, #December, #Feb, #February, #Fri, #Friday, #Jan, #January, #Jul, #July, #Jun, #June, #Mar, #March, #May, #Mon, #Monday, #Nov, #November, #Oct, #October, #Sat, #Saturday, #Sep, #September, #Sun, #Sunday, #Thu, #Thursday, #Tue, #Tuesday, #WEEKDAYS, #WEEKENDS, #Wed, #Wednesday, #adjacent_to?, #at_time, #between_times, #build_subrange, #day, #day_range, #each_april, #each_august, #each_day_of_month, #each_days, #each_days_of_week, #each_december, #each_february, #each_friday, #each_hours, #each_january, #each_july, #each_june, #each_march, #each_may, #each_minutes, #each_monday, #each_monthnum, #each_months, #each_november, #each_october, #each_saturday, #each_seconds, #each_september, #each_sunday, #each_thursday, #each_time_of_day, #each_tuesday, #each_wdays, #each_wednesday, #each_weekdays, #each_weekends, #each_weekends_including_friday, #each_weeks, #each_years, #friday, #hour, #intersection_with, #intersects?, #minute, #monday, #month, #on_day, #precedes?, #saturday, #second, #subsume?, #succeeds?, #sunday, #thursday, #time_range, #tuesday, #wday, #wednesday, #week, #within?, #year

Constructor Details

#initialize(range) {|_self| ... } ⇒ SubRangeIterator

Returns a new instance of SubRangeIterator.

Yields:

  • (_self)

Yield Parameters:



609
610
611
612
# File 'lib/tempr/date_time_range.rb', line 609

def initialize(range)
  self.range = range
  yield self if block_given?
end

Instance Attribute Details

#limitObject

Returns the value of attribute limit.



597
598
599
# File 'lib/tempr/date_time_range.rb', line 597

def limit
  @limit
end

#rangeObject

Returns the value of attribute range.



597
598
599
# File 'lib/tempr/date_time_range.rb', line 597

def range
  @range
end

#stepObject

Returns the value of attribute step.



597
598
599
# File 'lib/tempr/date_time_range.rb', line 597

def step
  @step
end

Instance Method Details

#adjust_range(&p) ⇒ Object



626
627
628
629
# File 'lib/tempr/date_time_range.rb', line 626

def adjust_range(&p)
  self.range_proc = p
  self
end

#by_step(n) ⇒ Object

‘stateless’ step enumerator simply generates infinite integer sequence if ruby already has such a facility built-in, let me know



704
705
706
707
708
709
710
711
# File 'lib/tempr/date_time_range.rb', line 704

def by_step(n)
  @step_enumerator ||= Enumerator.new do |y|
    i=0
    loop do
      y << i; i+=n
    end
  end
end

#cover?(dt) ⇒ Boolean

Returns:

  • (Boolean)


651
652
653
# File 'lib/tempr/date_time_range.rb', line 651

def cover?(dt)
  any? {|r| r.cover?(dt)}
end

#each(&b) ⇒ Object

Recursive madness… note this could possibly use cached results stored by #all method, similar to Sequel



658
659
660
661
662
663
664
665
666
667
668
669
# File 'lib/tempr/date_time_range.rb', line 658

def each(&b)
  if self.range.respond_to?(:each_by_step)
    self.range.each do |sub|
      each_by_step(sub, &b)
    end
  else
    each_by_step do |sub|
  #          puts "self.range = #{self.range} yielded: #{sub}"
      yield sub
    end
  end
end

#each_by_step(rng = self.range) ⇒ Object

Iteration

  1. adjust base range

  2. get offset

  3. for each step, 3.1. if limit reached, break 3.2. find begin of next subrange (step_proc) 3.3. find end of next subrange (span_proc) 3.4. check if begin in adjusted base range, stop iteration if not 3.5. check if begin matches any exceptions (exception_procs)

    3.5.1 if not, increment the yield count (i)
    3.5.2 and yield the subrange, extended with same modules as base range
    


682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
# File 'lib/tempr/date_time_range.rb', line 682

def each_by_step(rng=self.range)
  rng = range_proc.call(rng)
  #      puts "each_by_step range: #{rng}"
  initial = offset_proc.call(rng.begin)
  i=0
  by_step(self.step).each do |n|
    break if self.limit && self.limit <= i
    next_begin = step_proc.call(initial,n)
    next_end   = span_proc.call(next_begin)
    if rng.respond_to?(:cover?) && !rng.cover?(next_begin) 
      raise StopIteration
    end
    unless exception_procs.any? {|except| except.call(next_begin)}
      i+=1
      yield((next_begin...next_end).extend(*range_extensions))
    end
  end
end

#except(&p) ⇒ Object



646
647
648
649
# File 'lib/tempr/date_time_range.rb', line 646

def except(&p)
  exception_procs << p
  self
end

#increment(&p) ⇒ Object



636
637
638
639
# File 'lib/tempr/date_time_range.rb', line 636

def increment(&p)
  self.step_proc = p
  self
end

#limit_to(n) ⇒ Object

note: useful for chaining instead of limit=



621
622
623
624
# File 'lib/tempr/date_time_range.rb', line 621

def limit_to(n)
  self.limit = n
  self
end

#offset(&p) ⇒ Object



631
632
633
634
# File 'lib/tempr/date_time_range.rb', line 631

def offset(&p)
  self.offset_proc = p
  self
end

#range_extensionsObject

a bit hacky - used to extend concrete subranges with the same extensions as the range



602
603
604
605
606
607
# File 'lib/tempr/date_time_range.rb', line 602

def range_extensions
  @range_extensions ||= 
    class << self.range
      self.included_modules - [Kernel]
    end
end

#span(&p) ⇒ Object



641
642
643
644
# File 'lib/tempr/date_time_range.rb', line 641

def span(&p)
  self.span_proc = p
  self
end

#step_by(n) ⇒ Object

note: useful for chaining instead of step=



615
616
617
618
# File 'lib/tempr/date_time_range.rb', line 615

def step_by(n)
  self.step = n
  self
end