vestal_versions 0.8.3 → 1.0.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 +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