README.md in u-attributes-2.3.0 vs README.md in u-attributes-2.4.0
- old
+ new
@@ -52,11 +52,11 @@
- [`#attribute?()`](#attribute-2)
- [`#attributes()`](#attributes-1)
- [`#attributes(keys_as:)`](#attributeskeys_as)
- [`#attributes(*names)`](#attributesnames)
- [`#attributes([names])`](#attributesnames-1)
- - [`#attributes(with:, without)`](#attributeswith-without)
+ - [`#attributes(with:, without:)`](#attributeswith-without)
- [`#defined_attributes`](#defined_attributes)
- [Built-in extensions](#built-in-extensions)
- [Picking specific features](#picking-specific-features)
- [`Micro::Attributes.with`](#microattributeswith)
- [`Micro::Attributes.without`](#microattributeswithout)
@@ -65,10 +65,11 @@
- [`ActiveModel::Validation` extension](#activemodelvalidation-extension)
- [`.attribute()` options](#attribute-options)
- [Diff extension](#diff-extension)
- [Initialize extension](#initialize-extension)
- [Strict mode](#strict-mode)
+ - [Keys as symbol extension](#keys-as-symbol-extension)
- [Development](#development)
- [Contributing](#contributing)
- [License](#license)
- [Code of Conduct](#code-of-conduct)
@@ -82,11 +83,11 @@
# Compatibility
| u-attributes | branch | ruby | activemodel |
| -------------- | ------- | -------- | ------------- |
-| 2.3.0 | main | >= 2.2.0 | >= 3.2, < 6.1 |
+| 2.4.0 | main | >= 2.2.0 | >= 3.2, < 6.1 |
| 1.2.0 | v1.x | >= 2.2.0 | >= 3.2, < 6.1 |
> **Note**: The activemodel is an optional dependency, this module [can be enabled](#activemodelvalidation-extension) to validate the attributes.
[⬆️ Back to Top](#table-of-contents-)
@@ -496,18 +497,21 @@
person2.attributes # {"age"=>nil, "first_name"=>"Rodrigo", "last_name"=>"Rodrigues"}
```
#### `#attributes(keys_as:)`
-Use the `keys_as:` option with `Symbol` or `String` to transform the attributes hash keys.
+Use the `keys_as:` option with `Symbol`/`:symbol` or `String`/`:string` to transform the attributes hash keys.
```ruby
person1 = Person.new(age: 20)
-person1.attributes(keys_as: Symbol) # {:age=>20, :first_name=>"John", :last_name=>"Doe"}
-
person2 = Person.new(first_name: 'Rodrigo', last_name: 'Rodrigues')
+
+person1.attributes(keys_as: Symbol) # {:age=>20, :first_name=>"John", :last_name=>"Doe"}
person2.attributes(keys_as: String) # {"age"=>nil, "first_name"=>"Rodrigo", "last_name"=>"Rodrigues"}
+
+person1.attributes(keys_as: :symbol) # {:age=>20, :first_name=>"John", :last_name=>"Doe"}
+person2.attributes(keys_as: :string) # {"age"=>nil, "first_name"=>"Rodrigo", "last_name"=>"Rodrigues"}
```
#### `#attributes(*names)`
Slices the attributes to include only the given keys (in their types).
@@ -542,11 +546,11 @@
# You could also use the keys_as: option to ensure the same type for all of the hash keys.
person.attributes([:age, 'last_name'], keys_as: Symbol) # {:age=>20, :last_name=>"Doe"}
```
-#### `#attributes(with:, without)`
+#### `#attributes(with:, without:)`
Use the `with:` option to include any method value of the instance inside of the hash, and,
you can use the `without:` option to exclude one or more attribute keys from the final hash.
```ruby
@@ -589,45 +593,55 @@
### `Micro::Attributes.with`
```ruby
Micro::Attributes.with(:initialize)
-Micro::Attributes.with(initialize: :strict)
+Micro::Attributes.with(:initialize, :keys_as_symbol)
+Micro::Attributes.with(:keys_as_symbol, initialize: :strict)
+
Micro::Attributes.with(:diff, :initialize)
Micro::Attributes.with(:diff, initialize: :strict)
+Micro::Attributes.with(:diff, :keys_as_symbol, initialize: :strict)
+
Micro::Attributes.with(:activemodel_validations)
Micro::Attributes.with(:activemodel_validations, :diff)
Micro::Attributes.with(:activemodel_validations, :diff, initialize: :strict)
+
+Micro::Attributes.with(:activemodel_validations, :diff, :keys_as_symbol, initialize: :strict)
```
The method `Micro::Attributes.with()` will raise an exception if no arguments/features were declared.
```ruby
class Job
- include Micro::Attributes.with() # ArgumentError (Invalid feature name! Available options: :activemodel_validations, :diff, :initialize)
+ include Micro::Attributes.with() # ArgumentError (Invalid feature name! Available options: :activemodel_validations, :diff, :initialize, :keys_as_symbol)
end
```
### `Micro::Attributes.without`
Picking *except* one or more features
```ruby
-Micro::Attributes.without(:diff) # will load :activemodel_validations and initialize: :strict
+Micro::Attributes.without(:diff) # will load :activemodel_validations, :keys_as_symbol and initialize: :strict
-Micro::Attributes.without(initialize: :strict) # will load :activemodel_validations and :diff
+Micro::Attributes.without(initialize: :strict) # will load :activemodel_validations, :diff and :keys_as_symbol
```
## Picking all the features
```ruby
Micro::Attributes.with_all_features
+
+# This method returns the same of:
+
+Micro::Attributes.with(:activemodel_validations, :diff, :keys_as_symbol, initialize: :strict)
```
[⬆️ Back to Top](#table-of-contents-)
## Extensions
@@ -812,9 +826,43 @@
job.id # 1
job.state # 'sleeping'
```
> **Note**: This extension works like the `initialize` extension. So, look at its section to understand all of the other features.
+
+[⬆️ Back to Top](#table-of-contents-)
+
+### Keys as symbol extension
+
+Disables the indifferent access requiring the declaration/usage of the attributes as symbols.
+
+The advantage of this extension over the default behavior is because it avoids an unnecessary allocation in memory of strings. All the keys are transformed into strings in the indifferent access mode, but, with this extension, this typecasting will be avoided. So, it has a better performance and reduces the usage of memory/Garbage collector, but gives for you the responsibility to always use symbols to set/access the attributes.
+
+```ruby
+class Job
+ include Micro::Attributes.with(:initialize, :keys_as_symbol)
+
+ attribute :id
+ attribute :state, default: 'sleeping'
+end
+
+job = Job.new(id: 1)
+
+job.attributes # {:id => 1, :state => "sleeping"}
+
+job.attribute?(:id) # true
+job.attribute?('id') # false
+
+job.attribute(:id) # 1
+job.attribute('id') # nil
+
+job.attribute!(:id) # 1
+job.attribute!('id') # NameError (undefined attribute `id)
+```
+
+As you could see in the previous example only symbols will work to do something with the attributes.
+
+This extension also changes the `diff extension` making everything (arguments, outputs) working only with symbols.
[⬆️ Back to Top](#table-of-contents-)
# Development