Skip to content

Instantly share code, notes, and snippets.

@nicoolas25
Created July 4, 2012 12:00
Show Gist options
  • Save nicoolas25/3046972 to your computer and use it in GitHub Desktop.
Save nicoolas25/3046972 to your computer and use it in GitHub Desktop.
Some class that may be useful for dealing with time ranges.
# This class assumes that you have ranges associated to a value
# and that you want to merge those values. This is, for instance,
# useful to count overlaps of date ranges.
#
# Example of uses:
#
# rm = RangeMixer.new(0..10, 0)
# rm.add(0..5){ |memo| memo + 1 }
# rm.add(0..5){ |memo| memo + 4 }
#
# puts rm.hash.inspect # => {0=>5, 5=>4, 7=>0}
#
# The previous example can also be written as:
#
# rm = RangeMixer.new(0..10, 0){ |memo, value| memo + value }
# rm.add(0..5, 1)
# rm.add(0..7, 4)
#
# The last method avoid the creation of useless Proc objects.
#
# This is an other context (where ActiveSupport is required):
#
# from = Date.today ; to = from + 1.month
# rm = RangeMixer.new(from..to, 0){ |memo, _| memo + 1 }
# rm.add(from..(from + 1.week))
# rm.add((from + 1.week)..to)
#
# # Check if there is an overlap
# rm.hash.values.any?{ |v| v > 1 } # => false
#
# rm.add((from + 3.days)..to)
#
# # Check if there is an overlap
# rm.hash.values.any?{ |v| v > 1 } # => true
class RangeMixer
attr_reader :hash
def initialize(range, memo, &mixer)
@start = range.begin
@stop = range.end
@memo = memo
@mixer = mixer
@hash = {@start => @memo}
end
def add(range, value=nil, &block)
return if range.end <= @start || range.begin >= @stop
insert_steps!(range)
fill_steps!(range, value || block)
end
private
def fill_steps!(range, pv)
@hash.each do |step, memo|
if range.begin <= step && step < range.end
@hash[step] = pv.kind_of?(Proc) ? pv.call(memo) : @mixer.call(memo, pv)
end
end
@hash
end
def insert_steps!(range)
@hash[range.begin] ||= previous(range.begin) if range.begin > @start
@hash[range.end] ||= previous(range.end) if range.end < @stop
end
def previous(step)
prev = @start
@hash.keys.sort.find{ |d| if d > step then true else prev = d and false end }
@hash[prev]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment