couch_cloner 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 +1 -0
- data/couch_cloner.gemspec +23 -0
- data/lib/couch_cloner.rb +7 -0
- data/lib/couch_cloner/clone.rb +42 -0
- data/lib/couch_cloner/couch_cloner.rb +8 -0
- data/lib/couch_cloner/maps/by_clone_id_and_start_time.rb +17 -0
- data/lib/couch_cloner/query.rb +77 -0
- data/lib/couch_cloner/scheduling.rb +15 -0
- data/readme.markdown +293 -0
- metadata +222 -0
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "couch_cloner"
|
3
|
+
s.version = File.read "VERSION"
|
4
|
+
s.authors = "Matt Parker"
|
5
|
+
s.homepage = "http://github.com/moonmaster9000/couch_cloner"
|
6
|
+
s.summary = "Clone and schedule CouchDB documents"
|
7
|
+
s.description = "Create clones of CouchDB documents, and schedule them for publication."
|
8
|
+
s.email = "moonmaster9000@gmail.com"
|
9
|
+
s.files = Dir["lib/**/*"] << "VERSION" << "readme.markdown" << "couch_cloner.gemspec"
|
10
|
+
s.test_files = Dir["feature/**/*"]
|
11
|
+
|
12
|
+
s.add_development_dependency "cucumber"
|
13
|
+
s.add_development_dependency "rspec"
|
14
|
+
s.add_development_dependency "couchrest_model_config"
|
15
|
+
s.add_development_dependency "couch_publish", "~> 0.0.3"
|
16
|
+
s.add_development_dependency "couch_visible"
|
17
|
+
s.add_development_dependency "timecop"
|
18
|
+
|
19
|
+
s.add_dependency "couchrest", "1.0.1"
|
20
|
+
s.add_dependency "couchrest_model", "~> 1.0.0"
|
21
|
+
s.add_dependency "recloner", "~> 0.1.1"
|
22
|
+
s.add_dependency "couch_view", "~> 0.0.3"
|
23
|
+
end
|
data/lib/couch_cloner.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module CouchCloner
|
2
|
+
module Clone
|
3
|
+
def self.included(base)
|
4
|
+
base.property :clone_id
|
5
|
+
base.send :include, InstanceMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
def clone(&block)
|
10
|
+
verify_clone_preconditions
|
11
|
+
block ||= Proc.new {}
|
12
|
+
|
13
|
+
property_names = properties.map(&:name) - (protected_properties.map(&:name) + %w{_id _attachments _rev milestone_memories})
|
14
|
+
attrs = property_names.inject({}){|hash, x|
|
15
|
+
val = send(x)
|
16
|
+
val = val.to_a if val.class == CouchRest::Model::CastedArray
|
17
|
+
hash[x] = val
|
18
|
+
hash
|
19
|
+
}
|
20
|
+
|
21
|
+
self.class.new(attrs).tap(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def clone!(&block)
|
25
|
+
verify_clone_preconditions
|
26
|
+
has_block = !block.nil?
|
27
|
+
block ||= Proc.new {}
|
28
|
+
next_id = database.server.next_uuid
|
29
|
+
copy next_id
|
30
|
+
doc = self.class.get(next_id)
|
31
|
+
has_block ? doc.tap(&block).tap {|d| d.save} : doc
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def verify_clone_preconditions
|
36
|
+
unless self.clone_id
|
37
|
+
raise "You must specify a non-nil clone_id on your '#{self.class}' instance before you can clone it."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CouchCloner
|
2
|
+
class ByCloneIdAndStartTime
|
3
|
+
include CouchView::Map
|
4
|
+
|
5
|
+
def map
|
6
|
+
"
|
7
|
+
function(doc){
|
8
|
+
if (#{conditions} && (doc.start == null || doc.start == '')) {
|
9
|
+
emit([doc.clone_id, {'created_at': doc.created_at}], null)
|
10
|
+
} else if (#{conditions} && doc.start != null && doc.start != ''){
|
11
|
+
emit([doc.clone_id, doc.start], null)
|
12
|
+
}
|
13
|
+
}
|
14
|
+
"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module CouchCloner
|
2
|
+
module Query
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
base.map :clone_id
|
6
|
+
base.couch_view :by_clone_id_and_start_time do
|
7
|
+
map CouchCloner::ByCloneIdAndStartTime
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def map_by_clone_id_and_start(clone_id, start=nil)
|
13
|
+
map_by_clone_id_and_start_time.startkey!([clone_id, start]).endkey!([clone_id, {:end => nil}])
|
14
|
+
end
|
15
|
+
|
16
|
+
def count_by_clone_id_and_start(clone_id, start=nil)
|
17
|
+
count_by_clone_id_and_start_time.
|
18
|
+
startkey!([clone_id, start]).
|
19
|
+
endkey!([clone_id, {:end => nil}])
|
20
|
+
end
|
21
|
+
|
22
|
+
def map_active_by_clone_id(clone_id)
|
23
|
+
map_by_clone_id_and_start_time.
|
24
|
+
startkey!([clone_id, Time.now]).
|
25
|
+
endkey!([clone_id]).
|
26
|
+
descending!(true)
|
27
|
+
end
|
28
|
+
|
29
|
+
def map_future_by_clone_id(clone_id)
|
30
|
+
map_by_clone_id_and_start_time.
|
31
|
+
startkey!([clone_id, Time.now]).
|
32
|
+
endkey!([clone_id, {:end => nil}])
|
33
|
+
end
|
34
|
+
|
35
|
+
#new
|
36
|
+
def count_future_by_clone_id(clone_id)
|
37
|
+
count_by_clone_id_and_start_time.
|
38
|
+
startkey!([clone_id, Time.now]).
|
39
|
+
endkey!([clone_id, {:end => nil}])
|
40
|
+
end
|
41
|
+
|
42
|
+
def map_past_by_clone_id(clone_id)
|
43
|
+
map_by_clone_id_and_start_time.
|
44
|
+
startkey!([clone_id, Time.now]).
|
45
|
+
endkey!([clone_id]).
|
46
|
+
descending!(true)
|
47
|
+
end
|
48
|
+
|
49
|
+
def count_past_by_clone_id(clone_id)
|
50
|
+
count_by_clone_id_and_start_time.
|
51
|
+
startkey!([clone_id, Time.now]).
|
52
|
+
endkey!([clone_id]).
|
53
|
+
descending!(true)
|
54
|
+
end
|
55
|
+
|
56
|
+
def map_clone_ids
|
57
|
+
map_by_clone_id.
|
58
|
+
reduce!(true).
|
59
|
+
group!(true)
|
60
|
+
end
|
61
|
+
|
62
|
+
def count_clone_ids!
|
63
|
+
map_by_clone_id.
|
64
|
+
reduce!(true).
|
65
|
+
group!(true).get!['rows'].count
|
66
|
+
end
|
67
|
+
|
68
|
+
def map_last_future_by_clone_id(clone_id)
|
69
|
+
map_by_clone_id_and_start_time.
|
70
|
+
startkey!([clone_id, {:end => nil}]).
|
71
|
+
endkey!([clone_id]).
|
72
|
+
descending!(true).
|
73
|
+
limit!(1)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CouchCloner
|
2
|
+
module Scheduling
|
3
|
+
def self.included(base)
|
4
|
+
base.property :start, Time
|
5
|
+
base.validate :uniqueness_of_start_and_clone_id
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
def uniqueness_of_start_and_clone_id
|
10
|
+
if !start.nil? && self.class.count_by_clone_id_and_start_time.key([clone_id, start]).get! != 0
|
11
|
+
errors.add :start, "must be unique for the clone_id group '#{clone_id}'"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/readme.markdown
ADDED
@@ -0,0 +1,293 @@
|
|
1
|
+
## CouchCloner
|
2
|
+
|
3
|
+
Clone your CouchDB `CouchRest::Model::Base` documents and schedule them for publishing.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
It's a ruby gem called `couch_cloner`. Install it.
|
9
|
+
|
10
|
+
|
11
|
+
## Setup
|
12
|
+
|
13
|
+
Simply include the module `CouchCloner` into your `CouchRest::Model::Base` document. For example:
|
14
|
+
|
15
|
+
class HtmlSnippet < CouchRest::Model::Base
|
16
|
+
include CouchCloner
|
17
|
+
end
|
18
|
+
|
19
|
+
Setup complete.
|
20
|
+
|
21
|
+
|
22
|
+
## Cloning (.clone/.clone!)
|
23
|
+
|
24
|
+
Let's imagine we'd like to create an HtmlSnippet that appears on the home page of our website. Our model definition might look like this:
|
25
|
+
|
26
|
+
class HtmlSnippet < CouchRest::Model::Base
|
27
|
+
include CouchCloner
|
28
|
+
|
29
|
+
property :content
|
30
|
+
|
31
|
+
timestamps!
|
32
|
+
end
|
33
|
+
|
34
|
+
And our snippet might look like this:
|
35
|
+
|
36
|
+
homepage = HtmlSnippet.create :clone_id => "homepage", :content => "<h1>Homepage!</h1>"
|
37
|
+
|
38
|
+
OK, so that's a pretty lame bit of content, but did you notice the `clone_id`? If you're going to clone, you have to set a `clone_id` on your document first. The `clone_id` is the shared identifier between all of your clones. That's important; you'll see why in a few moments. Read on.
|
39
|
+
|
40
|
+
So now your content administrators want to use your CMS to schedule clones of this content to publish on the site several days in advance. How do we clone it?
|
41
|
+
|
42
|
+
We can create a soft clone (i.e., a new HtmlSnippet based on the original, but not yet persisted to the database) via the `clone` method:
|
43
|
+
|
44
|
+
next = homepage.clone
|
45
|
+
|
46
|
+
next.content #==> "<h1>Homepage!</h1>"
|
47
|
+
next.clone_id #==> "homepage"
|
48
|
+
next.new_record? #==> true
|
49
|
+
|
50
|
+
We can create a persisted clone with the `clone!` method:
|
51
|
+
|
52
|
+
next = homepage.clone!
|
53
|
+
|
54
|
+
next.content #==> "<h1>Homepage!</h1>"
|
55
|
+
next.clone_id #==> "homepage"
|
56
|
+
next.new_record? #==> false
|
57
|
+
|
58
|
+
Note that, when cloned, the `start` scheduling property of the clone is not copied. See the next section for details about how scheduling works.
|
59
|
+
|
60
|
+
|
61
|
+
## Scheduling (.start)
|
62
|
+
|
63
|
+
The utility of these clones is most apparent when you schedule multiple clones. The scheduling has only one constraint: each document in a clone group must have a unique date/time stamp, or `nil`.
|
64
|
+
|
65
|
+
Returning to our previous example of `next` and `homepage` HtmlSnippet clones:
|
66
|
+
|
67
|
+
homepage.start = Time.now.beginning_of_day
|
68
|
+
homepage.save #==> true
|
69
|
+
|
70
|
+
We've now scheduled the `original` clone to start at the beginning of today.
|
71
|
+
|
72
|
+
Next, we'll try to schedule the `next` clone for the same time:
|
73
|
+
|
74
|
+
next.start = Time.now.beginning_of_day
|
75
|
+
next.save #==> false
|
76
|
+
next.errors[:start] #==> "must be unique"
|
77
|
+
|
78
|
+
Since we need to create a unique timestamp, we'll schedule `next` to start tomorrow:
|
79
|
+
|
80
|
+
next.start = 1.day.from_now
|
81
|
+
next.save #==> true
|
82
|
+
next.errors.empty? #==> true
|
83
|
+
|
84
|
+
We could proceed creating and scheduling clones like this ad infinitum.
|
85
|
+
|
86
|
+
|
87
|
+
## Retrieving all the clones in a clone_id group (.map_by_clone_id/.count_by_clone_id)
|
88
|
+
|
89
|
+
To retrieve all of the clones with the same clone_id, call the `.map_by_clone_id` query proxy and provide it with a clone_id key that you want to look up:
|
90
|
+
|
91
|
+
HtmlSnippet.map_by_clone_id.key("some_clone_id").get!
|
92
|
+
|
93
|
+
If you're unfamiliar with this syntax, read up on the `couch_view` gem at http://github.com/moonmaster9000/couch_view
|
94
|
+
|
95
|
+
This will return all clones with that clone_id. You can pass all of the usual map/reduce options to this method (e.g., limit/skip):
|
96
|
+
|
97
|
+
HtmlSnippet.map_by_clone_id.key("some_clone_id").limit(10).skip(10).get!
|
98
|
+
|
99
|
+
Clones with the same clone_id will be sorted by their `_id` (this is simply how CouchDB works).
|
100
|
+
|
101
|
+
A more useful sorting option is to have the documents sorted by their `start` property. Clones with a `start` of `nil` or `""` will sort last, and will order by their `created_at` property. Thus, it's as if the clones with a `start` time are assumed to be scheduled at time `infinity + created_at`. Pretty cool, right?
|
102
|
+
|
103
|
+
To get all the clones with the same `clone_id` sorted in this order, call `map_by_clone_id_and_start`:
|
104
|
+
|
105
|
+
HtmlSnippet.map_by_clone_id_and_start("some_clone_id")
|
106
|
+
|
107
|
+
This will return a query proxy with a startkey of `["some_clone_id"]`, and an endkey of `["some_clone_id", {:end => true}]`, which will select all of the documents with clone id "some_clone_id", sorted by their "start" time.
|
108
|
+
|
109
|
+
You can pass off all of the usual map/reduce options to this view:
|
110
|
+
|
111
|
+
HtmlSnippet.map_by_clone_id_and_start("some_clone_id").limit(10).skip(1).get!
|
112
|
+
|
113
|
+
If you'd like to retrieve only a subset of this view, you can use the `:key` map/reduce option. For example, suppose we'd like to see all clones scheduled to start after now:
|
114
|
+
|
115
|
+
HtmlSnippet.map_by_clone_id_and_start("some_clone_id", Time.now)
|
116
|
+
|
117
|
+
The `endkey` will still be automatically defaulted to `["some_clone_id", {:end => nil}]`
|
118
|
+
|
119
|
+
Lastly, you can find the total number of clones with the same `clone_id` by calling the `count_by_clone_id` class method on your model:
|
120
|
+
|
121
|
+
HtmlSnippet.count_by_clone_id("some_clone_id")
|
122
|
+
|
123
|
+
If you wanted to count only a subset of your clones based on their `start` time, you can use `count_by_clone_id_and_start`:
|
124
|
+
|
125
|
+
HtmlSnippet.count_by_clone_id_and_start("some_clone_id", Time.now)
|
126
|
+
|
127
|
+
Again, the `endkey` will be automatically defaulted to `["some_clone_id", {:end => nil}]`
|
128
|
+
|
129
|
+
|
130
|
+
## Retrieving the active clone by clone_id (.map_active_by_clone_id)
|
131
|
+
|
132
|
+
Now that we've created an original clone scheduled today, and a `next` clone scheduled tomorrow, let's determine which one is currently active:
|
133
|
+
|
134
|
+
HtmlSnippet.map_active_by_clone_id("homepage").get!.first.content #==> "<h1>this is awesome</h1>"
|
135
|
+
|
136
|
+
The `map_active_by_clone_id` method accepts a `clone_id` (in our case a `label`), and returns a query proxy that will return either zero or one results (zero if no currently active `HtmlSnippet` is found with that label, otherwise, one for the currently active `HtmlSnippet`).
|
137
|
+
|
138
|
+
|
139
|
+
## Retrieving clones scheduled into the future (.map_future_by_clone_id)
|
140
|
+
|
141
|
+
We can get a list of the future clones by label via the `map_future_by_clone_id` method:
|
142
|
+
|
143
|
+
past = HtmlSnippet.create :clone_id => "homepage", :start => 1.day.ago
|
144
|
+
next = HtmlSnippet.create :clone_id => "homepage", :start => 1.day.from_now
|
145
|
+
|
146
|
+
HtmlSnippet.map_future_by_clone_id("homepage").get!
|
147
|
+
#==> returns the homepage snippet "next" that starts one day from now
|
148
|
+
|
149
|
+
This is essentially a shortcut for:
|
150
|
+
|
151
|
+
HtmlSnippet.map_by_clone_id_and_start("homepage", Time.now)
|
152
|
+
|
153
|
+
If we create a clone with a `start` of `nil`, they will show up sorted at the end of `map_future_by_clone_id`:
|
154
|
+
|
155
|
+
future = next.clone! #==> remember, on clone, the `start` property is not copied
|
156
|
+
future.start.should == nil
|
157
|
+
future.save
|
158
|
+
|
159
|
+
HtmlSnippet.map_future_by_clone_id("homepage").get!
|
160
|
+
#==> would return an array consisting of the `next` clone followed by the `future` clone
|
161
|
+
|
162
|
+
If there are multiple clones with a start of `nil`, they will sort by their `created_at` timestamp.
|
163
|
+
|
164
|
+
We also provide a method for counting the number of active and future clones in a given clone_id group:
|
165
|
+
|
166
|
+
HtmlSnippet.count_future_by_clone_id("some_clone_id").get!
|
167
|
+
|
168
|
+
|
169
|
+
## Retrieving past clones (.map_past_by_clone_id)
|
170
|
+
|
171
|
+
You might find it useful to retrieve only the clones scheduled in the past. You can use the `map_past_by_clone_id` method:
|
172
|
+
|
173
|
+
HtmlSnippet.map_past_by_clone_id("some_clone_id").get!
|
174
|
+
|
175
|
+
They will be ordered by their start date.
|
176
|
+
|
177
|
+
You can also count the number of past clones via the `count_past_by_clone_id`:
|
178
|
+
|
179
|
+
HtmlSnippet.count_past_by_clone_id("some_clone_id").get!
|
180
|
+
|
181
|
+
|
182
|
+
## Retreiving the list of currently used clone_ids (.map_clone_ids)
|
183
|
+
|
184
|
+
You can retrieve an array of all of the `clone_id`'s in use by calling the `map_clone_ids` method on your model:
|
185
|
+
|
186
|
+
HtmlSnippet.database.recreate!
|
187
|
+
HtmlSnippet.create :clone_id => "homepage"
|
188
|
+
HtmlSnippet.create :clone_id => "contact_us"
|
189
|
+
HtmlSnippet.create :clone_id => "news"
|
190
|
+
|
191
|
+
HtmlSnippet.map_clone_ids.get!['rows'].map {|row| row['key']}
|
192
|
+
#==> ["contact_us", "homepage", "news"]
|
193
|
+
|
194
|
+
You can use all of the map/reduce options you're used to (e.g., limit/skip):
|
195
|
+
|
196
|
+
HtmlSnippet.map_clone_ids.limit(1).skip(1).get!['rows'].map {|row| row['key']}
|
197
|
+
#==> ["homepage"]
|
198
|
+
|
199
|
+
You can also get a count of all clone_ids:
|
200
|
+
|
201
|
+
HtmlSnippet.count_clone_ids!
|
202
|
+
#==> 3
|
203
|
+
|
204
|
+
|
205
|
+
## Retreiving the clone created farthest in the future for a clone_id group (.map_last_future_by_clone_id)
|
206
|
+
|
207
|
+
If you'd like to retrieve the latest clone within a clone group, you could of course call `future_clones_by_clone_id` and then call `last` on the resulting array - however, that would be quite silly and idiotically inefficiant. So, instead, call `last_future_clone_by_clone_id`:
|
208
|
+
|
209
|
+
snippet_1 = HtmlSnippet.create :clone_id => "snippety", :start => Time.now
|
210
|
+
snippet_2 = HtmlSnippet.create :clone_id => "snippety", :start => 1000.years.from_now
|
211
|
+
|
212
|
+
HtmlSnippet.map_last_future_by_clone_id("snippety").get!.first.should == snippet_2
|
213
|
+
|
214
|
+
After creating these two snippet's, calling `HtmlSnippet.last_future_clone_by_clone_id "snippety"` would return `snippet_2`. However, if we create another "snippety" snippet without a `start` date:
|
215
|
+
|
216
|
+
snippet_3 = HtmlSnippet.create :clone_id => "snippety"
|
217
|
+
|
218
|
+
HtmlSnippet.map_last_future_by_clone_id("snippety").get!.first.should == snippet_3
|
219
|
+
|
220
|
+
Then calling `HtmlSnippet.last_future_clone_by_clone_id "snippety"` would return `snippet3`. Basically, you can imagine clones with a null start date or an empty string start date to have a start scheduled for `infinity + created_at`; in other words, they sort at the end of the map of clones in a clone_id group, and if there are multiple clones without a start date, then they sort by created at (still at the end of the map).
|
221
|
+
|
222
|
+
|
223
|
+
## CouchPublish Integration
|
224
|
+
|
225
|
+
The `couch_cloner` gem integrates nicely with the `couch_publish` gem.
|
226
|
+
|
227
|
+
If you include `CouchCloner` into a gem that already includes `CouchPublish`, then you can use `published` and `unpublished` query modifiers on your query proxies:
|
228
|
+
|
229
|
+
class HtmlSnippet < CouchRest::Model::Base
|
230
|
+
include CouchPublish
|
231
|
+
include CouchCloner
|
232
|
+
|
233
|
+
# etc...
|
234
|
+
end
|
235
|
+
|
236
|
+
HtmlSnippet.map_by_clone_id.key("some-clone-id").published.get!
|
237
|
+
HtmlSnippet.count_by_clone_id.key("some-clone-id").unpublished.get!
|
238
|
+
HtmlSnippet.map_active_by_clone_id("some-clone-id").published.get!.first
|
239
|
+
HtmlSnippet.map_by_clone_id_and_start("some_clone_id")
|
240
|
+
HtmlSnippet.map_active_and_future_clones_by_clone_id("some-clone-id").unpublished.get!.first
|
241
|
+
HtmlSnippet.map_last_future_by_clone_id("some-clone-id").published.get!.first
|
242
|
+
HtmlSnippet.clone_ids.unpublished.get!
|
243
|
+
HtmlSnippet.count_clone_ids.published.get!
|
244
|
+
|
245
|
+
|
246
|
+
## CouchVisible Integration
|
247
|
+
|
248
|
+
The `couch_cloner` gem integrates nicely with the `couch_visible` gem.
|
249
|
+
|
250
|
+
If you include `CouchCloner` into a gem that already includes `CouchVisible`, then you can pass `:shown => true` and `:hidden => true` options to your `CouchCloner` query methods:
|
251
|
+
|
252
|
+
|
253
|
+
class HtmlSnippet < CouchRest::Model::Base
|
254
|
+
include CouchVisible
|
255
|
+
include CouchCloner
|
256
|
+
|
257
|
+
# etc...
|
258
|
+
end
|
259
|
+
|
260
|
+
HtmlSnippet.map_by_clone_id.key("some-clone-id").shown.get!
|
261
|
+
HtmlSnippet.count_by_clone_id.key("some-clone-id").hidden.get!
|
262
|
+
HtmlSnippet.map_active_by_clone_id("some-clone-id").shown.get!.first
|
263
|
+
HtmlSnippet.map_by_clone_id_and_start("some_clone_id")
|
264
|
+
HtmlSnippet.map_active_and_future_clones_by_clone_id("some-clone-id").hidden.get!.first
|
265
|
+
HtmlSnippet.map_last_future_by_clone_id("some-clone-id").shown.get!.first
|
266
|
+
HtmlSnippet.clone_ids.hidden.get!
|
267
|
+
HtmlSnippet.count_clone_ids.shown.get!
|
268
|
+
|
269
|
+
|
270
|
+
## CouchPublish and CouchVisible Integration
|
271
|
+
|
272
|
+
If you include `CouchCloner` into a gem that already includes both `CouchVisible` and `CouchPublish`, then you can, of course, mix and match `unpublished`, `published`, `shown`, and `hidden` query modifiers in your `CouchCloner` query methods:
|
273
|
+
|
274
|
+
class HtmlSnippet < CouchRest::Model::Base
|
275
|
+
include CouchPublish
|
276
|
+
include CouchVisible
|
277
|
+
include CouchCloner
|
278
|
+
|
279
|
+
# etc...
|
280
|
+
end
|
281
|
+
|
282
|
+
HtmlSnippet.map_by_clone_id.key("some-clone-id").shown.published.get!
|
283
|
+
HtmlSnippet.count_by_clone_id.key("some-clone-id").hidden.get!
|
284
|
+
HtmlSnippet.map_active_by_clone_id("some-clone-id").shown.get!.first
|
285
|
+
HtmlSnippet.map_by_clone_id_and_start("some_clone_id")
|
286
|
+
HtmlSnippet.map_active_and_future_clones_by_clone_id("some-clone-id").hidden.published.get!.first
|
287
|
+
HtmlSnippet.map_last_future_by_clone_id("some-clone-id").shown.get!.first
|
288
|
+
HtmlSnippet.clone_ids.hidden.get!
|
289
|
+
HtmlSnippet.count_clone_ids.shown.unpublished.get!
|
290
|
+
|
291
|
+
## PUBLIC DOMAIN
|
292
|
+
|
293
|
+
This software is public domain. By contributing to it, you agree to let your code contribution enter the public domain.
|
metadata
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: couch_cloner
|
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-08-24 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: 25
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
- 0
|
74
|
+
- 3
|
75
|
+
version: 0.0.3
|
76
|
+
type: :development
|
77
|
+
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: couch_visible
|
80
|
+
prerelease: false
|
81
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
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
|
108
|
+
prerelease: false
|
109
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - "="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 21
|
115
|
+
segments:
|
116
|
+
- 1
|
117
|
+
- 0
|
118
|
+
- 1
|
119
|
+
version: 1.0.1
|
120
|
+
type: :runtime
|
121
|
+
version_requirements: *id007
|
122
|
+
- !ruby/object:Gem::Dependency
|
123
|
+
name: couchrest_model
|
124
|
+
prerelease: false
|
125
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ~>
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
hash: 23
|
131
|
+
segments:
|
132
|
+
- 1
|
133
|
+
- 0
|
134
|
+
- 0
|
135
|
+
version: 1.0.0
|
136
|
+
type: :runtime
|
137
|
+
version_requirements: *id008
|
138
|
+
- !ruby/object:Gem::Dependency
|
139
|
+
name: recloner
|
140
|
+
prerelease: false
|
141
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ~>
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
hash: 25
|
147
|
+
segments:
|
148
|
+
- 0
|
149
|
+
- 1
|
150
|
+
- 1
|
151
|
+
version: 0.1.1
|
152
|
+
type: :runtime
|
153
|
+
version_requirements: *id009
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: couch_view
|
156
|
+
prerelease: false
|
157
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
159
|
+
requirements:
|
160
|
+
- - ~>
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
hash: 25
|
163
|
+
segments:
|
164
|
+
- 0
|
165
|
+
- 0
|
166
|
+
- 3
|
167
|
+
version: 0.0.3
|
168
|
+
type: :runtime
|
169
|
+
version_requirements: *id010
|
170
|
+
description: Create clones of CouchDB documents, and schedule them for publication.
|
171
|
+
email: moonmaster9000@gmail.com
|
172
|
+
executables: []
|
173
|
+
|
174
|
+
extensions: []
|
175
|
+
|
176
|
+
extra_rdoc_files: []
|
177
|
+
|
178
|
+
files:
|
179
|
+
- lib/couch_cloner/clone.rb
|
180
|
+
- lib/couch_cloner/couch_cloner.rb
|
181
|
+
- lib/couch_cloner/maps/by_clone_id_and_start_time.rb
|
182
|
+
- lib/couch_cloner/query.rb
|
183
|
+
- lib/couch_cloner/scheduling.rb
|
184
|
+
- lib/couch_cloner.rb
|
185
|
+
- VERSION
|
186
|
+
- readme.markdown
|
187
|
+
- couch_cloner.gemspec
|
188
|
+
homepage: http://github.com/moonmaster9000/couch_cloner
|
189
|
+
licenses: []
|
190
|
+
|
191
|
+
post_install_message:
|
192
|
+
rdoc_options: []
|
193
|
+
|
194
|
+
require_paths:
|
195
|
+
- lib
|
196
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
197
|
+
none: false
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
hash: 3
|
202
|
+
segments:
|
203
|
+
- 0
|
204
|
+
version: "0"
|
205
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
206
|
+
none: false
|
207
|
+
requirements:
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
hash: 3
|
211
|
+
segments:
|
212
|
+
- 0
|
213
|
+
version: "0"
|
214
|
+
requirements: []
|
215
|
+
|
216
|
+
rubyforge_project:
|
217
|
+
rubygems_version: 1.8.5
|
218
|
+
signing_key:
|
219
|
+
specification_version: 3
|
220
|
+
summary: Clone and schedule CouchDB documents
|
221
|
+
test_files: []
|
222
|
+
|