cronscription 1.0.0
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 +2 -0
- data/Gemfile +2 -0
- data/Rakefile +8 -0
- data/cronscription.gemspec +22 -0
- data/lib/cronscription.rb +18 -0
- data/lib/cronscription/entry.rb +91 -0
- data/lib/cronscription/tab.rb +27 -0
- data/lib/cronscription/version.rb +3 -0
- data/spec/cronscription/entry_spec.rb +178 -0
- data/spec/cronscription/tab_spec.rb +103 -0
- data/spec/cronscription_spec.rb +32 -0
- data/spec/spec_helper.rb +2 -0
- metadata +110 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "cronscription/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "cronscription"
|
|
7
|
+
s.version = Cronscription::VERSION
|
|
8
|
+
s.authors = ["Ben Feng"]
|
|
9
|
+
s.email = ["bfeng@enova.com"]
|
|
10
|
+
s.homepage = "https://github.com/enova/cronscription"
|
|
11
|
+
s.summary = %q{Cron parsing}
|
|
12
|
+
s.description = %q{Cron parsing}
|
|
13
|
+
|
|
14
|
+
s.files = `git ls-files`.split("\n")
|
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
17
|
+
s.require_paths = ["lib"]
|
|
18
|
+
|
|
19
|
+
s.add_development_dependency "rake"
|
|
20
|
+
s.add_development_dependency "rspec"
|
|
21
|
+
s.add_development_dependency "simplecov"
|
|
22
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'cronscription/tab'
|
|
2
|
+
require 'cronscription/version'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module Cronscription
|
|
6
|
+
class << self
|
|
7
|
+
# Convenient construction methods
|
|
8
|
+
def from_s(str)
|
|
9
|
+
Tab.new(str.lines.to_a)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def from_filepath(path)
|
|
13
|
+
File.open(path) do |f|
|
|
14
|
+
Tab.new(f.readlines)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module Cronscription
|
|
2
|
+
class Entry
|
|
3
|
+
ORDERED_KEYS = [:min, :hour, :day, :month, :wday]
|
|
4
|
+
FULL_RANGE = {
|
|
5
|
+
:min => (0..59).to_a,
|
|
6
|
+
:hour => (0..23).to_a,
|
|
7
|
+
:day => (1..31).to_a,
|
|
8
|
+
:month => (1..12).to_a,
|
|
9
|
+
:wday => (0..6).to_a,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
attr_reader :times, :command
|
|
13
|
+
|
|
14
|
+
def initialize(line)
|
|
15
|
+
@line = line
|
|
16
|
+
@times = {}
|
|
17
|
+
|
|
18
|
+
raw = {}
|
|
19
|
+
raw[:min], raw[:hour], raw[:day], raw[:month], raw[:wday], @command = line.split(nil, 6)
|
|
20
|
+
@command.gsub!(/#.*/, '')
|
|
21
|
+
|
|
22
|
+
raw.each do |key, val|
|
|
23
|
+
@times[key] = parse_column(val, FULL_RANGE[key])
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def ==(other)
|
|
28
|
+
@line == other.instance_variable_get(:@line)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
@line
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.parsable?(str)
|
|
36
|
+
!!(str =~ /([*\d,-]+\s+){5}.*/)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def parse_column(column, default=[])
|
|
40
|
+
case column
|
|
41
|
+
when /\*\/(\d+)/ then default.select { |val| val % $1.to_i == 0 }
|
|
42
|
+
when /\*/ then default
|
|
43
|
+
when /,/ then column.split(',').map{|c| parse_column(c)}.flatten.uniq
|
|
44
|
+
when /-/ then Range.new(*column.split('-').map{|c| c.to_i}).to_a
|
|
45
|
+
else [column.to_i]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def match_command?(regex)
|
|
50
|
+
regex === @command
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def times_to_execute(start, finish)
|
|
54
|
+
ret = []
|
|
55
|
+
|
|
56
|
+
incr_min = 60
|
|
57
|
+
incr_hour = incr_min*60
|
|
58
|
+
incr_day = incr_hour*24
|
|
59
|
+
incr = incr_min
|
|
60
|
+
|
|
61
|
+
current = nearest_minute(start)
|
|
62
|
+
while current <= finish
|
|
63
|
+
if ORDERED_KEYS.map{|k| @times[k].include?(current.send k)}.all?
|
|
64
|
+
ret << current
|
|
65
|
+
# If only I could goto into the middle of the loop, this wouldn't run every time.
|
|
66
|
+
# Optimizations to reduce execution time. No need to run minutely if there is only one minute.
|
|
67
|
+
if @times[:min].size == 1
|
|
68
|
+
if @times[:hour].size == 1
|
|
69
|
+
incr = incr_day
|
|
70
|
+
else
|
|
71
|
+
incr = incr_hour
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
current += incr
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
ret
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
def nearest_minute(time)
|
|
83
|
+
if time.sec == 0
|
|
84
|
+
time
|
|
85
|
+
else
|
|
86
|
+
# Always round up
|
|
87
|
+
time + (60 - time.sec)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'cronscription/entry'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Cronscription
|
|
5
|
+
class Tab
|
|
6
|
+
def initialize(cron_lines)
|
|
7
|
+
# Eliminate all lines starting with '#' since they are full comments
|
|
8
|
+
@entries = cron_lines.select{|l| Entry.parsable?(l)}.map{|e| Entry.new(e)}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def ==(other)
|
|
12
|
+
@entries == other.instance_variable_get(:@entries)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def find(regex)
|
|
16
|
+
@entries.select{|e| e.match_command?(regex)}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def sorted_merge(*arrs)
|
|
20
|
+
arrs.flatten.uniq.sort
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def times_to_execute(regex, start, finish)
|
|
24
|
+
sorted_merge(find(regex).map{|e| e.times_to_execute(start, finish)})
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'cronscription/entry'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
describe Cronscription::Entry do
|
|
6
|
+
before :all do
|
|
7
|
+
# <minute> <hour> <day> <month> <day of week> <tags and command>
|
|
8
|
+
@line = '1 2 3 4 5 comm'
|
|
9
|
+
@entry = Cronscription::Entry.new(@line)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'should be equal when created from same values' do
|
|
13
|
+
Cronscription::Entry.new(@line).should == @entry
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe 'from_s' do
|
|
17
|
+
it 'should map columns with correct fields' do
|
|
18
|
+
@entry.times.should == {
|
|
19
|
+
:min => [1],
|
|
20
|
+
:hour => [2],
|
|
21
|
+
:day => [3],
|
|
22
|
+
:month => [4],
|
|
23
|
+
:wday => [5],
|
|
24
|
+
}
|
|
25
|
+
@entry.command.should == 'comm'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'should convert to original line on to_s' do
|
|
29
|
+
line = ' 1 2 * 4 5 fun today! # some comment'
|
|
30
|
+
entry = Cronscription::Entry.new(line)
|
|
31
|
+
entry.to_s.should == line
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'should use FULL_RANGE for default values' do
|
|
35
|
+
entry = Cronscription::Entry.new('* * * * * comm')
|
|
36
|
+
entry.times.should == Cronscription::Entry::FULL_RANGE
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'should understand compex command structure' do
|
|
40
|
+
command = 'comm/rad --gen=ro -s tail'
|
|
41
|
+
entry = Cronscription::Entry.new("* * * * * #{command}")
|
|
42
|
+
entry.command.should == command
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe 'parsable?' do
|
|
47
|
+
it 'should be true for basic lines' do
|
|
48
|
+
Cronscription::Entry.parsable?('* * * * * comm').should be_true
|
|
49
|
+
Cronscription::Entry.parsable?('1 2 3 4 5 comm').should be_true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'should be true for compound time directives' do
|
|
53
|
+
Cronscription::Entry.parsable?('1-2 * * * * comm').should be_true
|
|
54
|
+
Cronscription::Entry.parsable?(' * 3,4 * * * comm').should be_true
|
|
55
|
+
Cronscription::Entry.parsable?(' * * 3,4-5 * * comm').should be_true
|
|
56
|
+
Cronscription::Entry.parsable?(' * * * 6-7,0,8-9 * comm').should be_true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'should be true for complex commands' do
|
|
60
|
+
Cronscription::Entry.parsable?('* * * * * comm/rad --gen=ro -s tail').should be_true
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'should be false for bad time declaration' do
|
|
64
|
+
Cronscription::Entry.parsable?('* b * * * comm').should be_false
|
|
65
|
+
Cronscription::Entry.parsable?('* * * * . comm').should be_false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'should be false for dumb lines' do
|
|
69
|
+
Cronscription::Entry.parsable?(' # This is a comment').should be_false
|
|
70
|
+
Cronscription::Entry.parsable?('rawr!').should be_false
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe 'parse_column' do
|
|
75
|
+
it 'should return fixed value as list of one' do
|
|
76
|
+
@entry.parse_column('1').should == [1]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'should return comma-separated as list of values' do
|
|
80
|
+
@entry.parse_column('5,2,8').should == [5, 2, 8]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'should return range as list of everything within the range' do
|
|
84
|
+
@entry.parse_column('4-6').should == [4, 5, 6]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'should return combination of range and comma-separated' do
|
|
88
|
+
@entry.parse_column('9,2-5,7').should == [9, 2, 3, 4, 5, 7]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'should use default value on asterisk' do
|
|
92
|
+
default = [1, 5, 9, 2, 6]
|
|
93
|
+
@entry.parse_column('*', default).should == default
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'should find every n minutes from the default on */n' do
|
|
97
|
+
default = [*0..100]
|
|
98
|
+
@entry.parse_column('*/31', default).should == [0, 31, 62, 93]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'should return unique entries only' do
|
|
102
|
+
@entry.parse_column('1,1,1').should == [1]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe 'match_command?' do
|
|
107
|
+
it 'should match command by regex' do
|
|
108
|
+
entry = Cronscription::Entry.new('1 2 3 4 5 command one')
|
|
109
|
+
entry.match_command?(/m*and\s*on/).should be_true
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'should not match command within comments' do
|
|
113
|
+
entry = Cronscription::Entry.new('1 2 3 4 5 command #herp')
|
|
114
|
+
entry.match_command?(/herp/).should be_false
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'should not match command within time directives' do
|
|
118
|
+
entry = Cronscription::Entry.new('1 2 3 4 5 command #herp')
|
|
119
|
+
entry.match_command?(/\d/).should be_false
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
describe 'times_to_execute' do
|
|
124
|
+
it 'should return times based on minutes' do
|
|
125
|
+
entry = Cronscription::Entry.new("21-40 * * * * comm")
|
|
126
|
+
start = Time.local(2011, 1, 1, 0, 0)
|
|
127
|
+
finish = Time.local(2011, 1, 1, 0, 30)
|
|
128
|
+
|
|
129
|
+
times = entry.times_to_execute(start, finish)
|
|
130
|
+
times.should == (21..30).map{|m| Time.local(2011, 1, 1, 0, m)}
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'should return times based on hours' do
|
|
134
|
+
entry = Cronscription::Entry.new("0 1-8 * * * comm")
|
|
135
|
+
start = Time.local(2011, 1, 1, 0, 0)
|
|
136
|
+
finish = Time.local(2011, 1, 1, 6, 0)
|
|
137
|
+
|
|
138
|
+
times = entry.times_to_execute(start, finish)
|
|
139
|
+
times.should == (1..6).map{|h| Time.local(2011, 1, 1, h, 0)}
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'should return times based on days' do
|
|
143
|
+
entry = Cronscription::Entry.new("0 0 8-20 * * comm")
|
|
144
|
+
start = Time.local(2011, 1, 5, 0, 0)
|
|
145
|
+
finish = Time.local(2011, 1, 15, 0, 0)
|
|
146
|
+
|
|
147
|
+
times = entry.times_to_execute(start, finish)
|
|
148
|
+
times.should == (8..15).map{|d| Time.local(2011, 1, d, 0, 0)}
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it 'should return times based on months' do
|
|
152
|
+
entry = Cronscription::Entry.new("0 0 1 1-5 * comm")
|
|
153
|
+
start = Time.local(2011, 4, 1, 0, 0)
|
|
154
|
+
finish = Time.local(2011, 12, 1, 0, 0)
|
|
155
|
+
|
|
156
|
+
times = entry.times_to_execute(start, finish)
|
|
157
|
+
times.should == (4..5).map{|m| Time.local(2011, m, 1, 0, 0)}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'should round start time up to the next minute' do
|
|
161
|
+
entry = Cronscription::Entry.new("* * * * * comm")
|
|
162
|
+
start = Time.local(2011, 1, 1, 0, 0, 45)
|
|
163
|
+
finish = Time.local(2011, 1, 1, 0, 1, 45)
|
|
164
|
+
|
|
165
|
+
times = entry.times_to_execute(start, finish)
|
|
166
|
+
times.should == [Time.local(2011, 1, 1, 0, 1)]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'should round start time up by bumping up necessary other fields' do
|
|
170
|
+
entry = Cronscription::Entry.new("* * * * * comm")
|
|
171
|
+
start = Time.local(2011, 12, 31, 23, 59, 45)
|
|
172
|
+
finish = Time.local(2012, 1, 1, 0, 0, 45)
|
|
173
|
+
|
|
174
|
+
times = entry.times_to_execute(start, finish)
|
|
175
|
+
times.should == [Time.local(2012, 1, 1, 0, 0)]
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'cronscription'
|
|
3
|
+
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
describe Cronscription::Tab do
|
|
8
|
+
before :all do
|
|
9
|
+
@cronstr = <<-END
|
|
10
|
+
# <minute> <hour> <day> <month> <day of week> <tags and command>
|
|
11
|
+
0 * * * * cron.hourly
|
|
12
|
+
0 0 * * * cron.daily
|
|
13
|
+
0 0 * * 0 cron.weekly
|
|
14
|
+
0 0 1 * * cron.monthly
|
|
15
|
+
1 2 3 4 5 0 # test trailing comment
|
|
16
|
+
END
|
|
17
|
+
@cron_lines = @cronstr.lines.to_a
|
|
18
|
+
@tab = Cronscription::Tab.new(@cron_lines)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should be equal when created from same values' do
|
|
22
|
+
Cronscription::Tab.new(@cron_lines).should == @tab
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe 'find' do
|
|
26
|
+
it 'should find the daily entry' do
|
|
27
|
+
entries = @tab.find(/daily/).map{|e| e.to_s}
|
|
28
|
+
entries.should == [@cron_lines[2]]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'should find all cron.* entries' do
|
|
32
|
+
entries = @tab.find(/cron\..*/).map{|e| e.to_s}
|
|
33
|
+
entries.should == @cron_lines[1..4]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'should ignore complete line comments' do
|
|
37
|
+
entries = @tab.find(/.*/).map{|e| e.to_s}
|
|
38
|
+
entries.should == @cron_lines[1..-1]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'should ignore trailing comments' do
|
|
42
|
+
entries = @tab.find(/test trailing comment/).map{|e| e.to_s}
|
|
43
|
+
entries.should == []
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'should ignore time directives' do
|
|
47
|
+
entries = @tab.find(/0/).map{|e| e.to_s}
|
|
48
|
+
entries.should == [@cron_lines[-1]]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'should attempt to use possible lines when encountering mangled garbage' do
|
|
52
|
+
cronstr = <<-END
|
|
53
|
+
# The history of all hitherto
|
|
54
|
+
existing society is the
|
|
55
|
+
* * * * * comm
|
|
56
|
+
history of class struggles.
|
|
57
|
+
END
|
|
58
|
+
cron_lines = cronstr.lines.to_a
|
|
59
|
+
tab = Cronscription::Tab.new(cron_lines)
|
|
60
|
+
entries = tab.find(/.*/).map{|e| e.to_s}
|
|
61
|
+
entries.should == [cron_lines[2]]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe 'sorted_merge' do
|
|
66
|
+
before :all do
|
|
67
|
+
@tab = Cronscription::Tab.new([])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'should merge in order' do
|
|
71
|
+
@tab.sorted_merge([1, 4], [2, 7, 9]).should == [1, 2, 4, 7, 9]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'should merge while eliminating duplicates' do
|
|
75
|
+
@tab.sorted_merge([2, 2, 2, 6, 7], [7, 8]).should == [2, 6, 7, 8]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe 'times_to_execute' do
|
|
80
|
+
it 'should return merged times' do
|
|
81
|
+
hour1 = 3
|
|
82
|
+
min1 = 48
|
|
83
|
+
|
|
84
|
+
hour2 = 6
|
|
85
|
+
min2 = 21
|
|
86
|
+
cronfile = <<-END
|
|
87
|
+
#{min1} #{hour1} * * * common
|
|
88
|
+
#{min2} #{hour2} * * * common
|
|
89
|
+
END
|
|
90
|
+
tab = Cronscription::Tab.new(cronfile.lines.to_a)
|
|
91
|
+
|
|
92
|
+
start = Time.local(2011, 1, 1, 0, 0)
|
|
93
|
+
finish = Time.local(2011, 1, 3, 0, 0)
|
|
94
|
+
tab.times_to_execute(/common/, start, finish).should == [
|
|
95
|
+
Time.local(2011, 1, 1, hour1, min1),
|
|
96
|
+
Time.local(2011, 1, 1, hour2, min2),
|
|
97
|
+
Time.local(2011, 1, 2, hour1, min1),
|
|
98
|
+
Time.local(2011, 1, 2, hour2, min2),
|
|
99
|
+
]
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'cronscription'
|
|
3
|
+
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
describe Cronscription do
|
|
8
|
+
before(:all) do
|
|
9
|
+
@cronstr = <<-END
|
|
10
|
+
59 * 10 * * entry1
|
|
11
|
+
* 12 2 * 5 entry2
|
|
12
|
+
END
|
|
13
|
+
@tab = Cronscription::Tab.new(@cronstr.lines.to_a)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe 'convenient constructors' do
|
|
17
|
+
it 'should create from string' do
|
|
18
|
+
Cronscription.from_s(@cronstr).should == @tab
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should create from filepath' do
|
|
22
|
+
path = nil
|
|
23
|
+
Tempfile.open('cronscription') do |f|
|
|
24
|
+
f.write(@cronstr)
|
|
25
|
+
path = f.path
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Cronscription.from_filepath(path).should == @tab
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: cronscription
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Ben Feng
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-05-13 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rake
|
|
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: rspec
|
|
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: simplecov
|
|
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
|
+
description: Cron parsing
|
|
63
|
+
email:
|
|
64
|
+
- bfeng@enova.com
|
|
65
|
+
executables: []
|
|
66
|
+
extensions: []
|
|
67
|
+
extra_rdoc_files: []
|
|
68
|
+
files:
|
|
69
|
+
- .gitignore
|
|
70
|
+
- Gemfile
|
|
71
|
+
- Rakefile
|
|
72
|
+
- cronscription.gemspec
|
|
73
|
+
- lib/cronscription.rb
|
|
74
|
+
- lib/cronscription/entry.rb
|
|
75
|
+
- lib/cronscription/tab.rb
|
|
76
|
+
- lib/cronscription/version.rb
|
|
77
|
+
- spec/cronscription/entry_spec.rb
|
|
78
|
+
- spec/cronscription/tab_spec.rb
|
|
79
|
+
- spec/cronscription_spec.rb
|
|
80
|
+
- spec/spec_helper.rb
|
|
81
|
+
homepage: https://github.com/enova/cronscription
|
|
82
|
+
licenses: []
|
|
83
|
+
post_install_message:
|
|
84
|
+
rdoc_options: []
|
|
85
|
+
require_paths:
|
|
86
|
+
- lib
|
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
88
|
+
none: false
|
|
89
|
+
requirements:
|
|
90
|
+
- - ! '>='
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '0'
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
none: false
|
|
95
|
+
requirements:
|
|
96
|
+
- - ! '>='
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '0'
|
|
99
|
+
requirements: []
|
|
100
|
+
rubyforge_project:
|
|
101
|
+
rubygems_version: 1.8.23
|
|
102
|
+
signing_key:
|
|
103
|
+
specification_version: 3
|
|
104
|
+
summary: Cron parsing
|
|
105
|
+
test_files:
|
|
106
|
+
- spec/cronscription/entry_spec.rb
|
|
107
|
+
- spec/cronscription/tab_spec.rb
|
|
108
|
+
- spec/cronscription_spec.rb
|
|
109
|
+
- spec/spec_helper.rb
|
|
110
|
+
has_rdoc:
|