couch_scheduler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,35 @@
1
+ Feature: CouchPublish Integration
2
+ As a programmer
3
+ I want to integrate CouchScheduler with CouchPublish
4
+ So that I can query my database for published documents within a schedule
5
+
6
+ Scenario: Query for published documents within a schedule
7
+ Given an Article model that includes CouchPublish and CouchVisible
8
+ When I create several published articles scheduled now and in the future
9
+ And I create several unpublished articles scheduled now and in the future
10
+ When I call "Article.by_schedule_and_published"
11
+ Then I should receive the published documents scheduled now
12
+ When I call "Article.by_schedule_and_unpublished"
13
+ Then I should receive the unpublished documents scheduled now
14
+ When I wait till the future
15
+ And I call "Article.by_schedule_and_published"
16
+ Then I should receive the published documents scheduled in the future
17
+ When I call "Article.by_schedule_and_unpublished"
18
+ Then I should receive the unpublished documents scheduled in the future
19
+
20
+ @focus
21
+ Scenario: Count of published and unpublished documents within a schedule
22
+ Given an Article model that includes CouchPublish and CouchVisible
23
+ When I create 2 published articles scheduled now
24
+ And I create 3 published articles schedule in the future
25
+ And I create 4 unpublished articles scheduled now
26
+ And I create 7 unpublished articles schedule in the future
27
+ When I call "Article.count_schedule_and_published"
28
+ Then I should receive 2
29
+ When I call "Article.count_schedule_and_unpublished"
30
+ Then I should receive 4
31
+ When I wait till the future
32
+ And I call "Article.count_schedule_and_published"
33
+ Then I should receive 3
34
+ When I call "Article.count_schedule_and_unpublished"
35
+ Then I should receive 7
@@ -0,0 +1,35 @@
1
+ Feature: CouchVisible and CouchPublish Integration
2
+ As a programmer
3
+ I want to integrate CouchScheduler and CouchPublish with CouchVisible
4
+ So that I can query my database for shown, published documents within a schedule
5
+
6
+ Scenario: Query for shown, published documents within a schedule
7
+ Given a Slide model that includes CouchVisible, CouchPublish and CouchScheduler
8
+ When I create several shown, published slides scheduled now and in the future
9
+ And I create several hidden, published slides scheduled now and in the future
10
+ When I call "Slide.by_schedule_and_published_and_shown"
11
+ Then I should receive the shown, published documents scheduled now
12
+ When I call "Slide.by_schedule_and_published_and_hidden"
13
+ Then I should receive the hidden, published documents scheduled now
14
+ When I wait till the future
15
+ And I call "Slide.by_schedule_and_published_and_shown"
16
+ Then I should receive the shown, published documents scheduled in the future
17
+ When I call "Slide.by_schedule_and_published_and_hidden"
18
+ Then I should receive the hidden, published documents scheduled in the future
19
+
20
+ @focus
21
+ Scenario: Count of shown and hidden documents within a schedule
22
+ Given a Slide model that includes CouchVisible, CouchPublish and CouchScheduler
23
+ When I create 2 shown, published slides scheduled now
24
+ And I create 3 shown, published slides schedule in the future
25
+ And I create 4 hidden, published slides scheduled now
26
+ And I create 7 hidden, published slides schedule in the future
27
+ When I call "Slide.count_schedule_and_published_and_shown"
28
+ Then I should receive 2
29
+ When I call "Slide.count_schedule_and_published_and_hidden"
30
+ Then I should receive 4
31
+ When I wait till the future
32
+ And I call "Slide.count_schedule_and_published_and_shown"
33
+ Then I should receive 3
34
+ When I call "Slide.count_schedule_and_published_and_hidden"
35
+ Then I should receive 7
@@ -0,0 +1,35 @@
1
+ Feature: CouchVisible Integration
2
+ As a programmer
3
+ I want to integrate CouchScheduler with CouchVisible
4
+ So that I can query my database for shown documents within a schedule
5
+
6
+ Scenario: Query for shown documents within a schedule
7
+ Given an Post model that includes CouchVisible and CouchScheduler
8
+ When I create several shown posts scheduled now and in the future
9
+ And I create several hidden posts scheduled now and in the future
10
+ When I call "Post.by_schedule_and_shown"
11
+ Then I should receive the shown documents scheduled now
12
+ When I call "Post.by_schedule_and_hidden"
13
+ Then I should receive the hidden documents scheduled now
14
+ When I wait till the future
15
+ And I call "Post.by_schedule_and_shown"
16
+ Then I should receive the shown documents scheduled in the future
17
+ When I call "Post.by_schedule_and_hidden"
18
+ Then I should receive the hidden documents scheduled in the future
19
+
20
+ @focus
21
+ Scenario: Count of shown and hidden documents within a schedule
22
+ Given an Post model that includes CouchVisible and CouchScheduler
23
+ When I create 2 shown posts scheduled now
24
+ And I create 3 shown posts schedule in the future
25
+ And I create 4 hidden posts scheduled now
26
+ And I create 7 hidden posts schedule in the future
27
+ When I call "Post.count_schedule_and_shown"
28
+ Then I should receive 2
29
+ When I call "Post.count_schedule_and_hidden"
30
+ Then I should receive 4
31
+ When I wait till the future
32
+ And I call "Post.count_schedule_and_shown"
33
+ Then I should receive 3
34
+ When I call "Post.count_schedule_and_hidden"
35
+ Then I should receive 7
@@ -0,0 +1,55 @@
1
+ Feature: Scheduling
2
+ As a programmer
3
+ I want the ability to schedule my documents
4
+ So that I can control when they are accessible
5
+
6
+ Scenario: Setting valid start and end dates
7
+ Given an instance of a model that includes CouchScheduler
8
+ When I set "start" to now
9
+ And I set "end" to a day from now
10
+ Then I should be able to save my document
11
+
12
+ Scenario: Setting invalid start and end dates
13
+ Given an instance of a model that includes CouchScheduler
14
+ When I set "start" to now
15
+ And I set "end" to yesterday
16
+ Then I should not be able to save my document
17
+ And I should get an error message that the end "must be greater than start"
18
+
19
+ Scenario: Determining if a document is within it's schedule
20
+ Given an instance of a model that includes CouchScheduler
21
+ When I set "start" to now
22
+ And I set "end" to a day from now
23
+ Then "within_schedule?" should return true on my instance
24
+ When I wait two days
25
+ Then "within_schedule?" should return false on my instance
26
+
27
+ Scenario: Determining if a document is within it's schedule for a document that has only a start date
28
+ Given an instance of a model that includes CouchScheduler
29
+ When I set "start" to a day from now
30
+ Then "within_schedule?" should return false on my instance
31
+ When I wait two days
32
+ Then "within_schedule?" should return true on my instance
33
+
34
+ Scenario: Determining if a document is within it's schedule for a document that has only an end date
35
+ Given an instance of a model that includes CouchScheduler
36
+ When I set "end" to a day from now
37
+ Then "within_schedule?" should return true on my instance
38
+ When I wait two days
39
+ Then "within_schedule?" should return false on my instance
40
+
41
+ Scenario: Getting all documents that are within schedule on a given date
42
+ Given there are several documents currently scheduled
43
+ And there are several documents scheduled in the future
44
+ Then "by_schedule" should return the documents currently within schedule
45
+ And "by_schedule" should not return the documents scheduled in the future
46
+
47
+ Scenario: Counting documents
48
+ Given there are 3 documents scheduled between now and tomorrow
49
+ And ther are 10 documents scheduled between tomorrow and two days from now
50
+ Then "count_schedule" should return 3
51
+ And "count_schedule :key => 1.day.from_now" should return 10
52
+ When I wait a day
53
+ Then "count_schedule" should return 10
54
+ When I wait another day
55
+ Then "count_schedule" should return 0
@@ -0,0 +1,74 @@
1
+ Given /^an Article model that includes CouchPublish and CouchVisible$/ do
2
+ unless defined?(Article)
3
+ class Article < CouchRest::Model::Base
4
+ include CouchPublish
5
+ include CouchScheduler
6
+ end
7
+ end
8
+ end
9
+
10
+ When /^I create several published articles scheduled now and in the future$/ do
11
+ @published_now = []
12
+ @published_future = []
13
+
14
+ 5.times { @published_now << Article.create(:start => Time.now, :end => 1.day.from_now).tap {|a| a.publish! } }
15
+ 5.times { @published_future << Article.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.publish! } }
16
+ end
17
+
18
+ When /^I create several unpublished articles scheduled now and in the future$/ do
19
+ @unpublished_now = []
20
+ @unpublished_future = []
21
+
22
+ 5.times { @unpublished_now << Article.create(:start => Time.now, :end => 1.day.from_now) }
23
+ 5.times { @unpublished_future << Article.create(:start => 1.day.from_now, :end => 2.days.from_now) }
24
+ end
25
+
26
+ When /^I call "([^"]*)"$/ do |code|
27
+ @result = eval code
28
+ end
29
+
30
+ Then /^I should receive the published documents scheduled now$/ do
31
+ @result.collect(&:id).sort.should == @published_now.collect(&:id).sort
32
+ end
33
+
34
+ Then /^I should receive the unpublished documents scheduled now$/ do
35
+ @result.collect(&:id).sort.should == @unpublished_now.collect(&:id).sort
36
+ end
37
+
38
+ When /^I wait till the future$/ do
39
+ Timecop.freeze 1.day.from_now
40
+ end
41
+
42
+ Then /^I should receive the published documents scheduled in the future$/ do
43
+ @result.collect(&:id).sort.should == @published_future.collect(&:id).sort
44
+ end
45
+
46
+ Then /^I should receive the unpublished documents scheduled in the future$/ do
47
+ @result.collect(&:id).sort.should == @unpublished_future.collect(&:id).sort
48
+ end
49
+
50
+ When /^I create (\d+) published articles scheduled now$/ do |num|
51
+ @published_now = []
52
+ num.to_i.times { @published_now << Article.create(:start => Time.now, :end => 1.day.from_now).tap {|a| a.publish!}}
53
+ end
54
+
55
+ When /^I create (\d+) published articles schedule in the future$/ do |num|
56
+ @published_future = []
57
+ num.to_i.times { @published_future << Article.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.publish!}}
58
+ end
59
+
60
+ When /^I create (\d+) unpublished articles scheduled now$/ do |num|
61
+ @unpublished_now = []
62
+ num.to_i.times { @unpublished_now << Article.create(:start => Time.now, :end => 1.day.from_now)}
63
+ end
64
+
65
+ When /^I create (\d+) unpublished articles schedule in the future$/ do |num|
66
+ @unpublished_future = []
67
+ num.to_i.times { @unpublished_future << Article.create(:start => 1.day.from_now, :end => 2.days.from_now)}
68
+ end
69
+
70
+ Then /^I should receive (\d+)$/ do |count|
71
+ @result.should == count.to_i
72
+ end
73
+
74
+
@@ -0,0 +1,61 @@
1
+ Given /^a Slide model that includes CouchVisible, CouchPublish and CouchScheduler$/ do
2
+ unless defined? Slide
3
+ class Slide < CouchRest::Model::Base
4
+ include CouchVisible
5
+ include CouchPublish
6
+ include CouchScheduler
7
+ end
8
+ end
9
+ end
10
+
11
+ When /^I create several shown, published slides scheduled now and in the future$/ do
12
+ @published_shown_now = []
13
+ @published_shown_future = []
14
+
15
+ 5.times { @published_shown_now << Slide.create(:start => Time.now, :end => 1.day.from_now).tap {|a| a.show!; a.publish! } }
16
+ 5.times { @published_shown_future << Slide.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.show!; a.publish! } }
17
+ end
18
+
19
+ When /^I create several hidden, published slides scheduled now and in the future$/ do
20
+ @published_hidden_now = []
21
+ @published_hidden_future = []
22
+
23
+ 5.times { @published_hidden_now << Slide.create(:start => Time.now, :end => 1.day.from_now).tap {|a| a.hide!; a.publish! } }
24
+ 5.times { @published_hidden_future << Slide.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.hide!; a.publish! } }
25
+ end
26
+
27
+ Then /^I should receive the shown, published documents scheduled now$/ do
28
+ @result.collect(&:id).sort.should == @published_shown_now.collect(&:id).sort
29
+ end
30
+
31
+ Then /^I should receive the hidden, published documents scheduled now$/ do
32
+ @result.collect(&:id).sort.should == @published_hidden_now.collect(&:id).sort
33
+ end
34
+
35
+ Then /^I should receive the shown, published documents scheduled in the future$/ do
36
+ @result.collect(&:id).sort.should == @published_shown_future.collect(&:id).sort
37
+ end
38
+
39
+ Then /^I should receive the hidden, published documents scheduled in the future$/ do
40
+ @result.collect(&:id).sort.should == @published_hidden_future.collect(&:id).sort
41
+ end
42
+
43
+ When /^I create (\d+) shown, published slides scheduled now$/ do |num|
44
+ @published_shown_now = []
45
+ num.to_i.times { @published_shown_now << Slide.create(:start => Time.now, :end => 1.day.from_now).tap {|a| a.show!; a.publish!}}
46
+ end
47
+
48
+ When /^I create (\d+) shown, published slides schedule in the future$/ do |num|
49
+ @published_shown_future = []
50
+ num.to_i.times { @published_shown_future << Slide.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.show!; a.publish!}}
51
+ end
52
+
53
+ When /^I create (\d+) hidden, published slides scheduled now$/ do |num|
54
+ @published_hidden_now = []
55
+ num.to_i.times { @published_hidden_now << Slide.create(:start => Time.now, :end => 1.day.from_now).tap {|a| a.hide!; a.publish!}}
56
+ end
57
+
58
+ When /^I create (\d+) hidden, published slides schedule in the future$/ do |num|
59
+ @published_hidden_future = []
60
+ num.to_i.times { @published_hidden_future << Slide.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.hide!; a.publish!}}
61
+ end
@@ -0,0 +1,60 @@
1
+ Given /^an Post model that includes CouchVisible and CouchScheduler$/ do
2
+ unless defined? Post
3
+ class Post < CouchRest::Model::Base
4
+ include CouchVisible
5
+ include CouchScheduler
6
+ end
7
+ end
8
+ end
9
+
10
+ When /^I create several shown posts scheduled now and in the future$/ do
11
+ @shown_now = []
12
+ @shown_future = []
13
+
14
+ 5.times { @shown_now << Post.create(:start => Time.now, :end => 1.day.from_now ).tap {|a| a.show!; a.save }}
15
+ 5.times { @shown_future << Post.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.show!; a.save }}
16
+ end
17
+
18
+ When /^I create several hidden posts scheduled now and in the future$/ do
19
+ @hidden_now = []
20
+ @hidden_future = []
21
+
22
+ 5.times { @hidden_now << Post.create(:start => Time.now, :end => 1.day.from_now ).tap {|a| a.hide!; a.save }}
23
+ 5.times { @hidden_future << Post.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.hide!; a.save }}
24
+ end
25
+
26
+ Then /^I should receive the shown documents scheduled now$/ do
27
+ @result.collect(&:id).sort.should == @shown_now.collect(&:id).sort
28
+ end
29
+
30
+ Then /^I should receive the hidden documents scheduled now$/ do
31
+ @result.collect(&:id).sort.should == @hidden_now.collect(&:id).sort
32
+ end
33
+
34
+ Then /^I should receive the shown documents scheduled in the future$/ do
35
+ @result.collect(&:id).sort.should == @shown_future.collect(&:id).sort
36
+ end
37
+
38
+ Then /^I should receive the hidden documents scheduled in the future$/ do
39
+ @result.collect(&:id).sort.should == @hidden_future.collect(&:id).sort
40
+ end
41
+
42
+ When /^I create (\d+) shown posts scheduled now$/ do |num|
43
+ @shown_now = []
44
+ num.to_i.times { @shown_now << Post.create(:start => Time.now, :end => 1.day.from_now ).tap {|a| a.show!; a.save }}
45
+ end
46
+
47
+ When /^I create (\d+) shown posts schedule in the future$/ do |num|
48
+ @shown_future = []
49
+ num.to_i.times { @shown_future << Post.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.show!; a.save }}
50
+ end
51
+
52
+ When /^I create (\d+) hidden posts scheduled now$/ do |num|
53
+ @hidden_now = []
54
+ num.to_i.times { @hidden_now << Post.create(:start => Time.now, :end => 1.day.from_now).tap {|a| a.hide!; a.save }}
55
+ end
56
+
57
+ When /^I create (\d+) hidden posts schedule in the future$/ do |num|
58
+ @hidden_future = []
59
+ num.to_i.times { @hidden_future << Post.create(:start => 1.day.from_now, :end => 2.days.from_now).tap {|a| a.hide!; a.save }}
60
+ end
@@ -0,0 +1,107 @@
1
+ Given /^an instance of a model that includes CouchScheduler$/ do
2
+ class Model < CouchRest::Model::Base
3
+ include CouchScheduler
4
+ end
5
+ @instance = Model.new
6
+ end
7
+
8
+ When /^I set "([^"]*)" to now$/ do |property|
9
+ @instance.send "#{property}=", Time.now
10
+ end
11
+
12
+ When /^I set "([^"]*)" to a day from now$/ do |property|
13
+ @instance.send "#{property}=", 1.day.from_now
14
+ end
15
+
16
+ Then /^I should be able to save my document$/ do
17
+ @instance.save
18
+ @instance.errors.empty?.should be(true)
19
+ end
20
+
21
+ When /^I set "([^"]*)" to yesterday$/ do |property|
22
+ @instance.send "#{property}=", 1.day.ago
23
+ end
24
+
25
+ Then /^I should not be able to save my document$/ do
26
+ @instance.save
27
+ @instance.errors.empty?.should be(false)
28
+ end
29
+
30
+ Then /^I should get an error message that the end "([^"]*)"$/ do |end_message|
31
+ @instance.errors[:end].should == [end_message]
32
+ end
33
+
34
+ Then /^"([^"]*)" should return true on my instance$/ do |method|
35
+ @instance.send(method).should be(true)
36
+ end
37
+
38
+ When /^I set "([^"]*)" to a week from now$/ do |property|
39
+ @instance.send "#{property}=", 1.week.from_now
40
+ end
41
+
42
+ Then /^"([^"]*)" should return false on my instance$/ do |method|
43
+ @instance.send(method).should be(false)
44
+ end
45
+
46
+ When /^I wait two days$/ do
47
+ tomorrow = 2.days.from_now.beginning_of_day
48
+ Timecop.freeze tomorrow
49
+ end
50
+
51
+ Then /^"([^"]*)" should return the documents currently within schedule$/ do |method|
52
+ @result = Document.send(method).collect &:id
53
+ @currently_scheduled.collect(&:id).sort.should == @result.sort
54
+ end
55
+
56
+ Then /^"([^"]*)" should not return the documents scheduled in the future$/ do |method|
57
+ @result = Document.send(method)
58
+ (@future_scheduled.collect(&:id) - @result.collect(&:id)).should == @future_scheduled.collect(&:id)
59
+ end
60
+
61
+ Given /^there are several documents currently scheduled$/ do
62
+ unless defined? Document
63
+ class Document < CouchRest::Model::Base
64
+ include CouchScheduler
65
+ end
66
+ end
67
+
68
+ @currently_scheduled = []
69
+ 4.times { @currently_scheduled << Document.create(:start => Time.now, :end => 4.days.from_now) }
70
+ end
71
+
72
+ Given /^there are several documents scheduled in the future$/ do
73
+ unless defined? Document
74
+ class Document < CouchRest::Model::Base
75
+ include CouchScheduler
76
+ end
77
+ end
78
+
79
+ @future_scheduled = []
80
+ 10.times { @future_scheduled << Document.create(:start => 1.day.from_now, :end => 4.days.from_now) }
81
+ end
82
+
83
+ Given /^there are (\d+) documents scheduled between now and tomorrow$/ do |num|
84
+ unless defined? Document
85
+ class Document < CouchRest::Model::Base
86
+ include CouchScheduler
87
+ end
88
+ end
89
+ num.to_i.times { Document.create :start => Time.now, :end => 1.day.from_now }
90
+ end
91
+
92
+ Given /^ther are (\d+) documents scheduled between tomorrow and two days from now$/ do |num|
93
+ num.to_i.times { Document.create :start => 1.day.from_now, :end => 2.days.from_now }
94
+ end
95
+
96
+ Then /^"([^"]*)" should return (\d+)$/ do |code, num|
97
+ eval("Document.#{code}").should == num.to_i
98
+ end
99
+
100
+ When /^I wait a day$/ do
101
+ Timecop.freeze 1.day.from_now
102
+ end
103
+
104
+ When /^I wait another day$/ do
105
+ Timecop.freeze 1.day.from_now
106
+ end
107
+
@@ -0,0 +1,18 @@
1
+ $LOAD_PATH.unshift './lib'
2
+
3
+ require 'couch_scheduler'
4
+ require 'couchrest_model_config'
5
+ require 'couch_publish'
6
+ require 'couch_visible'
7
+ require 'timecop'
8
+
9
+ CouchRest::Model::Config.edit do
10
+ database do
11
+ default "http://admin:password@localhost:5984/couch_scheduler_test"
12
+ end
13
+ end
14
+
15
+ Before do
16
+ CouchRest::Model::Config.default_database.recreate!
17
+ Timecop.return
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'couchrest_model'
2
+ require 'couch_scheduler/time_massager'
3
+ require 'couch_scheduler/map'
4
+ require 'couch_scheduler/couch_visible_integration'
5
+ require 'couch_scheduler/couch_publish_integration'
6
+ require 'couch_scheduler/couch_publish_and_couch_visible_integration'
7
+ require 'couch_scheduler/couch_scheduler'
@@ -0,0 +1,27 @@
1
+ module CouchScheduler
2
+ module CouchVisibleCouchPublishIntegration
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.view_by :couch_schedule_and_published_and_shown, :map => Map.new(base, :published, :shown).to_s, :reduce => '_count'
6
+ base.view_by :couch_schedule_and_published_and_hidden, :map => Map.new(base, :published, :hidden).to_s, :reduce => '_count'
7
+ end
8
+
9
+ module ClassMethods
10
+ def by_schedule_and_published_and_shown(options={})
11
+ by_couch_schedule_and_shown CouchScheduler::TimeMassager.massage(options)
12
+ end
13
+
14
+ def by_schedule_and_published_and_hidden(options={})
15
+ by_couch_schedule_and_hidden CouchScheduler::TimeMassager.massage(options)
16
+ end
17
+
18
+ def count_schedule_and_published_and_shown(options={})
19
+ count_by_map :by_schedule_and_published_and_shown, options
20
+ end
21
+
22
+ def count_schedule_and_published_and_hidden(options={})
23
+ count_by_map :by_schedule_and_published_and_hidden, options
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module CouchScheduler
2
+ module CouchPublishIntegration
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.view_by :couch_schedule_and_unpublished, :map => Map.new(base, :unpublished).to_s, :reduce => '_count'
6
+ base.view_by :couch_schedule_and_published, :map => Map.new(base, :published).to_s, :reduce => '_count'
7
+ end
8
+
9
+ module ClassMethods
10
+ def by_schedule_and_published(options={})
11
+ by_couch_schedule_and_published CouchScheduler::TimeMassager.massage(options)
12
+ end
13
+
14
+ def by_schedule_and_unpublished(options={})
15
+ by_couch_schedule_and_unpublished CouchScheduler::TimeMassager.massage(options)
16
+ end
17
+
18
+ def count_schedule_and_published(options={})
19
+ count_by_map :by_schedule_and_published, options
20
+ end
21
+
22
+ def count_schedule_and_unpublished(options={})
23
+ count_by_map :by_schedule_and_unpublished, options
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ module CouchScheduler
2
+ def self.included(base)
3
+ base.property :start, Time
4
+ base.property :end, Time
5
+ base.validate :validate_start_and_end
6
+ base.view_by :couch_schedule, :map => Map.new(base).to_s, :reduce => '_count'
7
+ base.extend ClassMethods
8
+
9
+ if defined?(CouchPublish) && base.ancestors.include?(CouchPublish)
10
+ base.send :include, CouchPublishIntegration
11
+ end
12
+
13
+ if defined?(CouchVisible) && base.ancestors.include?(CouchVisible)
14
+ base.send :include, CouchVisibleIntegration
15
+ end
16
+
17
+ if defined?(CouchVisible) && base.ancestors.include?(CouchVisible) && defined?(CouchPublish) && base.ancestors.include?(CouchPublish)
18
+ base.send :include, CouchVisibleCouchPublishIntegration
19
+ end
20
+ end
21
+
22
+ module ClassMethods
23
+ def by_schedule(options={})
24
+ by_couch_schedule CouchScheduler::TimeMassager.massage(options)
25
+ end
26
+
27
+ def count_schedule(options={})
28
+ count_by_map :by_schedule, options
29
+ end
30
+
31
+ private
32
+ def count_by_map(map, options)
33
+ result = self.send(map, options.merge(:reduce => true))['rows'].first
34
+ result ? result['value'] : 0
35
+ end
36
+ end
37
+
38
+ def within_schedule?
39
+ start_valid = true
40
+ end_valid = true
41
+
42
+ start_valid = Time.now >= self.start if self.start
43
+ end_valid = Time.now < self.end if self.end
44
+
45
+ start_valid && end_valid
46
+ end
47
+
48
+ private
49
+ def validate_start_and_end
50
+ if self.end && self.start && self.end < self.start
51
+ errors[:end] = "must be greater than start"
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,27 @@
1
+ module CouchScheduler
2
+ module CouchVisibleIntegration
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.view_by :couch_schedule_and_shown, :map => Map.new(base, :shown).to_s, :reduce => '_count'
6
+ base.view_by :couch_schedule_and_hidden, :map => Map.new(base, :hidden).to_s, :reduce => '_count'
7
+ end
8
+
9
+ module ClassMethods
10
+ def by_schedule_and_shown(options={})
11
+ by_couch_schedule_and_shown CouchScheduler::TimeMassager.massage(options)
12
+ end
13
+
14
+ def by_schedule_and_hidden(options={})
15
+ by_couch_schedule_and_hidden CouchScheduler::TimeMassager.massage(options)
16
+ end
17
+
18
+ def count_schedule_and_shown(options={})
19
+ count_by_map :by_schedule_and_shown, options
20
+ end
21
+
22
+ def count_schedule_and_hidden(options={})
23
+ count_by_map :by_schedule_and_hidden, options
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,61 @@
1
+ module CouchScheduler
2
+ class Map
3
+ def initialize(original_base, *args)
4
+ @base = original_base
5
+ @options = [:base_check] + args
6
+ end
7
+
8
+ def to_s
9
+ %{
10
+ function(doc){
11
+ if (#{conditions}){
12
+ var start = doc.start ? new Date(doc.start) : new Date(2011, 0, 1, 0, 0, 0, 0)
13
+ var end = doc.end ? new Date(doc.end ) : new Date(2025, 0, 1, 0, 0, 0, 0)
14
+
15
+ while(start < end){
16
+ emit(
17
+ [
18
+ start.getFullYear(),
19
+ start.getMonth(),
20
+ start.getDate(),
21
+ 0,
22
+ 0,
23
+ 0
24
+ ],
25
+ null
26
+ );
27
+ start.setDate(start.getDate() + 1)
28
+ }
29
+ }
30
+ }
31
+ }
32
+ end
33
+
34
+ private
35
+ def conditions
36
+ @options.map do |option|
37
+ self.send option
38
+ end.join " && "
39
+ end
40
+
41
+ def base_check
42
+ "doc['couchrest-type'] == '#{@base.to_s}'"
43
+ end
44
+
45
+ def shown
46
+ "doc.couch_visible === true"
47
+ end
48
+
49
+ def hidden
50
+ "doc.couch_visible === false"
51
+ end
52
+
53
+ def published
54
+ "doc.milestone_memories.length > 0"
55
+ end
56
+
57
+ def unpublished
58
+ "doc.milestone_memories.length == 0"
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,22 @@
1
+ module CouchScheduler
2
+ module TimeMassager
3
+ extend self
4
+
5
+ def massage(options)
6
+ if !options[:startkey] && !options[:key]
7
+ options = {:key => format_time(Time.now), :reduce => false}.merge options
8
+ end
9
+
10
+ [:key, :startkey, :endkey].each do |option|
11
+ options[option] = format_time options[option] if options[option].kind_of?(Time)
12
+ end
13
+
14
+ options
15
+ end
16
+
17
+ private
18
+ def format_time(t)
19
+ [t.year, t.month - 1, t.day, 0, 0, 0]
20
+ end
21
+ end
22
+ end
data/readme.markdown ADDED
@@ -0,0 +1,122 @@
1
+ # Couch Scheduler
2
+
3
+ Schedule your `CouchRest::Model::Base` documents with start and end dates. What those start and end dates signify is up to you.
4
+
5
+ ## Installation
6
+
7
+ It's a gem called `couch_scheduler`. Install it in whatever way is appropriate to you.
8
+
9
+ ## Basics
10
+
11
+ The gem includes a module, `CouchScheduler`, that you can mix into your documents.
12
+
13
+ For example, let's imagine that the we have an Article model:
14
+
15
+ class Article < CouchRest::Model::Base
16
+ include CouchScheduler
17
+
18
+ property :title
19
+ end
20
+
21
+ You can now provide start and end dates for your articles:
22
+
23
+ @article = Article.create :title => "Couch Scheduler is simple and cool."
24
+ @article.start = Time.now
25
+ @article.end = 6.days.from_now
26
+ @article.save
27
+
28
+ ## Validation
29
+
30
+ `CouchSchedule` will use `ActiveModel` validation to ensure that your `end` is after your `start`:
31
+
32
+ @article.start = Time.now
33
+ @article.end = 2.days.ago
34
+ @article.save #==> false
35
+ @artile.errors #==> [:end, " must be greater than start"]
36
+
37
+ ## Uses?
38
+
39
+ Now what can you do with these start and end dates? One use: publishing.
40
+
41
+ Let's imagine that you only to display this article on your website between the start and end dates. You can use the `within_schedule?` method to determine if an article is available for viewing given the current time:
42
+
43
+ @article.within_schedule? #==> true
44
+
45
+ # wait 6 days....
46
+
47
+ @article.within_schedule? #==> false
48
+
49
+ You can also query the databases for all of the articles currently within their schedule via `by_schedule`:
50
+
51
+ Article.by_schedule
52
+
53
+ `by_schedule` simply queries a map with a default key of `Time.now.start_of_day`. You can pass any options to it that you would normally pass to a map function in `CouchRest::Model::Base`:
54
+
55
+ Article.by_schedule :key => 10.days.from_now
56
+ #==> all the articles active 10 days from now
57
+
58
+ Article.by_schedule :startkey => Time.now, :endkey => 10.days.from_now
59
+ #==> all the articles active between now and 10 days from now
60
+
61
+ `CouchVisible` also provides you with a convenience method for getting the count of the `by_schedule` map/reduce:
62
+
63
+ Article.count_schedule
64
+ #==> the number of documents that are currently within their schedule
65
+
66
+ Like `by_schedule`, `count_schedule` supports all the usual map/reduce options:
67
+
68
+ Article.count_schedule :key => 10.days.from_now
69
+ #==> the count of all articles that are within their start/end dates 10 days from now
70
+
71
+ ## CouchPublish Integration
72
+
73
+ If you include `CouchScheduler` into a model that already includes `CouchPublish`, then you get a new map function for free, `by_schedule_and_published`:
74
+
75
+ # with a class definition like this:
76
+ class Article < CouchRest::Model::Base
77
+ include CouchPublish
78
+ include CouchScheduler
79
+ property :title
80
+ end
81
+
82
+ # you can query for all published and currently scheduled documents like this:
83
+ Article.by_schedule_and_published
84
+ #==> returns all documents that are published and currently within their schedule
85
+
86
+ # you can also query for the unpublished and currently scheduled documents like this:
87
+ Article.by_schedule_and_unpublished
88
+
89
+ You'll also get `count_schedule_and_published` and `count_schedule_and_unpublished` for free.
90
+
91
+ ## CouchVisible Integration
92
+
93
+ If you include `CouchScheduler` into a model that includes `CouchVisible`, you'll get the following map/reduce functions for free:
94
+
95
+ Article.by_schedule_and_shown
96
+ #==> all articles that are currently within their start and end dates and are shown
97
+
98
+ Article.by_schedule_and_hidden
99
+ #==> all articles that are currently within their start and end dates and are hidden
100
+
101
+ Article.count_schedule_and_shown
102
+ Article.count_schedule_and_hidden
103
+
104
+ ## CouchPublish/CouchVisible integration
105
+
106
+ If you include `CouchScheduler` into a model that includes both `CouchVisible` and `CouchPublish`, you'll get the following map/reduce functions for free:
107
+
108
+ Article.by_schedule_and_published_and_shown
109
+ Article.by_schedule_and_published_and_hidden
110
+ Article.by_schedule_and_unpublished_and_shown
111
+ Article.by_schedule_and_unpublished_and_hidden
112
+
113
+ And of course, all the corresponding `count` methods are available:
114
+
115
+ Article.count_schedule_and_published_and_shown
116
+ Article.count_schedule_and_published_and_hidden
117
+ Article.count_schedule_and_unpublished_and_shown
118
+ Article.count_schedule_and_unpublished_and_hidden
119
+
120
+ ## LICENSE
121
+
122
+ This software is PUBLIC DOMAIN. By contributing to it, you agree to let your contribution enter the PUBLIC DOMAIN.
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: couch_scheduler
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Matt Parker
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-20 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: cucumber
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: couchrest_model_config
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: couch_publish
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :development
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: couch_visible
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ~>
83
+ - !ruby/object:Gem::Version
84
+ hash: 27
85
+ segments:
86
+ - 0
87
+ - 0
88
+ - 2
89
+ version: 0.0.2
90
+ type: :development
91
+ version_requirements: *id005
92
+ - !ruby/object:Gem::Dependency
93
+ name: timecop
94
+ prerelease: false
95
+ requirement: &id006 !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 3
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ type: :development
105
+ version_requirements: *id006
106
+ - !ruby/object:Gem::Dependency
107
+ name: couchrest_model
108
+ prerelease: false
109
+ requirement: &id007 !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ~>
113
+ - !ruby/object:Gem::Version
114
+ hash: 23
115
+ segments:
116
+ - 1
117
+ - 0
118
+ - 0
119
+ version: 1.0.0
120
+ type: :runtime
121
+ version_requirements: *id007
122
+ description: Create a publishing system that allows you to schedule your documents for publication.
123
+ email: moonmaster9000@gmail.com
124
+ executables: []
125
+
126
+ extensions: []
127
+
128
+ extra_rdoc_files: []
129
+
130
+ files:
131
+ - lib/couch_scheduler/couch_publish_and_couch_visible_integration.rb
132
+ - lib/couch_scheduler/couch_publish_integration.rb
133
+ - lib/couch_scheduler/couch_scheduler.rb
134
+ - lib/couch_scheduler/couch_visible_integration.rb
135
+ - lib/couch_scheduler/map.rb
136
+ - lib/couch_scheduler/time_massager.rb
137
+ - lib/couch_scheduler.rb
138
+ - VERSION
139
+ - readme.markdown
140
+ - features/couch_publish_integration.feature
141
+ - features/couch_visible_and_couch_publish_integration.feature
142
+ - features/couch_visible_integration.feature
143
+ - features/scheduling.feature
144
+ - features/step_definitions/couch_publish_integration.rb
145
+ - features/step_definitions/couch_visible_and_couch_publish_integration.rb
146
+ - features/step_definitions/couch_visible_integration.rb
147
+ - features/step_definitions/scheduling.rb
148
+ - features/support/env.rb
149
+ homepage: http://github.com/moonmaster9000/couch_scheduler
150
+ licenses: []
151
+
152
+ post_install_message:
153
+ rdoc_options: []
154
+
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ hash: 3
163
+ segments:
164
+ - 0
165
+ version: "0"
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ none: false
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ hash: 3
172
+ segments:
173
+ - 0
174
+ version: "0"
175
+ requirements: []
176
+
177
+ rubyforge_project:
178
+ rubygems_version: 1.8.5
179
+ signing_key:
180
+ specification_version: 3
181
+ summary: Schedule documents with start and end dates.
182
+ test_files:
183
+ - features/couch_publish_integration.feature
184
+ - features/couch_visible_and_couch_publish_integration.feature
185
+ - features/couch_visible_integration.feature
186
+ - features/scheduling.feature
187
+ - features/step_definitions/couch_publish_integration.rb
188
+ - features/step_definitions/couch_visible_and_couch_publish_integration.rb
189
+ - features/step_definitions/couch_visible_integration.rb
190
+ - features/step_definitions/scheduling.rb
191
+ - features/support/env.rb