Class: Hiccup::Inferable::Guesser

Inherits:
Object
  • Object
show all
Defined in:
lib/hiccup/inferable/guesser.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, options = {}) ⇒ Guesser

Returns a new instance of Guesser.



7
8
9
10
11
12
# File 'lib/hiccup/inferable/guesser.rb', line 7

def initialize(klass, options={})
  @klass = klass
  @verbose = options.fetch(:verbose, false)
  @allow_skips = options.fetch(:allow_skips, true)
  @max_complexity = options.fetch(:max_complexity, 3)
end

Instance Attribute Details

#max_complexityObject (readonly)

Returns the value of attribute max_complexity.



14
15
16
# File 'lib/hiccup/inferable/guesser.rb', line 14

def max_complexity
  @max_complexity
end

Instance Method Details

#allow_skips?Boolean

Returns:

  • (Boolean)


16
17
18
# File 'lib/hiccup/inferable/guesser.rb', line 16

def allow_skips?
  @allow_skips
end

#enumerate_by_popularity(values_by_popularity) ⇒ Object

Expects a hash of values grouped by popularity Yields the most popular values first, and then increasingly less popular values



139
140
141
142
143
144
145
# File 'lib/hiccup/inferable/guesser.rb', line 139

def enumerate_by_popularity(values_by_popularity)
  popularities = values_by_popularity.keys.sort.reverse
  popularities.length.times do |i|
    at_popularities = popularities.take(i + 1)
    yield values_by_popularity.values_at(*at_popularities).flatten(1)
  end
end

#generate_guesses(dates) ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/hiccup/inferable/guesser.rb', line 22

def generate_guesses(dates)
  @start_date = dates.first
  @end_date = dates.last
  [].tap do |guesses|
    guesses.concat generate_yearly_guesses(dates)
    guesses.concat generate_monthly_guesses(dates)
    guesses.concat generate_weekly_guesses(dates)
  end
end

#generate_monthly_guesses(dates) ⇒ Object



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
# File 'lib/hiccup/inferable/guesser.rb', line 53

def generate_monthly_guesses(dates)
  histogram_of_patterns = dates.to_histogram do |date|
    [date.get_nth_wday_of_month, Date::DAYNAMES[date.wday]]
  end
  patterns_by_popularity = histogram_of_patterns.flip
  
  histogram_of_days = dates.to_histogram(&:day)
  days_by_popularity = histogram_of_days.flip
  
  if @verbose
    puts "",
         "  monthly analysis:",
         "    input: #{dates.inspect}",
         "    histogram (weekday): #{histogram_of_patterns.inspect}",
         "    by_popularity (weekday): #{patterns_by_popularity.inspect}",
         "    histogram (day): #{histogram_of_days.inspect}",
         "    by_popularity (day): #{days_by_popularity.inspect}"
  end
  
  [].tap do |guesses|
    skip_range.each do |skip|
      enumerate_by_popularity(days_by_popularity) do |days|
        next if days.length > max_complexity
        guesses << @klass.new.tap do |schedule|
          schedule.kind = :monthly
          schedule.start_date = @start_date
          schedule.end_date = @end_date
          schedule.skip = skip
          schedule.monthly_pattern = days
        end
      end
      
      enumerate_by_popularity(patterns_by_popularity) do |patterns|
        next if patterns.length > max_complexity
        guesses << @klass.new.tap do |schedule|
          schedule.kind = :monthly
          schedule.start_date = @start_date
          schedule.end_date = @end_date
          schedule.skip = skip
          schedule.monthly_pattern = patterns
        end
      end
    end
  end
end

#generate_weekly_guesses(dates) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/hiccup/inferable/guesser.rb', line 99

def generate_weekly_guesses(dates)
  [].tap do |guesses|
    histogram_of_wdays = dates.to_histogram do |date|
      Date::DAYNAMES[date.wday]
    end
    wdays_by_popularity = histogram_of_wdays.flip
    
    if @verbose
      puts "",
           "  weekly analysis:",
           "    input: #{dates.inspect}",
           "    histogram: #{histogram_of_wdays.inspect}",
           "    by_popularity: #{wdays_by_popularity.inspect}"
    end
    
    skip_range.each do |skip|
      enumerate_by_popularity(wdays_by_popularity) do |wdays|
        next if wdays.length > max_complexity
        guesses << @klass.new.tap do |schedule|
          schedule.kind = :weekly
          schedule.start_date = @start_date
          schedule.end_date = @end_date
          schedule.skip = skip
          schedule.weekly_pattern = wdays
        end
      end
    end
  end
end

#generate_yearly_guesses(dates) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/hiccup/inferable/guesser.rb', line 32

def generate_yearly_guesses(dates)
  histogram_of_patterns = dates.to_histogram do |date|
    [date.month, date.day]
  end
  patterns_by_popularity = histogram_of_patterns.flip # => {1 => [...], 2 => [...], 5 => [a, b]}
  highest_popularity = patterns_by_popularity.keys.max # => 5
  most_popular = patterns_by_popularity[highest_popularity].first # => a
  start_date = Date.new(@start_date.year, *most_popular)
  
  [].tap do |guesses|
    skip_range.each do |skip|
      guesses << @klass.new.tap do |schedule|
        schedule.kind = :annually
        schedule.start_date = start_date
        schedule.end_date = @end_date
        schedule.skip = skip
      end
    end
  end
end

#skip_rangeObject



129
130
131
132
# File 'lib/hiccup/inferable/guesser.rb', line 129

def skip_range
  return 1..1 unless allow_skips?
  1...5
end