rufus-scheduler 3.1.7 → 3.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +6 -0
- data/CREDITS.txt +1 -0
- data/lib/rufus/scheduler.rb +1 -1
- data/lib/rufus/scheduler/zotime.rb +13 -7
- data/spec/cronline_spec.rb +176 -22
- data/spec/spec_helper.rb +2 -0
- data/spec/zotime_spec.rb +8 -13
- data/t.txt +31 -0
- metadata +22 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe6be00fcf61f4df224dfe810d39b370cd34dc70
|
4
|
+
data.tar.gz: 92527aec3d327a51f57f53bda26e369e247a33bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48531b28fdb9af27e37fd8f94188f0144d8542294e039df27c8c0476bfadb8a82f3623cf915e6ff1fe0e114675cd640697a4ad43e50cc9e423e70afe3626f6a9
|
7
|
+
data.tar.gz: 2bdaacf21eec775ce0a76208e8b1a1dc009c77717144d4897d79af8875915585dcf0d565363524dc27932388e12ac1de5c000f9e6775b511fe044d5d14f2b022
|
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
+
== rufus-scheduler - 3.1.8 released 2015-11-10
|
6
|
+
|
7
|
+
- stop jumping eagerly out of DST, fix for one hour jump when leaving DST
|
8
|
+
thanks Alyssa http://github.com/alyssa
|
9
|
+
|
10
|
+
|
5
11
|
== rufus-scheduler - 3.1.7 released 2015-10-15
|
6
12
|
|
7
13
|
- ack #unscheduled_at in #scheduled?, by Claude https://github.com/claudeatsafe
|
data/CREDITS.txt
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
== Contributors
|
6
6
|
|
7
|
+
- Alyssa Pohahau (https://github.com/alyssa) out of DST transition specs
|
7
8
|
- Claude Vessaz (https://github.com/claudeatsafe) ack #unscheduled_at in #scheduled?
|
8
9
|
- 김성식 (https://github.com/kssminus) job id uniqueness effort
|
9
10
|
- Jesse Willet (https://github.com/jhw-at-prosperworks-com) cron vs "*/10"
|
data/lib/rufus/scheduler.rb
CHANGED
@@ -47,13 +47,19 @@ class Rufus::Scheduler
|
|
47
47
|
|
48
48
|
t = Time.at(@seconds)
|
49
49
|
|
50
|
-
if t.isdst
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
else
|
55
|
-
|
56
|
-
end
|
50
|
+
#if t.isdst
|
51
|
+
# t1 = Time.at(@seconds + 3600)
|
52
|
+
# t = t1 if t.zone != t1.zone && t.hour == t1.hour && t.min == t1.min
|
53
|
+
# # ambiguous TZ (getting out of DST)
|
54
|
+
#else
|
55
|
+
# t.hour # force t to compute itself
|
56
|
+
#end
|
57
|
+
#
|
58
|
+
# jump out of DST as soon as possible, jumps 1h as seen from UTC
|
59
|
+
|
60
|
+
t.hour # force t to compute itself
|
61
|
+
#
|
62
|
+
# stay in DST as long as possible, no jump seen from UTC
|
57
63
|
|
58
64
|
t
|
59
65
|
end
|
data/spec/cronline_spec.rb
CHANGED
@@ -7,6 +7,17 @@
|
|
7
7
|
|
8
8
|
require 'spec_helper'
|
9
9
|
|
10
|
+
class Time
|
11
|
+
|
12
|
+
def to_compact_s
|
13
|
+
|
14
|
+
off = self.utc_offset / 3600
|
15
|
+
off = off >= 0 ? "+#{off}" : off.to_s
|
16
|
+
|
17
|
+
self.strftime('%H%M') + off + self.dup.utc.strftime('(%H%M)')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
10
21
|
|
11
22
|
describe Rufus::Scheduler::CronLine do
|
12
23
|
|
@@ -392,7 +403,10 @@ describe Rufus::Scheduler::CronLine do
|
|
392
403
|
'30 1 31 10 * America/New_York',
|
393
404
|
ltz('America/New_York', 2004, 10, 1)
|
394
405
|
)
|
395
|
-
).to eq(
|
406
|
+
).to eq(
|
407
|
+
ltz('America/New_York', 0, 30, 1, 31, 10, 2004, nil, nil, true, nil)
|
408
|
+
# EDT summer time UTC-4
|
409
|
+
)
|
396
410
|
end
|
397
411
|
end
|
398
412
|
|
@@ -495,7 +509,10 @@ describe Rufus::Scheduler::CronLine do
|
|
495
509
|
'30 1 31 10 * America/New_York',
|
496
510
|
ltz('America/New_York', 2004, 10, 31, 14, 30, 0)
|
497
511
|
)
|
498
|
-
).to eq(
|
512
|
+
).to eq(
|
513
|
+
ltz('America/New_York', 0, 30, 1, 31, 10, 2004, nil, nil, false, nil)
|
514
|
+
# EST time UTC-5
|
515
|
+
)
|
499
516
|
end
|
500
517
|
end
|
501
518
|
|
@@ -863,19 +880,17 @@ describe Rufus::Scheduler::CronLine do
|
|
863
880
|
t = Time.local(2015, 3, 8, 1, 57)
|
864
881
|
|
865
882
|
points =
|
866
|
-
|
883
|
+
4.times.collect do
|
867
884
|
t = line.next_time(t)
|
868
|
-
t.
|
885
|
+
t.to_compact_s
|
869
886
|
end
|
870
887
|
|
871
|
-
expect(points).to eq(
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
]
|
878
|
-
)
|
888
|
+
expect(points).to eq([
|
889
|
+
'0158-8(0958)',
|
890
|
+
'0159-8(0959)',
|
891
|
+
'0300-7(1000)',
|
892
|
+
'0301-7(1001)'
|
893
|
+
])
|
879
894
|
end
|
880
895
|
end
|
881
896
|
|
@@ -895,19 +910,158 @@ describe Rufus::Scheduler::CronLine do
|
|
895
910
|
t = Time.local(2015, 3, 8, 3, 2)
|
896
911
|
|
897
912
|
points =
|
898
|
-
|
913
|
+
4.times.collect do
|
899
914
|
t = line.previous_time(t)
|
900
|
-
t.
|
915
|
+
t.to_compact_s
|
901
916
|
end
|
902
917
|
|
903
|
-
expect(points).to eq(
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
918
|
+
expect(points).to eq([
|
919
|
+
'0301-7(1001)',
|
920
|
+
'0300-7(1000)',
|
921
|
+
'0159-8(0959)',
|
922
|
+
'0158-8(0958)'
|
923
|
+
])
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
it 'correctly increments when entering DST' do
|
928
|
+
|
929
|
+
in_zone 'America/Los_Angeles' do
|
930
|
+
|
931
|
+
line = cl('*/10 * * * * America/Los_Angeles')
|
932
|
+
|
933
|
+
t = Time.local(2015, 3, 8, 1, 40)
|
934
|
+
t1 = t.dup
|
935
|
+
|
936
|
+
points = []
|
937
|
+
while t1 - t < 1 * 3600
|
938
|
+
t1 = line.next_time(t1)
|
939
|
+
points << t1.to_compact_s
|
940
|
+
end
|
941
|
+
|
942
|
+
expect(points).to eq(%w[
|
943
|
+
0150-8(0950)
|
944
|
+
0300-7(1000)
|
945
|
+
0310-7(1010)
|
946
|
+
0320-7(1020)
|
947
|
+
0330-7(1030)
|
948
|
+
0340-7(1040)
|
949
|
+
])
|
950
|
+
end
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
context 'fall time' do
|
955
|
+
|
956
|
+
it 'correctly increments through a DST transition' do
|
957
|
+
|
958
|
+
expect(
|
959
|
+
nt('* * * * * America/Los_Angeles', Time.utc(2015, 11, 1, 9, 59))
|
960
|
+
).to eq(Time.utc(2015, 11, 1, 10, 00))
|
961
|
+
end
|
962
|
+
|
963
|
+
it 'correctly increments every minute through a DST transition' do
|
964
|
+
|
965
|
+
in_zone 'America/Los_Angeles' do
|
966
|
+
|
967
|
+
line = cl('* * * * * America/Los_Angeles')
|
968
|
+
|
969
|
+
#t = Time.local(2015, 11, 1, 1, 57)
|
970
|
+
#
|
971
|
+
# --> 2015-11-01 01:57:00 -0800 (already PST)
|
972
|
+
|
973
|
+
t = Time.local(0, 57, 1, 1, 11, 2015, nil, nil, true, nil)
|
974
|
+
#
|
975
|
+
# --> 2015-11-01 01:57:00 -0700 (still PDT)
|
976
|
+
|
977
|
+
points =
|
978
|
+
4.times.collect do
|
979
|
+
t = line.next_time(t)
|
980
|
+
t.to_compact_s
|
981
|
+
end
|
982
|
+
|
983
|
+
expect(points).to eq([
|
984
|
+
'0158-7(0858)',
|
985
|
+
'0159-7(0859)',
|
986
|
+
'0100-8(0900)',
|
987
|
+
'0101-8(0901)'
|
988
|
+
])
|
989
|
+
end
|
990
|
+
end
|
991
|
+
|
992
|
+
it 'correctly decrements through a DST transition' do
|
993
|
+
|
994
|
+
expect(
|
995
|
+
pt('* * * * * America/Los_Angeles', Time.utc(2015, 11, 1, 10, 00))
|
996
|
+
).to eq(Time.utc(2015, 11, 1, 9, 59))
|
997
|
+
end
|
998
|
+
|
999
|
+
it 'correctly decrements every minute through a DST transition' do
|
1000
|
+
|
1001
|
+
in_zone 'America/Los_Angeles' do
|
1002
|
+
|
1003
|
+
line = cl('* * * * * America/Los_Angeles')
|
1004
|
+
|
1005
|
+
t = Time.local(0, 2, 1, 1, 11, 2015, nil, nil, true, nil)
|
1006
|
+
#
|
1007
|
+
# try to force PST
|
1008
|
+
|
1009
|
+
# TODO: at some point, try to find out if the latest jRuby still
|
1010
|
+
# exhibits that behaviour, report to them if necessary
|
1011
|
+
|
1012
|
+
points =
|
1013
|
+
(0..3).collect do
|
1014
|
+
t = line.previous_time(t)
|
1015
|
+
t.to_compact_s
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
if t.zone == 'PST'
|
1019
|
+
expect(points).to eq([
|
1020
|
+
'0101-8(0901)',
|
1021
|
+
'0100-8(0900)',
|
1022
|
+
'0159-7(0859)',
|
1023
|
+
'0158-7(0858)'
|
1024
|
+
])
|
1025
|
+
else
|
1026
|
+
expect(points).to eq([
|
1027
|
+
'0101-7(0801)',
|
1028
|
+
'0100-7(0800)',
|
1029
|
+
'0059-7(0759)',
|
1030
|
+
'0058-7(0758)'
|
1031
|
+
])
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
it 'correctly increments when leaving DST' do
|
1037
|
+
|
1038
|
+
in_zone 'America/Los_Angeles' do
|
1039
|
+
|
1040
|
+
line = cl('*/10 * * * * America/Los_Angeles')
|
1041
|
+
|
1042
|
+
t = Time.local(2015, 11, 1, 0, 40)
|
1043
|
+
t1 = t.dup
|
1044
|
+
|
1045
|
+
points = []
|
1046
|
+
while t1 - t < 2 * 3600
|
1047
|
+
t1 = line.next_time(t1)
|
1048
|
+
points << t1.to_compact_s
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
expect(points).to eq([
|
1052
|
+
'0050-7(0750)', # | PDT
|
1053
|
+
'0100-7(0800)', # |
|
1054
|
+
'0110-7(0810)', # V
|
1055
|
+
'0120-7(0820)',
|
1056
|
+
'0130-7(0830)',
|
1057
|
+
'0140-7(0840)',
|
1058
|
+
'0150-7(0850)',
|
1059
|
+
'0100-8(0900)', # + PST
|
1060
|
+
'0110-8(0910)', # |
|
1061
|
+
'0120-8(0920)', # V
|
1062
|
+
'0130-8(0930)',
|
1063
|
+
'0140-8(0940)'
|
1064
|
+
])
|
911
1065
|
end
|
912
1066
|
end
|
913
1067
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/zotime_spec.rb
CHANGED
@@ -73,22 +73,17 @@ describe Rufus::Scheduler::ZoTime do
|
|
73
73
|
# New York EST: UTC-5
|
74
74
|
# summer (dst) EDT: UTC-4
|
75
75
|
|
76
|
-
it 'chooses the
|
76
|
+
it 'chooses the DST time when there is ambiguity' do
|
77
77
|
|
78
78
|
t = ltz('America/New_York', 2004, 10, 31, 0, 30, 0)
|
79
79
|
zt = Rufus::Scheduler::ZoTime.new(t, 'America/New_York')
|
80
80
|
zt.add(3600)
|
81
81
|
ztt = zt.time
|
82
82
|
|
83
|
-
expect(ztt.to_i).to eq(1099204200)
|
83
|
+
expect(ztt.to_i).to eq(1099204200 - 3600)
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
).to eq('2004/10/31 01:30:00 EST -0500')
|
88
|
-
else
|
89
|
-
expect(ztt.strftime('%Y/%m/%d %H:%M:%S %Z %z')
|
90
|
-
).to eq('2004/10/31 01:30:00 EST -0500')
|
91
|
-
end
|
85
|
+
expect(ztt.strftime('%Y/%m/%d %H:%M:%S %Z %z')
|
86
|
+
).to eq('2004/10/31 01:30:00 EDT -0400')
|
92
87
|
end
|
93
88
|
end
|
94
89
|
|
@@ -162,17 +157,17 @@ describe Rufus::Scheduler::ZoTime do
|
|
162
157
|
st3 = t3.strftime('%Y/%m/%d %H:%M:%S %Z') + " #{t3.isdst}"
|
163
158
|
|
164
159
|
expect(t0.to_i).to eq(1414281599)
|
165
|
-
expect(t1.to_i).to eq(1414285200)
|
160
|
+
expect(t1.to_i).to eq(1414285200 - 3600)
|
166
161
|
expect(t2.to_i).to eq(1414285200)
|
167
162
|
expect(t3.to_i).to eq(1414285201)
|
168
163
|
|
169
164
|
expect(st0).to eq('2014/10/26 01:59:59 CEST true')
|
170
|
-
expect(st1).to eq('2014/10/26 02:00:00
|
165
|
+
expect(st1).to eq('2014/10/26 02:00:00 CEST true')
|
171
166
|
expect(st2).to eq('2014/10/26 02:00:00 CET false')
|
172
167
|
expect(st3).to eq('2014/10/26 02:00:01 CET false')
|
173
168
|
|
174
|
-
expect(t1 - t0).to eq(
|
175
|
-
expect(t2 - t1).to eq(
|
169
|
+
expect(t1 - t0).to eq(1)
|
170
|
+
expect(t2 - t1).to eq(3600)
|
176
171
|
expect(t3 - t2).to eq(1)
|
177
172
|
end
|
178
173
|
end
|
data/t.txt
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
JRUBY
|
3
|
+
|
4
|
+
1) Rufus::Scheduler::CronLine fall time correctly decrements every minute through a DST transition
|
5
|
+
|
6
|
+
Failure/Error: expect(points).to eq([
|
7
|
+
|
8
|
+
expected: ["0101-8(0901)", "0100-8(0900)", "0159-7(0859)", "0158-7(0858)"]
|
9
|
+
got: ["0101-7(0801)", "0100-7(0800)", "0059-7(0759)", "0058-7(0758)"]
|
10
|
+
|
11
|
+
(compared using ==)
|
12
|
+
# ./spec/cronline_spec.rb:1013:in `(root)'
|
13
|
+
# ./spec/spec_helper.rb:69:in `in_zone'
|
14
|
+
# ./spec/cronline_spec.rb:1001:in `(root)'
|
15
|
+
|
16
|
+
|
17
|
+
RUBY1.8
|
18
|
+
|
19
|
+
1) Rufus::Scheduler::CronLine fall time correctly decrements every minute through a DST transition
|
20
|
+
|
21
|
+
Failure/Error: expect(points).to eq([
|
22
|
+
|
23
|
+
expected: ["0101-8(0901)", "0100-8(0900)", "0159-7(0859)", "0158-7(0858)"]
|
24
|
+
got: ["0101-7(0801)", "0100-7(0800)", "0059-7(0759)", "0058-7(0758)"]
|
25
|
+
|
26
|
+
(compared using ==)
|
27
|
+
# ./spec/cronline_spec.rb:1013
|
28
|
+
# ./spec/spec_helper.rb:69:in `call'
|
29
|
+
# ./spec/spec_helper.rb:69:in `in_zone'
|
30
|
+
# ./spec/cronline_spec.rb:1001
|
31
|
+
|
metadata
CHANGED
@@ -1,69 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rufus-scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Mettraux
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 2.13.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.13.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: chronic
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: tzinfo
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - '>='
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
description: job scheduler for Ruby (at, cron, in and every jobs).
|
@@ -73,14 +73,7 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
-
- CHANGELOG.txt
|
77
|
-
- CREDITS.txt
|
78
|
-
- LICENSE.txt
|
79
|
-
- README.md
|
80
76
|
- Rakefile
|
81
|
-
- TODO.txt
|
82
|
-
- lib/rufus-scheduler.rb
|
83
|
-
- lib/rufus/scheduler.rb
|
84
77
|
- lib/rufus/scheduler/cronline.rb
|
85
78
|
- lib/rufus/scheduler/job_array.rb
|
86
79
|
- lib/rufus/scheduler/jobs.rb
|
@@ -88,7 +81,8 @@ files:
|
|
88
81
|
- lib/rufus/scheduler/util.rb
|
89
82
|
- lib/rufus/scheduler/zones.rb
|
90
83
|
- lib/rufus/scheduler/zotime.rb
|
91
|
-
- rufus
|
84
|
+
- lib/rufus/scheduler.rb
|
85
|
+
- lib/rufus-scheduler.rb
|
92
86
|
- spec/basics_spec.rb
|
93
87
|
- spec/cronline_spec.rb
|
94
88
|
- spec/error_spec.rb
|
@@ -114,6 +108,13 @@ files:
|
|
114
108
|
- spec/spec_helper.rb
|
115
109
|
- spec/threads_spec.rb
|
116
110
|
- spec/zotime_spec.rb
|
111
|
+
- rufus-scheduler.gemspec
|
112
|
+
- CHANGELOG.txt
|
113
|
+
- CREDITS.txt
|
114
|
+
- LICENSE.txt
|
115
|
+
- t.txt
|
116
|
+
- TODO.txt
|
117
|
+
- README.md
|
117
118
|
homepage: http://github.com/jmettraux/rufus-scheduler
|
118
119
|
licenses:
|
119
120
|
- MIT
|
@@ -124,17 +125,17 @@ require_paths:
|
|
124
125
|
- lib
|
125
126
|
required_ruby_version: !ruby/object:Gem::Requirement
|
126
127
|
requirements:
|
127
|
-
- -
|
128
|
+
- - '>='
|
128
129
|
- !ruby/object:Gem::Version
|
129
130
|
version: '0'
|
130
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
132
|
requirements:
|
132
|
-
- -
|
133
|
+
- - '>='
|
133
134
|
- !ruby/object:Gem::Version
|
134
135
|
version: '0'
|
135
136
|
requirements: []
|
136
137
|
rubyforge_project: rufus
|
137
|
-
rubygems_version: 2.
|
138
|
+
rubygems_version: 2.0.14
|
138
139
|
signing_key:
|
139
140
|
specification_version: 4
|
140
141
|
summary: job scheduler for Ruby (at, cron, in and every jobs)
|