memories 0.2.0 → 0.2.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.
Files changed (3) hide show
  1. data/README.markdown +84 -0
  2. data/lib/memories/base.rb +51 -11
  3. metadata +7 -6
data/README.markdown ADDED
@@ -0,0 +1,84 @@
1
+ #Introduction
2
+
3
+ A simple gem for adding versioning to your CouchRest::Model::Base documents. When you update a document, the previous version gets
4
+ stored as an attachment on the document. This versioning strategy was originally created here: http://blog.couch.io/post/632718824/simple-document-versioning-with-couchdb
5
+
6
+ ##Installation
7
+
8
+ $ gem install memories
9
+
10
+ ##How does it work?
11
+
12
+ Just "include Memories" in your "CouchRest::Model::Base" classes and let the auto-versioning begin.
13
+
14
+ ###Basic Versioning
15
+
16
+ Here's how basic versioning works. Every time you save your document, you get a new version. You have the ability to roll back to a previous version.
17
+
18
+ class Book < CouchRest::Model::Base
19
+ include Memories
20
+ use_database SOME_DATABASE
21
+
22
+ property :name
23
+ view_by :name
24
+ end
25
+
26
+ b = Book.create :name => "2001"
27
+ b.current_version #==> 1
28
+ b.name = "2001: A Space Odyssey"
29
+ b.save
30
+ b.current_version #==> 2
31
+ b.previous_version #==> 1
32
+ b.name #==> "2001: A Space Odyssey"
33
+ b.revert_to! 1
34
+ b.name #==> "2001"
35
+ b.current_version #==> 3
36
+
37
+ ###Milestones
38
+
39
+ As of version 0.2.0, Memories also supports milestones. Milestones are special versions that you want to flag in some way.
40
+ For example, suppose you were creating a content management system, and every time someone publishes an article to the website, you want to flag the version
41
+ they published as a milestone.
42
+
43
+ class Article < CouchRest::Model::Base
44
+ include Memories
45
+ use_database SOME_DATABASE
46
+
47
+ property :title
48
+ property :author
49
+ property :body
50
+
51
+ def publish!
52
+ # .... publishing logic
53
+ end
54
+ end
55
+
56
+ a = Article.create(
57
+ :title => "Memories gem makes versioning simple",
58
+ :author => "moonmaster9000",
59
+ :body => <<-ARTICLE
60
+ Check it out at http://github.com/moonmaster9000/memories
61
+ ARTICLE
62
+ )
63
+ a.save
64
+ a.publish!
65
+ a.current_version #==> 1
66
+ a.milestone! do
67
+ name "First publish."
68
+ notes "Passed all relevant editing. Signed off by moonmaster10000"
69
+ end
70
+
71
+ Notice that we annotated our milestone; we gave it a name, and some notes. You can annotate with whatever properties you desire. The annotation do block is entirely optional.
72
+ Now that we've created a milestone, let's inspect it:
73
+
74
+ a.milestones.count #==> 1
75
+ a.latest_milestone.version # ==> 1
76
+ a.latest_milestone.annotations.name ==> "First publish."
77
+ a.latest_milestone.annotations.notes ==> "Passed all relevant editing. Signed off by moonmaster 10000"
78
+
79
+ Now, let's imagine that we've made some more edits / saves to the document, but they don't get approved. Now we want to revert to the version the document was
80
+ at at the first milestone. How do we do that? Simple!
81
+
82
+ a.revert_to_milestone! 1
83
+
84
+ And now our document properties are back to the where they were when we first published the document.
data/lib/memories/base.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Memories
2
2
  def self.included(base)
3
3
  base.property(:milestone_memories) do |milestone_memory|
4
- milestone_memory.property :version, Fixnum
4
+ milestone_memory.property :version
5
5
  milestone_memory.property :annotations, Memories::Annotation
6
6
  end
7
7
 
@@ -11,21 +11,40 @@ module Memories
11
11
 
12
12
  VERSION_REGEX = /(?:rev-)?(\d+)-[a-zA-Z0-9]+/
13
13
 
14
- def revert_to!(version=nil)
15
- version ||= previous_version
16
- if (match = version.to_s.match(VERSION_REGEX)) && match[1]
17
- version = match[1].to_i
18
- end
19
-
20
- if properties = JSON.parse(read_attachment(version_id version))
21
- self.update_attributes properties
22
- end
14
+ def revert_to!(version)
15
+ revert version, :hard
16
+ end
17
+
18
+ def revert_to(version)
19
+ revert version
20
+ end
21
+
22
+ def rollback
23
+ self.revert_to self.previous_version
24
+ end
25
+
26
+ def rollback!
27
+ self.revert_to! self.previous_version
23
28
  end
24
29
 
25
30
  def revert_to_milestone!(n)
31
+ verify_milestone_exists n
26
32
  self.revert_to! self.milestones[n.to_i-1].version
27
33
  end
28
34
 
35
+ def revert_to_milestone(n)
36
+ verify_milestone_exists n
37
+ self.revert_to self.milestones[n.to_i-1].version
38
+ end
39
+
40
+ def rollback_to_latest_milestone
41
+ self.revert_to_milestone self.milestones.count
42
+ end
43
+
44
+ def rollback_to_latest_milestone!
45
+ self.revert_to_milestone! self.milestones.count
46
+ end
47
+
29
48
  def version_id(version_num)
30
49
  self["_attachments"].keys.sort {|a,b| version_number(a) <=> version_number(b)}[version_num - 1] if self["_attachments"]
31
50
  end
@@ -45,7 +64,7 @@ module Memories
45
64
  def milestone!(&block)
46
65
  annotations = Memories::Annotation.new
47
66
  annotations.instance_eval(&block) if block
48
- self.milestone_memories << {:version => self.current_version, :annotations => annotations}
67
+ self.milestone_memories << {:version => self.rev, :annotations => annotations}
49
68
  self.save
50
69
  end
51
70
 
@@ -58,6 +77,27 @@ module Memories
58
77
  end
59
78
 
60
79
  private
80
+ def verify_milestone_exists(n)
81
+ raise StandardError, "This document does not have any milestones." if self.milestones.empty?
82
+ raise StandardError, "Unknown milestone" if n > self.milestones.count
83
+ end
84
+
85
+ def revert(version, revert_type = :soft)
86
+ raise StandardError, "Unknown revert type passed to 'revert' method. Allowed types: :soft, :hard." if revert_type != :soft && revert_type != :hard
87
+
88
+ if (match = version.to_s.match(VERSION_REGEX)) && match[1]
89
+ version = match[1].to_i
90
+ end
91
+
92
+ if properties = JSON.parse(read_attachment(version_id version))
93
+ if revert_type == :soft
94
+ self.update_attributes_without_saving properties
95
+ elsif revert_type == :hard
96
+ self.update_attributes properties
97
+ end
98
+ end
99
+ end
100
+
61
101
  def add_version_attachment
62
102
  current_document_version = Attachment.new prep_for_versioning(self.database.get(self.id, :rev => self.rev)).to_json
63
103
 
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: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 0
10
- version: 0.2.0
9
+ - 1
10
+ version: 0.2.1
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-08-28 00:00:00 -04:00
18
+ date: 2010-08-29 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -41,13 +41,14 @@ executables: []
41
41
 
42
42
  extensions: []
43
43
 
44
- extra_rdoc_files: []
45
-
44
+ extra_rdoc_files:
45
+ - README.markdown
46
46
  files:
47
47
  - lib/memories.rb
48
48
  - lib/memories/annotation.rb
49
49
  - lib/memories/attachment.rb
50
50
  - lib/memories/base.rb
51
+ - README.markdown
51
52
  has_rdoc: true
52
53
  homepage: http://github.com/moonmaster9000/memories
53
54
  licenses: []