lib/eventual.rb in eventual-0.4.9 vs lib/eventual.rb in eventual-0.5.0

- old
+ new

@@ -1,193 +1,7 @@ +require 'rubygems' +require 'treetop' require 'date' -require 'iconv' -require 'strscan' -module Eventual - class WdayMatchError < StandardError; end - - - VERSION = '0.4.9' - extend self +require "#{ File.dirname __FILE__ }/eventual/syntax_nodes" - WDAY_LIST = %w(domingo lunes martes miércoles jueves viernes sábado).freeze - MESES = %w(enero febrero marzo abril mayo junio julio agosto septiembre octubre noviembre diciembre).unshift(nil).freeze - DIAS_DE_LA_SEMANA = WDAY_LIST.map{ |d| d.match(/s$/) ? d : "#{d}s?" } - - def rango_de a, b = nil - a = a.join('|') if Array === a - b ||= a - /(?:de |del )?(?:#{ a }) (?:a|al) (?:#{ b })/ - end - - def lista_de elementos - elementos = elementos.join('|') if Array === elementos - /(?:#{ elementos }) # Primer elemento -requerido- - (?: # Cualquier número de - (?-x:, | y ) # concatenador - (?:#{ elementos }) # y elemento. - )*/ix - end - - def plural_opcional elementos - elementos.map{ |d| d.match(/s$/) ? d : "#{d}s?" } - end - - year = /(?-x:del |de )?(\d{4})/i - horarios = /a las (#{ lista_de '\d{1,2}:\d{2}' })(?: horas| hrs)?/i - - - DAY_LIST = / - (#{ lista_de %r"(?:(?:#{ DIAS_DE_LA_SEMANA.join('|') }) )?\d{1,2}" })\s - de\s(#{ MESES.compact.join('|') }) # Mes - (?:\s#{ year })? # Año opcional - (\s#{ horarios })? # Hora opcional - /ixo - - DAY_PERIOD = / - (?: - ( - (?:#{ rango_de DIAS_DE_LA_SEMANA })\s - | - (?:#{ lista_de DIAS_DE_LA_SEMANA })\s - ) - (?-x:de |del ) - )? - (?-x:(?:de |del )?(?:(#{ DIAS_DE_LA_SEMANA.join('|') }) )?(\d{1,2})(?: de (#{ MESES.compact.join('|') })(?: #{ year })?)?) - (?-x: (?:a|al) (?:(#{ DIAS_DE_LA_SEMANA.join('|') }) )?(\d{1,2}) de (#{ MESES.compact.join('|') })(?: #{ year })?) - (?:\s#{ horarios })? - /ixo - - WHOLE_MONTH = / - ( # Dias de la semana opcionales - (?-x:los |todos los )? - (?: - (?:#{ rango_de DIAS_DE_LA_SEMANA }) - | - (?:#{ lista_de DIAS_DE_LA_SEMANA }) - )\s - (?-x:de|durante|durante todo)\s - )? - (?: - (?:#{ rango_de %r"(#{ MESES.compact.join('|') })(?:\s#{ year })?" }) - | - (#{ lista_de MESES.compact })(?:\s#{ year })? - ) - (?:\s#{ horarios })? # Hora opcional - /ixo - - def event_parse string, opts = {}, &block - parser = opts.delete(:parser) || (self == Eventual ? DateTime : self) - use_trailing = opts.delete(:use_trailing) - string = string.gsub('miercoles', 'miércoles').gsub('sabado', 'sábado').gsub(/'/, '').gsub(/(\s)+/, '\1') - results = [] - scanner = StringScanner.new string - - map_months = lambda{ |months| months.scan(/#{ MESES.compact.join('|') }/).map{ |m| MESES.index(m.downcase) } } - make_range = lambda{ |first, last, min, max| first > last ? (first..max).map + (min..last).map : (first..last).map } - - extract_wdays = lambda do |wdays| - wdays_array = wdays ? wdays.scan( /#{ WDAY_LIST.join('|') }/ ).map{ |d| WDAY_LIST.index d.downcase } : [] - next wdays_array unless rango_de(DIAS_DE_LA_SEMANA) === wdays - make_range[wdays_array.first, wdays_array.last, 0, 6] - end - - until scanner.eos? - case match = scanner.scan(/.*?(?:#{ DAY_LIST }|#{ DAY_PERIOD }|#{ WHOLE_MONTH })/m) - - when DAY_PERIOD - wdays, first_wday, first_day, first_month, first_year, last_wday, last_day, last_month, last_year, times = $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 - - wdays_array = extract_wdays[wdays] - last_year ||= string.match(/\d{4}/) ? $& : Date.today.year - first_year ||= last_year - first_month ||= last_month - last_month = MESES.index last_month.downcase - first_month = MESES.index first_month.downcase - - make_days = lambda do |hour, minute| - first = make_day parser, first_year, first_month, first_day, hour, minute - last = make_day parser, last_year, last_month, last_day, hour, minute - - [first, last].zip([first_wday, last_wday]).each do |day, wday| - raise WdayMatchError.new("El día #{ day } cae en #{ DIAS_DE_LA_SEMANA[day.wday] }, no en #{ wday.downcase }") unless day.wday == WDAY_LIST.index(wday.downcase) if wday - end - - next (first..last).map if wdays_array.empty? - (first..last).select{ |day| wdays_array.include? day.wday } - end - - when DAY_LIST - daynums, month, year, times = $1, MESES.index($2.downcase), $3, $4 - - year ||= string.match(/\d{4}/) ? $& : Date.today.year - make_days = lambda do |hour, minute| - daynums.scan(/(?:(#{ DIAS_DE_LA_SEMANA.join('|') }) )?(\d{1,2})/).collect do |wday, daynum| - day = make_day(parser, year, month, daynum, hour, minute) - raise WdayMatchError.new("El día #{ day } cae en #{ DIAS_DE_LA_SEMANA[day.wday] }, no en #{ wday.downcase }") unless day.wday == WDAY_LIST.index(wday.downcase) if wday - day - end - end - - when WHOLE_MONTH - wdays, month_range_start, starting_year, month_range_end, ending_year, months, year, times = $1, $2, $3, $4, $5, $6, $7, $8 - wdays_array = extract_wdays[wdays] - - month_array = - if month_range_start - ending_year ||= Date.today.year - first = Date.civil( (starting_year || ending_year).to_i, MESES.index(month_range_start.downcase) ) - last = Date.civil ending_year.to_i, MESES.index(month_range_end.downcase) - (first..last) - else - year ||= Date.today.year - months.scan(/#{ MESES.compact.join('|') }/).map do |m| - Date.civil year.to_i, MESES.index(m.downcase) - end - end - - make_days = lambda do |hour, minute| - months = month_array.map do |date| - first = make_day(parser, date.year, date.month, 1, hour, minute) - last = (first >> 1) - 1 - next (first..last).map if wdays_array.empty? - (first..last).select{ |day| wdays_array.include? day.wday } - end.flatten - end - - else - break - end - - extra = scanner.scan(/.*?(?=#{ DAY_LIST }|#{ DAY_PERIOD }|\z)/m).to_s.chomp - extra.gsub!(/^(,|\n|\.)/, '') - - days = - if times - times.scan( /(\d{2}):(\d{2})/ ).map{ |hour, minute| make_days.call hour, minute }.flatten - else - make_days.call nil, nil - end - - days.each { |day| day.instance_variable_set('@extra', extra) } - results += days - end - - raise ArgumentError.new( 'El formato de las fechas parece ser incorrecto' ) if results.empty? - results.uniq! - results.sort! - - use_trailing ? results.map!{ |day| yield day, day.instance_variable_get('@extra') } : results.map!{ |day| yield day } if block_given? - results - end - - protected - def make_day *args - maker = args.shift - if maker == Date - maker.civil *args.compact.collect{ |a| a.to_i }[0...4] - else - maker.civil *args.compact.collect{ |a| a.to_i } - end - end -end - +autoload :EsDatesParser, 'eventual/es' \ No newline at end of file