brianjlandau-vestal_versions 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +27 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +196 -0
  5. data/Rakefile +50 -0
  6. data/VERSION +1 -0
  7. data/generators/vestal_versions/templates/initializer.rb +9 -0
  8. data/generators/vestal_versions/templates/migration.rb +28 -0
  9. data/generators/vestal_versions/vestal_versions_generator.rb +10 -0
  10. data/init.rb +1 -0
  11. data/lib/vestal_versions.rb +104 -0
  12. data/lib/vestal_versions/associations.rb +67 -0
  13. data/lib/vestal_versions/changes.rb +125 -0
  14. data/lib/vestal_versions/conditions.rb +69 -0
  15. data/lib/vestal_versions/configuration.rb +40 -0
  16. data/lib/vestal_versions/control.rb +175 -0
  17. data/lib/vestal_versions/creation.rb +85 -0
  18. data/lib/vestal_versions/deletion.rb +46 -0
  19. data/lib/vestal_versions/options.rb +45 -0
  20. data/lib/vestal_versions/reload.rb +22 -0
  21. data/lib/vestal_versions/reset.rb +28 -0
  22. data/lib/vestal_versions/reversion.rb +92 -0
  23. data/lib/vestal_versions/tagging.rb +54 -0
  24. data/lib/vestal_versions/users.rb +56 -0
  25. data/lib/vestal_versions/version.rb +76 -0
  26. data/lib/vestal_versions/versioned.rb +30 -0
  27. data/lib/vestal_versions/versions.rb +74 -0
  28. data/test/associations_test.rb +49 -0
  29. data/test/changes_test.rb +169 -0
  30. data/test/conditions_test.rb +137 -0
  31. data/test/configuration_test.rb +39 -0
  32. data/test/control_test.rb +152 -0
  33. data/test/creation_test.rb +110 -0
  34. data/test/deletion_test.rb +121 -0
  35. data/test/options_test.rb +52 -0
  36. data/test/reload_test.rb +19 -0
  37. data/test/reset_test.rb +112 -0
  38. data/test/reversion_test.rb +99 -0
  39. data/test/schema.rb +62 -0
  40. data/test/tagging_test.rb +39 -0
  41. data/test/test_helper.rb +12 -0
  42. data/test/users_test.rb +25 -0
  43. data/test/version_test.rb +61 -0
  44. data/test/versioned_test.rb +18 -0
  45. data/test/versions_test.rb +172 -0
  46. data/vestal_versions.gemspec +124 -0
  47. metadata +245 -0
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class ReloadTest < Test::Unit::TestCase
4
+ context 'Reloading a reverted model' do
5
+ setup do
6
+ @user = User.create(:name => 'Steve Richert')
7
+ first_version = @user.version
8
+ @user.update_attributes(:last_name => 'Jobs')
9
+ @last_version = @user.version
10
+ @user.revert_to(first_version)
11
+ end
12
+
13
+ should 'reset the version number to the most recent version' do
14
+ assert_not_equal @last_version, @user.version
15
+ @user.reload
16
+ assert_equal @last_version, @user.version
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,112 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class ResetTest < Test::Unit::TestCase
4
+ context 'Resetting a model' do
5
+ setup do
6
+ @original_dependent = User.reflect_on_association(:versions).options[:dependent]
7
+ @user, @versions = User.new, []
8
+ @names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs']
9
+ @names.each do |name|
10
+ @user.update_attributes(:name => name)
11
+ @versions << @user.version
12
+ end
13
+ end
14
+
15
+ should "properly revert the model's attributes" do
16
+ @versions.reverse.each_with_index do |version, i|
17
+ @user.reset_to!(version)
18
+ assert_equal @names.reverse[i], @user.name
19
+ end
20
+ end
21
+
22
+ should 'dissociate all versions after the target' do
23
+ @versions.reverse.each do |version|
24
+ @user.reset_to!(version)
25
+ assert_equal 0, @user.versions(true).after(version).count
26
+ end
27
+ end
28
+
29
+ context 'with the :dependent option as :delete_all' do
30
+ setup do
31
+ User.reflect_on_association(:versions).options[:dependent] = :delete_all
32
+ end
33
+
34
+ should 'delete all versions after the target version' do
35
+ @versions.reverse.each do |version|
36
+ later_versions = @user.versions.after(version)
37
+ @user.reset_to!(version)
38
+ later_versions.each do |later_version|
39
+ assert_raise ActiveRecord::RecordNotFound do
40
+ later_version.reload
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ should 'not destroy all versions after the target version' do
47
+ VestalVersions::Version.any_instance.stubs(:destroy).raises(RuntimeError)
48
+ @versions.reverse.each do |version|
49
+ assert_nothing_raised do
50
+ @user.reset_to!(version)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ context 'with the :dependent option as :destroy' do
57
+ setup do
58
+ User.reflect_on_association(:versions).options[:dependent] = :destroy
59
+ end
60
+
61
+ should 'delete all versions after the target version' do
62
+ @versions.reverse.each do |version|
63
+ later_versions = @user.versions.after(version)
64
+ @user.reset_to!(version)
65
+ later_versions.each do |later_version|
66
+ assert_raise ActiveRecord::RecordNotFound do
67
+ later_version.reload
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ should 'destroy all versions after the target version' do
74
+ VestalVersions::Version.any_instance.stubs(:destroy).raises(RuntimeError)
75
+ @versions.reverse.each do |version|
76
+ later_versions = @user.versions.after(version)
77
+ if later_versions.empty?
78
+ assert_nothing_raised do
79
+ @user.reset_to!(version)
80
+ end
81
+ else
82
+ assert_raise RuntimeError do
83
+ @user.reset_to!(version)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ context 'with the :dependent option as :nullify' do
91
+ setup do
92
+ User.reflect_on_association(:versions).options[:dependent] = :nullify
93
+ end
94
+
95
+ should 'leave all versions after the target version' do
96
+ @versions.reverse.each do |version|
97
+ later_versions = @user.versions.after(version)
98
+ @user.reset_to!(version)
99
+ later_versions.each do |later_version|
100
+ assert_nothing_raised do
101
+ later_version.reload
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ teardown do
109
+ User.reflect_on_association(:versions).options[:dependent] = @original_dependent
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,99 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class ReversionTest < Test::Unit::TestCase
4
+ context 'A model reversion' do
5
+ setup do
6
+ @user, @attributes, @times = User.new, {}, {}
7
+ names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs']
8
+ time = names.size.hours.ago
9
+ names.each do |name|
10
+ @user.update_attributes(:name => name)
11
+ @attributes[@user.version] = @user.attributes
12
+ time += 1.hour
13
+ if last_version = @user.versions.last
14
+ last_version.update_attributes(:created_at => time)
15
+ end
16
+ @times[@user.version] = time
17
+ end
18
+ @user.reload.versions.reload
19
+ @first_version, @last_version = @attributes.keys.min, @attributes.keys.max
20
+ end
21
+
22
+ should 'return the new version number' do
23
+ new_version = @user.revert_to(@first_version)
24
+ assert_equal @first_version, new_version
25
+ end
26
+
27
+ should 'change the version number when saved' do
28
+ current_version = @user.version
29
+ @user.revert_to!(@first_version)
30
+ assert_not_equal current_version, @user.version
31
+ end
32
+
33
+ should 'do nothing for a invalid argument' do
34
+ current_version = @user.version
35
+ [nil, :bogus, 'bogus', (1..2)].each do |invalid|
36
+ @user.revert_to(invalid)
37
+ assert_equal current_version, @user.version
38
+ end
39
+ end
40
+
41
+ should 'be able to target a version number' do
42
+ @user.revert_to(1)
43
+ assert_equal 1, @user.version
44
+ end
45
+
46
+ should 'be able to target a date and time' do
47
+ @times.each do |version, time|
48
+ @user.revert_to(time + 1.second)
49
+ assert_equal version, @user.version
50
+ end
51
+ end
52
+
53
+ should 'be able to target a version object' do
54
+ @user.versions.each do |version|
55
+ @user.revert_to(version)
56
+ assert_equal version.number, @user.version
57
+ end
58
+ end
59
+
60
+ should "correctly roll back the model's attributes" do
61
+ timestamps = %w(created_at created_on updated_at updated_on)
62
+ @attributes.each do |version, attributes|
63
+ @user.revert_to!(version)
64
+ assert_equal attributes.except(*timestamps), @user.attributes.except(*timestamps)
65
+ end
66
+ end
67
+
68
+ should "store the reverted_from pointing to the previous version" do
69
+ @user.revert_to!(1)
70
+ assert_equal 1, @user.versions.last.reverted_from
71
+ end
72
+
73
+ should "not store the revereted_from for subsequent saves" do
74
+ @user.revert_to!(1)
75
+ @user.update_attributes(:name => 'Bill Gates')
76
+ assert_equal nil, @user.versions.last.reverted_from
77
+ end
78
+ should "store the reverted_from pointing to the version it was reverted from when save is called later" do
79
+ @user.revert_to(1)
80
+ @user.name = "Reverted"
81
+ @user.save
82
+ assert_equal 1, @user.versions.last.reverted_from
83
+ end
84
+ should "not store the reverted_from for subsequent saves when the revert_to-save is called later" do
85
+ @user.revert_to(1)
86
+ @user.name = "Reverted"
87
+ @user.save
88
+ @user.update_attributes(:name => 'Bill Gates')
89
+ assert_equal nil, @user.versions.last.reverted_from
90
+ end
91
+ should "clear the reverted_from if the model is reloaded after a revert_to without a save" do
92
+ @user.revert_to(1)
93
+ @user.reload
94
+ @user.update_attributes(:name => 'Bill Gates')
95
+ assert_equal nil, @user.versions.last.reverted_from
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,62 @@
1
+ ActiveRecord::Base.establish_connection(
2
+ :adapter => defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' ? 'jdbcsqlite3' : 'sqlite3',
3
+ :database => File.join(File.dirname(__FILE__), 'test.db')
4
+ )
5
+
6
+ class CreateSchema < ActiveRecord::Migration
7
+ def self.up
8
+ create_table :groups, :force => true do |t|
9
+ t.string :name
10
+ t.timestamps
11
+ end
12
+
13
+ create_table :users, :force => true do |t|
14
+ t.string :first_name
15
+ t.string :last_name
16
+ t.integer :group_id
17
+ t.timestamps
18
+ end
19
+
20
+ create_table :versions, :force => true do |t|
21
+ t.belongs_to :versioned, :polymorphic => true
22
+ t.belongs_to :user, :polymorphic => true
23
+ t.string :user_name
24
+ t.text :modifications
25
+ t.integer :number
26
+ t.integer :reverted_from
27
+ t.string :tag
28
+ t.timestamps
29
+ end
30
+ end
31
+ end
32
+
33
+ CreateSchema.suppress_messages do
34
+ CreateSchema.migrate(:up)
35
+ end
36
+
37
+ class Group < ActiveRecord::Base
38
+ versioned
39
+ has_many :users, :versioned => true
40
+ end
41
+
42
+ class User < ActiveRecord::Base
43
+ versioned
44
+ belongs_to :group, :versioned => true
45
+
46
+ def name
47
+ [first_name, last_name].compact.join(' ')
48
+ end
49
+
50
+ def name=(names)
51
+ self[:first_name], self[:last_name] = names.split(' ', 2)
52
+ end
53
+ end
54
+
55
+ class DeletedUser < ActiveRecord::Base
56
+ set_table_name 'users'
57
+ versioned :dependent => :tracking
58
+
59
+ end
60
+
61
+ class MyCustomVersion < VestalVersions::Version
62
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class TaggingTest < Test::Unit::TestCase
4
+ context 'Tagging a version' do
5
+ setup do
6
+ @user = User.create(:name => 'Steve Richert')
7
+ @user.update_attributes(:last_name => 'Jobs')
8
+ end
9
+
10
+ should "update the version record's tag column" do
11
+ tag_name = 'TAG'
12
+ last_version = @user.versions.last
13
+ assert_not_equal tag_name, last_version.tag
14
+ @user.tag_version(tag_name)
15
+ assert_equal tag_name, last_version.reload.tag
16
+ end
17
+
18
+ should 'create a version record for an initial version' do
19
+ @user.revert_to(1)
20
+ assert_nil @user.versions.at(1)
21
+ @user.tag_version('TAG')
22
+ assert_not_nil @user.versions.at(1)
23
+ end
24
+ end
25
+
26
+ context 'A tagged version' do
27
+ setup do
28
+ user = User.create(:name => 'Steve Richert')
29
+ user.update_attributes(:last_name => 'Jobs')
30
+ user.tag_version('TAG')
31
+ @version = user.versions.last
32
+ end
33
+
34
+ should 'return true for the "tagged?" method' do
35
+ assert @version.respond_to?(:tagged?)
36
+ assert_equal true, @version.tagged?
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
2
+ $: << File.dirname(__FILE__)
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'active_record'
7
+ require 'shoulda'
8
+ require 'mocha'
9
+ # require 'vestal_versions'
10
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/vestal_versions'))
11
+ require 'schema'
12
+ begin; require 'redgreen'; rescue LoadError; end
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class UsersTest < Test::Unit::TestCase
4
+ context 'The user responsible for an update' do
5
+ setup do
6
+ @updated_by = User.create(:name => 'Steve Jobs')
7
+ @user = User.create(:name => 'Steve Richert')
8
+ end
9
+
10
+ should 'default to nil' do
11
+ @user.update_attributes(:first_name => 'Stephen')
12
+ assert_nil @user.versions.last.user
13
+ end
14
+
15
+ should 'accept and return an ActiveRecord user' do
16
+ @user.update_attributes(:first_name => 'Stephen', :updated_by => @updated_by)
17
+ assert_equal @updated_by, @user.versions.last.user
18
+ end
19
+
20
+ should 'accept and return a string user name' do
21
+ @user.update_attributes(:first_name => 'Stephen', :updated_by => @updated_by.name)
22
+ assert_equal @updated_by.name, @user.versions.last.user
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,61 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class VersionTest < Test::Unit::TestCase
4
+ context 'Versions' do
5
+ setup do
6
+ @user = User.create(:name => 'Stephen Richert')
7
+ @user.update_attributes(:name => 'Steve Jobs')
8
+ @user.update_attributes(:last_name => 'Richert')
9
+ @first_version, @last_version = @user.versions.first, @user.versions.last
10
+ end
11
+
12
+ should 'be comparable to another version based on version number' do
13
+ assert @first_version == @first_version
14
+ assert @last_version == @last_version
15
+ assert @first_version != @last_version
16
+ assert @last_version != @first_version
17
+ assert @first_version < @last_version
18
+ assert @last_version > @first_version
19
+ assert @first_version <= @last_version
20
+ assert @last_version >= @first_version
21
+ end
22
+
23
+ should "not equal a separate model's version with the same number" do
24
+ user = User.create(:name => 'Stephen Richert')
25
+ user.update_attributes(:name => 'Steve Jobs')
26
+ user.update_attributes(:last_name => 'Richert')
27
+ first_version, last_version = user.versions.first, user.versions.last
28
+ assert_not_equal @first_version, first_version
29
+ assert_not_equal @last_version, last_version
30
+ end
31
+
32
+ should 'default to ordering by number when finding through association' do
33
+ numbers = @user.versions.map(&:number)
34
+ assert_equal numbers.sort, numbers
35
+ end
36
+
37
+ should 'return true for the "initial?" method when the version number is 1' do
38
+ version = @user.versions.build(:number => 1)
39
+ assert_equal 1, version.number
40
+ assert_equal true, version.initial?
41
+ end
42
+
43
+ should "return the version number if it is not a revert" do
44
+ assert_equal @user.version, @user.versions.last.original_number
45
+ end
46
+
47
+ should "return the reverted_version if it is a revert" do
48
+ @user.revert_to!(1)
49
+ assert_equal 1, @user.versions.last.original_number
50
+ end
51
+
52
+ should "return the original version if it is a double revert" do
53
+ @user.revert_to!(2)
54
+ version = @user.version
55
+ @user.update_attributes(:last_name => 'Gates')
56
+ @user.revert_to!(version)
57
+ assert_equal 2, @user.versions.last.original_number
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class VersionedTest < Test::Unit::TestCase
4
+ context 'ActiveRecord models' do
5
+ should 'respond to the "versioned?" method' do
6
+ assert ActiveRecord::Base.respond_to?(:versioned?)
7
+ assert User.respond_to?(:versioned?)
8
+ end
9
+
10
+ should 'return true for the "versioned?" method if the model is versioned' do
11
+ assert_equal true, User.versioned?
12
+ end
13
+
14
+ should 'return false for the "versioned?" method if the model is not versioned' do
15
+ assert_equal false, ActiveRecord::Base.versioned?
16
+ end
17
+ end
18
+ end