Module: Hiccup::Inferable::ClassMethods

Defined in:
lib/hiccup/inferable.rb

Instance Method Summary collapse

Instance Method Details

#assert_date!(date) ⇒ Object



107
108
109
110
# File 'lib/hiccup/inferable.rb', line 107

def assert_date!(date)
  return date if date.is_a?(Date)
  date.to_date rescue raise_invalid_dates_error!
end

#extract_array_of_dates!(dates) ⇒ Object



102
103
104
105
# File 'lib/hiccup/inferable.rb', line 102

def extract_array_of_dates!(dates)
  raise_invalid_dates_error! unless dates.respond_to?(:each)
  dates.map { |date| assert_date!(date) }.sort
end

#infer(dates, options = {}) ⇒ Object



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
49
50
51
52
53
54
55
56
57
58
59
60
61
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
# File 'lib/hiccup/inferable.rb', line 14

def infer(dates, options={})
  allow_null_schedules = options.fetch(:allow_null_schedules, false)
  verbosity = options.fetch(:verbosity, (options[:verbose] ? 1 : 0)) # 0, 1, or 2
  
  dates = extract_array_of_dates!(dates)
  enumerator = DatesEnumerator.new(dates)
  guesser = Guesser.new(self, {verbose: verbosity >= 2})
  schedules = []
  
  confidences = []
  high_confidence_threshold = 0.6
  min_confidence_threshold  = 0.35
  
  last_confident_schedule = nil
  iterations_since_last_confident_schedule = 0
  
  until enumerator.done?
    date = enumerator.next
    guesser << date
    confidence = guesser.confidence.to_f
    confidences << confidence
    predicted = guesser.predicted?(date)
    
    # if the last two confidences are both below a certain
    # threshhold and both declining, back up to where we
    # started to go wrong and start a new schedule.
    
    confident = !(confidences.length >= 3 && (
                  (confidences[-1] < high_confidence_threshold &&
                   confidences[-2] < high_confidence_threshold &&
                   confidences[-1] < confidences[-2] &&
                   confidences[-2] < confidences[-3]) ||
                  (confidences[-1] < min_confidence_threshold &&
                   confidences[-2] < min_confidence_threshold)))
    
    if predicted && confidence >= min_confidence_threshold
      iterations_since_last_confident_schedule = 0
      last_confident_schedule = guesser.schedule
    else
      iterations_since_last_confident_schedule += 1
    end
    
    rewind_by = iterations_since_last_confident_schedule == guesser.count ? iterations_since_last_confident_schedule - 1 : iterations_since_last_confident_schedule
    
    
    
    if verbosity >= 1
      output = "  #{enumerator.index.to_s.rjust(3)} #{date}"
      output << " #{"[#{guesser.count}]".rjust(5)}  =>  "
      output << "~#{(guesser.confidence.to_f * 100).to_i.to_s.rjust(2, "0")} @ "
      output << guesser.schedule.humanize.ljust(130)
      output << "  :( move back #{rewind_by}" unless confident
      puts output
    end
    
    
    
    unless confident
      
      if last_confident_schedule
        schedules << last_confident_schedule
      elsif allow_null_schedules
        guesser.dates.take(guesser.count - rewind_by).each do |date|
          schedules << self.new(:kind => :never, :start_date => date)
        end
      end
      
      enumerator.rewind_by(rewind_by)
      guesser.restart!
      confidences = []
      iterations_since_last_confident_schedule = 0
      last_confident_schedule = nil
    end
  end
  
  if last_confident_schedule
    schedules << last_confident_schedule
  elsif allow_null_schedules
    guesser.dates.each do |date|
      schedules << self.new(:kind => :never, :start_date => date)
    end
  end
  
  schedules
end

#raise_invalid_dates_error!Object

Raises:

  • (ArgumentError)


112
113
114
# File 'lib/hiccup/inferable.rb', line 112

def raise_invalid_dates_error!
  raise ArgumentError.new("Inferable.infer expects to receive a collection of dates")
end