lib/hiccup/inferable/guesser.rb in hiccup-0.5.14 vs lib/hiccup/inferable/guesser.rb in hiccup-0.5.15

- old
+ new

@@ -1,45 +1,45 @@ require 'hiccup/inferable/scorer' module Hiccup module Inferable class Guesser - + 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 - + attr_reader :max_complexity - + def allow_skips? @allow_skips end - - - + + + 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 - + 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 @@ -47,30 +47,30 @@ schedule.skip = skip end end end end - + 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| @@ -79,11 +79,11 @@ 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 @@ -93,26 +93,26 @@ end end end end end - + 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 @@ -123,27 +123,27 @@ end end end end end - + def skip_range return 1..1 unless allow_skips? 1...5 end - - - + + + # Expects a hash of values grouped by popularity # Yields the most popular values first, and then # increasingly less popular values 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 - + end end end