u-attributes 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  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.