agnostic-duplicate 1.0.0 → 1.0.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.
- checksums.yaml +4 -4
- data/.travis.yml +8 -5
- data/CHANGELOG.md +7 -0
- data/README.md +24 -1
- data/Rakefile.rb +13 -0
- data/agnostic-duplicate.gemspec +4 -2
- data/lib/agnostic/duplicate.rb +72 -21
- data/lib/agnostic/duplicate/version.rb +2 -1
- data/spec/agnostic_duplicate_spec.rb +42 -2
- data/spec/spec_helper.rb +8 -0
- metadata +32 -3
- data/Rakefile +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f1eab323490625f666f5be5cb411b804541d471
|
4
|
+
data.tar.gz: e51eb8409624bdb8ac8819b20056fe06686ddecf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61853c9158efa07ca9a8ff3d8f5791655a6269d692f1bbb4c6ecd823ca1bdd6ac569443fde5813420566a1d7ee679c5d41490094ea6e07508fbb2d47e3cf6993
|
7
|
+
data.tar.gz: 0d073b672d0f70242e7b24ef5f0f9802efded6ca751ec49fb92a9cde4772f734f9eb4b2b676eb045b9e546287e5139df839020d7d4748edb591ecbab10491a4d
|
data/.travis.yml
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
- 2.1.2
|
4
|
+
- 2.1.1
|
5
|
+
- 2.1.0
|
6
|
+
- 2.0.0
|
7
|
+
- 1.9.3
|
8
8
|
script: rspec spec
|
9
|
+
addons:
|
10
|
+
code_climate:
|
11
|
+
repo_token: 11404e3572fdb6bae4c9e45cb6effc8c294a8f9d7ec3f5d581e189eae6008912
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
[](http://badge.fury.io/rb/agnostic-duplicate)
|
2
|
+
[](https://travis-ci.org/dsaenztagarro/agnostic-duplicate)
|
3
|
+
[](https://codeclimate.com/github/dsaenztagarro/agnostic-duplicate)
|
4
|
+
[](https://coveralls.io/r/dsaenztagarro/agnostic-duplicate?branch=master)
|
5
|
+
[](https://gemnasium.com/dsaenztagarro/agnostic-duplicate)
|
6
|
+
|
1
7
|
# Agnostic::Duplicate
|
2
8
|
|
3
9
|
Duplicate objects are provided with an additional method `duplicate` that
|
@@ -99,9 +105,26 @@ set this configuration through `duplicable_config` method:
|
|
99
105
|
end
|
100
106
|
```
|
101
107
|
|
108
|
+
If you want to apply the `duplicate` over a custom instance object instead
|
109
|
+
of the default template for the current configuration, then you can pass a
|
110
|
+
`dup_template` option on the method call
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
otherobject # => Object sharing duplicable attributes with 'myobject'
|
114
|
+
myobject.duplicate dup_template: otherobject
|
115
|
+
```
|
116
|
+
|
117
|
+
As the object passed to dup_template should be compliant with the duplicable
|
118
|
+
attribute list, if there is an error during the process an exception will
|
119
|
+
be raise according to the type of error:
|
120
|
+
|
121
|
+
- Agnostic::Duplicate::ChangeSet::AttributeNotFound
|
122
|
+
- Agnostic::Duplicate::ChangeSet::CopyError
|
123
|
+
|
124
|
+
|
102
125
|
## Contributing
|
103
126
|
|
104
|
-
1. Fork it ( https://github.com/
|
127
|
+
1. Fork it ( https://github.com/dsaenztagarro/agnostic-duplicate/fork )
|
105
128
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
106
129
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
107
130
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/Rakefile.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RuboCop::RakeTask.new do |task|
|
6
|
+
task.requires << 'rubocop-rspec'
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new :specs do |task|
|
10
|
+
task.pattern = Dir['spec/**/*_spec.rb']
|
11
|
+
end
|
12
|
+
|
13
|
+
task default: ['specs']
|
data/agnostic-duplicate.gemspec
CHANGED
@@ -12,10 +12,10 @@ Gem::Specification.new do |spec|
|
|
12
12
|
Duplicate library provides additional support for deep copy or shallow copy of
|
13
13
|
specific fields in your models while you are `dupping` an instance.)
|
14
14
|
summary
|
15
|
-
spec.description = <<-
|
15
|
+
spec.description = <<-desc
|
16
16
|
The advantage of using Duplicate module reside in support for fields that
|
17
17
|
are not duplicated by default for any reason by calling `dup`.)
|
18
|
-
|
18
|
+
desc
|
19
19
|
spec.homepage = 'https://github.com/dsaenztagarro/agnostic-duplicate'
|
20
20
|
spec.license = 'MIT'
|
21
21
|
|
@@ -27,7 +27,9 @@ description
|
|
27
27
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
28
28
|
spec.add_development_dependency 'rake'
|
29
29
|
spec.add_development_dependency 'rspec'
|
30
|
+
spec.add_development_dependency 'codeclimate-test-reporter'
|
30
31
|
spec.add_development_dependency 'simplecov'
|
32
|
+
spec.add_development_dependency 'coveralls'
|
31
33
|
spec.add_development_dependency 'rubocop'
|
32
34
|
spec.add_development_dependency 'reek'
|
33
35
|
spec.add_development_dependency 'cane'
|
data/lib/agnostic/duplicate.rb
CHANGED
@@ -84,6 +84,22 @@ module Agnostic
|
|
84
84
|
# # ...
|
85
85
|
# end
|
86
86
|
# ```
|
87
|
+
#
|
88
|
+
# If you want to apply the `duplicate` over a custom instance object instead
|
89
|
+
# of the default template for the current configuration, then you can pass a
|
90
|
+
# `dup_template` option on the method call
|
91
|
+
#
|
92
|
+
# ```ruby
|
93
|
+
# otherobject # => Object sharing duplicable attributes with 'myobject'
|
94
|
+
# myobject.duplicate dup_template: otherobject
|
95
|
+
# ```
|
96
|
+
#
|
97
|
+
# As the object passed to dup_template should be compliant with the duplicable
|
98
|
+
# attribute list, if there is an error during the process an exception will
|
99
|
+
# be raise according to the type of error:
|
100
|
+
# - Agnostic::Duplicate::ChangeSet::AttributeNotFound
|
101
|
+
# - Agnostic::Duplicate::ChangeSet::CopyError
|
102
|
+
#
|
87
103
|
module Duplicate
|
88
104
|
def self.included(base)
|
89
105
|
base.extend(ClassMethods)
|
@@ -93,8 +109,11 @@ module Agnostic
|
|
93
109
|
|
94
110
|
# Duplicates the object
|
95
111
|
# @return [Duplicate] the new instance object
|
96
|
-
|
97
|
-
|
112
|
+
# @return opts [Hash] the options for duplicating
|
113
|
+
# @option [Object] dup_template The object over attributes are going to be
|
114
|
+
# copied
|
115
|
+
def duplicate(opts = {})
|
116
|
+
(opts[:dup_template] || dup_template).tap do |model|
|
98
117
|
apply_changesets!(model)
|
99
118
|
hook_after_duplicate!(model) if respond_to? :hook_after_duplicate!
|
100
119
|
end
|
@@ -113,6 +132,13 @@ module Agnostic
|
|
113
132
|
# Contains all kinds of changesets that can be applied to a duplicable
|
114
133
|
# object
|
115
134
|
module ChangeSet
|
135
|
+
# Raised when there is an error while trying to copy an attribute
|
136
|
+
class CopyError < StandardError
|
137
|
+
end
|
138
|
+
# Raised when a non existing attribute is tried to be duplicated
|
139
|
+
class AttributeNotFound < StandardError
|
140
|
+
end
|
141
|
+
|
116
142
|
# Base class for all changesets. Subclasses should implement method
|
117
143
|
# `apply` (see #apply)
|
118
144
|
class Base
|
@@ -120,6 +146,13 @@ module Agnostic
|
|
120
146
|
def initialize(attributes)
|
121
147
|
@attributes = attributes
|
122
148
|
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def raise_copy_error_for(attribute)
|
153
|
+
msg = "It wasn't possible to copy attribute '#{attribute}'"
|
154
|
+
fail CopyError, msg, caller
|
155
|
+
end
|
123
156
|
end
|
124
157
|
|
125
158
|
# Defines a changeset where a deep copy wants to be applied to all
|
@@ -130,17 +163,25 @@ module Agnostic
|
|
130
163
|
# @param model [Duplicate] the duplicated new instance object
|
131
164
|
def apply(parent, model)
|
132
165
|
attributes.each do |attribute|
|
133
|
-
|
134
|
-
|
135
|
-
model.send(setter_method, dup_attribute(parent, attribute))
|
136
|
-
else
|
137
|
-
fail "Invalid duplicable attribute '#{attribute}'"
|
166
|
+
unless model.respond_to? "#{attribute}="
|
167
|
+
fail AttributeNotFound, "Attribute: '#{attribute}'", caller
|
138
168
|
end
|
169
|
+
deep_copy = dup_attribute(parent, attribute)
|
170
|
+
copy_attribute(attribute, model, deep_copy)
|
139
171
|
end
|
140
172
|
end
|
141
173
|
|
142
174
|
private
|
143
175
|
|
176
|
+
# @param attribute [Symbol] attribute to be copied
|
177
|
+
# @param parent [Duplicable] the original object to be duplicated
|
178
|
+
# @param model [Duplicable] the duplicated new instance object
|
179
|
+
def copy_attribute(attribute, model, deep_copy)
|
180
|
+
model.send("#{attribute}=", deep_copy)
|
181
|
+
rescue
|
182
|
+
raise_copy_error_for(attribute)
|
183
|
+
end
|
184
|
+
|
144
185
|
# @param parent [Duplicate] the original object to be duplicated
|
145
186
|
# @param attribute [Symbol] the attribute to be duplicated
|
146
187
|
# @return from a duplicable object the duplicated value for the
|
@@ -177,19 +218,30 @@ module Agnostic
|
|
177
218
|
# of the primitive type.
|
178
219
|
class ShallowCopy < Base
|
179
220
|
# Applies changes needed on the duplicated new instance object
|
180
|
-
# @param parent [
|
181
|
-
# @param model [
|
221
|
+
# @param parent [Duplicable] the original object to be duplicated
|
222
|
+
# @param model [Duplicable] the duplicated new instance object
|
182
223
|
def apply(parent, model)
|
183
224
|
attributes.each do |attribute|
|
184
|
-
|
225
|
+
copy_attribute(attribute, parent, model)
|
185
226
|
end
|
186
227
|
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
# @param attribute [Symbol] attribute to be copied
|
232
|
+
# @param parent [Duplicable] the original object to be duplicated
|
233
|
+
# @param model [Duplicable] the duplicated new instance object
|
234
|
+
def copy_attribute(attribute, parent, model)
|
235
|
+
model.send("#{attribute}=", parent.send(attribute))
|
236
|
+
rescue
|
237
|
+
raise_copy_error_for(attribute)
|
238
|
+
end
|
187
239
|
end
|
188
240
|
end
|
189
241
|
|
190
242
|
private
|
191
243
|
|
192
|
-
# @return [
|
244
|
+
# @return [Duplicable] a new instance object based on global duplicable
|
193
245
|
# configuration
|
194
246
|
def dup_template
|
195
247
|
klass = self.class
|
@@ -200,7 +252,7 @@ module Agnostic
|
|
200
252
|
end
|
201
253
|
end
|
202
254
|
|
203
|
-
# Methods added to classes including
|
255
|
+
# Methods added to classes including Duplicable module
|
204
256
|
module ClassMethods
|
205
257
|
attr_accessor :duplicable_changesets, :duplicable_options
|
206
258
|
|
@@ -220,15 +272,14 @@ module Agnostic
|
|
220
272
|
|
221
273
|
# Sets global options for applying changesets
|
222
274
|
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
# in first place `new` method over the class. if
|
226
|
-
# instance is created calling to `dup` method
|
227
|
-
#
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
@duplicable_options.merge! options
|
275
|
+
# @param opts [Hash] The options for duplicable configuration
|
276
|
+
# @option opts [Boolean] :new_instance If `true` the duplicated instance
|
277
|
+
# is created calling in first place `new` method over the class. if
|
278
|
+
# `false` the duplicated instance is created calling to `dup` method
|
279
|
+
# over the instance object.
|
280
|
+
def duplicable_config(opts)
|
281
|
+
if opts.is_a? Hash
|
282
|
+
@duplicable_options.merge! opts
|
232
283
|
keep_valid_options
|
233
284
|
else
|
234
285
|
fail ArgumentError, 'Invalid options configuration'
|
@@ -213,7 +213,7 @@ describe Agnostic::Duplicate do
|
|
213
213
|
end
|
214
214
|
context 'when invalid settings' do
|
215
215
|
context "when attribute doesn't exist" do
|
216
|
-
it 'raises an
|
216
|
+
it 'raises an attribute not found error' do
|
217
217
|
expect do
|
218
218
|
#:nodoc
|
219
219
|
module DuplicateSpec
|
@@ -224,7 +224,47 @@ describe Agnostic::Duplicate do
|
|
224
224
|
end
|
225
225
|
InvalidAttributeTest.new.duplicate
|
226
226
|
end
|
227
|
-
end.to raise_error
|
227
|
+
end.to raise_error Agnostic::Duplicate::ChangeSet::AttributeNotFound
|
228
|
+
end
|
229
|
+
end
|
230
|
+
context 'when custom dup_template lacks of duplicable attribute' do
|
231
|
+
it 'raises a copy error on deep copy' do
|
232
|
+
expect do
|
233
|
+
#:nodoc
|
234
|
+
module DuplicateSpec
|
235
|
+
#:nodoc
|
236
|
+
class InvalidDupTemplateTest < Base
|
237
|
+
include Agnostic::Duplicate
|
238
|
+
attr_duplicable :name
|
239
|
+
end
|
240
|
+
|
241
|
+
obj = Object.new
|
242
|
+
obj.define_singleton_method('name=') do
|
243
|
+
fail 'Internal error'
|
244
|
+
end
|
245
|
+
|
246
|
+
InvalidDupTemplateTest.new.duplicate dup_template: obj
|
247
|
+
end
|
248
|
+
end.to raise_error Agnostic::Duplicate::ChangeSet::CopyError
|
249
|
+
end
|
250
|
+
it 'raises a copy error on shallow copy' do
|
251
|
+
expect do
|
252
|
+
#:nodoc
|
253
|
+
module DuplicateSpec
|
254
|
+
#:nodoc
|
255
|
+
class InvalidDupTemplateTest < Base
|
256
|
+
include Agnostic::Duplicate
|
257
|
+
attr_duplicable :name, strategy: :shallow_copy
|
258
|
+
end
|
259
|
+
|
260
|
+
obj = Object.new
|
261
|
+
obj.define_singleton_method('name=') do
|
262
|
+
fail 'Internal error'
|
263
|
+
end
|
264
|
+
|
265
|
+
InvalidDupTemplateTest.new.duplicate dup_template: obj
|
266
|
+
end
|
267
|
+
end.to raise_error Agnostic::Duplicate::ChangeSet::CopyError
|
228
268
|
end
|
229
269
|
end
|
230
270
|
context 'when duplicable config is invalid' do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
+
require 'codeclimate-test-reporter'
|
2
|
+
CodeClimate::TestReporter.start
|
3
|
+
|
1
4
|
require 'simplecov'
|
5
|
+
require 'coveralls'
|
6
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
7
|
+
SimpleCov::Formatter::HTMLFormatter,
|
8
|
+
Coveralls::SimpleCov::Formatter
|
9
|
+
]
|
2
10
|
SimpleCov.start
|
3
11
|
|
4
12
|
require_relative '../lib/agnostic/duplicate'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: agnostic-duplicate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Saenz Tagarro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: codeclimate-test-reporter
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: simplecov
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +80,20 @@ dependencies:
|
|
66
80
|
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: coveralls
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: rubocop
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,10 +150,11 @@ files:
|
|
122
150
|
- ".ruby-gemset"
|
123
151
|
- ".ruby-version"
|
124
152
|
- ".travis.yml"
|
153
|
+
- CHANGELOG.md
|
125
154
|
- Gemfile
|
126
155
|
- LICENSE.txt
|
127
156
|
- README.md
|
128
|
-
- Rakefile
|
157
|
+
- Rakefile.rb
|
129
158
|
- agnostic-duplicate.gemspec
|
130
159
|
- lib/agnostic/duplicate.rb
|
131
160
|
- lib/agnostic/duplicate/version.rb
|
data/Rakefile
DELETED