file_scheduler 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/Gemfile +9 -0
- data/Guardfile +8 -0
- data/Rakefile +10 -0
- data/bin/file-scheduler +19 -0
- data/file_scheduler.gemspec +24 -0
- data/lib/file_scheduler.rb +21 -0
- data/lib/file_scheduler/attributes_parser.rb +40 -0
- data/lib/file_scheduler/base.rb +62 -0
- data/lib/file_scheduler/content.rb +19 -0
- data/lib/file_scheduler/core_ext.rb +37 -0
- data/lib/file_scheduler/file.rb +80 -0
- data/lib/file_scheduler/log.rb +53 -0
- data/lib/file_scheduler/playlist.rb +36 -0
- data/lib/file_scheduler/scheduling.rb +59 -0
- data/lib/file_scheduler/time_chain.rb +19 -0
- data/lib/file_scheduler/time_interval.rb +38 -0
- data/lib/file_scheduler/time_mark.rb +66 -0
- data/lib/file_scheduler/time_parser.rb +37 -0
- data/lib/file_scheduler/url.rb +56 -0
- data/lib/file_scheduler/version.rb +3 -0
- data/spec/lib/file_scheduler/attributes_parser_spec.rb +33 -0
- data/spec/lib/file_scheduler/base_spec.rb +75 -0
- data/spec/lib/file_scheduler/content_shared_examples.rb +12 -0
- data/spec/lib/file_scheduler/file_spec.rb +104 -0
- data/spec/lib/file_scheduler/log_spec.rb +50 -0
- data/spec/lib/file_scheduler/playlist_spec.rb +17 -0
- data/spec/lib/file_scheduler/scheduling_spec.rb +114 -0
- data/spec/lib/file_scheduler/time_interval_spec.rb +46 -0
- data/spec/lib/file_scheduler/time_mark_spec.rb +51 -0
- data/spec/lib/file_scheduler/time_parser_spec.rb +33 -0
- data/spec/lib/file_scheduler/url_spec.rb +33 -0
- data/spec/lib/file_scheduler_spec.rb +117 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/pathname.rb +23 -0
- data/spec/support/time.rb +19 -0
- data/spec/support/tmpdir.rb +1 -0
- metadata +118 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FileScheduler::Log do
|
4
|
+
|
5
|
+
let(:content) { mock }
|
6
|
+
|
7
|
+
def another_content
|
8
|
+
mock
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#distance" do
|
12
|
+
|
13
|
+
it "should be nil when content is unknown" do
|
14
|
+
subject.distance(mock).should be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be zero when content has been logged just before" do
|
18
|
+
subject.log(content)
|
19
|
+
subject.distance(content).should be_zero
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be increase each time another content is logged" do
|
23
|
+
subject.log(content)
|
24
|
+
5.times { subject.log another_content }
|
25
|
+
subject.distance(content).should == 5
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#log" do
|
31
|
+
|
32
|
+
it "should returh the logged content" do
|
33
|
+
subject.log(content).should == content
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#max_size" do
|
39
|
+
|
40
|
+
it "should limit the number of reminded contents" do
|
41
|
+
subject.max_size = 10
|
42
|
+
subject.log(content)
|
43
|
+
10.times { subject.log another_content }
|
44
|
+
subject.distance(content).should be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FileScheduler::Playlist do
|
4
|
+
|
5
|
+
def url(definition)
|
6
|
+
FileScheduler::URL.new definition
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "contents" do
|
10
|
+
|
11
|
+
it "should return contents described by URLs" do
|
12
|
+
FileScheduler::Playlist.new(:content => "dummy").contents.should include(url("dummy"))
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FileScheduler::Scheduling do
|
4
|
+
|
5
|
+
let(:content) { mock }
|
6
|
+
let(:root) { mock :contents => [] }
|
7
|
+
|
8
|
+
subject { FileScheduler::Scheduling.new root, Time.now }
|
9
|
+
|
10
|
+
it "should logged each next content" do
|
11
|
+
subject.stub :next_without_log => content
|
12
|
+
subject.log.should_receive(:log).with(content)
|
13
|
+
subject.next
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "schedulable?" do
|
17
|
+
|
18
|
+
it "should not accept a content not schedulable_by_time" do
|
19
|
+
subject.stub :schedulable_by_repeat? => true
|
20
|
+
subject.should_receive(:schedulable_by_time?).with(content).and_return(false)
|
21
|
+
subject.schedulable?(content).should be_false
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not accept a content not schedulable_by_repeat" do
|
25
|
+
subject.stub :schedulable_by_time? => true
|
26
|
+
subject.should_receive(:schedulable_by_repeat?).with(content).and_return(false)
|
27
|
+
subject.schedulable?(content).should be_false
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should accept a content schedulable by time and repeat" do
|
31
|
+
subject.stub :schedulable_by_time? => true
|
32
|
+
subject.stub :schedulable_by_repeat? => true
|
33
|
+
|
34
|
+
subject.schedulable?(content).should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "schedulable_by_time?" do
|
40
|
+
|
41
|
+
context "when context time_constraints matches time" do
|
42
|
+
before(:each) do
|
43
|
+
content.stub :time_constraints => mock(:matches? => true)
|
44
|
+
end
|
45
|
+
|
46
|
+
it { subject.schedulable_by_time?(content).should be_true }
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when content has no time_constraints" do
|
50
|
+
before(:each) do
|
51
|
+
content.stub :time_constraints => nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it { subject.schedulable_by_time?(content).should be_true }
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when content time_constraints doesn't match time" do
|
58
|
+
before(:each) do
|
59
|
+
content.stub :time_constraints => mock(:matches? => false)
|
60
|
+
end
|
61
|
+
|
62
|
+
it { subject.schedulable_by_time?(content).should be_false }
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "schedulable_by_repeat?" do
|
68
|
+
|
69
|
+
context "when content has no repeat_constraints" do
|
70
|
+
|
71
|
+
before(:each) do
|
72
|
+
content.stub :repeat_constraints => nil
|
73
|
+
end
|
74
|
+
|
75
|
+
it { subject.schedulable_by_repeat?(content).should be_true }
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when content has never been scheduled" do
|
80
|
+
|
81
|
+
before(:each) do
|
82
|
+
content.stub :repeat_constraints => 10
|
83
|
+
subject.log.stub :distance => nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it { subject.schedulable_by_repeat?(content).should be_true }
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when content has been scheduled longer than the repeat constraints" do
|
91
|
+
|
92
|
+
before(:each) do
|
93
|
+
content.stub :repeat_constraints => 5
|
94
|
+
subject.log.stub :distance => 10
|
95
|
+
end
|
96
|
+
|
97
|
+
it { subject.schedulable_by_repeat?(content).should be_true }
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when content has been scheduled less than the repeat constraints" do
|
102
|
+
|
103
|
+
before(:each) do
|
104
|
+
content.stub :repeat_constraints => 10
|
105
|
+
subject.log.stub :distance => 5
|
106
|
+
end
|
107
|
+
|
108
|
+
it { subject.schedulable_by_repeat?(content).should be_false }
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FileScheduler::TimeInterval do
|
4
|
+
|
5
|
+
let(:time) { Time.now }
|
6
|
+
|
7
|
+
def mark(attributes = {})
|
8
|
+
FileScheduler::TimeMark.new attributes
|
9
|
+
end
|
10
|
+
|
11
|
+
def interval(from, to)
|
12
|
+
from = mark(from) if Hash === from
|
13
|
+
to = mark(to) if Hash === to
|
14
|
+
|
15
|
+
FileScheduler::TimeInterval.new from, to
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#includes?" do
|
19
|
+
|
20
|
+
it "should include 13h55 in 12h30m-15h45m" do
|
21
|
+
interval({:hour => 12, :minute => 30}, {:hour => 15, :minute => 45}).should include(Time.parse("13:55"))
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should include 00h15 in 22h30-06h45" do
|
25
|
+
interval({:hour => 22, :minute => 30}, {:hour => 06, :minute => 45}).should include(Time.parse("00:15"))
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should include 23h45 in 22h30-06h45" do
|
29
|
+
interval({:hour => 22, :minute => 30}, {:hour => 06, :minute => 45}).should include(Time.parse("23:45"))
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not include 00h15 in 22h30-2009Y06h45" do
|
33
|
+
interval({:hour => 22, :minute => 30}, {:year => 2009, :hour => 06, :minute => 45}).should_not include(Time.parse("00:15"))
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should include Sun Dec 18 2011 in 6w-1w" do
|
37
|
+
interval({:week_day => 6}, {:week_day => 1}).should include(Time.parse("Sun Dec 18 2011"))
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should include Sun Dec 18 2011 in 3w-4w" do
|
41
|
+
interval({:week_day => 3}, {:week_day => 4}).should_not include(Time.parse("Sun Dec 18 2011"))
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FileScheduler::TimeMark do
|
4
|
+
|
5
|
+
let(:time) { Time.now }
|
6
|
+
|
7
|
+
def mark(attributes = {})
|
8
|
+
attributes = attributes.attributes if attributes.respond_to?(:attributes)
|
9
|
+
FileScheduler::TimeMark.new attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#matches?" do
|
13
|
+
|
14
|
+
RSpec::Matchers.define :match do |time|
|
15
|
+
match do |mark|
|
16
|
+
mark.matches? time
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should match a Time when all defined attributes are equal" do
|
21
|
+
mark(time).should match(time)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not match a Time when an attribute is diffirent" do
|
25
|
+
mark(time.attributes.merge(:month => time.month + 1)).should_not match(time)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should match week day" do
|
29
|
+
mark(time.attributes(:week_day)).should match(time)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#<=>" do
|
35
|
+
|
36
|
+
it "should be smaller when all attributes are equal or smaller" do
|
37
|
+
mark(time).should < time + 60
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should be equal when all attributes are equal" do
|
41
|
+
mark(time).should == time
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be higher when all attributes are equal or higher" do
|
45
|
+
mark(time).should > time - 60
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FileScheduler::TimeParser do
|
4
|
+
|
5
|
+
describe "#parse" do
|
6
|
+
|
7
|
+
it "should return nil for dummy" do
|
8
|
+
subject.parse("dummy").should be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should parse 12h30m-dummy" do
|
12
|
+
subject.parse("12h30m-dummy").should == FileScheduler::TimeMark.new(:hour => 12, :minute => 30)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should parse 1w12h30m-dummy" do
|
16
|
+
subject.parse("1w12h30m-dummy").should == FileScheduler::TimeMark.new(:week_day => 1, :hour => 12, :minute => 30)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should parse 2011y11M24d12h30m-dummy" do
|
20
|
+
subject.parse("1w12h30m-dummy").should == FileScheduler::TimeMark.new(:week_day => 1, :hour => 12, :minute => 30)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should parse 12h30m-15h45m-dummy" do
|
24
|
+
subject.parse("12h30m-15h45m-dummy").should == FileScheduler::TimeInterval.new(FileScheduler::TimeMark.new(:hour => 12, :minute => 30), FileScheduler::TimeMark.new(:hour => 15, :minute => 45))
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse T12h30m-dummy" do
|
28
|
+
subject.parse("T12h30m-dummy").should == FileScheduler::TimeMark.new(:hour => 12, :minute => 30)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FileScheduler::URL do
|
4
|
+
|
5
|
+
def url(definition)
|
6
|
+
FileScheduler::URL.new definition
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#time_constraints" do
|
10
|
+
|
11
|
+
it "should parse 12h30m-dummy" do
|
12
|
+
url("12h30m-dummy").time_constraints.should == FileScheduler::TimeMark.new(:hour => 12, :minute => 30)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should parse 1w/12h30m-dummy" do
|
16
|
+
url("1w/12h30m-dummy").time_constraints.should == FileScheduler::TimeChain.new(FileScheduler::TimeMark.new(:week_day => 1), FileScheduler::TimeMark.new(:hour => 12, :minute => 30))
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#attributes" do
|
22
|
+
|
23
|
+
it "should merge the parts attributes" do
|
24
|
+
url("parent{key1=parent_value,key2=value2}/dummy{key1=value1}.wav").attributes.should == { :key1 => "value1", :key2 => "value2" }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
require File.expand_path("../content_shared_examples", __FILE__)
|
30
|
+
|
31
|
+
it_behaves_like "a content"
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
class TestDir < Pathname
|
6
|
+
|
7
|
+
def self.open
|
8
|
+
Dir.mktmpdir do |directory|
|
9
|
+
yield TestDir.new(directory)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def file(name)
|
14
|
+
(self + name).tap do |file|
|
15
|
+
file.dirname.mkpath
|
16
|
+
FileUtils.touch file
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def scheduler
|
21
|
+
@scheduler ||= FileScheduler::Base.new self
|
22
|
+
end
|
23
|
+
|
24
|
+
def next(time = nil)
|
25
|
+
time = time ? Time::parse(time) : Time.now
|
26
|
+
next_content = scheduler.next(time)
|
27
|
+
next_content.to_s.gsub("#{self}/", "") if next_content
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class TestPlaylist
|
33
|
+
|
34
|
+
attr_reader :definition
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
@definition = ""
|
38
|
+
end
|
39
|
+
|
40
|
+
def url(definition)
|
41
|
+
@definition << "#{definition}\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
def scheduler
|
45
|
+
@scheduler ||= FileScheduler::Base.new :playlist => definition
|
46
|
+
end
|
47
|
+
|
48
|
+
def next(time)
|
49
|
+
scheduler.next(Time::parse(time)).to_s.gsub("#{self}/", "")
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe FileScheduler do
|
55
|
+
|
56
|
+
def at(time)
|
57
|
+
Time::parse time
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should support time intervals in files" do
|
61
|
+
TestDir.open do |directory|
|
62
|
+
directory.file "13h-15h-test.wav"
|
63
|
+
directory.file "15h-17h-test.wav"
|
64
|
+
|
65
|
+
directory.next("13:30").should == "13h-15h-test.wav"
|
66
|
+
directory.next("16:00").should == "15h-17h-test.wav"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should support time intervals in directories" do
|
71
|
+
TestDir.open do |directory|
|
72
|
+
directory.file "13h-15h/test1.wav"
|
73
|
+
directory.file "15h-17h/test2.wav"
|
74
|
+
|
75
|
+
directory.next("13:30").should == "13h-15h/test1.wav"
|
76
|
+
directory.next("16:00").should == "15h-17h/test2.wav"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should support week day intervals" do
|
81
|
+
TestDir.open do |directory|
|
82
|
+
directory.file "3w-4w-music.wav"
|
83
|
+
|
84
|
+
directory.next("Sun Dec 18 2011").should be_nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should support fixed time" do
|
89
|
+
TestDir.open do |directory|
|
90
|
+
directory.file "test.wav"
|
91
|
+
directory.file "T13h-test.wav"
|
92
|
+
|
93
|
+
directory.next("13:00").should == "T13h-test.wav"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should support repeat constraint" do
|
98
|
+
TestDir.open do |directory|
|
99
|
+
directory.file "test{repeat=+5}.wav"
|
100
|
+
|
101
|
+
directory.next.should == "test{repeat=+5}.wav"
|
102
|
+
directory.next.should be_nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "with playlist" do
|
107
|
+
it "should support time intervals in files" do
|
108
|
+
TestPlaylist.new.tap do |playlist|
|
109
|
+
playlist.url "13h-15h-test.wav"
|
110
|
+
playlist.url "15h-17h-test.wav"
|
111
|
+
|
112
|
+
playlist.next("16:00").should == "15h-17h-test.wav"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|