mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-24 23:06:42 +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 = [
|
@@datetime_formats = [
|
||||||
'yyyy-mm-dd hh:nn:ss.u',
|
|
||||||
'yyyy-mm-dd hh:nn:ss',
|
'yyyy-mm-dd hh:nn:ss',
|
||||||
'yyyy-mm-dd h:nn',
|
'yyyy-mm-dd h:nn',
|
||||||
|
'yyyy-mm-dd hh:nn:ss.u',
|
||||||
'm/d/yy h:nn:ss',
|
'm/d/yy h:nn:ss',
|
||||||
'm/d/yy h:nn',
|
|
||||||
'm/d/yy h:nn_ampm',
|
'm/d/yy h:nn_ampm',
|
||||||
|
'm/d/yy h:nn',
|
||||||
'd/m/yy hh:nn:ss',
|
'd/m/yy hh:nn:ss',
|
||||||
'd/m/yy h:nn',
|
|
||||||
'd/m/yy h:nn_ampm',
|
'd/m/yy h:nn_ampm',
|
||||||
|
'd/m/yy h:nn',
|
||||||
'ddd, dd mmm yyyy hh:nn:ss (zo|tz)', # RFC 822
|
'ddd, dd mmm yyyy hh:nn:ss (zo|tz)', # RFC 822
|
||||||
'ddd mmm d hh:nn:ss zo yyyy', # Ruby time string
|
'ddd mmm d hh:nn:ss zo yyyy', # Ruby time string
|
||||||
'yyyy-mm-ddThh:nn:ss(?:Z|zo)' # iso 8601
|
'yyyy-mm-ddThh:nn:ss(?:Z|zo)' # iso 8601
|
||||||
@ -151,51 +151,6 @@ module ValidatesTimeliness
|
|||||||
|
|
||||||
class << self
|
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
|
def compile_format_expressions
|
||||||
@@time_expressions = compile_formats(@@time_formats)
|
@@time_expressions = compile_formats(@@time_formats)
|
||||||
@@date_expressions = compile_formats(@@date_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
|
# pre or post match strings to exist if strict is false. Otherwise wrap
|
||||||
# regexp in start and end anchors.
|
# regexp in start and end anchors.
|
||||||
# Returns 7 part time array.
|
# Returns 7 part time array.
|
||||||
def parse(time_string, type, strict=true)
|
def parse(string, type, strict=true)
|
||||||
expressions = self.send("#{type}_expressions")
|
return string unless string.is_a?(String)
|
||||||
|
|
||||||
|
expressions = expression_set(type, string)
|
||||||
time_array = nil
|
time_array = nil
|
||||||
expressions.each do |(regexp, processor)|
|
expressions.each do |(regexp, processor)|
|
||||||
regexp = strict || type == :datetime ? /\A#{regexp}\Z/ : (type == :date ? /\A#{regexp}/ : /#{regexp}\Z/)
|
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])
|
time_array = processor.call(*matches[1..7])
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@ -260,6 +217,71 @@ module ValidatesTimeliness
|
|||||||
compile_format_expressions
|
compile_format_expressions
|
||||||
end
|
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)
|
def full_hour(hour, meridian)
|
||||||
hour = hour.to_i
|
hour = hour.to_i
|
||||||
return hour if meridian.nil?
|
return hour if meridian.nil?
|
||||||
|
|||||||
@ -153,6 +153,11 @@ describe ValidatesTimeliness::Formats do
|
|||||||
time_array.should == [2000,2,1,12,13,14,0]
|
time_array.should == [2000,2,1,12,13,14,0]
|
||||||
end
|
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
|
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 = formats.parse('2000-02-01 12:12', :date, false)
|
||||||
time_array.should == [2000,2,1,0,0,0,0]
|
time_array.should == [2000,2,1,0,0,0,0]
|
||||||
@ -252,15 +257,15 @@ describe ValidatesTimeliness::Formats do
|
|||||||
|
|
||||||
def generate_regexp(format)
|
def generate_regexp(format)
|
||||||
# wrap in line start and end anchors to emulate extract values method
|
# 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
|
end
|
||||||
|
|
||||||
def generate_regexp_str(format)
|
def generate_regexp_str(format)
|
||||||
formats.format_expression_generator(format)[0].inspect
|
formats.send(:format_expression_generator, format)[0].inspect
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_proc(format)
|
def generate_proc(format)
|
||||||
formats.format_expression_generator(format)[1]
|
formats.send(:format_expression_generator, format)[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_format(type, format)
|
def delete_format(type, format)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user