vrinek-cronos 0.6.1

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.
data/CHANGELOG ADDED
@@ -0,0 +1,30 @@
1
+ == 0.6.1 2009-08-07
2
+ - fixed README
3
+
4
+ == 0.6.0 2009-08-07
5
+ - added Cronos::Parser with syntax: Cronos::Parser.new(cron_string).now? => true or false
6
+
7
+ == 0.5.1 2009-08-07
8
+ - will try to combine multiple times eg. at(12, 15, '5:00 pm') will return "0 12,15,17 * * *"
9
+
10
+ == 0.5.0 2009-08-07
11
+ - can now use multiple times eg. at(12.30, 15.15, '5.20 pm')
12
+
13
+ == 0.4.0 2009-03-06
14
+ - every method now handles days and months eg. every(:mon, :tue), every('mon'..'wed'), every(:jan, :feb) etc.
15
+ - added schedule method which takes a command and outputs it in the cron string
16
+
17
+ == 0.3.1 2009-02-03
18
+ - added ranges to #days
19
+
20
+ == 0.3.0 2009-01-27
21
+ - better range handling for #on and #of including support for end excluded ranges
22
+ - aliased #of with #in
23
+ - make #every more flexible to allow use with for days and months eg. every(:thursday, 'Friday') or every(:jan, :feb)
24
+ - adde midnight and midday methods
25
+
26
+ == 0.2.2 2009-01-17
27
+ - fix to ensure string values in hash from to_hash method
28
+
29
+ == 0.2.1 2009-01-17
30
+ - added to_hash method with CronEdit compatible key names
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Adam Meehan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,83 @@
1
+ = Cronos
2
+
3
+ A Ruby DSL for outputting Cron intervals.
4
+
5
+ Using a natural syntax to write cron task intervals assists in generating the correct cron interval
6
+ you are after instead of trying to remember the cron syntax and conventions.
7
+
8
+
9
+ == Examples
10
+
11
+ cron = Cronos::Interval
12
+
13
+ puts cron.new.hourly
14
+ # => '0 * * * *'
15
+
16
+ puts cron.new.daily
17
+ # => '0 0 * * *'
18
+
19
+ puts cron.new.weekly
20
+ # => '0 0 * * 0'
21
+
22
+ puts cron.new.weekdays.at(12.30)
23
+ # => '30 12 * * 1-5'
24
+
25
+ puts cron.new.weekends.at(12.30)
26
+ # => '30 12 * * 0,6'
27
+
28
+ puts cron.new.at('1.30pm').daily
29
+ # => '30 13 * * *'
30
+
31
+ puts cron.new.every(6).hours.on('15th').of(:january)
32
+ # => '0 0,6,12,18 15 1 *'
33
+
34
+ puts cron.new.every(20).minutes.on('15th'..'18th').of(:jan, :feb, :mar)
35
+ # => '0,20,40 * 15-18 1,2,3 *'
36
+
37
+ puts cron.new.at(14.45).every(:monday, :tuesday)
38
+ # => '45 14 * * 1,2'
39
+
40
+
41
+ You can also output the whole cron task string using the schedule method:
42
+
43
+ puts Cronos.schedule('some_task').every(:Sunday).at('3am')
44
+ # => '0 3 * * 0 some_task'
45
+
46
+ This does not actually schedule the task in cron. Cronos is merely a DSL to output the cron intervals.
47
+
48
+ == Caveats
49
+
50
+ Certain combinations produce unintuitive results. They should be obvious but just in case I will
51
+ list some. Such as
52
+
53
+ weekly.on_days(:monday, :tuesday)
54
+
55
+ Will actually run the task *twice* weekly
56
+
57
+ TODO: more weird stuff?
58
+
59
+ Also cron itself allows days of month and days of week to be set. These are independent of each other.
60
+
61
+ For example:
62
+
63
+ on_the('15th').of(:jan).on_days(:mon, :tue)
64
+
65
+ This will be run on the 15th of January AND every Monday and Tuesday of January, so be aware. Though it
66
+ is a strange combination anyway, the result is the union of both and not the intersection.
67
+
68
+
69
+ == Install
70
+
71
+ sudo gem install vrinek-cronos -s http://gems.github.com
72
+
73
+
74
+ == Credits
75
+
76
+ Adam Meehan (http://duckpunching.com, adam.meehan@gmail.com)
77
+
78
+ Kostas Karachalios (kostas.karachalios@gmail.com)
79
+
80
+
81
+ == License
82
+
83
+ Copyright (c) 2008 Adam Meehan, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require 'spec/rake/spectask'
6
+ require 'lib/cronos'
7
+
8
+ GEM = "cronos"
9
+ GEM_VERSION = Cronos::VERSION
10
+ AUTHOR = "Adam Meehan"
11
+ EMAIL = "adam.meehan@gmail.com"
12
+ HOMEPAGE = "http://github.com/adzap/cronos"
13
+ SUMMARY = "Tool for generating cron intervals using a natural syntax"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.name = GEM
17
+ s.version = GEM_VERSION
18
+ s.platform = Gem::Platform::RUBY
19
+ s.has_rdoc = true
20
+ s.extra_rdoc_files = ["README.rdoc", "LICENSE", 'TODO', "CHANGELOG"]
21
+ s.summary = SUMMARY
22
+ s.description = s.summary
23
+ s.author = AUTHOR
24
+ s.email = EMAIL
25
+ s.homepage = HOMEPAGE
26
+
27
+ # Uncomment this to add a dependency
28
+ # s.add_dependency "foo"
29
+
30
+ s.require_path = 'lib'
31
+ s.autorequire = GEM
32
+ s.files = %w(LICENSE README.rdoc Rakefile TODO CHANGELOG) + Dir.glob("{lib,spec}/**/*")
33
+ end
34
+
35
+ task :default => :spec
36
+
37
+ desc "Run specs"
38
+ Spec::Rake::SpecTask.new do |t|
39
+ t.spec_files = FileList['spec/**/*_spec.rb']
40
+ t.spec_opts = %w(-fs --color)
41
+ end
42
+
43
+
44
+ Rake::GemPackageTask.new(spec) do |pkg|
45
+ pkg.gem_spec = spec
46
+ end
47
+
48
+ desc "install the gem locally"
49
+ task :install => [:package] do
50
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
51
+ end
52
+
53
+ desc "create a gemspec file"
54
+ task :make_spec do
55
+ File.open("#{GEM}.gemspec", "w") do |file|
56
+ file.puts spec.to_ruby
57
+ end
58
+ end
data/TODO ADDED
@@ -0,0 +1,7 @@
1
+ TODO:
2
+ - more examples
3
+ - more everything as its a start
4
+ - default time setting, when time not explicit, instead of midnight
5
+ - instantiate interval from cron string
6
+ - say method to output English description as comment at end of cron interval
7
+
data/lib/cronos.rb ADDED
@@ -0,0 +1,396 @@
1
+ module Cronos
2
+
3
+ VERSION = '0.6.1'
4
+
5
+ def self.schedule(task)
6
+ TaskInterval.new(task)
7
+ end
8
+
9
+ class Interval
10
+ attr_accessor :min, :hour, :day, :month, :dow
11
+
12
+ MONTHS = [nil, :jan, :feb, :mar, :apr, :may, :jun, :jul, :aug, :sep, :oct, :nov, :dec]
13
+
14
+ DAYS = [:sun, :mon, :tue, :wed, :thu, :fri, :sat]
15
+
16
+ =begin rdoc
17
+ Time:
18
+ at(12)
19
+ at(1.30)
20
+ at('01.30')
21
+ at(14.30)
22
+ at('2pm')
23
+ at('2:20')
24
+ at('5:15pm')
25
+
26
+ at(12.30, '3.15 pm', 22, '15:30')
27
+ Note that the last one will return an array of cron strings
28
+ =end
29
+ def at(*times)
30
+ @hours = []
31
+ @mins = []
32
+
33
+ times.each do |time|
34
+ @hour, @min, meridian = parse_time(time)
35
+
36
+ raise "invalid hour value for 'at'" if @hour > 12 && meridian
37
+ raise "invalid minute value for 'at'" if @min > 59
38
+
39
+ case meridian
40
+ when 'am'
41
+ @hour = 0 if @hour == 12
42
+ when 'pm'
43
+ @hour += 12 if @hour < 12
44
+ end
45
+
46
+ raise "invalid hour value for 'at'" if @hour > 23
47
+
48
+ @hours << @hour
49
+ @mins << @min
50
+ end
51
+
52
+ self
53
+ end
54
+
55
+ =begin rdoc
56
+ Repeats an interval:
57
+ every(10).minutes
58
+ every(6).hours
59
+ every(2).months
60
+
61
+ or use as an alias for #on or #days
62
+ every(:monday)
63
+ every(:mon, :tues)
64
+ every('Monday'.. 'Wednesday')
65
+ every('February', :march)
66
+ every('Feb'..'June')
67
+ =end
68
+ def every(*multiple)
69
+ return RepeatInterval.new(multiple.first, self) if multiple.first.is_a?(Fixnum)
70
+
71
+ if multiple.all? {|abbr| is_month?(abbr) }
72
+ of(*multiple)
73
+ elsif multiple.all? {|abbr| is_day?(abbr) }
74
+ days(*multiple)
75
+ else
76
+ raise "Unknown interval type passed to #every"
77
+ end
78
+ end
79
+
80
+ =begin rdoc
81
+ Days of month:
82
+ on(13)
83
+ on('13th')
84
+ on(13..17)
85
+ on('13th'..'17th')
86
+ on(13...18)
87
+ on_the('13th')
88
+ =end
89
+ def on(*args)
90
+ if args.first.is_a?(Range)
91
+ @day = format_range(args.first)
92
+ else
93
+ list = args.collect {|day| day.to_s.to_i }
94
+ @day = list.join(',')
95
+ end
96
+ self
97
+ end
98
+ alias on_the on
99
+
100
+ =begin rdoc
101
+ Days of the week:
102
+ days(:monday)
103
+ days('Monday')
104
+ days(:mon)
105
+ days(1..3)
106
+ days('mon'..'wed')
107
+ days(1...4)
108
+ on_day(:monday)
109
+ days(:mon, :tues)
110
+ on_days(:mon, :tues)
111
+ =end
112
+ def days(*args)
113
+ if args.first.is_a?(Range)
114
+ @dow = format_range(args.first)
115
+ else
116
+ list = args.map {|day| day_value(day) unless day.is_a?(Fixnum) }
117
+ @dow = list.join(',')
118
+ end
119
+ self
120
+ end
121
+ alias on_days days
122
+ alias on_day days
123
+
124
+ =begin rdoc
125
+ Months:
126
+ of(:january)
127
+ of('January')
128
+ of(:jan)
129
+ of(:jan, :feb, :mar)
130
+ of(1..3)
131
+ of('jan'..'mar')
132
+ of(1...4)
133
+ of_months(1, 2, 3)
134
+ in(:january)
135
+ =end
136
+ def of(*args)
137
+ if args.first.is_a?(Range)
138
+ @month = format_range(args.first)
139
+ else
140
+ list = args.map {|month| month_value(month) unless month.is_a?(Fixnum) }
141
+ @month = list.join(',')
142
+ end
143
+ self
144
+ end
145
+ alias of_months of
146
+ alias in of
147
+
148
+ def hourly
149
+ @min = 0
150
+ @hour = nil
151
+ self
152
+ end
153
+
154
+ def daily
155
+ @min ||= 0
156
+ @hour ||= 0
157
+ @day = nil
158
+ self
159
+ end
160
+ alias once_a_day daily
161
+
162
+ def midnight
163
+ @min = 0
164
+ @hour = 0
165
+ self
166
+ end
167
+ alias at_midnight midnight
168
+
169
+ def midday
170
+ @min = 0
171
+ @hour = 12
172
+ self
173
+ end
174
+ alias at_midday midday
175
+
176
+ def weekly
177
+ @min ||= 0
178
+ @hour ||= 0
179
+ @dow ||= 0
180
+ @day = nil
181
+ @month = nil
182
+ self
183
+ end
184
+ alias once_a_week weekly
185
+
186
+ def monthly
187
+ @min ||= 0
188
+ @hour ||= 0
189
+ @day ||= 1
190
+ @month = nil
191
+ @dow = nil
192
+ self
193
+ end
194
+ alias once_a_month monthly
195
+
196
+ def weekdays
197
+ @min ||= 0
198
+ @hour ||= 0
199
+ @dow = '1-5'
200
+ self
201
+ end
202
+
203
+ def weekends
204
+ @min ||= 0
205
+ @hour ||= 0
206
+ @dow = '0,6'
207
+ self
208
+ end
209
+
210
+ =begin rdoc
211
+ Returns the rules as a cron string (like the ones used in /etc/crontab)
212
+ =end
213
+ def to_s
214
+ if @hours and @mins and @hours.length == @mins.length and @mins.length > 1
215
+ try_to_combine([@hours, @mins].transpose.collect do |hour, min|
216
+ cron_string hour, min
217
+ end)
218
+ else
219
+ cron_string
220
+ end
221
+ end
222
+
223
+ =begin rdoc
224
+ Returns the rules as a human-readable hash
225
+ =end
226
+ def to_hash
227
+ if @hours and @mins and @hours.length == @mins.length and @mins.length > 1
228
+ [@hours, @mins].transpose.collect do |hour, min|
229
+ cron_hash hour, min
230
+ end
231
+ else
232
+ cron_hash
233
+ end
234
+ end
235
+
236
+ private
237
+
238
+ def try_to_combine(cron_strings)
239
+ if (multiples = cron_strings.collect{ |str| str.split ' '}.transpose).select{ |a| a.uniq.length > 1}.length > 1
240
+ return cron_strings # no can do
241
+ elsif cron_strings.uniq.length == 1
242
+ cron_strings.first
243
+ else
244
+ multiples.collect{|a| a.uniq.join ","}.join ' '
245
+ end
246
+ end
247
+
248
+ def cron_string(hour = nil, min = nil)
249
+ "#{min || @min || '*'} #{hour || @hour || '*'} #{day || '*'} #{month || '*'} #{dow || '*'}"
250
+ end
251
+
252
+ def cron_hash(hour = nil, min = nil)
253
+ {
254
+ :minute => "#{min || @min || '*'}",
255
+ :hour => "#{hour || @hour || '*'}",
256
+ :day => "#{day || '*'}",
257
+ :month => "#{month || '*'}",
258
+ :weekday => "#{dow || '*'}"
259
+ }
260
+ end
261
+
262
+ def parse_time(time)
263
+ meridian = /pm|am/i.match(time.to_s)[0].downcase rescue nil
264
+ hour, min = *time.to_s.split(/[\.:]/)
265
+
266
+ hour = hour.to_i
267
+ min = min.strip.ljust(2, '0').to_i if min
268
+ min ||= 0
269
+
270
+ return hour, min, meridian
271
+ end
272
+
273
+ def format_range(range)
274
+ values = [range.first, range.last]
275
+
276
+ if values.all? {|v| v.to_i > 0 }
277
+ first, last = values.first.to_i, values.last.to_i
278
+ elsif values.all? {|abbr| is_month?(abbr) }
279
+ first, last = month_value(values.first), month_value(values.last)
280
+ elsif values.all? {|abbr| is_day?(abbr) }
281
+ first, last = day_value(values.first), day_value(values.last)
282
+ end
283
+
284
+ int_range = range.exclude_end? ? first...last : first..last
285
+ list = Array(int_range).sort
286
+ "#{list.first}-#{list.last}"
287
+ end
288
+
289
+ def is_month?(value)
290
+ MONTHS.include?(value.to_s.downcase[0..2].to_sym)
291
+ end
292
+
293
+ def month_value(value)
294
+ MONTHS.index(value.to_s.downcase[0..2].to_sym)
295
+ end
296
+
297
+ def is_day?(value)
298
+ DAYS.include?(value.to_s.downcase[0..2].to_sym)
299
+ end
300
+
301
+ def day_value(value)
302
+ DAYS.index(value.to_s.downcase[0..2].to_sym)
303
+ end
304
+
305
+ class RepeatInterval
306
+ def initialize(multiple, interval)
307
+ @multiple, @interval = multiple, interval
308
+ end
309
+
310
+ def minutes
311
+ raise 'Multiple of minutes will not fit into an hour' if (60 % @multiple) > 0
312
+ calculate_intervals(60)
313
+ @interval.min = self
314
+ @interval
315
+ end
316
+
317
+ def hours
318
+ raise 'Multiple of hours will not fit into a day' if (24 % @multiple) > 0
319
+ calculate_intervals(24)
320
+ @interval.min = 0
321
+ @interval.hour = self
322
+ @interval
323
+ end
324
+
325
+ def months
326
+ raise 'Multiple of months will not fit into a year' if (12 % @multiple) > 0
327
+ calculate_intervals(12, 1)
328
+ @interval.min ||= 0
329
+ @interval.hour ||= 0
330
+ @interval.day ||= 1
331
+ @interval.month = self
332
+ @interval
333
+ end
334
+
335
+ def calculate_intervals(base, initial = 0)
336
+ repeats = (base / @multiple) - 1
337
+ set = [initial]
338
+ 1.upto(repeats) {|factor| set << (factor * @multiple + initial) }
339
+ @intervals = set
340
+ end
341
+
342
+ def to_s
343
+ @intervals.join(',')
344
+ end
345
+
346
+ def to_a
347
+ @intervals
348
+ end
349
+ end
350
+ end
351
+
352
+ =begin rdoc
353
+ == Usage:
354
+ cron = Cronos::Interval.new.at('11pm').on_days(:monday, :tuesday).to_s # => '0 23 * * 1,2'
355
+ Cronos::Parser.new(cron).now? # => true or false
356
+ =end
357
+ class Parser
358
+ =begin rdoc
359
+ The cron_string should ideally come from Cronos::Interval#to_s
360
+ =end
361
+ def initialize(cron_string)
362
+ @cron_string = cron_string
363
+ end
364
+
365
+ =begin rdoc
366
+ Returns true or false depending if the time matches the cron string given on initialization
367
+ =end
368
+ def now?(time = Time.now)
369
+ min, hour, day, month, wday = @cron_string.split ' '
370
+
371
+ [:min, :hour, :day, :month, :wday].all? do |period|
372
+ p = eval(period.to_s)
373
+ p == '*' or p.split(',').collect{ |parts|
374
+ if parts[/-/]
375
+ first, last = parts.split '-'
376
+ (first..last).to_a
377
+ else
378
+ parts
379
+ end
380
+ }.flatten.include? eval("time.#{period}").to_s
381
+ end
382
+ end
383
+ end
384
+
385
+ class TaskInterval < Interval
386
+ attr_accessor :task
387
+
388
+ def initialize(task)
389
+ @task = task
390
+ end
391
+
392
+ def to_s
393
+ "#{super} #{@task}"
394
+ end
395
+ end
396
+ end
@@ -0,0 +1,482 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'activesupport'
4
+
5
+ describe Cronos do
6
+
7
+ it "should return task interval instance from schedule method" do
8
+ Cronos.schedule('ls').should be_kind_of(Cronos::TaskInterval)
9
+ end
10
+
11
+ end
12
+
13
+ describe Cronos::Interval do
14
+
15
+ it "should return default interval for every minute" do
16
+ interval.to_s.should == '* * * * *'
17
+ end
18
+
19
+ it "should return hash of values from to_hash method" do
20
+ interval.at(2.01).on_the('3rd').of(:april).to_hash.should == {:minute => '1', :hour => '2', :day => '3', :month => '4', :weekday => '*'}
21
+ end
22
+
23
+ describe "at method" do
24
+ it "should output interval from integer with hour as integer value and 0 minute" do
25
+ interval.at(8).to_s.should == '0 8 * * *'
26
+ end
27
+
28
+ it "should output interval from a float with hour value from integer part and minute from decimal part" do
29
+ interval.at(8.21).to_s.should == '21 8 * * *'
30
+ end
31
+
32
+ it "should output interval from a float with hour value from integer part and minute from decimal part left justified to 2 digits" do
33
+ interval.at(8.20).to_s.should == '20 8 * * *'
34
+ end
35
+
36
+ it "should output interval from time string with pm meridian having hour adjusted 24 hour time" do
37
+ interval.at('8.21pm').to_s.should == '21 20 * * *'
38
+ end
39
+
40
+ it "should output interval from time string with pm meridian having hour unadjusted if hour is 12" do
41
+ interval.at('12.21pm').to_s.should == '21 12 * * *'
42
+ end
43
+
44
+ it "should output interval from time string with am meridian having hour adjusted to 0 if hour is 12" do
45
+ interval.at('12.21am').to_s.should == '21 0 * * *'
46
+ end
47
+
48
+ it "should raise error if hours out of range" do
49
+ lambda { interval.daily.at('24.21') }.should raise_error
50
+ end
51
+
52
+ it "should raise error if minutes out of range" do
53
+ lambda { interval.daily.at('23.60') }.should raise_error
54
+ end
55
+
56
+ it "should output string interval for multiple times" do
57
+ interval.at(8, 10, 22).to_s.should == '0 8,10,22 * * *'
58
+ interval.at(8.20, 10.30, 22.55).to_s.should == ['20 8 * * *', '30 10 * * *', '55 22 * * *']
59
+ end
60
+
61
+ it "should output a combined string interval for multiple times (that can be combined)" do
62
+ interval.at(8, 10, 22).to_s.should == '0 8,10,22 * * *'
63
+ interval.at(8.20, 10.20, 22.20).to_s.should == '20 8,10,22 * * *'
64
+ interval.at('8:20', 10.20, '10:20 pm').to_s.should == '20 8,10,22 * * *'
65
+
66
+ interval.at(8, 8, 8, 5).to_s.should == '0 8,5 * * *'
67
+ end
68
+
69
+ it "should output string interval for mixed formats multiple times" do
70
+ interval.at('8:20 am', '10:30', '22:55', '5:15pm').to_s.should == ['20 8 * * *', '30 10 * * *', '55 22 * * *', '15 17 * * *']
71
+ interval.at(12.30, '3.15 pm', 22, '15:30').to_s.should == ['30 12 * * *', '15 15 * * *', '0 22 * * *', '30 15 * * *']
72
+ end
73
+
74
+ it "should output hash interval for multiple times" do
75
+ interval.at(8, 10, 22).to_hash.should == [
76
+ {
77
+ :minute => "0",
78
+ :hour => "8",
79
+ :day => "*",
80
+ :month => "*",
81
+ :weekday => "*"
82
+ }, {
83
+ :minute => "0",
84
+ :hour => "10",
85
+ :day => "*",
86
+ :month => "*",
87
+ :weekday => "*"
88
+ }, {
89
+ :minute => "0",
90
+ :hour => "22",
91
+ :day => "*",
92
+ :month => "*",
93
+ :weekday => "*"
94
+ }
95
+ ]
96
+
97
+ interval.at(8.20, 10.30, 22.55).to_hash.should == [
98
+ {
99
+ :minute => "20",
100
+ :hour => "8",
101
+ :day => "*",
102
+ :month => "*",
103
+ :weekday => "*"
104
+ }, {
105
+ :minute => "30",
106
+ :hour => "10",
107
+ :day => "*",
108
+ :month => "*",
109
+ :weekday => "*"
110
+ }, {
111
+ :minute => "55",
112
+ :hour => "22",
113
+ :day => "*",
114
+ :month => "*",
115
+ :weekday => "*"
116
+ }
117
+ ]
118
+ end
119
+ end
120
+
121
+ describe "on method" do
122
+ it "should output interval from integer with day of month as value" do
123
+ interval.on(15).to_s.should == '* * 15 * *'
124
+ end
125
+
126
+ it "should output interval from day string with ordinal suffix" do
127
+ interval.on('15th').to_s.should == '* * 15 * *'
128
+ end
129
+
130
+ it "should output interval from inclusive range as dashed day of month range " do
131
+ interval.on(15..17).to_s.should == '* * 15-17 * *'
132
+ end
133
+
134
+ it "should output interval from string inclusive range as dashed day of month range " do
135
+ interval.on('15th'..'17th').to_s.should == '* * 15-17 * *'
136
+ end
137
+
138
+ it "should output interval from exclusive range as dashed day of month range " do
139
+ interval.on(15...18).to_s.should == '* * 15-17 * *'
140
+ end
141
+
142
+ it "should output interval from integer array as day number list" do
143
+ interval.on(15, 16, 17).to_s.should == '* * 15,16,17 * *'
144
+ end
145
+
146
+ it "should output interval from day string array as day number list" do
147
+ interval.on('15th', '16th', '17th').to_s.should == '* * 15,16,17 * *'
148
+ end
149
+ end
150
+
151
+ describe "of method" do
152
+ it "should output interval with month number from a symbol month name" do
153
+ interval.of(:january).to_s.should == '* * * 1 *'
154
+ end
155
+
156
+ it "should output interval with month number from a symbol short month name" do
157
+ interval.of(:jan).to_s.should == '* * * 1 *'
158
+ end
159
+
160
+ it "should output interval with month number from a strong month name" do
161
+ interval.of('January').to_s.should == '* * * 1 *'
162
+ end
163
+
164
+ it "should output interval with comma seperated month numbers from array of symbol month names" do
165
+ interval.of(:january, :february, :march).to_s.should == '* * * 1,2,3 *'
166
+ end
167
+
168
+ it "should output interval with comma seperated month numbers from array of short symbol month names" do
169
+ interval.of(:jan, :feb, :mar).to_s.should == '* * * 1,2,3 *'
170
+ end
171
+
172
+ it "should output interval with comma seperated month numbers from array of string month names" do
173
+ interval.of('January', 'February', 'March').to_s.should == '* * * 1,2,3 *'
174
+ end
175
+
176
+ it "should output interval from integer inclusive range as dashed month range " do
177
+ interval.of(1..3).to_s.should == '* * * 1-3 *'
178
+ end
179
+
180
+ it "should output interval from string inclusive range as dashed month range " do
181
+ interval.of('jan'..'mar').to_s.should == '* * * 1-3 *'
182
+ end
183
+
184
+ it "should output interval from integer exclusive range as dashed month range " do
185
+ interval.of(1...4).to_s.should == '* * * 1-3 *'
186
+ end
187
+ end
188
+
189
+ describe "days method" do
190
+ it "should output interval with day number from a symbol day name" do
191
+ interval.days(:monday).to_s.should == '* * * * 1'
192
+ end
193
+
194
+ it "should output interval with day number from a string day name" do
195
+ interval.days('Mondays').to_s.should == '* * * * 1'
196
+ end
197
+
198
+ it "should output interval with day number from a symbol short day name" do
199
+ interval.days(:mon).to_s.should == '* * * * 1'
200
+ end
201
+
202
+ it "should output interval with day numbers from array of symbol day names" do
203
+ interval.days(:monday, :wednesday, :friday).to_s.should == '* * * * 1,3,5'
204
+ end
205
+
206
+ it "should output interval with day numbers from array of symbol short day names" do
207
+ interval.days(:mon, :wed, :fri).to_s.should == '* * * * 1,3,5'
208
+ end
209
+
210
+ it "should output interval with day numbers from array of string day names" do
211
+ interval.days('Monday', 'Wednesday', 'Friday').to_s.should == '* * * * 1,3,5'
212
+ end
213
+
214
+ it "should output interval from integer inclusive range as dashed dow range " do
215
+ interval.days(1..3).to_s.should == '* * * * 1-3'
216
+ end
217
+
218
+ it "should output interval from string inclusive range as dashed dow range " do
219
+ interval.days('mon'..'wed').to_s.should == '* * * * 1-3'
220
+ end
221
+
222
+ it "should output interval from integer exclusive range as dashed dow range " do
223
+ interval.days(1...4).to_s.should == '* * * * 1-3'
224
+ end
225
+ end
226
+
227
+ describe "hourly method" do
228
+ it "should output interval to run at start of every hour" do
229
+ interval.hourly.to_s.should == '0 * * * *'
230
+ end
231
+
232
+ it "should only affect the hour and minutes" do
233
+ interval.day = 1
234
+ interval.month = 1
235
+ interval.dow = 1
236
+ interval.hourly.to_s.should == '0 * 1 1 1'
237
+ end
238
+ end
239
+
240
+ describe "daily method" do
241
+ it "should output interval to run at 00:00 every day by default" do
242
+ interval.daily.to_s.should == '0 0 * * *'
243
+ end
244
+
245
+ it "should only affect the hour, minutes and day" do
246
+ interval.month = 1
247
+ interval.dow = 1
248
+ interval.daily.to_s.should == '0 0 * 1 1'
249
+ end
250
+
251
+ it "should preserve hour and minutes if set" do
252
+ interval.min = 10
253
+ interval.hour = 11
254
+ interval.daily.to_s.should == '10 11 * * *'
255
+ end
256
+ end
257
+
258
+ describe "midnight method" do
259
+ it "should output interval to run at 00:00" do
260
+ interval.midnight.to_s.should == '0 0 * * *'
261
+ end
262
+ end
263
+
264
+ describe "midday method" do
265
+ it "should output interval to run at 12:00" do
266
+ interval.midday.to_s.should == '0 12 * * *'
267
+ end
268
+ end
269
+
270
+ describe "weekly method" do
271
+ it "should output interval to run on Sunday at 00:00 by default" do
272
+ interval.weekly.to_s.should == '0 0 * * 0'
273
+ end
274
+
275
+ it "should override day of month and month" do
276
+ interval.day = 1
277
+ interval.month = 1
278
+ interval.weekly.to_s.should == '0 0 * * 0'
279
+ end
280
+
281
+ it "should preserve hour, minute and day of week if set" do
282
+ interval.min = 10
283
+ interval.hour = 11
284
+ interval.dow = 1
285
+ interval.daily.to_s.should == '10 11 * * 1'
286
+ end
287
+ end
288
+
289
+ describe "monthly method" do
290
+ it "should output interval to run on the 1st day of every month at 00:00 by default" do
291
+ interval.monthly.to_s.should == '0 0 1 * *'
292
+ end
293
+
294
+ it "should override day of month and month" do
295
+ interval.day = 1
296
+ interval.month = 1
297
+ interval.monthly.to_s.should == '0 0 1 * *'
298
+ end
299
+
300
+ it "should preserve hour, minute and day if set" do
301
+ interval.min = 10
302
+ interval.hour = 11
303
+ interval.day = 12
304
+ interval.monthly.to_s.should == '10 11 12 * *'
305
+ end
306
+ end
307
+
308
+ describe "weekends method" do
309
+ it "should output interval to run at 00:00 every Saturday and Sunday" do
310
+ interval.weekends.to_s.should == '0 0 * * 0,6'
311
+ end
312
+ end
313
+
314
+ describe "weekdays method" do
315
+ it "should output interval to run at 00:00 every day Monday to Friday" do
316
+ interval.weekdays.to_s.should == '0 0 * * 1-5'
317
+ end
318
+ end
319
+
320
+ describe "every(x).minutes" do
321
+ it "should output interval for list of minutes differing by arg value" do
322
+ interval.every(15).minutes.to_s.should == '0,15,30,45 * * * *'
323
+ end
324
+
325
+ it "should raise error if x not a divisor of 60" do
326
+ lambda { interval.every(13).minutes }.should raise_error
327
+ end
328
+ end
329
+
330
+ describe "every(x).hours" do
331
+ it "should output interval for 0 minute and list of hours differing by arg value" do
332
+ interval.every(6).hours.to_s.should == '0 0,6,12,18 * * *'
333
+ end
334
+
335
+ it "should raise error if x not a divisor of 24" do
336
+ lambda { interval.every(13).minutes }.should raise_error
337
+ end
338
+ end
339
+
340
+ describe "every(x).months" do
341
+ it "should output interval for 00:00 on 1st day of month and list of months differing by arg value" do
342
+ interval.every(6).hours.to_s.should == '0 0,6,12,18 * * *'
343
+ end
344
+
345
+ it "should raise error if x not a divisor of 12" do
346
+ lambda { interval.every(7).minutes }.should raise_error
347
+ end
348
+ end
349
+
350
+ describe "every(day_name)" do
351
+ it "should output interval for day symbol as day of week" do
352
+ interval.every(:sunday).to_s.should == '* * * * 0'
353
+ end
354
+
355
+ it "should output interval for list of days as days of week" do
356
+ interval.every(:thursay, 'Friday').to_s.should == '* * * * 4,5'
357
+ end
358
+ end
359
+
360
+ describe "every(month_name)" do
361
+ it "should output interval for month symbol as month" do
362
+ interval.every(:january).to_s.should == '* * * 1 *'
363
+ end
364
+
365
+ it "should output interval for list of months as months" do
366
+ interval.every(:february, 'March').to_s.should == '* * * 2,3 *'
367
+ end
368
+ end
369
+
370
+ describe "combinations" do
371
+ it "weekly.at(3.30) should output '30 3 * * 0'" do
372
+ interval.weekly.at(3.30).to_s.should == '30 3 * * 0'
373
+ end
374
+
375
+ it "monthly.at(3.30) should output '30 3 * * *'" do
376
+ interval.monthly.at(3.30).to_s.should == '30 3 1 * *'
377
+ end
378
+
379
+ it "monthly.on_the('15th').at(3.30) should output '30 3 15 * *'" do
380
+ interval.monthly.on_the('15th').at(3.30).to_s.should == '30 3 15 * *'
381
+ end
382
+
383
+ it "at('11pm').on_days(:monday, :tuesday) should output '0 11 * * 1,2'" do
384
+ interval.at('11pm').on_days(:monday, :tuesday).to_s.should == '0 23 * * 1,2'
385
+ end
386
+
387
+ it "on(15).of(:january) should output '* * 15 1 *'" do
388
+ interval.on(15).of(:january).to_s.should == '* * 15 1 *'
389
+ end
390
+
391
+ it "on(15, 16, 17).of(:january) should output '* * 15,16,17 1 *'" do
392
+ interval.on(15, 16, 17).of(:january).to_s.should == '* * 15,16,17 1 *'
393
+ end
394
+
395
+ it "on(15..17).of(:january) should output '* * 15-17 1 *'" do
396
+ interval.on(15..17).of(:january).to_s.should == '* * 15-17 1 *'
397
+ end
398
+
399
+ it "on(15, 16, 17).of(:january) should output '* * 15 1,6,12 *'" do
400
+ interval.on(15).of(:jan, :jun, :dec).to_s.should == '* * 15 1,6,12 *'
401
+ end
402
+
403
+ it "at('2.13pm').on_the_('15th').of(:january) should output '13 14 15 1'" do
404
+ interval.at('2.13pm').on_the(15).of(:january).to_s.should == '13 14 15 1 *'
405
+ end
406
+
407
+ it "every(15).minutes.on_the('15th').of(:january) should output '0,15,30,45 * 15 1 *'" do
408
+ interval.every(15).minutes.on_the('15th').of(:january).to_s.should == '0,15,30,45 * 15 1 *'
409
+ end
410
+ end
411
+
412
+ def interval
413
+ @interval ||= Cronos::Interval.new
414
+ end
415
+ end
416
+
417
+ describe Cronos::TaskInterval do
418
+
419
+ it "should output task at end of interval string" do
420
+ Cronos::TaskInterval.new('ls').at('12pm').to_s.should == '0 12 * * * ls'
421
+ end
422
+
423
+ end
424
+
425
+ describe Cronos::Parser do
426
+ describe '#now?' do
427
+ it "should return true if cron_string is all stars" do
428
+ Cronos::Parser.new("* * * * *").now?(time).should == true
429
+ Cronos::Parser.new("* * * * *").now?.should == true
430
+ end
431
+
432
+ it "should return true if cron_string matches parts and rest is stars" do
433
+ Cronos::Parser.new("* 14 * * *").now?(time).should == true
434
+ Cronos::Parser.new("40 14 * * *").now?(time).should == true
435
+ Cronos::Parser.new("40 * * * *").now?(time).should == true
436
+ Cronos::Parser.new("40 * 5 * *").now?(time).should == true
437
+ Cronos::Parser.new("* * * 8 *").now?(time).should == true
438
+ Cronos::Parser.new("* 14 * 8 *").now?(time).should == true
439
+ Cronos::Parser.new("* 14 * * 3").now?(time).should == true
440
+ end
441
+
442
+ it "should return true if cron_string is in range" do
443
+ Cronos::Parser.new("* 10-20 * * *").now?(time).should == true
444
+ Cronos::Parser.new("30-50 10-20 * * *").now?(time).should == true
445
+ Cronos::Parser.new("30-50 * * * 1-5").now?(time).should == true
446
+ end
447
+
448
+ it "should return true if cron_string matches on a lists" do
449
+ Cronos::Parser.new("20,40 10,14,20 * * *").now?(time).should == true
450
+ Cronos::Parser.new("20,40 * 5,12 * *").now?(time).should == true
451
+ Cronos::Parser.new("20,40 14 5,12 * *").now?(time).should == true
452
+ Cronos::Parser.new("20,40 * 5,12 * 2,3,6").now?(time).should == true
453
+ end
454
+
455
+ it "should return false if cron_string does not match some parts" do
456
+ Cronos::Parser.new("* 15 * * *").now?(time).should == false
457
+ Cronos::Parser.new("45 14 * * *").now?(time).should == false
458
+ Cronos::Parser.new("30 * * * *").now?(time).should == false
459
+ Cronos::Parser.new("40 * 6 * *").now?(time).should == false
460
+ Cronos::Parser.new("* * * 10 *").now?(time).should == false
461
+ Cronos::Parser.new("* 15 * 8 *").now?(time).should == false
462
+ Cronos::Parser.new("* 14 * 8 2").now?(time).should == false
463
+ end
464
+
465
+ it "should return false if cron_string is not in range" do
466
+ Cronos::Parser.new("* 20-25 * * *").now?(time).should == false
467
+ Cronos::Parser.new("10-30 10-20 * * *").now?(time).should == false
468
+ Cronos::Parser.new("* 10-20 * * 4-5").now?(time).should == false
469
+ end
470
+
471
+ it "should return false if cron_string does not match on a lists" do
472
+ Cronos::Parser.new("20,40 10,20 * * *").now?(time).should == false
473
+ Cronos::Parser.new("20,35 * 5,12 * *").now?(time).should == false
474
+ Cronos::Parser.new("20,40 14 3,8,12 * *").now?(time).should == false
475
+ Cronos::Parser.new("20,40 14 5,12 * 0,6").now?(time).should == false
476
+ end
477
+ end
478
+
479
+ def time
480
+ @time ||= Time.local(2009, "aug", 5, 14, 40, 23) # day is Wednesday (3)
481
+ end
482
+ end
@@ -0,0 +1,6 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'rubygems'
5
+ require 'spec'
6
+ require 'cronos'
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vrinek-cronos
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.1
5
+ platform: ruby
6
+ authors:
7
+ - Adam Meehan
8
+ autorequire: cronos
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-07 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Tool for generating cron intervals using a natural syntax
17
+ email: adam.meehan@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ - LICENSE
25
+ - TODO
26
+ - CHANGELOG
27
+ files:
28
+ - LICENSE
29
+ - README.rdoc
30
+ - Rakefile
31
+ - TODO
32
+ - CHANGELOG
33
+ - lib/cronos.rb
34
+ - spec/cronos_spec.rb
35
+ - spec/spec_helper.rb
36
+ has_rdoc: false
37
+ homepage: http://github.com/adzap/cronos
38
+ licenses:
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.3.5
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: Tool for generating cron intervals using a natural syntax
63
+ test_files: []
64
+