couch_scheduler 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/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