lib/timespan.rb in timespan-0.4.6 vs lib/timespan.rb in timespan-0.4.9

- old
+ new

@@ -1,10 +1,17 @@ require 'duration' require 'chronic' require 'chronic_duration' require 'spanner' +# Range intersection that works with dates! +require 'sugar-high/range' +require 'sugar-high/delegate' +require 'sugar-high/kind_of' + +require 'timespan/core_ext' + require 'timespan/units' require 'timespan/compare' require 'timespan/printer' require 'timespan/span' require 'active_support/core_ext/date/calculations.rb' @@ -42,11 +49,10 @@ ALL_KEYS = START_KEYS + END_KEYS + DURATION_KEYS def initialize options = {} @is_new = true - @init_options = options validate! if options == {} options = {:duration => options} if options.kind_of? Numeric @@ -58,45 +64,74 @@ configure! options @is_new = false end - def self.from start, duration, options = {} - start = case start.to_sym - when :now, :asap - Time.now - when :today - Date.today - when :tomorrow - Date.today + 1.day - when :next_week # requires active_support - date = Date.today.next_week - options[:start] ? date.beginning_of_week : date - when :next_month - date = Date.today.next_month - options[:start] ? date.at_beginning_of_month.next_month : date - else - start + class << self + def max_date + @max_date ||= Time.now + 10.years end - self.new start_date: start, duration: duration - end + def min_date + @min_date ||= Time.now + end - def self.untill ending - ending = case ending.to_sym - when :tomorrow - Date.today + 1.day - when :next_week # requires active_support - date = Date.today.next_week - options[:start] ? date.beginning_of_week : date - when :next_month - date = Date.today.next_month - options[:start] ? date.at_beginning_of_month.next_month : date - else - ending + def max_date= date + @max_date = date if valid_date?(date) end - self.new start_date: Date.now, end_date: ending + + def min_date= date + @max_date = date if valid_date?(date) + end + + def asap options = {} + self.new options.merge(asap: true) + end + + def from start, duration, options = {} + start = case start.to_sym + when :now, :asap + Time.now + when :today + Date.today + when :tomorrow + Date.today + 1.day + when :next_week # requires active_support + date = Date.today.next_week + options[:start] ? date.beginning_of_week : date + when :next_month + date = Date.today.next_month + options[:start] ? date.at_beginning_of_month.next_month : date + else + start + end + + self.new start_date: start, duration: duration + end + + def untill ending + ending = case ending.to_sym + when :tomorrow + Date.today + 1.day + when :next_week # requires active_support + date = Date.today.next_week + options[:start] ? date.beginning_of_week : date + when :next_month + date = Date.today.next_month + options[:start] ? date.at_beginning_of_month.next_month : date + else + ending + end + self.new start_date: Date.now, end_date: ending + end + alias_method :until, :untill + + protected + + def valid_date? date + date.any_kind_of?(Date, Time, DateTime) + end end def start_time= time @start_time = convert_to_time time unless is_new? @@ -120,25 +155,41 @@ calculate! end end alias_method :end_date=, :end_time= - def until time + def asap? + @asap + end + + def min + asap ? Time.now : start_time + end + + def max + end_time + end + + def untill time self.end_time = time self end + alias_method :until, :untill def convert_to_time time + time = Duration.new time if time.kind_of? Numeric case time when String Chronic.parse(time) when Date, DateTime time.to_time + when Duration + (Time.now + time).to_time when Time time else - raise ArgumentError, "A valid time must be either a String, Date, Time or DateTime, was: #{time.inspect}" + raise ArgumentError, "A valid time must be either a String, Duration, Date, Time or DateTime, was: #{time.inspect} (#{time.class})" end end protected @@ -151,21 +202,43 @@ # uses init_options to configure def configure! options = {} from = options[first_from(START_KEYS, options)] to = options[first_from(END_KEYS, options)] dur = options[first_from(DURATION_KEYS, options)] + asap = options[:asap] + if options[:at_least] + to = Timespan.max_date + from = Time.now + options[:at_least] + end + + if options[:at_most] + to = Time.now + options[:at_most] + from = Time.now + end + + if options[:between] + from = Time.now + options[:between].min + to = Time.now + options[:between].max + end + + # puts "configure: to:#{to}, from:#{from}, dur:#{dur}, asap:#{asap}" + + @asap = asap if asap self.duration = dur if dur self.start_time = from if from self.end_time = to if to + # puts "configured: start:#{self.start_time}, end:#{self.end_time}, duration:#{self.duration}, asap:#{self.asap?}" + default_from_now! calculate_miss! rescue ArgumentError => e raise TimeParseError, e.message - rescue Exception => e - calculate_miss! - validate! + # rescue Exception => e + # puts "Exception: #{e}" + # calculate_miss! + # validate! end def default_from_now! self.start_time = now unless start_time || (end_time && duration) self.end_time = now unless end_time || (start_time && duration) \ No newline at end of file