README.md in u-attributes-2.0.1 vs README.md in u-attributes-2.1.0
- old
+ new
@@ -1,23 +1,43 @@
-![Ruby](https://img.shields.io/badge/ruby-2.2+-ruby.svg?colorA=99004d&colorB=cc0066)
-[![Gem](https://img.shields.io/gem/v/u-attributes.svg?style=flat-square)](https://rubygems.org/gems/u-attributes)
-[![Build Status](https://travis-ci.com/serradura/u-attributes.svg?branch=main)](https://travis-ci.com/serradura/u-attributes)
-[![Maintainability](https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/maintainability)](https://codeclimate.com/github/serradura/u-attributes/maintainability)
-[![Test Coverage](https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/test_coverage)](https://codeclimate.com/github/serradura/u-attributes/test_coverage)
+<p align="center">
+ <img src="./assets/u-attributes_logo_v1.png" alt='Create "immutable" objects. No setters, just getters!'>
-μ-attributes (Micro::Attributes) <!-- omit in toc -->
-================================
+ <p align="center"><i>Create "immutable" objects. No setters, just getters!</i></p>
+ <br>
+</p>
+<p align="center">
+ <img src="https://img.shields.io/badge/ruby-2.2+-ruby.svg?colorA=99004d&colorB=cc0066" alt="Ruby">
+
+ <a href="https://rubygems.org/gems/u-attributes">
+ <img alt="Gem" src="https://img.shields.io/gem/v/u-attributes.svg?style=flat-square">
+ </a>
+
+ <a href="https://travis-ci.com/serradura/u-attributes">
+ <img alt="Build Status" src="https://travis-ci.com/serradura/u-attributes.svg?branch=main">
+ </a>
+
+ <a href="https://codeclimate.com/github/serradura/u-attributes/maintainability">
+ <img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/maintainability">
+ </a>
+
+ <a href="https://codeclimate.com/github/serradura/u-attributes/test_coverage">
+ <img alt="Test Coverage" src="https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/test_coverage">
+ </a>
+</p>
+
This gem allows you to define "immutable" objects, and your objects will have only getters and no setters.
So, if you change [[1](#with_attribute)] [[2](#with_attributes)] some object attribute, you will have a new object instance. That is, you transform the object instead of modifying it.
-## Table of contents <!-- omit in toc -->
+# Table of contents <!-- omit in toc -->
- [Installation](#installation)
- [Compatibility](#compatibility)
- [Usage](#usage)
- [How to define attributes?](#how-to-define-attributes)
- [`Micro::Attributes#attributes=`](#microattributesattributes)
+ - [How to extract attributes from an object or hash?](#how-to-extract-attributes-from-an-object-or-hash)
+ - [Is it possible to define an attribute as required?](#is-it-possible-to-define-an-attribute-as-required)
- [`Micro::Attributes#attribute`](#microattributesattribute)
- [`Micro::Attributes#attribute!`](#microattributesattribute-1)
- [How to define multiple attributes?](#how-to-define-multiple-attributes)
- [`Micro::Attributes.with(:initialize)`](#microattributeswithinitialize)
- [`#with_attribute()`](#with_attribute)
@@ -53,24 +73,24 @@
# Compatibility
| u-attributes | branch | ruby | activemodel |
| -------------- | ------- | -------- | ------------- |
-| 2.0.0 | main | >= 2.2.0 | >= 3.2, < 6.1 |
+| 2.1.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-)
# Usage
## How to define attributes?
-```ruby
-# By default you must to define the class constructor.
+By default, you must define the class constructor.
+```ruby
class Person
include Micro::Attributes
attribute :age
attribute :name
@@ -114,10 +134,70 @@
person.age # 20
person.name # John Doe
```
+#### How to extract attributes from an object or hash?
+
+You can extract attributes using the `extract_attributes_from` method, it will try to fetch attributes from the
+object using either the `object[attribute_key]` accessor or the reader method `object.attribute_key`.
+
+```ruby
+class Person
+ include Micro::Attributes
+
+ attribute :age
+ attribute :name, default: 'John Doe'
+
+ def initialize(user:)
+ self.attributes = extract_attributes_from(user)
+ end
+end
+
+# extracting from an object
+
+class User
+ attr_accessor :age, :name
+end
+
+user = User.new
+user.age = 20
+
+person = Person.new(user: user)
+
+person.age # 20
+person.name # John Doe
+
+# extracting from a hash
+
+another_person = Person.new(user: { age: 55, name: 'Julia Not Roberts' })
+
+another_person.age # 55
+another_person.name # Julia Not Roberts
+```
+
+#### Is it possible to define an attribute as required?
+
+You only need to use the `required: true` option.
+
+But to this work, you need to assign the attributes using the [`#attributes=`](#microattributesattributes) method or the extensions: [initialize](#initialize-extension), [activemodel_validations](#activemodelvalidation-extension).
+
+```ruby
+class Person
+ include Micro::Attributes
+
+ attribute :age
+ attribute :name, required: true
+
+ def initialize(attributes)
+ self.attributes = attributes
+ end
+end
+
+Person.new(age: 32) # ArgumentError (missing keyword: :name)
+```
+
[⬆️ Back to Top](#table-of-contents-)
### `Micro::Attributes#attribute`
Use this method with a valid attribute name to get its value.
@@ -183,11 +263,11 @@
```ruby
class Person
include Micro::Attributes.with(:initialize)
- attribute :age
+ attribute :age, required: true
attribute :name, default: 'John Doe'
end
person = Person.new(age: 18)
@@ -256,12 +336,14 @@
[⬆️ Back to Top](#table-of-contents-)
## The strict initializer
-Use `.with(initialize: :strict)` to forbids an instantiation without all the attribute keywords. e.g.
+Use `.with(initialize: :strict)` to forbids an instantiation without all the attribute keywords.
+In other words, it is equivalent to you define all the attributes using the [`required: true` option](#is-it-possible-to-define-an-attribute-as-required).
+
```ruby
class StrictPerson
include Micro::Attributes.with(initialize: :strict)
attribute :age
@@ -366,9 +448,15 @@
Person.attribute?(:foo) # false
# ---
person = Person.new(age: 20)
+
+#---------------------#
+# #defined_attributes #
+#---------------------#
+
+person.defined_attributes # ['name', 'age']
#---------------#
# #attribute?() #
#---------------#