chronic-davispuh 0.10.2.v0.1da32066b3f46f2506b3471e39557497e34afa27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +3 -0
  5. data/HISTORY.md +243 -0
  6. data/LICENSE +21 -0
  7. data/README.md +185 -0
  8. data/Rakefile +68 -0
  9. data/chronic.gemspec +27 -0
  10. data/lib/chronic.rb +122 -0
  11. data/lib/chronic/arrow.rb +270 -0
  12. data/lib/chronic/date.rb +272 -0
  13. data/lib/chronic/definition.rb +208 -0
  14. data/lib/chronic/dictionary.rb +36 -0
  15. data/lib/chronic/handler.rb +44 -0
  16. data/lib/chronic/handlers/anchor.rb +65 -0
  17. data/lib/chronic/handlers/arrow.rb +84 -0
  18. data/lib/chronic/handlers/date.rb +270 -0
  19. data/lib/chronic/handlers/date_time.rb +72 -0
  20. data/lib/chronic/handlers/general.rb +130 -0
  21. data/lib/chronic/handlers/narrow.rb +54 -0
  22. data/lib/chronic/handlers/time.rb +167 -0
  23. data/lib/chronic/handlers/time_zone.rb +50 -0
  24. data/lib/chronic/objects/anchor_object.rb +263 -0
  25. data/lib/chronic/objects/arrow_object.rb +27 -0
  26. data/lib/chronic/objects/date_object.rb +164 -0
  27. data/lib/chronic/objects/date_time_object.rb +64 -0
  28. data/lib/chronic/objects/handler_object.rb +81 -0
  29. data/lib/chronic/objects/narrow_object.rb +85 -0
  30. data/lib/chronic/objects/time_object.rb +96 -0
  31. data/lib/chronic/objects/time_zone_object.rb +27 -0
  32. data/lib/chronic/parser.rb +154 -0
  33. data/lib/chronic/span.rb +32 -0
  34. data/lib/chronic/tag.rb +84 -0
  35. data/lib/chronic/tags/day_name.rb +34 -0
  36. data/lib/chronic/tags/day_portion.rb +33 -0
  37. data/lib/chronic/tags/day_special.rb +30 -0
  38. data/lib/chronic/tags/grabber.rb +29 -0
  39. data/lib/chronic/tags/keyword.rb +63 -0
  40. data/lib/chronic/tags/month_name.rb +39 -0
  41. data/lib/chronic/tags/ordinal.rb +52 -0
  42. data/lib/chronic/tags/pointer.rb +28 -0
  43. data/lib/chronic/tags/rational.rb +35 -0
  44. data/lib/chronic/tags/scalar.rb +101 -0
  45. data/lib/chronic/tags/season_name.rb +31 -0
  46. data/lib/chronic/tags/separator.rb +130 -0
  47. data/lib/chronic/tags/sign.rb +35 -0
  48. data/lib/chronic/tags/time_special.rb +34 -0
  49. data/lib/chronic/tags/time_zone.rb +56 -0
  50. data/lib/chronic/tags/unit.rb +174 -0
  51. data/lib/chronic/time.rb +141 -0
  52. data/lib/chronic/time_zone.rb +80 -0
  53. data/lib/chronic/token.rb +61 -0
  54. data/lib/chronic/token_group.rb +271 -0
  55. data/lib/chronic/tokenizer.rb +42 -0
  56. data/lib/chronic/version.rb +3 -0
  57. data/test/helper.rb +12 -0
  58. data/test/test_chronic.rb +190 -0
  59. data/test/test_daylight_savings.rb +98 -0
  60. data/test/test_handler.rb +113 -0
  61. data/test/test_parsing.rb +1520 -0
  62. data/test/test_span.rb +23 -0
  63. data/test/test_token.rb +31 -0
  64. metadata +218 -0
@@ -0,0 +1,272 @@
1
+ module Chronic
2
+ class Date
3
+ YEAR_QUARTERS = 4
4
+ YEAR_MONTHS = 12
5
+ SEASON_MONTHS = 3
6
+ QUARTER_MONTHS = 3
7
+ MONTH_DAYS = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
8
+ MONTH_DAYS_LEAP = [nil, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
9
+ FORTNIGHT_DAYS = 14
10
+ WEEK_DAYS = 7
11
+ DAY_HOURS = 24
12
+ YEAR_SECONDS = 31_536_000 # 365 * 24 * 60 * 60
13
+ SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
14
+ QUARTER_SECONDS = 7_776_000 # 90 * 24 * 60 * 60
15
+ MONTH_SECONDS = 2_592_000 # 30 * 24 * 60 * 60
16
+ FORTNIGHT_SECONDS = 1_209_600 # 14 * 24 * 60 * 60
17
+ WEEK_SECONDS = 604_800 # 7 * 24 * 60 * 60
18
+ WEEKEND_SECONDS = 172_800 # 2 * 24 * 60 * 60
19
+ DAY_SECONDS = 86_400 # 24 * 60 * 60
20
+ SEASONS = [
21
+ :spring,
22
+ :summer,
23
+ :autumn,
24
+ :winter
25
+ ]
26
+ SEASON_DATES = {
27
+ :spring => [3, 20],
28
+ :summer => [6, 21],
29
+ :autumn => [9, 23],
30
+ :winter => [12, 22]
31
+ }
32
+ QUARTERS = [nil, 1, 4, 7, 10]
33
+ MONTHS = {
34
+ :january => 1,
35
+ :february => 2,
36
+ :march => 3,
37
+ :april => 4,
38
+ :may => 5,
39
+ :june => 6,
40
+ :july => 7,
41
+ :august => 8,
42
+ :september => 9,
43
+ :october => 10,
44
+ :november => 11,
45
+ :december => 12
46
+ }
47
+ DAYS = {
48
+ :sunday => 0,
49
+ :monday => 1,
50
+ :tuesday => 2,
51
+ :wednesday => 3,
52
+ :thursday => 4,
53
+ :friday => 5,
54
+ :saturday => 6
55
+ }
56
+
57
+ # Checks if given number could be day
58
+ def self.could_be_day?(day, width = nil)
59
+ day >= 1 && day <= 31 && (width.nil? || width <= 2)
60
+ end
61
+
62
+ # Checks if given number could be month
63
+ def self.could_be_month?(month, width = nil)
64
+ month >= 1 && month <= 12 && (width.nil? || width <= 2)
65
+ end
66
+
67
+ # Checks if given number could be year
68
+ def self.could_be_year?(year, width = nil)
69
+ year >= 0 && year <= 9999 && (width.nil? || width == 2 || width == 4)
70
+ end
71
+ # Build a year from a 2 digit suffix.
72
+ #
73
+ # year - The two digit Integer year to build from.
74
+ # bias - The Integer amount of future years to bias.
75
+ #
76
+ # Examples:
77
+ #
78
+ # make_year(96, 50) #=> 1996
79
+ # make_year(79, 20) #=> 2079
80
+ # make_year(00, 50) #=> 2000
81
+ #
82
+ # Returns The Integer 4 digit year.
83
+ def self.make_year(year, bias)
84
+ return year if year.to_s.size > 2
85
+ start_year = Chronic.time_class.now.year - bias
86
+ century = (start_year / 100) * 100
87
+ full_year = century + year
88
+ full_year += 100 if full_year < start_year
89
+ full_year
90
+ end
91
+
92
+ def self.days_month(year, month)
93
+ days_month = ::Date.leap?(year) ? Date::MONTH_DAYS_LEAP[month] : Date::MONTH_DAYS[month]
94
+ end
95
+
96
+ def self.month_overflow?(year, month, day)
97
+ day > days_month(year, month)
98
+ end
99
+
100
+ def self.add_season(year, season, modifier = 1)
101
+ index = SEASONS.index(season) + modifier
102
+ year += index / SEASONS.count
103
+ season = SEASONS[index % SEASONS.count]
104
+ [year, season]
105
+ end
106
+
107
+ def self.add_quarter(year, quarter, amount = 1)
108
+ quarter += amount
109
+ if quarter > YEAR_QUARTERS or quarter < 1
110
+ year += (quarter - 1) / YEAR_QUARTERS
111
+ quarter = (quarter - 1) % YEAR_QUARTERS + 1
112
+ end
113
+ [year, quarter]
114
+ end
115
+
116
+ def self.add_month(year, month, amount = 1)
117
+ month += amount
118
+ if month > YEAR_MONTHS or month < 1
119
+ year += (month - 1) / YEAR_MONTHS
120
+ month = (month - 1) % YEAR_MONTHS + 1
121
+ end
122
+ [year, month]
123
+ end
124
+
125
+ def self.add_day(year, month, day, amount = 1)
126
+ day += amount
127
+ days_month = self.days_month(year, month)
128
+ while day > days_month
129
+ day -= days_month
130
+ year, month = add_month(year, month, 1)
131
+ days_month = self.days_month(year, month)
132
+ end
133
+ days_prev_month = self.days_month(year, (month - 2) % YEAR_MONTHS + 1)
134
+ while day < 1
135
+ day += days_prev_month
136
+ year, month = add_month(year, month, -1)
137
+ days_prev_month = self.days_month(year, month)
138
+ end
139
+ [year, month, day]
140
+ end
141
+
142
+ def self.get_quarter_index(month)
143
+ (month - 1) / QUARTER_MONTHS + 1
144
+ end
145
+
146
+ def self.get_quarter_month(month)
147
+ (get_quarter_index(month) - 1) * QUARTER_MONTHS + 1
148
+ end
149
+
150
+ def self.get_quarter_end(quarter)
151
+ QUARTERS[(quarter - 1) % YEAR_QUARTERS + 1]
152
+ end
153
+
154
+ def self.normalize(year, month, day)
155
+ year, month = add_month(year, month, 0)
156
+ year, month, day = add_day(year, month, day, 0)
157
+ [year, month, day]
158
+ end
159
+
160
+ def self.split(date)
161
+ [date.year, date.month, date.day]
162
+ end
163
+
164
+ def self.calculate_difference(diff, limit, modifier = 1, context = 0)
165
+ state = diff <=> 0
166
+ unless modifier.zero?
167
+ skew = modifier
168
+ skew += (modifier <=> 0) * -1 if diff * modifier > 0
169
+ diff += limit * skew
170
+ end
171
+ unless context.zero?
172
+ if modifier.zero?
173
+ diff += limit * context if state * context <= 0
174
+ elsif state.zero?
175
+ diff += limit * context if modifier * context < 0
176
+ end
177
+ end
178
+ diff
179
+ end
180
+
181
+ # Calculate difference in days between given week day and date day
182
+ def self.wday_diff(date, wday, modifier = 1, context = 0)
183
+ self.calculate_difference(wday - date.wday, WEEK_DAYS, modifier, context)
184
+ end
185
+
186
+ # Get day difference for weekday
187
+ def self.wd_diff(date, modifier = 1)
188
+ diff = modifier
189
+ wday = date.wday
190
+ if modifier == 0 and wday == DAYS[:sunday]
191
+ diff = 1
192
+ elsif modifier == 0 and wday == DAYS[:saturday]
193
+ diff = 2
194
+ elsif modifier == 1 and wday == DAYS[:friday]
195
+ diff = 3
196
+ elsif modifier == 1 and wday == DAYS[:saturday]
197
+ diff = 2
198
+ elsif modifier == -1 and wday == DAYS[:sunday]
199
+ diff = -2
200
+ elsif modifier == -1 and wday == DAYS[:monday]
201
+ diff = -3
202
+ end
203
+ diff
204
+ end
205
+
206
+ # Calculate difference in months between given month and date month
207
+ def self.month_diff(date_month, month, modifier = 1, context = 0)
208
+ self.calculate_difference(month - date_month, YEAR_MONTHS, modifier, context)
209
+ end
210
+
211
+ # Calculate difference in quarters between given quarter and date quarter
212
+ def self.quarter_diff(date_quarter, quarter, modifier = 1, context = 0)
213
+ self.calculate_difference(quarter - date_quarter, YEAR_QUARTERS, modifier, context)
214
+ end
215
+
216
+ end
217
+
218
+ module DateStructure
219
+ attr_accessor :year
220
+ attr_accessor :month
221
+ attr_accessor :day
222
+ attr_accessor :have_year
223
+ attr_accessor :have_month
224
+ attr_accessor :have_day
225
+ attr_reader :precision
226
+ def update(date)
227
+ @year = date.year
228
+ @month = date.month
229
+ @day = date.day
230
+ self
231
+ end
232
+
233
+ def is_equal?(date)
234
+ @year == date.year &&
235
+ @month == date.month &&
236
+ @day == date.day
237
+ end
238
+
239
+ def add_day(amount = 1)
240
+ @year, @month, @day = Date::add_day(@year, @month, @day, amount)
241
+ end
242
+
243
+ def to_a
244
+ [@year, @month, @day]
245
+ end
246
+
247
+ def get_end
248
+ [@year, @month, @day]
249
+ end
250
+
251
+ def to_span(time = nil, timezone = nil)
252
+ hour = minute = second = 0
253
+ hour, minute, second = time.to_a if time
254
+ span_start = Chronic.construct(@year, @month, @day, hour, minute, second, timezone)
255
+ end_year, end_month, end_day = get_end
256
+ span_end = Chronic.construct(end_year, end_month, end_day, 0, 0, 0, timezone)
257
+ span = Span.new(span_start, span_end, true)
258
+ span.precision = @precision
259
+ span.precision = time.precision if time and time.precision
260
+ span
261
+ end
262
+ end
263
+
264
+ class DateInfo
265
+ include DateStructure
266
+ def initialize(now = nil)
267
+ @now = now ? now : Chronic.time_class.now
268
+ update(@now)
269
+ end
270
+ end
271
+
272
+ end
@@ -0,0 +1,208 @@
1
+ module Chronic
2
+ # SpanDefinitions subclasses return definitions constructed by Handler instances (see handler.rb)
3
+ # SpanDefinitions subclasses follow a <Type> + Definitions naming pattern
4
+ # Types of Definitions are collected in Dictionaries (see dictionary.rb)
5
+ class Definitions
6
+ attr_reader :options
7
+
8
+ def initialize(options = {})
9
+ @options = options
10
+ end
11
+
12
+ def definitions
13
+ raise "definitions are set in subclasses of #{self.class}"
14
+ end
15
+ end
16
+
17
+ class SpanDefinitions < Definitions
18
+ end
19
+
20
+ # Match only Time
21
+ class TimeDefinitions < SpanDefinitions
22
+ def definitions
23
+ [
24
+ [[SeparatorSpace, TimeSpecial, SeparatorSpace, [KeywordAt, :optional], [SeparatorSpace, :optional], ScalarHour, SeparatorColon, ScalarMinute], :handle_ts_h_m],
25
+ [[SeparatorSpace, TimeSpecial, SeparatorSpace, [KeywordAt, :optional], [SeparatorSpace, :optional], ScalarHour], :handle_ts_h],
26
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, SeparatorColon, ScalarMinute, SeparatorColon, ScalarSecond, [SeparatorDot, SeparatorColon], ScalarSubsecond], :handle_h_m_s_ss],
27
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, SeparatorColon, ScalarMinute, [SeparatorColon, SeparatorDot], ScalarSecond, [SeparatorSpace, :optional], DayPortion], :handle_h_m_s_dp],
28
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, SeparatorColon, ScalarMinute, [SeparatorColon, SeparatorDot], ScalarSecond], :handle_h_m_s],
29
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, [SeparatorColon, SeparatorDot], ScalarMinute, SeparatorSpace, [KeywordIn, KeywordAt], SeparatorSpace, TimeSpecial], :handle_h_m_ts],
30
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, [SeparatorColon, SeparatorDot], ScalarMinute, [SeparatorSpace, :optional], DayPortion], :handle_h_m_dp],
31
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, [SeparatorColon, SeparatorDot], ScalarMinute], :handle_h_m],
32
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarWide, [SeparatorSpace, :optional], DayPortion], :handle_hhmm_dp],
33
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, SeparatorSpace, KeywordIn, SeparatorSpace, TimeSpecial], :handle_h_ts],
34
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, SeparatorSpace, [KeywordAt, :optional], [SeparatorSpace, :optional], TimeSpecial], :handle_h_ts],
35
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, [SeparatorSpace, :optional], DayPortion], :handle_h_dp],
36
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarWide, SeparatorSpace], :handle_hhmm],
37
+ [[[KeywordAt, :optional], SeparatorSpace, TimeSpecial], :handle_ts],
38
+ [[[KeywordAt, :optional], SeparatorSpace, ScalarHour, SeparatorSpace], :handle_h]
39
+ ]
40
+ end
41
+ end
42
+
43
+ # Match only Date
44
+ class DateDefinitions < SpanDefinitions
45
+ def definitions
46
+ [
47
+ [[DayName, SeparatorSpace, MonthName, SeparatorSpace, OrdinalDay, SeparatorSpace, ScalarYear], :handle_dn_mn_od_sy],
48
+ [[DayName, SeparatorSpace, MonthName, SeparatorSpace, ScalarDay, SeparatorSpace, ScalarYear], :handle_dn_mn_sd_sy],
49
+ [[DayName, SeparatorSpace, MonthName, SeparatorSpace, OrdinalDay], :handle_dn_mn_od],
50
+ [[DayName, SeparatorSpace, MonthName, SeparatorSpace, ScalarDay], :handle_dn_mn_sd],
51
+ [[MonthName, SeparatorSpace, OrdinalDay, [SeparatorComma, SeparatorSpace], [SeparatorSpace, :optional], ScalarYear], :handle_mn_od_sy],
52
+ [[MonthName, SeparatorSpace, ScalarDay, [SeparatorComma, :optional], [SeparatorSpace, :optional], ScalarYear], :handle_mn_sd_sy],
53
+ [[ScalarYear, SeparatorSpace, MonthName, SeparatorSpace, OrdinalDay], :handle_sy_mn_od],
54
+ [[ScalarYear, SeparatorSpace, MonthName, SeparatorSpace, ScalarDay], :handle_sy_mn_sd],
55
+ [[ScalarYear, SeparatorSlash, ScalarMonth, SeparatorSlash, ScalarDay], :handle_sy_sm_sd],
56
+ [[ScalarYear, SeparatorDash, ScalarMonth, SeparatorDash, ScalarDay], :handle_sy_sm_sd],
57
+ [[ScalarYear, SeparatorDot, ScalarMonth, SeparatorDot, ScalarDay], :handle_sy_sm_sd],
58
+ [[ScalarYear, SeparatorColon, ScalarMonth, SeparatorColon, ScalarDay], :handle_sy_sm_sd],
59
+ [[OrdinalDay, SeparatorSpace, MonthName, SeparatorSpace, ScalarYear], :handle_od_mn_sy],
60
+ [[ScalarDay, SeparatorDash, MonthName, SeparatorDash, ScalarYear], :handle_sd_mn_sy],
61
+ [[ScalarDay, SeparatorSpace, MonthName, SeparatorSpace, ScalarYear], :handle_sd_mn_sy],
62
+ [[ScalarDay, SeparatorDot, ScalarMonth, SeparatorDot, ScalarYear], :handle_sd_sm_sy]
63
+ ]
64
+ end
65
+ end
66
+
67
+ # Match only Date in short form
68
+ class ShortDateDefinitions < SpanDefinitions
69
+ def definitions
70
+ [
71
+ [[DayName, SeparatorSpace, OrdinalDay], :handle_dn_od],
72
+ [[MonthName, SeparatorSpace, OrdinalDay], :handle_mn_od],
73
+ [[MonthName, [SeparatorSpace, SeparatorDash], ScalarDay, [SeparatorSpace, Unit, :none]], :handle_mn_sd],
74
+ [[MonthName, SeparatorSpace, SeparatorApostrophe, ScalarYear], :handle_mn_sy],
75
+ [[MonthName, SeparatorSpace, ScalarYear], :handle_mn_sy],
76
+ [[ScalarFullYear, [SeparatorDash, SeparatorSlash], ScalarMonth], :handle_sy_sm],
77
+ [[ScalarFullYear, SeparatorSpace, MonthName], :handle_sy_mn],
78
+ [[OrdinalDay, SeparatorSpace, MonthName], :handle_od_mn],
79
+ [[ScalarDay, [SeparatorSpace, SeparatorDash, :optional], MonthName], :handle_sd_mn],
80
+ [[KeywordIn, SeparatorSpace, MonthName], :handle_mn],
81
+ [[DaySpecial], :handle_ds],
82
+ [[MonthName], :handle_mn],
83
+ [[DayName], :handle_dn],
84
+ [[SeparatorSpace, ScalarYear, SeparatorSpace], :handle_sy],
85
+ [[OrdinalDay], :handle_od],
86
+ [[ScalarFullYear], :handle_sy]
87
+ ]
88
+ end
89
+ end
90
+
91
+ # Match only TimeZone
92
+ class TimezoneDefinitions < SpanDefinitions
93
+ def definitions
94
+ [
95
+ [[[Sign, :optional], ScalarHour, SeparatorColon, ScalarMinute], :handle_hh_mm],
96
+ [[Sign, ScalarWide], :handle_hhmm],
97
+ [[TimeZoneAbbreviation], :handle_abbr],
98
+ [[TimeZoneGeneric], :handle_generic]
99
+ ]
100
+ end
101
+ end
102
+
103
+ # Match full Date+Time, can be with TimeZone
104
+ class DateTimeDefinitions < SpanDefinitions
105
+ def definitions
106
+ [
107
+ [[DayName, SeparatorSpace, MonthName, SeparatorSpace, ScalarDay, SeparatorSpace, ScalarHour, SeparatorColon, ScalarMinute, SeparatorColon, ScalarSecond, SeparatorSpace, TimeZoneAbbreviation, SeparatorSpace, ScalarYear], :handle_dn_mn_sd_h_m_s_abbr_sy],
108
+ [[ScalarYear, SeparatorDash, ScalarMonth, SeparatorDash, ScalarDay, SeparatorT, ScalarHour, SeparatorColon, ScalarMinute, SeparatorColon, ScalarSecond, [SeparatorDot, SeparatorColon], ScalarSubsecond, Sign, ScalarHour, SeparatorColon, ScalarMinute], :handle_sy_sm_sd_h_m_s_ss_hh_mm],
109
+ [[ScalarYear, SeparatorDash, ScalarMonth, SeparatorDash, ScalarDay, SeparatorT, ScalarHour, SeparatorColon, ScalarMinute, SeparatorColon, ScalarSecond, Sign, ScalarHour, SeparatorColon, ScalarMinute], :handle_sy_sm_sd_h_m_s_hh_mm],
110
+ [[ScalarYear, SeparatorDash, ScalarMonth, SeparatorDash, ScalarDay, SeparatorT, ScalarHour, SeparatorColon, ScalarMinute, SeparatorColon, ScalarSecond, [SeparatorDot, SeparatorColon], ScalarSubsecond, TimeZoneGeneric], :handle_sy_sm_sd_h_m_s_ss_tz],
111
+ [[ScalarYear, SeparatorDash, ScalarMonth, SeparatorDash, ScalarDay, SeparatorT, ScalarHour, SeparatorColon, ScalarMinute, SeparatorColon, ScalarSecond, [SeparatorDot, SeparatorColon], ScalarSubsecond], :handle_sy_sm_sd_h_m_s_ss],
112
+ [[ScalarYear, SeparatorDash, ScalarMonth, SeparatorDash, ScalarDay, SeparatorT, ScalarHour, SeparatorColon, ScalarMinute, SeparatorColon, ScalarSecond, TimeZoneGeneric], :handle_sy_sm_sd_h_m_s_tz],
113
+ [[ScalarYear, SeparatorDash, ScalarMonth, SeparatorDash, ScalarDay, SeparatorT, ScalarHour, SeparatorColon, ScalarMinute, SeparatorColon, ScalarSecond], :handle_sy_sm_sd_h_m_s]
114
+ ]
115
+ end
116
+ end
117
+
118
+ class AnchorDefinitions < SpanDefinitions
119
+ def definitions
120
+ [
121
+ [[Grabber, SeparatorSpace, DayName], :handle_gr_dn],
122
+ [[Grabber, SeparatorSpace, MonthName], :handle_gr_mn],
123
+ [[Grabber, SeparatorSpace, SeasonName], :handle_gr_sn],
124
+ [[Grabber, SeparatorSpace, TimeSpecial], :handle_gr_ts],
125
+ [[Grabber, SeparatorSpace, KeywordQ, Scalar], :handle_gr_q_s],
126
+ [[Grabber, SeparatorSpace, Unit], :handle_gr_u],
127
+ [[KeywordIn, SeparatorSpace, Scalar, SeparatorSpace, Unit], :handle_in_s_u],
128
+ [[DaySpecial], :handle_ds],
129
+ [[KeywordQ, Scalar], :handle_q_s],
130
+ [[Unit], :handle_u]
131
+ ]
132
+ end
133
+ end
134
+
135
+ class ArrowDefinitions < SpanDefinitions
136
+ def definitions
137
+ [
138
+ [[Pointer, [SeparatorSpace, :optional], Scalar, [SeparatorSpace, :optional], Unit], :handle_p_s_u],
139
+ [[Scalar, [SeparatorSpace, :optional], Unit, SeparatorSpace, Pointer], :handle_s_u_p],
140
+ [[Scalar, [SeparatorSpace, :optional], DayName, SeparatorSpace, Pointer], :handle_s_dn_p],
141
+ [[Rational, SeparatorSpace, Pointer], :handle_r_p],
142
+ [[Unit, SeparatorSpace, Pointer], :handle_u_p],
143
+ [[Scalar, [SeparatorSpace, :optional], Unit], :handle_s_u],
144
+ [[Scalar, [SeparatorSpace, :optional], Pointer], :handle_s_p],
145
+ ]
146
+ end
147
+ end
148
+
149
+ class NarrowDefinitions < SpanDefinitions
150
+ def definitions
151
+ [
152
+ [[Grabber, SeparatorSpace, Ordinal, SeparatorSpace, Unit], :handle_gr_o_u],
153
+ [[Ordinal, SeparatorSpace, Unit], :handle_o_u],
154
+ [[Ordinal, SeparatorSpace, DayName], :handle_o_dn],
155
+ [[KeywordQ, Scalar], :handle_q_s]
156
+ ]
157
+ end
158
+ end
159
+
160
+ # Date depending on endianess
161
+ class EndianDefinitions < SpanDefinitions
162
+ def definitions
163
+ prefered_endian
164
+ end
165
+
166
+ def self.middle
167
+ [
168
+ [[ScalarMonth, SeparatorSlash, ScalarDay, SeparatorSlash, ScalarYear, [SeparatorDot, Scalar, :none]], :handle_sm_sd_sy],
169
+ [[ScalarMonth, SeparatorDash, ScalarDay, SeparatorDash, ScalarYear, [SeparatorDot, Scalar, :none]], :handle_sm_sd_sy],
170
+ [[ScalarMonth, [SeparatorSlash, SeparatorDash, SeparatorDot], ScalarDay, [SeparatorSlash, :none]], :handle_sm_sd]
171
+ ]
172
+ end
173
+
174
+ def self.little
175
+ [
176
+ [[ScalarDay, SeparatorDash, ScalarMonth, SeparatorDash, ScalarYear, [SeparatorDot, Scalar, :none]], :handle_sd_sm_sy],
177
+ [[ScalarDay, SeparatorSlash, ScalarMonth, SeparatorSlash, ScalarYear, [SeparatorDot, Scalar, :none]], :handle_sd_sm_sy],
178
+ [[ScalarDay, [SeparatorSlash, SeparatorDash, SeparatorDot], ScalarMonth, [SeparatorSlash, :none]], :handle_sd_sm]
179
+ ]
180
+ end
181
+
182
+ def self.month_year
183
+ [
184
+ [[ScalarMonth, SeparatorSlash, ScalarYear], :handle_sm_sy]
185
+ ]
186
+ end
187
+
188
+ def prefered_endian
189
+ options[:endian_precedence] ||= [:middle, :little]
190
+ options[:endian_precedence] = [options[:endian_precedence]] unless options[:endian_precedence].is_a?(Array)
191
+ definition_list = []
192
+ options[:endian_precedence].each do |endian|
193
+ case endian
194
+ when :little
195
+ definition_list += self.class.little
196
+ when :middle
197
+ definition_list += self.class.middle
198
+ when :month_year
199
+ definition_list += self.class.month_year
200
+ else
201
+ raise ArgumentError, "Unknown endian option '#{endian}'"
202
+ end
203
+ end
204
+ definition_list
205
+ end
206
+ end
207
+
208
+ end