couch_cloner 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|