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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 32cdc91880b4712356cc059c8460a991cd79d39e
4
- data.tar.gz: 79d5fb7a6d55d51ece7ee459b5fd95fdb164cacd
3
+ metadata.gz: 0f1eab323490625f666f5be5cb411b804541d471
4
+ data.tar.gz: e51eb8409624bdb8ac8819b20056fe06686ddecf
5
5
  SHA512:
6
- metadata.gz: 8dab11d2925bb2e145230cd2ff3cb4e341f4cfaf68a7bca55d11805d712f257979a8d0d19b61e975ec13cfffb28e47293f9a0b614bce5aed13c0bcd9a2b52e7c
7
- data.tar.gz: 74020d056b6f1493a9788281476fa52b4e743a1aa9466be38137e8522b4cda172eac53fc67973de2a3177f716bd0a1893d3d0dee96676763cd2fbaa49af36c94
6
+ metadata.gz: 61853c9158efa07ca9a8ff3d8f5791655a6269d692f1bbb4c6ecd823ca1bdd6ac569443fde5813420566a1d7ee679c5d41490094ea6e07508fbb2d47e3cf6993
7
+ data.tar.gz: 0d073b672d0f70242e7b24ef5f0f9802efded6ca751ec49fb92a9cde4772f734f9eb4b2b676eb045b9e546287e5139df839020d7d4748edb591ecbab10491a4d
@@ -1,8 +1,11 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.2
4
- - 2.1.1
5
- - 2.1.0
6
- - 2.0.0
7
- - 1.9.3
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
@@ -0,0 +1,7 @@
1
+ ## 1.0.1
2
+
3
+ * Added custom handling exception:
4
+ - Agnostic::Duplicate::ChangeSet::AttributeNotFound
5
+ - Agnostic::Duplicate::ChangeSet::CopyError
6
+ * Added option `dup_template` for duplicating fields over a custom template
7
+ object. Updated documentation
data/README.md CHANGED
@@ -1,3 +1,9 @@
1
+ [![Gem Version](https://badge.fury.io/rb/agnostic-duplicate.svg)](http://badge.fury.io/rb/agnostic-duplicate)
2
+ [![Build Status](https://travis-ci.org/dsaenztagarro/agnostic-duplicate.png)](https://travis-ci.org/dsaenztagarro/agnostic-duplicate)
3
+ [![Code Climate](https://codeclimate.com/github/dsaenztagarro/agnostic-duplicate/badges/gpa.svg)](https://codeclimate.com/github/dsaenztagarro/agnostic-duplicate)
4
+ [![Coverage Status](https://coveralls.io/repos/dsaenztagarro/agnostic-duplicate/badge.png?branch=master)](https://coveralls.io/r/dsaenztagarro/agnostic-duplicate?branch=master)
5
+ [![Dependency Status](https://gemnasium.com/dsaenztagarro/agnostic-duplicate.svg)](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/[my-github-username]/agnostic-duplicate/fork )
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`)
@@ -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']
@@ -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 = <<-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
- description
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'
@@ -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
- def duplicate
97
- dup_template.tap do |model|
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
- setter_method = "#{attribute}="
134
- if model.respond_to?(setter_method)
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 [Duplicate] the original object to be duplicated
181
- # @param model [Duplicate] the duplicated new instance object
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
- model.send("#{attribute}=", parent.send(attribute))
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 [Duplicate] a new instance object based on global duplicable
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 Duplicate module
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
- # ## Options available:
224
- # - `new_instance`: if `true` the duplicated instance is created calling
225
- # in first place `new` method over the class. if `false` the duplicated
226
- # instance is created calling to `dup` method over the instance object.
227
- #
228
- # @param options [Hash]
229
- def duplicable_config(options)
230
- if options.is_a? Hash
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'
@@ -1,5 +1,6 @@
1
1
  module Agnostic
2
+ #:nodoc:
2
3
  module Duplicate
3
- VERSION = '1.0.0'
4
+ VERSION = '1.0.1'
4
5
  end
5
6
  end
@@ -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 exception' do
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("Invalid duplicable attribute 'name'")
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
@@ -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.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-09-26 00:00:00.000000000 Z
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
@@ -1,2 +0,0 @@
1
- require "bundler/gem_tasks"
2
-