versions 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/History.txt +9 -0
- data/lib/versions/auto.rb +5 -2
- data/lib/versions/destroy.rb +12 -50
- data/lib/versions/multi.rb +26 -8
- data/lib/versions/shared_attachment.rb +26 -15
- data/lib/versions/version.rb +1 -1
- data/lib/versions.rb +1 -0
- data/test/fixtures.rb +6 -7
- data/test/unit/auto_test.rb +11 -0
- data/test/unit/destroy_test.rb +94 -0
- data/test/unit/multi_test.rb +99 -54
- data/versions.gemspec +5 -3
- metadata +40 -21
data/.gitignore
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.3.0 2010-05-27
|
2
|
+
|
3
|
+
* 1 major enhancement
|
4
|
+
* Added 'destroy' module to destroy with __destroy nested attribute.
|
5
|
+
|
6
|
+
* 2 minor enhancements
|
7
|
+
* Moved filepath generation in a class method.
|
8
|
+
* Hook to define previous number on increase.
|
9
|
+
|
1
10
|
== 0.2.1 2010-02-16
|
2
11
|
|
3
12
|
* 1 major enhancement
|
data/lib/versions/auto.rb
CHANGED
@@ -30,8 +30,7 @@ module Versions
|
|
30
30
|
self[:number] = 1
|
31
31
|
elsif changed? && should_clone?
|
32
32
|
@previous_id = self[:id]
|
33
|
-
|
34
|
-
self[:number] = @previous_number + 1
|
33
|
+
self[:number] = self.previous_number + 1
|
35
34
|
|
36
35
|
self[:id] = nil
|
37
36
|
self[:created_at] = nil
|
@@ -48,5 +47,9 @@ module Versions
|
|
48
47
|
@previous_number = nil
|
49
48
|
true
|
50
49
|
end
|
50
|
+
|
51
|
+
def previous_number
|
52
|
+
@previous_number ||= self[:number]
|
53
|
+
end
|
51
54
|
end # Auto
|
52
55
|
end # Versions
|
data/lib/versions/destroy.rb
CHANGED
@@ -2,62 +2,24 @@ module Versions
|
|
2
2
|
# If you include this module in your model (which should also include Versions::Multi), deleting
|
3
3
|
# the last version will destroy the model.
|
4
4
|
module Destroy
|
5
|
-
|
6
|
-
# This module should be included in the model that serves as version.
|
7
|
-
module Version
|
8
|
-
def self.included(base)
|
9
|
-
|
10
|
-
base.class_eval do
|
11
|
-
attr_accessor :__destroy
|
12
|
-
belongs_to :node
|
13
|
-
before_create :setup_version_on_create
|
14
|
-
attr_protected :number, :user_id
|
15
|
-
|
16
|
-
alias_method_chain :save, :destroy
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def save_with_destroy(*args)
|
21
|
-
if @__destroy
|
22
|
-
node = self.node
|
23
|
-
if destroy
|
24
|
-
# reset @version
|
25
|
-
node.send(:version_destroyed)
|
26
|
-
true
|
27
|
-
end
|
28
|
-
else
|
29
|
-
save_without_destroy(*args)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
def setup_version_on_create
|
35
|
-
raise "You should define 'setup_version_on_create' method in '#{self.class}' class."
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
5
|
def self.included(base)
|
40
|
-
base.
|
6
|
+
base.class_eval do
|
7
|
+
before_destroy :check_can_destroy
|
8
|
+
alias_method_chain :attributes=, :destroy
|
9
|
+
end
|
41
10
|
end
|
42
11
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
if version.__destroy && versions.count == 1
|
47
|
-
destroy # will destroy last version
|
48
|
-
else
|
49
|
-
save_without_destroy(*args)
|
12
|
+
def attributes_with_destroy=(hash)
|
13
|
+
if hash.delete(:__destroy) || hash.delete('__destroy')
|
14
|
+
self.mark_for_destruction
|
50
15
|
end
|
16
|
+
self.attributes_without_destroy = hash
|
51
17
|
end
|
52
|
-
|
18
|
+
|
53
19
|
private
|
54
|
-
#
|
55
|
-
def
|
56
|
-
|
57
|
-
if versions.loaded?
|
58
|
-
node.versions -= [@version]
|
59
|
-
end
|
20
|
+
# Default is to forbid destruction
|
21
|
+
def check_can_destroy
|
22
|
+
raise Exception.new("You should implement 'check_can_destroy' in #{self.class}")
|
60
23
|
end
|
61
|
-
|
62
24
|
end
|
63
25
|
end
|
data/lib/versions/multi.rb
CHANGED
@@ -31,27 +31,27 @@ module Versions
|
|
31
31
|
# local key to get the current page. Note that the local key does not need to live in the database if the model
|
32
32
|
# defines <tt>set_current_[assoc]_before_update</tt> and <tt>set_current_[assoc]_after_create</tt> where '[assoc]'
|
33
33
|
# represents the association name.
|
34
|
-
def has_multiple(
|
35
|
-
name =
|
36
|
-
klass = (options[:class_name]
|
37
|
-
owner_name = options[:inverse]
|
34
|
+
def has_multiple(association_name, options = {})
|
35
|
+
name = association_name.to_s.singularize
|
36
|
+
klass = (options[:class_name] || name.capitalize).constantize
|
37
|
+
owner_name = options[:inverse] || self.to_s.split('::').last.underscore
|
38
38
|
foreign_key = (options[:foreign_key] || "#{owner_name}_id").to_s
|
39
39
|
local_key = (options[:local_key] || "#{name}_id").to_s
|
40
40
|
|
41
41
|
raise TypeError.new("Missing 'number' field in table #{klass.table_name}.") unless klass.column_names.include?('number')
|
42
42
|
raise TypeError.new("Missing '#{foreign_key}' in table #{klass.table_name}.") unless klass.column_names.include?(foreign_key)
|
43
43
|
|
44
|
-
has_many
|
44
|
+
has_many association_name, :order => 'number DESC', :class_name => klass.to_s, :foreign_key => foreign_key, :dependent => :destroy
|
45
45
|
validate :"validate_#{name}"
|
46
46
|
after_create :"save_#{name}_after_create"
|
47
47
|
before_update :"save_#{name}_before_update"
|
48
48
|
|
49
|
-
include module_for_multiple(name, klass, owner_name, foreign_key, local_key)
|
49
|
+
include module_for_multiple(name, klass, owner_name, foreign_key, local_key, association_name)
|
50
50
|
klass.belongs_to owner_name, :class_name => self.to_s
|
51
51
|
end
|
52
52
|
|
53
53
|
protected
|
54
|
-
def module_for_multiple(name, klass, owner_name, foreign_key, local_key)
|
54
|
+
def module_for_multiple(name, klass, owner_name, foreign_key, local_key, association_name)
|
55
55
|
|
56
56
|
# Eval is ugly, but it's the fastest solution I know of
|
57
57
|
line = __LINE__
|
@@ -84,6 +84,15 @@ module Versions
|
|
84
84
|
end # end
|
85
85
|
|
86
86
|
def save_#{name}_before_update # def save_version_before_update
|
87
|
+
return true unless @#{name} # return true unless @version
|
88
|
+
if @#{name}.marked_for_destruction? # if @version.marked_for_destruction?
|
89
|
+
if @#{name}.destroy # if @version.destroy
|
90
|
+
set_current_#{name}_before_update # set_current_version_before_update
|
91
|
+
return true # return true
|
92
|
+
else # else
|
93
|
+
return false # return false
|
94
|
+
end # end
|
95
|
+
end # end
|
87
96
|
return true if !@#{name}.changed? # return true if !@version.changed?
|
88
97
|
@#{name}.#{foreign_key} = self[:id] # @version.owner_id = self[:id]
|
89
98
|
if !@#{name}.save(false) # if !@version.save_with_validation(false)
|
@@ -113,7 +122,16 @@ module Versions
|
|
113
122
|
# master record is updated. This method is usually overwritten
|
114
123
|
# in the class.
|
115
124
|
def set_current_#{name}_before_update # def set_current_version_before_update
|
116
|
-
|
125
|
+
if @#{name}.marked_for_destruction? # if @version.marked_for_destruction?
|
126
|
+
if last = #{association_name}.last # if last = versions.last
|
127
|
+
self[:#{local_key}] = last.id # self[:version_id] = versions.last.id
|
128
|
+
else # else
|
129
|
+
self[:#{local_key}] = nil # self[:version_id] = nil
|
130
|
+
end # end
|
131
|
+
@#{name} = nil # @version = nil
|
132
|
+
else # else
|
133
|
+
self[:#{local_key}] = @#{name}.id # self[:version_id] = @version.id
|
134
|
+
end # end
|
117
135
|
end # end
|
118
136
|
|
119
137
|
# This method is triggered when the version is saved, after the
|
@@ -6,6 +6,11 @@ module Versions
|
|
6
6
|
after_destroy :destroy_file
|
7
7
|
after_save :write_file
|
8
8
|
|
9
|
+
def self.filepath(id, filename)
|
10
|
+
digest = ::Digest::SHA1.hexdigest(id.to_s)
|
11
|
+
"#{digest[0..0]}/#{digest[1..1]}/#{filename}"
|
12
|
+
end
|
13
|
+
|
9
14
|
def unlink(model)
|
10
15
|
link_count = model.class.count(:conditions => ["attachment_id = ? AND id != ?", self.id, model.id])
|
11
16
|
if link_count == 0
|
@@ -15,7 +20,16 @@ module Versions
|
|
15
20
|
|
16
21
|
def file=(file)
|
17
22
|
@file = file
|
18
|
-
self
|
23
|
+
self.filename = get_filename(file)
|
24
|
+
end
|
25
|
+
|
26
|
+
def filename=(name)
|
27
|
+
fname = name.gsub(/[^a-zA-Z\-_0-9\.]/,'')
|
28
|
+
if fname[0..0] == '.'
|
29
|
+
# Forbid names starting with a dot
|
30
|
+
fname = Digest::SHA1.hexdigest(Time.now.to_i.to_s)[0..6]
|
31
|
+
end
|
32
|
+
self[:filename] = fname
|
19
33
|
end
|
20
34
|
|
21
35
|
def file
|
@@ -23,9 +37,7 @@ module Versions
|
|
23
37
|
end
|
24
38
|
|
25
39
|
def filepath
|
26
|
-
@filepath ||=
|
27
|
-
"#{digest[0..0]}/#{digest[1..1]}/#{filename}"
|
28
|
-
end
|
40
|
+
@filepath ||= self.class.filepath(self[:id], filename)
|
29
41
|
end
|
30
42
|
|
31
43
|
private
|
@@ -45,10 +57,15 @@ module Versions
|
|
45
57
|
FileUtils::mkpath(File.dirname(path)) unless File.exist?(File.dirname(path))
|
46
58
|
if data.respond_to?(:rewind)
|
47
59
|
data.rewind
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
60
|
+
|
61
|
+
File.open(path, "wb") do |file|
|
62
|
+
while buffer = data.read(2_024_000)
|
63
|
+
file.syswrite(buffer)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else
|
67
|
+
File.open(path, "wb") do |file|
|
68
|
+
file.syswrite(data.read)
|
52
69
|
end
|
53
70
|
end
|
54
71
|
end
|
@@ -58,13 +75,7 @@ module Versions
|
|
58
75
|
end
|
59
76
|
|
60
77
|
def get_filename(file)
|
61
|
-
|
62
|
-
fname = file.original_filename.gsub(/[^a-zA-Z\-_0-9\.]/,'')
|
63
|
-
if fname[0..0] == '.'
|
64
|
-
# Forbid names starting with a dot
|
65
|
-
fname = Digest::SHA1.hexdigest(Time.now.to_i.to_s)[0..6]
|
66
|
-
end
|
67
|
-
fname
|
78
|
+
file.original_filename
|
68
79
|
end
|
69
80
|
end # SharedAttachment
|
70
81
|
end # Versions
|
data/lib/versions/version.rb
CHANGED
data/lib/versions.rb
CHANGED
data/test/fixtures.rb
CHANGED
@@ -20,7 +20,6 @@ begin
|
|
20
20
|
def self.up
|
21
21
|
create_table 'pages' do |t|
|
22
22
|
t.integer 'version_id'
|
23
|
-
t.integer 'foo_id'
|
24
23
|
t.string 'name'
|
25
24
|
t.timestamps
|
26
25
|
end
|
@@ -44,10 +43,10 @@ begin
|
|
44
43
|
end
|
45
44
|
|
46
45
|
ActiveRecord::Base.establish_connection(:adapter=>'sqlite3', :database=>':memory:')
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
log_path = Pathname(__FILE__).dirname + '../log/test.log'
|
47
|
+
Dir.mkdir(log_path.dirname) unless File.exist?(log_path.dirname)
|
48
|
+
ActiveRecord::Base.logger = Logger.new(File.open(log_path, 'wb'))
|
49
|
+
ActiveRecord::Migration.verbose = false
|
50
|
+
VersionsMigration.migrate(:up)
|
51
|
+
ActiveRecord::Migration.verbose = true
|
53
52
|
end
|
data/test/unit/auto_test.rb
CHANGED
@@ -112,6 +112,17 @@ class AutoTest < Test::Unit::TestCase
|
|
112
112
|
subject.update_attributes('title' => 'Kierkegaard')
|
113
113
|
assert_equal 3, subject.number
|
114
114
|
end
|
115
|
+
|
116
|
+
should 'call previous_number to build number' do
|
117
|
+
class << subject
|
118
|
+
def previous_number
|
119
|
+
5
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
subject.update_attributes('title' => 'Aristotle')
|
124
|
+
assert_equal 6, subject.number
|
125
|
+
end
|
115
126
|
end
|
116
127
|
end
|
117
128
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class DestroyTest < Test::Unit::TestCase
|
4
|
+
class Version < ActiveRecord::Base
|
5
|
+
attr_accessor :can_destroy
|
6
|
+
set_table_name :versions
|
7
|
+
include Versions::Auto
|
8
|
+
include Versions::Destroy
|
9
|
+
|
10
|
+
def check_can_destroy
|
11
|
+
defined?(@can_destroy) ? @can_destroy : true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Page < ActiveRecord::Base
|
16
|
+
set_table_name :pages
|
17
|
+
include Versions::Multi
|
18
|
+
has_multiple :versions, :class_name => 'DestroyTest::Version'
|
19
|
+
end
|
20
|
+
|
21
|
+
class VersionWithoutCanDestroy < ActiveRecord::Base
|
22
|
+
attr_accessor :can_destroy
|
23
|
+
set_table_name :versions
|
24
|
+
include Versions::Auto
|
25
|
+
include Versions::Destroy
|
26
|
+
end
|
27
|
+
|
28
|
+
class Page2 < ActiveRecord::Base
|
29
|
+
set_table_name :pages
|
30
|
+
include Versions::Multi
|
31
|
+
has_multiple :versions, :class_name => 'DestroyTest::VersionWithoutCanDestroy', :foreign_key => 'page_id'
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'A page with a version' do
|
35
|
+
subject do
|
36
|
+
Page.create('name' => 'one', 'version_attributes' => {'title' => 'First'})
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'destroy version on __destroy nested attribute' do
|
40
|
+
subject
|
41
|
+
assert_difference('Version.count', -1) do
|
42
|
+
subject.update_attributes('version_attributes' => {:__destroy => true})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
should 'not destroy if not allowed' do
|
47
|
+
subject.version.can_destroy = false
|
48
|
+
assert_difference('Version.count', 0) do
|
49
|
+
subject.update_attributes('version_attributes' => {:__destroy => true})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end # A page with a version
|
53
|
+
|
54
|
+
context 'A version without can destroy' do
|
55
|
+
subject do
|
56
|
+
Page2.create('name' => 'one', 'version_attributes' => {'title' => 'First'})
|
57
|
+
end
|
58
|
+
|
59
|
+
should 'raise an exception on __destroy' do
|
60
|
+
assert_raise(Exception) do
|
61
|
+
subject.update_attributes('version_attributes' => {:__destroy => true})
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'A page with many versions' do
|
67
|
+
subject do
|
68
|
+
p = Page.create('name' => 'one', 'version_attributes' => {'title' => 'first'})
|
69
|
+
p.update_attributes('version_attributes' => {'title' => 'second'})
|
70
|
+
p
|
71
|
+
end
|
72
|
+
|
73
|
+
should 'remove version from versions on destroy' do
|
74
|
+
# This also loads versions association
|
75
|
+
assert_equal 2, subject.versions.count
|
76
|
+
|
77
|
+
assert_difference('Version.count', -1) do
|
78
|
+
subject.update_attributes('version_attributes' => {'__destroy' => true})
|
79
|
+
end
|
80
|
+
|
81
|
+
assert_equal 1, subject.versions.count
|
82
|
+
assert_equal 'first', subject.versions.first.title
|
83
|
+
end
|
84
|
+
|
85
|
+
should 'update current version on destroy' do
|
86
|
+
old_version_id = subject.version_id
|
87
|
+
|
88
|
+
assert subject.update_attributes('version_attributes' => {'__destroy' => true})
|
89
|
+
|
90
|
+
assert_not_equal old_version_id, subject.version_id
|
91
|
+
assert_equal 'first', subject.version.title
|
92
|
+
end
|
93
|
+
end # A page with a version
|
94
|
+
end
|
data/test/unit/multi_test.rb
CHANGED
@@ -19,103 +19,112 @@ class MultiTest < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
+
|
22
23
|
class SimplePage < ActiveRecord::Base
|
24
|
+
set_table_name :pages
|
23
25
|
include Versions::Multi
|
24
26
|
|
25
|
-
|
26
|
-
has_multiple :foos, :class_name => 'MultiTest::SimpleVersion', :inverse => 'node'
|
27
|
+
has_multiple :simple_versions, :class_name => 'MultiTest::SimpleVersion', :inverse => 'node', :local_key => 'version_id'
|
27
28
|
end
|
28
29
|
|
29
30
|
class Version < ActiveRecord::Base
|
30
31
|
set_table_name :versions
|
31
32
|
include Versions::Auto
|
32
33
|
end
|
34
|
+
|
33
35
|
class Page < ActiveRecord::Base
|
34
36
|
set_table_name :pages
|
35
37
|
include Versions::Multi
|
36
38
|
has_multiple :versions, :class_name => 'MultiTest::Version'
|
37
39
|
end
|
38
40
|
|
39
|
-
context '
|
40
|
-
|
41
|
-
|
42
|
-
assert_nothing_raised { SimplePage.create('name' => 'one', 'foo_attributes' => {'title' => 'First'}) }
|
41
|
+
context 'Creating a page with versions' do
|
42
|
+
should 'accept simple_version nested attributes' do
|
43
|
+
assert_nothing_raised { SimplePage.create('name' => 'one', 'simple_version_attributes' => {'title' => 'First'}) }
|
43
44
|
end
|
44
45
|
|
45
|
-
should 'create a
|
46
|
+
should 'create a simple_version instance of the given type' do
|
46
47
|
page = SimplePage.create
|
47
48
|
assert page.valid?
|
48
|
-
assert_kind_of MultiTest::SimpleVersion, page.
|
49
|
+
assert_kind_of MultiTest::SimpleVersion, page.simple_version
|
49
50
|
end
|
50
51
|
|
51
|
-
should 'set
|
52
|
+
should 'set version_id after_create' do
|
52
53
|
page = SimplePage.create
|
53
|
-
|
54
|
-
assert
|
54
|
+
version_id = page.version_id
|
55
|
+
assert version_id
|
55
56
|
page = SimplePage.find(page)
|
56
|
-
assert_equal
|
57
|
+
assert_equal version_id, page.version_id
|
57
58
|
end
|
58
59
|
|
59
|
-
should 'replace current instance on new
|
60
|
+
should 'replace current instance on new simple_versions' do
|
60
61
|
page = SimplePage.create
|
61
|
-
|
62
|
-
page.
|
62
|
+
first_simple_version = page.simple_version.id
|
63
|
+
page.simple_version = SimpleVersion.new('title' => 'hello')
|
63
64
|
assert page.save
|
64
65
|
page = SimplePage.find(page.id)
|
65
|
-
assert_not_equal
|
66
|
+
assert_not_equal first_simple_version, page.simple_version.id
|
66
67
|
end
|
67
68
|
|
68
|
-
should 'merge
|
69
|
-
page = SimplePage.create('
|
69
|
+
should 'merge simple_version errors in model on create' do
|
70
|
+
page = SimplePage.create('simple_version_attributes' => {'title' => 'Fox'})
|
70
71
|
assert !page.valid?
|
71
|
-
assert_equal 'should not contain letter x', page.errors['
|
72
|
+
assert_equal 'should not contain letter x', page.errors['simple_version_title']
|
72
73
|
end
|
73
74
|
|
74
|
-
should 'merge
|
75
|
-
page = SimplePage.create('
|
75
|
+
should 'merge simple_version errors in model on update' do
|
76
|
+
page = SimplePage.create('simple_version_attributes' => {'title' => 'phone'})
|
76
77
|
assert page.valid?
|
77
|
-
assert !page.update_attributes('
|
78
|
-
assert_equal 'should not contain letter x', page.errors['
|
78
|
+
assert !page.update_attributes('simple_version_attributes' => {'title' => 'fax'})
|
79
|
+
assert_equal 'should not contain letter x', page.errors['simple_version_title']
|
79
80
|
end
|
80
81
|
|
81
|
-
should 'rollback if
|
82
|
+
should 'rollback if simple_version save fails on create' do
|
82
83
|
page = nil
|
83
84
|
assert_difference('MultiTest::SimpleVersion.count', 0) do
|
84
85
|
assert_difference('MultiTest::SimplePage.count', 0) do
|
85
|
-
page = SimplePage.new('
|
86
|
+
page = SimplePage.new('simple_version_attributes' => {'title' => 'Fly'})
|
86
87
|
assert !page.save
|
87
|
-
assert_contains page.errors
|
88
|
+
assert_contains page.errors[:simple_version_title], 'should not contain letter y'
|
88
89
|
end
|
89
90
|
end
|
90
91
|
end
|
91
92
|
|
92
|
-
should 'abort if
|
93
|
-
page = SimplePage.create('
|
93
|
+
should 'abort if version save fails on update' do
|
94
|
+
page = SimplePage.create('simple_version_attributes' => {'title' => 'mosquito'})
|
94
95
|
assert page.valid?
|
95
|
-
assert !page.update_attributes('
|
96
|
-
assert_equal 'should not contain letter y', page.errors['
|
96
|
+
assert !page.update_attributes('simple_version_attributes' => {'title' => 'fly'})
|
97
|
+
assert_equal 'should not contain letter y', page.errors['simple_version_title']
|
97
98
|
end
|
98
99
|
|
99
100
|
should 'find owner back using inverse' do
|
100
101
|
page = SimplePage.create
|
101
|
-
assert_equal page, page.
|
102
|
+
assert_equal page, page.simple_version.node
|
102
103
|
end
|
103
104
|
|
104
|
-
should 'list
|
105
|
-
page = SimplePage.create('
|
106
|
-
page.
|
105
|
+
should 'list simple_versions' do
|
106
|
+
page = SimplePage.create('simple_version_attributes' => {'title' => 'One'})
|
107
|
+
page.simple_version = SimpleVersion.new('title' => 'Two')
|
107
108
|
page.save
|
108
|
-
assert_equal 2, page.
|
109
|
+
assert_equal 2, page.simple_versions.size
|
109
110
|
end
|
110
|
-
end
|
111
|
+
end # Creating a page with versions
|
111
112
|
|
112
|
-
context 'A
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
113
|
+
context 'A simple page with a version' do
|
114
|
+
subject do
|
115
|
+
p = SimplePage.create('simple_version_attributes' => {'title' => 'Buz'})
|
116
|
+
SimplePage.find(p.id)
|
117
|
+
end
|
118
|
+
|
119
|
+
should 'save without validations' do
|
120
|
+
subject.name = 'hop'
|
121
|
+
assert_difference('SimpleVersion.count', 0) do
|
122
|
+
assert subject.save_with_validation(false)
|
117
123
|
end
|
118
124
|
end
|
125
|
+
end # A page with a version
|
126
|
+
|
127
|
+
context 'Creating an object with multiple auto versions' do
|
119
128
|
|
120
129
|
should 'mark new version as not dirty after create' do
|
121
130
|
page = Page.create
|
@@ -128,28 +137,64 @@ class MultiTest < Test::Unit::TestCase
|
|
128
137
|
assert !page.version.changed?
|
129
138
|
end
|
130
139
|
|
131
|
-
should 'find latest version' do
|
132
|
-
page = Page.create
|
133
|
-
v_id = page.version.id
|
134
|
-
assert page.update_attributes('version_attributes' => {'title' => 'newTitle'})
|
135
|
-
assert_not_equal v_id, page.version.id
|
136
|
-
end
|
137
|
-
|
138
140
|
should 'not create new versions on update if content did not change' do
|
139
141
|
page = Page.create('version_attributes' => {'title' => 'One'})
|
140
142
|
assert_difference('Version.count', 0) do
|
141
143
|
assert page.update_attributes('version_attributes' => {'title' => 'One'})
|
142
144
|
end
|
143
145
|
end
|
146
|
+
end
|
144
147
|
|
148
|
+
context 'A page' do
|
145
149
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
150
|
+
context 'with a version' do
|
151
|
+
subject do
|
152
|
+
p = Page.create('version_attributes' => {'title' => 'Fly'})
|
153
|
+
Page.find(p.id)
|
154
|
+
end
|
155
|
+
|
156
|
+
should 'create new versions on update' do
|
157
|
+
subject # create
|
158
|
+
assert_difference('Version.count', 1) do
|
159
|
+
assert subject.update_attributes('version_attributes' => {'title' => 'newTitle'})
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
should 'save without validations' do
|
164
|
+
subject.name = 'hop'
|
165
|
+
assert_difference('Version.count', 0) do
|
166
|
+
assert subject.save_with_validation(false)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
should 'find latest version' do
|
171
|
+
v_id = subject.version.id
|
172
|
+
assert subject.update_attributes('version_attributes' => {'title' => 'newTitle'})
|
173
|
+
assert_not_equal v_id, subject.version.id
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
should 'save master model if version only changed' do
|
178
|
+
subject # create
|
179
|
+
assert_difference('Version.count', 1) do
|
180
|
+
assert subject.update_attributes('version_attributes' => {'title' => 'Two'})
|
181
|
+
end
|
182
|
+
end
|
151
183
|
end
|
152
|
-
|
184
|
+
|
185
|
+
context 'with many versions' do
|
186
|
+
subject do
|
187
|
+
page = Page.create('version_attributes' => {'title' => 'One'})
|
188
|
+
page.update_attributes('version_attributes' => {'title' => 'Two'})
|
189
|
+
page.update_attributes('version_attributes' => {'title' => 'Three'})
|
190
|
+
page
|
191
|
+
end
|
192
|
+
|
193
|
+
should 'list versions' do
|
194
|
+
assert_equal 3, subject.versions.size
|
195
|
+
end
|
196
|
+
end # with many versions
|
197
|
+
end # A page with a version
|
153
198
|
|
154
199
|
context 'Defining association with custom foreign_key' do
|
155
200
|
should 'not raise an exception if the key exists' do
|
data/versions.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{versions}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Gaspard Bucher"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-05-27}
|
13
13
|
s.description = %q{A list of libraries to work with ActiveRecord model versioning: Auto (duplicate on save), Multi (hide many versions behind a single one), Transparent (hide versions from outside world), Property (define properties on model, store them in versions)}
|
14
14
|
s.email = %q{gaspard@teti.ch}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
"test/unit/after_commit_test.rb",
|
39
39
|
"test/unit/attachment_test.rb",
|
40
40
|
"test/unit/auto_test.rb",
|
41
|
+
"test/unit/destroy_test.rb",
|
41
42
|
"test/unit/multi_test.rb",
|
42
43
|
"test/unit/property_test.rb",
|
43
44
|
"test/unit/transparent_test.rb",
|
@@ -46,7 +47,7 @@ Gem::Specification.new do |s|
|
|
46
47
|
s.homepage = %q{http://zenadmin.org/650}
|
47
48
|
s.rdoc_options = ["--charset=UTF-8"]
|
48
49
|
s.require_paths = ["lib"]
|
49
|
-
s.rubygems_version = %q{1.3.
|
50
|
+
s.rubygems_version = %q{1.3.6}
|
50
51
|
s.summary = %q{A list of libraries to work with ActiveRecord model versioning}
|
51
52
|
s.test_files = [
|
52
53
|
"test/fixtures.rb",
|
@@ -54,6 +55,7 @@ Gem::Specification.new do |s|
|
|
54
55
|
"test/unit/after_commit_test.rb",
|
55
56
|
"test/unit/attachment_test.rb",
|
56
57
|
"test/unit/auto_test.rb",
|
58
|
+
"test/unit/destroy_test.rb",
|
57
59
|
"test/unit/multi_test.rb",
|
58
60
|
"test/unit/property_test.rb",
|
59
61
|
"test/unit/transparent_test.rb"
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: versions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Gaspard Bucher
|
@@ -9,49 +14,59 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-
|
17
|
+
date: 2010-05-27 00:00:00 +02:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: shoulda
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
23
29
|
version: "0"
|
24
|
-
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
25
32
|
- !ruby/object:Gem::Dependency
|
26
33
|
name: property
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
37
|
- - ">="
|
32
38
|
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
- 8
|
42
|
+
- 1
|
33
43
|
version: 0.8.1
|
34
|
-
|
44
|
+
type: :development
|
45
|
+
version_requirements: *id002
|
35
46
|
- !ruby/object:Gem::Dependency
|
36
47
|
name: activesupport
|
37
|
-
|
38
|
-
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
50
|
requirements:
|
41
51
|
- - ">="
|
42
52
|
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
43
55
|
version: "0"
|
44
|
-
|
56
|
+
type: :development
|
57
|
+
version_requirements: *id003
|
45
58
|
- !ruby/object:Gem::Dependency
|
46
59
|
name: activerecord
|
47
|
-
|
48
|
-
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
prerelease: false
|
61
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
50
62
|
requirements:
|
51
63
|
- - ">="
|
52
64
|
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
53
67
|
version: "0"
|
54
|
-
|
68
|
+
type: :runtime
|
69
|
+
version_requirements: *id004
|
55
70
|
description: "A list of libraries to work with ActiveRecord model versioning: Auto (duplicate on save), Multi (hide many versions behind a single one), Transparent (hide versions from outside world), Property (define properties on model, store them in versions)"
|
56
71
|
email: gaspard@teti.ch
|
57
72
|
executables: []
|
@@ -83,6 +98,7 @@ files:
|
|
83
98
|
- test/unit/after_commit_test.rb
|
84
99
|
- test/unit/attachment_test.rb
|
85
100
|
- test/unit/auto_test.rb
|
101
|
+
- test/unit/destroy_test.rb
|
86
102
|
- test/unit/multi_test.rb
|
87
103
|
- test/unit/property_test.rb
|
88
104
|
- test/unit/transparent_test.rb
|
@@ -100,18 +116,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
116
|
requirements:
|
101
117
|
- - ">="
|
102
118
|
- !ruby/object:Gem::Version
|
119
|
+
segments:
|
120
|
+
- 0
|
103
121
|
version: "0"
|
104
|
-
version:
|
105
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
123
|
requirements:
|
107
124
|
- - ">="
|
108
125
|
- !ruby/object:Gem::Version
|
126
|
+
segments:
|
127
|
+
- 0
|
109
128
|
version: "0"
|
110
|
-
version:
|
111
129
|
requirements: []
|
112
130
|
|
113
131
|
rubyforge_project:
|
114
|
-
rubygems_version: 1.3.
|
132
|
+
rubygems_version: 1.3.6
|
115
133
|
signing_key:
|
116
134
|
specification_version: 3
|
117
135
|
summary: A list of libraries to work with ActiveRecord model versioning
|
@@ -121,6 +139,7 @@ test_files:
|
|
121
139
|
- test/unit/after_commit_test.rb
|
122
140
|
- test/unit/attachment_test.rb
|
123
141
|
- test/unit/auto_test.rb
|
142
|
+
- test/unit/destroy_test.rb
|
124
143
|
- test/unit/multi_test.rb
|
125
144
|
- test/unit/property_test.rb
|
126
145
|
- test/unit/transparent_test.rb
|