fugit 1.3.5 → 1.3.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2a28ef486584f37659fbcf4e6e4fecfc76aa2a4a6e1fc61d25dd3c44cd3a5c3
4
- data.tar.gz: db726ca071f0f98d0f59c3054fca04a537ec2a17fd302013b354d90e1d7dc3c8
3
+ metadata.gz: 90b61604e15e2cb24d4fb124306affea15a644c2591fc3a49649981616351d66
4
+ data.tar.gz: 235eec423691346077fd9cfdaed895e28843ecf6681b5aa00a83cfcf9ca711a3
5
5
  SHA512:
6
- metadata.gz: d1105627f83fd730a7826047679edfd38ad7deb19960715e93769d5c04e80e0079b02b9513f9e5d01614e2e70b75a016a2e16b7a72f568e2a5d3072c42e7e1dc
7
- data.tar.gz: eb4b14f1f564bd89ae919c16d6c06ef180b725c81b8d78225661b0a0fb34dee067063de9f2b883e6361e51c0db323224b6ee0a80ab3ca80dd9091a0e872ceae4
6
+ metadata.gz: 1fd5abf6871b1cb60220bf7d6089be6bff48dfae80a05db6d031def126275940d50cbc5dfcaad493f2b6d327b66162c2a44329966459bfb3d9d5b912e3b7e68c
7
+ data.tar.gz: '08a846fcce60834f8f0c289e14317249123f1f4028c478953ed04f759e633080c4d843f55c56fb973a104e1b44bbbbc92eecc978a954d7b0b317d7b23b82611b'
@@ -2,6 +2,12 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
+ ## fugit 1.3.6 released 2020-06-01
6
+
7
+ * Introduce new nat syntaxed, gh-38
8
+ * Rework nat parser
9
+
10
+
5
11
  ## fugit 1.3.5 released 2020-05-07
6
12
 
7
13
  * Implement cron @noon, gh-37
data/CREDITS.md CHANGED
@@ -1,6 +1,7 @@
1
1
 
2
2
  # fugit credits
3
3
 
4
+ * Danny Ben Shitrit https://github.com/DannyBen nat variants, gh-38
4
5
  * Dominik Sander https://github.com/dsander #rough_frequency 0, gh-36
5
6
  * Milovan Zogovic https://github.com/assembler Cron#match? vs TZ, gh-31
6
7
  * Jessica Stokes https://github.com/ticky 0-24 issue with cron, gh-30
data/README.md CHANGED
@@ -232,6 +232,29 @@ p d.to_plain_s # => "2Y2M1D5h3600s"
232
232
  p Fugit::Duration.parse('1y2M1d4h').to_sec # => 36820800
233
233
  ```
234
234
 
235
+ There is a `#deflate` method
236
+
237
+ ```ruby
238
+ Fugit::Duration.parse(1000).to_plain_s # => "1000s"
239
+ Fugit::Duration.parse(3600).to_plain_s # => "3600s"
240
+ Fugit::Duration.parse(1000).deflate.to_plain_s # => "16m40s"
241
+ Fugit::Duration.parse(3600).deflate.to_plain_s # => "1h"
242
+
243
+ # or event shorter
244
+ Fugit.parse(1000).deflate.to_plain_s # => "16m40s"
245
+ Fugit.parse(3600).deflate.to_plain_s # => "1h"
246
+ ```
247
+
248
+ There is also an `#inflate` method
249
+
250
+ ```ruby
251
+ Fugit::Duration.parse('1h30m12').inflate.to_plain_s # => "5412s"
252
+ Fugit.parse('1h30m12').inflate.to_plain_s # => "5412s"
253
+
254
+ Fugit.parse('1h30m12').to_sec # => 5412
255
+ Fugit.parse('1h30m12').to_sec.to_s + 's' # => "5412s"
256
+ ```
257
+
235
258
  The `to_*_s` methods are also available as class methods:
236
259
  ```ruby
237
260
  p Fugit::Duration.to_plain_s('1y2M1d4h')
@@ -40,7 +40,7 @@ Time tools for flor and the floraison project. Cron parsing and occurrence compu
40
40
  #s.add_runtime_dependency 'tzinfo'
41
41
  # this dependency appears in 'et-orbi'
42
42
 
43
- s.add_runtime_dependency 'raabro', '~> 1.1'
43
+ s.add_runtime_dependency 'raabro', '~> 1.3'
44
44
  s.add_runtime_dependency 'et-orbi', '~> 1.1', '>= 1.1.8'
45
45
 
46
46
  s.add_development_dependency 'rspec', '~> 3.8'
@@ -1,7 +1,7 @@
1
1
 
2
2
  module Fugit
3
3
 
4
- VERSION = '1.3.5'
4
+ VERSION = '1.3.6'
5
5
  end
6
6
 
7
7
  require 'time'
@@ -757,7 +757,7 @@ module Fugit
757
757
 
758
758
  def rewrite_tz(t)
759
759
 
760
- s = t.string.strip
760
+ s = t.strim
761
761
  z = EtOrbi.get_tzone(s)
762
762
 
763
763
  [ s, z ]
@@ -16,16 +16,7 @@ module Fugit
16
16
 
17
17
  #p s; Raabro.pp(Parser.parse(s, debug: 3), colours: true)
18
18
  #(p s; Raabro.pp(Parser.parse(s, debug: 1), colours: true)) rescue nil
19
- a = Parser.parse(s)
20
-
21
- return nil unless a
22
-
23
- return parse_crons(s, a, opts) \
24
- if a.include?([ :flag, 'every' ])
25
- return parse_crons(s, a, opts) \
26
- if a.include?([ :flag, 'from' ]) && a.find { |e| e[0] == :day_range }
27
-
28
- nil
19
+ parse_crons(s, Parser.parse(s), opts)
29
20
  end
30
21
 
31
22
  def do_parse(s, opts={})
@@ -38,16 +29,37 @@ module Fugit
38
29
 
39
30
  def parse_crons(s, a, opts)
40
31
 
41
- hms, aa = a
42
- .partition { |e| e[0] == :point && e[1][0] == :hour }
43
- ms = hms
44
- .inject({}) { |h, e| (h[e[1][1]] ||= []) << e[1][2]; h }
45
- .values
32
+ #p a
33
+ return nil unless a
34
+
35
+ h = a
36
+ .reverse
37
+ .inject({}) { |r, e| send("parse_#{e[0]}_elt", e, opts, r); r }
38
+ #
39
+ # the reverse ensure that in "every day at five", the
40
+ # "at five" is placed before the "every day" so that
41
+ # parse_x_elt calls have the right sequence
42
+ #p h
43
+
44
+ if f = h[:_fail]
45
+ #fail ArgumentError.new(f)
46
+ return nil
47
+ end
48
+
49
+ hms = h[:hms]
50
+
51
+ hours = (hms || [])
46
52
  .uniq
47
- crons =
48
- ms.size > 1 ?
49
- hms.collect { |e| parse_cron([ e ] + aa, opts) } :
50
- [ parse_cron(a, opts) ]
53
+ .inject({}) { |r, hm| (r[hm[1]] ||= []) << hm[0]; r }
54
+ .inject({}) { |r, (m, hs)| (r[hs.sort] ||= []) << m; r }
55
+ .to_a
56
+ .sort_by { |hs, ms| -hs.size }
57
+ if hours.empty?
58
+ hours << (h[:dom] ? [ [ '0' ], [ '0' ] ] : [ [ '*' ], [ '*' ] ])
59
+ end
60
+
61
+ crons = hours
62
+ .collect { |hm| assemble_cron(h.merge(hms: hm)) }
51
63
 
52
64
  fail ArgumentError.new(
53
65
  "multiple crons in #{s.inspect} " +
@@ -61,299 +73,451 @@ module Fugit
61
73
  end
62
74
  end
63
75
 
64
- def parse_cron(a, opts)
65
-
66
- h = { min: nil, hou: nil, dom: nil, mon: nil, dow: nil }
67
- hkeys = h.keys
68
-
69
- i0s, es = a.partition { |e| e[0] == :interval0 }
70
- a = es + i0s
71
- # interval0s are fallback
72
-
73
- a.each do |key, val|
74
- case key
75
- when :biz_day
76
- (h[:dow] ||= []) << '1-5'
77
- when :name_day
78
- (h[:dow] ||= []) << val
79
- when :day_range
80
- (h[:dow] ||= []) << val.collect { |v| v.to_s[0, 3] }.join('-')
81
- when :tz
82
- h[:tz] = val
83
- when :point
84
- process_point(h, *val)
85
- when :interval1
86
- process_interval1(h, *val[0].to_h.first)
87
- when :interval0
88
- process_interval0(h, val)
89
- end
76
+ def assemble_cron(h)
77
+
78
+ #puts "ac: " + h.inspect
79
+ s = []
80
+ s << h[:sec] if h[:sec]
81
+ s << h[:hms][1].join(',')
82
+ s << h[:hms][0].join(',')
83
+ s << (h[:dom] || '*') << (h[:mon] || '*') << (h[:dow] || '*')
84
+ s << h[:tz] if h[:tz]
85
+
86
+ Fugit::Cron.parse(s.join(' '))
87
+ end
88
+
89
+ def eone(e); e1 = e[1]; e1 == 1 ? '*' : "*/#{e1}"; end
90
+
91
+ def parse_interval_elt(e, opts, h)
92
+
93
+ e1 = e[1]
94
+
95
+ case e[2]
96
+ when 's', 'sec', 'second', 'seconds'
97
+ h[:sec] = eone(e)
98
+ when 'm', 'min', 'mins', 'minute', 'minutes'
99
+ #(h[:hms] ||= []) << [ '*', eone(e) ]
100
+ h[:hms] ||= [ [ '*', eone(e) ] ]
101
+ when 'h', 'hour', 'hours'
102
+ h[:hms] ||= [ [ eone(e), 0 ] ]
103
+ when 'd', 'day', 'days'
104
+ h[:dom] = "*/#{e1}" if e1 > 1
105
+ h[:hms] ||= [ [ 0, 0 ] ]
106
+ when 'w', 'week', 'weeks'
107
+ h[:_fail] = "cannot have crons for \"every #{e1} weeks\"" if e1 > 1
108
+ h[:hms] ||= [ [ 0, 0 ] ]
109
+ h[:dow] ||= 0
110
+ when 'M', 'month', 'months'
111
+ h[:_fail] = "cannot have crons for \"every #{e1} months\"" if e1 > 12
112
+ h[:hms] ||= [ [ 0, 0 ] ]
113
+ h[:dom] = 1
114
+ h[:mon] = eone(e)
115
+ when 'Y', 'y', 'year', 'years'
116
+ h[:_fail] = "cannot have crons for \"every #{e1} years\"" if e1 > 1
117
+ h[:hms] ||= [ [ 0, 0 ] ]
118
+ h[:dom] = 1
119
+ h[:mon] = 1
90
120
  end
121
+ end
91
122
 
92
- return nil if h[:fail]
93
-
94
- h[:min] = (h[:min] || [ 0 ]).uniq
95
- h[:hou] = (h[:hou] || []).uniq.sort
96
- h[:dow].sort! if h[:dow]
123
+ def parse_dow_list_elt(e, opts, h)
97
124
 
98
- a = hkeys
99
- .collect { |k|
100
- v = h[k]
101
- (v && v.any?) ? v.collect(&:to_s).join(',') : '*' }
102
- a.insert(0, h[:sec]) if h[:sec]
103
- a << h[:tz].first if h[:tz]
125
+ h[:hms] ||= [ [ 0, 0 ] ]
126
+ h[:dow] = e[1..-1].collect(&:to_s).sort.join(',')
127
+ end
104
128
 
105
- s = a.join(' ')
129
+ def parse_dow_range_elt(e, opts, h)
106
130
 
107
- Fugit::Cron.parse(s)
131
+ h[:hms] ||= [ [ 0, 0 ] ]
132
+ h[:dow] = e[1] == e[2] ? e[1] : "#{e[1]}-#{e[2]}"
108
133
  end
109
134
 
110
- def process_point(h, key, *value)
135
+ def parse_day_of_month_elt(e, opts, h)
111
136
 
112
- case key
113
- when :hour
114
- v0, v1 = value
115
- v0 = v0.to_i if v0.is_a?(String) && v0.match(/^\d+$/)
116
- (h[:hou] ||= []) << v0
117
- (h[:min] ||= []) << v1.to_i if v1
118
- when :sec, :min
119
- (h[key] ||= []) << value[0]
120
- end
137
+ h[:dom] = e[1..-1].join(',')
121
138
  end
122
139
 
123
- def process_interval0(h, value)
124
-
125
- case value
126
- when 'sec', 'second'
127
- h[:min] = [ '*' ]
128
- h[:sec] = [ '*' ]
129
- when 'min', 'minute'
130
- h[:min] = [ '*' ]
131
- when 'hour'
132
- unless h[:min] || h[:hou]
133
- h[:min] = [ 0 ]
134
- h[:hou] = [ '*' ]
135
- end
136
- when 'day'
137
- unless h[:min] || h[:hou]
138
- h[:min] = [ 0 ]
139
- h[:hou] = [ 0 ]
140
- end
141
- when 'week'
142
- unless h[:min] || h[:hou] || h[:dow]
143
- h[:min] = [ 0 ]
144
- h[:hou] = [ 0 ]
145
- h[:dow] = [ 0 ]
146
- end
147
- when 'month'
148
- unless h[:min] || h[:hou]
149
- h[:min] = [ 0 ]
150
- h[:hou] = [ 0 ]
151
- end
152
- (h[:dom] ||= []) << 1
153
- when 'year'
154
- unless h[:min] || h[:hou]
155
- h[:min] = [ 0 ]
156
- h[:hou] = [ 0 ]
157
- end
158
- (h[:dom] ||= []) << 1
159
- (h[:mon] ||= []) << 1
160
- end
140
+ def parse_at_elt(e, opts, h)
141
+
142
+ (h[:hms] ||= []).concat(e[1])
143
+
144
+ l = h[:hms].last
145
+ h[:sec] = l.pop if l.size > 2
161
146
  end
162
147
 
163
- def process_interval1(h, interval, value)
148
+ def parse_on_elt(e, opts, h)
164
149
 
165
- if value != 1 && [ :yea, :wee ].include?(interval)
166
- int = interval == :year ? 'years' : 'weeks'
167
- h[:fail] = "cannot cron for \"every #{value} #{int}\""
168
- return
169
- end
150
+ e1 = e[1]
151
+ h[:dow] = e1[0]
152
+ h[:hms] = [ e1[1] ]
170
153
 
171
- case interval
172
- when :yea
173
- h[:hou] = [ 0 ]
174
- h[:mon] = [ 1 ]
175
- h[:dom] = [ 1 ]
176
- when :mon
177
- h[:hou] = [ 0 ]
178
- h[:dom] = [ 1 ]
179
- h[:mon] = [ value == 1 ? '*' : "*/#{value}" ]
180
- when :wee
181
- h[:hou] = [ 0 ]
182
- h[:dow] = [ 0 ] # Sunday
183
- when :day
184
- h[:hou] = [ 0 ]
185
- h[:dom] = [ value == 1 ? '*' : "*/#{value}" ]
186
- when :hou
187
- h[:hou] = [ value == 1 ? '*' : "*/#{value}" ]
188
- when :min
189
- h[:hou] = [ '*' ]
190
- h[:min] = [ value == 1 ? '*' : "*/#{value}" ]
191
- when :sec
192
- h[:hou] = [ '*' ]
193
- h[:min] = [ '*' ]
194
- h[:sec] = [ value == 1 ? '*' : "*/#{value}" ]
195
- end
154
+ l = h[:hms].last
155
+ h[:sec] = l.pop if l.size > 2
156
+ end
157
+
158
+ def parse_tz_elt(e, opts, h)
159
+
160
+ h[:tz] = e[1]
196
161
  end
197
162
  end
198
163
 
199
164
  module Parser include Raabro
200
165
 
201
166
  NUMS = %w[
202
- zero
203
- one two three four five six seven eight nine
204
- ten eleven twelve ]
167
+ zero one two three four five six seven eight nine ten eleven twelve ]
205
168
 
206
169
  WEEKDAYS =
207
170
  Fugit::Cron::Parser::WEEKDS + Fugit::Cron::Parser::WEEKDAYS
208
171
 
209
- NHOURS =
210
- { 'noon' => [ 12, 0 ], 'midnight' => [ 0, 0 ] }
172
+ NHOURS = {
173
+ 'noon' => [ 12, 0 ],
174
+ 'midnight' => [ 0, 0 ], 'oh' => [ 0, 0 ] }
175
+ NMINUTES = {
176
+ "o'clock" => 0, 'five' => 5,
177
+ 'ten' => 10, 'fifteen' => 15,
178
+ 'twenty' => 20, 'twenty-five' => 25,
179
+ 'thirty' => 30, 'thirty-five' => 35,
180
+ 'fourty' => 40, 'fourty-five' => 45,
181
+ 'fifty' => 50, 'fifty-five' => 55 }
182
+
183
+ oh = {
184
+ '1st' => 1, '2nd' => 2, '3rd' => 3, '21st' => 21, '22nd' => 22,
185
+ '23rd' => 23, '31st' => 31 }
186
+ %w[ 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 24 25 26 27 28 29 30 ]
187
+ .each { |i| oh["#{i}th"] = i.to_i }
188
+ %w[
189
+ first second third fourth fifth sixth seventh eighth ninth tenth
190
+ eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth
191
+ eighteenth nineteenth twentieth twenty-first twenty-second twenty-third
192
+ twenty-fourth twenty-fifth twenty-fifth twenty-sixth twenty-seventh
193
+ twenty-eighth twenty-ninth thirtieth thirty-first ]
194
+ .each_with_index { |e, i| oh[e] = i + 1 }
195
+ ORDINALS = oh
211
196
 
212
197
  # piece parsers bottom to top
213
198
 
214
- def interval0(i)
215
- rex(:interval0, i,
216
- /(year|month|week|day|hour|min(ute)?|sec(ond)?)(?![a-z])/i)
199
+ def _from(i); rex(nil, i, /\s*from\s+/i); end
200
+ def _every(i); rex(nil, i, /\s*(every)\s+/i); end
201
+ def _at(i); rex(nil, i, /\s*at\s+/i); end
202
+ def _in(i); rex(nil, i, /\s*(in|on)\s+/i); end
203
+ def _to(i); rex(nil, i, /\s*to\s+/i); end
204
+ def _dash(i); rex(nil, i, /-\s*/i); end
205
+ def _and(i); rex(nil, i, /\s*and\s+/i); end
206
+ def _on(i); rex(nil, i, /\s*on\s+/i); end
207
+
208
+ def _and_or_comma(i)
209
+ rex(nil, i, /\s*(,?\s*and\s|,?\s*or\s|,)\s*/i)
210
+ end
211
+ def _at_comma(i)
212
+ rex(nil, i, /\s*(at\s|,|)\s*/i)
213
+ end
214
+ def _to_through(i)
215
+ rex(nil, i, /\s*(to|through)\s+/i)
216
+ end
217
+
218
+ def integer(i); rex(:int, i, /\d+\s*/); end
219
+
220
+ def tz_name(i)
221
+ rex(nil, i,
222
+ /\s*[A-Z][a-zA-Z0-9+\-]+(\/[A-Z][a-zA-Z0-9+\-_]+){0,2}(\s+|$)/)
223
+ end
224
+ def tz_delta(i)
225
+ rex(nil, i,
226
+ /\s*[-+]([01][0-9]|2[0-4]):?(00|15|30|45)(\s+|$)/)
227
+ end
228
+ def tzone(i)
229
+ alt(:tzone, i, :tz_delta, :tz_name)
230
+ end
231
+
232
+ def and_named_digits(i)
233
+ rex(:xxx, i, 'TODO')
234
+ end
235
+
236
+ def dname(i)
237
+ rex(:dname, i, /(s(ec(onds?)?)?|m(in(utes?)?)?)\s+/i)
238
+ end
239
+ def named_digit(i)
240
+ seq(:named_digit, i, :dname, :integer)
241
+ end
242
+ def named_digits(i)
243
+ seq(nil, i, :named_digit, '+', :and_named_digits, '*')
217
244
  end
218
245
 
219
246
  def am_pm(i)
220
- rex(:am_pm, i, / *(am|pm)/i)
247
+ rex(:am_pm, i, /\s*(am|pm|dark)\s*/i)
248
+ end
249
+
250
+ def nminute(i)
251
+ rex(:nminute, i, /(#{NMINUTES.keys.join('|')})\s*/i)
252
+ end
253
+ def nhour(i)
254
+ rex(:nhour, i, /(#{NUMS.join('|')})\s*/i)
255
+ end
256
+ def numeral_hour(i)
257
+ seq(:numeral_hour, i, :nhour, :am_pm, '?', :nminute, '?')
258
+ end
259
+
260
+ def named_hour(i)
261
+ rex(:named_hour, i, /(#{NHOURS.keys.join('|')})/i)
262
+ end
263
+
264
+ def shour(i)
265
+ rex(:shour, i, /(2[0-4]|[01]?[0-9])/)
266
+ end
267
+ def simple_hour(i)
268
+ seq(:simple_hour, i, :shour, :am_pm, '?')
221
269
  end
222
270
 
223
271
  def digital_hour(i)
224
272
  rex(:digital_hour, i, /(2[0-4]|[01][0-9]):?[0-5]\d/)
225
273
  end
226
274
 
227
- def _simple_hour(i)
228
- rex(:sh, i, /(2[0-4]|[01]?[0-9])/)
275
+ def at_point(i)
276
+ alt(nil, i,
277
+ :digital_hour, :simple_hour, :named_hour, :numeral_hour,
278
+ :named_digits)
229
279
  end
230
- def simple_hour(i)
231
- seq(:simple_hour, i, :_simple_hour, :am_pm, '?')
280
+
281
+ def weekday(i)
282
+ rex(:weekday, i, /(#{WEEKDAYS.reverse.join('|')})\s*/i)
232
283
  end
233
284
 
234
- def _numeral_hour(i)
235
- rex(:nh, i, /(#{NUMS.join('|')})/i)
285
+ def and_at(i)
286
+ seq(nil, i, :_and_or_comma, :at_point)
236
287
  end
237
- def numeral_hour(i)
238
- seq(:numeral_hour, i, :_numeral_hour, :am_pm, '?')
288
+
289
+ def _intervals(i)
290
+ rex(:intervals, i,
291
+ /(
292
+ y(ears?)?|months?|w(eeks?)?|d(ays?)?|
293
+ h(ours?)?|m(in(ute)?s?)?|s(ec(ond)?s?)?
294
+ )(\s+|$)/ix)
295
+ end
296
+
297
+ def sinterval(i)
298
+ rex(:sinterval, i,
299
+ /(year|month|week|day|hour|min(ute)?|sec(ond)?)(\s+|$)/i)
300
+ end
301
+ def ninterval(i)
302
+ seq(:ninterval, i, :integer, :_intervals)
239
303
  end
240
304
 
241
- def name_hour(i)
242
- rex(:name_hour, i, /(#{NHOURS.keys.join('|')})/i)
305
+ def ordinal(i)
306
+ rex(:ordinal, i, /\s*(#{ORDINALS.keys.join('|')})\s*/)
243
307
  end
244
308
 
245
- def biz_day(i); rex(:biz_day, i, /(biz|business|week) *day/i); end
246
- def name_day(i); rex(:name_day, i, /#{WEEKDAYS.reverse.join('|')}/i); end
309
+ def _mod(i); rex(nil, i, /\s*month\s+on\s+days?\s+/i); end
310
+ def _oftm(i); rex(nil, i, /\s*(day\s)?\s*of\s+the\s+month\s*/i); end
247
311
 
248
- def range_sep(i); rex(nil, i, / *- *| +(to|through) +/); end
312
+ def dom(i)
313
+ rex(:int, i, /([12][0-9]|3[01]|[0-9])/)
314
+ end
315
+ def and_or_dom(i)
316
+ seq(nil, i, :_and_or_comma, :dom)
317
+ end
318
+ def dom_list(i)
319
+ seq(:dom_list, i, :dom, :and_or_dom, '*')
320
+ end
321
+
322
+ def dom_mod(i) # every month on day
323
+ seq(:dom, i, :_mod, :dom_list)
324
+ end
325
+ def dom_noftm(i) # every nth of month
326
+ seq(:dom, i, :ordinal, :_oftm)
327
+ end
328
+ def day_of_month(i)
329
+ alt(nil, i, :dom_noftm, :dom_mod)
330
+ end
249
331
 
250
- def day_range(i)
251
- seq(:day_range, i, :name_day, :range_sep, :name_day)
332
+ def dow_class(i)
333
+ rex(:dow_class, i, /(weekday)(\s+|$)/i)
252
334
  end
253
335
 
254
- def _tz_name(i)
255
- rex(nil, i, /[A-Z][a-zA-Z0-9+\-]+(\/[A-Z][a-zA-Z0-9+\-_]+){0,2}/)
336
+ def dow(i)
337
+ seq(:dow, i, :weekday)
256
338
  end
257
- def _tz_delta(i)
258
- rex(nil, i, /[-+]([01][0-9]|2[0-4]):?(00|15|30|45)/)
339
+ def and_or_dow(i)
340
+ seq(nil, i, :_and_or_comma, :dow)
341
+ end
342
+ def dow_list(i)
343
+ seq(:dow_list, i, :dow, :and_or_dow, '*')
259
344
  end
260
- def _tz(i); alt(:tz, i, :_tz_delta, :_tz_name); end
261
345
 
262
- def interval1(i)
263
- rex(:interval1, i,
264
- /
265
- \d+
266
- \s?
267
- (y(ears?)?|months?|w(eeks?)?|d(ays?)?|
268
- h(ours?)?|m(in(ute)?s?)?|s(ec(ond)?s?)?)
269
- /ix)
346
+ def to_dow_range(i)
347
+ seq(:dow_range, i, :weekday, :_to_through, :weekday)
348
+ end
349
+ def dash_dow_range(i)
350
+ seq(:dow_range, i, :weekday, :_dash, :weekday)
351
+ end
352
+ def dow_range(i)
353
+ alt(nil, i, :to_dow_range, :dash_dow_range)
270
354
  end
271
355
 
272
- def min_or_sec(i)
273
- rex(:min_or_sec, i, /(min(ute)?|sec(ond)?)\s+\d+/i)
356
+ def day_of_week(i)
357
+ alt(nil, i, :dow_range, :dow_list, :dow_class)
274
358
  end
275
359
 
276
- def point(i)
277
- alt(:point, i,
278
- :min_or_sec,
279
- :name_hour, :numeral_hour, :digital_hour, :simple_hour)
360
+ def interval(i)
361
+ alt(nil, i, :sinterval, :ninterval)
280
362
  end
281
363
 
282
- def flag(i); rex(:flag, i, /(every|from|at|after|on|in)/i); end
364
+ def every_object(i)
365
+ alt(nil, i, :day_of_month, :interval, :day_of_week)
366
+ end
367
+ def from_object(i)
368
+ alt(nil, i, :interval, :to_dow_range)
369
+ end
283
370
 
284
- def datum(i)
285
- alt(nil, i,
286
- :flag,
287
- :interval1,
288
- :point,
289
- :interval0,
290
- :day_range, :biz_day, :name_day,
291
- :_tz)
371
+ def tz(i)
372
+ seq(nil, i, :_in, '?', :tzone)
373
+ end
374
+ def on(i)
375
+ seq(:on, i, :_on, :weekday, :at_point, :and_at, '*')
376
+ end
377
+ def at(i)
378
+ seq(:at, i, :_at_comma, :at_point, :and_at, '*')
379
+ end
380
+ def from(i)
381
+ seq(:from, i, :_from, :from_object)
382
+ end
383
+ def every(i)
384
+ seq(:every, i, :_every, :every_object)
292
385
  end
293
386
 
294
- def sugar(i); rex(nil, i, /(and|or|[, \t]+)/i); end
387
+ def at_from(i)
388
+ seq(nil, i, :at, :from, :tz, '?')
389
+ end
390
+ def at_every(i)
391
+ seq(nil, i, :at, :every, :tz, '?')
392
+ end
393
+
394
+ def from_at(i)
395
+ seq(nil, i, :from, :at, '?', :tz, '?')
396
+ end
397
+
398
+ def every_(i)
399
+ seq(nil, i, :every, :tz, '?')
400
+ end
401
+ def every_on(i)
402
+ seq(nil, i, :every, :on, :tz, '?')
403
+ end
404
+ def every_at(i)
405
+ seq(nil, i, :every, :at, :tz, '?')
406
+ end
295
407
 
296
- def elt(i); alt(nil, i, :sugar, :datum); end
297
- def nat(i); rep(:nat, i, :elt, 1); end
408
+ def nat(i)
409
+ alt(:nat, i,
410
+ :every_at, :every_on, :every_,
411
+ :from_at,
412
+ :at_every, :at_from)
413
+ end
298
414
 
299
415
  # rewrite parsed tree
300
416
 
301
- def _rewrite(t)
302
- [ t.name, t.string.downcase ]
417
+ #def _rewrite_single(t)
418
+ # [ t.name, rewrite(t.sublookup(nil)) ]
419
+ #end
420
+ def _rewrite_children(t)
421
+ t.subgather(nil).collect { |tt| rewrite(tt) }
422
+ end
423
+ def _rewrite_multiple(t)
424
+ [ t.name, _rewrite_children(t) ]
425
+ end
426
+ def _rewrite_child(t)
427
+ rewrite(t.sublookup(nil))
428
+ end
429
+
430
+ def rewrite_int(t); t.string.to_i; end
431
+
432
+ def rewrite_tzone(t)
433
+
434
+ [ :tz, t.strim ]
303
435
  end
304
- alias rewrite_flag _rewrite
305
- alias rewrite_interval0 _rewrite
306
- alias rewrite_biz_day _rewrite
307
436
 
308
- def rewrite_name_day(t)
309
- [ :name_day, WEEKDAYS.index(t.string.downcase[0, 3]) ]
437
+ def rewrite_sinterval(t)
438
+
439
+ [ :interval, 1, t.strim ]
310
440
  end
311
441
 
312
- def rewrite_day_range(t)
313
- [ :day_range, t.subgather(nil).collect { |st| st.string.downcase } ]
442
+ def rewrite_ninterval(t)
443
+
444
+ [ :interval,
445
+ t.sublookup(:int).string.to_i,
446
+ t.sublookup(:intervals).strim ]
314
447
  end
315
448
 
316
- def rewrite_name_hour(t)
317
- [ :hour, *NHOURS[t.string.strip.downcase] ]
449
+ def rewrite_named_digit(t)
450
+
451
+ i = t.sublookup(:int).string.to_i
452
+
453
+ case n = t.sublookup(:dname).strim
454
+ when /^s/ then [ '*', '*', i ]
455
+ when /^m/ then [ '*', i ]
456
+ end
457
+ end
458
+
459
+ def rewrite_named_hour(t)
460
+ NHOURS[t.strim.downcase]
318
461
  end
319
462
  def rewrite_numeral_hour(t)
320
- vs = t.subgather(nil).collect { |st| st.string.downcase.strip }
463
+ vs = t.subgather(nil).collect { |st| st.strim.downcase }
321
464
  v = NUMS.index(vs[0])
322
465
  v += 12 if vs[1] == 'pm'
323
- [ :hour, v, 0 ]
466
+ m = NMINUTES[vs[2]] || 0
467
+ [ v, m ]
324
468
  end
325
469
  def rewrite_simple_hour(t)
326
- vs = t.subgather(nil).collect { |st| st.string.downcase.strip }
470
+ vs = t.subgather(nil).collect { |st| st.strim.downcase }
327
471
  v = vs[0].to_i
328
472
  v += 12 if vs[1] == 'pm'
329
- [ :hour, v, 0 ]
473
+ [ v, 0 ]
330
474
  end
331
475
  def rewrite_digital_hour(t)
332
- v = t.string.gsub(/:/, '')
333
- [ :hour, v[0, 2], v[2, 2] ]
476
+ m = t.string.match(/(\d\d?):?(\d\d)/)
477
+ [ m[1].to_i, m[2].to_i ]
334
478
  end
335
479
 
336
- def rewrite_min_or_sec(t)
337
- unit, num = t.string.split(/\s+/)
338
- [ unit[0, 3].to_sym, num.to_i ]
480
+ def rewrite_weekday(t)
481
+
482
+ WEEKDAYS.index(t.strim.downcase[0, 3])
339
483
  end
340
484
 
341
- def rewrite_point(t)
342
- [ :point, rewrite(t.sublookup) ]
485
+ def rewrite_ordinal(t); ORDINALS[t.strim]; end
486
+
487
+ def rewrite_dom(t)
488
+
489
+ #Raabro.pp(t, colours: true)
490
+ [ :day_of_month,
491
+ *_rewrite_children(t).flatten.select { |e| e.is_a?(Integer) } ]
343
492
  end
344
493
 
345
- def rewrite_tz(t)
346
- [ :tz, [ t.string.strip, EtOrbi.get_tzone(t.string.strip) ] ]
494
+ alias rewrite_dow _rewrite_child
495
+
496
+ def rewrite_dom_list(t); [ :dom_list, *_rewrite_children(t) ]; end
497
+ def rewrite_dow_list(t); [ :dow_list, *_rewrite_children(t) ]; end
498
+
499
+ def rewrite_dow_class(t)
500
+
501
+ [ :dow_range, 1, 5 ] # only "weekday" for now
347
502
  end
348
503
 
349
- def rewrite_interval1(t)
350
- [ t.name, [ Fugit::Duration.parse(t.string.strip) ] ]
504
+ def rewrite_dow_range(t)
505
+
506
+ tts = t.subgather(nil)
507
+
508
+ [ :dow_range, rewrite(tts[0]), rewrite(tts[1]) ]
351
509
  end
352
510
 
511
+ alias rewrite_on _rewrite_multiple
512
+ alias rewrite_at _rewrite_multiple
513
+
514
+ alias rewrite_from _rewrite_child
515
+ alias rewrite_every _rewrite_child
516
+
353
517
  def rewrite_nat(t)
354
518
 
355
- #Raabro.pp(t, colours: true)
356
519
  t.subgather(nil).collect { |tt| rewrite(tt) }
520
+ #.tap { |x| pp x }
357
521
  end
358
522
  end
359
523
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fugit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.5
4
+ version: 1.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-07 00:00:00.000000000 Z
11
+ date: 2020-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: raabro
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.1'
19
+ version: '1.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.1'
26
+ version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: et-orbi
29
29
  requirement: !ruby/object:Gem::Requirement