couch_cloner 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,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
@@ -0,0 +1,7 @@
1
+ require 'couchrest_model'
2
+ require 'couch_view'
3
+ require 'couch_cloner/couch_cloner'
4
+ require 'couch_cloner/clone'
5
+ require 'couch_cloner/scheduling'
6
+ require 'couch_cloner/query'
7
+ require 'couch_cloner/maps/by_clone_id_and_start_time'
@@ -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,8 @@
1
+ module CouchCloner
2
+ def self.included(base)
3
+ base.send :include, CouchView unless base.ancestors.include?(CouchView)
4
+ base.send :include, CouchCloner::Clone
5
+ base.send :include, CouchCloner::Scheduling
6
+ base.send :include, CouchCloner::Query
7
+ end
8
+ 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
@@ -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
+