crony 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +9 -0
- data/README.md +55 -0
- data/Rakefile +11 -0
- data/crony.gemspec +24 -0
- data/cucumber.yml +3 -0
- data/features/date.feature +251 -0
- data/features/rubycron.feature +22 -0
- data/features/step_definitions/crony_steps.rb +9 -0
- data/features/support/env.rb +5 -0
- data/features/time.feature +61 -0
- data/lib/crony.rb +27 -0
- data/lib/crony/formatters/cron_struct.rb +28 -0
- data/lib/crony/formatters/day_of_month_formatter.rb +53 -0
- data/lib/crony/formatters/day_of_week_formatter.rb +46 -0
- data/lib/crony/formatters/hour_formatter.rb +31 -0
- data/lib/crony/formatters/minute_formatter.rb +35 -0
- data/lib/crony/formatters/month_formatter.rb +46 -0
- data/lib/crony/formatters/year_formatter.rb +33 -0
- data/lib/crony/parser.rb +49 -0
- data/lib/crony/presenters/day_presenter.rb +21 -0
- data/lib/crony/presenters/time_presenter.rb +30 -0
- data/lib/crony/presenters/year_presenter.rb +8 -0
- data/lib/crony/version.rb +3 -0
- data/lib/utility_functions.rb +31 -0
- metadata +143 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'cucumber', :cli => '--profile default' do
|
5
|
+
watch(%r{^features/.+\.feature$}) { 'features' }
|
6
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
7
|
+
watch(%r{^lib/.+$}) { 'features' }
|
8
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
9
|
+
end
|
data/LICENSE.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
## Does this sound like you?
|
2
|
+
|
3
|
+
* you _sorta_ know how to write a [cron][cron_wiki] expression
|
4
|
+
* you have to write them from time to time, but...
|
5
|
+
* you know that getting the answer from a friend (or the internet) isn't going to help you learn how to write them for yourself
|
6
|
+
* you'd just like to know if that cron expression you just wrote does what you meant it to
|
7
|
+
|
8
|
+
Crony's got your back.
|
9
|
+
|
10
|
+
# Crony
|
11
|
+
|
12
|
+
Crony is a 'spell-checker' for cron expressions. Ask it to parse that cron
|
13
|
+
expression you just wrote, and it'll let you know if it's gonna do anything
|
14
|
+
close to what you meant it to.
|
15
|
+
|
16
|
+
See Usage below for examples.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Add this line to your application's Gemfile:
|
21
|
+
|
22
|
+
gem 'crony'
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
$ gem install crony
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
irb > require 'crony'
|
35
|
+
=> true
|
36
|
+
irb > Crony.parse("3 4 22 5 * 2015")
|
37
|
+
=> "04:03 on May 22, 2015"
|
38
|
+
irb > Crony.parse("30 6 * * 6L *")
|
39
|
+
=> "06:30 on the last Saturday of every month"
|
40
|
+
irb > Crony.parse("10-15 6,12,18 * NOV THU#4 *")
|
41
|
+
=> "Every minute between 06:10 and 06:15, 12:10 and 12:15 and 18:10 and 18:15 on the 4th Thursday of November"
|
42
|
+
|
43
|
+
## Contributing
|
44
|
+
|
45
|
+
1. Fork it
|
46
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
47
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
48
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
49
|
+
5. Create new Pull Request
|
50
|
+
|
51
|
+
## Copyright
|
52
|
+
|
53
|
+
Copyright (c) 2013 Michael Berkowitz (@hal678). See LICENSE.txt for further details.
|
54
|
+
|
55
|
+
[cron_wiki]: http://en.wikipedia.org/wiki/Cron
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'cucumber/rake/task'
|
4
|
+
|
5
|
+
Cucumber::Rake::Task.new(:features)
|
6
|
+
|
7
|
+
Cucumber::Rake::Task.new('features:wip', 'Run work-in-progress cukes') do |task|
|
8
|
+
task.profile = 'wip'
|
9
|
+
end
|
10
|
+
|
11
|
+
task default: 'features:wip'
|
data/crony.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'crony/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "crony"
|
8
|
+
gem.version = Crony::VERSION
|
9
|
+
gem.authors = ["Michael Berkowitz"]
|
10
|
+
gem.email = ["michael.berkowitz@gmail.com"]
|
11
|
+
gem.description = %q{Spell-checker for cron expressions}
|
12
|
+
gem.summary = %q{Confirm that the cron expression you just wrote does what you meant it to do.}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency('cucumber')
|
21
|
+
gem.add_development_dependency('guard')
|
22
|
+
gem.add_development_dependency('guard-cucumber')
|
23
|
+
gem.add_development_dependency('rb-fsevent')
|
24
|
+
end
|
data/cucumber.yml
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
Feature: Parsing a cron expression with dates
|
2
|
+
In order to give anyone who doesn't have cron format 100% down cold
|
3
|
+
a way to check that they've got the correct expression
|
4
|
+
|
5
|
+
Scenario Outline: Parsing cron expressions
|
6
|
+
When I parse the expression "<cron_expression>"
|
7
|
+
Then I return "<human_readable>"
|
8
|
+
|
9
|
+
Examples:
|
10
|
+
| cron_expression | human_readable |
|
11
|
+
| * * 3-20/3 * * * | Every minute on every 3rd day from the 3rd to the 20th of every month |
|
12
|
+
| * * 1-15 * * * | Every minute on the 1st to the 15th of every month |
|
13
|
+
| * * */5 * * * | Every minute on every 5th day of every month |
|
14
|
+
| * * 2/5 * * * | Every minute on every 5th day starting on the 2nd of every month |
|
15
|
+
| * * 22 * * * | Every minute on the 22nd of every month |
|
16
|
+
| * * 4,5,7 * * * | Every minute on the 4th, 5th and 7th of every month |
|
17
|
+
| * * L * * * | Every minute on the last day of every month |
|
18
|
+
| * * 17W * * * | Every minute on the weekday closest to the 17th of every month |
|
19
|
+
| * * * 1-11/2 * * | Every minute on every day of every 2nd month from January to November |
|
20
|
+
| * * 3-20/3 1-11/2 * * | Every minute on every 3rd day from the 3rd to the 20th of every 2nd month from January to November |
|
21
|
+
| * * 1-15 1-11/2 * * | Every minute on the 1st to the 15th of every 2nd month from January to November |
|
22
|
+
| * * */5 1-11/2 * * | Every minute on every 5th day of every 2nd month from January to November |
|
23
|
+
| * * 2/5 1-11/2 * * | Every minute on every 5th day starting on the 2nd of every 2nd month from January to November |
|
24
|
+
| * * 22 1-11/2 * * | Every minute on the 22nd of every 2nd month from January to November |
|
25
|
+
| * * 4,5,7 1-11/2 * * | Every minute on the 4th, 5th and 7th of every 2nd month from January to November |
|
26
|
+
| * * L 1-11/2 * * | Every minute on the last day of every 2nd month from January to November |
|
27
|
+
| * * 17W 1-11/2 * * | Every minute on the weekday closest to the 17th of every 2nd month from January to November |
|
28
|
+
| * * * 3-7 * * | Every minute on every day of every month from March to July |
|
29
|
+
| * * 3-20/3 3-7 * * | Every minute on every 3rd day from the 3rd to the 20th of every month from March to July |
|
30
|
+
| * * 1-15 3-7 * * | Every minute on the 1st to the 15th of every month from March to July |
|
31
|
+
| * * */5 3-7 * * | Every minute on every 5th day of every month from March to July |
|
32
|
+
| * * 2/5 3-7 * * | Every minute on every 5th day starting on the 2nd of every month from March to July |
|
33
|
+
| * * 22 3-7 * * | Every minute on the 22nd of every month from March to July |
|
34
|
+
| * * 4,5,7 3-7 * * | Every minute on the 4th, 5th and 7th of every month from March to July |
|
35
|
+
| * * L 3-7 * * | Every minute on the last day of every month from March to July |
|
36
|
+
| * * 17W 3-7 * * | Every minute on the weekday closest to the 17th of every month from March to July |
|
37
|
+
| * * * */4 * * | Every minute on every day of every 4th month |
|
38
|
+
| * * 3-20/3 */4 * * | Every minute on every 3rd day from the 3rd to the 20th of every 4th month |
|
39
|
+
| * * 1-15 */4 * * | Every minute on the 1st to the 15th of every 4th month |
|
40
|
+
| * * */5 */4 * * | Every minute on every 5th day of every 4th month |
|
41
|
+
| * * 2/5 */4 * * | Every minute on every 5th day starting on the 2nd of every 4th month |
|
42
|
+
| * * 22 */4 * * | Every minute on the 22nd of every 4th month |
|
43
|
+
| * * 4,5,7 */4 * * | Every minute on the 4th, 5th and 7th of every 4th month |
|
44
|
+
| * * L */4 * * | Every minute on the last day of every 4th month |
|
45
|
+
| * * 17W */4 * * | Every minute on the weekday closest to the 17th of every 4th month |
|
46
|
+
| * * * 2/5 * * | Every minute on every day of every 5th month from February to December |
|
47
|
+
| * * 3-20/3 2/5 * * | Every minute on every 3rd day from the 3rd to the 20th of every 5th month from February to December |
|
48
|
+
| * * 1-15 2/5 * * | Every minute on the 1st to the 15th of every 5th month from February to December |
|
49
|
+
| * * */5 2/5 * * | Every minute on every 5th day of every 5th month from February to December |
|
50
|
+
| * * 2/5 2/5 * * | Every minute on every 5th day starting on the 2nd of every 5th month from February to December |
|
51
|
+
| * * 22 2/5 * * | Every minute on the 22nd of every 5th month from February to December |
|
52
|
+
| * * 4,5,7 2/5 * * | Every minute on the 4th, 5th and 7th of every 5th month from February to December |
|
53
|
+
| * * L 2/5 * * | Every minute on the last day of every 5th month from February to December |
|
54
|
+
| * * 17W 2/5 * * | Every minute on the weekday closest to the 17th of every 5th month from February to December |
|
55
|
+
| * * * 5 * * | Every minute on every day of May |
|
56
|
+
| * * 3-20/3 5 * * | Every minute on every 3rd day from the 3rd to the 20th of May |
|
57
|
+
| * * 1-15 5 * * | Every minute on the 1st to the 15th of May |
|
58
|
+
| * * */5 5 * * | Every minute on every 5th day of May |
|
59
|
+
| * * 2/5 5 * * | Every minute on every 5th day of May starting on the 2nd |
|
60
|
+
| * * 22 5 * * | Every minute on May 22nd |
|
61
|
+
| * * 4,5,7 5 * * | Every minute on May 4th, 5th and 7th |
|
62
|
+
| * * L 5 * * | Every minute on the last day of May |
|
63
|
+
| * * 17W 5 * * | Every minute on the weekday closest to May 17th |
|
64
|
+
| * * * APR,AUG * * | Every minute on every day of April and August |
|
65
|
+
| * * 3-20/3 apr,aug * * | Every minute on every 3rd day from the 3rd to the 20th of April and August |
|
66
|
+
| * * 1-15 APR,AUG * * | Every minute on the 1st to the 15th of April and August |
|
67
|
+
| * * */5 apr,aug * * | Every minute on every 5th day of April and August |
|
68
|
+
| * * 2/5 apr,aug * * | Every minute on every 5th day of April and August starting on the 2nd |
|
69
|
+
| * * 22 APR,AUG * * | Every minute on the 22nd of April and August |
|
70
|
+
| * * 4,5,7 apr,aug * * | Every minute on the 4th, 5th and 7th of April and August |
|
71
|
+
| * * L APR,AUG * * | Every minute on the last day of April and August |
|
72
|
+
| * * 17W APR,AUG * * | Every minute on the weekdays closest to April and August 17th |
|
73
|
+
| * * * * 1 * | Every minute on every Monday of every month |
|
74
|
+
| * * 3-20/3 * 1 * | Every minute on every 3rd day from the 3rd to the 20th and every Monday of every month |
|
75
|
+
| * * 1-15 * 1 * | Every minute on the 1st to the 15th and every Monday of every month |
|
76
|
+
| * * */5 * 1 * | Every minute on every 5th day and every Monday of every month |
|
77
|
+
| * * 2/5 * 1 * | Every minute on every 5th day starting on the 2nd and every Monday of every month |
|
78
|
+
| * * 22 * 1 * | Every minute on the 22nd and every Monday of every month |
|
79
|
+
| * * 4,5,7 * 1 * | Every minute on the 4th, 5th and 7th and every Monday of every month |
|
80
|
+
| * * L * 1 * | Every minute on the last day and every Monday of every month |
|
81
|
+
| * * 17W * 1 * | Every minute on the weekday closest to the 17th and every Monday of every month |
|
82
|
+
| * * * 1-11/2 1 * | Every minute on every Monday of every 2nd month from January to November |
|
83
|
+
| * * 3-20/3 1-11/2 1 * | Every minute on every 3rd day from the 3rd to the 20th and every Monday of every 2nd month from January to November |
|
84
|
+
| * * 1-15 1-11/2 1 * | Every minute on the 1st to the 15th and every Monday of every 2nd month from January to November |
|
85
|
+
| * * */5 1-11/2 1 * | Every minute on every 5th day and every Monday of every 2nd month from January to November |
|
86
|
+
| * * 2/5 1-11/2 1 * | Every minute on every 5th day starting on the 2nd and every Monday of every 2nd month from January to November |
|
87
|
+
| * * 22 1-11/2 1 * | Every minute on the 22nd and every Monday of every 2nd month from January to November |
|
88
|
+
| * * 4,5,7 1-11/2 1 * | Every minute on the 4th, 5th and 7th and every Monday of every 2nd month from January to November |
|
89
|
+
| * * L 1-11/2 1 * | Every minute on the last day and every Monday of every 2nd month from January to November |
|
90
|
+
| * * 17W 1-11/2 1 * | Every minute on the weekday closest to the 17th and every Monday of every 2nd month from January to November |
|
91
|
+
| * * * 5 1 * | Every minute on every Monday of May |
|
92
|
+
| * * 3-20/3 5 1 * | Every minute on every 3rd day from the 3rd to the 20th and every Monday of May |
|
93
|
+
| * * 1-15 5 1 * | Every minute on the 1st to the 15th and every Monday of May |
|
94
|
+
| * * */5 5 1 * | Every minute on every 5th day and every Monday of May |
|
95
|
+
| * * 2/5 5 1 * | Every minute on every 5th day starting on the 2nd and every Monday of May |
|
96
|
+
| * * 22 5 1 * | Every minute on May 22nd and every Monday in May |
|
97
|
+
| * * 4,5,7 5 1 * | Every minute on May 4th, 5th and 7th and every Monday in May |
|
98
|
+
| * * L 5 1 * | Every minute on the last day and every Monday of May |
|
99
|
+
| * * 17W 5 1 * | Every minute on the weekday closest to May 17th and every Monday in May |
|
100
|
+
| * * * APR,AUG 1 * | Every minute on every Monday of April and August |
|
101
|
+
| * * 3-20/3 apr,aug 1 * | Every minute on every 3rd day from the 3rd to the 20th and every Monday of April and August |
|
102
|
+
| * * 1-15 APR,AUG 1 * | Every minute on the 1st to the 15th and every Monday of April and August |
|
103
|
+
| * * */5 apr,aug 1 * | Every minute on every 5th day and every Monday of April and August |
|
104
|
+
| * * 2/5 apr,aug 1 * | Every minute on every 5th day starting on the 2nd and every Monday of April and August |
|
105
|
+
| * * 22 APR,AUG 1 * | Every minute on the 22nd and every Monday of April and August |
|
106
|
+
| * * 4,5,7 apr,aug 1 * | Every minute on the 4th, 5th and 7th and every Monday of April and August |
|
107
|
+
| * * L APR,AUG 1 * | Every minute on the last day and every Monday of April and August |
|
108
|
+
| * * 17W APR,AUG 1 * | Every minute on the weekdays closest to April and August 17th and every Monday in April and August |
|
109
|
+
| * * * * 2-4 * | Every minute on every Tuesday, Wednesday and Thursday of every month |
|
110
|
+
| * * 3-20/3 * 2-4 * | Every minute on every 3rd day from the 3rd to the 20th and every Tuesday, Wednesday and Thursday of every month |
|
111
|
+
| * * 1-15 * 2-4 * | Every minute on the 1st to the 15th and every Tuesday, Wednesday and Thursday of every month |
|
112
|
+
| * * */5 * 2-4 * | Every minute on every 5th day and every Tuesday, Wednesday and Thursday of every month |
|
113
|
+
| * * 2/5 * 2-4 * | Every minute on every 5th day starting on the 2nd and every Tuesday, Wednesday and Thursday of every month |
|
114
|
+
| * * 22 * 2-4 * | Every minute on the 22nd and every Tuesday, Wednesday and Thursday of every month |
|
115
|
+
| * * 4,5,7 * 2-4 * | Every minute on the 4th, 5th and 7th and every Tuesday, Wednesday and Thursday of every month |
|
116
|
+
| * * L * 2-4 * | Every minute on the last day and every Tuesday, Wednesday and Thursday of every month |
|
117
|
+
| * * 17W * 2-4 * | Every minute on the weekday closest to the 17th and every Tuesday, Wednesday and Thursday of every month |
|
118
|
+
| * * * 1-11/2 2-4 * | Every minute on every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
119
|
+
| * * 3-20/3 1-11/2 2-4 * | Every minute on every 3rd day from the 3rd to the 20th and every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
120
|
+
| * * 1-15 1-11/2 2-4 * | Every minute on the 1st to the 15th and every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
121
|
+
| * * */5 1-11/2 2-4 * | Every minute on every 5th day and every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
122
|
+
| * * 2/5 1-11/2 2-4 * | Every minute on every 5th day starting on the 2nd and every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
123
|
+
| * * 22 1-11/2 2-4 * | Every minute on the 22nd and every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
124
|
+
| * * 4,5,7 1-11/2 2-4 * | Every minute on the 4th, 5th and 7th and every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
125
|
+
| * * L 1-11/2 2-4 * | Every minute on the last day and every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
126
|
+
| * * 17W 1-11/2 2-4 * | Every minute on the weekday closest to the 17th and every Tuesday, Wednesday and Thursday of every 2nd month from January to November |
|
127
|
+
| * * * 5 2-4 * | Every minute on every Tuesday, Wednesday and Thursday of May |
|
128
|
+
| * * 3-20/3 5 2-4 * | Every minute on every 3rd day from the 3rd to the 20th and every Tuesday, Wednesday and Thursday of May |
|
129
|
+
| * * 1-15 5 2-4 * | Every minute on the 1st to the 15th and every Tuesday, Wednesday and Thursday of May |
|
130
|
+
| * * */5 5 2-4 * | Every minute on every 5th day and every Tuesday, Wednesday and Thursday of May |
|
131
|
+
| * * 2/5 5 2-4 * | Every minute on every 5th day starting on the 2nd and every Tuesday, Wednesday and Thursday of May |
|
132
|
+
| * * 22 5 2-4 * | Every minute on May 22nd and every Tuesday, Wednesday and Thursday in May |
|
133
|
+
| * * 4,5,7 5 2-4 * | Every minute on May 4th, 5th and 7th and every Tuesday, Wednesday and Thursday in May |
|
134
|
+
| * * L 5 2-4 * | Every minute on the last day and every Tuesday, Wednesday and Thursday of May |
|
135
|
+
| * * 17W 5 2-4 * | Every minute on the weekday closest to May 17th and every Tuesday, Wednesday and Thursday in May |
|
136
|
+
| * * * APR,AUG 2-4 * | Every minute on every Tuesday, Wednesday and Thursday of April and August |
|
137
|
+
| * * 3-20/3 apr,aug 2-4 * | Every minute on every 3rd day from the 3rd to the 20th and every Tuesday, Wednesday and Thursday of April and August |
|
138
|
+
| * * 1-15 APR,AUG 2-4 * | Every minute on the 1st to the 15th and every Tuesday, Wednesday and Thursday of April and August |
|
139
|
+
| * * */5 apr,aug 2-4 * | Every minute on every 5th day and every Tuesday, Wednesday and Thursday of April and August |
|
140
|
+
| * * 2/5 apr,aug 2-4 * | Every minute on every 5th day starting on the 2nd and every Tuesday, Wednesday and Thursday of April and August |
|
141
|
+
| * * 22 APR,AUG 2-4 * | Every minute on the 22nd and every Tuesday, Wednesday and Thursday of April and August |
|
142
|
+
| * * 4,5,7 apr,aug 2-4 * | Every minute on the 4th, 5th and 7th and every Tuesday, Wednesday and Thursday of April and August |
|
143
|
+
| * * L APR,AUG 2-4 * | Every minute on the last day and every Tuesday, Wednesday and Thursday of April and August |
|
144
|
+
| * * 17W APR,AUG 2-4 * | Every minute on the weekdays closest to April and August 17th and every Tuesday, Wednesday and Thursday in April and August |
|
145
|
+
| * * * * mon,wed,fri * | Every minute on every Monday, Wednesday and Friday of every month |
|
146
|
+
| * * 3-20/3 * MON,WED,FRI * | Every minute on every 3rd day from the 3rd to the 20th and every Monday, Wednesday and Friday of every month |
|
147
|
+
| * * 1-15 * MON,WED,FRI * | Every minute on the 1st to the 15th and every Monday, Wednesday and Friday of every month |
|
148
|
+
| * * */5 * MON,WED,FRI * | Every minute on every 5th day and every Monday, Wednesday and Friday of every month |
|
149
|
+
| * * 2/5 * MON,WED,FRI * | Every minute on every 5th day starting on the 2nd and every Monday, Wednesday and Friday of every month |
|
150
|
+
| * * 22 * MON,WED,FRI * | Every minute on the 22nd and every Monday, Wednesday and Friday of every month |
|
151
|
+
| * * 4,5,7 * MON,WED,FRI * | Every minute on the 4th, 5th and 7th and every Monday, Wednesday and Friday of every month |
|
152
|
+
| * * L * MON,WED,FRI * | Every minute on the last day and every Monday, Wednesday and Friday of every month |
|
153
|
+
| * * 17W * MON,WED,FRI * | Every minute on the weekday closest to the 17th and every Monday, Wednesday and Friday of every month |
|
154
|
+
| * * * 1-11/2 MON,WED,FRI * | Every minute on every Monday, Wednesday and Friday of every 2nd month from January to November |
|
155
|
+
| * * 3-20/3 1-11/2 MON,WED,FRI * | Every minute on every 3rd day from the 3rd to the 20th and every Monday, Wednesday and Friday of every 2nd month from January to November |
|
156
|
+
| * * 1-15 1-11/2 MON,WED,FRI * | Every minute on the 1st to the 15th and every Monday, Wednesday and Friday of every 2nd month from January to November |
|
157
|
+
| * * */5 1-11/2 MON,WED,FRI * | Every minute on every 5th day and every Monday, Wednesday and Friday of every 2nd month from January to November |
|
158
|
+
| * * 2/5 1-11/2 MON,WED,FRI * | Every minute on every 5th day starting on the 2nd and every Monday, Wednesday and Friday of every 2nd month from January to November |
|
159
|
+
| * * 22 1-11/2 MON,WED,FRI * | Every minute on the 22nd and every Monday, Wednesday and Friday of every 2nd month from January to November |
|
160
|
+
| * * 4,5,7 1-11/2 MON,WED,FRI * | Every minute on the 4th, 5th and 7th and every Monday, Wednesday and Friday of every 2nd month from January to November |
|
161
|
+
| * * L 1-11/2 MON,WED,FRI * | Every minute on the last day and every Monday, Wednesday and Friday of every 2nd month from January to November |
|
162
|
+
| * * 17W 1-11/2 MON,WED,FRI * | Every minute on the weekday closest to the 17th and every Monday, Wednesday and Friday of every 2nd month from January to November |
|
163
|
+
| * * * 5 MON,WED,FRI * | Every minute on every Monday, Wednesday and Friday of May |
|
164
|
+
| * * 3-20/3 5 MON,WED,FRI * | Every minute on every 3rd day from the 3rd to the 20th and every Monday, Wednesday and Friday of May |
|
165
|
+
| * * 1-15 5 MON,WED,FRI * | Every minute on the 1st to the 15th and every Monday, Wednesday and Friday of May |
|
166
|
+
| * * 2/5 5 MON,WED,FRI * | Every minute on every 5th day starting on the 2nd and every Monday, Wednesday and Friday of May |
|
167
|
+
| * * 22 5 MON,WED,FRI * | Every minute on May 22nd and every Monday, Wednesday and Friday in May |
|
168
|
+
| * * 4,5,7 5 MON,WED,FRI * | Every minute on May 4th, 5th and 7th and every Monday, Wednesday and Friday in May |
|
169
|
+
| * * L 5 MON,WED,FRI * | Every minute on the last day and every Monday, Wednesday and Friday of May |
|
170
|
+
| * * 17W 5 MON,WED,FRI * | Every minute on the weekday closest to May 17th and every Monday, Wednesday and Friday in May |
|
171
|
+
| * * * APR,AUG MON,WED,FRI * | Every minute on every Monday, Wednesday and Friday of April and August |
|
172
|
+
| * * 3-20/3 apr,aug MON,WED,FRI * | Every minute on every 3rd day from the 3rd to the 20th and every Monday, Wednesday and Friday of April and August |
|
173
|
+
| * * 1-15 APR,AUG MON,WED,FRI * | Every minute on the 1st to the 15th and every Monday, Wednesday and Friday of April and August |
|
174
|
+
| * * */5 apr,aug MON,WED,FRI * | Every minute on every 5th day and every Monday, Wednesday and Friday of April and August |
|
175
|
+
| * * 2/5 apr,aug MON,WED,FRI * | Every minute on every 5th day starting on the 2nd and every Monday, Wednesday and Friday of April and August |
|
176
|
+
| * * 22 APR,AUG MON,WED,FRI * | Every minute on the 22nd and every Monday, Wednesday and Friday of April and August |
|
177
|
+
| * * 4,5,7 apr,aug MON,WED,FRI * | Every minute on the 4th, 5th and 7th and every Monday, Wednesday and Friday of April and August |
|
178
|
+
| * * L APR,AUG MON,WED,FRI * | Every minute on the last day and every Monday, Wednesday and Friday of April and August |
|
179
|
+
| * * 17W APR,AUG MON,WED,FRI * | Every minute on the weekdays closest to April and August 17th and every Monday, Wednesday and Friday in April and August |
|
180
|
+
| * * * * 6l * | Every minute on the last Saturday of every month |
|
181
|
+
| * * 3-20/3 * 6L * | Every minute on every 3rd day from the 3rd to the 20th and the last Saturday of every month |
|
182
|
+
| * * 1-15 * 6L * | Every minute on the 1st to the 15th and the last Saturday of every month |
|
183
|
+
| * * */5 * 6L * | Every minute on every 5th day and the last Saturday of every month |
|
184
|
+
| * * 2/5 * 6L * | Every minute on every 5th day starting on the 2nd and the last Saturday of every month |
|
185
|
+
| * * 22 * 6L * | Every minute on the 22nd and the last Saturday of every month |
|
186
|
+
| * * 4,5,7 * 6L * | Every minute on the 4th, 5th and 7th and the last Saturday of every month |
|
187
|
+
| * * L * 6L * | Every minute on the last day and the last Saturday of every month |
|
188
|
+
| * * 17W * 6L * | Every minute on the weekday closest to the 17th and the last Saturday of every month |
|
189
|
+
| * * * 1-11/2 6L * | Every minute on the last Saturday of every 2nd month from January to November |
|
190
|
+
| * * 3-20/3 1-11/2 6L * | Every minute on every 3rd day from the 3rd to the 20th and the last Saturday of every 2nd month from January to November |
|
191
|
+
| * * 1-15 1-11/2 6L * | Every minute on the 1st to the 15th and the last Saturday of every 2nd month from January to November |
|
192
|
+
| * * */5 1-11/2 6L * | Every minute on every 5th day and the last Saturday of every 2nd month from January to November |
|
193
|
+
| * * 2/5 1-11/2 6L * | Every minute on every 5th day starting on the 2nd and the last Saturday of every 2nd month from January to November |
|
194
|
+
| * * 22 1-11/2 6L * | Every minute on the 22nd and the last Saturday of every 2nd month from January to November |
|
195
|
+
| * * 4,5,7 1-11/2 6L * | Every minute on the 4th, 5th and 7th and the last Saturday of every 2nd month from January to November |
|
196
|
+
| * * L 1-11/2 6L * | Every minute on the last day and the last Saturday of every 2nd month from January to November |
|
197
|
+
| * * 17W 1-11/2 6L * | Every minute on the weekday closest to the 17th and the last Saturday of every 2nd month from January to November |
|
198
|
+
| * * * 5 6L * | Every minute on the last Saturday of May |
|
199
|
+
| * * 3-20/3 5 6L * | Every minute on every 3rd day from the 3rd to the 20th and the last Saturday of May |
|
200
|
+
| * * 1-15 5 6L * | Every minute on the 1st to the 15th and the last Saturday of May |
|
201
|
+
| * * */5 5 6L * | Every minute on every 5th day and the last Saturday of May |
|
202
|
+
| * * 2/5 5 6L * | Every minute on every 5th day starting on the 2nd and the last Saturday of May |
|
203
|
+
| * * 22 5 6L * | Every minute on May 22nd and the last Saturday in May |
|
204
|
+
| * * 4,5,7 5 6L * | Every minute on May 4th, 5th and 7th and the last Saturday in May |
|
205
|
+
| * * L 5 6L * | Every minute on the last day and the last Saturday of May |
|
206
|
+
| * * 17W 5 6L * | Every minute on the weekday closest to May 17th and the last Saturday in May |
|
207
|
+
| * * * APR,AUG 6L * | Every minute on the last Saturday of April and August |
|
208
|
+
| * * 3-20/3 apr,aug 6L * | Every minute on every 3rd day from the 3rd to the 20th and the last Saturday of April and August |
|
209
|
+
| * * 1-15 APR,AUG 6L * | Every minute on the 1st to the 15th and the last Saturday of April and August |
|
210
|
+
| * * */5 apr,aug 6L * | Every minute on every 5th day and the last Saturday of April and August |
|
211
|
+
| * * 2/5 apr,aug 6L * | Every minute on every 5th day starting on the 2nd and the last Saturday of April and August |
|
212
|
+
| * * 22 APR,AUG 6L * | Every minute on the 22nd and the last Saturday of April and August |
|
213
|
+
| * * 4,5,7 apr,aug 6L * | Every minute on the 4th, 5th and 7th and the last Saturday of April and August |
|
214
|
+
| * * L APR,AUG satL * | Every minute on the last day and the last Saturday of April and August |
|
215
|
+
| * * 17W APR,AUG SATL * | Every minute on the weekdays closest to April and August 17th and the last Saturday in April and August |
|
216
|
+
| * * * * THU#4 * | Every minute on the 4th Thursday of every month |
|
217
|
+
| * * 3-20/3 * THU#4 * | Every minute on every 3rd day from the 3rd to the 20th and the 4th Thursday of every month |
|
218
|
+
| * * 1-15 * THU#4 * | Every minute on the 1st to the 15th and the 4th Thursday of every month |
|
219
|
+
| * * */5 * THU#4 * | Every minute on every 5th day and the 4th Thursday of every month |
|
220
|
+
| * * 2/5 * THU#4 * | Every minute on every 5th day starting on the 2nd and the 4th Thursday of every month |
|
221
|
+
| * * 22 * THU#4 * | Every minute on the 22nd and the 4th Thursday of every month |
|
222
|
+
| * * 4,5,7 * THU#4 * | Every minute on the 4th, 5th and 7th and the 4th Thursday of every month |
|
223
|
+
| * * L * THU#4 * | Every minute on the last day and the 4th Thursday of every month |
|
224
|
+
| * * 17W * THU#4 * | Every minute on the weekday closest to the 17th and the 4th Thursday of every month |
|
225
|
+
| * * * 1-11/2 THU#4 * | Every minute on the 4th Thursday of every 2nd month from January to November |
|
226
|
+
| * * 3-20/3 1-11/2 THU#4 * | Every minute on every 3rd day from the 3rd to the 20th and the 4th Thursday of every 2nd month from January to November |
|
227
|
+
| * * 1-15 1-11/2 THU#4 * | Every minute on the 1st to the 15th and the 4th Thursday of every 2nd month from January to November |
|
228
|
+
| * * */5 1-11/2 THU#4 * | Every minute on every 5th day and the 4th Thursday of every 2nd month from January to November |
|
229
|
+
| * * 2/5 1-11/2 THU#4 * | Every minute on every 5th day starting on the 2nd and the 4th Thursday of every 2nd month from January to November |
|
230
|
+
| * * 22 1-11/2 THU#4 * | Every minute on the 22nd and the 4th Thursday of every 2nd month from January to November |
|
231
|
+
| * * 4,5,7 1-11/2 THU#4 * | Every minute on the 4th, 5th and 7th and the 4th Thursday of every 2nd month from January to November |
|
232
|
+
| * * L 1-11/2 THU#4 * | Every minute on the last day and the 4th Thursday of every 2nd month from January to November |
|
233
|
+
| * * 17W 1-11/2 THU#4 * | Every minute on the weekday closest to the 17th and the 4th Thursday of every 2nd month from January to November |
|
234
|
+
| * * * 5 THU#4 * | Every minute on the 4th Thursday of May |
|
235
|
+
| * * 3-20/3 5 THU#4 * | Every minute on every 3rd day from the 3rd to the 20th and the 4th Thursday of May |
|
236
|
+
| * * 1-15 5 THU#4 * | Every minute on the 1st to the 15th and the 4th Thursday of May |
|
237
|
+
| * * */5 5 THU#4 * | Every minute on every 5th day and the 4th Thursday of May |
|
238
|
+
| * * 2/5 5 THU#4 * | Every minute on every 5th day starting on the 2nd and the 4th Thursday of May |
|
239
|
+
| * * 22 5 THU#4 * | Every minute on May 22nd and the 4th Thursday in May |
|
240
|
+
| * * 4,5,7 5 THU#4 * | Every minute on May 4th, 5th and 7th and the 4th Thursday in May |
|
241
|
+
| * * L 5 THU#4 * | Every minute on the last day and the 4th Thursday of May |
|
242
|
+
| * * 17W 5 THU#4 * | Every minute on the weekday closest to May 17th and the 4th Thursday in May |
|
243
|
+
| * * * APR,AUG THU#4 * | Every minute on the 4th Thursday of April and August |
|
244
|
+
| * * 3-20/3 apr,aug THU#4 * | Every minute on every 3rd day from the 3rd to the 20th and the 4th Thursday of April and August |
|
245
|
+
| * * 1-15 APR,AUG THU#4 * | Every minute on the 1st to the 15th and the 4th Thursday of April and August |
|
246
|
+
| * * */5 apr,aug THU#4 * | Every minute on every 5th day and the 4th Thursday of April and August |
|
247
|
+
| * * 2/5 apr,aug THU#4 * | Every minute on every 5th day starting on the 2nd and the 4th Thursday of April and August |
|
248
|
+
| * * 22 APR,AUG THU#4 * | Every minute on the 22nd and the 4th Thursday of April and August |
|
249
|
+
| * * 4,5,7 apr,aug THU#4 * | Every minute on the 4th, 5th and 7th and the 4th Thursday of April and August |
|
250
|
+
| * * L APR,AUG thu#4 * | Every minute on the last day and the 4th Thursday of April and August |
|
251
|
+
| * * 17W APR,AUG thu#4 * | Every minute on the weekdays closest to April and August 17th and the 4th Thursday in April and August |
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Feature: Parsing a cron expression
|
2
|
+
In order to give anyone who doesn't have cron format 100% down cold
|
3
|
+
a way to check that they've got the correct expression
|
4
|
+
|
5
|
+
Scenario Outline: Parsing cron expressions
|
6
|
+
When I parse the expression "<cron_expression>"
|
7
|
+
Then I return "<human_readable>"
|
8
|
+
|
9
|
+
Examples:
|
10
|
+
| cron_expression | human_readable |
|
11
|
+
| sudo rm -r -f * | Invalid Format |
|
12
|
+
| * | Invalid Format |
|
13
|
+
| * * | Invalid Format |
|
14
|
+
| * * * | Invalid Format |
|
15
|
+
| * * * * | Invalid Format |
|
16
|
+
| 3 4 22 5 * * | 04:03 on May 22nd |
|
17
|
+
| 3 4 22 5 * 1985 | 04:03 on May 22nd, 1985 |
|
18
|
+
| 3 4 22 5 * 1985,1989 | 04:03 on May 22nd in 1985 and 1989 |
|
19
|
+
| 3 4 22 5 * 1990-2000/2 | 04:03 on May 22nd every 2 years between 1990 and 2000 |
|
20
|
+
| 3 4 22 5 * 2013/3 | 04:03 on May 22nd every 3 years starting in 2013 |
|
21
|
+
| 3 4 22 5 * */4 | 04:03 on May 22nd every 4 years |
|
22
|
+
| 3 4 22 5 * 1985-2000 | 04:03 on May 22nd every year between 1985 and 2000 |
|
@@ -0,0 +1,61 @@
|
|
1
|
+
Feature: Parsing a cron expression
|
2
|
+
In order to give anyone who doesn't have cron format 100% down cold
|
3
|
+
a way to check that they've got the correct expression
|
4
|
+
|
5
|
+
Scenario Outline: Parsing cron expressions
|
6
|
+
When I parse the expression "<cron_expression>"
|
7
|
+
Then I return "<human_readable>"
|
8
|
+
|
9
|
+
Examples:
|
10
|
+
| cron_expression | human_readable |
|
11
|
+
| * * * * * | Every minute every day |
|
12
|
+
| * * * * * * | Every minute every day |
|
13
|
+
| * 8-20/3 * * * * | Every minute of every 3rd hour between 08:00 and 20:59 every day |
|
14
|
+
| * 9-19 * * * * | Every minute between 09:00 and 19:59 every day |
|
15
|
+
| * */4 * * * * | Every minute of every 4th hour every day |
|
16
|
+
| * 1/6 * * * * | Every minute of every 6th hour starting at 01:00 every day |
|
17
|
+
| * 5 * * * * | Every minute between 05:00 and 05:59 every day |
|
18
|
+
| * 5,10,15 * * * * | Every minute between 05:00 and 05:59, 10:00 and 10:59 and 15:00 and 15:59 every day |
|
19
|
+
| 0 * * * * | The beginning of every hour every day |
|
20
|
+
| 8 * * * * * | The 8th minute of every hour every day |
|
21
|
+
| 8 8-20/3 * * * * | The 8th minute of every 3rd hour between 08:00 and 20:59 every day |
|
22
|
+
| 8 9-19 * * * * | The 8th minute of every hour between 09:00 and 19:59 every day |
|
23
|
+
| 8 */4 * * * * | The 8th minute of every 4th hour every day |
|
24
|
+
| 8 1/6 * * * * | The 8th minute of every 6th hour starting at 01:00 every day |
|
25
|
+
| 8 5 * * * * | 05:08 every day |
|
26
|
+
| 8 5,10,15 * * * * | 05:08, 10:08 and 15:08 every day |
|
27
|
+
| 2,21,33,44 * * * * * | The 2nd, 21st, 33rd and 44th minutes of every hour every day |
|
28
|
+
| 2,21,33,44 8-20/3 * * * * | The 2nd, 21st, 33rd and 44th minutes of every 3rd hour between 08:00 and 20:59 every day |
|
29
|
+
| 2,21,33,44 9-19 * * * * | The 2nd, 21st, 33rd and 44th minutes of every hour between 09:00 and 19:59 every day |
|
30
|
+
| 2,21,33,44 */4 * * * * | The 2nd, 21st, 33rd and 44th minutes of every 4th hour every day |
|
31
|
+
| 2,21,33,44 1/6 * * * * | The 2nd, 21st, 33rd and 44th minutes of every 6th hour starting at 01:00 every day |
|
32
|
+
| 2,21,33,44 5 * * * * | 05:02, 05:21, 05:33 and 05:44 every day |
|
33
|
+
| 2,21,33,44 5,10,15 * * * * | 05:02, 05:21, 05:33, 05:44, 10:02, 10:21, 10:33, 10:44, 15:02, 15:21, 15:33 and 15:44 every day |
|
34
|
+
| */2 * * * * * | Every 2 minutes every day |
|
35
|
+
| */2 8-20/3 * * * * | Every 2 minutes of every 3rd hour between 08:00 and 20:59 every day |
|
36
|
+
| */2 9-19 * * * * | Every 2 minutes between 09:00 and 19:59 every day |
|
37
|
+
| */2 */4 * * * * | Every 2 minutes of every 4th hour every day |
|
38
|
+
| */2 1/6 * * * * | Every 2 minutes of every 6th hour starting at 01:00 every day |
|
39
|
+
| */2 5 * * * * | Every 2 minutes between 05:00 and 05:59 every day |
|
40
|
+
| */2 5,10,15 * * * * | Every 2 minutes between 05:00 and 05:59, 10:00 and 10:59 and 15:00 and 15:59 every day |
|
41
|
+
| 3/4 * * * * * | Every 4 minutes starting at xx:03 of every hour every day |
|
42
|
+
| 3/4 8-20/3 * * * * | Every 4 minutes starting at xx:03 of every 3rd hour between 08:00 and 20:59 every day |
|
43
|
+
| 3/4 9-19 * * * * | Every 4 minutes starting at xx:03 of every hour between 09:00 and 19:59 every day |
|
44
|
+
| 3/4 */4 * * * * | Every 4 minutes starting at xx:03 of every 4th hour every day |
|
45
|
+
| 3/4 1/6 * * * * | Every 4 minutes starting at xx:03 of every 6th hour starting at 01:00 every day |
|
46
|
+
| 3/4 5 * * * * | Every 4 minutes between 05:03 and 05:59 every day |
|
47
|
+
| 3/4 5,10,15 * * * * | Every 4 minutes between 05:03 and 05:59, 10:03 and 10:59 and 15:03 and 15:59 every day |
|
48
|
+
| 11-13 * * * * * | Every hour from xx:11 to xx:13 every day |
|
49
|
+
| 11-13 8-20/3 * * * * | Every minute between xx:11 and xx:13 of every 3rd hour between 08:00 and 20:59 every day |
|
50
|
+
| 11-13 9-19 * * * * | Every minute between xx:11 and xx:13 of every hour between 09:00 and 19:59 every day |
|
51
|
+
| 11-13 */4 * * * * | Every minute between xx:11 and xx:13 of every 4th hour every day |
|
52
|
+
| 11-13 1/6 * * * * | Every minute between xx:11 and xx:13 of every 6th hour starting at 01:00 every day |
|
53
|
+
| 11-13 5 * * * * | Every minute between 05:11 and 05:13 every day |
|
54
|
+
| 11-13 5,10,15 * * * * | Every minute between 05:11 and 05:13, 10:11 and 10:13 and 15:11 and 15:13 every day |
|
55
|
+
| 10-18/2 * * * * * | Every 2 minutes between xx:10 and xx:18 of every hour every day |
|
56
|
+
| 10-18/2 8-20/3 * * * * | Every 2 minutes between xx:10 and xx:18 of every 3rd hour between 08:00 and 20:59 every day |
|
57
|
+
| 10-18/2 9-19 * * * * | Every 2 minutes between xx:10 and xx:18 of every hour between 09:00 and 19:59 every day |
|
58
|
+
| 10-18/2 */4 * * * * | Every 2 minutes between xx:10 and xx:18 of every 4th hour every day |
|
59
|
+
| 10-18/2 1/6 * * * * | Every 2 minutes between xx:10 and xx:18 of every 6th hour starting at 01:00 every day |
|
60
|
+
| 10-18/2 5 * * * * | Every 2 minutes between 05:10 and 05:18 every day |
|
61
|
+
| 10-18/2 5,10,15 * * * * | Every 2 minutes between 05:10 and 05:18, 10:10 and 10:18 and 15:10 and 15:18 every day |
|
data/lib/crony.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'utility_functions'
|
2
|
+
require 'crony/parser'
|
3
|
+
Dir['./lib/crony/**/*.rb'].each {|file| require file}
|
4
|
+
|
5
|
+
module Crony
|
6
|
+
def self.parse(expression)
|
7
|
+
return 'Invalid Format' if expression.split(/\s+/).size < 5
|
8
|
+
|
9
|
+
@minute, @hour, @day, @month, @weekday, @year = expression.split(/\s+/)
|
10
|
+
return 'Invalid Format' unless valid?
|
11
|
+
|
12
|
+
time = TimePresenter.parse(@minute, @hour)
|
13
|
+
day = DayPresenter.parse(@day, @month, @weekday)
|
14
|
+
year = !!@year ? YearPresenter.parse(@year) : ''
|
15
|
+
result = "#{time} #{day} #{year}".strip.squeeze(' ').gsub(/ ,/, ',')
|
16
|
+
result.sub(/^(.)/) { $1 == 'x' ? $1 : $1.upcase}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.valid?
|
20
|
+
@minute =~ /^[\*\/,\-\d]+$/ &&
|
21
|
+
@hour =~ /^[\*\/,\-\d]+$/ &&
|
22
|
+
@day =~ /^[\*\/,\-\?LW\d]+$/ &&
|
23
|
+
@month =~ /^[\*\/,\-\djanfebmrpyjulgsoctv]+$/i &&
|
24
|
+
@weekday =~ /^[\*\/,\-\?\dsunmotewdhfriaL#]+$/i &&
|
25
|
+
(@year.nil? || @year =~ /^[\*\/,\-\d]*$/)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Crony
|
4
|
+
class CronStruct < OpenStruct
|
5
|
+
def every?; !!every; end
|
6
|
+
def frequency?; !!frequency; end
|
7
|
+
def range?; !!start && !!stop; end
|
8
|
+
def unbounded_range?; !!start; end
|
9
|
+
def collection?; !!collection; end
|
10
|
+
def single_element?; collection? && collection.size == 1; end
|
11
|
+
|
12
|
+
def single_element; collection[0]; end
|
13
|
+
|
14
|
+
def sym
|
15
|
+
return "e" if every?
|
16
|
+
return "f" if frequency? && range?
|
17
|
+
return "u" if frequency? && unbounded_range?
|
18
|
+
return "v" if frequency?
|
19
|
+
return "r" if range?
|
20
|
+
return "s" if single_element?
|
21
|
+
return "c" if collection?
|
22
|
+
end
|
23
|
+
|
24
|
+
def format(*args)
|
25
|
+
send sym, *args
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Crony
|
2
|
+
module Formatters
|
3
|
+
class DayOfMonthFormatter < CronStruct
|
4
|
+
def ordinal; self.single_element.ordinal; end
|
5
|
+
|
6
|
+
def range
|
7
|
+
"the #{self.start.ordinal} to the #{self.stop.ordinal}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def sym
|
11
|
+
return 'w' if !!nearest
|
12
|
+
return 'l' if !!last
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def c(lead_in=true)
|
17
|
+
"#{"on the " if lead_in}#{collection.map(&:ordinal).to_sentence}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def e
|
21
|
+
"on every day"
|
22
|
+
end
|
23
|
+
|
24
|
+
def f
|
25
|
+
"#{v} from #{range}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def l
|
29
|
+
"on the last day"
|
30
|
+
end
|
31
|
+
|
32
|
+
def r
|
33
|
+
"on #{range}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def s(lead_in=true)
|
37
|
+
"#{"on the " if lead_in}#{ordinal}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def u
|
41
|
+
"#{v} starting on the #{start.ordinal}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def v
|
45
|
+
"on every #{frequency.ordinal} day"
|
46
|
+
end
|
47
|
+
|
48
|
+
def w
|
49
|
+
"on the weekday closest to the #{ordinal}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Crony
|
2
|
+
module Formatters
|
3
|
+
class DayOfWeekFormatter < CronStruct
|
4
|
+
DAYS = %w{ Sunday Monday Tuesday Wednesday Thursday Friday Saturday }
|
5
|
+
CRON_DAYS = %w{ sun mon tue wed thu fri sat }
|
6
|
+
|
7
|
+
def sym
|
8
|
+
return 'l' if !!last
|
9
|
+
return 'n' if !!nth_week
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_weekday(day)
|
14
|
+
if day =~ /[a-z]/i
|
15
|
+
DAYS[CRON_DAYS.index(day.downcase)]
|
16
|
+
else
|
17
|
+
DAYS[day.to_i]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def c(weekdays=collection)
|
22
|
+
"every #{weekdays.map{|weekday| get_weekday(weekday)}.to_sentence}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def e
|
26
|
+
""
|
27
|
+
end
|
28
|
+
|
29
|
+
def l
|
30
|
+
"the last #{get_weekday(single_element)}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def n
|
34
|
+
"the #{nth_week.ordinal} #{get_weekday(single_element)}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def r
|
38
|
+
c(Array(start.to_i..stop.to_i))
|
39
|
+
end
|
40
|
+
|
41
|
+
def s
|
42
|
+
"every #{get_weekday(single_element)}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Crony
|
2
|
+
module Formatters
|
3
|
+
class HourFormatter < CronStruct
|
4
|
+
def c
|
5
|
+
collection.map{|hour| "#{hour.two_digits}:00 and #{hour.two_digits}:59" }.to_sentence
|
6
|
+
end
|
7
|
+
|
8
|
+
def e
|
9
|
+
'every hour'
|
10
|
+
end
|
11
|
+
|
12
|
+
def f
|
13
|
+
"#{v} between #{r}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def r
|
17
|
+
"#{start.two_digits}:00 and #{stop.two_digits}:59"
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :s :c
|
21
|
+
|
22
|
+
def u
|
23
|
+
"#{v} starting at #{start.two_digits}:00"
|
24
|
+
end
|
25
|
+
|
26
|
+
def v
|
27
|
+
"every #{frequency.ordinal} hour"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Crony
|
2
|
+
module Formatters
|
3
|
+
class MinuteFormatter < CronStruct
|
4
|
+
def c
|
5
|
+
"the #{collection.map{|minute| minute.ordinal}.to_sentence} minutes"
|
6
|
+
end
|
7
|
+
|
8
|
+
def e
|
9
|
+
'every minute'
|
10
|
+
end
|
11
|
+
|
12
|
+
def f(hours=nil)
|
13
|
+
hours ||= ['xx']
|
14
|
+
"#{v} between #{hours.map(&:two_digits).map{|hour| "#{hour}:#{start.two_digits} and #{hour}:#{stop.two_digits}"}.to_sentence}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def r(hours=nil)
|
18
|
+
hours ||= ['xx']
|
19
|
+
"every minute between #{hours.map(&:two_digits).map{|hour| "#{hour}:#{start.two_digits} and #{hour}:#{stop.two_digits}"}.to_sentence}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def s
|
23
|
+
"the #{single_element.to_i == 0 ? "beginning" : "#{single_element.ordinal} minute"}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def u(starting_at=true)
|
27
|
+
starting_at ? "#{v} starting at xx:#{start.two_digits}" : v
|
28
|
+
end
|
29
|
+
|
30
|
+
def v
|
31
|
+
"every #{frequency} minutes"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Crony
|
2
|
+
module Formatters
|
3
|
+
class MonthFormatter < CronStruct
|
4
|
+
MONTHS = %w{ January February March April May June July August September October November December }
|
5
|
+
CRON_MONTHS = %w{ jan feb mar apr may jun jul aug sep oct nov dec }
|
6
|
+
|
7
|
+
def get_month(month)
|
8
|
+
if month =~ /[a-z]/i
|
9
|
+
MONTHS[CRON_MONTHS.index(month.downcase)]
|
10
|
+
else
|
11
|
+
MONTHS[month.to_i - 1]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def range
|
16
|
+
"from #{s(start)} to #{s(stop)}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def c
|
20
|
+
collection.map{|month| get_month(month)}.to_sentence
|
21
|
+
end
|
22
|
+
|
23
|
+
def e
|
24
|
+
"every month"
|
25
|
+
end
|
26
|
+
|
27
|
+
def f
|
28
|
+
"every #{frequency.ordinal} month #{range}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def r
|
32
|
+
"every month #{range}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def s(month=single_element)
|
36
|
+
get_month(month)
|
37
|
+
end
|
38
|
+
|
39
|
+
alias :u :f
|
40
|
+
|
41
|
+
def v
|
42
|
+
"every #{frequency.ordinal} month"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Crony
|
2
|
+
module Formatters
|
3
|
+
class YearFormatter < CronStruct
|
4
|
+
def c
|
5
|
+
"in #{collection.to_sentence}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def e
|
9
|
+
''
|
10
|
+
end
|
11
|
+
|
12
|
+
def f
|
13
|
+
"#{v} between #{start} and #{stop}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def r
|
17
|
+
"every year between #{start} and #{stop}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def s
|
21
|
+
", #{single_element}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def u
|
25
|
+
"#{v} starting in #{start}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def v
|
29
|
+
"every #{frequency} years"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/crony/parser.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Crony
|
2
|
+
class Parser
|
3
|
+
def self.parse(element)
|
4
|
+
@element = element
|
5
|
+
case @element
|
6
|
+
when '*' then { every: true }
|
7
|
+
when /^l$/i then { last: true }
|
8
|
+
when /(\d|\w{3})l$/i
|
9
|
+
@element = @element.sub(/l$/i, '')
|
10
|
+
{ last: true, collection: parse_collection }
|
11
|
+
when /.*#\d$/
|
12
|
+
@element, nth_week = @element.scan(/(.*)#(\d)$/)[0]
|
13
|
+
{ nth_week: nth_week, collection: parse_collection }
|
14
|
+
when /\d+w$/i
|
15
|
+
@element = @element.sub(/w$/i, '')
|
16
|
+
{ nearest: true, collection: parse_collection }
|
17
|
+
when /\//
|
18
|
+
start, frequency = @element.scan(/(.*)\/(.*)/)[0]
|
19
|
+
case start
|
20
|
+
when '*'
|
21
|
+
{ frequency: frequency }
|
22
|
+
when /^\d+$/ #single number
|
23
|
+
{ frequency: frequency, start: start }
|
24
|
+
when /^\d+-\d+$/
|
25
|
+
range_start, range_end = *start.scan(/(\d+)-(\d+)/)[0]
|
26
|
+
{ frequency: frequency, start: range_start, stop: range_end }
|
27
|
+
end
|
28
|
+
when /^\d+-\d+$/
|
29
|
+
range_start, range_end = *@element.scan(/(\d+)-(\d+)/)[0]
|
30
|
+
{ start: range_start, stop: range_end }
|
31
|
+
else { collection: parse_collection }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.parse_collection
|
36
|
+
parts = @element.split(',')
|
37
|
+
res = []
|
38
|
+
parts.each do |part|
|
39
|
+
if part =~ /\-/
|
40
|
+
range = part.scan(/(\d+)-(\d+)/)[0]
|
41
|
+
res += Array(range[0].to_i..range[1].to_i)
|
42
|
+
else
|
43
|
+
res << part
|
44
|
+
end
|
45
|
+
end
|
46
|
+
res
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Crony
|
2
|
+
class DayPresenter
|
3
|
+
def self.parse(day, month, weekday)
|
4
|
+
day = Formatters::DayOfMonthFormatter.new(Parser.parse(day))
|
5
|
+
month = Formatters::MonthFormatter.new(Parser.parse(month))
|
6
|
+
weekday = Formatters::DayOfWeekFormatter.new(Parser.parse(weekday))
|
7
|
+
|
8
|
+
case [day, month, weekday].map(&:sym).join('')
|
9
|
+
when 'eee' then 'every day'
|
10
|
+
# 'on May 22nd,' not 'on the 22nd of May'
|
11
|
+
when /^[sc]s.$/ then "on #{month.s} #{day.format(false)} #{"and #{weekday.format} in #{month.format}" unless weekday.sym == 'e'}"
|
12
|
+
# 'on the weekday(s) closest to May 22nd,' not 'on the weekday(s) closest to the 22nd of May'
|
13
|
+
when /^w[cs].$/ then "on the weekday#{"s" if month.sym == 'c'} closest to #{month.format} #{day.s(false)} #{"and #{weekday.format} in #{month.format}" unless weekday.sym == 'e'}"
|
14
|
+
when /^u[cs]e$/ then "#{day.v} of #{month.format} starting on the #{day.start.ordinal}"
|
15
|
+
when /^e.[^e]$/ then ("on %s of %s" % [weekday.format, month.format]).squeeze(' ')
|
16
|
+
when /^..e$/ then ("%s of %s" % [day.format, month.format]).squeeze(' ')
|
17
|
+
else ("%s and %s of %s" % [day.format, weekday.format, month.format]).squeeze(' ')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Crony
|
2
|
+
module TimePresenter
|
3
|
+
def self.parse(minute, hour)
|
4
|
+
minute = Formatters::MinuteFormatter.new(Parser.parse(minute))
|
5
|
+
hour = Formatters::HourFormatter.new(Parser.parse(hour))
|
6
|
+
|
7
|
+
case [minute, hour].map(&:sym).join('')
|
8
|
+
when /[ev]e/ then minute.format
|
9
|
+
when 're' then "every hour from xx:#{minute.start.two_digits} to xx:#{minute.stop.two_digits}"
|
10
|
+
when 'ss' then "#{time(hour.single_element, minute.single_element)}"
|
11
|
+
when 'sc' then "#{hour.collection.map{|hour| time(hour, minute.single_element)}.to_sentence}"
|
12
|
+
when 'us' then "#{minute.format(false)} between #{time_range(hour.single_element, minute.start, hour.single_element, 59)}"
|
13
|
+
when 'uc' then "#{minute.format(false)} between #{hour.collection.map{|hour| time_range(hour, minute.start, hour, 59)}.to_sentence}"
|
14
|
+
when /c[cs]/ then "#{hour.collection.map{|hour| minute.collection.map{|minute| time(hour, minute)}}.flatten.to_sentence}"
|
15
|
+
when /[ucsfr]r/ then ("%s of every hour between %s" % [minute.format, hour.format]).squeeze(' ')
|
16
|
+
when /^[fr][cs]$/ then "#{minute.format(hour.collection)}"
|
17
|
+
when /^.[rsc]$/ then ("%s between %s" % [minute.format, hour.format]).squeeze(' ')
|
18
|
+
else ("%s of %s" % [minute.format, hour.format]).squeeze(' ')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.time(hour, minute)
|
23
|
+
[hour, minute].map(&:two_digits).join(':')
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.time_range(s_hour, s_minute, e_hour, e_minute)
|
27
|
+
"#{time(s_hour, s_minute)} and #{time(e_hour, e_minute)}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Array
|
2
|
+
def to_sentence
|
3
|
+
case self.size
|
4
|
+
when 1 then self.first
|
5
|
+
when 2 then self.join(' and ')
|
6
|
+
else self[0..-2].join(', ') + " and #{self.last}"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class String
|
12
|
+
def two_digits
|
13
|
+
self.rjust(2, '0')
|
14
|
+
end
|
15
|
+
|
16
|
+
def ordinal; self.to_i.ordinal; end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Numeric
|
20
|
+
def two_digits; self.to_s.two_digits; end
|
21
|
+
|
22
|
+
def ordinal
|
23
|
+
return "#{self}th" if self.between?(10, 20)
|
24
|
+
case self. % 10
|
25
|
+
when 1 then "#{self}st"
|
26
|
+
when 2 then "#{self}nd"
|
27
|
+
when 3 then "#{self}rd"
|
28
|
+
else "#{self}th"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crony
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Berkowitz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: cucumber
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: guard
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: guard-cucumber
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rb-fsevent
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Spell-checker for cron expressions
|
79
|
+
email:
|
80
|
+
- michael.berkowitz@gmail.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- Gemfile
|
87
|
+
- Guardfile
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- crony.gemspec
|
92
|
+
- cucumber.yml
|
93
|
+
- features/date.feature
|
94
|
+
- features/rubycron.feature
|
95
|
+
- features/step_definitions/crony_steps.rb
|
96
|
+
- features/support/env.rb
|
97
|
+
- features/time.feature
|
98
|
+
- lib/crony.rb
|
99
|
+
- lib/crony/formatters/cron_struct.rb
|
100
|
+
- lib/crony/formatters/day_of_month_formatter.rb
|
101
|
+
- lib/crony/formatters/day_of_week_formatter.rb
|
102
|
+
- lib/crony/formatters/hour_formatter.rb
|
103
|
+
- lib/crony/formatters/minute_formatter.rb
|
104
|
+
- lib/crony/formatters/month_formatter.rb
|
105
|
+
- lib/crony/formatters/year_formatter.rb
|
106
|
+
- lib/crony/parser.rb
|
107
|
+
- lib/crony/presenters/day_presenter.rb
|
108
|
+
- lib/crony/presenters/time_presenter.rb
|
109
|
+
- lib/crony/presenters/year_presenter.rb
|
110
|
+
- lib/crony/version.rb
|
111
|
+
- lib/utility_functions.rb
|
112
|
+
homepage: ''
|
113
|
+
licenses: []
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ! '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 1.8.24
|
133
|
+
signing_key:
|
134
|
+
specification_version: 3
|
135
|
+
summary: Confirm that the cron expression you just wrote does what you meant it to
|
136
|
+
do.
|
137
|
+
test_files:
|
138
|
+
- features/date.feature
|
139
|
+
- features/rubycron.feature
|
140
|
+
- features/step_definitions/crony_steps.rb
|
141
|
+
- features/support/env.rb
|
142
|
+
- features/time.feature
|
143
|
+
has_rdoc:
|