lib/stamp/translator.rb in stamp-0.5.0 vs lib/stamp/translator.rb in stamp-0.6.0
- old
+ new
@@ -32,97 +32,81 @@
MERIDIAN_UPPER_REGEXP = /^(A|P)M$/
ORDINAL_DAY_REGEXP = /^(\d{1,2})(st|nd|rd|th)$/
# Disambiguate based on value
- OBVIOUS_YEARS = 60..99
- OBVIOUS_MONTHS = 12
- OBVIOUS_DAYS = 13..31
OBVIOUS_24_HOUR = 13..23
+ OBVIOUS_DAY = 13..31
+ OBVIOUS_YEAR = 32..99
TWO_DIGIT_YEAR_EMITTER = Emitters::TwoDigit.new(:year) { |year| year % 100 }
TWO_DIGIT_MONTH_EMITTER = Emitters::TwoDigit.new(:month)
TWO_DIGIT_DAY_EMITTER = Emitters::TwoDigit.new(:day)
HOUR_TO_12_HOUR = lambda { |h| ((h - 1) % 12) + 1 }
- OBVIOUS_DATE_MAP = {
- OBVIOUS_YEARS => TWO_DIGIT_YEAR_EMITTER,
- OBVIOUS_MONTHS => TWO_DIGIT_MONTH_EMITTER,
- OBVIOUS_DAYS => TWO_DIGIT_DAY_EMITTER
- }
-
- TWO_DIGIT_DATE_SUCCESSION = {
- :month => TWO_DIGIT_DAY_EMITTER,
- :day => TWO_DIGIT_YEAR_EMITTER,
- :year => TWO_DIGIT_MONTH_EMITTER
- }
-
- TWO_DIGIT_TIME_SUCCESSION = {
- :hour => Emitters::TwoDigit.new(:min),
- :min => Emitters::TwoDigit.new(:sec)
- }
-
def translate(example)
# extract any substrings that look like times, like "23:59" or "8:37 am"
before, time_example, after = example.partition(TIME_REGEXP)
# build emitters from the example date
emitters = Emitters::Composite.new
- emitters << build_emitters(before.split(/\b/)) do |token, previous_part|
- date_emitter(token, previous_part)
+ emitters << build_emitters(before.split(/\b/)) do |token|
+ date_emitter(token)
end
# build emitters from the example time
unless time_example.empty?
time_parts = time_example.scan(TIME_REGEXP).first
- emitters << build_emitters(time_parts) do |token, previous_part|
- time_emitter(token, previous_part)
+ emitters << build_emitters(time_parts) do |token|
+ time_emitter(token)
end
end
# recursively process any remaining text
emitters << translate(after) unless after.empty?
emitters
end
# Transforms tokens that look like date/time parts to emitter objects.
def build_emitters(tokens)
- previous_part = nil
tokens.map do |token|
- emitter = yield(token, previous_part)
- previous_part = emitter.field unless emitter.nil?
-
- emitter || Emitters::String.new(token)
+ yield(token) || Emitters::String.new(token)
end
end
- def time_emitter(token, previous_part)
+ def time_emitter(token)
case token
when MERIDIAN_LOWER_REGEXP
Emitters::AmPm.new
when MERIDIAN_UPPER_REGEXP
Emitters::AmPm.new { |v| v.upcase }
when TWO_DIGIT_REGEXP
- TWO_DIGIT_TIME_SUCCESSION[previous_part] ||
- case token.to_i
- when OBVIOUS_24_HOUR
- # 24-hour clock
- Emitters::TwoDigit.new(:hour)
- else
- # 12-hour clock with leading zero
- Emitters::TwoDigit.new(:hour, &HOUR_TO_12_HOUR)
- end
+ Emitters::Ambiguous.new(
+ two_digit_hour_emitter(token),
+ Emitters::TwoDigit.new(:min),
+ Emitters::TwoDigit.new(:sec))
when ONE_DIGIT_REGEXP
# 12-hour clock without leading zero
Emitters::Delegate.new(:hour, &HOUR_TO_12_HOUR)
end
end
- def date_emitter(token, previous_part)
+ def two_digit_hour_emitter(token)
+ case token.to_i
+ when OBVIOUS_24_HOUR
+ # 24-hour clock
+ Emitters::TwoDigit.new(:hour)
+ else
+ # 12-hour clock with leading zero
+ Emitters::TwoDigit.new(:hour, &HOUR_TO_12_HOUR)
+ end
+ end
+
+ def date_emitter(token)
case token
when MONTHNAMES_REGEXP
Emitters::Lookup.new(:month, Date::MONTHNAMES)
when ABBR_MONTHNAMES_REGEXP
@@ -144,24 +128,25 @@
Emitters::Ordinal.new(:day)
when TWO_DIGIT_REGEXP
value = token.to_i
- obvious_mappings =
- OBVIOUS_DATE_MAP.reject { |k,v| v.field == previous_part }
-
- obvious_directive = obvious_mappings.find do |range, directive|
- break directive if range === value
+ case value
+ when OBVIOUS_DAY
+ TWO_DIGIT_DAY_EMITTER
+ when OBVIOUS_YEAR
+ TWO_DIGIT_YEAR_EMITTER
+ else
+ Emitters::Ambiguous.new(
+ TWO_DIGIT_MONTH_EMITTER,
+ TWO_DIGIT_DAY_EMITTER,
+ TWO_DIGIT_YEAR_EMITTER)
end
- # if the intent isn't obvious based on the example value, try to
- # disambiguate based on context
- obvious_directive ||
- TWO_DIGIT_DATE_SUCCESSION[previous_part] ||
- TWO_DIGIT_MONTH_EMITTER
-
when ONE_DIGIT_REGEXP
- Emitters::Delegate.new(:day)
+ Emitters::Ambiguous.new(
+ Emitters::Delegate.new(:month),
+ Emitters::Delegate.new(:day))
end
end
end
end