u-attributes 1.2.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97dfa238f3a4bbeea816dd6965e9261de6cff2af2c14a5934c9d2ffdee03b2a4
4
- data.tar.gz: a21fb9c6247d7d8b6969c0f60539dfe9e5bec6fb502c945dea64ec8534a86265
3
+ metadata.gz: ac1586077d89b91d2e851ce3f59819d0c474bc809fe9d64eff5d5627bd78a967
4
+ data.tar.gz: 7246180e49313f3b9038e3bfdd858356dce65a80c7c94aa6173a15afbea9ab90
5
5
  SHA512:
6
- metadata.gz: a99ea97d70785cfa6f90a3a638ca4fe68bffc2ee05d4b3d9f5a3b9b31de2c3076607f1c64753c1c3850df6150d105985a5336b2d66e0560dab77ceea35a12b28
7
- data.tar.gz: daaee31a1f10ec4c74ffc59131196f040ce33eee787ea0381643737ade568615d1b52c78964a392f8e41a476de940d5b0a215102537514783273dd79da0329f1
6
+ metadata.gz: 1ce2864d28e95139a1fc3e3a08ca08ea2c771eec936b5ff21567fb3f0bae792bd406a4b905c7c5346b7f53de3972a6f01ce4629e50e786935186ae6f93614956
7
+ data.tar.gz: 28076be013bc9038497297186994d23df2b39b16fb46b2a6c82d59520f3f5de84a3c1f1f89196a6dc073677f0fa339a707e1a2cb10591e9aabfc19dab80036b6
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ Gemfile.lock
data/.travis.sh CHANGED
@@ -20,5 +20,12 @@ ACTIVEMODEL_VERSION='5.0' bundle exec rake test
20
20
  ACTIVEMODEL_VERSION='5.1' bundle update
21
21
  ACTIVEMODEL_VERSION='5.1' bundle exec rake test
22
22
 
23
- ACTIVEMODEL_VERSION='5.2' bundle update
24
- ACTIVEMODEL_VERSION='5.2' bundle exec rake test
23
+ if [[ ! $ruby_v =~ '2.2.0' ]]; then
24
+ ACTIVEMODEL_VERSION='5.2' bundle update
25
+ ACTIVEMODEL_VERSION='5.2' bundle exec rake test
26
+ fi
27
+
28
+ if [[ $ruby_v =~ '2.5.' ]] || [[ $ruby_v =~ '2.6.' ]] || [[ $ruby_v =~ '2.7.' ]]; then
29
+ ACTIVEMODEL_VERSION='6.0' bundle update
30
+ ACTIVEMODEL_VERSION='6.0' bundle exec rake test
31
+ fi
@@ -8,6 +8,7 @@ rvm:
8
8
  - 2.4.0
9
9
  - 2.5.0
10
10
  - 2.6.0
11
+ - 2.7.0
11
12
 
12
13
  cache: bundler
13
14
 
@@ -20,9 +21,9 @@ install: bundle install --jobs=3 --retry=3
20
21
  before_script:
21
22
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
22
23
  - chmod +x ./cc-test-reporter
23
- - "./cc-test-reporter before-build"
24
+ - './cc-test-reporter before-build'
24
25
 
25
- script: "./.travis.sh"
26
+ script: './.travis.sh'
26
27
 
27
28
  after_success:
28
- - "./cc-test-reporter after-build -t simplecov"
29
+ - './cc-test-reporter after-build -t simplecov'
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ activemodel = case activemodel_version
10
10
  when '5.0' then '5.0.7'
11
11
  when '5.1' then '5.1.7'
12
12
  when '5.2' then '5.2.3'
13
- when '6.0' then '6.0.0.rc1'
13
+ when '6.0' then '6.0.0'
14
14
  end
15
15
 
16
16
  if activemodel_version < '6.1'
@@ -3,7 +3,7 @@ The MIT License (MIT)
3
3
  Copyright (c) 2019 Rodrigo Serradura
4
4
 
5
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
6
+ of this software and associated documentation files (the 'Software'), to deal
7
7
  in the Software without restriction, including without limitation the rights
8
8
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
9
  copies of the Software, and to permit persons to whom the Software is
@@ -12,7 +12,7 @@ furnished to do so, subject to the following conditions:
12
12
  The above copyright notice and this permission notice shall be included in
13
13
  all copies or substantial portions of the Software.
14
14
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
16
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
17
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
data/README.md CHANGED
@@ -1,34 +1,42 @@
1
+ ![Ruby](https://img.shields.io/badge/ruby-2.2+-ruby.svg?colorA=99004d&colorB=cc0066)
1
2
  [![Gem](https://img.shields.io/gem/v/u-attributes.svg?style=flat-square)](https://rubygems.org/gems/u-attributes)
2
3
  [![Build Status](https://travis-ci.com/serradura/u-attributes.svg?branch=master)](https://travis-ci.com/serradura/u-attributes)
3
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/maintainability)](https://codeclimate.com/github/serradura/u-attributes/maintainability)
4
5
  [![Test Coverage](https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/test_coverage)](https://codeclimate.com/github/serradura/u-attributes/test_coverage)
5
6
 
6
- μ-attributes (Micro::Attributes)
7
+ μ-attributes (Micro::Attributes) <!-- omit in toc -->
7
8
  ================================
8
9
 
9
10
  This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.
10
11
 
11
- ## Table of contents
12
- - [μ-attributes (Micro::Attributes)](#%ce%bc-attributes-microattributes)
13
- - [Table of contents](#table-of-contents)
14
- - [Required Ruby version](#required-ruby-version)
15
- - [Installation](#installation)
16
- - [Usage](#usage)
17
- - [How to require?](#how-to-require)
18
- - [How to define attributes?](#how-to-define-attributes)
19
- - [How to define multiple attributes?](#how-to-define-multiple-attributes)
20
- - [How to define attributes with a constructor to assign them?](#how-to-define-attributes-with-a-constructor-to-assign-them)
21
- - [How to inherit the attributes?](#how-to-inherit-the-attributes)
22
- - [How to query the attributes?](#how-to-query-the-attributes)
23
- - [Built-in extensions](#built-in-extensions)
24
- - [ActiveModel::Validations extension](#activemodelvalidations-extension)
25
- - [Diff extension](#diff-extension)
26
- - [Initialize extension](#initialize-extension)
27
- - [Strict initialize extension](#strict-initialize-extension)
28
- - [Development](#development)
29
- - [Contributing](#contributing)
30
- - [License](#license)
31
- - [Code of Conduct](#code-of-conduct)
12
+ ## Table of contents <!-- omit in toc -->
13
+ - [Required Ruby version](#required-ruby-version)
14
+ - [Installation](#installation)
15
+ - [Compatibility](#compatibility)
16
+ - [Usage](#usage)
17
+ - [How to define attributes?](#how-to-define-attributes)
18
+ - [`Micro::Attributes#attributes=`](#microattributesattributes)
19
+ - [`Micro::Attributes#attribute`](#microattributesattribute)
20
+ - [`Micro::Attributes#attribute!`](#microattributesattribute-1)
21
+ - [How to define multiple attributes?](#how-to-define-multiple-attributes)
22
+ - [`Micro::Attributes.with(:initialize)`](#microattributeswithinitialize)
23
+ - [`#with_attribute()`](#with_attribute)
24
+ - [`#with_attributes()`](#with_attributes)
25
+ - [Defining default values to the attributes](#defining-default-values-to-the-attributes)
26
+ - [Strict initializer](#strict-initializer)
27
+ - [Is it possible to inherit the attributes?](#is-it-possible-to-inherit-the-attributes)
28
+ - [.attribute!()](#attribute)
29
+ - [How to query the attributes?](#how-to-query-the-attributes)
30
+ - [Built-in extensions](#built-in-extensions)
31
+ - [ActiveModel::Validations extension](#activemodelvalidations-extension)
32
+ - [Attribute options](#attribute-options)
33
+ - [Diff extension](#diff-extension)
34
+ - [Initialize extension](#initialize-extension)
35
+ - [Strict initialize mode](#strict-initialize-mode)
36
+ - [Development](#development)
37
+ - [Contributing](#contributing)
38
+ - [License](#license)
39
+ - [Code of Conduct](#code-of-conduct)
32
40
 
33
41
  ## Required Ruby version
34
42
 
@@ -36,37 +44,24 @@ This gem allows defining read-only attributes, that is, your objects will have o
36
44
 
37
45
  ## Installation
38
46
 
39
- Add this line to your application's Gemfile:
47
+ Add this line to your application's Gemfile and `bundle install`:
40
48
 
41
49
  ```ruby
42
50
  gem 'u-attributes'
43
51
  ```
44
52
 
45
- And then execute:
53
+ ## Compatibility
46
54
 
47
- $ bundle
48
-
49
- Or install it yourself as:
50
-
51
- $ gem install u-attributes
55
+ | u-attributes | branch | ruby | activemodel |
56
+ | -------------- | ------- | -------- | ------------- |
57
+ | 2.0.0 | master | >= 2.2.0 | >= 3.2, < 6.1 |
58
+ | 1.2.0 | v1.x | >= 2.2.0 | >= 3.2, < 6.1 |
52
59
 
53
60
  ## Usage
54
61
 
55
- ### How to require?
56
- ```ruby
57
- # Bundler will do it automatically, but if you desire to do a manual require.
58
- # Use one of the following options:
59
-
60
- require 'micro/attributes'
61
-
62
- # or
63
-
64
- require 'u-attributes'
65
- ```
66
-
67
62
  ### How to define attributes?
68
- ```ruby
69
63
 
64
+ ```ruby
70
65
  # By default you must to define the class constructor.
71
66
 
72
67
  class Person
@@ -82,25 +77,25 @@ end
82
77
 
83
78
  person = Person.new(age: 21)
84
79
 
85
- puts person.name # John Doe
86
- puts person.age # 21
80
+ person.name # John Doe
81
+ person.age # 21
87
82
 
88
- # By design, the attributes expose only reader methods (getters).
89
- # If you try to call a setter, you will see a NoMethodError.
83
+ # By design the attributes are always exposed as reader methods (getters).
84
+ # If you try to call a setter you will see a NoMethodError.
90
85
  #
91
86
  # person.name = 'Rodrigo'
92
- # NoMethodError (undefined method `name=' for #<Person:0x0000... @name="John Doe", @age=21>)
87
+ # NoMethodError (undefined method `name=' for #<Person:0x0000... @name='John Doe', @age=21>)
88
+ ```
93
89
 
94
- #------------------#
95
- # self.attributes= #
96
- #------------------#
90
+ #### `Micro::Attributes#attributes=`
97
91
 
98
- # This protected method is added to make easier the assignment in a constructor.
92
+ This is a protected method to make easier the assignment in a constructor. e.g.
99
93
 
94
+ ```ruby
100
95
  class Person
101
96
  include Micro::Attributes
102
97
 
103
- attribute :name, 'John Doe' # .attribute() accepts a second arg as its default value
98
+ attribute :name, default: 'John Doe'
104
99
  attribute :age
105
100
 
106
101
  def initialize(options)
@@ -110,46 +105,49 @@ end
110
105
 
111
106
  person = Person.new(age: 20)
112
107
 
113
- puts person.name # John Doe
114
- puts person.age # 20
108
+ person.name # John Doe
109
+ person.age # 20
110
+ ```
115
111
 
116
- #--------------#
117
- # #attribute() #
118
- #--------------#
119
- #
120
- # Use the #attribute() method with a valid attribute name to get its value
112
+ #### `Micro::Attributes#attribute`
121
113
 
122
- puts person.attribute(:name) # John Doe
123
- puts person.attribute('age') # 20
124
- puts person.attribute('foo') # nil
114
+ Use this method with a valid attribute name to get its value.
125
115
 
126
- #
127
- # If you pass a block, it will be executed only if the attribute is valid.
116
+ ```ruby
117
+ person = Person.new(age: 20)
118
+
119
+ person.attribute(:name) # John Doe
120
+ person.attribute('age') # 20
121
+ person.attribute('foo') # nil
122
+ ```
128
123
 
124
+ If you pass a block, it will be executed only if the attribute was valid.
125
+
126
+ ```ruby
129
127
  person.attribute(:name) { |value| puts value } # John Doe
130
128
  person.attribute('age') { |value| puts value } # 20
131
- person.attribute('foo') { |value| puts value } # !! Nothing happened, because of the attribute not exists.
129
+ person.attribute('foo') { |value| puts value } # !! Nothing happened, because of the attribute doesn't exist.
130
+ ```
132
131
 
133
- #---------------#
134
- # #attribute!() #
135
- #---------------#
136
- #
137
- # Works like the #attribute() method, but will raise an exception when the attribute not exist.
132
+ #### `Micro::Attributes#attribute!`
138
133
 
139
- puts person.attribute!('foo') # NameError (undefined attribute `foo)
140
- person.attribute!('foo') { |value| puts value } # NameError (undefined attribute `foo)
134
+ Works like the `#attribute` method, but it will raise an exception when the attribute doesn't exist.
135
+
136
+ ```ruby
137
+ person.attribute!('foo') # NameError (undefined attribute `foo)
138
+
139
+ person.attribute!('foo') { |value| value } # NameError (undefined attribute `foo)
141
140
  ```
142
141
 
143
142
  ### How to define multiple attributes?
144
143
 
145
- ```ruby
146
-
147
- # Use .attributes with a list of attribute names.
144
+ Use `.attributes` with a list of attribute names.
148
145
 
146
+ ```ruby
149
147
  class Person
150
148
  include Micro::Attributes
151
149
 
152
- attributes :age, name: 'John Doe' # Use a hash to define attributes with default values
150
+ attributes :age, :name
153
151
 
154
152
  def initialize(options)
155
153
  self.attributes = options
@@ -158,89 +156,123 @@ end
158
156
 
159
157
  person = Person.new(age: 32)
160
158
 
161
- puts person.name # 'John Doe'
162
- puts person.age # 32
159
+ person.name # nil
160
+ person.age # 32
163
161
  ```
164
162
 
165
- ### How to define attributes with a constructor to assign them?
166
- A: Use `Micro::Attributes.to_initialize`
163
+ > **Note:** This method can't define default values. To do this, use the `#attribute()` method.
164
+
165
+ ### `Micro::Attributes.with(:initialize)`
166
+
167
+ Use `Micro::Attributes.with(:initialize)` to define a constructor to assign the attributes. e.g.
167
168
 
168
169
  ```ruby
169
170
  class Person
170
- include Micro::Attributes.to_initialize
171
+ include Micro::Attributes.with(:initialize)
171
172
 
172
- attributes :age, name: 'John Doe'
173
+ attribute :age
174
+ attribute :name, default: 'John Doe'
173
175
  end
174
176
 
175
177
  person = Person.new(age: 18)
176
178
 
177
- puts person.name # John Doe
178
- puts person.age # 18
179
+ person.name # John Doe
180
+ person.age # 18
181
+ ```
179
182
 
180
- ##############################################
181
- # Assigning new values to get a new instance #
182
- ##############################################
183
+ This extension enables two methods for your objects.
184
+ The `#with_attribute()` and `#with_attributes()`.
183
185
 
184
- #-------------------#
185
- # #with_attribute() #
186
- #-------------------#
186
+ #### `#with_attribute()`
187
187
 
188
+ ```ruby
188
189
  another_person = person.with_attribute(:age, 21)
189
190
 
190
- puts another_person.name # John Doe
191
- puts another_person.age # 21
192
- puts another_person.equal?(person) # false
191
+ another_person.name # John Doe
192
+ another_person.age # 21
193
+ another_person.equal?(person) # false
194
+ ```
193
195
 
194
- #--------------------#
195
- # #with_attributes() #
196
- #--------------------#
197
- #
198
- # Use it to assign multiple attributes
196
+ #### `#with_attributes()`
199
197
 
198
+ Use it to assign multiple attributes
199
+ ```ruby
200
200
  other_person = person.with_attributes(name: 'Serradura', age: 32)
201
201
 
202
- puts other_person.name # Serradura
203
- puts other_person.age # 32
204
- puts other_person.equal?(person) # false
202
+ other_person.name # Serradura
203
+ other_person.age # 32
204
+ other_person.equal?(person) # false
205
+ ```
205
206
 
206
- # If you pass a value different of a Hash, an ArgumentError will be raised.
207
- #
208
- # Person.new(1)
209
- # ArgumentError (argument must be a Hash)
207
+ If you pass a value different of a Hash, a Kind::Error will be raised.
210
208
 
211
- #--------------------#
212
- # Strict initializer #
213
- #--------------------#
209
+ ```ruby
210
+ Person.new(1) # Kind::Error (1 must be a Hash)
211
+ ```
212
+
213
+ ### Defining default values to the attributes
214
+
215
+ To do this, you only need make use of the `default:` keyword. e.g.
216
+
217
+ ```ruby
218
+ class Person
219
+ include Micro::Attributes.with(:initialize)
220
+
221
+ attribute :age
222
+ attribute :name, default: 'John Doe'
223
+ end
224
+ ```
225
+
226
+ There are 3 different strategies to define default values.
227
+ 1. Pass a regular object, like in the previous example.
228
+ 2. Pass a `proc`/`lambda`, and if it has an argument you will receive the attribute value to do something before assign it.
229
+ 3. Pass a **callable**, that is, a `class`, `module` or `instance` which responds to the `call` method. The behavior will be like the previous item (`proc`/`lambda`).
214
230
 
215
- # Use .to_initialize! to forbids an instantiation without all keywords.
231
+ ```ruby
232
+ class Person
233
+ include Micro::Attributes.with(:initialize)
216
234
 
235
+ attribute :age, default: -> age { age&.to_i }
236
+ attribute :name, default: -> name { String(name || 'John Doe').strip }
237
+ end
238
+ ```
239
+
240
+ ### Strict initializer
241
+
242
+ Use `.with(initialize: :strict)` to forbids an instantiation without all the attribute keywords. e.g.
243
+
244
+ ```ruby
217
245
  class StrictPerson
218
- include Micro::Attributes.to_initialize!
246
+ include Micro::Attributes.with(initialize: :strict)
219
247
 
220
- attributes :age, name: 'John Doe'
248
+ attribute :age
249
+ attribute :name, default: 'John Doe'
221
250
  end
222
251
 
223
- StrictPerson.new({})
252
+ StrictPerson.new({}) # ArgumentError (missing keyword: :age)
253
+ ```
224
254
 
225
- # The code above will raise:
226
- # ArgumentError (missing keyword: :age)
255
+ An attribute with a default value can be omitted.
227
256
 
257
+ ``` ruby
228
258
  person_without_age = StrictPerson.new(age: nil)
229
259
 
230
- p person_without_age.name # "John Doe"
231
- p person_without_age.age # nil
232
-
233
- # Except for this validation when initializing,
234
- # the `to_initialize!` method will works in the same ways of `to_initialize`.
260
+ person_without_age.name # 'John Doe'
261
+ person_without_age.age # nil
235
262
  ```
236
263
 
237
- ### How to inherit the attributes?
264
+ > **Note:** Except for this validation the `.with(initialize: :strict)` method will works in the same ways of `.with(:initialize)`.
265
+
266
+ ### Is it possible to inherit the attributes?
267
+
268
+ Yes. e.g.
238
269
 
239
270
  ```ruby
240
271
  class Person
241
- include Micro::Attributes.to_initialize
272
+ include Micro::Attributes.with(:initialize)
242
273
 
243
- attributes :age, name: 'John Doe'
274
+ attribute :age
275
+ attribute :name, default: 'John Doe'
244
276
  end
245
277
 
246
278
  class Subclass < Person # Will preserve the parent class attributes
@@ -249,33 +281,34 @@ end
249
281
 
250
282
  instance = Subclass.new({})
251
283
 
252
- puts instance.name # John Doe
253
- puts instance.respond_to?(:age) # true
254
- puts instance.respond_to?(:foo) # true
284
+ instance.name # John Doe
285
+ instance.respond_to?(:age) # true
286
+ instance.respond_to?(:foo) # true
287
+ ```
255
288
 
256
- #---------------------------------#
257
- # .attribute!() or .attributes!() #
258
- #---------------------------------#
289
+ #### .attribute!()
259
290
 
260
- # The methods above allow redefining the attributes default data
291
+ This method allows us to redefine the attributes default data that was defined in the parent class. e.g.
261
292
 
293
+ ```ruby
262
294
  class AnotherSubclass < Person
263
- attribute! :name, 'Alfa'
295
+ attribute! :name, default: 'Alfa'
264
296
  end
265
297
 
266
298
  alfa_person = AnotherSubclass.new({})
267
299
 
268
- p alfa_person.name # "Alfa"
269
- p alfa_person.age # nil
300
+ alfa_person.name # 'Alfa'
301
+ alfa_person.age # nil
270
302
 
271
303
  class SubSubclass < Subclass
272
- attributes! name: 'Beta', age: 0
304
+ attribute! :age, default: 0
305
+ attribute! :name, default: 'Beta'
273
306
  end
274
307
 
275
308
  beta_person = SubSubclass.new({})
276
309
 
277
- p beta_person.name # "Beta"
278
- p beta_person.age # 0
310
+ beta_person.name # 'Beta'
311
+ beta_person.age # 0
279
312
  ```
280
313
 
281
314
  ### How to query the attributes?
@@ -284,7 +317,8 @@ p beta_person.age # 0
284
317
  class Person
285
318
  include Micro::Attributes
286
319
 
287
- attributes :age, name: 'John Doe'
320
+ attribute :age
321
+ attribute :name, default: 'John Doe'
288
322
 
289
323
  def initialize(options)
290
324
  self.attributes = options
@@ -295,16 +329,16 @@ end
295
329
  # .attributes() #
296
330
  #---------------#
297
331
 
298
- p Person.attributes # ["name", "age"]
332
+ Person.attributes # ['name', 'age']
299
333
 
300
334
  #---------------#
301
335
  # .attribute?() #
302
336
  #---------------#
303
337
 
304
- puts Person.attribute?(:name) # true
305
- puts Person.attribute?('name') # true
306
- puts Person.attribute?('foo') # false
307
- puts Person.attribute?(:foo) # false
338
+ Person.attribute?(:name) # true
339
+ Person.attribute?('name') # true
340
+ Person.attribute?('foo') # false
341
+ Person.attribute?(:foo) # false
308
342
 
309
343
  # ---
310
344
 
@@ -314,17 +348,17 @@ person = Person.new(age: 20)
314
348
  # #attribute?() #
315
349
  #---------------#
316
350
 
317
- puts person.attribute?(:name) # true
318
- puts person.attribute?('name') # true
319
- puts person.attribute?('foo') # false
320
- puts person.attribute?(:foo) # false
351
+ person.attribute?(:name) # true
352
+ person.attribute?('name') # true
353
+ person.attribute?('foo') # false
354
+ person.attribute?(:foo) # false
321
355
 
322
356
  #---------------#
323
357
  # #attributes() #
324
358
  #---------------#
325
359
 
326
- p person.attributes # {"age"=>20, "name"=>"John Doe"}
327
- p Person.new(name: 'John').attributes # {"age"=>nil, "name"=>"John"}
360
+ person.attributes # {'age'=>20, 'name'=>'John Doe'}
361
+ Person.new(name: 'John').attributes # {'age'=>nil, 'name'=>'John'}
328
362
 
329
363
  #---------------------#
330
364
  # #attributes(*names) #
@@ -333,18 +367,16 @@ p Person.new(name: 'John').attributes # {"age"=>nil, "name"=>"John"}
333
367
  # Slices the attributes to include only the given keys.
334
368
  # Returns a hash containing the given keys (in their types).
335
369
 
336
- p person.attributes(:age) # {age: 20}
337
- p person.attributes(:age, :name) # {age: 20, name: "John Doe"}
338
- p person.attributes('age', 'name') # {"age"=>20, "name"=>"John Doe"}
370
+ person.attributes(:age) # {age: 20}
371
+ person.attributes(:age, :name) # {age: 20, name: 'John Doe'}
372
+ person.attributes('age', 'name') # {'age'=>20, 'name'=>'John Doe'}
339
373
  ```
340
374
 
341
375
  ## Built-in extensions
342
376
 
343
- You can use the method `Micro::Attributes.features()` or `Micro::Attributes.with()` to combine and require only the features that better fit your needs.
377
+ You can use the method `Micro::Attributes.with()` to combine and require only the features that better fit your needs.
344
378
 
345
- But, if you desire...
346
- 1. only one feature, use the `Micro::Attributes.feature()` method.
347
- 2. except one or more features, use the `Micro::Attributes.without()` method.
379
+ But, if you desire except one or more features, use the `Micro::Attributes.without()` method.
348
380
 
349
381
  ```ruby
350
382
  #===========================#
@@ -352,10 +384,10 @@ But, if you desire...
352
384
  #===========================#
353
385
 
354
386
  class Job
355
- include Micro::Attributes.feature(:diff)
387
+ include Micro::Attributes.with(:diff)
356
388
 
357
389
  attribute :id
358
- attribute :state, 'sleeping'
390
+ attribute :state, default: 'sleeping'
359
391
 
360
392
  def initialize(options)
361
393
  self.attributes = options
@@ -368,21 +400,20 @@ end
368
400
  #======================#
369
401
 
370
402
  class Job
371
- include Micro::Attributes.features
403
+ include Micro::Attributes.with_all_features
372
404
 
373
- attributes :id, state: 'sleeping'
405
+ attribute :id
406
+ attribute :state, default: 'sleeping'
374
407
  end
375
408
 
376
- # Note:
377
- # If `Micro::Attributes.features()` be invoked without arguments, a module with all features will be returned.
378
-
379
409
  #----------------------------------------------------------------------------#
380
410
  # Using the .with() method alias and adding the strict initialize extension. #
381
411
  #----------------------------------------------------------------------------#
382
412
  class Job
383
- include Micro::Attributes.with(:strict_initialize, :diff)
413
+ include Micro::Attributes.with(:diff, initialize: :strict)
384
414
 
385
- attributes :id, state: 'sleeping'
415
+ attribute :id
416
+ attribute :state, default: 'sleeping'
386
417
  end
387
418
 
388
419
  # Note:
@@ -392,28 +423,6 @@ end
392
423
  # include Micro::Attributes.with() # ArgumentError (Invalid feature name! Available options: diff, initialize, activemodel_validations)
393
424
  # end
394
425
 
395
- #===================================#
396
- # Alternatives to the methods above #
397
- #===================================#
398
-
399
- #---------------------------------------#
400
- # Via Micro::Attributes.to_initialize() #
401
- #---------------------------------------#
402
- class Job
403
- include Micro::Attributes.to_initialize(diff: true, activemodel_validations: true)
404
-
405
- # Same of `include Micro::Attributes.with(:initialize, :diff, :activemodel_validations)`
406
- end
407
-
408
- #----------------------------------------#
409
- # Via Micro::Attributes.to_initialize!() #
410
- #----------------------------------------#
411
- class Job
412
- include Micro::Attributes.to_initialize!(diff: false, activemodel_validations: true)
413
-
414
- # Same of `include Micro::Attributes.with(:strict_initialize, :activemodel_validations)`
415
- end
416
-
417
426
  #=====================================#
418
427
  # Loading except one or more features #
419
428
  # ----- #
@@ -422,7 +431,8 @@ end
422
431
  class Job
423
432
  include Micro::Attributes.without(:diff)
424
433
 
425
- attributes :id, state: 'sleeping'
434
+ attribute :id
435
+ attribute :state, default: 'sleeping'
426
436
  end
427
437
 
428
438
  # Note:
@@ -435,11 +445,11 @@ If your application uses ActiveModel as a dependency (like a regular Rails app).
435
445
 
436
446
  ```ruby
437
447
  class Job
438
- # include Micro::Attributes.with(:initialize, :activemodel_validations)
439
- # include Micro::Attributes.features(:initialize, :activemodel_validations)
440
- include Micro::Attributes.to_initialize(activemodel_validations: true)
448
+ include Micro::Attributes.with(:activemodel_validations)
449
+
450
+ attribute :id
451
+ attribute :state, default: 'sleeping'
441
452
 
442
- attributes :id, state: 'sleeping'
443
453
  validates! :id, :state, presence: true
444
454
  end
445
455
 
@@ -447,8 +457,27 @@ Job.new({}) # ActiveModel::StrictValidationFailed (Id can't be blank)
447
457
 
448
458
  job = Job.new(id: 1)
449
459
 
450
- p job.id # 1
451
- p job.state # "sleeping"
460
+ job.id # 1
461
+ job.state # 'sleeping'
462
+ ```
463
+
464
+ #### Attribute options
465
+
466
+ You can use the `validate` or `validates` options to define your attributes. e.g.
467
+
468
+ ```ruby
469
+ class Job
470
+ include Micro::Attributes.with(:activemodel_validations)
471
+
472
+ attribute :id, validates: { presence: true }
473
+ attribute :state, validate: :must_be_a_filled_string
474
+
475
+ def must_be_a_string
476
+ return if state.is_a?(String) && state.present?
477
+
478
+ errors.add(:state, 'must be a filled string')
479
+ end
480
+ end
452
481
  ```
453
482
 
454
483
  ### Diff extension
@@ -459,21 +488,20 @@ Provides a way to track changes in your object attributes.
459
488
  require 'securerandom'
460
489
 
461
490
  class Job
462
- # include Micro::Attributes.with(:initialize, :diff)
463
- # include Micro::Attributes.to_initialize(diff: true)
464
- include Micro::Attributes.features(:initialize, :diff)
491
+ include Micro::Attributes.with(:initialize, :diff)
465
492
 
466
- attributes :id, state: 'sleeping'
493
+ attribute :id
494
+ attribute :state, default: 'sleeping'
467
495
  end
468
496
 
469
497
  job = Job.new(id: SecureRandom.uuid())
470
498
 
471
- p job.id # A random UUID generated from SecureRandom.uuid(). e.g: "e68bcc74-b91c-45c2-a904-12f1298cc60e"
472
- p job.state # "sleeping"
499
+ job.id # A random UUID generated from SecureRandom.uuid(). e.g: 'e68bcc74-b91c-45c2-a904-12f1298cc60e'
500
+ job.state # 'sleeping'
473
501
 
474
502
  job_running = job.with_attribute(:state, 'running')
475
503
 
476
- p job_running.state # "running"
504
+ job_running.state # 'running'
477
505
 
478
506
  job_changes = job.diff_attributes(job_running)
479
507
 
@@ -481,50 +509,47 @@ job_changes = job.diff_attributes(job_running)
481
509
  # #present?, #blank?, #empty? #
482
510
  #-----------------------------#
483
511
 
484
- p job_changes.present? # true
485
- p job_changes.blank? # false
486
- p job_changes.empty? # false
512
+ job_changes.present? # true
513
+ job_changes.blank? # false
514
+ job_changes.empty? # false
487
515
 
488
516
  #-----------#
489
517
  # #changed? #
490
518
  #-----------#
491
- p job_changes.changed? # true
519
+ job_changes.changed? # true
492
520
 
493
- p job_changes.changed?(:id) # false
521
+ job_changes.changed?(:id) # false
494
522
 
495
- p job_changes.changed?(:state) # true
496
- p job_changes.changed?(:state, from: 'sleeping', to: 'running') # true
523
+ job_changes.changed?(:state) # true
524
+ job_changes.changed?(:state, from: 'sleeping', to: 'running') # true
497
525
 
498
526
  #----------------#
499
527
  # #differences() #
500
528
  #----------------#
501
- p job_changes.differences # {"state"=> {"from" => "sleeping", "to" => "running"}}
529
+ job_changes.differences # {'state'=> {'from' => 'sleeping', 'to' => 'running'}}
502
530
  ```
503
531
 
504
532
  ### Initialize extension
505
533
 
506
534
  1. Creates a constructor to assign the attributes.
507
- 2. Adds methods to build new instances when some data was assigned.
535
+ 2. Add methods to build new instances when some data was assigned.
508
536
 
509
537
  ```ruby
510
538
  class Job
511
- # include Micro::Attributes.with(:initialize)
512
- # include Micro::Attributes.feature(:initialize)
513
- # include Micro::Attributes.features(:initialize)
514
- include Micro::Attributes.to_initialize
539
+ include Micro::Attributes.with(:initialize)
515
540
 
516
541
  attributes :id, :state
517
542
  end
518
543
 
519
544
  job_null = Job.new({})
520
545
 
521
- p job.id # nil
522
- p job.state # nil
546
+ job.id # nil
547
+ job.state # nil
523
548
 
524
549
  job = Job.new(id: 1, state: 'sleeping')
525
550
 
526
- p job.id # 1
527
- p job.state # "sleeping"
551
+ job.id # 1
552
+ job.state # 'sleeping'
528
553
 
529
554
  ##############################################
530
555
  # Assigning new values to get a new instance #
@@ -536,9 +561,9 @@ p job.state # "sleeping"
536
561
 
537
562
  new_job = job.with_attribute(:state, 'running')
538
563
 
539
- puts new_job.id # 1
540
- puts new_job.state # running
541
- puts new_job.equal?(job) # false
564
+ new_job.id # 1
565
+ new_job.state # running
566
+ new_job.equal?(job) # false
542
567
 
543
568
  #--------------------#
544
569
  # #with_attributes() #
@@ -548,12 +573,12 @@ puts new_job.equal?(job) # false
548
573
 
549
574
  other_job = job.with_attributes(id: 2, state: 'killed')
550
575
 
551
- puts other_job.id # 2
552
- puts other_job.state # killed
553
- puts other_job.equal?(job) # false
576
+ other_job.id # 2
577
+ other_job.state # killed
578
+ other_job.equal?(job) # false
554
579
  ```
555
580
 
556
- ### Strict initialize extension
581
+ ### Strict initialize mode
557
582
 
558
583
  1. Creates a constructor to assign the attributes.
559
584
  2. Adds methods to build new instances when some data was assigned.
@@ -561,16 +586,13 @@ puts other_job.equal?(job) # false
561
586
 
562
587
  ```ruby
563
588
  class Job
564
- # include Micro::Attributes.with(:strict_initialize)
565
- # include Micro::Attributes.feature(:strict_initialize)
566
- # include Micro::Attributes.features(:strict_initialize)
567
- include Micro::Attributes.to_initialize!
589
+ include Micro::Attributes.with(initialize: :strict)
568
590
 
569
591
  attributes :id, :state
570
592
  end
571
- #----------------------------------------------------------------------------#
572
- # The strict_initialize extension will require all the keys when initialize. #
573
- #----------------------------------------------------------------------------#
593
+ #-----------------------------------------------------------------------#
594
+ # The strict initialize mode will require all the keys when initialize. #
595
+ #-----------------------------------------------------------------------#
574
596
 
575
597
  Job.new({})
576
598
 
@@ -583,20 +605,17 @@ Job.new({})
583
605
 
584
606
  job_null = Job.new(id: nil, state: nil)
585
607
 
586
- p job.id # nil
587
- p job.state # nil
608
+ job.id # nil
609
+ job.state # nil
588
610
 
589
611
  job = Job.new(id: 1, state: 'sleeping')
590
612
 
591
- p job.id # 1
592
- p job.state # "sleeping"
593
-
594
-
595
- # Note:
596
- # This extension works like the `initialize` extension.
597
- # So, look at its section to understand all the other features.
613
+ job.id # 1
614
+ job.state # 'sleeping'
598
615
  ```
599
616
 
617
+ > **Note**: This extension works like the `initialize` extension. So, look at its section to understand all of the other features.
618
+
600
619
  ## Development
601
620
 
602
621
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.