crony 0.0.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/.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:
|