vestal_versions 0.8.3 → 1.0.0

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.
Files changed (47) hide show
  1. data/.gitignore +20 -2
  2. data/README.rdoc +110 -8
  3. data/Rakefile +14 -3
  4. data/VERSION +1 -1
  5. data/lib/vestal_versions.rb +93 -143
  6. data/lib/vestal_versions/changes.rb +125 -0
  7. data/lib/vestal_versions/conditions.rb +69 -0
  8. data/lib/vestal_versions/configuration.rb +40 -0
  9. data/lib/vestal_versions/control.rb +175 -0
  10. data/lib/vestal_versions/creation.rb +85 -0
  11. data/lib/vestal_versions/options.rb +42 -0
  12. data/lib/vestal_versions/reload.rb +23 -0
  13. data/lib/vestal_versions/reset.rb +56 -0
  14. data/lib/vestal_versions/reversion.rb +69 -0
  15. data/lib/vestal_versions/tagging.rb +50 -0
  16. data/lib/vestal_versions/users.rb +57 -0
  17. data/lib/vestal_versions/version.rb +32 -0
  18. data/lib/vestal_versions/versioned.rb +30 -0
  19. data/lib/vestal_versions/versions.rb +74 -0
  20. data/rails/init.rb +1 -0
  21. data/rails_generators/vestal_versions/templates/initializer.rb +9 -0
  22. data/{generators/vestal_versions_migration → rails_generators/vestal_versions}/templates/migration.rb +9 -2
  23. data/rails_generators/vestal_versions/vestal_versions_generator.rb +10 -0
  24. data/test/changes_test.rb +154 -13
  25. data/test/conditions_test.rb +137 -0
  26. data/test/configuration_test.rb +39 -0
  27. data/test/control_test.rb +152 -0
  28. data/test/creation_test.rb +70 -30
  29. data/test/options_test.rb +52 -0
  30. data/test/reload_test.rb +19 -0
  31. data/test/reset_test.rb +107 -0
  32. data/test/{revert_test.rb → reversion_test.rb} +8 -22
  33. data/test/schema.rb +4 -1
  34. data/test/tagging_test.rb +38 -0
  35. data/test/test_helper.rb +2 -1
  36. data/test/users_test.rb +25 -0
  37. data/test/version_test.rb +43 -0
  38. data/test/versioned_test.rb +18 -0
  39. data/test/versions_test.rb +172 -0
  40. data/vestal_versions.gemspec +61 -21
  41. metadata +75 -15
  42. data/generators/vestal_versions_migration/vestal_versions_migration_generator.rb +0 -11
  43. data/init.rb +0 -1
  44. data/lib/version.rb +0 -14
  45. data/test/between_test.rb +0 -58
  46. data/test/comparable_test.rb +0 -35
  47. data/test/latest_changes_test.rb +0 -42
@@ -0,0 +1,9 @@
1
+ VestalVersions.configure do |config|
2
+ # Place any global options here. For example, in order to specify your own version model to use
3
+ # throughout the application, simply specify:
4
+ #
5
+ # config.class_name = "MyCustomVersion"
6
+ #
7
+ # Any options passed to the "versioned" method in the model itself will override this global
8
+ # configuration.
9
+ end
@@ -2,14 +2,21 @@ class CreateVestalVersions < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :versions do |t|
4
4
  t.belongs_to :versioned, :polymorphic => true
5
+ t.belongs_to :user, :polymorphic => true
6
+ t.string :user_name
5
7
  t.text :changes
6
8
  t.integer :number
7
- t.datetime :created_at
9
+ t.string :tag
10
+
11
+ t.timestamps
8
12
  end
9
13
 
10
14
  change_table :versions do |t|
11
- t.index [:versioned_type, :versioned_id]
15
+ t.index [:versioned_id, :versioned_type]
16
+ t.index [:user_id, :user_type]
17
+ t.index :user_name
12
18
  t.index :number
19
+ t.index :tag
13
20
  t.index :created_at
14
21
  end
15
22
  end
@@ -0,0 +1,10 @@
1
+ class VestalVersionsGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'migration.rb', File.join('db', 'migrate'), :migration_file_name => 'create_vestal_versions'
5
+
6
+ m.directory File.join('config', 'initializers')
7
+ m.template 'initializer.rb', File.join('config', 'initializers', 'vestal_versions.rb')
8
+ end
9
+ end
10
+ end
@@ -1,28 +1,169 @@
1
- require 'test_helper'
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
3
  class ChangesTest < Test::Unit::TestCase
4
4
  context "A version's changes" do
5
5
  setup do
6
6
  @user = User.create(:name => 'Steve Richert')
7
+ @user.update_attribute(:last_name, 'Jobs')
8
+ @changes = @user.versions.last.changes
7
9
  end
8
10
 
9
- should "initially be blank" do
10
- assert @user.versions.first.changes.blank?
11
+ should 'be a hash' do
12
+ assert_kind_of Hash, @changes
11
13
  end
12
14
 
13
- should 'contain all changed attributes' do
14
- @user.name = 'Steve Jobs'
15
- changes = @user.changes
16
- @user.save
17
- assert_equal changes, @user.versions.last.changes.slice(*changes.keys)
15
+ should 'not be empty' do
16
+ assert !@changes.empty?
17
+ end
18
+
19
+ should 'have string keys' do
20
+ @changes.keys.each do |key|
21
+ assert_kind_of String, key
22
+ end
23
+ end
24
+
25
+ should 'have array values' do
26
+ @changes.values.each do |value|
27
+ assert_kind_of Array, value
28
+ end
18
29
  end
19
30
 
20
- should 'contain no more than the changed attributes and timestamps' do
21
- timestamps = %w(created_at created_on updated_at updated_on)
22
- @user.name = 'Steve Jobs'
23
- changes = @user.changes
31
+ should 'have two-element values' do
32
+ @changes.values.each do |value|
33
+ assert_equal 2, value.size
34
+ end
35
+ end
36
+
37
+ should 'have unique-element values' do
38
+ @changes.values.each do |value|
39
+ assert_equal value.uniq, value
40
+ end
41
+ end
42
+
43
+ should "equal the model's changes" do
44
+ @user.first_name = 'Stephen'
45
+ model_changes = @user.changes
24
46
  @user.save
25
- assert_equal changes, @user.versions.last.changes.except(*timestamps)
47
+ changes = @user.versions.last.changes
48
+ assert_equal model_changes, changes
49
+ end
50
+ end
51
+
52
+ context 'A hash of changes' do
53
+ setup do
54
+ @changes = {'first_name' => ['Steve', 'Stephen']}
55
+ @other = {'first_name' => ['Catie', 'Catherine']}
56
+ end
57
+
58
+ should 'properly append other changes' do
59
+ expected = {'first_name' => ['Steve', 'Catherine']}
60
+ changes = @changes.append_changes(@other)
61
+ assert_equal expected, changes
62
+ @changes.append_changes!(@other)
63
+ assert_equal expected, @changes
64
+ end
65
+
66
+ should 'properly prepend other changes' do
67
+ expected = {'first_name' => ['Catie', 'Stephen']}
68
+ changes = @changes.prepend_changes(@other)
69
+ assert_equal expected, changes
70
+ @changes.prepend_changes!(@other)
71
+ assert_equal expected, @changes
72
+ end
73
+
74
+ should 'be reversible' do
75
+ expected = {'first_name' => ['Stephen', 'Steve']}
76
+ changes = @changes.reverse_changes
77
+ assert_equal expected, changes
78
+ @changes.reverse_changes!
79
+ assert_equal expected, @changes
80
+ end
81
+ end
82
+
83
+ context 'The changes between two versions' do
84
+ setup do
85
+ name = 'Steve Richert'
86
+ @user = User.create(:name => name) # 1
87
+ @user.update_attribute(:last_name, 'Jobs') # 2
88
+ @user.update_attribute(:first_name, 'Stephen') # 3
89
+ @user.update_attribute(:last_name, 'Richert') # 4
90
+ @user.update_attribute(:name, name) # 5
91
+ @version = @user.version
92
+ end
93
+
94
+ should 'be a hash' do
95
+ 1.upto(@version) do |i|
96
+ 1.upto(@version) do |j|
97
+ changes = @user.changes_between(i, j)
98
+ assert_kind_of Hash, changes
99
+ end
100
+ end
101
+ end
102
+
103
+ should 'have string keys' do
104
+ 1.upto(@version) do |i|
105
+ 1.upto(@version) do |j|
106
+ changes = @user.changes_between(i, j)
107
+ changes.keys.each do |key|
108
+ assert_kind_of String, key
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ should 'have array values' do
115
+ 1.upto(@version) do |i|
116
+ 1.upto(@version) do |j|
117
+ changes = @user.changes_between(i, j)
118
+ changes.values.each do |value|
119
+ assert_kind_of Array, value
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ should 'have two-element values' do
126
+ 1.upto(@version) do |i|
127
+ 1.upto(@version) do |j|
128
+ changes = @user.changes_between(i, j)
129
+ changes.values.each do |value|
130
+ assert_equal 2, value.size
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ should 'have unique-element values' do
137
+ 1.upto(@version) do |i|
138
+ 1.upto(@version) do |j|
139
+ changes = @user.changes_between(i, j)
140
+ changes.values.each do |value|
141
+ assert_equal value.uniq, value
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ should 'be empty between identical versions' do
148
+ assert @user.changes_between(1, @version).empty?
149
+ assert @user.changes_between(@version, 1).empty?
150
+ end
151
+
152
+ should 'be should reverse with direction' do
153
+ 1.upto(@version) do |i|
154
+ i.upto(@version) do |j|
155
+ up = @user.changes_between(i, j)
156
+ down = @user.changes_between(j, i)
157
+ assert_equal up, down.reverse_changes
158
+ end
159
+ end
160
+ end
161
+
162
+ should 'be empty with invalid arguments' do
163
+ 1.upto(@version) do |i|
164
+ assert @user.changes_between(i, nil)
165
+ assert @user.changes_between(nil, i)
166
+ end
26
167
  end
27
168
  end
28
169
  end
@@ -0,0 +1,137 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ConditionsTest < Test::Unit::TestCase
4
+ context 'Converted :if conditions' do
5
+ setup do
6
+ User.class_eval do
7
+ def true; true; end
8
+ end
9
+ end
10
+
11
+ should 'be an array' do
12
+ assert_kind_of Array, User.vestal_versions_options[:if]
13
+ User.prepare_versioned_options(:if => :true)
14
+ assert_kind_of Array, User.vestal_versions_options[:if]
15
+ end
16
+
17
+ should 'have proc values' do
18
+ User.prepare_versioned_options(:if => :true)
19
+ assert User.vestal_versions_options[:if].all?{|i| i.is_a?(Proc) }
20
+ end
21
+
22
+ teardown do
23
+ User.prepare_versioned_options(:if => [])
24
+ end
25
+ end
26
+
27
+ context 'Converted :unless conditions' do
28
+ setup do
29
+ User.class_eval do
30
+ def true; true; end
31
+ end
32
+ end
33
+
34
+ should 'be an array' do
35
+ assert_kind_of Array, User.vestal_versions_options[:unless]
36
+ User.prepare_versioned_options(:unless => :true)
37
+ assert_kind_of Array, User.vestal_versions_options[:unless]
38
+ end
39
+
40
+ should 'have proc values' do
41
+ User.prepare_versioned_options(:unless => :true)
42
+ assert User.vestal_versions_options[:unless].all?{|i| i.is_a?(Proc) }
43
+ end
44
+
45
+ teardown do
46
+ User.prepare_versioned_options(:unless => [])
47
+ end
48
+ end
49
+
50
+ context 'A new version' do
51
+ setup do
52
+ User.class_eval do
53
+ def true; true; end
54
+ def false; false; end
55
+ end
56
+
57
+ @user = User.create(:name => 'Steve Richert')
58
+ @count = @user.versions.count
59
+ end
60
+
61
+ context 'with :if conditions' do
62
+ context 'that pass' do
63
+ setup do
64
+ User.prepare_versioned_options(:if => [:true])
65
+ @user.update_attribute(:last_name, 'Jobs')
66
+ end
67
+
68
+ should 'be created' do
69
+ assert_equal @count + 1, @user.versions.count
70
+ end
71
+ end
72
+
73
+ context 'that fail' do
74
+ setup do
75
+ User.prepare_versioned_options(:if => [:false])
76
+ @user.update_attribute(:last_name, 'Jobs')
77
+ end
78
+
79
+ should 'not be created' do
80
+ assert_equal @count, @user.versions.count
81
+ end
82
+ end
83
+ end
84
+
85
+ context 'with :unless conditions' do
86
+ context 'that pass' do
87
+ setup do
88
+ User.prepare_versioned_options(:unless => [:true])
89
+ @user.update_attribute(:last_name, 'Jobs')
90
+ end
91
+
92
+ should 'not be created' do
93
+ assert_equal @count, @user.versions.count
94
+ end
95
+ end
96
+
97
+ context 'that fail' do
98
+ setup do
99
+ User.prepare_versioned_options(:unless => [:false])
100
+ @user.update_attribute(:last_name, 'Jobs')
101
+ end
102
+
103
+ should 'not be created' do
104
+ assert_equal @count + 1, @user.versions.count
105
+ end
106
+ end
107
+ end
108
+
109
+ context 'with :if and :unless conditions' do
110
+ context 'that pass' do
111
+ setup do
112
+ User.prepare_versioned_options(:if => [:true], :unless => [:true])
113
+ @user.update_attribute(:last_name, 'Jobs')
114
+ end
115
+
116
+ should 'not be created' do
117
+ assert_equal @count, @user.versions.count
118
+ end
119
+ end
120
+
121
+ context 'that fail' do
122
+ setup do
123
+ User.prepare_versioned_options(:if => [:false], :unless => [:false])
124
+ @user.update_attribute(:last_name, 'Jobs')
125
+ end
126
+
127
+ should 'not be created' do
128
+ assert_equal @count, @user.versions.count
129
+ end
130
+ end
131
+ end
132
+
133
+ teardown do
134
+ User.prepare_versioned_options(:if => [], :unless => [])
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,39 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ConfigurationTest < Test::Unit::TestCase
4
+ context 'Global configuration options' do
5
+ setup do
6
+ module Extension; end
7
+
8
+ @options = {
9
+ 'class_name' => 'CustomVersion',
10
+ :extend => Extension,
11
+ :as => :parent
12
+ }
13
+
14
+ VestalVersions.configure do |config|
15
+ @options.each do |key, value|
16
+ config.send("#{key}=", value)
17
+ end
18
+ end
19
+
20
+ @configuration = VestalVersions::Configuration.options
21
+ end
22
+
23
+ should 'should be a hash' do
24
+ assert_kind_of Hash, @configuration
25
+ end
26
+
27
+ should 'have symbol keys' do
28
+ assert @configuration.keys.all?{|k| k.is_a?(Symbol) }
29
+ end
30
+
31
+ should 'store values identical to those given' do
32
+ assert_equal @options.symbolize_keys, @configuration
33
+ end
34
+
35
+ teardown do
36
+ VestalVersions::Configuration.options.clear
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,152 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ControlTest < Test::Unit::TestCase
4
+ context 'Within a skip_version block,' do
5
+ setup do
6
+ @user = User.create(:name => 'Steve Richert')
7
+ @count = @user.versions.count
8
+ end
9
+
10
+ context 'a model update' do
11
+ setup do
12
+ @user.skip_version do
13
+ @user.update_attribute(:last_name, 'Jobs')
14
+ end
15
+ end
16
+
17
+ should 'not create a version' do
18
+ assert_equal @count, @user.versions.count
19
+ end
20
+ end
21
+
22
+ context 'multiple model updates' do
23
+ setup do
24
+ @user.skip_version do
25
+ @user.update_attribute(:first_name, 'Stephen')
26
+ @user.update_attribute(:last_name, 'Jobs')
27
+ @user.update_attribute(:first_name, 'Steve')
28
+ end
29
+ end
30
+
31
+ should 'not create a version' do
32
+ assert_equal @count, @user.versions.count
33
+ end
34
+ end
35
+ end
36
+
37
+ context 'Within a merge_version block,' do
38
+ setup do
39
+ @user = User.create(:name => 'Steve Richert')
40
+ @count = @user.versions.count
41
+ end
42
+
43
+ context 'a model update' do
44
+ setup do
45
+ @user.merge_version do
46
+ @user.update_attribute(:last_name, 'Jobs')
47
+ end
48
+ end
49
+
50
+ should 'create a version' do
51
+ assert_equal @count + 1, @user.versions.count
52
+ end
53
+ end
54
+
55
+ context 'multiple model updates' do
56
+ setup do
57
+ @user.merge_version do
58
+ @user.update_attribute(:first_name, 'Stephen')
59
+ @user.update_attribute(:last_name, 'Jobs')
60
+ @user.update_attribute(:first_name, 'Steve')
61
+ end
62
+ end
63
+
64
+ should 'create a version' do
65
+ assert_equal @count + 1, @user.versions.count
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'Within a append_version block' do
71
+ context '(when no versions exist),' do
72
+ setup do
73
+ @user = User.create(:name => 'Steve Richert')
74
+ @count = @user.versions.count
75
+ end
76
+
77
+ context 'a model update' do
78
+ setup do
79
+ @user.append_version do
80
+ @user.update_attribute(:last_name, 'Jobs')
81
+ end
82
+ end
83
+
84
+ should 'create a version' do
85
+ assert_equal @count + 1, @user.versions.count
86
+ end
87
+ end
88
+
89
+ context 'multiple model updates' do
90
+ setup do
91
+ @user.append_version do
92
+ @user.update_attribute(:first_name, 'Stephen')
93
+ @user.update_attribute(:last_name, 'Jobs')
94
+ @user.update_attribute(:first_name, 'Steve')
95
+ end
96
+ end
97
+
98
+ should 'create a version' do
99
+ assert_equal @count + 1, @user.versions.count
100
+ end
101
+ end
102
+ end
103
+
104
+ context '(when versions exist),' do
105
+ setup do
106
+ @user = User.create(:name => 'Steve Richert')
107
+ @user.update_attribute(:last_name, 'Jobs')
108
+ @user.update_attribute(:last_name, 'Richert')
109
+ @last_version = @user.versions.last
110
+ @count = @user.versions.count
111
+ end
112
+
113
+ context 'a model update' do
114
+ setup do
115
+ @user.append_version do
116
+ @user.update_attribute(:last_name, 'Jobs')
117
+ end
118
+ end
119
+
120
+ should 'not create a version' do
121
+ assert_equal @count, @user.versions.count
122
+ end
123
+
124
+ should 'update the last version' do
125
+ last_version = @user.versions.last
126
+ assert_equal @last_version.id, last_version.id
127
+ assert_not_equal @last_version.attributes, last_version.attributes
128
+ end
129
+ end
130
+
131
+ context 'multiple model updates' do
132
+ setup do
133
+ @user.append_version do
134
+ @user.update_attribute(:first_name, 'Stephen')
135
+ @user.update_attribute(:last_name, 'Jobs')
136
+ @user.update_attribute(:first_name, 'Steve')
137
+ end
138
+ end
139
+
140
+ should 'not create a version' do
141
+ assert_equal @count, @user.versions.count
142
+ end
143
+
144
+ should 'update the last version' do
145
+ last_version = @user.versions.last
146
+ assert_equal @last_version.id, last_version.id
147
+ assert_not_equal @last_version.attributes, last_version.attributes
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end