On 11/15/06, James Edward Gray II <james / grayproductions.net> wrote:
> On Nov 13, 2006, at 5:56 PM, Jamie Macey wrote:
>
> > Rule of the day was the simplest thing that could possibly work.  As
> > such, I didn't feel the need to split the logic out into a separate
> > Program class, but I kept two arrays of prospective programs - one for
> > recurring and one for one-shot.
>
> When I was new from to Ruby, from Perl, I use to think those ad hoc
> data structures were "the simplest thing" too.  With a fair amount of
> Ruby experience now, I'm not so sure though.
>
> For example, have a look at Dale Martenson's solution, which is very
> close to your own in size.  Dale used a Program class.
>
> In fact, Program could be as simple as:
>
>    Program = Struct.new(:start_time, :end_time, :channel, :days)

I think that there's a trade-off here.  If you have a stupid (no
internal logic) Program class, you can trade a very simple add method
for a more complicated record? method.

My position on it is that if I'm going to be leaving the brunt of the
logic in the ProgramManager, I don't think there's a huge difference
between nested arrays, a struct, or a class being the holder of the
data.

That being said, on a lark I did a bit of refactoring and tried to
move as much logic out of the ProgramManager into an actual Program
class - the results are below.

I definitely prefer the second version.  It's got 10 more lines of
actual code, but there's less random logic strewn about (and the logic
is simpler).  There's a definite separation of responsibilities -
Program just does querying, ProgramManager handles priorities.

> I'm not saying anything about your solution here.  Just thinking out
> loud in hopes of inspiring discussion...  ;)

Discussion is always good - and this time it caused a better solution
to the problem to spring into being :)

- Jamie

class Program
  DAYS = %w(sun mon tue wed thu fri sat)
  attr_reader :channel

  def initialize(settings)
    @range   = settings[:start]..settings[:end]
    @channel = settings[:channel]
    @days    = settings[:days]
  end

  def recurring?
    !@days.nil?
  end

  def include?(time)
    if recurring?
      return false unless @days.include? DAYS[time.wday]
      time_s = (time.hour*60 + time.min)*60 + time.sec
      @range.include? time_s
    else
      @range.include? time
    end
  end
end

class ProgramManager

  def initialize
    @programs = []
  end

  def add(settings)
    program = Program.new(settings)
    if program.recurring?
      @programs << program       # Recurring to end of list
    else
      @programs.unshift program  # Non-recurring to front
    end
  end

  def record?(time)
    @programs.each do |program|
      return program.channel if program.include? time
    end
    nil
  end
end