shallow_attributes 0.9.0 → 0.9.2
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 +6 -3
- data/CHANGELOG.md +2 -0
- data/Gemfile +2 -0
- data/README.md +84 -28
- data/Rakefile +1 -1
- data/lib/shallow_attributes/class_methods.rb +21 -9
- data/lib/shallow_attributes/instance_methods.rb +8 -4
- data/lib/shallow_attributes/type.rb +48 -46
- data/lib/shallow_attributes/type/boolean.rb +1 -1
- data/lib/shallow_attributes/type/date_time.rb +1 -1
- data/lib/shallow_attributes/type/float.rb +1 -1
- data/lib/shallow_attributes/type/integer.rb +1 -1
- data/lib/shallow_attributes/type/string.rb +1 -1
- data/lib/shallow_attributes/type/time.rb +1 -1
- data/lib/shallow_attributes/version.rb +1 -1
- data/shallow_attributes.gemspec +0 -1
- metadata +3 -18
- data/bin/console +0 -14
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eae949ec12824705349bf498a92b2f524bd912a0
|
4
|
+
data.tar.gz: 1d3a7b3754419370e910cd6b90978425ff12010b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 109b2b4f4e0f699c1d4ba567c988ddc6da547e7be22b10f063b347f1489fc1f1a6c81325822ca7427ce7bca7dc6f3a7b1c1ecafb2609ab0cf0099023eb4adf8b
|
7
|
+
data.tar.gz: 32b707b41127ab624d0566a6d0fbbb455326c0b36085daacf8a71d0d6d1685d5a3e63c9b9c8deafad65dbb5f01ef44a8305969f0bd513a57837fc5655bf91489
|
data/.travis.yml
CHANGED
@@ -4,11 +4,14 @@ cache: bundler
|
|
4
4
|
before_install: gem install bundler -v 1.11.2
|
5
5
|
rvm:
|
6
6
|
- 2.0.0
|
7
|
-
- 2.1.
|
8
|
-
- 2.2.
|
9
|
-
- 2.3.
|
7
|
+
- 2.1.9
|
8
|
+
- 2.2.5
|
9
|
+
- 2.3.1
|
10
|
+
- 2.4.0
|
10
11
|
- jruby-head
|
11
12
|
- rbx-2
|
13
|
+
- ruby-head
|
12
14
|
matrix:
|
13
15
|
allow_failures:
|
14
16
|
- rvm: rbx-2
|
17
|
+
- rvm: ruby-head
|
data/CHANGELOG.md
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
# ShallowAttributes
|
2
2
|
[](https://travis-ci.org/davydovanton/shallow_attributes)
|
3
3
|
[](https://codeclimate.com/github/davydovanton/shallow_attributes)
|
4
|
+
[](https://coveralls.io/github/davydovanton/shallow_attributes?branch=master)
|
4
5
|
[](http://inch-ci.org/github/davydovanton/shallow_attributes)
|
5
6
|
|
6
|
-
Simple and lightweight Virtus analog.
|
7
|
+
Simple and lightweight Virtus analog without any dependencies. [Documentation][doc-link].
|
7
8
|
|
8
9
|
## Motivation
|
9
10
|
|
10
|
-
There are already a lot of good and flexible gems which solve a similar problem, allowing attributes
|
11
|
-
defined with their types, for example: virtus, fast_attributes
|
12
|
-
|
13
|
-
to the Virtus API, simple, fast,
|
11
|
+
There are already a lot of good and flexible gems which solve a similar problem, allowing attributes
|
12
|
+
to be defined with their types, for example: [virtus][virtus-link], [fast_attributes][fast-attributes-link]
|
13
|
+
or [attrio][attrio-link]. However, the disadvantage of these gems is performance or API. So, the goal
|
14
|
+
of `ShallowAttributes` is to provide a simple solution which is similar to the `Virtus` API, simple, fast,
|
15
|
+
understandable and extendable.
|
14
16
|
|
15
|
-
This is [the performance benchmark]
|
17
|
+
This is [the performance benchmark][performance-benchmark] of ShallowAttributes compared to virtus gems.
|
16
18
|
|
17
19
|
## Installation
|
18
20
|
|
@@ -31,6 +33,15 @@ Or install it yourself as:
|
|
31
33
|
$ gem install shallow_attributes
|
32
34
|
|
33
35
|
## Examples
|
36
|
+
### Table of contents
|
37
|
+
* [Using ShallowAttributes with Classes](#using-shallowattributes-with-classes)
|
38
|
+
* [Default Values](#default-values)
|
39
|
+
* [Embedded Value](#embedded-value)
|
40
|
+
* [Custom Coercions](#custom-coercions)
|
41
|
+
* [Collection Member Coercions](#collection-member-coercions)
|
42
|
+
* [Note about Member Coercions](#important-note-about-member-coercions)
|
43
|
+
* [Overriding setters](#overriding-setters)
|
44
|
+
* [ActiveModel validation](#activemodel-validation)
|
34
45
|
|
35
46
|
### Using ShallowAttributes with Classes
|
36
47
|
You can create classes extended with Virtus and define attributes:
|
@@ -53,11 +64,11 @@ class SuperUser < User
|
|
53
64
|
end
|
54
65
|
|
55
66
|
user = User.new(name: 'Anton', age: 31)
|
56
|
-
user.name
|
67
|
+
user.name # => "Anton"
|
57
68
|
|
58
69
|
user.age = '31' # => 31
|
59
|
-
user.age = nil
|
60
|
-
user.age.class
|
70
|
+
user.age = nil # => nil
|
71
|
+
user.age.class # => Fixnum
|
61
72
|
|
62
73
|
user.birthday = 'November 18th, 1983' # => #<DateTime: 1983-11-18T00:00:00+00:00 (4891313/2,0/1,2299161)>
|
63
74
|
|
@@ -65,11 +76,11 @@ user.attributes # => { name: "Anton", age: 31, birthday: nil }
|
|
65
76
|
|
66
77
|
# mass-assignment
|
67
78
|
user.attributes = { name: 'Jane', age: 21 }
|
68
|
-
user.name
|
69
|
-
user.age
|
79
|
+
user.name # => "Jane"
|
80
|
+
user.age # => 21
|
70
81
|
|
71
82
|
super_user = SuperUser.new
|
72
|
-
user.age = nil
|
83
|
+
user.age = nil # => 0
|
73
84
|
```
|
74
85
|
|
75
86
|
### Default Values
|
@@ -109,7 +120,7 @@ page.reset_attribute(:views) # => 0
|
|
109
120
|
page.views # => 0
|
110
121
|
```
|
111
122
|
|
112
|
-
|
123
|
+
### Embedded Value
|
113
124
|
|
114
125
|
``` ruby
|
115
126
|
class City
|
@@ -142,7 +153,7 @@ user = User.new(address: {
|
|
142
153
|
}
|
143
154
|
})
|
144
155
|
|
145
|
-
user.address.street
|
156
|
+
user.address.street # => "Street 1/2"
|
146
157
|
user.address.city.name # => "NYC"
|
147
158
|
```
|
148
159
|
|
@@ -165,7 +176,7 @@ end
|
|
165
176
|
|
166
177
|
user = User.new
|
167
178
|
user.info = '{"email":"john@domain.com"}' # => {"email"=>"john@domain.com"}
|
168
|
-
user.info.class
|
179
|
+
user.info.class # => Hash
|
169
180
|
|
170
181
|
# With a custom attribute encapsulating coercion-specific configuration
|
171
182
|
class NoisyString
|
@@ -228,15 +239,49 @@ user = User.new(
|
|
228
239
|
{ :address => '1234 Any St.', :locality => 'Anytown', :region => "DC", :postal_code => "21234" } ])
|
229
240
|
|
230
241
|
user.phone_numbers # => [#<PhoneNumber:0x007fdb2d3bef88 @number="212-555-1212">, #<PhoneNumber:0x007fdb2d3beb00 @number="919-444-3265">]
|
231
|
-
user.addresses
|
232
|
-
|
233
|
-
user.attributes
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
242
|
+
user.addresses # => [#<Address:0x007fdb2d3be448 @address="1234 Any St.", @locality="Anytown", @region="DC", @postal_code="21234">]
|
243
|
+
|
244
|
+
user.attributes
|
245
|
+
# => {
|
246
|
+
# => :phone_numbers => [
|
247
|
+
# => { :number => '212-555-1212' },
|
248
|
+
# => { :number => '919-444-3265' }
|
249
|
+
# => ],
|
250
|
+
# => :addresses => [
|
251
|
+
# => {
|
252
|
+
# => :address => '1234 Any St.',
|
253
|
+
# => :locality => 'Anytown',
|
254
|
+
# => :region => "DC",
|
255
|
+
# => :postal_code => "21234"
|
256
|
+
# => }
|
257
|
+
# => ]
|
258
|
+
# => }
|
259
|
+
```
|
260
|
+
|
261
|
+
### IMPORTANT note about member coercions
|
262
|
+
|
263
|
+
ShallowAttributes performs coercions only when a value is being assigned. If you mutate the value later on using its own interfaces then coercion won't be triggered.
|
264
|
+
|
265
|
+
Here's an example:
|
266
|
+
|
267
|
+
``` ruby
|
268
|
+
class Book
|
269
|
+
include ShallowAttributes
|
270
|
+
attribute :title, String
|
271
|
+
end
|
272
|
+
|
273
|
+
class Library
|
274
|
+
include ShallowAttributes
|
275
|
+
attribute :books, Array, of: Book
|
276
|
+
end
|
277
|
+
|
278
|
+
library = Library.new
|
279
|
+
|
280
|
+
# This will coerce Hash to a Book instance
|
281
|
+
library.books = [ { :title => 'Introduction' } ]
|
282
|
+
|
283
|
+
# This WILL NOT COERCE the value because you mutate the books array with Array#<<
|
284
|
+
library.books << { :title => 'Another Introduction' }
|
240
285
|
```
|
241
286
|
|
242
287
|
### Overriding setters
|
@@ -286,11 +331,16 @@ user.valid? # => true
|
|
286
331
|
|
287
332
|
## Ruby version support
|
288
333
|
|
289
|
-
ShallowAttributes is known to work correctly with the following rubies:
|
334
|
+
ShallowAttributes is [known to work correctly][travis-link] with the following rubies:
|
290
335
|
|
291
|
-
* 2.
|
336
|
+
* 2.0
|
337
|
+
* 2.1
|
338
|
+
* 2.2
|
339
|
+
* 2.3
|
340
|
+
* 2.4
|
341
|
+
* jruby-head
|
292
342
|
|
293
|
-
|
343
|
+
Also we run rbx-2 buld too.
|
294
344
|
|
295
345
|
## Contributing
|
296
346
|
|
@@ -298,8 +348,14 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/davydo
|
|
298
348
|
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected
|
299
349
|
to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
300
350
|
|
301
|
-
|
302
351
|
## License
|
303
352
|
|
304
353
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
305
354
|
|
355
|
+
|
356
|
+
[doc-link]: http://www.rubydoc.info/github/davydovanton/shallow_attributes/master
|
357
|
+
[virtus-link]: https://github.com/solnic/virtus
|
358
|
+
[fast-attributes-link]: https://github.com/applift/fast_attributes
|
359
|
+
[attrio-link]: https://github.com/jetrockets/attrio
|
360
|
+
[performance-benchmark]: https://gist.github.com/davydovanton/d14b51ab63e3fab63ecb
|
361
|
+
[travis-link]: https://travis-ci.org/davydovanton/shallow_attributes
|
data/Rakefile
CHANGED
@@ -6,6 +6,19 @@ module ShallowAttributes
|
|
6
6
|
#
|
7
7
|
# @since 0.1.0
|
8
8
|
module ClassMethods
|
9
|
+
# Inject our default values into subclasses.
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @param [Object] subclass
|
14
|
+
#
|
15
|
+
def inherited(subclass)
|
16
|
+
super
|
17
|
+
if respond_to?(:default_values)
|
18
|
+
subclass.default_values.merge!(default_values)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
9
22
|
# Returns hash which contain default values for each attribute
|
10
23
|
#
|
11
24
|
# @private
|
@@ -14,16 +27,11 @@ module ShallowAttributes
|
|
14
27
|
#
|
15
28
|
# @since 0.1.0
|
16
29
|
def default_values
|
17
|
-
|
18
|
-
@default_values.merge!(superclass.default_values) { |_, v, _| v }
|
19
|
-
else
|
20
|
-
@default_values
|
21
|
-
end
|
30
|
+
@default_values ||= {}
|
22
31
|
end
|
23
32
|
|
24
33
|
# Returns all class attributes.
|
25
34
|
#
|
26
|
-
#
|
27
35
|
# @example Create new User instance
|
28
36
|
# class User
|
29
37
|
# include ShallowAttributes
|
@@ -66,8 +74,7 @@ module ShallowAttributes
|
|
66
74
|
def attribute(name, type, options = {})
|
67
75
|
options[:default] ||= [] if type == Array
|
68
76
|
|
69
|
-
|
70
|
-
@default_values[name] = options.delete(:default)
|
77
|
+
default_values[name] = options.delete(:default)
|
71
78
|
|
72
79
|
initialize_setter(name, type, options)
|
73
80
|
initialize_getter(name)
|
@@ -89,7 +96,12 @@ module ShallowAttributes
|
|
89
96
|
def initialize_setter(name, type, options)
|
90
97
|
module_eval <<-EOS, __FILE__, __LINE__ + 1
|
91
98
|
def #{name}=(value)
|
92
|
-
@#{name} =
|
99
|
+
@#{name} = if value.is_a?(#{type}) && !value.is_a?(Array)
|
100
|
+
value
|
101
|
+
else
|
102
|
+
ShallowAttributes::Type.coerce(#{type}, value, #{options})
|
103
|
+
end
|
104
|
+
|
93
105
|
@attributes[:#{name}] = @#{name}
|
94
106
|
end
|
95
107
|
EOS
|
@@ -12,11 +12,11 @@ module ShallowAttributes
|
|
12
12
|
# @private
|
13
13
|
#
|
14
14
|
# @since 0.1.0
|
15
|
-
TO_H_PROC = ->
|
15
|
+
TO_H_PROC = ->(value) { value.respond_to?(:to_hash) ? value.to_hash : value }
|
16
16
|
|
17
17
|
# Initialize instance object with specific attributes
|
18
18
|
#
|
19
|
-
# @param [Hash]
|
19
|
+
# @param [Hash] attrs the attributes contained in the class
|
20
20
|
#
|
21
21
|
# @example Create new User instance
|
22
22
|
# class User
|
@@ -30,7 +30,11 @@ module ShallowAttributes
|
|
30
30
|
#
|
31
31
|
# @since 0.1.0
|
32
32
|
def initialize(attrs = {})
|
33
|
-
@attributes =
|
33
|
+
@attributes = {}
|
34
|
+
attrs.each_pair do |key, value|
|
35
|
+
key = key.to_sym
|
36
|
+
@attributes[key] = value if default_values.key?(key)
|
37
|
+
end
|
34
38
|
define_attributes
|
35
39
|
define_default_attributes
|
36
40
|
end
|
@@ -131,7 +135,7 @@ module ShallowAttributes
|
|
131
135
|
# @return the object
|
132
136
|
#
|
133
137
|
# @since 0.1.0
|
134
|
-
def coerce(value,
|
138
|
+
def coerce(value, _options = {})
|
135
139
|
self.attributes = value
|
136
140
|
self
|
137
141
|
end
|
@@ -17,33 +17,6 @@ module ShallowAttributes
|
|
17
17
|
class InvalidValueError < TypeError
|
18
18
|
end
|
19
19
|
|
20
|
-
# Convert value object to specific Type class
|
21
|
-
#
|
22
|
-
# @private
|
23
|
-
#
|
24
|
-
# @param [Class] type the type class object
|
25
|
-
# @param [Object] value the value that should be submit to the necessary type
|
26
|
-
# @param [Hash] options the options to create a message with.
|
27
|
-
# @option options [String] :of The type of array
|
28
|
-
# @option options [boolean] :allow_nil cast `nil` to integer or float
|
29
|
-
#
|
30
|
-
# @example Convert integer to sting type
|
31
|
-
# ShallowAttributes::Type.coerce(String, 1)
|
32
|
-
# # => '1'
|
33
|
-
#
|
34
|
-
# @example Convert string to custom hash type
|
35
|
-
# ShallowAttributes::Type.instance_for(JsonType, '{"a"=>1}')
|
36
|
-
# # => { a: 1 }
|
37
|
-
#
|
38
|
-
# @return the converted value object
|
39
|
-
#
|
40
|
-
# @since 0.1.0
|
41
|
-
def self.coerce(type, value, options = {})
|
42
|
-
type_instance(type).coerce(value, options)
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
20
|
# Hash object with cached type objects.
|
48
21
|
#
|
49
22
|
# @private
|
@@ -58,25 +31,54 @@ module ShallowAttributes
|
|
58
31
|
::Time => ShallowAttributes::Type::Time.new
|
59
32
|
}.freeze
|
60
33
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
34
|
+
class << self
|
35
|
+
# Convert value object to specific Type class
|
36
|
+
#
|
37
|
+
# @private
|
38
|
+
#
|
39
|
+
# @param [Class] type the type class object
|
40
|
+
# @param [Object] value the value that should be submit to the necessary type
|
41
|
+
# @param [Hash] options the options to create a message with.
|
42
|
+
# @option options [String] :of The type of array
|
43
|
+
# @option options [boolean] :allow_nil cast `nil` to integer or float
|
44
|
+
#
|
45
|
+
# @example Convert integer to sting type
|
46
|
+
# ShallowAttributes::Type.coerce(String, 1)
|
47
|
+
# # => '1'
|
48
|
+
#
|
49
|
+
# @example Convert string to custom hash type
|
50
|
+
# ShallowAttributes::Type.instance_for(JsonType, '{"a"=>1}')
|
51
|
+
# # => { a: 1 }
|
52
|
+
#
|
53
|
+
# @return the converted value object
|
54
|
+
#
|
55
|
+
# @since 0.1.0
|
56
|
+
def coerce(type, value, options = {})
|
57
|
+
type_instance(type).coerce(value, options)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Returns class object for specific Type class
|
63
|
+
#
|
64
|
+
# @private
|
65
|
+
#
|
66
|
+
# @param [Class] type the type class object
|
67
|
+
#
|
68
|
+
# @example Returns Sting type class
|
69
|
+
# ShallowAttributes::Type.instance_for(String)
|
70
|
+
# # => ShallowAttributes::Type::Sting class
|
71
|
+
#
|
72
|
+
# @example Returns other type class
|
73
|
+
# ShallowAttributes::Type.instance_for(MySpecialStringType)
|
74
|
+
# # => MySpecialStringType class
|
75
|
+
#
|
76
|
+
# @return [Class]
|
77
|
+
#
|
78
|
+
# @since 0.1.0
|
79
|
+
def type_instance(klass)
|
80
|
+
DEFAULT_TYPE_OBJECTS[klass] || ShallowAttributes::Type.const_get(klass.name).new
|
81
|
+
end
|
80
82
|
end
|
81
83
|
end
|
82
84
|
end
|
data/shallow_attributes.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shallow_attributes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Davydov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '5.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: simplecov
|
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'
|
69
55
|
description: Attributes for Plain Old Ruby Objects
|
70
56
|
email:
|
71
57
|
- antondavydov.o@gmail.com
|
@@ -75,13 +61,12 @@ extra_rdoc_files: []
|
|
75
61
|
files:
|
76
62
|
- ".gitignore"
|
77
63
|
- ".travis.yml"
|
64
|
+
- CHANGELOG.md
|
78
65
|
- CODE_OF_CONDUCT.md
|
79
66
|
- Gemfile
|
80
67
|
- LICENSE.txt
|
81
68
|
- README.md
|
82
69
|
- Rakefile
|
83
|
-
- bin/console
|
84
|
-
- bin/setup
|
85
70
|
- lib/shallow_attributes.rb
|
86
71
|
- lib/shallow_attributes/class_methods.rb
|
87
72
|
- lib/shallow_attributes/instance_methods.rb
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "shallow_attributes"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start
|