mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-22 22:06:45 +00:00
added compile_set method to get expressions and combine date and datetime expressions to allow a date string to parse when type is datetime
made internal methods private
This commit is contained in:
parent
85ac2bfc69
commit
7500781887
@ -83,15 +83,15 @@ module ValidatesTimeliness
|
||||
]
|
||||
|
||||
@@datetime_formats = [
|
||||
'yyyy-mm-dd hh:nn:ss.u',
|
||||
'yyyy-mm-dd hh:nn:ss',
|
||||
'yyyy-mm-dd h:nn',
|
||||
'yyyy-mm-dd hh:nn:ss.u',
|
||||
'm/d/yy h:nn:ss',
|
||||
'm/d/yy h:nn',
|
||||
'm/d/yy h:nn_ampm',
|
||||
'm/d/yy h:nn',
|
||||
'd/m/yy hh:nn:ss',
|
||||
'd/m/yy h:nn',
|
||||
'd/m/yy h:nn_ampm',
|
||||
'd/m/yy h:nn',
|
||||
'ddd, dd mmm yyyy hh:nn:ss (zo|tz)', # RFC 822
|
||||
'ddd mmm d hh:nn:ss zo yyyy', # Ruby time string
|
||||
'yyyy-mm-ddThh:nn:ss(?:Z|zo)' # iso 8601
|
||||
@ -151,51 +151,6 @@ module ValidatesTimeliness
|
||||
|
||||
class << self
|
||||
|
||||
# Compile formats into validation regexps and format procs
|
||||
def format_expression_generator(string_format)
|
||||
regexp = string_format.dup
|
||||
order = {}
|
||||
regexp.gsub!(/([\.\\])/, '\\\\\1') # escapes dots and backslashes ]/
|
||||
|
||||
format_tokens.each do |token|
|
||||
token_name = token.keys.first
|
||||
token_regexp, regexp_str, arg_key = *token.values.first
|
||||
|
||||
# hack for lack of look-behinds. If has a capture group then is
|
||||
# considered an anchor to put straight back in the regexp string.
|
||||
regexp.gsub!(token_regexp) {|m| "#{$1}" + regexp_str }
|
||||
order[arg_key] = $~.begin(0) if $~ && !arg_key.nil?
|
||||
end
|
||||
|
||||
return Regexp.new(regexp), format_proc(order)
|
||||
rescue
|
||||
puts "The following format regular expression failed to compile: #{regexp}\n from format #{string_format}."
|
||||
raise
|
||||
end
|
||||
|
||||
# Generates a proc which when executed maps the regexp capture groups to a
|
||||
# proc argument based on order captured. A time array is built using the proc
|
||||
# argument in the position indicated by the first element of the proc arg
|
||||
# array.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# 'yyyy-mm-dd hh:nn' => lambda {|y,m,d,h,n| md||=0; [unambiguous_year(y),month_index(m),d,full_hour(h,md),n,nil,nil].map {|i| i.to_i } }
|
||||
# 'dd/mm/yyyy h:nn_ampm' => lambda {|d,m,y,h,n,md| md||=0; [unambiguous_year(y),month_index(m),d,full_hour(h,md),n,nil,nil].map {|i| i.to_i } }
|
||||
#
|
||||
def format_proc(order)
|
||||
arg_map = format_proc_args
|
||||
args = order.invert.sort.map {|p| arg_map[p[1]][1] }
|
||||
arr = [nil] * 7
|
||||
order.keys.each {|k| i = arg_map[k][0]; arr[i] = arg_map[k][2] unless i.nil? }
|
||||
proc_string = "lambda {|#{args.join(',')}| md||=nil; [#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.to_i } }"
|
||||
eval proc_string
|
||||
end
|
||||
|
||||
def compile_formats(formats)
|
||||
formats.collect { |format| regexp, format_proc = format_expression_generator(format) }
|
||||
end
|
||||
|
||||
def compile_format_expressions
|
||||
@@time_expressions = compile_formats(@@time_formats)
|
||||
@@date_expressions = compile_formats(@@date_formats)
|
||||
@ -206,12 +161,14 @@ module ValidatesTimeliness
|
||||
# pre or post match strings to exist if strict is false. Otherwise wrap
|
||||
# regexp in start and end anchors.
|
||||
# Returns 7 part time array.
|
||||
def parse(time_string, type, strict=true)
|
||||
expressions = self.send("#{type}_expressions")
|
||||
def parse(string, type, strict=true)
|
||||
return string unless string.is_a?(String)
|
||||
|
||||
expressions = expression_set(type, string)
|
||||
time_array = nil
|
||||
expressions.each do |(regexp, processor)|
|
||||
regexp = strict || type == :datetime ? /\A#{regexp}\Z/ : (type == :date ? /\A#{regexp}/ : /#{regexp}\Z/)
|
||||
if matches = regexp.match(time_string.strip)
|
||||
if matches = regexp.match(string.strip)
|
||||
time_array = processor.call(*matches[1..7])
|
||||
break
|
||||
end
|
||||
@ -260,6 +217,71 @@ module ValidatesTimeliness
|
||||
compile_format_expressions
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Compile formats into validation regexps and format procs
|
||||
def format_expression_generator(string_format)
|
||||
regexp = string_format.dup
|
||||
order = {}
|
||||
regexp.gsub!(/([\.\\])/, '\\\\\1') # escapes dots and backslashes ]/
|
||||
|
||||
format_tokens.each do |token|
|
||||
token_name = token.keys.first
|
||||
token_regexp, regexp_str, arg_key = *token.values.first
|
||||
|
||||
# hack for lack of look-behinds. If has a capture group then is
|
||||
# considered an anchor to put straight back in the regexp string.
|
||||
regexp.gsub!(token_regexp) {|m| "#{$1}" + regexp_str }
|
||||
order[arg_key] = $~.begin(0) if $~ && !arg_key.nil?
|
||||
end
|
||||
|
||||
return Regexp.new(regexp), format_proc(order)
|
||||
rescue
|
||||
puts "The following format regular expression failed to compile: #{regexp}\n from format #{string_format}."
|
||||
raise
|
||||
end
|
||||
|
||||
# Generates a proc which when executed maps the regexp capture groups to a
|
||||
# proc argument based on order captured. A time array is built using the proc
|
||||
# argument in the position indicated by the first element of the proc arg
|
||||
# array.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# 'yyyy-mm-dd hh:nn' => lambda {|y,m,d,h,n| md||=0; [unambiguous_year(y),month_index(m),d,full_hour(h,md),n,nil,nil].map {|i| i.to_i } }
|
||||
# 'dd/mm/yyyy h:nn_ampm' => lambda {|d,m,y,h,n,md| md||=0; [unambiguous_year(y),month_index(m),d,full_hour(h,md),n,nil,nil].map {|i| i.to_i } }
|
||||
#
|
||||
def format_proc(order)
|
||||
arg_map = format_proc_args
|
||||
args = order.invert.sort.map {|p| arg_map[p[1]][1] }
|
||||
arr = [nil] * 7
|
||||
order.keys.each {|k| i = arg_map[k][0]; arr[i] = arg_map[k][2] unless i.nil? }
|
||||
proc_string = "lambda {|#{args.join(',')}| md||=nil; [#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.to_i } }"
|
||||
eval proc_string
|
||||
end
|
||||
|
||||
def compile_formats(formats)
|
||||
formats.collect { |format| regexp, format_proc = format_expression_generator(format) }
|
||||
end
|
||||
|
||||
# Pick expression set and combine date and datetimes for
|
||||
# datetime attributes to allow date string as datetime
|
||||
def expression_set(type, string)
|
||||
case type
|
||||
when :date
|
||||
date_expressions
|
||||
when :time
|
||||
time_expressions
|
||||
when :datetime
|
||||
# gives a speed-up for date string as datetime attributes
|
||||
if string.length < 11
|
||||
date_expressions + datetime_expressions
|
||||
else
|
||||
datetime_expressions + date_expressions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def full_hour(hour, meridian)
|
||||
hour = hour.to_i
|
||||
return hour if meridian.nil?
|
||||
|
||||
@ -153,6 +153,11 @@ describe ValidatesTimeliness::Formats do
|
||||
time_array.should == [2000,2,1,12,13,14,0]
|
||||
end
|
||||
|
||||
it "should parse date string when type is datetime" do
|
||||
time_array = formats.parse('2000-02-01', :datetime, false)
|
||||
time_array.should == [2000,2,1,0,0,0,0]
|
||||
end
|
||||
|
||||
it "should ignore time when extracting date and strict is false" do
|
||||
time_array = formats.parse('2000-02-01 12:12', :date, false)
|
||||
time_array.should == [2000,2,1,0,0,0,0]
|
||||
@ -252,15 +257,15 @@ describe ValidatesTimeliness::Formats do
|
||||
|
||||
def generate_regexp(format)
|
||||
# wrap in line start and end anchors to emulate extract values method
|
||||
/\A#{formats.format_expression_generator(format)[0]}\Z/
|
||||
/\A#{formats.send(:format_expression_generator, format)[0]}\Z/
|
||||
end
|
||||
|
||||
def generate_regexp_str(format)
|
||||
formats.format_expression_generator(format)[0].inspect
|
||||
formats.send(:format_expression_generator, format)[0].inspect
|
||||
end
|
||||
|
||||
def generate_proc(format)
|
||||
formats.format_expression_generator(format)[1]
|
||||
formats.send(:format_expression_generator, format)[1]
|
||||
end
|
||||
|
||||
def delete_format(type, format)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user