memories 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,9 @@
1
1
  module Memories
2
2
  class Attachment #:nodoc:
3
- def initialize(string)
4
- @string = string
3
+ def initialize(data)
4
+ @data = data
5
5
  end
6
6
 
7
- def read; @string; end
7
+ def read; @data; end
8
8
  end
9
9
  end
data/lib/memories/base.rb CHANGED
@@ -7,6 +7,7 @@ module Memories
7
7
  end
8
8
 
9
9
  base.before_update :add_version_attachment
10
+ base.after_create :decode_attachments
10
11
  base.after_update :decode_attachments
11
12
  base.send :extend, ClassMethods
12
13
  end
@@ -56,6 +57,46 @@ module Memories
56
57
  end
57
58
  end
58
59
 
60
+ # Returns true if self is set up to remember attachments. False otherwise.
61
+ def remember_attachments?
62
+ @remember_attachments ? true : false
63
+ end
64
+
65
+ # Returns a list of attachment patterns for versioning. The list may contain
66
+ # strings, denoting the names of attachments to version, but it may
67
+ # also contain regular expressions, indicating that attachments
68
+ # with matching names should be versioned.
69
+ def remember_attachments; @remember_attachments || []; end
70
+
71
+ # If you'd like to version attachments, simply call this macro in your
72
+ # class definition:
73
+ #
74
+ # class MyDoc < CouchRest::Model::Base
75
+ # use_database MY_DB
76
+ # include Memories
77
+ #
78
+ # remember_attachments!
79
+ # end
80
+ #
81
+ # If you only want specific attachments versioned, pass
82
+ # strings and/or regular expressions to this macro. Any attachments
83
+ # with matching names will be versioned.
84
+ #
85
+ # class HtmlPage < CouchRest::Model::Base
86
+ # use_database MY_DB
87
+ # include Memories
88
+ #
89
+ # remember_attachments! "image.png", %r{stylesheets/.*}
90
+ # end
91
+ #
92
+ def remember_attachments!(*attachment_names)
93
+ if attachment_names.empty?
94
+ @remember_attachments = [/.*/]
95
+ else
96
+ @remember_attachments = attachment_names
97
+ end
98
+ end
99
+
59
100
  def remember_properties #:nodoc
60
101
  @remember_properties ||= nil
61
102
  end
@@ -75,6 +116,17 @@ module Memories
75
116
 
76
117
  VERSION_REGEX = /(?:rev-)?(\d+)-[a-zA-Z0-9]+/
77
118
 
119
+ # Returns a list of attachments it should remember.
120
+ def attachments_to_remember
121
+ return [] unless self.class.remember_attachments?
122
+ (self['_attachments'] || {}).keys.reject do |a|
123
+ a.match(VERSION_REGEX) ||
124
+ !(self.class.remember_attachments.map { |attachment_name_pattern|
125
+ a.match attachment_name_pattern
126
+ }.inject(false) {|b, sum| sum || b})
127
+ end
128
+ end
129
+
78
130
  # Revert the document to a specific version and save.
79
131
  # You can provide either a complete revision number ("1-u54abz3948302sjjej3jej300rj", or "rev-1-u54abz3948302sjjej3jej300rj")
80
132
  # or simply a number (e.g, 1, 4, 100, etc.).
@@ -128,7 +180,7 @@ module Memories
128
180
  # For example, suppose my doc has 5 versions.
129
181
  # my_doc.version_id 4 #==> "rev-4-74fj838r838fhjkdfklasdjrieu4839493"
130
182
  def version_id(version_num)
131
- self["_attachments"].keys.sort {|a,b| version_number(a) <=> version_number(b)}[version_num - 1] if self["_attachments"]
183
+ self["_attachments"].keys.select {|a| a.match /^rev-#{version_num}-.*$/}.first if self["_attachments"]
132
184
  end
133
185
 
134
186
  # Retrieve the version number, given a revision id.
@@ -191,18 +243,29 @@ module Memories
191
243
  version = match[1].to_i
192
244
  end
193
245
 
194
- if properties = JSON.parse(read_attachment(version_id version))
195
- if revert_type == :soft
196
- self.update_attributes_without_saving properties
197
- elsif revert_type == :hard
198
- self.update_attributes properties
246
+ if properties = JSON.parse(self.read_attachment(version_id version))
247
+ revert_attachments properties
248
+ self.update_attributes_without_saving properties
249
+ self.save if revert_type == :hard
250
+ end
251
+ end
252
+
253
+ def revert_attachments(properties)
254
+ if versioned_attachments = properties.delete('attachment_memories')
255
+ versioned_attachments['versioned_attachments'].each do |name, attrs|
256
+ attachment = { :name => name, :content_type => attrs['content_type'], :file => Attachment.new(Base64.decode64(attrs['data']))}
257
+ has_attachment?(name) ? self.update_attachment(attachment) : self.create_attachment(attachment)
258
+ end
259
+
260
+ self["_attachments"].keys.select {|a| !a.match(VERSION_REGEX)}.each do |attachment|
261
+ self.delete_attachment(attachment) unless versioned_attachments['known_attachments'].include?(attachment)
199
262
  end
200
263
  end
201
264
  end
202
265
 
203
266
  def add_version_attachment
204
267
  current_document_version = Attachment.new prep_for_versioning(self.database.get(self.id, :rev => self.rev)).to_json
205
-
268
+
206
269
  self.create_attachment(
207
270
  :file => current_document_version,
208
271
  :content_type => "application/json",
@@ -211,16 +274,45 @@ module Memories
211
274
  end
212
275
 
213
276
  def prep_for_versioning(doc)
277
+ versioned_doc = doc.dup
278
+ strip_unversioned_properties versioned_doc
279
+ add_attachment_memories versioned_doc if self.class.remember_attachments?
280
+ versioned_doc
281
+ end
282
+
283
+ def add_attachment_memories(doc)
284
+ doc['attachment_memories'] = {
285
+ 'versioned_attachments' => base64_encoded_attachments_to_remember,
286
+ 'known_attachments' => (self.database.get(self.id, :rev => self.rev)["_attachments"] || {}).keys.select {|a| !a.match(VERSION_REGEX)}
287
+ }
288
+ end
289
+
290
+ def base64_encoded_attachments_to_remember
291
+ encoded_attachments = {}
292
+ attachments_to_remember.each do |a|
293
+ attachment_data = self.read_attachment(a) rescue nil
294
+ if attachment_data
295
+ encoded_attachments[a] = {
296
+ :content_type => self['_attachments'][a]['content_type'],
297
+ :data => Base64.encode64(attachment_data)
298
+ }
299
+ end
300
+ end
301
+ encoded_attachments
302
+ end
303
+
304
+ def strip_unversioned_properties(doc)
214
305
  if self.class.remember_properties.nil?
215
- doc.dup.delete_if {|k,v| self.class.forget_properties.include? k}
306
+ doc.delete_if {|k,v| self.class.forget_properties.include? k}
216
307
  else
217
- doc.dup.delete_if {|k,v| !self.class.remember_properties.include?(k)}
218
- end
308
+ doc.delete_if {|k,v| !self.class.remember_properties.include?(k)}
309
+ end
219
310
  end
220
311
 
312
+ # why is this necessary? Because couchrest destructively base64 encodes all attachments in your document.
221
313
  def decode_attachments
222
314
  self["_attachments"].each do |attachment_id, attachment_properties|
223
- attachment_properties["data"] = Base64.decode64 attachment_properties["data"] if attachment_properties["data"]
224
- end
315
+ self["_attachments"][attachment_id]["data"] = Base64.decode64 attachment_properties["data"] if attachment_properties["data"]
316
+ end if self["_attachments"]
225
317
  end
226
318
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memories
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 3
10
- version: 0.2.3
9
+ - 4
10
+ version: 0.2.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matt Parker
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-11 00:00:00 -04:00
18
+ date: 2010-10-31 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency