--------------090203040309040801070102
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Well, as everybody are sending in solutions here are mines ...

The first one (sleep1.rb) simply takes the computations, order them, and
consider the time to sleep is between the end of the previous and the
beginning of the next.

The second one (sleep3.rb) takes the same arguments but sleep according
to the *beginning* time of each set of operations. All the operations
supposed to begin at the same time will happen in the order they were
defined (i.e. we have one thread per beginning)

At last, the third one (sleep4.rb) uses one thread per computation,
hence there is no predictability in the order of computation for
operations which are suppose to begin at the same time.

Attached also, a test file ... just change the require to test each module.

Pierre

--------------090203040309040801070102
Content-Type: text/plain;
 nameleep1.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filenameleep1.rb"


class Sleep

  attr_reader :time

  def initialize time
    @time  ime
  end

  def <<(comp)
    if Sleep  comp
      @time + omp.time
      self
    else
      Comp.new(time) << comp
    end
  end

end

class Comp

  Op  truct.new :time, :op

  attr_reader :ops

  def initialize(time  , &block)
    @ops  ]
    @ops << Op.new(time, block) if block
    @time  ime
  end

  def <<(comp)
    case comp
    when Sleep
      t  omp.time
      @time + 
    when Comp
      @ops.concat comp.ops.map { |o| Op.new(o.time+@time, o.op) }
    when Proc
      @ops << Op.new(@time, comp)
    end
    self
  end

  def run
    h  ash.new { |h,k| h[k]  ] }
    @ops.each do |c|
      h[ c.time ] << c.op
    end
    order  .keys.sort
    time  rder[0]
    ref_time  ime
    order.each do |t|
      sleep(t-time)
      h[t].each { |b| b.call(t) }
      time  
    end
  end

end


--------------090203040309040801070102
Content-Type: text/plain;
 nameleep3.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filenameleep3.rb"


class Sleep

  attr_reader :time

  def initialize time
    @time  ime
  end

  def <<(comp)
    if Sleep  comp
      @time + omp.time
      self
    else
      Comp.new(time) << comp
    end
  end

end

class Comp

  attr_reader :ops

  def initialize(time  , &block)
    @ops  ash.new { |h,k| h[k]  ] }
    @ops[time] << block if block
    @time  ime
  end

  def <<(comp)
    case comp
    when Sleep
      @time + omp.time
    when Comp
      comp.ops.each { |t,bs| @ops[t+@time].concat bs }
    when Proc
      @ops[@time] << comp
    end
    self
  end

  def run
    ref_time  ops.keys.min
    ts  ops.map do |t,bs|
      Thread.new(bs) do |bs|
        sleep(t-ref_time)
        bs.each { |b| b.call(t) }
      end
    end
    ts.each { |t| t.join }
  end

end


--------------090203040309040801070102
Content-Type: text/plain;
 nameleep4.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filenameleep4.rb"


class Sleep

  attr_reader :time

  def initialize time
    @time  ime
  end

  def <<(comp)
    if Sleep  comp
      @time + omp.time
      self
    else
      Comp.new(time) << comp
    end
  end

end

class Comp

  attr_reader :ops

  def initialize(time  , &block)
    @ops  ash.new { |h,k| h[k]  ] }
    @ops[time] << block if block
    @time  ime
  end

  def <<(comp)
    case comp
    when Sleep
      @time + omp.time
    when Comp
      comp.ops.each { |t,bs| @ops[t+@time].concat bs }
    when Proc
      @ops[@time] << comp
    end
    self
  end

  def run
    ref_time  ops.keys.min
    ts  ops.map do |t,bs|
      bs.map do |b|
        Thread.new(b) do |b|
          sleep(t-ref_time)
          b.call t
        end
      end
    end
    ts.flatten.each { |t| t.join }
  end

end


--------------090203040309040801070102
Content-Type: text/plain;
 nameest_sleep.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filenameest_sleep.rb"

require "sleep1"

puts "Test 1"

c  omp.new { |t| sleep 1; puts "#{t} :: Foo here" } <<
    Sleep.new(-1) <<
    Comp.new { |t| puts "#{t} :: Bar there" } <<
    Sleep.new(1) <<
    Comp.new { |t| puts "#{t} :: Well ..." } <<
    Comp.new { |t| puts "#{t} :: Why not" } <<
    Sleep.new(-2) <<
    Comp.new { |t| puts "#{t} :: Just another test" } <<
    Sleep.new(2.5) <<
    Comp.new { |t| puts "#{t} :: A last one ?" }
c.run

puts "Test 2"

c  omp.new { |t| sleep 1; puts "#{t} :: Foo here" } <<
    Sleep.new(-1) <<
    Comp.new { |t| puts "#{t} :: Bar there" } <<
    Sleep.new(2) <<
    Comp.new { |t| puts "#{t} :: Well ..." } <<
    Comp.new { |t| puts "#{t} :: Why not" } <<
    Sleep.new(-3) <<
    Comp.new { |t| puts "#{t} :: Just another test" }
c.run

puts "Test 3"

c  omp.new(10) { |t| sleep 1; puts "#{t} :: Foo here" } <<
    Sleep.new(-1) <<
    lambda { |t| puts "#{t} :: Bar there" } <<
    ( Sleep.new(2) <<
    Comp.new { |t| puts "#{t} :: Well ..." } <<
    Comp.new { |t| puts "#{t} :: Why not" } <<
    Sleep.new(-3) <<
    Comp.new { |t| puts "#{t} :: Just another test" } ) <<
    Sleep.new(1.5) <<
    Comp.new { |t| puts "#{t} :: A last one ?" }
c.run


--------------090203040309040801070102--