memories 0.2.1 → 0.2.2

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