memories 0.2.1 → 0.2.2

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.
data/README.markdown CHANGED
@@ -34,6 +34,34 @@ Here's how basic versioning works. Every time you save your document, you get a
34
34
  b.name #==> "2001"
35
35
  b.current_version #==> 3
36
36
 
37
+ If you'd like to exclude certain properties from versioning, use the #forget class method:
38
+
39
+ class Book < CouchRest::Model::Base
40
+ include Memories
41
+ use_database SOME_DATABASE
42
+
43
+ forget :notes
44
+
45
+ property :name
46
+ property :notes
47
+ view_by :name
48
+ end
49
+
50
+ b = Book.create :name => "2001", :notes => "creating the book."
51
+ b.current_version #==> 1
52
+ b.name = "2001: A Space Odyssey"
53
+ b.notes += "updating the title. might ship today. 9/2/2010. MKP"
54
+ b.save
55
+ b.current_version #==> 2
56
+ b.previous_version #==> 1
57
+ p b.name #==> "2001: A Space Odyssey"
58
+ p b.notes # ==> "creating the book. updating the title. might ship today. 9/2/2010. MKP"
59
+ b.revert_to! 1
60
+ p b.name #==> "2001"
61
+ p b.notes # ==> "creating the book. updating the title. might ship today. 9/2/2010. MKP"
62
+ b.current_version #==> 3
63
+
64
+
37
65
  ###Milestones
38
66
 
39
67
  As of version 0.2.0, Memories also supports milestones. Milestones are special versions that you want to flag in some way.
data/README.rdoc ADDED
@@ -0,0 +1,111 @@
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
+ If you'd like to exclude certain properties from versioning, use the #forget class method:
38
+
39
+ class Book < CouchRest::Model::Base
40
+ include Memories
41
+ use_database SOME_DATABASE
42
+
43
+ forget :notes
44
+
45
+ property :name
46
+ property :notes
47
+ view_by :name
48
+ end
49
+
50
+ b = Book.create :name => "2001", :notes => "creating the book."
51
+ b.current_version #==> 1
52
+ b.name = "2001: A Space Odyssey"
53
+ b.notes += "updating the title. might ship today. 9/2/2010. MKP"
54
+ b.save
55
+ b.current_version #==> 2
56
+ b.previous_version #==> 1
57
+ p b.name #==> "2001: A Space Odyssey"
58
+ p b.notes # ==> "creating the book. updating the title. might ship today. 9/2/2010. MKP"
59
+ b.revert_to! 1
60
+ p b.name #==> "2001"
61
+ p b.notes # ==> "creating the book. updating the title. might ship today. 9/2/2010. MKP"
62
+ b.current_version #==> 3
63
+
64
+ === Milestones
65
+
66
+ As of version 0.2.0, Memories also supports milestones. Milestones are special versions that you want to flag in some way.
67
+ 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
68
+ they published as a milestone.
69
+
70
+ class Article < CouchRest::Model::Base
71
+ include Memories
72
+ use_database SOME_DATABASE
73
+
74
+ property :title
75
+ property :author
76
+ property :body
77
+
78
+ def publish!
79
+ # .... publishing logic
80
+ end
81
+ end
82
+
83
+ a = Article.create(
84
+ :title => "Memories gem makes versioning simple",
85
+ :author => "moonmaster9000",
86
+ :body => <<-ARTICLE
87
+ Check it out at http://github.com/moonmaster9000/memories
88
+ ARTICLE
89
+ )
90
+ a.save
91
+ a.publish!
92
+ a.current_version #==> 1
93
+ a.milestone! do
94
+ name "First publish."
95
+ notes "Passed all relevant editing. Signed off by moonmaster10000"
96
+ end
97
+
98
+ 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.
99
+ Now that we've created a milestone, let's inspect it:
100
+
101
+ a.milestones.count #==> 1
102
+ a.latest_milestone.version # ==> 1
103
+ a.latest_milestone.annotations.name ==> "First publish."
104
+ a.latest_milestone.annotations.notes ==> "Passed all relevant editing. Signed off by moonmaster 10000"
105
+
106
+ 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
107
+ at at the first milestone. How do we do that? Simple!
108
+
109
+ a.revert_to_milestone! 1
110
+
111
+ And now our document properties are back to the where they were when we first published the document.
@@ -1,5 +1,5 @@
1
1
  module Memories
2
- class Annotation < Hash
2
+ class Annotation < Hash #:nodoc:
3
3
  def method_missing(method_name, *args, &block)
4
4
  if args.empty?
5
5
  self[method_name]
@@ -1,5 +1,5 @@
1
1
  module Memories
2
- class Attachment
2
+ class Attachment #:nodoc:
3
3
  def initialize(string)
4
4
  @string = string
5
5
  end
data/lib/memories/base.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # Simply "include Memories" in your CouchRest::Model::Base derived classes to add versioning to your document.
1
2
  module Memories
2
3
  def self.included(base)
3
4
  base.property(:milestone_memories) do |milestone_memory|
@@ -7,60 +8,120 @@ module Memories
7
8
 
8
9
  base.before_update :add_version_attachment
9
10
  base.after_update :decode_attachments
11
+ base.send :extend, ClassMethods
10
12
  end
11
13
 
12
- VERSION_REGEX = /(?:rev-)?(\d+)-[a-zA-Z0-9]+/
14
+ module ClassMethods
15
+ # If you'd like to exclude certain properties from versioning, simply pass those properties
16
+ # to this method:
17
+ #
18
+ # class MyDocument < CouchRest::Model::Base
19
+ # use_database MY_DATABASE
20
+ # forget :prop1, :prop2
21
+ #
22
+ # property :prop1 #not versioned
23
+ # property :prop2 #not versioned
24
+ # property :prop3 #versioned
25
+ # end
26
+ def forget(*props)
27
+ self.forget_properties += props.map {|p| p.to_s}
28
+ end
29
+
30
+ def forget_properties #:nodoc:
31
+ @forget_properties ||= ["couchrest-type", "_id", "_rev", "_attachments", "milestone_memories"]
32
+ end
13
33
 
34
+ def forget_properties=(props) #:nodoc:
35
+ @forget_properties = props
36
+ end
37
+ end
38
+
39
+ VERSION_REGEX = /(?:rev-)?(\d+)-[a-zA-Z0-9]+/
40
+
41
+ # Revert the document to a specific version and save.
42
+ # You can provide either a complete revision number ("1-u54abz3948302sjjej3jej300rj", or "rev-1-u54abz3948302sjjej3jej300rj")
43
+ # or simply a number (e.g, 1, 4, 100, etc.).
44
+ # my_doc.revert_to! 3 # ==> would revert your document "my_doc" to version 3.
14
45
  def revert_to!(version)
15
46
  revert version, :hard
16
47
  end
17
48
 
49
+ # Same as #revert_to!, except that it doesn't save.
18
50
  def revert_to(version)
19
51
  revert version
20
52
  end
21
53
 
54
+ # Same as #rollback!, but doesn't save.
22
55
  def rollback
23
56
  self.revert_to self.previous_version
24
57
  end
25
58
 
59
+ # Revert to the previous version, and resave the document. Shortcut for:
60
+ # my_doc.revert_to! my_doc.previous_version
26
61
  def rollback!
27
62
  self.revert_to! self.previous_version
28
63
  end
29
64
 
65
+ # Revert to a given milestone and save. Milestones are stored in the .milestones array.
66
+ # Reverting to milestone "n" reverts to milestone represented in the nth element in the
67
+ # milestones array.
30
68
  def revert_to_milestone!(n)
31
69
  verify_milestone_exists n
32
70
  self.revert_to! self.milestones[n.to_i-1].version
33
71
  end
34
-
72
+
73
+ # Same as #revert_to_milestone!, except it doesn't save.
35
74
  def revert_to_milestone(n)
36
75
  verify_milestone_exists n
37
76
  self.revert_to self.milestones[n.to_i-1].version
38
77
  end
39
-
78
+
79
+ # Same as #rollback_to_latest_milestone, but doesn't save.
40
80
  def rollback_to_latest_milestone
41
81
  self.revert_to_milestone self.milestones.count
42
82
  end
43
83
 
84
+ # Reverts to the latest milestone. Shortcut for:
85
+ # my_doc.revert_to_milestone! my_doc.milestones.count
44
86
  def rollback_to_latest_milestone!
45
87
  self.revert_to_milestone! self.milestones.count
46
88
  end
47
-
89
+
90
+ # Retrieve the entire revision number, given an integer.
91
+ # For example, suppose my doc has 5 versions.
92
+ # my_doc.version_id 4 #==> "rev-4-74fj838r838fhjkdfklasdjrieu4839493"
48
93
  def version_id(version_num)
49
94
  self["_attachments"].keys.sort {|a,b| version_number(a) <=> version_number(b)}[version_num - 1] if self["_attachments"]
50
95
  end
51
96
 
97
+ # Retrieve the version number, given a revision id.
98
+ # For example,
99
+ # my_doc.version_number "rev-5-kjfldsjaiu932489023rewar" #==> 5
100
+ # my_doc.version_number "4-jkfldsjli3290843029irelajfldsa" # ==> 4
52
101
  def version_number(version_id)
53
102
  version_id.gsub(VERSION_REGEX, '\1').to_i
54
103
  end
55
104
 
105
+ # Shortcut for:
106
+ # my_doc.current_version - 1
56
107
  def previous_version
57
108
  current_version - 1
58
109
  end
59
110
 
111
+ # Returns a simple version number (integer) corresponding to the current revision.
112
+ # For example, suppose the current revision (_rev) is: "4-jkfdlsi9432943wklrejwalr94302".
113
+ # my_doc.current_version #==> 4
60
114
  def current_version
61
115
  version_number rev
62
116
  end
63
117
 
118
+ # Flag the current version as a milestone. You can optionally annotate the milestone by passing a do block to the method.
119
+ # some_article.milestone! do
120
+ # notes "Passed first round of editing."
121
+ # approved_by "Joe the editor."
122
+ # end
123
+ #
124
+ # You may annotate with whatever properties you desire. "notes" and "approved_by" were simply examples.
64
125
  def milestone!(&block)
65
126
  annotations = Memories::Annotation.new
66
127
  annotations.instance_eval(&block) if block
@@ -68,10 +129,14 @@ module Memories
68
129
  self.save
69
130
  end
70
131
 
132
+ # returns an array of all milestones. Each milestone contains a "version" property (pointing to a specific revision)
133
+ # and an "annotations" property, containing a (possible empty) hash of key/value pairs corresponding to any annotations
134
+ # the creator of the milestone decided to write.
71
135
  def milestones
72
136
  self.milestone_memories
73
137
  end
74
138
 
139
+ # Returns the metadata (version, annotations) for the latest milestone created.
75
140
  def latest_milestone
76
141
  self.milestone_memories.last
77
142
  end
@@ -109,7 +174,7 @@ module Memories
109
174
  end
110
175
 
111
176
  def prep_for_versioning(doc)
112
- doc.dup.delete_if {|k,v| ["couchrest-type", "_id", "_rev", "_attachments", "milestone_memories"].include? k}
177
+ doc.dup.delete_if {|k,v| self.class.forget_properties.include? k}
113
178
  end
114
179
 
115
180
  def decode_attachments
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: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
9
+ - 2
10
+ version: 0.2.2
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-29 00:00:00 -04:00
18
+ date: 2010-09-04 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -35,7 +35,7 @@ dependencies:
35
35
  version: 1.0.0.beta7
36
36
  type: :runtime
37
37
  version_requirements: *id001
38
- description: CouchDB has built in document versioning, but you can't rely on it for version control. This is an implementation of a version-as-attachments approach suggested by @jchris.moonmaster9000@gmail.com
38
+ description: CouchDB has built in document versioning, but you can't rely on it for version control. This is an implementation of a version-as-attachments approach created by @jchris.moonmaster9000@gmail.com
39
39
  email: moonmaster9000@gmail.com
40
40
  executables: []
41
41
 
@@ -43,7 +43,9 @@ extensions: []
43
43
 
44
44
  extra_rdoc_files:
45
45
  - README.markdown
46
+ - README.rdoc
46
47
  files:
48
+ - README.rdoc
47
49
  - lib/memories.rb
48
50
  - lib/memories/annotation.rb
49
51
  - lib/memories/attachment.rb