Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rspec
Original file line number Diff line number Diff line change
@@ -1 +1 @@
--color
--require spec_helper
8 changes: 5 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
language: ruby
rvm:
- "2.1.8"
- "2.2.4"
- "2.3.0"
- 2.1.10
- 2.2.10
- 2.3.7
- 2.4.3
- 2.5.1
13 changes: 10 additions & 3 deletions lib/cron_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,18 @@ def last(now = @time_source.now, num=1)
end


SUBELEMENT_REGEX = %r{^(\d+)(-(\d+)(/(\d+))?)?$}
def parse_element(elem, allowed_range)
SUBELEMENT_REGEX = %r{^(\d+|l)(-(\d+)(/(\d+))?)?$}
def parse_element(elem, allowed_range, field_name = nil)
values = elem.split(',').map do |subel|
if subel =~ /^\*/
step = subel.length > 1 ? subel[2..-1].to_i : 1
stepped_range(allowed_range, step)
else
if SUBELEMENT_REGEX === subel
if field_name != :dom && $1.include?('l')
raise ArgumentError, "'L' specification is supported only for DOM field"
end

if $5 # with range
stepped_range($1.to_i..$3.to_i, $5.to_i)
elsif $3 # range without step
Expand Down Expand Up @@ -191,6 +195,9 @@ def interpolate_weekdays_without_cache(year, month)
# Careful: crontabs may use either 0 or 7 for Sunday:
valid_wday << 0 if valid_wday.include?(7)

# L is converted to 0
valid_mday << (t.next_month - 1).day if valid_mday.include?(0)

result = []
while t.month == month
result << t.mday if valid_mday.include?(t.mday) || valid_wday.include?(t.wday)
Expand Down Expand Up @@ -251,7 +258,7 @@ def time_specs
{
:minute => parse_element(tokens[0], 0..59), #minute
:hour => parse_element(tokens[1], 0..23), #hour
:dom => parse_element(tokens[2], 1..31), #DOM
:dom => parse_element(tokens[2], 1..31, :dom), #DOM
:month => parse_element(tokens[3], 1..12), #mon
:dow => parse_element(tokens[4], 0..6) #DOW
}
Expand Down
2 changes: 1 addition & 1 deletion parse-cron.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ Gem::Specification.new do |s|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]

s.add_development_dependency 'rspec', '~>2.6.0'
s.add_development_dependency 'rspec', '~> 3.7.0'
end
48 changes: 34 additions & 14 deletions spec/cron_parser_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
require "time"
require "./spec/spec_helper"
require "cron_parser"
require "date"

Expand All @@ -8,7 +7,7 @@ def parse_date(str)
Time.local(dt.year, dt.month, dt.day, dt.hour, dt.min, 0)
end

describe "CronParser#parse_element" do
RSpec.describe "CronParser#parse_element" do
[
["*", 0..59, (0..59).to_a],
["*/10", 0..59, [0, 10, 20, 30, 40, 50]],
Expand All @@ -19,12 +18,12 @@ def parse_date(str)
].each do |element, range, expected|
it "should return #{expected} for '#{element}' when range is #{range}" do
parser = CronParser.new('* * * * *')
parser.parse_element(element, range).first.to_a.sort.should == expected.sort
expect(parser.parse_element(element, range).first).to match_array(expected)
end
end
end

describe "CronParser#next" do
RSpec.describe "CronParser#next" do
[
["* * * * *", "2011-08-15 12:00", "2011-08-15 12:01",1],
["* * * * *", "2011-08-15 02:25", "2011-08-15 02:26",1],
Expand Down Expand Up @@ -78,35 +77,39 @@ def parse_date(str)
["15-59/15 * * * *", "2014-02-01 15:45", "2014-02-01 16:15",4],
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 16:15",3],
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 16:15",2],
["* * L 2 *", "2015-02-01 15:36", "2015-02-28 00:00",1],
["* * L 2 *", "2016-02-01 15:36", "2016-02-29 00:00",1],
["* * 15,L 2 *", "2015-02-01 15:36", "2015-02-15 00:00",1],
["* * 15,L 2 *", "2015-02-16 15:36", "2015-02-28 00:00",1]
].each do |line, now, expected_next,num|
it "returns #{expected_next} for '#{line}' when now is #{now}" do
parsed_now = parse_date(now)
expected = parse_date(expected_next)
parser = CronParser.new(line)
parser.next(parsed_now).xmlschema.should == expected.xmlschema
expect(parser.next(parsed_now).xmlschema).to eql(expected.xmlschema)
end
it "returns the expected class" do
parsed_now = parse_date(now)
expected = parse_date(expected_next)
parser = CronParser.new(line)
result = parser.next(parsed_now,num)
result.class.to_s.should == (num > 1 ? 'Array' : 'Time')
expect(result).to be_a(num > 1 ? Array : Time)
end
it "returns the expected count" do
parsed_now = parse_date(now)
expected = parse_date(expected_next)
parser = CronParser.new(line)
result = parser.next(parsed_now,num)
if result.class.to_s == 'Array'
result.size.should == num
if result.is_a?(Array)
expect(result.size).to eql(num)
else
result.class.to_s.should == 'Time'
expect(result).to be_a(Time)
end
end
end
end

describe "CronParser#last" do
RSpec.describe "CronParser#last" do
[
["* * * * *", "2011-08-15 12:00", "2011-08-15 11:59"],
["* * * * *", "2011-08-15 02:25", "2011-08-15 02:24"],
Expand Down Expand Up @@ -157,32 +160,49 @@ def parse_date(str)
["15-59/15 * * * *", "2014-02-01 15:36", "2014-02-01 15:30"],
["15-59/15 * * * *", "2014-02-01 15:45", "2014-02-01 15:30"],
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 15:45"],
["* * L 2 *", "2014-02-01 15:36", "2013-02-28 23:59"],
["* * L 2 *", "2017-02-01 15:36", "2016-02-29 23:59"],
["* * 15,L 2 *", "2015-02-01 15:36", "2014-02-28 23:59"],
["* * 15,L 2 *", "2015-02-16 15:36", "2015-02-15 23:59"]
].each do |line, now, expected_next|
it "should return #{expected_next} for '#{line}' when now is #{now}" do
now = parse_date(now)
expected_next = parse_date(expected_next)

parser = CronParser.new(line)

parser.last(now).should == expected_next
expect(parser.last(now)).to eql(expected_next)
end
end
end

describe "CronParser#new" do
RSpec.describe "CronParser#new" do
it 'should not raise error when given a valid cronline' do
expect { CronParser.new('30 * * * *') }.not_to raise_error
end

it 'should raise error when given an invalid cronline' do
expect { CronParser.new('* * * *') }.to raise_error('not a valid cronline')
end

it 'should not raise error when L is passed in DOM field' do
expect { CronParser.new('* * L * *').next }.not_to raise_error
end

(0..4).each do |n|
next if n == 2
it "should raise error when L is passed in #{n} field" do
spec = Array.new(5) { '*' }
spec[n] = 'L'
expect { CronParser.new(spec.join(' ')).next }.to raise_error("'L' specification is supported only for DOM field")
end
end
end

describe "time source" do
RSpec.describe "time source" do
it "should use an alternate specified time source" do
ExtendedTime = Class.new(Time)
ExtendedTime.should_receive(:local).once
expect(ExtendedTime).to receive(:local).once
CronParser.new("* * * * *",ExtendedTime).next
end
end
34 changes: 27 additions & 7 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
spec_dir = File.dirname(__FILE__)
lib_dir = File.expand_path(File.join(spec_dir, '..', 'lib'))
$:.unshift(lib_dir)
$:.uniq!

RSpec.configure do |config|
end
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end

config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end

config.shared_context_metadata_behavior = :apply_to_host_groups

config.filter_run_when_matching :focus

config.example_status_persistence_file_path = 'spec/examples.txt'

require 'cron_parser'
config.disable_monkey_patching!

config.warnings = true

if config.files_to_run.one?
config.default_formatter = 'doc'
end

config.profile_examples = 10

config.order = :random

Kernel.srand config.seed
end