activerecord-duplicate 0.5.0 → 0.5.1

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.
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'activerecord-duplicate'
3
- gem.version = '0.5.0'
3
+ gem.version = '0.5.1'
4
4
  gem.authors = 'Mario Uher'
5
5
  gem.email = 'uher.mario@gmail.com'
6
6
  gem.description = gem.summary = 'Duplicating ActiveRecords is easy again.'
@@ -1,10 +1,11 @@
1
1
  source :rubygems
2
2
 
3
- gem 'activerecord', git: 'git://github.com/rails/rails.git'
3
+ gem 'activerecord', github: 'rails/rails'
4
+ gem 'active_record_deprecated_finders', github: 'rails/active_record_deprecated_finders'
4
5
 
5
6
  group :development do
6
7
  gem 'minitest'
7
8
  gem 'purdytest'
8
- gem 'rails', git: 'git://github.com/rails/rails.git'
9
+ gem 'rails', github: 'rails/rails'
9
10
  gem 'sqlite3'
10
11
  end
@@ -1,4 +1,4 @@
1
- require 'activerecord-duplicate/active_record/duplicate'
1
+ require 'activerecord-duplicate/duplicate'
2
2
  require 'activerecord-duplicate/railtie' if defined?(Rails)
3
3
 
4
4
  module ActiveRecord::Duplicate
@@ -0,0 +1,95 @@
1
+ module ActiveRecord::Duplicate
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ define_callbacks :duplication, terminator: "result == false", scope: [:kind, :name]
6
+
7
+ class_attribute :_duplicatable_attributes
8
+ attr_accessor :duplication_parent, :duplication_context
9
+ end
10
+
11
+ def duplicate
12
+ self.duplication_context = :original
13
+ self.run_callbacks(:duplication) do
14
+ dup.tap do |duplicate|
15
+ duplicate.duplication_context = :duplicate
16
+ duplicate.run_callbacks(:duplication) do
17
+ attributes.each do |key, value|
18
+ value = case true
19
+
20
+ # Duplicate attribute if whitelisted
21
+ when self.class.attr_duplicatable.include?(key.to_sym)
22
+ value
23
+
24
+ # If not whitelisted, set to default value
25
+ when (column = self.class.columns.detect { |c| c.name == key }).present?
26
+ column.default
27
+
28
+ else
29
+ nil
30
+ end
31
+
32
+ duplicate.send(:"#{key}=", value)
33
+ end
34
+
35
+ self.class.reflect_on_all_associations.each do |association|
36
+ name = association.name
37
+ macro = association.macro
38
+ association = self.association(association.name)
39
+
40
+ case macro
41
+ when :belongs_to
42
+ # Duplicate all belongs_to associations.
43
+ if duplication_parent.is_a?(association.klass)
44
+ duplicate.send(:"#{name}=", duplication_parent)
45
+ duplicate.send(:"#{name}_id=", nil)
46
+ else
47
+ duplicate.send(:"#{name}=", send(name))
48
+ end
49
+
50
+ when :has_many
51
+ # Duplicate all has_many associations.
52
+ duplicate.send(:"#{name}=", send(name).map do |object|
53
+ object.duplication_parent = duplicate
54
+ object = object.duplicate
55
+ next unless object.present?
56
+
57
+ object
58
+ end.compact)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ module ClassMethods
67
+ def attr_duplicatable(*attributes)
68
+ self._duplicatable_attributes = attributes.map(&:to_sym) if attributes.present?
69
+ self._duplicatable_attributes || []
70
+ end
71
+
72
+ # Duplicated from activemodel/lib/active_model/validations/callbacks.rb
73
+ def before_duplication(*args, &block)
74
+ options = args.last
75
+
76
+ if options.is_a?(Hash) && options[:on]
77
+ options[:if] = Array.wrap(options[:if])
78
+ options[:if].unshift("self.duplication_context == :#{options[:on]}")
79
+ end
80
+
81
+ set_callback(:duplication, :before, *args, &block)
82
+ end
83
+
84
+ def after_duplication(*args, &block)
85
+ options = args.extract_options!
86
+
87
+ options[:prepend] = true
88
+ options[:if] = Array.wrap(options[:if])
89
+ options[:if] << "!halted"
90
+ options[:if].unshift("self.duplication_context == :#{options[:on]}") if options[:on]
91
+
92
+ set_callback(:duplication, :after, *(args << options), &block)
93
+ end
94
+ end
95
+ end
@@ -1,6 +1,6 @@
1
1
  require File.expand_path('../spec_helper', __FILE__)
2
2
 
3
- describe ActiveRecord::Duplicate::Callbacks do
3
+ describe ActiveRecord::Duplicate do
4
4
  let(:klass) { Class.new(ActiveRecord::Base) { self.table_name = 'records' } }
5
5
 
6
6
 
@@ -16,7 +16,7 @@ describe ActiveRecord::Duplicate::Callbacks do
16
16
  mock.expect(:after_duplication, nil, [:original])
17
17
  mock.expect(:before_duplication, nil, [:duplicate])
18
18
  mock.expect(:after_duplication, nil, [:duplicate])
19
-
19
+
20
20
  klass.create.duplicate
21
21
  mock.verify
22
22
  end
@@ -32,23 +32,16 @@ describe 'Integration' do
32
32
  class Post < ActiveRecord::Base
33
33
  # Don't duplicate copyrighted posts
34
34
  before_duplication { !self.is_copyrighted? }
35
- after_duplication(:increase_counter, on: :duplicate)
35
+ after_duplication(on: :duplicate) { self.title = title.match(/\d+$/) ? title.succ : "#{title} 2" }
36
36
 
37
37
  belongs_to :blog
38
38
  has_many :comments
39
39
  has_many :ratings, as: :parent
40
40
 
41
- attr_duplicatable :content
41
+ attr_duplicatable :title, :content
42
42
  class_attribute :counter
43
43
 
44
44
  validates :title, presence: true, uniqueness: true
45
-
46
- private
47
- def increase_counter
48
- self.class.counter ||= 0
49
- self.class.counter += 1
50
- self.title = "Lorem #{self.class.counter}"
51
- end
52
45
  end
53
46
 
54
47
  class Comment < ActiveRecord::Base
@@ -64,7 +57,7 @@ describe 'Integration' do
64
57
  end
65
58
 
66
59
 
67
- let(:blog) { Blog.create }
60
+ let(:blog) { Blog.create! }
68
61
 
69
62
 
70
63
  describe 'duplicating blog' do
@@ -78,15 +71,15 @@ describe 'Integration' do
78
71
 
79
72
 
80
73
  it 'duplicates posts too' do
81
- 3.times do |i|
82
- post = blog.posts.create(title: "Post #{i}")
83
- rating = post.ratings.create(value: 5)
74
+ %w[Sample Blog Post].each do |title|
75
+ post = blog.posts.create!(title: title)
76
+ rating = post.ratings.create!(value: 5)
84
77
  end
85
78
 
86
79
  subject.posts.all?(&:new_record?).must_equal(true)
87
80
  subject.posts.size.must_equal(3)
88
81
 
89
- subject.save
82
+ subject.save!
90
83
 
91
84
  Blog.count.must_equal(2)
92
85
  Post.count.must_equal(6)
@@ -95,28 +88,30 @@ describe 'Integration' do
95
88
 
96
89
 
97
90
  it 'sets blog association' do
98
- 3.times do |i|
99
- post = blog.posts.create(title: "Post #{i}")
100
- rating = post.ratings.create(value: 5)
91
+ %w[Sample Blog Post].each do |title|
92
+ post = blog.posts.create!(title: title)
93
+ rating = post.ratings.create!(value: 5)
101
94
  end
102
95
 
103
96
  subject.posts.each do |post|
104
97
  post.blog.must_equal(subject)
105
98
  post.blog_id.must_be_nil
106
99
  end
100
+
101
+ subject.save!
107
102
  end
108
103
 
109
104
 
110
105
  it 'ignores copyrighted posts' do
111
- 3.times do |i|
112
- post = blog.posts.create(title: "Post #{i}", is_copyrighted: i == 0)
113
- rating = post.ratings.create(value: 5)
106
+ %w[Sample Blog Post].each do |title|
107
+ post = blog.posts.create!(title: title, is_copyrighted: title == 'Sample')
108
+ rating = post.ratings.create!(value: 5)
114
109
  end
115
110
 
116
111
  subject.posts.all?(&:new_record?).must_equal(true)
117
112
  subject.posts.size.must_equal(2)
118
113
 
119
- subject.save
114
+ subject.save!
120
115
 
121
116
  Blog.count.must_equal(2)
122
117
  Post.count.must_equal(5)
@@ -124,27 +119,29 @@ describe 'Integration' do
124
119
  end
125
120
 
126
121
 
127
- it 'ignores posts copyright flag' do
128
- post = blog.posts.create(title: 'Post', content: 'Lorem', published_at: Time.now)
129
- rating = post.ratings.create(value: 5)
122
+ it 'ignores posts published_at timestamp' do
123
+ post = blog.posts.create!(title: 'Post', content: 'Lorem', published_at: Time.now)
124
+ rating = post.ratings.create!(value: 5)
130
125
 
131
126
  post = subject.posts.first
132
127
  post.wont_be_nil
133
128
  post.content.must_equal('Lorem')
134
129
  post.published_at.must_be_nil
130
+
131
+ subject.save!
135
132
  end
136
133
 
137
134
 
138
135
  it 'wont duplicate comments' do
139
- post = blog.posts.create(title: 'Post')
140
- rating = post.ratings.create(value: 5)
141
- 3.times { post.comments.create }
136
+ post = blog.posts.create!(title: 'Post')
137
+ rating = post.ratings.create!(value: 5)
138
+ 3.times { post.comments.create! }
142
139
 
143
140
  post = subject.posts.first
144
141
  post.wont_be_nil
145
142
  post.comments.size.must_equal(0)
146
143
 
147
- subject.save
144
+ subject.save!
148
145
 
149
146
  Blog.count.must_equal(2)
150
147
  Post.count.must_equal(2)
@@ -156,9 +153,10 @@ describe 'Integration' do
156
153
 
157
154
  describe 'duplicating post' do
158
155
  it 'sets blog association' do
159
- post = blog.posts.create
156
+ post = blog.posts.create!(title: 'Post')
160
157
 
161
158
  post = post.duplicate
159
+ post.save!
162
160
 
163
161
  post.blog.must_equal(blog)
164
162
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-duplicate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-18 00:00:00.000000000 Z
12
+ date: 2012-04-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
- requirement: &70285775741840 !ruby/object:Gem::Requirement
16
+ requirement: &70282697881420 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70285775741840
24
+ version_requirements: *70282697881420
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: minitest
27
- requirement: &70285775741440 !ruby/object:Gem::Requirement
27
+ requirement: &70282697880800 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70285775741440
35
+ version_requirements: *70282697880800
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: purdytest
38
- requirement: &70285775740980 !ruby/object:Gem::Requirement
38
+ requirement: &70282697880060 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70285775740980
46
+ version_requirements: *70282697880060
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rails
49
- requirement: &70285775740480 !ruby/object:Gem::Requirement
49
+ requirement: &70282697879480 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '3.1'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70285775740480
57
+ version_requirements: *70282697879480
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &70285775740060 !ruby/object:Gem::Requirement
60
+ requirement: &70282697879060 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70285775740060
68
+ version_requirements: *70282697879060
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
- requirement: &70285775739600 !ruby/object:Gem::Requirement
71
+ requirement: &70282697878580 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70285775739600
79
+ version_requirements: *70282697878580
80
80
  description: Duplicating ActiveRecords is easy again.
81
81
  email: uher.mario@gmail.com
82
82
  executables: []
@@ -92,8 +92,7 @@ files:
92
92
  - gemfiles/Rails_3_2.gemfile
93
93
  - gemfiles/Rails_master.gemfile
94
94
  - lib/activerecord-duplicate.rb
95
- - lib/activerecord-duplicate/active_record/duplicate.rb
96
- - lib/activerecord-duplicate/active_record/duplicate/callbacks.rb
95
+ - lib/activerecord-duplicate/duplicate.rb
97
96
  - lib/activerecord-duplicate/railtie.rb
98
97
  - spec/acts_as_duplicator_spec.rb
99
98
  - spec/callbacks_spec.rb
@@ -1,71 +0,0 @@
1
- require 'activerecord-duplicate/active_record/duplicate/callbacks'
2
-
3
- module ActiveRecord
4
- module Duplicate
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- class_attribute :_duplicatable_attributes
9
-
10
- attr_accessor :duplication_parent
11
-
12
- include ActiveRecord::Duplicate::Callbacks
13
- end
14
-
15
- def duplicate
16
- dup.tap do |duplicate|
17
- attributes.each do |key, value|
18
- value = case true
19
-
20
- # Duplicate attribute if whitelisted
21
- when self.class.attr_duplicatable.include?(key.to_sym)
22
- value
23
-
24
- # If not whitelisted, set to default value
25
- when (column = self.class.columns.detect { |c| c.name == key }).present?
26
- column.default
27
-
28
- else
29
- nil
30
- end
31
-
32
- duplicate.send(:"#{key}=", value)
33
- end
34
-
35
- self.class.reflect_on_all_associations.each do |association|
36
- name = association.name
37
- macro = association.macro
38
- association = self.association(association.name)
39
-
40
- case macro
41
- when :belongs_to
42
- # Duplicate all belongs_to associations.
43
- if duplication_parent.is_a?(association.klass)
44
- duplicate.send(:"#{name}=", duplication_parent)
45
- duplicate.send(:"#{name}_id=", nil)
46
- else
47
- duplicate.send(:"#{name}=", send(name))
48
- end
49
-
50
- when :has_many
51
- # Duplicate all has_many associations.
52
- duplicate.send(:"#{name}=", send(name).map do |object|
53
- object.duplication_parent = duplicate
54
- object = object.duplicate
55
- next unless object.present?
56
-
57
- object
58
- end.compact)
59
- end
60
- end
61
- end
62
- end
63
-
64
- module ClassMethods
65
- def attr_duplicatable(*attributes)
66
- self._duplicatable_attributes = attributes.map(&:to_sym) if attributes.present?
67
- self._duplicatable_attributes || []
68
- end
69
- end
70
- end
71
- end
@@ -1,49 +0,0 @@
1
- module ActiveRecord
2
- module Duplicate
3
- module Callbacks
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- define_callbacks :duplication, terminator: "result == false", scope: [:kind, :name]
8
- attr_accessor :duplication_context
9
- end
10
-
11
- def dup
12
- super.tap do |duplicate|
13
- duplicate.duplication_context = :duplicate
14
- duplicate.run_callbacks(:duplication)
15
- end
16
- end
17
-
18
- def duplicate
19
- self.duplication_context = :original
20
- self.run_callbacks(:duplication) { super }
21
- end
22
-
23
- module ClassMethods
24
- # Duplicated from activemodel/lib/active_model/validations/callbacks.rb
25
- def before_duplication(*args, &block)
26
- options = args.last
27
-
28
- if options.is_a?(Hash) && options[:on]
29
- options[:if] = Array.wrap(options[:if])
30
- options[:if].unshift("self.duplication_context == :#{options[:on]}")
31
- end
32
-
33
- set_callback(:duplication, :before, *args, &block)
34
- end
35
-
36
- def after_duplication(*args, &block)
37
- options = args.extract_options!
38
-
39
- options[:prepend] = true
40
- options[:if] = Array.wrap(options[:if])
41
- options[:if] << "!halted"
42
- options[:if].unshift("self.duplication_context == :#{options[:on]}") if options[:on]
43
-
44
- set_callback(:duplication, :after, *(args << options), &block)
45
- end
46
- end
47
- end
48
- end
49
- end