acts_as_versionable 0.5.0 → 0.5.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.
@@ -1,28 +1,29 @@
1
1
  = Acts As Versionable
2
2
 
3
- Minimalist versionable engine for rails > 3
4
- Maintains versions in same table, just adding two new fields
3
+ Minimalist versionable engine for rails > 3
5
4
 
6
-
5
+ Maintains versions in same table, just adding two new fields
7
6
 
8
7
  === Installation
9
8
 
10
9
  gem 'acts_as_versionable'
11
10
 
12
- add two fields to your model
11
+ add two fields to your model
13
12
 
14
13
  version_number:integer
15
14
  version_id:integer
16
15
 
16
+ **Sample migration**
17
+
17
18
  class ActsAsVersionableDocuments < ActiveRecord::Migration
18
19
  def self.up
19
- add_column :documents, :version_number, :default => 0
20
- add_column :documents, :version_id, :default => null
21
-
22
- # optional indexes
23
- add_index :documents, :version_number, :name => "index_documents_on_version_number"
24
- add_index :documents, :version_id, :name => "index_documents_on_version_id"
25
- # optional unique :id, :version_number
20
+ add_column :documents, :version_number, :default => 0
21
+ add_column :documents, :version_id, :default => null
22
+
23
+ # optional indexes
24
+ add_index :documents, :version_number, :name => "index_documents_on_version_number"
25
+ add_index :documents, :version_id, :name => "index_documents_on_version_id"
26
+ # optional unique :id, :version_number
26
27
  end
27
28
 
28
29
  def self.down
@@ -30,17 +31,17 @@
30
31
  remove_column :documents, :version_id
31
32
  end
32
33
  end
33
-
34
+
34
35
  === Example
35
36
 
36
37
  class Document < ActiveRecord::Base
37
38
  acts_as_versionable :limit => 3
38
39
  end
39
40
 
40
- # use scope to get top versions
41
- documents = Document.last_versions => scope that return top versions
41
+ # use scope to get top versions
42
+ documents = Document.last_versions => scope that return most recent versions
42
43
 
43
- # cerate first version
44
+ # create first version
44
45
  document = Document.create(:title => 'title', :body => 'body')
45
46
  document.version => 1
46
47
  document.last_version => 1
@@ -56,14 +57,45 @@
56
57
 
57
58
  # revert to version 1
58
59
  document.revert_to_version(1) => #<Document ...>
59
- document.version => 3 # after revert a new version is created with content of version 1
60
+ document.version => 3 # after revert a new version is created with content of version 1
60
61
  document.title => 'title'
61
-
62
- # get a version
63
- version2 = document.get_version 2 => #<Document ... version_number => 2>
64
- version2.version => 2
65
- version2.title => 'new title"
62
+
63
+ # get a version
64
+ version2 = document.get_version 2 => #<Document ... version_number => 2>
65
+ version2.version => 2
66
+ version2.title => 'new title"
66
67
  version2.last_version => 4
67
68
 
69
+ # you can't edit a version
70
+ version2 = document.get_version 2
71
+ version2.title = "new version"
72
+ version2.save => raise NonEditableVersionError
73
+
74
+ version2.versionable? => false
75
+
76
+ # to edit a version you need get the editable_version
77
+ editable = version2.editable_version
78
+ editable.versionable? => true
79
+ editable.title = "new"
80
+ editable.save
81
+ editable.last_version => 5
82
+
83
+ == How to contribute
84
+
85
+ If you find what you might think is a bug:
86
+
87
+ 1. Check the GitHub issue tracker to see if anyone else has had the same issue.
88
+ http://github.com/csegura/acts_as_versionable/issues/
89
+ 2. If you don't see anything, create an issue with information on how to reproduce it.
90
+
91
+ If you want to contribute an enhancement or a fix:
92
+
93
+ 1. Fork the project on github.
94
+ http://github.com/csegura/acts_as_versionable/
95
+ 2. Make your changes with tests.
96
+ 3. Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
97
+ 4. Send a pull request.
98
+
99
+ Copyright ©2012 Carlos Segura, released under the MIT license
68
100
 
69
101
 
@@ -4,6 +4,8 @@ module ActsAsVersionable
4
4
 
5
5
  class NoSuchVersionError < Exception
6
6
  end
7
+ class NonEditableVersionError < Exception
8
+ end
7
9
 
8
10
  extend ActiveSupport::Concern
9
11
 
@@ -16,6 +18,7 @@ module ActsAsVersionable
16
18
  self.max_versions = (options[:max_versions] || 10)
17
19
 
18
20
  after_save :create_new_version
21
+ before_validation :versionable_validation
19
22
 
20
23
  has_many :internal_versions,
21
24
  :class_name => self.name,
@@ -35,7 +38,7 @@ module ActsAsVersionable
35
38
  module InstanceMethods
36
39
  def revert_to_version(number)
37
40
  version = get_version number
38
- editable = last_version_editable
41
+ editable = editable_version
39
42
  copy_version_values version, editable
40
43
  editable.version_number = nil
41
44
  editable.version_id = nil
@@ -75,13 +78,13 @@ module ActsAsVersionable
75
78
  return 0 if versions.count == 0
76
79
  versions.first.version_number
77
80
  end
78
-
79
- private
80
-
81
+
81
82
  # return the last version editable
82
- def last_version_editable
83
+ def editable_version
83
84
  parent_version.nil? ? self : parent_version
84
- end
85
+ end
86
+
87
+ private
85
88
 
86
89
  # callback after save
87
90
  def create_new_version
@@ -105,6 +108,13 @@ module ActsAsVersionable
105
108
  columns.each {|c| to[c.name] = from[c.name] }
106
109
  to
107
110
  end
111
+
112
+ def versionable_validation
113
+ if !new_record? && !versionable?
114
+ raise NonEditableVersionError, "Can't modify versioned record. Use version.editable_version!!"
115
+ end
116
+ end
117
+
108
118
  end
109
119
 
110
120
  end
@@ -1,3 +1,3 @@
1
1
  module ActsAsVersionable
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
@@ -0,0 +1,264 @@
1
+ require 'rubygems'
2
+ gem 'activerecord'
3
+ require 'active_record'
4
+ require 'test/unit'
5
+
6
+ #require "#{File.dirname(__FILE__)}/../init"
7
+ require File.join(File.dirname(__FILE__), '../lib', 'acts_as_versionable')
8
+
9
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
10
+
11
+ def setup_db
12
+ ActiveRecord::Schema.define(:version => 1) do
13
+ create_table :documents do |t|
14
+ t.string :title
15
+ t.text :body
16
+ t.integer :user_id
17
+ t.integer :version_number
18
+ t.integer :version_id
19
+ t.timestamps
20
+ end
21
+ end
22
+ end
23
+
24
+ def teardown_db
25
+ ActiveRecord::Base.connection.tables.each do |table|
26
+ ActiveRecord::Base.connection.drop_table(table)
27
+ end
28
+ end
29
+
30
+ class Document < ActiveRecord::Base
31
+ acts_as_versionable
32
+ end
33
+
34
+ class VersionableTest < Test::Unit::TestCase
35
+ def setup
36
+ setup_db
37
+
38
+ (1..3).each do |m|
39
+ document = Document.create!(:title => m.to_s, :body => m.to_s)
40
+ (1..m*2).each do |v|
41
+ document.title = v.to_s
42
+ document.body = v.to_s
43
+ document.save
44
+ end
45
+ end
46
+ end
47
+
48
+ def teardown
49
+ teardown_db
50
+ end
51
+
52
+ def test_documents
53
+ assert_equal 18, Document.all.count
54
+ #Document.last_versions.each do |d|
55
+ # p "title: #{d.title} versions: #{d.last_version}"
56
+ # p "#{d.versions.map &:title}"
57
+ #end
58
+ end
59
+
60
+ def test_if_class_methods_present
61
+ [:last_versions, :get_versionable].each do |method|
62
+ assert_equal true, Document.respond_to?(method)
63
+ end
64
+ end
65
+
66
+ def test_if_mixed_methods_present
67
+ document = Document.first
68
+ [:versions, :get_version, :revert_to_version,
69
+ :last_version, :versionable?, :editable_version,
70
+ :internal_versions, :parent_version].each do |method|
71
+ assert_equal true, document.respond_to?(method)
72
+ end
73
+ end
74
+
75
+ def test_last_versions
76
+ documents = Document.last_versions
77
+ assert_equal 3, documents.count
78
+ end
79
+
80
+ def test_initial_versions_of_the_documents
81
+ documents = Document.last_versions
82
+
83
+ documents.each do |d|
84
+ assert_equal nil, d.version_number
85
+ assert_equal nil, d.version_id
86
+ end
87
+ end
88
+
89
+ def test_get_versionable
90
+ document = Document.get_versionable(1,2).first
91
+ assert_equal 2, document.version_number
92
+ assert_equal '1', document.title
93
+ end
94
+
95
+ def test_versions_created
96
+ document = Document.create(:title => "A", :body => "AAAA")
97
+ assert_equal 1, document.last_version
98
+ assert_equal 1, document.version
99
+ document.title = "B"
100
+ document.save
101
+ assert_equal 2, document.version
102
+ end
103
+
104
+ def test_last_version
105
+ documents = Document.last_versions
106
+
107
+ assert_equal 3, documents[0].last_version
108
+ assert_equal 5, documents[1].last_version
109
+ assert_equal 7, documents[2].last_version
110
+ end
111
+
112
+ def test_version_change_to_2
113
+ document = Document.last_versions.first
114
+ assert_not_nil document
115
+
116
+ assert_equal '2', document.title
117
+ assert_equal 3, document.last_version
118
+
119
+ document.update_attributes(:title => '4', :body => '4')
120
+
121
+ assert_equal 4, document.last_version
122
+ assert_equal '4', document.title
123
+ assert_equal '4', document.body
124
+ end
125
+
126
+ def test_revert_to_version
127
+ document = Document.last_versions.first
128
+ assert_not_nil document
129
+
130
+ document.update_attributes(:title => '4', :body => '4')
131
+ assert_equal 4, document.last_version
132
+
133
+ document = document.revert_to_version(1)
134
+
135
+ assert_equal 5, document.last_version
136
+ assert_equal '1', document.title
137
+ assert_equal '1', document.body
138
+
139
+ document = document.revert_to_version(4)
140
+
141
+ assert_equal 6, document.last_version
142
+ assert_equal '4', document.title
143
+ assert_equal '4', document.body
144
+
145
+ assert_raise ActsAsVersionable::NoSuchVersionError do
146
+ document.revert_to_version(10)
147
+ end
148
+ end
149
+
150
+
151
+ # def test_new_from_version
152
+ # article = Article.first
153
+ # assert_not_nil article
154
+ #
155
+ # dummy = article.new_from_version 1
156
+ #
157
+ # article.revert_to(1)
158
+ # assert_equal dummy.title, article.title
159
+ # assert_equal dummy.body, article.body
160
+ # end
161
+
162
+ def test_versions
163
+ document = Document.last_versions.first
164
+ assert_not_nil document
165
+
166
+ assert_equal 3, document.versions.count
167
+
168
+ document = document.get_version(2)
169
+ assert_equal 3, document.versions.count
170
+ end
171
+
172
+ def test_get_version
173
+ document = Document.last_versions.first
174
+ assert_not_nil document
175
+
176
+ first = document.versions[1]
177
+ one = document.get_version(2)
178
+
179
+ assert_equal first.title, one.title
180
+ assert_equal first.body, one.body
181
+ end
182
+
183
+ def test_get_versions
184
+ document = Document.last_versions.first
185
+ assert_not_nil document
186
+
187
+ version2 = document.get_version 2
188
+ assert_equal 2, version2.version
189
+ end
190
+
191
+ def test_max_versions
192
+ document = Document.last_versions.last
193
+ (1..10).each do |v|
194
+ document.title = v.to_s
195
+ document.save
196
+ end
197
+ assert_equal 10, document.versions.count
198
+ end
199
+
200
+ def test_dependent_destroy
201
+ Document.last_versions.destroy_all
202
+ assert_equal [], Document.all
203
+ end
204
+
205
+ def test_modify_versioned
206
+ document = Document.last_versions.first
207
+ assert_not_nil document
208
+
209
+ assert_equal 3, document.last_version
210
+
211
+ version2 = document.get_version 2
212
+ version2.title = "version2 new"
213
+
214
+ assert_equal false, version2.versionable?
215
+
216
+ assert_raise ActsAsVersionable::NonEditableVersionError do
217
+ version2.save
218
+ end
219
+
220
+ assert_equal 2, version2.version
221
+ assert_equal "version2 new", version2.title
222
+
223
+ assert_equal 3, document.last_version
224
+ end
225
+
226
+ def test_readme
227
+ # cerate first version
228
+ document = Document.create(:title => 'title', :body => 'body')
229
+ assert_equal 1, document.version
230
+ assert_equal 1, document.last_version
231
+
232
+ # modify
233
+ document.title = 'new title'
234
+ document.save
235
+
236
+ # second version was created
237
+ assert_equal 2, document.version
238
+ assert_equal 2, document.last_version
239
+ assert_equal 2, document.versions.count
240
+
241
+ # revert to previous version
242
+ document.revert_to_version(1)
243
+ assert_equal "title", document.title
244
+ # a new version also is created
245
+ assert_equal 3, document.version
246
+
247
+ # get a version
248
+ document = document.get_version(2)
249
+ assert_equal 2, document.version
250
+ assert_equal "new title", document.title
251
+
252
+ # revert to a version
253
+ document = document.revert_to_version(2)
254
+ assert_equal "new title", document.title
255
+ assert_equal 4, document.version
256
+
257
+ version1 = document.get_version(1)
258
+ assert_equal 1, version1.version
259
+ assert_equal 4, version1.last_version
260
+
261
+ end
262
+
263
+ end
264
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_versionable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -26,6 +26,7 @@ files:
26
26
  - acts_as_versionable.gemspec
27
27
  - lib/acts_as_versionable.rb
28
28
  - lib/acts_as_versionable/version.rb
29
+ - test/acts_as_versionable_test.rb
29
30
  homepage: ''
30
31
  licenses: []
31
32
  post_install_message:
@@ -50,4 +51,5 @@ rubygems_version: 1.8.10
50
51
  signing_key:
51
52
  specification_version: 3
52
53
  summary: Minimalist engine for versions
53
- test_files: []
54
+ test_files:
55
+ - test/acts_as_versionable_test.rb