diff --git a/README.md b/README.md index 5ec1699..dff0dc5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ Enumerations for Ruby with some magic powers! 🎩 [![Downloads](https://img.shields.io/gem/dt/enumerate_it.svg)](https://rubygems.org/gems/enumerate_it) [![Changelog](https://img.shields.io/badge/changelog--brightgreen.svg?style=flat)](https://github.com/lucascaton/enumerate_it/releases) -**EnumerateIt** helps you to declare and use enumerations in a very simple and flexible way. +**EnumerateIt** helps you to declare and use enumerations in a very simple and +flexible way. ### Why would I want a gem if Rails already has native enumerations support? @@ -21,18 +22,21 @@ so you can **add behaviour** and also **reuse** them! 😀 +## Table of Contents + - [EnumerateIt](#enumerateit) - - [Why would I want a gem if Rails already has native enumerations support?](#why-would-i-want-a-gem-if-rails-already-has-native-enumerations-support) + - [Why would I want a gem if Rails already has native enumerations support?](#why-would-i-want-a-gem-if-rails-already-has-native-enumerations-support) + - [Table of Contents](#table-of-contents) - [Installation](#installation) - [Using with Rails](#using-with-rails) - [Creating enumerations](#creating-enumerations) - [Sorting enumerations](#sorting-enumerations) - [Using enumerations](#using-enumerations) - [FAQ](#faq) - - [Why define enumerations outside the class that uses them?](#why-define-enumerations-outside-the-class-that-uses-them) - - [Can I use `enumerate_it` gem without Rails?](#can-i-use-enumerate_it-gem-without-rails) - - [What versions of Ruby and Rails are supported?](#what-versions-of-ruby-and-rails-are-supported) - - [Can I set a value to always be at the end of a sorted list?](#can-i-set-a-value-to-always-be-at-the-end-of-a-sorted-list) + - [Why define enumerations outside the class that uses them?](#why-define-enumerations-outside-the-class-that-uses-them) + - [Can I use `enumerate_it` gem without Rails?](#can-i-use-enumerate_it-gem-without-rails) + - [What versions of Ruby and Rails are supported?](#what-versions-of-ruby-and-rails-are-supported) + - [Can I set a value to always be at the end of a sorted list?](#can-i-set-a-value-to-always-be-at-the-end-of-a-sorted-list) - [I18n](#i18n) - [Translate a name-spaced enumeration](#translate-a-name-spaced-enumeration) - [Handling a legacy database](#handling-a-legacy-database) @@ -64,10 +68,11 @@ rails generate enumerate_it:enum --help ## Creating enumerations -Enumerations are created as classes and you should put them inside `app/enumerations` folder. +Enumerations are created as classes and you should put them inside +`app/enumerations` folder. -You can pass an array of symbols, so that the respective value for each symbol will be the -stringified version of the symbol itself: +You can pass an array of symbols, so that the respective value for each symbol +will be the stringified version of the symbol itself: ```ruby class RelationshipStatus < EnumerateIt::Base @@ -81,7 +86,7 @@ end This will create some nice stuff: -* Each enumeration's value will turn into a constant: +- Each enumeration's value will turn into a constant: ```ruby RelationshipStatus::SINGLE @@ -91,68 +96,68 @@ This will create some nice stuff: #=> 'married' ``` -* You can retrieve a list with all the enumeration codes: +- You can retrieve a list with all the enumeration codes: ```ruby RelationshipStatus.list #=> ['divorced', 'married', 'single'] ``` -* You can retrieve a JSON with all the enumeration codes: +- You can retrieve a JSON with all the enumeration codes: ```ruby RelationshipStatus.to_json #=> "[{\"value\":\"divorced\",\"label\":\"Divorced\"},{\"value\":\"married\", ... ``` -* You can get an array of options, ready to use with the `select`, `select_tag`, etc. family of - Rails helpers. +- You can get an array of options, ready to use with the `select`, `select_tag`, + etc. family of Rails helpers. ```ruby RelationshipStatus.to_a #=> [['Divorced', 'divorced'], ['Married', 'married'], ['Single', 'single']] ``` -* You can retrieve a list with values for a group of enumeration constants. +- You can retrieve a list with values for a group of enumeration constants. ```ruby RelationshipStatus.values_for %w(MARRIED SINGLE) #=> ['married', 'single'] ``` -* You can retrieve the value for a specific enumeration constant: +- You can retrieve the value for a specific enumeration constant: ```ruby RelationshipStatus.value_for('MARRIED') #=> 'married' ``` -* You can retrieve the symbol used to declare a specific enumeration value: +- You can retrieve the symbol used to declare a specific enumeration value: ```ruby RelationshipStatus.key_for(RelationshipStatus::MARRIED) #=> :married ``` -* You can iterate over the list of the enumeration's values: +- You can iterate over the list of the enumeration's values: ```ruby RelationshipStatus.each_value { |value| ... } ``` -* You can iterate over the list of the enumeration's translations: +- You can iterate over the list of the enumeration's translations: ```ruby RelationshipStatus.each_translation { |translation| ... } ``` -* You can also retrieve all the translations of the enumeration: +- You can also retrieve all the translations of the enumeration: ```ruby RelationshipStatus.translations ``` -* You can ask for the enumeration's length: +- You can ask for the enumeration's length: ```ruby RelationshipStatus.length @@ -161,11 +166,11 @@ This will create some nice stuff: ### Sorting enumerations -When calling methods like `to_a`, `to_json` and `list`, the returned values will be sorted by -default in the same order passed to `associate_values` call. - -However, if you want to overwrite the default sort mode, you can use the `sort_by` class method: +When calling methods like `to_a`, `to_json` and `list`, the returned values will +be sorted by default in the same order passed to `associate_values` call. +However, if you want to overwrite the default sort mode, you can use the +`sort_by` class method: ```ruby class RelationshipStatus < EnumerateIt::Base @@ -205,14 +210,15 @@ class Person end ``` -> **Note:** **EnumerateIt** will try to load an enumeration class based on the camelized attribute -> name. If you have a different name, you can specify it by using the `with` option: +> **Note:** **EnumerateIt** will try to load an enumeration class based on the +> camelized attribute name. If you have a different name, you can specify it by +> using the `with` option: > > `has_enumeration_for :relationship_status, with: RelationshipStatus` This will create: -* A "humanized" version of the hash's key to humanize the attribute's value: +- A "humanized" version of the hash's key to humanize the attribute's value: ```ruby p = Person.new @@ -221,8 +227,8 @@ This will create: #=> 'Divorced' ``` -* A translation for your options, if you include a locale to represent it - (see more in the [I18n section](#i18n)). +- A translation for your options, if you include a locale to represent it (see + more in the [I18n section](#i18n)). ```ruby p = Person.new @@ -231,14 +237,16 @@ This will create: #=> 'Divorciado' ``` -* The associated enumerations, which can be retrieved with the `enumerations` class method: +- The associated enumerations, which can be retrieved with the `enumerations` + class method: ```ruby Person.enumerations #=> { relationship_status: RelationshipStatus } ``` -* A helper method for each enumeration option, if you pass the `create_helpers` option as `true`: +- A helper method for each enumeration option, if you pass the `create_helpers` + option as `true`: ```ruby class Person < ApplicationRecord @@ -255,8 +263,9 @@ This will create: #=> false ``` - It's also possible to "namespace" the created helper methods, passing a hash to the `create_helpers` - option. This can be useful when two or more of the enumerations used share the same constants: + It's also possible to "namespace" the created helper methods, passing a hash + to the `create_helpers` option. This can be useful when two or more of the + enumerations used share the same constants: ```ruby class Person < ApplicationRecord @@ -274,8 +283,8 @@ This will create: #=> false ``` - You can define polymorphic behavior for the enumeration values, so you can define a class for each - of them: + You can define polymorphic behavior for the enumeration values, so you can + define a class for each of them: ```ruby class RelationshipStatus < EnumerateIt::Base @@ -320,8 +329,8 @@ This will create: p.relationship_status_mode.saturday_night ``` - The `create_helpers` also creates some mutator helper methods, that can be used to change the - attribute's value. + The `create_helpers` also creates some mutator helper methods, that can be + used to change the attribute's value. ```ruby p = Person.new @@ -331,7 +340,8 @@ This will create: #=> true ``` -* A scope method for each enumeration option if you pass the `create_scopes` option as `true`: +- A scope method for each enumeration option if you pass the `create_scopes` + option as `true`: ```ruby class Person < ApplicationRecord @@ -353,7 +363,7 @@ This will create: Person.relationship_status_married.to_sql ``` -* An inclusion validation (if your class can manage validations and responds to +- An inclusion validation (if your class can manage validations and responds to `validates_inclusion_of`): ```ruby @@ -368,7 +378,7 @@ This will create: #=> 'is not included in the list' ``` -* A presence validation (if your class can manage validations and responds to +- A presence validation (if your class can manage validations and responds to `validates_presence_of` and you pass the `required` options as `true`): ```ruby @@ -383,7 +393,8 @@ This will create: #=> "can't be blank" ``` - If you pass the `skip_validation` option as `true`, it will not create any validations: + If you pass the `skip_validation` option as `true`, it will not create any + validations: ```ruby class Person < ApplicationRecord @@ -395,15 +406,16 @@ This will create: #=> true ``` -Remember that you can add validations to any kind of class and not only `ActiveRecord` ones. +Remember that you can add validations to any kind of class and not only +`ActiveRecord` ones. ## FAQ #### Why define enumerations outside the class that uses them? -* It's clearer. -* You can add behaviour to the enumeration class. -* You can reuse the enumeration inside other classes. +- It's clearer. +- You can add behaviour to the enumeration class. +- You can reuse the enumeration inside other classes. #### Can I use `enumerate_it` gem without Rails? @@ -411,20 +423,22 @@ You sure can! 😄 #### What versions of Ruby and Rails are supported? -* **Ruby**: `3.0+` -* **Rails** `6.0+` +- **Ruby**: `3.0+` +- **Rails** `6.0+` All versions are tested via [GitHub Actions](https://github.com/lucascaton/enumerate_it/blob/HEAD/.github/workflows/ci.yml). #### Can I set a value to always be at the end of a sorted list? -Yes, [see more details here](https://github.com/lucascaton/enumerate_it/issues/60). +Yes, +[see more details here](https://github.com/lucascaton/enumerate_it/issues/60). ## I18n -I18n lookup is provided on both `_humanized` and `Enumeration#to_a` methods, given the hash key is -a Symbol. The I18n strings are located on `enumerations..`: +I18n lookup is provided on both `_humanized` and `Enumeration#to_a` methods, +given the hash key is a Symbol. The I18n strings are located on +`enumerations..`: ```yaml # Your locale file @@ -462,22 +476,22 @@ RelationshipStatus.t(status) ### Translate a name-spaced enumeration -In order to translate an enumeration in a specific namespace (say `Design::Color`), -you can add the following: +In order to translate an enumeration in a specific namespace (say +`Design::Color`), you can add the following: ```yaml pt-BR: enumerations: - 'design/color': + "design/color": blue: Azul red: Vermelho ``` ## Handling a legacy database -**EnumerateIt** can help you build a Rails application around a legacy database which was filled -with those small and unchangeable tables used to create foreign key constraints everywhere, like the -following example: +**EnumerateIt** can help you build a Rails application around a legacy database +which was filled with those small and unchangeable tables used to create foreign +key constraints everywhere, like the following example: ```sql Table "public.relationship_status" @@ -499,14 +513,16 @@ code | description 3 | Divorced ``` -You might also have something like a `users` table with a `relationship_status` column and a foreign -key pointing to the `relationship_status` table. +You might also have something like a `users` table with a `relationship_status` +column and a foreign key pointing to the `relationship_status` table. -While this is a good thing from the database normalization perspective, managing these values in -tests is very hard. Doing database joins just to get the description of some value is absurd. -And, more than this, referencing them in the code using -[magic numbers](https://en.wikipedia.org/wiki/Magic_number_(programming)) was terrible and -meaningless: what does it mean when we say that someone or something is `2`? +While this is a good thing from the database normalization perspective, managing +these values in tests is very hard. Doing database joins just to get the +description of some value is absurd. And, more than this, referencing them in +the code using +[magic numbers]() was +terrible and meaningless: what does it mean when we say that someone or +something is `2`? To solve this, you can pass a **hash** to your enumeration values: @@ -534,14 +550,18 @@ you can see them on the [releases page](../../releases). ## Note on Patches/Pull Requests -* Fork the project. -* Make your feature addition or bug fix. -* Add tests for it. This is important so we don't break it in a future version unintentionally. -* [Optional] Run the tests against a specific Gemfile: `$ bundle exec appraisal rails_7.0 rake spec`. -* Run the tests against all supported versions: `$ bundle exec rake` (or `$ bundle exec wwtd`) -* Commit, but please do not mess with `Rakefile`, version, or history. -* Send a Pull Request. Bonus points for topic branches. +- Fork the project. +- Make your feature addition or bug fix. +- Add tests for it. This is important so we don't break it in a future version + unintentionally. +- [Optional] Run the tests against a specific Gemfile: + `$ bundle exec appraisal rails_7.0 rake spec`. +- Run the tests against all supported versions: `$ bundle exec rake` (or + `$ bundle exec wwtd`) +- Commit, but please do not mess with `Rakefile`, version, or history. +- Send a Pull Request. Bonus points for topic branches. ## Copyright -Copyright (c) 2010-2024 Cássio Marques and Lucas Caton. See `LICENSE` file for details. +Copyright (c) 2010-2024 Cássio Marques and Lucas Caton. See `LICENSE` file for +details.