shallow_attributes 0.9.0
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 +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +14 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +305 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/shallow_attributes/class_methods.rb +111 -0
- data/lib/shallow_attributes/instance_methods.rb +240 -0
- data/lib/shallow_attributes/type/array.rb +35 -0
- data/lib/shallow_attributes/type/boolean.rb +53 -0
- data/lib/shallow_attributes/type/date_time.rb +37 -0
- data/lib/shallow_attributes/type/float.rb +38 -0
- data/lib/shallow_attributes/type/integer.rb +38 -0
- data/lib/shallow_attributes/type/string.rb +39 -0
- data/lib/shallow_attributes/type/time.rb +37 -0
- data/lib/shallow_attributes/type.rb +82 -0
- data/lib/shallow_attributes/version.rb +6 -0
- data/lib/shallow_attributes.rb +31 -0
- data/shallow_attributes.gemspec +26 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8d9c84f7e0cad4b197b19de9247b98e29355907f
|
4
|
+
data.tar.gz: be6015df6fed9d6efb0d65abc9f2a6a2a4bcadd2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1eca913e91af6856f031b0e677d115f315d079de53d263601e6b7a51df4f186799813d26f30f3d21ae4536faa34e571debc767ed2db76d911cf30f97610140fb
|
7
|
+
data.tar.gz: 9f430c8bbe5c73d3a2ad22b0f6cdbe8d0a9b8309e7d5e15291735dea260facc1f7406e532bd53eca02e1c11a698acfb440c4ea5cc472f0fdec5c3ac4b0f6efa5
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at antondavydov.o@gmail.com. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Anton Davydov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
# ShallowAttributes
|
2
|
+
[](https://travis-ci.org/davydovanton/shallow_attributes)
|
3
|
+
[](https://codeclimate.com/github/davydovanton/shallow_attributes)
|
4
|
+
[](http://inch-ci.org/github/davydovanton/shallow_attributes)
|
5
|
+
|
6
|
+
Simple and lightweight Virtus analog.
|
7
|
+
|
8
|
+
## Motivation
|
9
|
+
|
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.
|
14
|
+
|
15
|
+
This is [the performance benchmark](https://gist.github.com/davydovanton/7cf0da532eae71381cbd) of ShallowAttributes compared to virtus gems.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'shallow_attributes'
|
23
|
+
```
|
24
|
+
|
25
|
+
And then execute:
|
26
|
+
|
27
|
+
$ bundle
|
28
|
+
|
29
|
+
Or install it yourself as:
|
30
|
+
|
31
|
+
$ gem install shallow_attributes
|
32
|
+
|
33
|
+
## Examples
|
34
|
+
|
35
|
+
### Using ShallowAttributes with Classes
|
36
|
+
You can create classes extended with Virtus and define attributes:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
class User
|
40
|
+
include ShallowAttributes
|
41
|
+
|
42
|
+
attribute :name, String
|
43
|
+
attribute :age, Integer
|
44
|
+
attribute :birthday, DateTime
|
45
|
+
end
|
46
|
+
|
47
|
+
class SuperUser < User
|
48
|
+
include ShallowAttributes
|
49
|
+
|
50
|
+
attribute :name, String
|
51
|
+
attribute :age, Integer, allow_nil: true
|
52
|
+
attribute :birthday, DateTime
|
53
|
+
end
|
54
|
+
|
55
|
+
user = User.new(name: 'Anton', age: 31)
|
56
|
+
user.name # => "Anton"
|
57
|
+
|
58
|
+
user.age = '31' # => 31
|
59
|
+
user.age = nil # => nil
|
60
|
+
user.age.class # => Fixnum
|
61
|
+
|
62
|
+
user.birthday = 'November 18th, 1983' # => #<DateTime: 1983-11-18T00:00:00+00:00 (4891313/2,0/1,2299161)>
|
63
|
+
|
64
|
+
user.attributes # => { name: "Anton", age: 31, birthday: nil }
|
65
|
+
|
66
|
+
# mass-assignment
|
67
|
+
user.attributes = { name: 'Jane', age: 21 }
|
68
|
+
user.name # => "Jane"
|
69
|
+
user.age # => 21
|
70
|
+
|
71
|
+
super_user = SuperUser.new
|
72
|
+
user.age = nil # => 0
|
73
|
+
```
|
74
|
+
|
75
|
+
### Default Values
|
76
|
+
|
77
|
+
``` ruby
|
78
|
+
class Page
|
79
|
+
include ShallowAttributes
|
80
|
+
|
81
|
+
attribute :title, String
|
82
|
+
|
83
|
+
# default from a singleton value (integer in this case)
|
84
|
+
attribute :views, Integer, default: 0
|
85
|
+
|
86
|
+
# default from a singleton value (boolean in this case)
|
87
|
+
attribute :published, 'Boolean', default: false
|
88
|
+
|
89
|
+
# default from a callable object (proc in this case)
|
90
|
+
attribute :slug, String, default: lambda { |page, attribute| page.title.downcase.gsub(' ', '-') }
|
91
|
+
|
92
|
+
# default from a method name as symbol
|
93
|
+
attribute :editor_title, String, default: :default_editor_title
|
94
|
+
|
95
|
+
def default_editor_title
|
96
|
+
published ? title : "UNPUBLISHED: #{title}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
page = Page.new(title: 'Virtus README')
|
101
|
+
page.slug # => 'virtus-readme'
|
102
|
+
page.views # => 0
|
103
|
+
page.published # => false
|
104
|
+
page.editor_title # => "UNPUBLISHED: Virtus README"
|
105
|
+
|
106
|
+
page.views = 10
|
107
|
+
page.views # => 10
|
108
|
+
page.reset_attribute(:views) # => 0
|
109
|
+
page.views # => 0
|
110
|
+
```
|
111
|
+
|
112
|
+
## Embedded Value
|
113
|
+
|
114
|
+
``` ruby
|
115
|
+
class City
|
116
|
+
include ShallowAttributes
|
117
|
+
|
118
|
+
attribute :name, String
|
119
|
+
attribute :size, Integer, default: 9000
|
120
|
+
end
|
121
|
+
|
122
|
+
class Address
|
123
|
+
include ShallowAttributes
|
124
|
+
|
125
|
+
attribute :street, String
|
126
|
+
attribute :zipcode, String, default: '111111'
|
127
|
+
attribute :city, City
|
128
|
+
end
|
129
|
+
|
130
|
+
class User
|
131
|
+
include ShallowAttributes
|
132
|
+
|
133
|
+
attribute :name, String
|
134
|
+
attribute :address, Address
|
135
|
+
end
|
136
|
+
|
137
|
+
user = User.new(address: {
|
138
|
+
street: 'Street 1/2',
|
139
|
+
zipcode: '12345',
|
140
|
+
city: {
|
141
|
+
name: 'NYC'
|
142
|
+
}
|
143
|
+
})
|
144
|
+
|
145
|
+
user.address.street # => "Street 1/2"
|
146
|
+
user.address.city.name # => "NYC"
|
147
|
+
```
|
148
|
+
|
149
|
+
### Custom Coercions
|
150
|
+
|
151
|
+
``` ruby
|
152
|
+
require 'json'
|
153
|
+
|
154
|
+
class Json
|
155
|
+
def coerce(value, options = {})
|
156
|
+
value.is_a?(::Hash) ? value : JSON.parse(value)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class User
|
161
|
+
include ShallowAttributes
|
162
|
+
|
163
|
+
attribute :info, Json, default: {}
|
164
|
+
end
|
165
|
+
|
166
|
+
user = User.new
|
167
|
+
user.info = '{"email":"john@domain.com"}' # => {"email"=>"john@domain.com"}
|
168
|
+
user.info.class # => Hash
|
169
|
+
|
170
|
+
# With a custom attribute encapsulating coercion-specific configuration
|
171
|
+
class NoisyString
|
172
|
+
def coerce(value, options = {})
|
173
|
+
value.to_s.upcase
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class User
|
178
|
+
include ShallowAttributes
|
179
|
+
|
180
|
+
attribute :scream, NoisyString
|
181
|
+
end
|
182
|
+
|
183
|
+
user = User.new(scream: 'hello world!')
|
184
|
+
user.scream # => "HELLO WORLD!"
|
185
|
+
```
|
186
|
+
|
187
|
+
### Collection Member Coercions
|
188
|
+
|
189
|
+
``` ruby
|
190
|
+
# Support "primitive" classes
|
191
|
+
class Book
|
192
|
+
include ShallowAttributes
|
193
|
+
|
194
|
+
attribute :page_numbers, Array, of: Integer
|
195
|
+
end
|
196
|
+
|
197
|
+
book = Book.new(:page_numbers => %w[1 2 3])
|
198
|
+
book.page_numbers # => [1, 2, 3]
|
199
|
+
|
200
|
+
# Support EmbeddedValues, too!
|
201
|
+
class Address
|
202
|
+
include ShallowAttributes
|
203
|
+
|
204
|
+
attribute :address, String
|
205
|
+
attribute :locality, String
|
206
|
+
attribute :region, String
|
207
|
+
attribute :postal_code, String
|
208
|
+
end
|
209
|
+
|
210
|
+
class PhoneNumber
|
211
|
+
include ShallowAttributes
|
212
|
+
|
213
|
+
attribute :number, String
|
214
|
+
end
|
215
|
+
|
216
|
+
class User
|
217
|
+
include ShallowAttributes
|
218
|
+
|
219
|
+
attribute :phone_numbers, Array, of: PhoneNumber
|
220
|
+
attribute :addresses, Array, of: Address
|
221
|
+
end
|
222
|
+
|
223
|
+
user = User.new(
|
224
|
+
:phone_numbers => [
|
225
|
+
{ :number => '212-555-1212' },
|
226
|
+
{ :number => '919-444-3265' } ],
|
227
|
+
:addresses => [
|
228
|
+
{ :address => '1234 Any St.', :locality => 'Anytown', :region => "DC", :postal_code => "21234" } ])
|
229
|
+
|
230
|
+
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
|
+
# => }
|
240
|
+
```
|
241
|
+
|
242
|
+
### Overriding setters
|
243
|
+
|
244
|
+
``` ruby
|
245
|
+
class User
|
246
|
+
include ShallowAttributes
|
247
|
+
|
248
|
+
attribute :name, String
|
249
|
+
|
250
|
+
alias_method :_name=, :name=
|
251
|
+
def name=(new_name)
|
252
|
+
custom_name = nil
|
253
|
+
if new_name == "Godzilla"
|
254
|
+
custom_name = "Can't tell"
|
255
|
+
end
|
256
|
+
|
257
|
+
self._name = custom_name || new_name
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
user = User.new(name: "Frank")
|
262
|
+
user.name # => 'Frank'
|
263
|
+
|
264
|
+
user = User.new(name: "Godzilla")
|
265
|
+
user.name # => 'Can't tell'
|
266
|
+
```
|
267
|
+
|
268
|
+
### ActiveModel validation
|
269
|
+
|
270
|
+
``` ruby
|
271
|
+
require 'active_model'
|
272
|
+
|
273
|
+
class Children
|
274
|
+
include ShallowAttributes
|
275
|
+
include ActiveModel::Validations
|
276
|
+
|
277
|
+
attribute :scream, String
|
278
|
+
validates :scream, presence: true
|
279
|
+
end
|
280
|
+
|
281
|
+
user = User.new(scream: '')
|
282
|
+
user.valid? # => false
|
283
|
+
user.scream = 'hello world!'
|
284
|
+
user.valid? # => true
|
285
|
+
```
|
286
|
+
|
287
|
+
## Ruby version support
|
288
|
+
|
289
|
+
ShallowAttributes is known to work correctly with the following rubies:
|
290
|
+
|
291
|
+
* 2.3+
|
292
|
+
|
293
|
+
In future I want ot support other ruby sersion/platforms.
|
294
|
+
|
295
|
+
## Contributing
|
296
|
+
|
297
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/davydovanton/shallow_attributes.
|
298
|
+
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected
|
299
|
+
to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
300
|
+
|
301
|
+
|
302
|
+
## License
|
303
|
+
|
304
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
305
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
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
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
# Abstract class for value classes. Provides some helper methods for
|
3
|
+
# working with class methods.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
module ClassMethods
|
9
|
+
# Returns hash which contain default values for each attribute
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @return [Hash] hash with default values
|
14
|
+
#
|
15
|
+
# @since 0.1.0
|
16
|
+
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
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns all class attributes.
|
25
|
+
#
|
26
|
+
#
|
27
|
+
# @example Create new User instance
|
28
|
+
# class User
|
29
|
+
# include ShallowAttributes
|
30
|
+
# attribute :name, String
|
31
|
+
# attribute :last_name, String
|
32
|
+
# attribute :age, Integer
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# User.attributes # => [:name, :last_name, :age]
|
36
|
+
#
|
37
|
+
# @return [Hash]
|
38
|
+
#
|
39
|
+
# @since 0.1.0
|
40
|
+
def attributes
|
41
|
+
default_values.keys
|
42
|
+
end
|
43
|
+
|
44
|
+
# Define attribute with specific type and default value
|
45
|
+
# for current class.
|
46
|
+
#
|
47
|
+
# @param [String, Symbol] name the attribute name
|
48
|
+
# @param [String, Symbol] type the type of attribute
|
49
|
+
# @param [hash] options the attribute options
|
50
|
+
# @option options [Object] :default default value for attribute
|
51
|
+
# @option options [Class] :of class of array elems
|
52
|
+
# @option options [boolean] :allow_nil cast `nil` to integer or float
|
53
|
+
#
|
54
|
+
# @example Create new User instance
|
55
|
+
# class User
|
56
|
+
# include ShallowAttributes
|
57
|
+
# attribute :name, String, default: 'Anton'
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# User.new # => #<User @attributes={:name=>"Anton"}, @name="Anton">
|
61
|
+
# User.new(name: 'ben') # => #<User @attributes={:name=>"Ben"}, @name="Ben">
|
62
|
+
#
|
63
|
+
# @return [Object]
|
64
|
+
#
|
65
|
+
# @since 0.1.0
|
66
|
+
def attribute(name, type, options = {})
|
67
|
+
options[:default] ||= [] if type == Array
|
68
|
+
|
69
|
+
@default_values ||= {}
|
70
|
+
@default_values[name] = options.delete(:default)
|
71
|
+
|
72
|
+
initialize_setter(name, type, options)
|
73
|
+
initialize_getter(name)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Define setter method for each attribute.
|
79
|
+
#
|
80
|
+
# @private
|
81
|
+
#
|
82
|
+
# @param [String, Symbol] name the attribute name
|
83
|
+
# @param [String, Symbol] type the type of attribute
|
84
|
+
# @param [hash] options the attribute options
|
85
|
+
#
|
86
|
+
# @return [Object]
|
87
|
+
#
|
88
|
+
# @since 0.1.0
|
89
|
+
def initialize_setter(name, type, options)
|
90
|
+
module_eval <<-EOS, __FILE__, __LINE__ + 1
|
91
|
+
def #{name}=(value)
|
92
|
+
@#{name} = ShallowAttributes::Type.coerce(#{type}, value, #{options})
|
93
|
+
@attributes[:#{name}] = @#{name}
|
94
|
+
end
|
95
|
+
EOS
|
96
|
+
end
|
97
|
+
|
98
|
+
# Define getter method for each attribute.
|
99
|
+
#
|
100
|
+
# @private
|
101
|
+
#
|
102
|
+
# @param [String, Symbol] name the attribute name
|
103
|
+
#
|
104
|
+
# @return [Object]
|
105
|
+
#
|
106
|
+
# @since 0.1.0
|
107
|
+
def initialize_getter(name)
|
108
|
+
attr_reader name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
# Abstract class for value classes. Provides some helper methods for
|
3
|
+
# working with attributes.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
module InstanceMethods
|
9
|
+
# Lambda object for gettring attributes hash for specific
|
10
|
+
# value object.
|
11
|
+
#
|
12
|
+
# @private
|
13
|
+
#
|
14
|
+
# @since 0.1.0
|
15
|
+
TO_H_PROC = -> (value) { value.respond_to?(:to_hash) ? value.to_hash : value }
|
16
|
+
|
17
|
+
# Initialize instance object with specific attributes
|
18
|
+
#
|
19
|
+
# @param [Hash] attributes the attributes contained in the class
|
20
|
+
#
|
21
|
+
# @example Create new User instance
|
22
|
+
# class User
|
23
|
+
# include ShallowAttributes
|
24
|
+
# attribute :name, String
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# User.new(name: 'Anton') # => #<User @attributes={:name=>"Anton"}, @name="Anton">
|
28
|
+
#
|
29
|
+
# @return the new instance of value class with specific attributes
|
30
|
+
#
|
31
|
+
# @since 0.1.0
|
32
|
+
def initialize(attrs = {})
|
33
|
+
@attributes = attrs.delete_if { |key, _| !default_values.key?(key) }
|
34
|
+
define_attributes
|
35
|
+
define_default_attributes
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns hash of object attributes
|
39
|
+
#
|
40
|
+
# @example Returns all user attributs
|
41
|
+
# class User
|
42
|
+
# include ShallowAttributes
|
43
|
+
# attribute :name, String
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# user = User.new(name: 'Anton')
|
47
|
+
# user.attributes # => { name: "Anton" }
|
48
|
+
#
|
49
|
+
# @return [Hash]
|
50
|
+
#
|
51
|
+
# @since 0.1.0
|
52
|
+
def attributes
|
53
|
+
hash = {}
|
54
|
+
@attributes.map do |key, value|
|
55
|
+
hash[key] =
|
56
|
+
value.is_a?(Array) ? value.map!(&TO_H_PROC) : TO_H_PROC.call(value)
|
57
|
+
end
|
58
|
+
hash
|
59
|
+
end
|
60
|
+
|
61
|
+
# @since 0.1.0
|
62
|
+
alias_method :to_h, :attributes
|
63
|
+
|
64
|
+
# @since 0.1.0
|
65
|
+
alias_method :to_hash, :attributes
|
66
|
+
|
67
|
+
# Mass-assignment attribut values
|
68
|
+
#
|
69
|
+
# @param [Hash] attributes the attributes which will be assignment
|
70
|
+
#
|
71
|
+
# @example Assignment new user name
|
72
|
+
# class User
|
73
|
+
# include ShallowAttributes
|
74
|
+
# attribute :name, String
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# user = User.new(name: 'Anton')
|
78
|
+
# user.attributes = { name: "Ben" }
|
79
|
+
# user.attributes # => { name: "Ben" }
|
80
|
+
#
|
81
|
+
# @return [Hash] attibutes hash
|
82
|
+
#
|
83
|
+
# @since 0.1.0
|
84
|
+
def attributes=(attributes)
|
85
|
+
@attributes.merge!(attributes)
|
86
|
+
define_attributes
|
87
|
+
end
|
88
|
+
|
89
|
+
# Reser specific attribute to defaul value.
|
90
|
+
#
|
91
|
+
# @param [Symbol] attribute the attribute which will be resete
|
92
|
+
#
|
93
|
+
# @example Reset name valus
|
94
|
+
# class User
|
95
|
+
# include ShallowAttributes
|
96
|
+
# attribute :name, String, defauil: 'Ben'
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# user = User.new(name: 'Anton')
|
100
|
+
# user.reset_attribute(:name)
|
101
|
+
# user.attributes # => { name: "Ben" }
|
102
|
+
#
|
103
|
+
# @return the last attribute value
|
104
|
+
#
|
105
|
+
# @since 0.1.0
|
106
|
+
def reset_attribute(attribute)
|
107
|
+
instance_variable_set("@#{attribute}", default_value_for(attribute))
|
108
|
+
end
|
109
|
+
|
110
|
+
# Sets new values and returns self. Needs for embedded value.
|
111
|
+
#
|
112
|
+
# @private
|
113
|
+
#
|
114
|
+
# @param [Hash] values the new attributes for current object
|
115
|
+
# @param [Hash] options
|
116
|
+
#
|
117
|
+
# @example Use embedded values
|
118
|
+
# class User
|
119
|
+
# include ShallowAttributes
|
120
|
+
# attribute :name, String, defauil: 'Ben'
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# class Post
|
124
|
+
# include ShallowAttributes
|
125
|
+
# attribute :author, User
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# post = Post.new(author: { name: 'Anton'} )
|
129
|
+
# post.user.name # => 'Anton'
|
130
|
+
#
|
131
|
+
# @return the object
|
132
|
+
#
|
133
|
+
# @since 0.1.0
|
134
|
+
def coerce(value, options = {})
|
135
|
+
self.attributes = value
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
# Equalate two value objects
|
140
|
+
#
|
141
|
+
# @param [Object] object the other object
|
142
|
+
#
|
143
|
+
# @example Equalate two value objects
|
144
|
+
# class User
|
145
|
+
# include ShallowAttributes
|
146
|
+
# attribute :name, String, defauil: 'Ben'
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# user1 = User.new(name: 'Anton')
|
150
|
+
# user2 = User.new(name: 'Anton')
|
151
|
+
# user1 == user2 # => true
|
152
|
+
#
|
153
|
+
# @return [boolean]
|
154
|
+
#
|
155
|
+
# @since 0.1.0
|
156
|
+
def ==(object)
|
157
|
+
self.to_h == object.to_h
|
158
|
+
end
|
159
|
+
|
160
|
+
# Inspect instance object
|
161
|
+
#
|
162
|
+
# @example Equalate two value objects
|
163
|
+
# class User
|
164
|
+
# include ShallowAttributes
|
165
|
+
# attribute :name, String, defauil: 'Ben'
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# user = User.new(name: 'Anton')
|
169
|
+
# user.inspect # => "#<User name=\"Anton\">"
|
170
|
+
#
|
171
|
+
# @return [String]
|
172
|
+
#
|
173
|
+
# @since 0.1.0
|
174
|
+
def inspect
|
175
|
+
"#<#{self.class}#{attributes.map{ |k, v| " #{k}=#{v.inspect}" }.join}>"
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
# Defene default value for attributes.
|
181
|
+
#
|
182
|
+
# @private
|
183
|
+
#
|
184
|
+
# @return the object
|
185
|
+
#
|
186
|
+
# @since 0.1.0
|
187
|
+
def define_default_attributes
|
188
|
+
default_values.each do |key, value|
|
189
|
+
next unless @attributes[key].nil? && !value.nil?
|
190
|
+
send("#{key}=", default_value_for(key))
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Defene attributes from `@attributes` instance value.
|
195
|
+
#
|
196
|
+
# @private
|
197
|
+
#
|
198
|
+
# @return the object
|
199
|
+
#
|
200
|
+
# @since 0.1.0
|
201
|
+
def define_attributes
|
202
|
+
@attributes.each do |key, value|
|
203
|
+
send("#{key}=", value)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Retrns default value for specific attribute. Defaul values hash
|
208
|
+
# takes from class getter `default_values`.
|
209
|
+
#
|
210
|
+
# @private
|
211
|
+
#
|
212
|
+
# @return [nil] if default value not defined
|
213
|
+
# @return [Object] if default value defined
|
214
|
+
#
|
215
|
+
# @since 0.1.0
|
216
|
+
def default_value_for(attribute)
|
217
|
+
value = default_values[attribute]
|
218
|
+
|
219
|
+
case value
|
220
|
+
when Proc
|
221
|
+
value.call(self, attribute)
|
222
|
+
when Symbol, String
|
223
|
+
self.class.method_defined?(value) ? send(value) : value
|
224
|
+
else
|
225
|
+
value
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Returns hash of default class values
|
230
|
+
#
|
231
|
+
# @private
|
232
|
+
#
|
233
|
+
# @return [Hash]
|
234
|
+
#
|
235
|
+
# @since 0.1.0
|
236
|
+
def default_values
|
237
|
+
@default_values ||= self.class.default_values
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
module Type
|
3
|
+
# Abstract class for typecast object to Array type.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
class Array
|
9
|
+
# Convert value to Array type
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @param [Array] values
|
14
|
+
# @param [Hash] options
|
15
|
+
# @option options [String] :of the type of array element class
|
16
|
+
#
|
17
|
+
# @example Convert integer array to string array
|
18
|
+
# ShallowAttributes::Type::Array.new.coerce([1, 2], String)
|
19
|
+
# # => ['1', '2']
|
20
|
+
#
|
21
|
+
# @raise [InvalidValueError] if values is not Array
|
22
|
+
#
|
23
|
+
# @return [Array]
|
24
|
+
#
|
25
|
+
# @since 0.1.0
|
26
|
+
def coerce(values, options = {})
|
27
|
+
unless values.is_a? ::Array
|
28
|
+
raise ShallowAttributes::Type::InvalidValueError, %(Invalid value "#{values}" for type "Array")
|
29
|
+
end
|
30
|
+
|
31
|
+
values.map! { |value| ShallowAttributes::Type.coerce(options[:of], value) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
module Type
|
3
|
+
# Abstract class for typecast object to Boolean type.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
class Boolean
|
9
|
+
# Array of true values
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @since 0.1.0
|
14
|
+
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].freeze
|
15
|
+
|
16
|
+
# Array of false values
|
17
|
+
#
|
18
|
+
# @private
|
19
|
+
#
|
20
|
+
# @since 0.1.0
|
21
|
+
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF', nil].freeze
|
22
|
+
|
23
|
+
# Convert value to Boolean type
|
24
|
+
#
|
25
|
+
# @private
|
26
|
+
#
|
27
|
+
# @param [Object] value
|
28
|
+
# @param [Hash] option
|
29
|
+
#
|
30
|
+
# @example Convert integer to boolean value
|
31
|
+
# ShallowAttributes::Type::Boolean.new.coerce(1)
|
32
|
+
# # => true
|
33
|
+
#
|
34
|
+
# ShallowAttributes::Type::Boolean.new.coerce(0)
|
35
|
+
# # => false
|
36
|
+
#
|
37
|
+
# @raise [InvalidValueError] if values is not included in true and false arrays
|
38
|
+
#
|
39
|
+
# @return [boolean]
|
40
|
+
#
|
41
|
+
# @since 0.1.0
|
42
|
+
def coerce(value, options = {})
|
43
|
+
if TRUE_VALUES.include?(value)
|
44
|
+
true
|
45
|
+
elsif FALSE_VALUES.include?(value)
|
46
|
+
false
|
47
|
+
else
|
48
|
+
raise ShallowAttributes::Type::InvalidValueError, %(Invalid value "#{value}" for type "Boolean")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
module Type
|
3
|
+
# Abstract class for typecast object to DateTime type.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
class DateTime
|
9
|
+
# Convert value to DateTime type
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @param [Object] value
|
14
|
+
# @param [Hash] option
|
15
|
+
#
|
16
|
+
# @example Convert integer to datetime value
|
17
|
+
# ShallowAttributes::Type::DateTime.new.coerce('Thu Nov 29 14:33:20 GMT 2001')
|
18
|
+
# # => '2001-11-29T14:33:20+00:00'
|
19
|
+
#
|
20
|
+
# @raise [InvalidValueError] if values is not a sting
|
21
|
+
#
|
22
|
+
# @return [DateTime]
|
23
|
+
#
|
24
|
+
# @since 0.1.0
|
25
|
+
def coerce(value, options = {})
|
26
|
+
case value
|
27
|
+
when ::DateTime then value
|
28
|
+
when ::Time then ::DateTime.parse(value.to_s)
|
29
|
+
else
|
30
|
+
::DateTime.parse(value)
|
31
|
+
end
|
32
|
+
rescue
|
33
|
+
raise ShallowAttributes::Type::InvalidValueError, %(Invalid value "#{value}" for type "DateTime")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
module Type
|
3
|
+
# Abstract class for typecast object to Float type.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
class Float
|
9
|
+
# Convert value to Float type
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @param [Object] value
|
14
|
+
# @param [Hash] option
|
15
|
+
# @option options [boolean] :allow_nil cast `nil` to integer or float
|
16
|
+
#
|
17
|
+
# @example Convert string to float value
|
18
|
+
# ShallowAttributes::Type::Float.new.coerce('2001')
|
19
|
+
# # => 2001.0
|
20
|
+
#
|
21
|
+
# @raise [InvalidValueError] if values is invalid
|
22
|
+
#
|
23
|
+
# @return [Float]
|
24
|
+
#
|
25
|
+
# @since 0.1.0
|
26
|
+
def coerce(value, options = {})
|
27
|
+
case value
|
28
|
+
when nil then options[:allow_nil] ? 0.0 : nil
|
29
|
+
when ::TrueClass then 1.0
|
30
|
+
when ::FalseClass then 0.0
|
31
|
+
else
|
32
|
+
value.respond_to?(:to_f) ? value.to_f
|
33
|
+
: raise(ShallowAttributes::Type::InvalidValueError, %(Invalid value "#{value}" for type "Float"))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
module Type
|
3
|
+
# Abstract class for typecast object to Integer type.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
class Integer
|
9
|
+
# Convert value to Integer type
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @param [Object] value
|
14
|
+
# @param [Hash] option
|
15
|
+
# @option options [boolean] :allow_nil cast `nil` to integer or float
|
16
|
+
#
|
17
|
+
# @example Convert sting to integer value
|
18
|
+
# ShallowAttributes::Type::Integer.new.coerce('2001')
|
19
|
+
# # => 2001
|
20
|
+
#
|
21
|
+
# @raise [InvalidValueError] if values is invalid
|
22
|
+
#
|
23
|
+
# @return [Integer]
|
24
|
+
#
|
25
|
+
# @since 0.1.0
|
26
|
+
def coerce(value, options = {})
|
27
|
+
case value
|
28
|
+
when nil then options[:allow_nil] ? 0 : nil
|
29
|
+
when ::TrueClass then 1
|
30
|
+
when ::FalseClass then 0
|
31
|
+
else
|
32
|
+
value.respond_to?(:to_i) ? value.to_i
|
33
|
+
: raise(ShallowAttributes::Type::InvalidValueError, %(Invalid value "#{value}" for type "Integer"))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
module Type
|
3
|
+
# Abstract class for typecast object to String type.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
class String
|
9
|
+
# Convert value to String type
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @param [Object] value
|
14
|
+
# @param [Hash] option
|
15
|
+
#
|
16
|
+
# @example Convert intger to string value
|
17
|
+
# ShallowAttributes::Type::String.new.coerce(2001)
|
18
|
+
# # => '2001'
|
19
|
+
#
|
20
|
+
# @return [Sting]
|
21
|
+
#
|
22
|
+
# @since 0.1.0
|
23
|
+
def coerce(value, options = {})
|
24
|
+
case value
|
25
|
+
when ::Array then value.join
|
26
|
+
when ::Hash, ::Class then error(value)
|
27
|
+
else
|
28
|
+
value.respond_to?(:to_s) ? value.to_s : error(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def error(value)
|
35
|
+
raise ShallowAttributes::Type::InvalidValueError, %(Invalid value "#{value}" for type "String")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ShallowAttributes
|
2
|
+
module Type
|
3
|
+
# Abstract class for typecast object to Time type.
|
4
|
+
#
|
5
|
+
# @abstract
|
6
|
+
#
|
7
|
+
# @since 0.1.0
|
8
|
+
class Time
|
9
|
+
# Convert value to Time type
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
#
|
13
|
+
# @param [Object] value
|
14
|
+
# @param [Hash] option
|
15
|
+
#
|
16
|
+
# @example Convert string to Time value
|
17
|
+
# ShallowAttributes::Type::Time.new.coerce('Thu Nov 29 14:33:20 GMT 2001')
|
18
|
+
# # => '2001-11-29 14:33:20 +0000'
|
19
|
+
#
|
20
|
+
# @raise [InvalidValueError] if values is not a sting or integer
|
21
|
+
#
|
22
|
+
# @return [Time]
|
23
|
+
#
|
24
|
+
# @since 0.1.0
|
25
|
+
def coerce(value, options = {})
|
26
|
+
case value
|
27
|
+
when ::Time then value
|
28
|
+
when ::Integer then ::Time.at(value)
|
29
|
+
else
|
30
|
+
::Time.parse(value.to_s)
|
31
|
+
end
|
32
|
+
rescue
|
33
|
+
raise ShallowAttributes::Type::InvalidValueError, %(Invalid value "#{value}" for type "Time")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'shallow_attributes/type/array'
|
2
|
+
require 'shallow_attributes/type/boolean'
|
3
|
+
require 'shallow_attributes/type/date_time'
|
4
|
+
require 'shallow_attributes/type/float'
|
5
|
+
require 'shallow_attributes/type/integer'
|
6
|
+
require 'shallow_attributes/type/string'
|
7
|
+
require 'shallow_attributes/type/time'
|
8
|
+
|
9
|
+
module ShallowAttributes
|
10
|
+
# Namespace for standart type classes
|
11
|
+
#
|
12
|
+
# @since 0.1.0
|
13
|
+
module Type
|
14
|
+
# Error class for ivalid value types
|
15
|
+
#
|
16
|
+
# @since 0.1.0
|
17
|
+
class InvalidValueError < TypeError
|
18
|
+
end
|
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
|
+
# Hash object with cached type objects.
|
48
|
+
#
|
49
|
+
# @private
|
50
|
+
#
|
51
|
+
# @since 0.1.0
|
52
|
+
DEFAULT_TYPE_OBJECTS = {
|
53
|
+
::Array => ShallowAttributes::Type::Array.new,
|
54
|
+
::DateTime => ShallowAttributes::Type::DateTime.new,
|
55
|
+
::Float => ShallowAttributes::Type::Float.new,
|
56
|
+
::Integer => ShallowAttributes::Type::Integer.new,
|
57
|
+
::String => ShallowAttributes::Type::String.new,
|
58
|
+
::Time => ShallowAttributes::Type::Time.new
|
59
|
+
}.freeze
|
60
|
+
|
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
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'shallow_attributes/class_methods'
|
2
|
+
require 'shallow_attributes/instance_methods'
|
3
|
+
require 'shallow_attributes/type'
|
4
|
+
require 'shallow_attributes/version'
|
5
|
+
|
6
|
+
# Main module
|
7
|
+
#
|
8
|
+
# @since 0.1.0
|
9
|
+
module ShallowAttributes
|
10
|
+
include InstanceMethods
|
11
|
+
|
12
|
+
# Including ShallowAttributes class methods to specific class
|
13
|
+
#
|
14
|
+
# @private
|
15
|
+
#
|
16
|
+
# @param [Class] base the class containing class methods
|
17
|
+
#
|
18
|
+
# @return [Class] class for incluting ShallowAttributes gem
|
19
|
+
#
|
20
|
+
# @since 0.1.0
|
21
|
+
def self.included(base)
|
22
|
+
base.extend(ClassMethods)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Boolean class for working with bool values
|
27
|
+
#
|
28
|
+
# @private
|
29
|
+
#
|
30
|
+
# @since 0.1.0
|
31
|
+
class Boolean; end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'shallow_attributes/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "shallow_attributes"
|
8
|
+
spec.version = ShallowAttributes::VERSION
|
9
|
+
spec.authors = ["Anton Davydov"]
|
10
|
+
spec.email = ["antondavydov.o@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Attributes for Plain Old Ruby Objects}
|
13
|
+
spec.description = %q{Attributes for Plain Old Ruby Objects}
|
14
|
+
spec.homepage = "https://github.com/davydovanton/shallow_attributes"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
25
|
+
spec.add_development_dependency "simplecov", '~> 0'
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shallow_attributes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anton Davydov
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
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
|
+
description: Attributes for Plain Old Ruby Objects
|
70
|
+
email:
|
71
|
+
- antondavydov.o@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".travis.yml"
|
78
|
+
- CODE_OF_CONDUCT.md
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- bin/console
|
84
|
+
- bin/setup
|
85
|
+
- lib/shallow_attributes.rb
|
86
|
+
- lib/shallow_attributes/class_methods.rb
|
87
|
+
- lib/shallow_attributes/instance_methods.rb
|
88
|
+
- lib/shallow_attributes/type.rb
|
89
|
+
- lib/shallow_attributes/type/array.rb
|
90
|
+
- lib/shallow_attributes/type/boolean.rb
|
91
|
+
- lib/shallow_attributes/type/date_time.rb
|
92
|
+
- lib/shallow_attributes/type/float.rb
|
93
|
+
- lib/shallow_attributes/type/integer.rb
|
94
|
+
- lib/shallow_attributes/type/string.rb
|
95
|
+
- lib/shallow_attributes/type/time.rb
|
96
|
+
- lib/shallow_attributes/version.rb
|
97
|
+
- shallow_attributes.gemspec
|
98
|
+
homepage: https://github.com/davydovanton/shallow_attributes
|
99
|
+
licenses:
|
100
|
+
- MIT
|
101
|
+
metadata: {}
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 2.5.1
|
119
|
+
signing_key:
|
120
|
+
specification_version: 4
|
121
|
+
summary: Attributes for Plain Old Ruby Objects
|
122
|
+
test_files: []
|
123
|
+
has_rdoc:
|