versions 0.2.1 → 0.3.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.
- 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
|