From: Dema Date: 2006-11-13T06:20:05+09:00 Subject: Re: VCR Program Manager (#101) Here is my solution (I extracted the Numeric extensions into a separate core_ext.rb along with an extension to Time): The key thing in the conflict resolution was partitioning the weekly from the specific candidate programs and picking the most recent addition. Cheers. # BEGIN -- program_manager.rb -- require 'core_ext' require 'program' class ProgramManager def initialize @programs = [] end # Query to determine if we should be recording at any particular # moment. It can be assumed that the VCR will query the program # manager at most twice per minute, and with always increasing minutes. # New programs may be added between two calls to #record?. # # This method must return either a +nil+, indicating to stop recording, # or don't start, or an +Integer+, which is the channel number we should # be recording. def record?(time) candidates = @programs.select { |p| p.on?(time) } weekly, specific = candidates.partition { |p| p.weekly? } return specific.last.channel unless specific.empty? return weekly.last.channel unless weekly.empty? nil end # Adds a new Program to the list of programs to record. def add(program) @programs << Program.new(program) end end # END -- program_manager.rb -- # BEGIN -- program.rb -- require 'core_ext' class Program WEEKDAYS = { 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3, 'thu' => 4, 'fri' => 5, 'sat' => 6 } attr_reader :start, :end, :channel, :days def initialize(program) @start = program[:start] @end = program[:end] @channel = program[:channel] @days = program[:days] raise "Missing start or end" if @start.nil? || @end.nil? raise "Wrong start or end types" unless (@start.is_a?(Time) && @end.is_a?(Time)) || (@start.is_a?(Integer) && @end.is_a?(Integer)) raise "Invalid program" if weekly? && (@start.is_a?(Time) || @end.is_a?(Time)) raise "End must come after Start" if !weekly? && @start > @end raise "Missing channel" if !@channel.is_a?(Integer) raise "Invalid weekday" if @days.is_a?(Array) && @days.any? { |day| WEEKDAYS[day] == nil } end def weekly? !@days.nil? end def on?(time) if weekly? #weekly program for day in @days if WEEKDAYS[day] == time.wday return @channel if time.secs >= @start && time.secs <= @end end end else #specific time return @channel if time >= @start && time <= @end end nil end end # END -- program.rb -- # BEGIN -- core_ext.rb -- class Numeric # Number of seconds since midnight def hours (self * 60).minutes end def minutes self * 60 end def seconds self end alias_method :hour, :hours alias_method :minute, :minutes alias_method :second, :seconds end class Time def secs self.hour * 3600 + self.min * 60 + self.sec end end # END -- core_ext.rb --