lib/timeliness/format_set.rb in timeliness-0.2.0 vs lib/timeliness/format_set.rb in timeliness-0.3.0
- old
+ new
@@ -1,98 +1,43 @@
module Timeliness
class FormatSet
- include Helpers
-
attr_reader :formats, :regexp
- class << self
-
- def compile(formats)
- set = new(formats)
- set.compile!
- set
- end
-
- def compile_format(string_format)
- format = string_format.dup
- format.gsub!(/([\.\\])/, '\\\\\1') # escapes dots and backslashes
- found_tokens, token_order, value_token_count = [], [], 0
-
- # Substitute tokens with numbered placeholder
- Formats.sorted_token_keys.each do |token|
- regexp_str, arg_key = *Formats.format_tokens[token]
- if format.gsub!(/#{token}/, "%<#{found_tokens.size}>")
- if arg_key
- regexp_str = "(#{regexp_str})"
- value_token_count += 1
- end
- found_tokens << [regexp_str, arg_key]
- end
- end
-
- # Replace placeholders with token regexps
- format.scan(/%<(\d)>/).each {|token_index|
- token_index = token_index.first
- regexp_str, arg_key = found_tokens[token_index.to_i]
- format.gsub!("%<#{token_index}>", regexp_str)
- token_order << arg_key
- }
-
- define_format_method(string_format, token_order.compact)
- return format, value_token_count
- rescue
- raise "The following format regular expression failed to compile: #{format}\n from format #{string_format}."
- end
-
- # Compiles a format method which maps the regexp capture groups to method
- # arguments based on order captured. A time array is built using the argument
- # values placed in the position defined by the component.
- #
- def define_format_method(name, components)
- values = [nil] * 8
- components.each do |component|
- position, code = *Formats.format_components[component]
- values[position] = code || "#{component}.to_i" if position
- end
- class_eval <<-DEF
- define_method(:"format_#{name}") do |#{components.join(',')}|
- [#{values.map {|i| i || 'nil' }.join(',')}]
- end
- DEF
- end
-
+ def self.compile(formats)
+ new(formats).compile!
end
def initialize(formats)
- @formats = formats
+ @formats = formats
+ @formats_hash = {}
+ @match_indexes = {}
end
# Compiles the formats into one big regexp. Stores the index of where
- # each format's capture values begin in the match data. Each individual
- # format regpexp is also stored for use with the parse :format option.
- #
+ # each format's capture values begin in the matchdata.
def compile!
- regexp_string = ''
- @format_regexps = {}
- @match_indexes = {}
- @formats.inject(0) { |index, format|
- format_regexp, token_count = self.class.compile_format(format)
- @format_regexps[format] = Regexp.new("^(#{format_regexp})$")
- @match_indexes[index] = format
- regexp_string = "#{regexp_string}(#{format_regexp})|"
- index + token_count + 1 # add one for wrapper capture
+ regexp_string = ''
+ @formats.inject(0) { |index, format_string|
+ format = Format.new(format_string).compile!
+ @formats_hash[format_string] = format
+ @match_indexes[index] = format
+ regexp_string = "#{regexp_string}(#{format.regexp_string})|"
+ index + format.token_count + 1 # add one for wrapper capture
}
@regexp = Regexp.new("^(?:#{regexp_string.chop})$")
+ self
end
- def match(string, format=nil)
- match_regexp = format ? @format_regexps[format] : @regexp
+ def match(string, format_string=nil)
+ format = @formats_hash[format_string] if format_string
+ match_regexp = format && format.regexp || @regexp
+
if match_data = match_regexp.match(string)
index = match_data.captures.index(string)
start = index + 1
values = match_data.captures[start..(start+7)].compact
format ||= @match_indexes[index]
- send(:"format_#{format}", *values)
+ format.process(*values)
end
end
end
end