Class: Temporal

Inherits:
Object show all
Defined in:
lib/temporals.rb,
lib/temporals/types.rb,
lib/temporals/parser.rb,
lib/temporals/patterns.rb

Defined Under Namespace

Classes: ArrayOfRanges, Classification, Month, Parser, Set, Union, WDay

Constant Summary collapse

VERSION =
'2.0.1'
TimeRegexp =
'\d{1,2}(?::\d\d)?(?::\d{1,2})?(?:[ap]m?)?'
WordOrds =
%w(first second third fourth fifth)
WordTypes =
{
  :ord => /^([1-3]?\d)(?:st|nd|rd|th)?$/i, # Should be able to distinguish
  :word_ord => /^(first|second|third|fourth|fifth|last)$/i,
  :wday => /^(#{(WDay.order + WDay.translations.keys).join('|')})s?$/i,
  :month => /^#{(Month.order + Month.translations.keys).join('|')}$/i,
  :year => /^([09]\d|\d{4})$/, # A year will be either 2 digits starting with a 9 or a 0, or 4 digits.
  :union => /^(?:and)$/i,
  :range => /^(?:-|to|through)$/i,
  :timerange => /^(#{TimeRegexp}?)-(#{TimeRegexp})$/i,
  # :from => /^from$/i,
  # :to => /^to$/i,
  # :between => /^between$/i
}
CommonPatterns =

These are in a specific order

[
  'ord range ord',
  'ord union ord',
  'year range year',
  'year union year',
  'wday range wday',
  'wday union wday',
  # 'timerange union timerange', # Not quite figured out yet, I'd need to implement new code into the question methods.
  'month ord',
  'ord month',
  'ord wday',
  'month_ord timerange',
  'month union month',
  'month range month',
  'ord_wday month',
  'ord_wday timerange',
  'ord_wday_month timerange',
  'timerange wday',
  'month_ord year',
  'month year',
  'wday year',
  "wday_timerange month",
  "wday_timerange year",
  "wday_timerange month_year"
]
CommonPatternActions =
{
  'ord range ord' => lambda {|words,i|
    words[i][:ord] = (words[i][:ord].to_i..words[i+2][:ord].to_i)
    words.slice!(i+1,2)
  },
  'ord union ord' => lambda {|words,i|
    words[i][:ord] = ArrayOfRanges.new(words[i][:ord], words[i+2][:ord])
    words.slice!(i+1,2)
  },
  'year range year' => lambda {|words,i|
    words[i][:year] = (words[i][:year].to_i..words[i+2][:year].to_i)
    words.slice!(i+1,2)
  },
  'year union year' => lambda {|words,i|
    words[i][:year] = ArrayOfRanges.new(words[i][:year], words[i+2][:year])
    words.slice!(i+1,2)
  },
  'wday range wday' => lambda {|words,i|
    words[i][:wday] = (words[i][:wday].to_i..words[i+2][:wday].to_i)
    words.slice!(i+1,2)
  },
  'wday union wday' => lambda {|words,i|
    words[i][:wday] = ArrayOfRanges.new(words[i][:wday], words[i+2][:wday])
    words.slice!(i+1,2)
  },
  # 'timerange union timerange' => lambda {|words,i|
  #   words[i][:wday] = ArrayOfRanges.new(words[i][:wday], words[i+2][:wday])
  #   words.slice!(i+1,2)
  # },
  'month ord' => lambda {|words,i|
    words[i][:type] = 'month_ord'
    words[i][:ord] = words[i+1][:ord]
    words.slice!(i+1,1)
  },
  'ord month' => lambda {|words,i|
    words[i][:type] = 'month_ord'
    words[i][:month] = words[i+1][:month]
    words.slice!(i+1,1)
  },
  'ord wday' => lambda {|words,i|
    words[i][:type] = 'ord_wday'
    words[i][:wday] = words[i+1][:wday]
    words.slice!(i+1,1)
  },
  'month_ord timerange' => lambda {|words,i|
    words[i][:type] = 'month_ord_timerange'
    words[i][:start_time] = words[i+1][:start_time]
    words[i][:end_time] = words[i+1][:end_time]
    words.slice!(i+1,1)
  },
  'month union month' => lambda {|words,i|
    words[i][:month] = ArrayOfRanges.new(words[i][:month], words[i+2][:month])
    words.slice!(i+1,2)
  },
  'month range month' => lambda {|words,i|
    # raise "Not Implemented Yet!"
    words[i][:month] = (words[i][:month]..words[i+2][:month])
    words.slice!(i+1,2)
  },
  'ord_wday month' => lambda {|words,i|
    words[i][:type] = 'ord_wday_month'
    words[i][:month] = words[i+1][:month]
    words.slice!(i+1,1)
  },
  'ord_wday timerange' => lambda {|words,i|
    words[i][:type] = 'ord_wday_timerange'
    words[i][:start_time] = words[i+1][:start_time]
    words[i][:end_time] = words[i+1][:end_time]
    words.slice!(i+1,1)
  },
  'timerange wday' => lambda {|words,i|
    words[i][:type] = 'wday_timerange'
    words[i][:wday] = words[i+1][:wday]
    words.slice!(i+1,1)
  },
  'ord_wday_month timerange' => lambda {|words,i|
    words[i][:type] = 'ord_wday_month_timerange'
    words[i][:start_time] = words[i+1][:start_time]
    words[i][:end_time] = words[i+1][:end_time]
    words.slice!(i+1,1)
  },
  'month_ord year' => lambda {|words,i|
    words[i][:type] = 'ord_month_year'
    words[i][:year] = words[i+1][:year]
    words.slice!(i+1,1)
  },
  'wday year' => lambda {|words,i|
    words[i][:type] = 'wday_year'
    words[i][:year] = words[i+1][:year]
    words.slice!(i+1,1)
  },
  'month year' => lambda {|words,i|
    words[i][:type] = 'month_year'
    words[i][:year] = words[i+1][:year]
    words.slice!(i+1,1)
  },
  'wday_timerange month' => lambda {|words,i|
    words[i][:type] = 'wday_timerange_month'
    words[i][:month] = words[i+1][:month]
    words.slice!(i+1,1)
  },
  'wday_timerange year' => lambda {|words,i|
    words[i][:type] = 'wday_timerange_year'
    words[i][:year] = words[i+1][:year]
    words.slice!(i+1,1)
  },
  'wday_timerange month_year' => lambda {|words,i|
    words[i][:type] = 'wday_timerange_month_year'
    words[i][:month] = words[i+1][:month]
    words[i][:year] = words[i+1][:year]
    words.slice!(i+1,1)
  }
}
BooleanPatterns =
[
  'union'
]
BooleanPatternActions =
{
  'union' => lambda {|words,i|
    words[i-1] = Temporal::Union.new(words[i-1], words[i+1])
    words.slice!(i,2)
    puts "Boolean-connected: " + words.inspect if $DEBUG
  }
}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Temporal

Returns a new instance of Temporal.



12
13
14
15
16
# File 'lib/temporals.rb', line 12

def initialize(options)
  options.each do |key,value|
    instance_variable_set(:"@#{key}", value)
  end
end

Class Method Details

.parse(expression) ⇒ Object



170
171
172
173
# File 'lib/temporals/parser.rb', line 170

def parse(expression)
  puts "Parsing expression: #{expression.inspect}" if $DEBUG
  Temporal::Parser.new(expression).yielded
end

Instance Method Details

#[](key) ⇒ Object



18
19
20
# File 'lib/temporals.rb', line 18

def [](key)
  instance_variable_get(:"@#{key}")
end

#end_time(date = nil) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/temporals.rb', line 86

def end_time(date=nil)
  if date
    @end_time.sub!(/^(\d+)/,'\1:00') if @end_time =~ /^(\d+)[^:]/
    puts "#{date.strftime("%Y-%m-%d")} #{@end_time}" if $DEBUG
    Time.parse("#{date.strftime("%Y-%m-%d")} #{@end_time}")
  else
    @end_time
  end
end

#include?(datetime) ⇒ Boolean

Returns:

  • (Boolean)


30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/temporals.rb', line 30

def include?(datetime)
  return false unless occurs_on_day?(datetime)
  if @type =~ /timerange/
    test_date = datetime.strftime("%Y-%m-%d")
    test_start_time = Time.parse("#{test_date} #{@start_time.gsub(/([ap]m)$/,'')}#{start_pm? ? 'pm' : 'am'}")
    test_end_time = Time.parse("#{test_date} #{@end_time}")
    test_end_time = test_end_time+59 if test_end_time == test_start_time # If they're equal, they are assumed to be to the minute precision
    puts "TimeRange: date:#{test_date} test_start:#{test_start_time} test_end:#{test_end_time} <=> #{datetime}" if $DEBUG
    return false unless datetime.between?(test_start_time, test_end_time)
  end
  return true
  puts "#{datetime} Included!" if $DEBUG
end

#occurrances_on_day(date) ⇒ Object



73
74
75
# File 'lib/temporals.rb', line 73

def occurrances_on_day(date)
  occurs_on_day?(date) ? [{:start_time => start_time(date), :end_time => end_time(date)}] : []
end

#occurs_on_day?(datetime) ⇒ Boolean

Returns:

  • (Boolean)


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/temporals.rb', line 44

def occurs_on_day?(datetime)
  puts "#{datetime} IN? #{inspect}" if $DEBUG
  if @type =~ /month/
    puts "Month #{Month.new(datetime.month-1).inspect} in? #{@month.inspect} >> #{Month.new(datetime.month-1).value_in?(@month)}" if $DEBUG
    return false unless Month.new(datetime.month-1).value_in?(@month)
  end
  if @type =~ /ord_wday/
    puts "Weekday: #{WDay.new(datetime.wday).inspect} in? #{@wday.inspect} >> #{WDay.new(datetime.wday).value_in?(@wday)}" if $DEBUG
    return false unless WDay.new(datetime.wday).value_in?(@wday)
    puts "WeekdayOrd: #{datetime.wday_ord} in? #{@ord.inspect} >> #{datetime.wday_ord.value_in?(@ord)}" if $DEBUG
    puts "WeekdayLast: #{datetime.wday_last} in? #{@ord.inspect} >> #{datetime.wday_last.value_in?(@ord)}" if $DEBUG
    return false unless datetime.wday_ord.value_in?(@ord) || datetime.wday_last.value_in?(@ord)
  end
  if @type =~ /month_ord/
    puts "Day #{datetime.day} == #{@ord.inspect} >> #{datetime.day.value_in?(@ord)}" if $DEBUG
    return false unless datetime.day.value_in?(@ord)
  end
  if @type =~ /year/
    puts "Year #{datetime.year} == #{@year.inspect} >> #{datetime.year.value_in?(@year)}" if $DEBUG
    return false unless datetime.year.value_in?(@year)
  end
  if @type =~ /wday/
    puts "Weekday: #{WDay.new(datetime.wday).inspect} in? #{@wday.inspect} == #{WDay.new(datetime.wday).value_in?(@wday)}" if $DEBUG
    return false unless WDay.new(datetime.wday).value_in?(@wday)
  end
  puts "Occurs on #{datetime}!" if $DEBUG
  return true
end

#start_pm?Boolean

Returns:

  • (Boolean)


22
23
24
25
26
27
28
# File 'lib/temporals.rb', line 22

def start_pm?
  if @start_time =~ /([ap])m$/ || @end_time =~ /([ap])m$/
    $1 == 'p'
  else
    nil
  end
end

#start_time(date = nil) ⇒ Object



77
78
79
80
81
82
83
84
85
# File 'lib/temporals.rb', line 77

def start_time(date=nil)
  if date
    @start_time.sub!(/^(\d+)/,'\1:00') if @start_time =~ /^(\d+)[^:]/
    puts "#{date.strftime("%Y-%m-%d")} #{@start_time}" if $DEBUG
    Time.parse("#{date.strftime("%Y-%m-%d")} #{@start_time}")
  else
    @start_time
  end
end

#to_naturalObject



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/temporals.rb', line 96

def to_natural
  @type.split(/_/).collect {|w|
    case w
    # when 'ord'
    #   if @ord.respond_to?(:to_natural)
    #     @ord.to_natural('ord')
    #   end
    #   if @ord.is_a?(Range)
    #     @ord.begin + 'th-' + @ord.end
    #   elsif @ord.is_a?(Array)
    #     
    #   else
    #     @ord + 'th'
    #   end
    when 'dummy'
    else
      instance_variable_get('@'+w)
    end
  }.join(' ')
end