u-attributes 1.0.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: b3daaa2daf1f8ce4a90b6053e8a5a35d5f066197a15b4353f8f5e09717639bba
4
- data.tar.gz: '0499ade9185a2406a06acbc9d33b2e3de808ee23e5625af436253f0d654c7762'
3
+ metadata.gz: ac1586077d89b91d2e851ce3f59819d0c474bc809fe9d64eff5d5627bd78a967
4
+ data.tar.gz: 7246180e49313f3b9038e3bfdd858356dce65a80c7c94aa6173a15afbea9ab90
5
5
  SHA512:
6
- metadata.gz: 8a8ca5c7ee283753e8cbc1a6bf43580d71d98578bb0462464753da03df03c4c2a967629ae54be767a35b5d25720d38b07b85b992546eead410fcbd2180b547f1
7
- data.tar.gz: b1cf4055d9e3cc08c87d4fefe2a6b91797fcab85904f0697299cfd22525a0615a3e0d947339bac23ae3fd8b3113c11b05cd8c1609f38adaaaabb1b3781513e1a
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,67 +1,67 @@
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
- - [Installation](#installation)
15
- - [Usage](#usage)
16
- - [How to require?](#how-to-require)
17
- - [How to define attributes?](#how-to-define-attributes)
18
- - [How to define multiple attributes?](#how-to-define-multiple-attributes)
19
- - [How to define attributes with a constructor to assign them?](#how-to-define-attributes-with-a-constructor-to-assign-them)
20
- - [How to inherit the attributes?](#how-to-inherit-the-attributes)
21
- - [How to query the attributes?](#how-to-query-the-attributes)
22
- - [Built-in extensions](#built-in-extensions)
23
- - [ActiveModel::Validations extension](#activemodelvalidations-extension)
24
- - [Diff extension](#diff-extension)
25
- - [Initialize extension](#initialize-extension)
26
- - [Strict initialize extension](#strict-initialize-extension)
27
- - [Development](#development)
28
- - [Contributing](#contributing)
29
- - [License](#license)
30
- - [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)
40
+
41
+ ## Required Ruby version
42
+
43
+ > \>= 2.2.0
31
44
 
32
45
  ## Installation
33
46
 
34
- Add this line to your application's Gemfile:
47
+ Add this line to your application's Gemfile and `bundle install`:
35
48
 
36
49
  ```ruby
37
50
  gem 'u-attributes'
38
51
  ```
39
52
 
40
- And then execute:
53
+ ## Compatibility
41
54
 
42
- $ bundle
43
-
44
- Or install it yourself as:
45
-
46
- $ 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 |
47
59
 
48
60
  ## Usage
49
61
 
50
- ### How to require?
51
- ```ruby
52
- # Bundler will do it automatically, but if you desire to do a manual require.
53
- # Use one of the following options:
54
-
55
- require 'micro/attributes'
56
-
57
- # or
58
-
59
- require 'u-attributes'
60
- ```
61
-
62
62
  ### How to define attributes?
63
- ```ruby
64
63
 
64
+ ```ruby
65
65
  # By default you must to define the class constructor.
66
66
 
67
67
  class Person
@@ -77,25 +77,25 @@ end
77
77
 
78
78
  person = Person.new(age: 21)
79
79
 
80
- puts person.name # John Doe
81
- puts person.age # 21
80
+ person.name # John Doe
81
+ person.age # 21
82
82
 
83
- # By design, the attributes expose only reader methods (getters).
84
- # 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.
85
85
  #
86
86
  # person.name = 'Rodrigo'
87
- # 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
+ ```
88
89
 
89
- #------------------#
90
- # self.attributes= #
91
- #------------------#
90
+ #### `Micro::Attributes#attributes=`
92
91
 
93
- # 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.
94
93
 
94
+ ```ruby
95
95
  class Person
96
96
  include Micro::Attributes
97
97
 
98
- attribute :name, 'John Doe' # .attribute() accepts a second arg as its default value
98
+ attribute :name, default: 'John Doe'
99
99
  attribute :age
100
100
 
101
101
  def initialize(options)
@@ -105,46 +105,49 @@ end
105
105
 
106
106
  person = Person.new(age: 20)
107
107
 
108
- puts person.name # John Doe
109
- puts person.age # 20
108
+ person.name # John Doe
109
+ person.age # 20
110
+ ```
110
111
 
111
- #--------------#
112
- # #attribute() #
113
- #--------------#
114
- #
115
- # Use the #attribute() method with a valid attribute name to get its value
112
+ #### `Micro::Attributes#attribute`
116
113
 
117
- puts person.attribute(:name) # John Doe
118
- puts person.attribute('age') # 20
119
- puts person.attribute('foo') # nil
114
+ Use this method with a valid attribute name to get its value.
120
115
 
121
- #
122
- # 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
+ ```
123
123
 
124
+ If you pass a block, it will be executed only if the attribute was valid.
125
+
126
+ ```ruby
124
127
  person.attribute(:name) { |value| puts value } # John Doe
125
128
  person.attribute('age') { |value| puts value } # 20
126
- 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
+ ```
127
131
 
128
- #---------------#
129
- # #attribute!() #
130
- #---------------#
131
- #
132
- # Works like the #attribute() method, but will raise an exception when the attribute not exist.
132
+ #### `Micro::Attributes#attribute!`
133
133
 
134
- puts person.attribute!('foo') # NameError (undefined attribute `foo)
135
- 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)
136
140
  ```
137
141
 
138
142
  ### How to define multiple attributes?
139
143
 
140
- ```ruby
141
-
142
- # Use .attributes with a list of attribute names.
144
+ Use `.attributes` with a list of attribute names.
143
145
 
146
+ ```ruby
144
147
  class Person
145
148
  include Micro::Attributes
146
149
 
147
- attributes :age, name: 'John Doe' # Use a hash to define attributes with default values
150
+ attributes :age, :name
148
151
 
149
152
  def initialize(options)
150
153
  self.attributes = options
@@ -153,89 +156,123 @@ end
153
156
 
154
157
  person = Person.new(age: 32)
155
158
 
156
- puts person.name # 'John Doe'
157
- puts person.age # 32
159
+ person.name # nil
160
+ person.age # 32
158
161
  ```
159
162
 
160
- ### How to define attributes with a constructor to assign them?
161
- 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.
162
168
 
163
169
  ```ruby
164
170
  class Person
165
- include Micro::Attributes.to_initialize
171
+ include Micro::Attributes.with(:initialize)
166
172
 
167
- attributes :age, name: 'John Doe'
173
+ attribute :age
174
+ attribute :name, default: 'John Doe'
168
175
  end
169
176
 
170
177
  person = Person.new(age: 18)
171
178
 
172
- puts person.name # John Doe
173
- puts person.age # 18
179
+ person.name # John Doe
180
+ person.age # 18
181
+ ```
174
182
 
175
- ##############################################
176
- # Assigning new values to get a new instance #
177
- ##############################################
183
+ This extension enables two methods for your objects.
184
+ The `#with_attribute()` and `#with_attributes()`.
178
185
 
179
- #-------------------#
180
- # #with_attribute() #
181
- #-------------------#
186
+ #### `#with_attribute()`
182
187
 
188
+ ```ruby
183
189
  another_person = person.with_attribute(:age, 21)
184
190
 
185
- puts another_person.name # John Doe
186
- puts another_person.age # 21
187
- puts another_person.equal?(person) # false
191
+ another_person.name # John Doe
192
+ another_person.age # 21
193
+ another_person.equal?(person) # false
194
+ ```
188
195
 
189
- #--------------------#
190
- # #with_attributes() #
191
- #--------------------#
192
- #
193
- # Use it to assign multiple attributes
196
+ #### `#with_attributes()`
194
197
 
198
+ Use it to assign multiple attributes
199
+ ```ruby
195
200
  other_person = person.with_attributes(name: 'Serradura', age: 32)
196
201
 
197
- puts other_person.name # Serradura
198
- puts other_person.age # 32
199
- puts other_person.equal?(person) # false
202
+ other_person.name # Serradura
203
+ other_person.age # 32
204
+ other_person.equal?(person) # false
205
+ ```
200
206
 
201
- # If you pass a value different of a Hash, an ArgumentError will be raised.
202
- #
203
- # Person.new(1)
204
- # ArgumentError (argument must be a Hash)
207
+ If you pass a value different of a Hash, a Kind::Error will be raised.
205
208
 
206
- #--------------------#
207
- # Strict initializer #
208
- #--------------------#
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`).
209
230
 
210
- # Use .to_initialize! to forbids an instantiation without all keywords.
231
+ ```ruby
232
+ class Person
233
+ include Micro::Attributes.with(:initialize)
211
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
212
245
  class StrictPerson
213
- include Micro::Attributes.to_initialize!
246
+ include Micro::Attributes.with(initialize: :strict)
214
247
 
215
- attributes :age, name: 'John Doe'
248
+ attribute :age
249
+ attribute :name, default: 'John Doe'
216
250
  end
217
251
 
218
- StrictPerson.new({})
252
+ StrictPerson.new({}) # ArgumentError (missing keyword: :age)
253
+ ```
219
254
 
220
- # The code above will raise:
221
- # ArgumentError (missing keyword: :age)
255
+ An attribute with a default value can be omitted.
222
256
 
257
+ ``` ruby
223
258
  person_without_age = StrictPerson.new(age: nil)
224
259
 
225
- p person_without_age.name # "John Doe"
226
- p person_without_age.age # nil
227
-
228
- # Except for this validation when initializing,
229
- # 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
230
262
  ```
231
263
 
232
- ### 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.
233
269
 
234
270
  ```ruby
235
271
  class Person
236
- include Micro::Attributes.to_initialize
272
+ include Micro::Attributes.with(:initialize)
237
273
 
238
- attributes :age, name: 'John Doe'
274
+ attribute :age
275
+ attribute :name, default: 'John Doe'
239
276
  end
240
277
 
241
278
  class Subclass < Person # Will preserve the parent class attributes
@@ -244,33 +281,34 @@ end
244
281
 
245
282
  instance = Subclass.new({})
246
283
 
247
- puts instance.name # John Doe
248
- puts instance.respond_to?(:age) # true
249
- puts instance.respond_to?(:foo) # true
284
+ instance.name # John Doe
285
+ instance.respond_to?(:age) # true
286
+ instance.respond_to?(:foo) # true
287
+ ```
250
288
 
251
- #---------------------------------#
252
- # .attribute!() or .attributes!() #
253
- #---------------------------------#
289
+ #### .attribute!()
254
290
 
255
- # 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.
256
292
 
293
+ ```ruby
257
294
  class AnotherSubclass < Person
258
- attribute! :name, 'Alfa'
295
+ attribute! :name, default: 'Alfa'
259
296
  end
260
297
 
261
298
  alfa_person = AnotherSubclass.new({})
262
299
 
263
- p alfa_person.name # "Alfa"
264
- p alfa_person.age # nil
300
+ alfa_person.name # 'Alfa'
301
+ alfa_person.age # nil
265
302
 
266
303
  class SubSubclass < Subclass
267
- attributes! name: 'Beta', age: 0
304
+ attribute! :age, default: 0
305
+ attribute! :name, default: 'Beta'
268
306
  end
269
307
 
270
308
  beta_person = SubSubclass.new({})
271
309
 
272
- p beta_person.name # "Beta"
273
- p beta_person.age # 0
310
+ beta_person.name # 'Beta'
311
+ beta_person.age # 0
274
312
  ```
275
313
 
276
314
  ### How to query the attributes?
@@ -279,7 +317,8 @@ p beta_person.age # 0
279
317
  class Person
280
318
  include Micro::Attributes
281
319
 
282
- attributes :age, name: 'John Doe'
320
+ attribute :age
321
+ attribute :name, default: 'John Doe'
283
322
 
284
323
  def initialize(options)
285
324
  self.attributes = options
@@ -290,16 +329,16 @@ end
290
329
  # .attributes() #
291
330
  #---------------#
292
331
 
293
- p Person.attributes # ["name", "age"]
332
+ Person.attributes # ['name', 'age']
294
333
 
295
334
  #---------------#
296
335
  # .attribute?() #
297
336
  #---------------#
298
337
 
299
- puts Person.attribute?(:name) # true
300
- puts Person.attribute?('name') # true
301
- puts Person.attribute?('foo') # false
302
- 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
303
342
 
304
343
  # ---
305
344
 
@@ -309,62 +348,72 @@ person = Person.new(age: 20)
309
348
  # #attribute?() #
310
349
  #---------------#
311
350
 
312
- puts person.attribute?(:name) # true
313
- puts person.attribute?('name') # true
314
- puts person.attribute?('foo') # false
315
- 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
316
355
 
317
356
  #---------------#
318
357
  # #attributes() #
319
358
  #---------------#
320
359
 
321
- p person.attributes # {"age"=>20, "name"=>"John Doe"}
322
- 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'}
362
+
363
+ #---------------------#
364
+ # #attributes(*names) #
365
+ #---------------------#
366
+
367
+ # Slices the attributes to include only the given keys.
368
+ # Returns a hash containing the given keys (in their types).
369
+
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'}
323
373
  ```
324
374
 
325
375
  ## Built-in extensions
326
376
 
327
- 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.
328
378
 
329
- Note: If you desire require only one feature, use the `Micro::Attributes.feature()` method.
379
+ But, if you desire except one or more features, use the `Micro::Attributes.without()` method.
330
380
 
331
381
  ```ruby
332
- #----------------------------------#
333
- # Via Micro::Attributes.features() #
334
- #----------------------------------#
335
-
336
- # Loading specific features
382
+ #===========================#
383
+ # Loading specific features #
384
+ #===========================#
337
385
 
338
386
  class Job
339
- include Micro::Attributes.feature(:diff)
387
+ include Micro::Attributes.with(:diff)
340
388
 
341
389
  attribute :id
342
- attribute :state, 'sleeping'
390
+ attribute :state, default: 'sleeping'
343
391
 
344
392
  def initialize(options)
345
393
  self.attributes = options
346
394
  end
347
395
  end
348
396
 
349
- # Loading all features
350
- # ---
397
+ #======================#
398
+ # Loading all features #
399
+ # --- #
400
+ #======================#
351
401
 
352
402
  class Job
353
- include Micro::Attributes.features
403
+ include Micro::Attributes.with_all_features
354
404
 
355
- attributes :id, state: 'sleeping'
405
+ attribute :id
406
+ attribute :state, default: 'sleeping'
356
407
  end
357
408
 
358
- # Note:
359
- # If `Micro::Attributes.features()` be invoked without arguments, a module with all features will be returned.
360
-
361
409
  #----------------------------------------------------------------------------#
362
410
  # Using the .with() method alias and adding the strict initialize extension. #
363
411
  #----------------------------------------------------------------------------#
364
412
  class Job
365
- include Micro::Attributes.with(:strict_initialize, :diff)
413
+ include Micro::Attributes.with(:diff, initialize: :strict)
366
414
 
367
- attributes :id, state: 'sleeping'
415
+ attribute :id
416
+ attribute :state, default: 'sleeping'
368
417
  end
369
418
 
370
419
  # Note:
@@ -374,27 +423,20 @@ end
374
423
  # include Micro::Attributes.with() # ArgumentError (Invalid feature name! Available options: diff, initialize, activemodel_validations)
375
424
  # end
376
425
 
377
- #===================================#
378
- # Alternatives to the methods above #
379
- #===================================#
426
+ #=====================================#
427
+ # Loading except one or more features #
428
+ # ----- #
429
+ #=====================================#
380
430
 
381
- #---------------------------------------#
382
- # Via Micro::Attributes.to_initialize() #
383
- #---------------------------------------#
384
431
  class Job
385
- include Micro::Attributes.to_initialize(diff: true, activemodel_validations: true)
432
+ include Micro::Attributes.without(:diff)
386
433
 
387
- # Same of `include Micro::Attributes.with(:initialize, :diff, :activemodel_validations)`
434
+ attribute :id
435
+ attribute :state, default: 'sleeping'
388
436
  end
389
437
 
390
- #----------------------------------------#
391
- # Via Micro::Attributes.to_initialize!() #
392
- #----------------------------------------#
393
- class Job
394
- include Micro::Attributes.to_initialize!(diff: false, activemodel_validations: true)
395
-
396
- # Same of `include Micro::Attributes.with(:strict_initialize, :activemodel_validations)`
397
- end
438
+ # Note:
439
+ # The method `Micro::Attributes.without()` returns `Micro::Attributes` if all features extensions were used.
398
440
  ```
399
441
 
400
442
  ### ActiveModel::Validations extension
@@ -403,11 +445,11 @@ If your application uses ActiveModel as a dependency (like a regular Rails app).
403
445
 
404
446
  ```ruby
405
447
  class Job
406
- # include Micro::Attributes.with(:initialize, :activemodel_validations)
407
- # include Micro::Attributes.features(:initialize, :activemodel_validations)
408
- include Micro::Attributes.to_initialize(activemodel_validations: true)
448
+ include Micro::Attributes.with(:activemodel_validations)
449
+
450
+ attribute :id
451
+ attribute :state, default: 'sleeping'
409
452
 
410
- attributes :id, state: 'sleeping'
411
453
  validates! :id, :state, presence: true
412
454
  end
413
455
 
@@ -415,8 +457,27 @@ Job.new({}) # ActiveModel::StrictValidationFailed (Id can't be blank)
415
457
 
416
458
  job = Job.new(id: 1)
417
459
 
418
- p job.id # 1
419
- 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
420
481
  ```
421
482
 
422
483
  ### Diff extension
@@ -427,21 +488,20 @@ Provides a way to track changes in your object attributes.
427
488
  require 'securerandom'
428
489
 
429
490
  class Job
430
- # include Micro::Attributes.with(:initialize, :diff)
431
- # include Micro::Attributes.to_initialize(diff: true)
432
- include Micro::Attributes.features(:initialize, :diff)
491
+ include Micro::Attributes.with(:initialize, :diff)
433
492
 
434
- attributes :id, state: 'sleeping'
493
+ attribute :id
494
+ attribute :state, default: 'sleeping'
435
495
  end
436
496
 
437
497
  job = Job.new(id: SecureRandom.uuid())
438
498
 
439
- p job.id # A random UUID generated from SecureRandom.uuid(). e.g: "e68bcc74-b91c-45c2-a904-12f1298cc60e"
440
- 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'
441
501
 
442
502
  job_running = job.with_attribute(:state, 'running')
443
503
 
444
- p job_running.state # "running"
504
+ job_running.state # 'running'
445
505
 
446
506
  job_changes = job.diff_attributes(job_running)
447
507
 
@@ -449,50 +509,47 @@ job_changes = job.diff_attributes(job_running)
449
509
  # #present?, #blank?, #empty? #
450
510
  #-----------------------------#
451
511
 
452
- p job_changes.present? # true
453
- p job_changes.blank? # false
454
- p job_changes.empty? # false
512
+ job_changes.present? # true
513
+ job_changes.blank? # false
514
+ job_changes.empty? # false
455
515
 
456
516
  #-----------#
457
517
  # #changed? #
458
518
  #-----------#
459
- p job_changes.changed? # true
519
+ job_changes.changed? # true
460
520
 
461
- p job_changes.changed?(:id) # false
521
+ job_changes.changed?(:id) # false
462
522
 
463
- p job_changes.changed?(:state) # true
464
- 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
465
525
 
466
526
  #----------------#
467
527
  # #differences() #
468
528
  #----------------#
469
- p job_changes.differences # {"state"=> {"from" => "sleeping", "to" => "running"}}
529
+ job_changes.differences # {'state'=> {'from' => 'sleeping', 'to' => 'running'}}
470
530
  ```
471
531
 
472
532
  ### Initialize extension
473
533
 
474
534
  1. Creates a constructor to assign the attributes.
475
- 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.
476
536
 
477
537
  ```ruby
478
538
  class Job
479
- # include Micro::Attributes.with(:initialize)
480
- # include Micro::Attributes.feature(:initialize)
481
- # include Micro::Attributes.features(:initialize)
482
- include Micro::Attributes.to_initialize
539
+ include Micro::Attributes.with(:initialize)
483
540
 
484
541
  attributes :id, :state
485
542
  end
486
543
 
487
544
  job_null = Job.new({})
488
545
 
489
- p job.id # nil
490
- p job.state # nil
546
+ job.id # nil
547
+ job.state # nil
491
548
 
492
549
  job = Job.new(id: 1, state: 'sleeping')
493
550
 
494
- p job.id # 1
495
- p job.state # "sleeping"
551
+ job.id # 1
552
+ job.state # 'sleeping'
496
553
 
497
554
  ##############################################
498
555
  # Assigning new values to get a new instance #
@@ -504,9 +561,9 @@ p job.state # "sleeping"
504
561
 
505
562
  new_job = job.with_attribute(:state, 'running')
506
563
 
507
- puts new_job.id # 1
508
- puts new_job.state # running
509
- puts new_job.equal?(job) # false
564
+ new_job.id # 1
565
+ new_job.state # running
566
+ new_job.equal?(job) # false
510
567
 
511
568
  #--------------------#
512
569
  # #with_attributes() #
@@ -516,12 +573,12 @@ puts new_job.equal?(job) # false
516
573
 
517
574
  other_job = job.with_attributes(id: 2, state: 'killed')
518
575
 
519
- puts other_job.id # 2
520
- puts other_job.state # killed
521
- puts other_job.equal?(job) # false
576
+ other_job.id # 2
577
+ other_job.state # killed
578
+ other_job.equal?(job) # false
522
579
  ```
523
580
 
524
- ### Strict initialize extension
581
+ ### Strict initialize mode
525
582
 
526
583
  1. Creates a constructor to assign the attributes.
527
584
  2. Adds methods to build new instances when some data was assigned.
@@ -529,16 +586,13 @@ puts other_job.equal?(job) # false
529
586
 
530
587
  ```ruby
531
588
  class Job
532
- # include Micro::Attributes.with(:strict_initialize)
533
- # include Micro::Attributes.feature(:strict_initialize)
534
- # include Micro::Attributes.features(:strict_initialize)
535
- include Micro::Attributes.to_initialize!
589
+ include Micro::Attributes.with(initialize: :strict)
536
590
 
537
591
  attributes :id, :state
538
592
  end
539
- #----------------------------------------------------------------------------#
540
- # The strict_initialize extension will require all the keys when initialize. #
541
- #----------------------------------------------------------------------------#
593
+ #-----------------------------------------------------------------------#
594
+ # The strict initialize mode will require all the keys when initialize. #
595
+ #-----------------------------------------------------------------------#
542
596
 
543
597
  Job.new({})
544
598
 
@@ -549,22 +603,19 @@ Job.new({})
549
603
  # Samples passing some data #
550
604
  #---------------------------#
551
605
 
552
- job_null = Job.new({})
606
+ job_null = Job.new(id: nil, state: nil)
553
607
 
554
- p job.id # nil
555
- p job.state # nil
608
+ job.id # nil
609
+ job.state # nil
556
610
 
557
611
  job = Job.new(id: 1, state: 'sleeping')
558
612
 
559
- p job.id # 1
560
- p job.state # "sleeping"
561
-
562
-
563
- # Note:
564
- # This extension works like the `initialize` extension.
565
- # So, look at its section to understand all the other features.
613
+ job.id # 1
614
+ job.state # 'sleeping'
566
615
  ```
567
616
 
617
+ > **Note**: This extension works like the `initialize` extension. So, look at its section to understand all of the other features.
618
+
568
619
  ## Development
569
620
 
570
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.