versions 0.1.0 → 0.2.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.
@@ -29,8 +29,25 @@ class AutoTest < Test::Unit::TestCase
29
29
  @version = BadVersion.create('title' => 'Socrate')
30
30
  end
31
31
 
32
- should 'raise an exception on update' do
33
- assert_raise(NoMethodError) { subject.update_attributes('title' => 'Aristotle') }
32
+ context 'if changed' do
33
+ should 'clone on update' do
34
+ assert_difference('Version.count', 1) do
35
+ subject.update_attributes('title' => 'Aristotle')
36
+ end
37
+
38
+
39
+ assert_difference('Version.count', 1) do
40
+ subject.update_attributes('title' => 'Augustin')
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'if not changed' do
46
+ should 'not clone on update' do
47
+ assert_difference('Version.count', 0) do
48
+ subject.update_attributes('title' => 'Socrate')
49
+ end
50
+ end
34
51
  end
35
52
  end
36
53
 
@@ -92,7 +109,7 @@ class AutoTest < Test::Unit::TestCase
92
109
  subject.update_attributes('title' => 'Aristotle')
93
110
  assert_equal 2, subject.number
94
111
 
95
- subject.update_attributes('title' => 'Aristotle')
112
+ subject.update_attributes('title' => 'Kierkegaard')
96
113
  assert_equal 3, subject.number
97
114
  end
98
115
  end
@@ -23,15 +23,12 @@ class MultiTest < Test::Unit::TestCase
23
23
  include Versions::Multi
24
24
 
25
25
  set_table_name :pages
26
- has_multiple :foos, :class_name => 'MultiTest::SimpleVersion'
26
+ has_multiple :foos, :class_name => 'MultiTest::SimpleVersion', :inverse => 'node'
27
27
  end
28
28
 
29
29
  class Version < ActiveRecord::Base
30
30
  set_table_name :versions
31
31
  include Versions::Auto
32
- def should_clone?
33
- changed?
34
- end
35
32
  end
36
33
  class Page < ActiveRecord::Base
37
34
  set_table_name :pages
@@ -82,16 +79,12 @@ class MultiTest < Test::Unit::TestCase
82
79
  end
83
80
 
84
81
  should 'rollback if foo save fails on create' do
82
+ page = nil
85
83
  assert_difference('MultiTest::SimpleVersion.count', 0) do
86
84
  assert_difference('MultiTest::SimplePage.count', 0) do
87
- assert_raise(ActiveRecord::RecordInvalid) do
88
- begin
89
- page = SimplePage.create('foo_attributes' => {'title' => 'Fly'})
90
- rescue ActiveRecord::RecordInvalid => err
91
- assert_equal 'Validation failed: Foo title should not contain letter y', err.message
92
- raise
93
- end
94
- end
85
+ page = SimplePage.new('foo_attributes' => {'title' => 'Fly'})
86
+ assert !page.save
87
+ assert_contains page.errors.full_messages, 'Foo title should not contain letter y'
95
88
  end
96
89
  end
97
90
  end
@@ -102,6 +95,18 @@ class MultiTest < Test::Unit::TestCase
102
95
  assert !page.update_attributes('foo_attributes' => {'title' => 'fly'})
103
96
  assert_equal 'should not contain letter y', page.errors['foo_title']
104
97
  end
98
+
99
+ should 'find owner back using inverse' do
100
+ page = SimplePage.create
101
+ assert_equal page, page.foo.node
102
+ end
103
+
104
+ should 'list foos' do
105
+ page = SimplePage.create('foo_attributes' => {'title' => 'One'})
106
+ page.foo = SimpleVersion.new('title' => 'Two')
107
+ page.save
108
+ assert_equal 2, page.foos.size
109
+ end
105
110
  end
106
111
 
107
112
  context 'A class with multiple auto versions' do
@@ -111,12 +116,12 @@ class MultiTest < Test::Unit::TestCase
111
116
  assert page.update_attributes('version_attributes' => {'title' => 'newTitle'})
112
117
  end
113
118
  end
114
-
119
+
115
120
  should 'mark new version as not dirty after create' do
116
121
  page = Page.create
117
122
  assert !page.version.changed?
118
123
  end
119
-
124
+
120
125
  should 'mark new version as not dirty after update' do
121
126
  page = Page.create
122
127
  assert page.update_attributes('version_attributes' => {'title' => 'Yodle'})
@@ -136,5 +141,44 @@ class MultiTest < Test::Unit::TestCase
136
141
  assert page.update_attributes('version_attributes' => {'title' => 'One'})
137
142
  end
138
143
  end
144
+
145
+
146
+ should 'list versions' do
147
+ page = Page.create('version_attributes' => {'title' => 'One'})
148
+ assert page.update_attributes('version_attributes' => {'title' => 'Two'})
149
+ assert page.update_attributes('version_attributes' => {'title' => 'Three'})
150
+ assert_equal 3, page.versions.size
151
+ end
152
+ end
153
+
154
+ context 'Defining association with custom foreign_key' do
155
+ should 'not raise an exception if the key exists' do
156
+ assert_nothing_raised do
157
+ class Book < ActiveRecord::Base
158
+ set_table_name :pages
159
+ include Versions::Multi
160
+ has_multiple :versions, :class_name => 'MultiTest::SimpleVersion', :inverse => 'big_book', :foreign_key => 'node_id'
161
+ has_multiple :versions, :class_name => 'MultiTest::SimpleVersion', :inverse => :big_book, :foreign_key => :node_id
162
+ end
163
+ end
164
+ end
165
+
166
+ should 'raise an exception if the key does not exist' do
167
+ assert_raise(TypeError) do
168
+ class Book < ActiveRecord::Base
169
+ set_table_name :pages
170
+ include Versions::Multi
171
+ has_multiple :versions, :class_name => 'MultiTest::SimpleVersion', :inverse => 'big_book', :foreign_key => 'bug_id'
172
+ end
173
+ end
174
+
175
+ assert_raise(TypeError) do
176
+ class Book < ActiveRecord::Base
177
+ set_table_name :pages
178
+ include Versions::Multi
179
+ has_multiple :versions, :class_name => 'MultiTest::SimpleVersion', :inverse => :big_book, :foreign_key => :bug_id
180
+ end
181
+ end
182
+ end
139
183
  end
140
184
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{versions}
8
- s.version = "0.1.0"
8
+ s.version = "0.2.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-02-14}
12
+ s.date = %q{2010-02-15}
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 = [
@@ -24,16 +24,18 @@ Gem::Specification.new do |s|
24
24
  "README.rdoc",
25
25
  "Rakefile",
26
26
  "lib/versions.rb",
27
+ "lib/versions/after_commit.rb",
28
+ "lib/versions/attachment.rb",
27
29
  "lib/versions/auto.rb",
28
30
  "lib/versions/destroy.rb",
29
31
  "lib/versions/multi.rb",
30
32
  "lib/versions/shared_attachment.rb",
31
- "lib/versions/shared_attachment/attachment.rb",
32
- "lib/versions/shared_attachment/owner.rb",
33
- "lib/versions/transparent.rb",
34
33
  "lib/versions/version.rb",
35
34
  "test/fixtures.rb",
35
+ "test/fixtures/files/bird.jpg",
36
+ "test/fixtures/files/lake.jpg",
36
37
  "test/helper.rb",
38
+ "test/unit/after_commit_test.rb",
37
39
  "test/unit/attachment_test.rb",
38
40
  "test/unit/auto_test.rb",
39
41
  "test/unit/multi_test.rb",
@@ -49,6 +51,7 @@ Gem::Specification.new do |s|
49
51
  s.test_files = [
50
52
  "test/fixtures.rb",
51
53
  "test/helper.rb",
54
+ "test/unit/after_commit_test.rb",
52
55
  "test/unit/attachment_test.rb",
53
56
  "test/unit/auto_test.rb",
54
57
  "test/unit/multi_test.rb",
@@ -63,15 +66,18 @@ Gem::Specification.new do |s|
63
66
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
64
67
  s.add_development_dependency(%q<shoulda>, [">= 0"])
65
68
  s.add_development_dependency(%q<property>, [">= 0.8.1"])
69
+ s.add_development_dependency(%q<activesupport>, [">= 0"])
66
70
  s.add_runtime_dependency(%q<activerecord>, [">= 0"])
67
71
  else
68
72
  s.add_dependency(%q<shoulda>, [">= 0"])
69
73
  s.add_dependency(%q<property>, [">= 0.8.1"])
74
+ s.add_dependency(%q<activesupport>, [">= 0"])
70
75
  s.add_dependency(%q<activerecord>, [">= 0"])
71
76
  end
72
77
  else
73
78
  s.add_dependency(%q<shoulda>, [">= 0"])
74
79
  s.add_dependency(%q<property>, [">= 0.8.1"])
80
+ s.add_dependency(%q<activesupport>, [">= 0"])
75
81
  s.add_dependency(%q<activerecord>, [">= 0"])
76
82
  end
77
83
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: versions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gaspard Bucher
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-14 00:00:00 +01:00
12
+ date: 2010-02-15 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,6 +32,16 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.8.1
34
34
  version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: activesupport
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
35
45
  - !ruby/object:Gem::Dependency
36
46
  name: activerecord
37
47
  type: :runtime
@@ -59,16 +69,18 @@ files:
59
69
  - README.rdoc
60
70
  - Rakefile
61
71
  - lib/versions.rb
72
+ - lib/versions/after_commit.rb
73
+ - lib/versions/attachment.rb
62
74
  - lib/versions/auto.rb
63
75
  - lib/versions/destroy.rb
64
76
  - lib/versions/multi.rb
65
77
  - lib/versions/shared_attachment.rb
66
- - lib/versions/shared_attachment/attachment.rb
67
- - lib/versions/shared_attachment/owner.rb
68
- - lib/versions/transparent.rb
69
78
  - lib/versions/version.rb
70
79
  - test/fixtures.rb
80
+ - test/fixtures/files/bird.jpg
81
+ - test/fixtures/files/lake.jpg
71
82
  - test/helper.rb
83
+ - test/unit/after_commit_test.rb
72
84
  - test/unit/attachment_test.rb
73
85
  - test/unit/auto_test.rb
74
86
  - test/unit/multi_test.rb
@@ -106,6 +118,7 @@ summary: A list of libraries to work with ActiveRecord model versioning
106
118
  test_files:
107
119
  - test/fixtures.rb
108
120
  - test/helper.rb
121
+ - test/unit/after_commit_test.rb
109
122
  - test/unit/attachment_test.rb
110
123
  - test/unit/auto_test.rb
111
124
  - test/unit/multi_test.rb
@@ -1,66 +0,0 @@
1
- module Versions
2
- # This module enables file attachments to versions. The file is shared between versions if
3
- # it is not changed. The Attachment only stores a reference to the file which is saved in the
4
- # filesystem.
5
- module SharedAttachment
6
- class Attachment < ::ActiveRecord::Base
7
- set_table_name 'attachments'
8
- after_destroy :destroy_file
9
- after_save :write_file
10
-
11
- def unlink(model)
12
- link_count = model.class.count(:conditions => ["attachment_id = ? AND id != ?", self.id, model.id])
13
- if link_count == 0
14
- destroy
15
- end
16
- end
17
-
18
- def file=(file)
19
- @file = file
20
- self[:filename] = get_filename(file)
21
- end
22
-
23
- def filepath
24
- @filepath ||= begin
25
- digest = Digest::SHA1.hexdigest(self[:id].to_s)
26
- "#{digest[0..0]}/#{digest[1..1]}/#{filename}"
27
- end
28
- end
29
-
30
- private
31
- def write_file
32
- after_commit do
33
- make_file(filepath, @file)
34
- end
35
- end
36
-
37
- def destroy_file
38
- after_commit do
39
- remove_file
40
- end
41
- end
42
-
43
- def make_file(path, data)
44
- FileUtils::mkpath(File.dirname(path)) unless File.exist?(File.dirname(path))
45
- if data.respond_to?(:rewind)
46
- data.rewind
47
- end
48
- File.open(path, "wb") { |f| f.syswrite(data.read) }
49
- end
50
-
51
- def remove_file
52
- FileUtils.rm(filepath)
53
- end
54
-
55
- def get_filename(file)
56
- # make sure name is not corrupted
57
- fname = file.original_filename.gsub(/[^a-zA-Z\-_0-9\.]/,'')
58
- if fname[0..0] == '.'
59
- # Forbid names starting with a dot
60
- fname = Digest::SHA1.hexdigest(Time.now.to_i.to_s)[0..6]
61
- end
62
- fname
63
- end
64
- end # Attachment
65
- end # SharedAttachment
66
- end # Versions
@@ -1,77 +0,0 @@
1
-
2
- module Zena
3
- module Use
4
-
5
- # The attachement module provides shared file attachments to a class with a copy-on-write
6
- # pattern.
7
- # Basically the module provides 'file=' and 'file' methods.
8
- module SharedAttachment
9
- module ClassMethods
10
- def set_attachment_class(class_name)
11
- belongs_to :attachment,
12
- :class_name => class_name,
13
- :foreign_key => 'attachment_id'
14
- end
15
- end
16
-
17
- def self.included(base)
18
- base.class_eval do
19
- before_create :save_attachment
20
- before_update :attachment_before_update
21
- before_destroy :attachment_before_destroy
22
-
23
- extend Zena::Use::SharedAttachment::ClassMethods
24
- set_attachment_class 'Zena::Use::SharedAttachment::Attachment'
25
- end
26
- end
27
-
28
- def file=(file)
29
- if attachment
30
- @attachment_to_unlink = self.attachment
31
- self.attachment = nil
32
- end
33
- @attachment_need_save = true
34
- self.build_attachment(:file => file)
35
- end
36
-
37
- def filepath
38
- attachment ? attachment.filepath : nil
39
- end
40
-
41
- private
42
- def save_attachment
43
- if @attachment_need_save
44
- @attachment_need_save = nil
45
- attachment.save
46
- else
47
- true
48
- end
49
- end
50
-
51
- def attachment_before_update
52
- if @attachment_to_unlink
53
- @attachment_to_unlink.unlink(self)
54
- @attachment_to_unlink = nil
55
- end
56
- save_attachment
57
- end
58
-
59
- def attachment_before_destroy
60
- if attachment = self.attachment
61
- attachment.unlink(self)
62
- else
63
- true
64
- end
65
- end
66
-
67
- def unlink_attachment_mark
68
- @attachment_to_unlink = self.attachment
69
- end
70
-
71
- def unlink_attachment
72
- end
73
-
74
-
75
- end # SharedAttachment
76
- end # Use
77
- end # Zena
@@ -1,98 +0,0 @@
1
- module Zena
2
- module Use
3
- # This module lets the user use a node as if it was not versioned and will
4
- # take care of routing the attributes between the node and the version.
5
- module TransparentVersion
6
-
7
- def self.included(base)
8
- base.class_eval do
9
- # When writing attributes, we send everything that we do not know of
10
- # to the version.
11
- def attributes_with_multi_version=(attributes)
12
- columns = self.class.column_names
13
- version_attributes = {}
14
- attributes.keys.each do |k|
15
- if !respond_to?("#{k}=") && !columns.include?(k)
16
- version_attributes[k] = attributes.delete(k)
17
- end
18
- end
19
- version.attributes = version_attributes
20
- self.attributes_without_multi_version = attributes
21
- end
22
-
23
- alias_method_chain :attributes=, :multi_version
24
- end
25
- end
26
-
27
- private
28
- # We need method_missing in forms, normal access in templates should be made
29
- # through 'node.version.xxxx', not 'node.xxxx'.
30
- def method_missing(meth, *args)
31
- method = meth.to_s
32
- if !args.empty? || method[-1..-1] == '?' || self.class.column_names.include?(method)
33
- super
34
- elsif version.respond_to?(meth)
35
- version.send(meth)
36
- else
37
- #version.prop[meth.to_s]
38
- super
39
- end
40
- end
41
-
42
- # Any attribute starting with 'v_' belongs to the 'version' or 'redaction'
43
- # Any attribute starting with 'c_' belongs to the 'version' or 'redaction' content
44
- # FIXME: performance: create methods on the fly so that next calls will not pass through 'method_missing'. #189.
45
- # FIXME: this should not be used anymore. Remove.
46
- # def method_missing(meth, *args)
47
- # if meth.to_s =~ /^(v_|c_|d_)(([\w_\?]+)(=?))$/
48
- # target = $1
49
- # method = $2
50
- # value = $3
51
- # mode = $4
52
- # if mode == '='
53
- # begin
54
- # # set
55
- # unless recipient = redaction
56
- # # remove trailing '='
57
- # redaction_error(meth.to_s[0..-2], "could not be set (no redaction)")
58
- # return
59
- # end
60
- #
61
- # case target
62
- # when 'c_'
63
- # if recipient.content_class && recipient = recipient.redaction_content
64
- # recipient.send(method,*args)
65
- # else
66
- # redaction_error(meth.to_s[0..-2], "cannot be set") # remove trailing '='
67
- # end
68
- # when 'd_'
69
- # recipient.prop[method[0..-2]] = args[0]
70
- # else
71
- # recipient.send(method,*args)
72
- # end
73
- # rescue NoMethodError
74
- # # bad attribute, just ignore
75
- # end
76
- # else
77
- # # read
78
- # recipient = version
79
- # if target == 'd_'
80
- # version.prop[method]
81
- # else
82
- # recipient = recipient.content if target == 'c_'
83
- # return nil unless recipient
84
- # begin
85
- # recipient.send(method,*args)
86
- # rescue NoMethodError
87
- # # bad attribute
88
- # return nil
89
- # end
90
- # end
91
- # end
92
- # else
93
- # super
94
- # end
95
- # end
96
- end
97
- end
98
- end