class Medjool::Parser
Attributes
context[R]
Public Class Methods
new(context = {})
click to toggle source
# File lib/medjool/parser.rb, line 8 def initialize(context = {}) @context = context end
Public Instance Methods
is_date_range?(text)
click to toggle source
# File lib/medjool/parser.rb, line 12 def is_date_range?(text) Medjool::DATE_RANGE_MATCHER.match(text.strip).present? end
parse(text, update_now = true)
click to toggle source
# File lib/medjool/parser.rb, line 53 def parse(text, update_now = true) if Medjool::DATE_MATCHER.match(text) # Let's do an aggressive strip of any whitespace at the start and end, including crazy unicodeness # that the standard 'strip' would miss text = text.gsub(/^[^a-zA-Z0-9]*/, "").gsub(/[^a-zA-Z0-9]*$/, "") if /^[0-9]$/.match(text) # Handle lone integers text = "#{text}st" end begin base_date = Date.parse(text) rescue ArgumentError => e # If Date.parse is used on the string "31st" during # a month with only 30 days, it will explode if Medjool::END_OF_MONTH_MATCHER.match(text) # This is a little bit hacky, but switch to a date that will definitely work base_date = Date.parse("#{text} January") else return nil end end unless @context[:now] # In the absence of context, always fall back on the default guess guess_date = base_date else # Determine the ambiguity level for this data ambiguity = determine_ambiguity(text) now = @context[:now].to_date case ambiguity when :none return base_date when :weekly # Pick the nearest week that meets the context guess_date = now + (base_date.wday - now.wday).days - 1.week while guess_date < now guess_date += 1.week end when :monthly # Pick the nearest month where the provided day of the month meets the context y = now.year m = now.month - 1 guess_date = nil while guess_date.nil? || guess_date < now m += 1 if m > 12 m = 1 y += 1 end begin guess_date = Date.new(y, m, base_date.day) rescue ArgumentError # This might happen e.g. 31st Feb, # so just carry on to the next month next end end when :yearly # Skip ahead a year at a time unless we meet the context guess_date = Date.new(now.year, base_date.month, base_date.day) while guess_date < now guess_date += 1.year end end end @context[:now] = guess_date if update_now return guess_date else return nil end end
parse_date_range(text)
click to toggle source
# File lib/medjool/parser.rb, line 16 def parse_date_range(text) if bits = Medjool::DATE_RANGE_MATCHER.match(text.strip) if bits[1].present? prefix = bits[1].strip.sub(/:$/, '') else prefix = nil end if bits[52] # October if month_start = self.parse(text.strip, update_now = false) month_end = month_start.end_of_month return Medjool::DateRange.new(month_start, month_end, prefix) end elsif bits[3] # 12-15 Oct # Start is 12 Oct end_month = bits[17] start_month = bits[6] || end_month range_start = self.parse("#{bits[4]} #{start_month}", update_now = false) # End is 15 Oct range_end = self.parse("#{bits[16]} #{end_month}", update_now = false) return Medjool::DateRange.new(range_start, range_end, prefix) elsif bits[29] # Oct 12-15 # Start is 12 Oct end_month = bits[41] start_month = bits[29] || end_month range_start = self.parse("#{bits[39]} #{start_month}", update_now = false) # End is 15 Oct range_end = self.parse("#{bits[51]} #{end_month}", update_now = false) return Medjool::DateRange.new(range_start, range_end, prefix) end end end
Protected Instance Methods
determine_ambiguity(text)
click to toggle source
# File lib/medjool/parser.rb, line 137 def determine_ambiguity(text) if /#{Medjool::DM_DM_YYYY_MATCHER}|#{Medjool::YYYY_MM_DD_MATCHER}/.match(text) # Plain as day return :none end # Work out how much detail we have data_present = { :day_name => Medjool::DAYNAME_MATCHER.match(text), :month => Medjool::MONTH_MATCHER.match(text), :ordinal => Medjool::ORDINAL_MATCHER.match(text) } if data_present[:month] && data_present[:ordinal] # 1st December return :yearly elsif data_present[:ordinal] # Monday 1 or just 1st return :monthly elsif data_present[:day_name] && !data_present[:month] # Tuesday return :weekly elsif data_present[:month] # October return :yearly else # Unknown return nil end end