agnostic-duplicate 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
-