set_vestal_versions 1.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/LICENSE +20 -0
- data/README.rdoc +196 -0
- data/lib/generators/vestal_versions.rb +11 -0
- data/lib/generators/vestal_versions/migration/migration_generator.rb +17 -0
- data/lib/generators/vestal_versions/migration/templates/initializer.rb +9 -0
- data/lib/generators/vestal_versions/migration/templates/migration.rb +28 -0
- data/lib/vestal_versions.rb +126 -0
- data/lib/vestal_versions/changes.rb +122 -0
- data/lib/vestal_versions/conditions.rb +57 -0
- data/lib/vestal_versions/control.rb +200 -0
- data/lib/vestal_versions/creation.rb +93 -0
- data/lib/vestal_versions/deletion.rb +39 -0
- data/lib/vestal_versions/options.rb +41 -0
- data/lib/vestal_versions/reload.rb +17 -0
- data/lib/vestal_versions/reset.rb +24 -0
- data/lib/vestal_versions/reversion.rb +82 -0
- data/lib/vestal_versions/users.rb +55 -0
- data/lib/vestal_versions/version.rb +80 -0
- data/lib/vestal_versions/version_num.rb +3 -0
- data/lib/vestal_versions/version_tagging.rb +50 -0
- data/lib/vestal_versions/versioned.rb +27 -0
- data/lib/vestal_versions/versions.rb +74 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/models.rb +19 -0
- data/spec/support/schema.rb +25 -0
- data/spec/vestal_versions/changes_spec.rb +134 -0
- data/spec/vestal_versions/conditions_spec.rb +103 -0
- data/spec/vestal_versions/control_spec.rb +120 -0
- data/spec/vestal_versions/creation_spec.rb +90 -0
- data/spec/vestal_versions/deletion_spec.rb +86 -0
- data/spec/vestal_versions/options_spec.rb +45 -0
- data/spec/vestal_versions/reload_spec.rb +18 -0
- data/spec/vestal_versions/reset_spec.rb +111 -0
- data/spec/vestal_versions/reversion_spec.rb +103 -0
- data/spec/vestal_versions/users_spec.rb +21 -0
- data/spec/vestal_versions/version_spec.rb +61 -0
- data/spec/vestal_versions/version_tagging_spec.rb +39 -0
- data/spec/vestal_versions/versioned_spec.rb +16 -0
- data/spec/vestal_versions/versions_spec.rb +176 -0
- metadata +165 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VestalVersions::Deletion do
|
4
|
+
let(:name){ 'Steve Richert' }
|
5
|
+
subject{ DeletedUser.create(:first_name => 'Steve', :last_name => 'Richert') }
|
6
|
+
|
7
|
+
context "a deleted version's changes" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
subject.update_attribute(:last_name, 'Jobs')
|
11
|
+
end
|
12
|
+
|
13
|
+
it "removes the original record" do
|
14
|
+
subject.destroy
|
15
|
+
|
16
|
+
DeletedUser.find_by_id(subject.id).should be_nil
|
17
|
+
end
|
18
|
+
|
19
|
+
it "creates another version record" do
|
20
|
+
expect{ subject.destroy }.to change{ VestalVersions::Version.count }.by(1)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "creates a version with a tag 'deleted'" do
|
24
|
+
subject.destroy
|
25
|
+
VestalVersions::Version.last.tag.should == 'deleted'
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
context "deleted versions" do
|
31
|
+
let(:last_version){ VestalVersions::Version.last }
|
32
|
+
before do
|
33
|
+
subject.update_attribute(:last_name, 'Jobs')
|
34
|
+
subject.destroy
|
35
|
+
end
|
36
|
+
|
37
|
+
context "restoring a record with a bang" do
|
38
|
+
it "is able to restore the user record" do
|
39
|
+
last_version.restore!
|
40
|
+
|
41
|
+
last_version.versioned.should == subject
|
42
|
+
end
|
43
|
+
|
44
|
+
it "removes the last versioned entry" do
|
45
|
+
expect{
|
46
|
+
last_version.restore!
|
47
|
+
}.to change{ VestalVersions::Version.count }.by(-1)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "works properly even if it's not on the proper version" do
|
51
|
+
another_version = VestalVersions::Version.where(
|
52
|
+
:versioned_id => last_version.versioned_id,
|
53
|
+
:versioned_type => last_version.versioned_type
|
54
|
+
).first
|
55
|
+
|
56
|
+
another_version.should_not == last_version
|
57
|
+
|
58
|
+
another_version.restore!.should == subject
|
59
|
+
end
|
60
|
+
|
61
|
+
it "restores even if the schema has changed" do
|
62
|
+
new_mods = last_version.modifications.merge(:old_column => 'old')
|
63
|
+
last_version.update_attributes(:modifications => new_mods)
|
64
|
+
|
65
|
+
last_version.restore.should == subject
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "restoring a record without a save" do
|
70
|
+
it "does not save the DeletedUser when restoring" do
|
71
|
+
last_version.restore.should be_new_record
|
72
|
+
end
|
73
|
+
|
74
|
+
it "restores the user object properly" do
|
75
|
+
last_version.restore.should == subject
|
76
|
+
end
|
77
|
+
|
78
|
+
it "does not decrement the versions table" do
|
79
|
+
expect{
|
80
|
+
last_version.restore
|
81
|
+
}.to change{ VestalVersions::Version.count }.by(0)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VestalVersions::Options do
|
4
|
+
context 'with explicit configuration' do
|
5
|
+
let(:options){ {:dependent => :destroy} }
|
6
|
+
let(:prepared_options){ User.prepare_versioned_options(options.dup) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
VestalVersions::Version.config.clear
|
10
|
+
VestalVersions::Version.config.class_name = 'MyCustomVersion'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'has symbolized keys' do
|
14
|
+
User.vestal_versions_options.keys.all?{|k| k.is_a?(Symbol) }
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'combines class-level and global configuration options' do
|
18
|
+
prepared_options.slice(:dependent, :class_name).should == {
|
19
|
+
:dependent => :destroy,
|
20
|
+
:class_name => 'MyCustomVersion'
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'default configuration options' do
|
27
|
+
subject { User.prepare_versioned_options({}) }
|
28
|
+
|
29
|
+
it 'defaults to "VestalVersions::Version" for :class_name' do
|
30
|
+
subject[:class_name].should == 'VestalVersions::Version'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'defaults to :delete_all for :dependent' do
|
34
|
+
subject[:dependent].should == :delete_all
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'forces the :as option value to :versioned' do
|
38
|
+
subject[:as].should == :versioned
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'defaults to [VestalVersions::Versions] for :extend' do
|
42
|
+
subject[:extend].should == [VestalVersions::Versions]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VestalVersions::Reload do
|
4
|
+
let(:user){ User.create(:name => 'Steve Richert') }
|
5
|
+
|
6
|
+
before do
|
7
|
+
first_version = user.version
|
8
|
+
user.update_attribute(:last_name, 'Jobs')
|
9
|
+
@last_version = user.version
|
10
|
+
user.revert_to(first_version)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'resets the version number to the most recent version' do
|
14
|
+
user.version.should_not == @last_version
|
15
|
+
user.reload
|
16
|
+
user.version.should == @last_version
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VestalVersions::Reset do
|
4
|
+
let(:names){
|
5
|
+
['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs']
|
6
|
+
}
|
7
|
+
|
8
|
+
subject{ User.new }
|
9
|
+
let(:versions){ names.map{ |name|
|
10
|
+
subject.update_attribute :name, name
|
11
|
+
subject.version
|
12
|
+
} }
|
13
|
+
|
14
|
+
before do
|
15
|
+
@dependent = User.reflect_on_association(:versions).options[:dependent]
|
16
|
+
end
|
17
|
+
|
18
|
+
after do
|
19
|
+
User.reflect_on_association(:versions).options[:dependent] = @dependent
|
20
|
+
end
|
21
|
+
|
22
|
+
it "properly reverts the model's attributes" do
|
23
|
+
versions.reverse.each_with_index do |version, i|
|
24
|
+
subject.reset_to!(version)
|
25
|
+
subject.name.should == names.reverse[i]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'dissociates all versions after the target' do
|
30
|
+
versions.reverse.each do |version|
|
31
|
+
subject.reset_to!(version)
|
32
|
+
subject.versions(true).after(version).count.should == 0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with the :dependent option as :delete_all' do
|
37
|
+
before do
|
38
|
+
User.reflect_on_association(:versions).options[:dependent] = :delete_all
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'deletes all versions after the target version' do
|
42
|
+
versions.reverse.each do |version|
|
43
|
+
later_versions = subject.versions.after(version)
|
44
|
+
subject.reset_to!(version)
|
45
|
+
|
46
|
+
later_versions.each do |later_version|
|
47
|
+
expect{
|
48
|
+
later_version.reload
|
49
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'does not destroy all versions after the target version' do
|
55
|
+
expect {
|
56
|
+
versions.reverse.each do |version|
|
57
|
+
subject.reset_to! version
|
58
|
+
end
|
59
|
+
}.to_not change{ VestalVersions::Version.count }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with the :dependent option as :destroy' do
|
64
|
+
before do
|
65
|
+
User.reflect_on_association(:versions).options[:dependent] = :destroy
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'deletes all versions after the target version' do
|
69
|
+
versions.reverse.each do |version|
|
70
|
+
later_versions = subject.versions.after(version)
|
71
|
+
subject.reset_to!(version)
|
72
|
+
|
73
|
+
later_versions.each do |later_version|
|
74
|
+
expect{
|
75
|
+
later_version.reload
|
76
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'destroys all versions after the target version' do
|
82
|
+
expect {
|
83
|
+
versions.reverse.each do |version|
|
84
|
+
later_versions = subject.versions.after(version)
|
85
|
+
|
86
|
+
subject.reset_to!(version)
|
87
|
+
end
|
88
|
+
}.to change{ VestalVersions::Version.count }.by(-versions.size + 1)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'with the :dependent option as :nullify' do
|
93
|
+
before do
|
94
|
+
User.reflect_on_association(:versions).options[:dependent] = :nullify
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'leaves all versions after the target version' do
|
98
|
+
versions.reverse.each do |version|
|
99
|
+
later_versions = subject.versions.after(version)
|
100
|
+
subject.reset_to!(version)
|
101
|
+
|
102
|
+
later_versions.each do |later_version|
|
103
|
+
expect{
|
104
|
+
later_version.reload
|
105
|
+
}.to_not raise_error
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VestalVersions::Reversion do
|
4
|
+
subject{ User.new }
|
5
|
+
let(:attributes){ {} }
|
6
|
+
let(:first_version){ attributes.keys.min }
|
7
|
+
let(:last_version){ attributes.keys.max }
|
8
|
+
let(:times){ {} }
|
9
|
+
let(:names){
|
10
|
+
['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs']
|
11
|
+
}
|
12
|
+
|
13
|
+
before do
|
14
|
+
time = names.size.hours.ago
|
15
|
+
|
16
|
+
names.each do |name|
|
17
|
+
subject.update_attribute(:name, name)
|
18
|
+
attributes[subject.version] = subject.attributes
|
19
|
+
time += 1.hour
|
20
|
+
|
21
|
+
subject.versions.last.try(:update_attribute, :created_at, time)
|
22
|
+
|
23
|
+
times[subject.version] = time
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns the new version number' do
|
28
|
+
subject.revert_to(first_version).should == first_version
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'changes the version number when saved' do
|
32
|
+
expect{ subject.revert_to! first_version }.to change{ subject.version }
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'does nothing for a invalid argument' do
|
36
|
+
[nil, :bogus, 'bogus', (1..2)].each do |invalid|
|
37
|
+
expect{ subject.revert_to(invalid) }.to_not change{ subject.version }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'is able to target a version number' do
|
42
|
+
subject.revert_to(1)
|
43
|
+
subject.version.should == 1
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'is able to target a date and time' do
|
47
|
+
times.each do |version, time|
|
48
|
+
subject.revert_to(time + 1.second)
|
49
|
+
subject.version.should == version
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'is able to target a version object' do
|
54
|
+
subject.versions.each do |version|
|
55
|
+
subject.revert_to(version)
|
56
|
+
subject.version.should == version.number
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "correctly rolls back the model's attributes" do
|
61
|
+
except = %w(created_at created_on updated_at updated_on)
|
62
|
+
|
63
|
+
attributes.each do |version, attributes|
|
64
|
+
subject.revert_to!(version)
|
65
|
+
subject.attributes.except(*except).should == attributes.except(*except)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "stores the reverted_from pointing to the previous version" do
|
70
|
+
subject.revert_to!(1)
|
71
|
+
subject.versions.last.reverted_from.should == 1
|
72
|
+
end
|
73
|
+
|
74
|
+
it "does not store the reverted_from for subsequent saves" do
|
75
|
+
subject.revert_to!(1)
|
76
|
+
subject.update_attributes(:name => 'Bill Gates')
|
77
|
+
subject.versions.last.reverted_from.should be_nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it "stores the reverted_from pointing to the version it was reverted from when save is called later" do
|
81
|
+
subject.revert_to(1)
|
82
|
+
subject.name = "Reverted"
|
83
|
+
subject.save
|
84
|
+
subject.versions.last.reverted_from.should == 1
|
85
|
+
end
|
86
|
+
|
87
|
+
it "does not store the reverted_from for subsequent saves when the revert_to-save is called later" do
|
88
|
+
subject.revert_to(1)
|
89
|
+
subject.name = "Reverted"
|
90
|
+
subject.save
|
91
|
+
subject.update_attributes(:name => 'Bill Gates')
|
92
|
+
subject.versions.last.reverted_from.should be_nil
|
93
|
+
end
|
94
|
+
|
95
|
+
it "clears the reverted_from if the model is reloaded after a revert_to without a save" do
|
96
|
+
subject.revert_to(1)
|
97
|
+
subject.reload
|
98
|
+
subject.update_attributes(:name => 'Bill Gates')
|
99
|
+
|
100
|
+
subject.versions.last.reverted_from.should be_nil
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VestalVersions::Users do
|
4
|
+
let(:updated_by){ User.create(:name => 'Steve Jobs') }
|
5
|
+
let(:user){ User.create(:name => 'Steve Richert') }
|
6
|
+
|
7
|
+
it 'defaults to nil' do
|
8
|
+
user.update_attributes(:first_name => 'Stephen')
|
9
|
+
user.versions.last.user.should be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'accepts and returns an ActiveRecord user' do
|
13
|
+
user.update_attributes(:first_name => 'Stephen', :updated_by => updated_by)
|
14
|
+
user.versions.last.user.should == updated_by
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'accepts and returns a string user name' do
|
18
|
+
user.update_attributes(:first_name => 'Stephen', :updated_by => updated_by.name)
|
19
|
+
user.versions.last.user.should == updated_by.name
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VestalVersions::Versions do
|
4
|
+
let(:user){ User.create(:name => 'Stephen Richert') }
|
5
|
+
|
6
|
+
before do
|
7
|
+
user.update_attribute(:name, 'Steve Jobs')
|
8
|
+
user.update_attribute(:last_name, 'Richert')
|
9
|
+
@first_version, @last_version = user.versions.first, user.versions.last
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'is comparable to another version based on version number' do
|
13
|
+
@first_version.should == @first_version
|
14
|
+
@last_version.should == @last_version
|
15
|
+
@first_version.should_not == @last_version
|
16
|
+
@last_version.should_not == @first_version
|
17
|
+
@first_version.should < @last_version
|
18
|
+
@last_version.should > @first_version
|
19
|
+
@first_version.should <= @last_version
|
20
|
+
@last_version.should >= @first_version
|
21
|
+
end
|
22
|
+
|
23
|
+
it "is not equal a separate model's version with the same number" do
|
24
|
+
other = User.create(:name => 'Stephen Richert')
|
25
|
+
other.update_attribute(:name, 'Steve Jobs')
|
26
|
+
other.update_attribute(:last_name, 'Richert')
|
27
|
+
first_version, last_version = other.versions.first, other.versions.last
|
28
|
+
|
29
|
+
@first_version.should_not == first_version
|
30
|
+
@last_version.should_not == last_version
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'defaults to ordering by number when finding through association' do
|
34
|
+
numbers = user.versions.map(&:number)
|
35
|
+
numbers.sort.should == numbers
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns true for the "initial?" method when the version number is 1' do
|
39
|
+
version = user.versions.build(:number => 1)
|
40
|
+
version.number.should == 1
|
41
|
+
version.should be_initial
|
42
|
+
end
|
43
|
+
|
44
|
+
it "sreturn the version number if it is not a revert" do
|
45
|
+
user.version.should == user.versions.last.original_number
|
46
|
+
end
|
47
|
+
|
48
|
+
it "return the reverted_version if it is a revert" do
|
49
|
+
user.revert_to!(1)
|
50
|
+
user.versions.last.original_number.should == 1
|
51
|
+
end
|
52
|
+
|
53
|
+
it "return the original version if it is a double revert" do
|
54
|
+
user.revert_to!(2)
|
55
|
+
version = user.version
|
56
|
+
user.update_attributes(:last_name => 'Gates')
|
57
|
+
user.revert_to!(version)
|
58
|
+
user.versions.last.original_number.should == 2
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|