fugit 1.1.9 → 1.1.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 35836e95c82a113fe2e5222a02522ab2bf36f1b0
4
- data.tar.gz: 0fb6db1cb77893af937354da715b2eb8b14403f5
3
+ metadata.gz: a7fb0dc867cacf79033c0f54f5780cdc5a567106
4
+ data.tar.gz: e06aec6abab852f7ea09c459353bbcbb42c007ee
5
5
  SHA512:
6
- metadata.gz: 7de61477e96c9612542641787346fb154394d8388eccccaeb1be257cb57410abe4e23d1377148539d92852674df3c58d0a44c9cc4816c50cd157515f185d59da
7
- data.tar.gz: c1f23c4a8395ddc29a85415300608fbc45d5900cbb42c502fd51f02f7f8c5f6fe945fe9b010349e9bde6fc1df6f3ec105a977c8705722820be41c65b47656ff7
6
+ metadata.gz: 55c7bdcaa5820e11f83b5d61e66bf44a6de98cd778e1ca80daefacf2e71fd0707696ec1161896738b4934125ba63881fc7023e89fbe27a1be24495dabc6a0ae5
7
+ data.tar.gz: 8b3471be0e7710016eabcb5ba26ca01463e0463fd370c290d91bea9c41883896cffb03dbc65aad62d8f51a9a8aa821ab02b6020dfda67725908357902ebd3b97
@@ -2,6 +2,12 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
+ ## fugit 1.1.10 released 2019-04-12
6
+
7
+ * Implement `"0 9 * * sun%2+1"`
8
+ * Simplify cron parser
9
+
10
+
5
11
  ## fugit 1.1.9 released 2019-03-26
6
12
 
7
13
  * Fix cron `"0 9 29 feb *"` endless loop, gh-18
data/Makefile CHANGED
@@ -11,6 +11,9 @@ count_lines:
11
11
  find spec -name "*_spec.rb" | xargs cat | ruby -e "p STDIN.readlines.count { |l| l = l.strip; l[0, 1] != '#' && l != '' }"
12
12
  cl: count_lines
13
13
 
14
+ scan:
15
+ scan lib/**/*.rb
16
+
14
17
  gemspec_validate:
15
18
  @echo "---"
16
19
  ruby -e "s = eval(File.read(Dir['*.gemspec'].first)); p s.validate"
@@ -48,5 +51,5 @@ tzones:
48
51
  # bundle exec ruby -r tzinfo -r tzinfo-data -e "::TZInfo::Timezone.all.each { |tz| p tz.name }"
49
52
 
50
53
 
51
- .PHONY: count_lines gemspec_validate name cw build push spec info tzones
54
+ .PHONY: count_lines scan gemspec_validate name cw build push spec info tzones
52
55
 
data/README.md CHANGED
@@ -104,6 +104,31 @@ Example of cron strings understood by fugit:
104
104
  # and more...
105
105
  ```
106
106
 
107
+ ### the modulo extension
108
+
109
+ Fugit, since 1.1.10, also understands cron strings like "`9 0 * * sun%2`" which can be read as "every other Sunday at 9am".
110
+
111
+ For odd Sundays, one can write `9 0 * * sun%2+1`.
112
+
113
+ It can be combined, as in `9 0 * * sun%2,tue%3+2`
114
+
115
+ But what does it references to? It starts at 1 on 2019-01-01.
116
+
117
+ ```ruby
118
+ require 'et-orbi' # >= 1.1.8
119
+
120
+ # the reference
121
+ p EtOrbi.parse('2019-01-01').wday # => 2
122
+ p EtOrbi.parse('2019-01-01').rweek # => 1
123
+ p EtOrbi.parse('2019-01-01').rweek % 2 # => 1
124
+
125
+ # today (as of this coding...)
126
+ p EtOrbi.parse('2019-04-11').wday # => 4
127
+ p EtOrbi.parse('2019-04-11').rweek # => 15
128
+ p EtOrbi.parse('2019-04-11').rweek % 2 # => 1
129
+ ```
130
+
131
+
107
132
  ## `Fugit::Duration`
108
133
 
109
134
  A class `Fugit::Duration` to parse duration strings (vanilla [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) ones and [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) ones).
@@ -41,7 +41,7 @@ Time tools for flor and the floraison project. Cron parsing and occurrence compu
41
41
  # this dependency appears in 'et-orbi'
42
42
 
43
43
  s.add_runtime_dependency 'raabro', '~> 1.1'
44
- s.add_runtime_dependency 'et-orbi', '~> 1.1', '>= 1.1.7'
44
+ s.add_runtime_dependency 'et-orbi', '~> 1.1', '>= 1.1.8'
45
45
 
46
46
  s.add_development_dependency 'rspec', '~> 3.7'
47
47
  s.add_development_dependency 'chronic', '~> 0.10'
@@ -1,7 +1,7 @@
1
1
 
2
2
  module Fugit
3
3
 
4
- VERSION = '1.1.9'
4
+ VERSION = '1.1.10'
5
5
  end
6
6
 
7
7
  require 'time'
@@ -11,8 +11,7 @@ module Fugit
11
11
  '@weekly' => '0 0 * * 0',
12
12
  '@daily' => '0 0 * * *',
13
13
  '@midnight' => '0 0 * * *',
14
- '@hourly' => '0 * * * *',
15
- }
14
+ '@hourly' => '0 * * * *' }
16
15
 
17
16
  attr_reader :original, :zone
18
17
  attr_reader :seconds, :minutes, :hours, :monthdays, :months, :weekdays, :timezone
@@ -49,17 +48,15 @@ module Fugit
49
48
 
50
49
  def to_cron_s
51
50
 
52
- @cron_s ||= begin
53
- [
54
- @seconds == [ 0 ] ? nil : (@seconds || [ '*' ]).join(','),
55
- (@minutes || [ '*' ]).join(','),
56
- (@hours || [ '*' ]).join(','),
57
- (@monthdays || [ '*' ]).join(','),
58
- (@months || [ '*' ]).join(','),
59
- (@weekdays || [ [ '*' ] ]).map { |d| d.compact.join('#') }.join(','),
60
- @timezone ? @timezone.name : nil
61
- ].compact.join(' ')
62
- end
51
+ @cron_s ||= [
52
+ @seconds == [ 0 ] ? nil : (@seconds || [ '*' ]).join(','),
53
+ (@minutes || [ '*' ]).join(','),
54
+ (@hours || [ '*' ]).join(','),
55
+ (@monthdays || [ '*' ]).join(','),
56
+ (@months || [ '*' ]).join(','),
57
+ (@weekdays || [ [ '*' ] ]).map { |d| d.compact.join('#') }.join(','),
58
+ @timezone ? @timezone.name : nil
59
+ ].compact.join(' ')
63
60
  end
64
61
 
65
62
  class TimeCursor
@@ -73,7 +70,7 @@ module Fugit
73
70
  def time; @t; end
74
71
  def to_i; @t.to_i; end
75
72
 
76
- %w[ year month day wday hour min sec wday_in_month ]
73
+ %w[ year month day wday hour min sec wday_in_month rweek rday ]
77
74
  .collect(&:to_sym).each { |k| define_method(k) { @t.send(k) } }
78
75
 
79
76
  def inc(i)
@@ -140,21 +137,35 @@ module Fugit
140
137
  def min_match?(nt); ( ! @minutes) || @minutes.include?(nt.min); end
141
138
  def sec_match?(nt); ( ! @seconds) || @seconds.include?(nt.sec); end
142
139
 
140
+ def weekday_hash_match?(nt, hsh)
141
+
142
+ phsh, nhsh = nt.wday_in_month
143
+
144
+ if hsh > 0
145
+ hsh == phsh # positive wday, from the beginning of the month
146
+ else
147
+ hsh == nhsh # negative wday, from the end of the month, -1 == last
148
+ end
149
+ end
150
+
151
+ def weekday_modulo_match?(nt, mod)
152
+
153
+ nt.rweek % mod[0] == mod[1]
154
+ end
155
+
143
156
  def weekday_match?(nt)
144
157
 
145
158
  return true if @weekdays.nil?
146
159
 
147
- wd, hsh = @weekdays.find { |d, _| d == nt.wday }
160
+ wd, hom = @weekdays.find { |d, _| d == nt.wday }
148
161
 
149
162
  return false unless wd
150
- return true if hsh.nil?
163
+ return true if hom.nil?
151
164
 
152
- phsh, nhsh = nt.wday_in_month
153
-
154
- if hsh > 0
155
- hsh == phsh # positive wday, from the beginning of the month
165
+ if hom.is_a?(Array)
166
+ weekday_modulo_match?(nt, hom)
156
167
  else
157
- hsh == nhsh # negative wday, from the end of the month, -1 == last
168
+ weekday_hash_match?(nt, hom)
158
169
  end
159
170
  end
160
171
 
@@ -487,11 +498,11 @@ module Fugit
487
498
 
488
499
  @weekdays = []
489
500
 
490
- arr.each do |a, z, s, h| # a to z, slash and hash
491
- if h
492
- @weekdays << [ a, h ]
493
- elsif s
494
- ((a || 0)..(z || (a ? a : 6))).step(s < 1 ? 1 : s)
501
+ arr.each do |a, z, sl, ha, mo| # a to z, slash, hash, and mod
502
+ if ha || mo
503
+ @weekdays << [ a, ha || mo ]
504
+ elsif sl
505
+ ((a || 0)..(z || (a ? a : 6))).step(sl < 1 ? 1 : sl)
495
506
  .each { |i| @weekdays << [ i ] }
496
507
  elsif z
497
508
  (a..z).each { |i| @weekdays << [ i ] }
@@ -527,20 +538,14 @@ module Fugit
527
538
 
528
539
  def slash(i); rex(:slash, i, /\/\d\d?/); end
529
540
 
530
- def core_mos(i); rex(:mos, i, /[0-5]?\d/); end # min or sec
531
- def core_hou(i); rex(:hou, i, /(2[0-4]|[01]?[0-9])/); end
532
- def core_dom(i); rex(:dom, i, /(-?(3[01]|[12][0-9]|0?[1-9])|last|l)/i); end
533
- def core_mon(i); rex(:mon, i, /(1[0-2]|0?[1-9]|#{MONTHS[1..-1].join('|')})/i); end
534
- def core_dow(i); rex(:dow, i, /([0-7]|#{WEEKDS.join('|')})/i); end
541
+ def mos(i); rex(:mos, i, /[0-5]?\d/); end # min or sec
542
+ def hou(i); rex(:hou, i, /(2[0-4]|[01]?[0-9])/); end
543
+ def dom(i); rex(:dom, i, /(-?(3[01]|[12][0-9]|0?[1-9])|last|l)/i); end
544
+ def mon(i); rex(:mon, i, /(1[0-2]|0?[1-9]|#{MONTHS[1..-1].join('|')})/i); end
545
+ def dow(i); rex(:dow, i, /([0-7]|#{WEEKDS.join('|')})/i); end
535
546
 
536
547
  def dow_hash(i); rex(:hash, i, /#(-?[1-5]|last|l)/i); end
537
548
 
538
- def mos(i); core_mos(i); end
539
- def hou(i); core_hou(i); end
540
- def dom(i); core_dom(i); end
541
- def mon(i); core_mon(i); end
542
- def dow(i); core_dow(i); end
543
-
544
549
  def _mos(i); seq(nil, i, :hyphen, :mos); end
545
550
  def _hou(i); seq(nil, i, :hyphen, :hou); end
546
551
  def _dom(i); seq(nil, i, :hyphen, :dom); end
@@ -568,9 +573,12 @@ module Fugit
568
573
  def sorws_mon(i); seq(:elt, i, :sor_mon, :slash, '?'); end
569
574
  def sorws_dow(i); seq(:elt, i, :sor_dow, :slash, '?'); end
570
575
 
571
- def h_dow(i); seq(:elt, i, :core_dow, :dow_hash); end
576
+ def mod(i); rex(:mod, i, /%\d+(\+\d+)?/); end
577
+
578
+ def mod_dow(i); seq(:elt, i, :dow, :mod); end
579
+ def h_dow(i); seq(:elt, i, :dow, :dow_hash); end
572
580
 
573
- def _sorws_dow(i); alt(nil, i, :h_dow, :sorws_dow); end
581
+ def _sorws_dow(i); alt(nil, i, :h_dow, :mod_dow, :sorws_dow); end
574
582
 
575
583
  def list_sec(i); jseq(:sec, i, :sorws_mos, :comma); end
576
584
  def list_min(i); jseq(:min, i, :sorws_mos, :comma); end
@@ -607,7 +615,7 @@ module Fugit
607
615
 
608
616
  # rewriting the parsed tree
609
617
 
610
- def to_i(k, t)
618
+ def rewrite_bound(k, t)
611
619
 
612
620
  s = t.string.downcase
613
621
 
@@ -617,23 +625,38 @@ module Fugit
617
625
  s.to_i
618
626
  end
619
627
 
628
+ def rewrite_mod(k, t)
629
+
630
+ mod, plus = t.string
631
+ .split(/[%+]/).reject(&:empty?).collect(&:to_i)
632
+
633
+ [ mod, plus || 0 ]
634
+ end
635
+
620
636
  def rewrite_elt(k, t)
621
637
 
622
- (a, z), others = t
623
- .subgather(nil)
624
- .partition { |tt| ![ :hash, :slash ].include?(tt.name) }
625
- s = others.find { |tt| tt.name == :slash }
626
- h = others.find { |tt| tt.name == :hash }
638
+ at, zt, slt, hat, mot = nil; t.subgather(nil).each do |tt|
639
+ case tt.name
640
+ when :slash then slt = tt
641
+ when :hash then hat = tt
642
+ when :mod then mot = tt
643
+ else if at; zt ||= tt; else; at = tt; end
644
+ end
645
+ end
646
+
647
+ sl = slt ? slt.string[1..-1].to_i : nil
648
+
649
+ ha = hat ? hat.string[1..-1] : nil
650
+ ha = -1 if ha && ha.upcase[0, 1] == 'L'
651
+ ha = ha.to_i if ha
627
652
 
628
- h = h ? h.string[1..-1] : nil
629
- h = -1 if h && h.upcase[0, 1] == 'L'
630
- h = h.to_i if h
653
+ mo = mot ? rewrite_mod(k, mot) : nil
631
654
 
632
- a = a ? to_i(k, a) : nil
633
- z = z ? to_i(k, z) : nil
655
+ a = at ? rewrite_bound(k, at) : nil
656
+ z = zt ? rewrite_bound(k, zt) : nil
634
657
  a, z = z, a if a && z && a > z
635
658
 
636
- [ a, z, s ? s.string[1..-1].to_i : nil, h ]
659
+ [ a, z, sl, ha, mo ]
637
660
  end
638
661
 
639
662
  def rewrite_entry(t)
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.1.9
4
+ version: 1.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-25 00:00:00.000000000 Z
11
+ date: 2019-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: raabro
@@ -33,7 +33,7 @@ dependencies:
33
33
  version: '1.1'
34
34
  - - ">="
35
35
  - !ruby/object:Gem::Version
36
- version: 1.1.7
36
+ version: 1.1.8
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '1.1'
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 1.1.7
46
+ version: 1.1.8
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
49
  requirement: !ruby/object:Gem::Requirement