memories 0.2.3 → 0.2.4

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.
@@ -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