shallow_attributes 0.9.0 → 0.9.2

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: 8d9c84f7e0cad4b197b19de9247b98e29355907f
4
- data.tar.gz: be6015df6fed9d6efb0d65abc9f2a6a2a4bcadd2
3
+ metadata.gz: eae949ec12824705349bf498a92b2f524bd912a0
4
+ data.tar.gz: 1d3a7b3754419370e910cd6b90978425ff12010b
5
5
  SHA512:
6
- metadata.gz: 1eca913e91af6856f031b0e677d115f315d079de53d263601e6b7a51df4f186799813d26f30f3d21ae4536faa34e571debc767ed2db76d911cf30f97610140fb
7
- data.tar.gz: 9f430c8bbe5c73d3a2ad22b0f6cdbe8d0a9b8309e7d5e15291735dea260facc1f7406e532bd53eca02e1c11a698acfb440c4ea5cc472f0fdec5c3ac4b0f6efa5
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
8
- - 2.2.4
9
- - 2.3.0
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
@@ -0,0 +1,2 @@
1
+ # ShallowAttributes Changes
2
+ ## HEAD
data/Gemfile CHANGED
@@ -6,3 +6,5 @@ gemspec
6
6
  if !ENV['TRAVIS']
7
7
  gem 'yard', require: false
8
8
  end
9
+
10
+ gem 'coveralls', require: false
data/README.md CHANGED
@@ -1,18 +1,20 @@
1
1
  # ShallowAttributes
2
2
  [![Build Status](https://travis-ci.org/davydovanton/shallow_attributes.svg?branch=master)](https://travis-ci.org/davydovanton/shallow_attributes)
3
3
  [![Code Climate](https://codeclimate.com/github/davydovanton/shallow_attributes/badges/gpa.svg)](https://codeclimate.com/github/davydovanton/shallow_attributes)
4
+ [![Coverage Status](https://coveralls.io/repos/github/davydovanton/shallow_attributes/badge.svg?branch=master)](https://coveralls.io/github/davydovanton/shallow_attributes?branch=master)
4
5
  [![Inline docs](http://inch-ci.org/github/davydovanton/shallow_attributes.svg?branch=master)](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 to be
11
- defined with their types, for example: virtus, fast_attributes or attrio. However, the disadvantage of these
12
- gems is performance or API. So, the goal of ShallowAttributes is to provide a simple solution which is similar
13
- to the Virtus API, simple, fast, understandable and extendable.
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](https://gist.github.com/davydovanton/7cf0da532eae71381cbd) of ShallowAttributes compared to virtus gems.
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 # => "Anton"
67
+ user.name # => "Anton"
57
68
 
58
69
  user.age = '31' # => 31
59
- user.age = nil # => nil
60
- user.age.class # => Fixnum
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 # => "Jane"
69
- user.age # => 21
79
+ user.name # => "Jane"
80
+ user.age # => 21
70
81
 
71
82
  super_user = SuperUser.new
72
- user.age = nil # => 0
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
- ## Embedded Value
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 # => "Street 1/2"
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 # => Hash
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 # => [#<Address:0x007fdb2d3be448 @address="1234 Any St.", @locality="Anytown", @region="DC", @postal_code="21234">]
232
-
233
- user.attributes # => {
234
- # => :phone_numbers => [
235
- # => { :number => '212-555-1212' },
236
- # => { :number => '919-444-3265' } ],
237
- # => :addresses => [
238
- # => { :address => '1234 Any St.', :locality => 'Anytown', :region => "DC", :postal_code => "21234" } ]
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.3+
336
+ * 2.0
337
+ * 2.1
338
+ * 2.2
339
+ * 2.3
340
+ * 2.4
341
+ * jruby-head
292
342
 
293
- In future I want ot support other ruby sersion/platforms.
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
@@ -7,4 +7,4 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.test_files = FileList['test/**/*_test.rb']
8
8
  end
9
9
 
10
- task :default => :test
10
+ task default: :test
@@ -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
- if superclass.respond_to?(:default_values)
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
- @default_values ||= {}
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} = ShallowAttributes::Type.coerce(#{type}, value, #{options})
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 = -> (value) { value.respond_to?(:to_hash) ? value.to_hash : value }
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] attributes the attributes contained in the class
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 = attrs.delete_if { |key, _| !default_values.key?(key) }
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, options = {})
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
- # Returns class object for specific Type class
62
- #
63
- # @private
64
- #
65
- # @param [Class] type the type class object
66
- #
67
- # @example Returns Sting type class
68
- # ShallowAttributes::Type.instance_for(String)
69
- # # => ShallowAttributes::Type::Sting class
70
- #
71
- # @example Returns other type class
72
- # ShallowAttributes::Type.instance_for(MySpecialStringType)
73
- # # => MySpecialStringType class
74
- #
75
- # @return [Class]
76
- #
77
- # @since 0.1.0
78
- def self.type_instance(klass)
79
- DEFAULT_TYPE_OBJECTS[klass] || ShallowAttributes::Type.const_get(klass.name).new
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
@@ -39,7 +39,7 @@ module ShallowAttributes
39
39
  # @return [boolean]
40
40
  #
41
41
  # @since 0.1.0
42
- def coerce(value, options = {})
42
+ def coerce(value, _options = {})
43
43
  if TRUE_VALUES.include?(value)
44
44
  true
45
45
  elsif FALSE_VALUES.include?(value)
@@ -22,7 +22,7 @@ module ShallowAttributes
22
22
  # @return [DateTime]
23
23
  #
24
24
  # @since 0.1.0
25
- def coerce(value, options = {})
25
+ def coerce(value, _options = {})
26
26
  case value
27
27
  when ::DateTime then value
28
28
  when ::Time then ::DateTime.parse(value.to_s)
@@ -1,6 +1,6 @@
1
1
  module ShallowAttributes
2
2
  module Type
3
- # Abstract class for typecast object to Float type.
3
+ # This class needs for cange object type to Float.
4
4
  #
5
5
  # @abstract
6
6
  #
@@ -1,6 +1,6 @@
1
1
  module ShallowAttributes
2
2
  module Type
3
- # Abstract class for typecast object to Integer type.
3
+ # This class cange object to Integer.
4
4
  #
5
5
  # @abstract
6
6
  #
@@ -20,7 +20,7 @@ module ShallowAttributes
20
20
  # @return [Sting]
21
21
  #
22
22
  # @since 0.1.0
23
- def coerce(value, options = {})
23
+ def coerce(value, _options = {})
24
24
  case value
25
25
  when ::Array then value.join
26
26
  when ::Hash, ::Class then error(value)
@@ -22,7 +22,7 @@ module ShallowAttributes
22
22
  # @return [Time]
23
23
  #
24
24
  # @since 0.1.0
25
- def coerce(value, options = {})
25
+ def coerce(value, _options = {})
26
26
  case value
27
27
  when ::Time then value
28
28
  when ::Integer then ::Time.at(value)
@@ -2,5 +2,5 @@ module ShallowAttributes
2
2
  # Defines the full version
3
3
  #
4
4
  # @since 0.1.0
5
- VERSION = "0.9.0".freeze
5
+ VERSION = "0.9.2".freeze
6
6
  end
@@ -22,5 +22,4 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "bundler", "~> 1.11"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
24
  spec.add_development_dependency "minitest", "~> 5.0"
25
- spec.add_development_dependency "simplecov", '~> 0'
26
25
  end
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.0
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: 2016-03-24 00:00:00.000000000 Z
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
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here