gitlab-chronic 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.gitlab-ci.yml +14 -0
- data/.travis.yml +10 -0
- data/Gemfile +3 -0
- data/HISTORY.md +252 -0
- data/LICENSE +21 -0
- data/README.md +188 -0
- data/Rakefile +68 -0
- data/chronic.gemspec +25 -0
- data/lib/chronic.rb +155 -0
- data/lib/chronic/date.rb +81 -0
- data/lib/chronic/definition.rb +128 -0
- data/lib/chronic/dictionary.rb +36 -0
- data/lib/chronic/handler.rb +97 -0
- data/lib/chronic/handlers.rb +672 -0
- data/lib/chronic/mini_date.rb +38 -0
- data/lib/chronic/parser.rb +222 -0
- data/lib/chronic/repeaters/repeater_day.rb +54 -0
- data/lib/chronic/repeaters/repeater_day_name.rb +53 -0
- data/lib/chronic/repeaters/repeater_day_portion.rb +109 -0
- data/lib/chronic/repeaters/repeater_fortnight.rb +72 -0
- data/lib/chronic/repeaters/repeater_hour.rb +59 -0
- data/lib/chronic/repeaters/repeater_minute.rb +59 -0
- data/lib/chronic/repeaters/repeater_month.rb +80 -0
- data/lib/chronic/repeaters/repeater_month_name.rb +95 -0
- data/lib/chronic/repeaters/repeater_quarter.rb +59 -0
- data/lib/chronic/repeaters/repeater_quarter_name.rb +40 -0
- data/lib/chronic/repeaters/repeater_season.rb +111 -0
- data/lib/chronic/repeaters/repeater_season_name.rb +43 -0
- data/lib/chronic/repeaters/repeater_second.rb +43 -0
- data/lib/chronic/repeaters/repeater_time.rb +159 -0
- data/lib/chronic/repeaters/repeater_week.rb +76 -0
- data/lib/chronic/repeaters/repeater_weekday.rb +86 -0
- data/lib/chronic/repeaters/repeater_weekend.rb +67 -0
- data/lib/chronic/repeaters/repeater_year.rb +78 -0
- data/lib/chronic/season.rb +26 -0
- data/lib/chronic/span.rb +31 -0
- data/lib/chronic/tag.rb +89 -0
- data/lib/chronic/tags/grabber.rb +29 -0
- data/lib/chronic/tags/ordinal.rb +52 -0
- data/lib/chronic/tags/pointer.rb +28 -0
- data/lib/chronic/tags/repeater.rb +160 -0
- data/lib/chronic/tags/scalar.rb +89 -0
- data/lib/chronic/tags/separator.rb +123 -0
- data/lib/chronic/tags/sign.rb +35 -0
- data/lib/chronic/tags/time_zone.rb +32 -0
- data/lib/chronic/time.rb +40 -0
- data/lib/chronic/token.rb +61 -0
- data/lib/chronic/tokenizer.rb +38 -0
- data/lib/chronic/version.rb +3 -0
- data/test/helper.rb +12 -0
- data/test/test_chronic.rb +203 -0
- data/test/test_daylight_savings.rb +122 -0
- data/test/test_handler.rb +128 -0
- data/test/test_mini_date.rb +32 -0
- data/test/test_parsing.rb +1537 -0
- data/test/test_repeater_day_name.rb +51 -0
- data/test/test_repeater_day_portion.rb +254 -0
- data/test/test_repeater_fortnight.rb +62 -0
- data/test/test_repeater_hour.rb +68 -0
- data/test/test_repeater_minute.rb +34 -0
- data/test/test_repeater_month.rb +50 -0
- data/test/test_repeater_month_name.rb +56 -0
- data/test/test_repeater_quarter.rb +70 -0
- data/test/test_repeater_quarter_name.rb +198 -0
- data/test/test_repeater_season.rb +40 -0
- data/test/test_repeater_time.rb +88 -0
- data/test/test_repeater_week.rb +115 -0
- data/test/test_repeater_weekday.rb +55 -0
- data/test/test_repeater_weekend.rb +74 -0
- data/test/test_repeater_year.rb +69 -0
- data/test/test_span.rb +23 -0
- data/test/test_token.rb +31 -0
- metadata +215 -0
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'chronic/version'
|
3
|
+
|
4
|
+
def version
|
5
|
+
Chronic::VERSION
|
6
|
+
end
|
7
|
+
|
8
|
+
def do_test
|
9
|
+
require 'chronic'
|
10
|
+
$:.unshift './test'
|
11
|
+
Dir.glob('test/test_*.rb').each { |t| require File.basename(t) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def open_command
|
15
|
+
case RUBY_PLATFORM
|
16
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
17
|
+
'start'
|
18
|
+
when /darwin|mac os/
|
19
|
+
'open'
|
20
|
+
else
|
21
|
+
'xdg-open'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Run tests'
|
26
|
+
task :test do
|
27
|
+
do_test
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Generate SimpleCov test coverage and open in your browser'
|
31
|
+
task :coverage do
|
32
|
+
require 'simplecov'
|
33
|
+
FileUtils.rm_rf('./coverage')
|
34
|
+
SimpleCov.command_name 'Unit Tests'
|
35
|
+
SimpleCov.at_exit do
|
36
|
+
SimpleCov.result.format!
|
37
|
+
sh "#{open_command} #{SimpleCov.coverage_path}/index.html"
|
38
|
+
end
|
39
|
+
SimpleCov.start
|
40
|
+
do_test
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Open an irb session preloaded with this library'
|
44
|
+
task :console do
|
45
|
+
sh 'irb -Ilib -rchronic'
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Release Chronic version #{version}"
|
49
|
+
task :release => :build do
|
50
|
+
unless `git branch` =~ /^\* master$/
|
51
|
+
puts "You must be on the master branch to release!"
|
52
|
+
exit!
|
53
|
+
end
|
54
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
55
|
+
sh "git tag v#{version}"
|
56
|
+
sh "git push origin master"
|
57
|
+
sh "git push origin v#{version}"
|
58
|
+
sh "gem push pkg/chronic-#{version}.gem"
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'Build a gem from the gemspec'
|
62
|
+
task :build do
|
63
|
+
FileUtils.mkdir_p 'pkg'
|
64
|
+
sh 'gem build chronic.gemspec'
|
65
|
+
FileUtils.mv("./gitlab-chronic-#{version}.gem", "pkg")
|
66
|
+
end
|
67
|
+
|
68
|
+
task :default => :test
|
data/chronic.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'chronic/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'gitlab-chronic'
|
6
|
+
s.version = Chronic::VERSION
|
7
|
+
s.rubyforge_project = 'chronic'
|
8
|
+
s.summary = 'Natural language date/time parsing.'
|
9
|
+
s.description = 'Chronic is a natural language date/time parser written in pure Ruby.'
|
10
|
+
s.authors = ['Tom Preston-Werner', 'Lee Jarvis']
|
11
|
+
s.email = ['tom@mojombo.com', 'ljjarvis@gmail.com']
|
12
|
+
s.homepage = 'https://gitlab.com/gitlab-org/gitlab-chronic'
|
13
|
+
s.license = 'MIT'
|
14
|
+
s.rdoc_options = ['--charset=UTF-8']
|
15
|
+
s.extra_rdoc_files = %w[README.md HISTORY.md LICENSE]
|
16
|
+
s.files = `git ls-files`.split($/)
|
17
|
+
s.test_files = `git ls-files -- test`.split($/)
|
18
|
+
|
19
|
+
s.add_runtime_dependency 'numerizer', '~> 0.2'
|
20
|
+
|
21
|
+
s.add_development_dependency 'rake', '~> 10'
|
22
|
+
s.add_development_dependency 'simplecov', '~> 0'
|
23
|
+
s.add_development_dependency 'minitest', '~> 5.0'
|
24
|
+
s.add_development_dependency 'activesupport', '~> 4'
|
25
|
+
end
|
data/lib/chronic.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'date'
|
3
|
+
require 'numerizer'
|
4
|
+
|
5
|
+
require 'chronic/version'
|
6
|
+
|
7
|
+
require 'chronic/parser'
|
8
|
+
require 'chronic/date'
|
9
|
+
require 'chronic/time'
|
10
|
+
|
11
|
+
require 'chronic/handler'
|
12
|
+
require 'chronic/handlers'
|
13
|
+
require 'chronic/mini_date'
|
14
|
+
require 'chronic/span'
|
15
|
+
require 'chronic/token'
|
16
|
+
require 'chronic/tokenizer'
|
17
|
+
require 'chronic/season'
|
18
|
+
|
19
|
+
require 'chronic/tag'
|
20
|
+
require 'chronic/tags/grabber'
|
21
|
+
require 'chronic/tags/ordinal'
|
22
|
+
require 'chronic/tags/pointer'
|
23
|
+
require 'chronic/tags/scalar'
|
24
|
+
require 'chronic/tags/separator'
|
25
|
+
require 'chronic/tags/sign'
|
26
|
+
require 'chronic/tags/time_zone'
|
27
|
+
|
28
|
+
require 'chronic/tags/repeater'
|
29
|
+
require 'chronic/repeaters/repeater_year'
|
30
|
+
require 'chronic/repeaters/repeater_quarter'
|
31
|
+
require 'chronic/repeaters/repeater_quarter_name'
|
32
|
+
require 'chronic/repeaters/repeater_season'
|
33
|
+
require 'chronic/repeaters/repeater_season_name'
|
34
|
+
require 'chronic/repeaters/repeater_month'
|
35
|
+
require 'chronic/repeaters/repeater_month_name'
|
36
|
+
require 'chronic/repeaters/repeater_fortnight'
|
37
|
+
require 'chronic/repeaters/repeater_week'
|
38
|
+
require 'chronic/repeaters/repeater_weekend'
|
39
|
+
require 'chronic/repeaters/repeater_weekday'
|
40
|
+
require 'chronic/repeaters/repeater_day'
|
41
|
+
require 'chronic/repeaters/repeater_day_name'
|
42
|
+
require 'chronic/repeaters/repeater_day_portion'
|
43
|
+
require 'chronic/repeaters/repeater_hour'
|
44
|
+
require 'chronic/repeaters/repeater_minute'
|
45
|
+
require 'chronic/repeaters/repeater_second'
|
46
|
+
require 'chronic/repeaters/repeater_time'
|
47
|
+
|
48
|
+
# Parse natural language dates and times into Time or Chronic::Span objects.
|
49
|
+
#
|
50
|
+
# Examples:
|
51
|
+
#
|
52
|
+
# require 'chronic'
|
53
|
+
#
|
54
|
+
# Time.now #=> Sun Aug 27 23:18:25 PDT 2006
|
55
|
+
#
|
56
|
+
# Chronic.parse('tomorrow')
|
57
|
+
# #=> Mon Aug 28 12:00:00 PDT 2006
|
58
|
+
#
|
59
|
+
# Chronic.parse('monday', :context => :past)
|
60
|
+
# #=> Mon Aug 21 12:00:00 PDT 2006
|
61
|
+
module Chronic
|
62
|
+
|
63
|
+
class << self
|
64
|
+
|
65
|
+
# Returns true when debug mode is enabled.
|
66
|
+
attr_accessor :debug
|
67
|
+
|
68
|
+
# Examples:
|
69
|
+
#
|
70
|
+
# require 'chronic'
|
71
|
+
# require 'active_support/time'
|
72
|
+
#
|
73
|
+
# Time.zone = 'UTC'
|
74
|
+
# Chronic.time_class = Time.zone
|
75
|
+
# Chronic.parse('June 15 2006 at 5:54 AM')
|
76
|
+
# # => Thu, 15 Jun 2006 05:45:00 UTC +00:00
|
77
|
+
#
|
78
|
+
# Returns The Time class Chronic uses internally.
|
79
|
+
attr_accessor :time_class
|
80
|
+
end
|
81
|
+
|
82
|
+
self.debug = false
|
83
|
+
self.time_class = ::Time
|
84
|
+
|
85
|
+
|
86
|
+
# Parses a string containing a natural language date or time.
|
87
|
+
#
|
88
|
+
# If the parser can find a date or time, either a Time or Chronic::Span
|
89
|
+
# will be returned (depending on the value of `:guess`). If no
|
90
|
+
# date or time can be found, `nil` will be returned.
|
91
|
+
#
|
92
|
+
# text - The String text to parse.
|
93
|
+
# opts - An optional Hash of configuration options passed to Parser::new.
|
94
|
+
def self.parse(text, options = {})
|
95
|
+
Parser.new(options).parse(text)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Construct a new time object determining possible month overflows
|
99
|
+
# and leap years.
|
100
|
+
#
|
101
|
+
# year - Integer year.
|
102
|
+
# month - Integer month.
|
103
|
+
# day - Integer day.
|
104
|
+
# hour - Integer hour.
|
105
|
+
# minute - Integer minute.
|
106
|
+
# second - Integer second.
|
107
|
+
#
|
108
|
+
# Returns a new Time object constructed from these params.
|
109
|
+
def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, offset = nil)
|
110
|
+
if second >= 60
|
111
|
+
minute += second / 60
|
112
|
+
second = second % 60
|
113
|
+
end
|
114
|
+
|
115
|
+
if minute >= 60
|
116
|
+
hour += minute / 60
|
117
|
+
minute = minute % 60
|
118
|
+
end
|
119
|
+
|
120
|
+
if hour >= 24
|
121
|
+
day += hour / 24
|
122
|
+
hour = hour % 24
|
123
|
+
end
|
124
|
+
|
125
|
+
# determine if there is a day overflow. this is complicated by our crappy calendar
|
126
|
+
# system (non-constant number of days per month)
|
127
|
+
day <= 56 || raise('day must be no more than 56 (makes month resolution easier)')
|
128
|
+
if day > 28 # no month ever has fewer than 28 days, so only do this if necessary
|
129
|
+
days_this_month = ::Date.leap?(year) ? Date::MONTH_DAYS_LEAP[month] : Date::MONTH_DAYS[month]
|
130
|
+
if day > days_this_month
|
131
|
+
month += day / days_this_month
|
132
|
+
day = day % days_this_month
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
if month > 12
|
137
|
+
if month % 12 == 0
|
138
|
+
year += (month - 12) / 12
|
139
|
+
month = 12
|
140
|
+
else
|
141
|
+
year += month / 12
|
142
|
+
month = month % 12
|
143
|
+
end
|
144
|
+
end
|
145
|
+
if Chronic.time_class.name == 'Date'
|
146
|
+
Chronic.time_class.new(year, month, day)
|
147
|
+
elsif not Chronic.time_class.respond_to?(:new) or (RUBY_VERSION.to_f < 1.9 and Chronic.time_class.name == 'Time')
|
148
|
+
Chronic.time_class.local(year, month, day, hour, minute, second)
|
149
|
+
else
|
150
|
+
offset = Time::normalize_offset(offset) if Chronic.time_class.name == 'DateTime'
|
151
|
+
Chronic.time_class.new(year, month, day, hour, minute, second, offset)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
data/lib/chronic/date.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
module Chronic
|
2
|
+
class Date
|
3
|
+
YEAR_MONTHS = 12
|
4
|
+
MONTH_DAYS = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
5
|
+
MONTH_DAYS_LEAP = [nil, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
6
|
+
YEAR_SECONDS = 31_536_000 # 365 * 24 * 60 * 60
|
7
|
+
SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
|
8
|
+
MONTH_SECONDS = 2_592_000 # 30 * 24 * 60 * 60
|
9
|
+
FORTNIGHT_SECONDS = 1_209_600 # 14 * 24 * 60 * 60
|
10
|
+
WEEK_SECONDS = 604_800 # 7 * 24 * 60 * 60
|
11
|
+
WEEKEND_SECONDS = 172_800 # 2 * 24 * 60 * 60
|
12
|
+
DAY_SECONDS = 86_400 # 24 * 60 * 60
|
13
|
+
MONTHS = {
|
14
|
+
:january => 1,
|
15
|
+
:february => 2,
|
16
|
+
:march => 3,
|
17
|
+
:april => 4,
|
18
|
+
:may => 5,
|
19
|
+
:june => 6,
|
20
|
+
:july => 7,
|
21
|
+
:august => 8,
|
22
|
+
:september => 9,
|
23
|
+
:october => 10,
|
24
|
+
:november => 11,
|
25
|
+
:december => 12
|
26
|
+
}
|
27
|
+
DAYS = {
|
28
|
+
:sunday => 0,
|
29
|
+
:monday => 1,
|
30
|
+
:tuesday => 2,
|
31
|
+
:wednesday => 3,
|
32
|
+
:thursday => 4,
|
33
|
+
:friday => 5,
|
34
|
+
:saturday => 6
|
35
|
+
}
|
36
|
+
|
37
|
+
# Checks if given number could be day
|
38
|
+
def self.could_be_day?(day, width = nil)
|
39
|
+
day >= 1 && day <= 31 && (width.nil? || width <= 2)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Checks if given number could be month
|
43
|
+
def self.could_be_month?(month, width = nil)
|
44
|
+
month >= 1 && month <= 12 && (width.nil? || width <= 2)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Checks if given number could be year
|
48
|
+
def self.could_be_year?(year, width = nil)
|
49
|
+
year >= 0 && year <= 9999 && (width.nil? || width == 2 || width == 4)
|
50
|
+
end
|
51
|
+
# Build a year from a 2 digit suffix.
|
52
|
+
#
|
53
|
+
# year - The two digit Integer year to build from.
|
54
|
+
# bias - The Integer amount of future years to bias.
|
55
|
+
#
|
56
|
+
# Examples:
|
57
|
+
#
|
58
|
+
# make_year(96, 50) #=> 1996
|
59
|
+
# make_year(79, 20) #=> 2079
|
60
|
+
# make_year(00, 50) #=> 2000
|
61
|
+
#
|
62
|
+
# Returns The Integer 4 digit year.
|
63
|
+
def self.make_year(year, bias)
|
64
|
+
return year if year.to_s.size > 2
|
65
|
+
start_year = Chronic.time_class.now.year - bias
|
66
|
+
century = (start_year / 100) * 100
|
67
|
+
full_year = century + year
|
68
|
+
full_year += 100 if full_year < start_year
|
69
|
+
full_year
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.month_overflow?(year, month, day)
|
73
|
+
if ::Date.leap?(year)
|
74
|
+
day > Date::MONTH_DAYS_LEAP[month]
|
75
|
+
else
|
76
|
+
day > Date::MONTH_DAYS[month]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'chronic/handlers'
|
2
|
+
|
3
|
+
module Chronic
|
4
|
+
# SpanDefinitions subclasses return definitions constructed by Handler instances (see handler.rb)
|
5
|
+
# SpanDefinitions subclasses follow a <Type> + Definitions naming pattern
|
6
|
+
# Types of Definitions are collected in Dictionaries (see dictionary.rb)
|
7
|
+
class Definitions
|
8
|
+
attr_reader :options
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def definitions
|
15
|
+
raise "definitions are set in subclasses of #{self.class}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class SpanDefinitions < Definitions
|
20
|
+
include Handlers
|
21
|
+
end
|
22
|
+
|
23
|
+
class TimeDefinitions < SpanDefinitions
|
24
|
+
def definitions
|
25
|
+
[
|
26
|
+
Handler.new([:repeater_time, :repeater_day_portion?], nil)
|
27
|
+
]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class DateDefinitions < SpanDefinitions
|
32
|
+
def definitions
|
33
|
+
[
|
34
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :repeater_time, [:separator_slash?, :separator_dash?], :time_zone, :scalar_year], :handle_generic),
|
35
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day], :handle_rdn_rmn_sd),
|
36
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :scalar_year], :handle_rdn_rmn_sd_sy),
|
37
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :ordinal_day], :handle_rdn_rmn_od),
|
38
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :ordinal_day, :scalar_year], :handle_rdn_rmn_od_sy),
|
39
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rdn_rmn_sd),
|
40
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rdn_rmn_od),
|
41
|
+
Handler.new([:repeater_day_name, :ordinal_day, :separator_at?, 'time?'], :handle_rdn_od),
|
42
|
+
Handler.new([:scalar_year, [:separator_slash, :separator_dash], :scalar_month, [:separator_slash, :separator_dash], :scalar_day, :repeater_time, :time_zone], :handle_generic),
|
43
|
+
Handler.new([:ordinal_day], :handle_generic),
|
44
|
+
Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :handle_rmn_sd_sy),
|
45
|
+
Handler.new([:repeater_month_name, :ordinal_day, :scalar_year], :handle_rmn_od_sy),
|
46
|
+
Handler.new([:repeater_month_name, :scalar_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_sd_sy),
|
47
|
+
Handler.new([:repeater_month_name, :ordinal_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_od_sy),
|
48
|
+
Handler.new([:repeater_month_name, [:separator_slash?, :separator_dash?], :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
|
49
|
+
Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :scalar_day], :handle_rmn_sd_on),
|
50
|
+
Handler.new([:repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rmn_od),
|
51
|
+
Handler.new([:ordinal_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_od_rmn_sy),
|
52
|
+
Handler.new([:ordinal_day, :repeater_month_name, :separator_at?, 'time?'], :handle_od_rmn),
|
53
|
+
Handler.new([:ordinal_day, :grabber?, :repeater_month, :separator_at?, 'time?'], :handle_od_rm),
|
54
|
+
Handler.new([:scalar_year, :repeater_month_name, :ordinal_day], :handle_sy_rmn_od),
|
55
|
+
Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :ordinal_day], :handle_rmn_od_on),
|
56
|
+
Handler.new([:repeater_month_name, :scalar_year], :handle_rmn_sy),
|
57
|
+
Handler.new([:repeater_quarter_name, :scalar_year], :handle_rqn_sy),
|
58
|
+
Handler.new([:scalar_year, :repeater_quarter_name], :handle_sy_rqn),
|
59
|
+
Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy),
|
60
|
+
Handler.new([:scalar_day, [:separator_slash?, :separator_dash?], :repeater_month_name, :separator_at?, 'time?'], :handle_sd_rmn),
|
61
|
+
Handler.new([:scalar_year, [:separator_slash, :separator_dash], :scalar_month, [:separator_slash, :separator_dash], :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
|
62
|
+
Handler.new([:scalar_year, [:separator_slash, :separator_dash], :scalar_month], :handle_sy_sm),
|
63
|
+
Handler.new([:scalar_month, [:separator_slash, :separator_dash], :scalar_year], :handle_sm_sy),
|
64
|
+
Handler.new([:scalar_day, [:separator_slash, :separator_dash], :repeater_month_name, [:separator_slash, :separator_dash], :scalar_year, :repeater_time?], :handle_sm_rmn_sy),
|
65
|
+
Handler.new([:scalar_year, [:separator_slash, :separator_dash], :scalar_month, [:separator_slash, :separator_dash], :scalar?, :time_zone], :handle_generic),
|
66
|
+
]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class AnchorDefinitions < SpanDefinitions
|
71
|
+
def definitions
|
72
|
+
[
|
73
|
+
Handler.new([:separator_on?, :grabber?, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
|
74
|
+
Handler.new([:grabber?, :repeater, :repeater, :separator?, :repeater?, :repeater?], :handle_r),
|
75
|
+
Handler.new([:repeater, :grabber, :repeater], :handle_r_g_r)
|
76
|
+
]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class ArrowDefinitions < SpanDefinitions
|
81
|
+
def definitions
|
82
|
+
[
|
83
|
+
Handler.new([:repeater_month_name, :scalar, :repeater, :pointer], :handle_rmn_s_r_p),
|
84
|
+
Handler.new([:scalar, :repeater, :pointer], :handle_s_r_p),
|
85
|
+
Handler.new([:scalar, :repeater, :separator_and?, :scalar, :repeater, :pointer, :separator_at?, 'anchor'], :handle_s_r_a_s_r_p_a),
|
86
|
+
Handler.new([:pointer, :scalar, :repeater], :handle_p_s_r),
|
87
|
+
Handler.new([:scalar, :repeater, :pointer, :separator_at?, 'anchor'], :handle_s_r_p_a)
|
88
|
+
]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class NarrowDefinitions < SpanDefinitions
|
93
|
+
def definitions
|
94
|
+
[
|
95
|
+
Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
|
96
|
+
Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)
|
97
|
+
]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class EndianDefinitions < SpanDefinitions
|
102
|
+
def definitions
|
103
|
+
prefered_endian
|
104
|
+
end
|
105
|
+
|
106
|
+
def prefered_endian
|
107
|
+
options[:endian_precedence] ||= [:middle, :little]
|
108
|
+
|
109
|
+
definitions = [
|
110
|
+
Handler.new([:scalar_month, [:separator_slash, :separator_dash], :scalar_day, [:separator_slash, :separator_dash], :scalar_year, :separator_at?, 'time?'], :handle_sm_sd_sy),
|
111
|
+
Handler.new([:scalar_month, [:separator_slash, :separator_dash], :scalar_day, :separator_at?, 'time?'], :handle_sm_sd),
|
112
|
+
Handler.new([:scalar_day, [:separator_slash, :separator_dash], :scalar_month, :separator_at?, 'time?'], :handle_sd_sm),
|
113
|
+
Handler.new([:scalar_day, [:separator_slash, :separator_dash], :scalar_month, [:separator_slash, :separator_dash], :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy),
|
114
|
+
Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy)
|
115
|
+
]
|
116
|
+
|
117
|
+
case endian = Array(options[:endian_precedence]).first
|
118
|
+
when :little
|
119
|
+
definitions.reverse
|
120
|
+
when :middle
|
121
|
+
definitions
|
122
|
+
else
|
123
|
+
raise ArgumentError, "Unknown endian option '#{endian}'"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|