pax_global_header00006660000000000000000000000064143220776210014516gustar00rootroot0000000000000052 comment=1027184f7bc8b8fa5c8ac9990a1dcc36361b7cd7 ruby-enumerize-2.5.0/000077500000000000000000000000001432207762100145045ustar00rootroot00000000000000ruby-enumerize-2.5.0/.github/000077500000000000000000000000001432207762100160445ustar00rootroot00000000000000ruby-enumerize-2.5.0/.github/workflows/000077500000000000000000000000001432207762100201015ustar00rootroot00000000000000ruby-enumerize-2.5.0/.github/workflows/ruby.yml000066400000000000000000000036401432207762100216100ustar00rootroot00000000000000name: Ruby on: push: branches: [ master ] pull_request: branches: [ master ] jobs: test: runs-on: ubuntu-20.04 services: mongodb: image: mongo:latest ports: - 27017:27017 postgres: image: postgres:12 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres ports: - 5432:5432 options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 mysql: image: mysql:5.6 env: MYSQL_ROOT_PASSWORD: mysql ports: - 3306:3306 options: --health-cmd "mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 10 strategy: fail-fast: false matrix: ruby-version: ['2.6', '2.7', '3.0.2'] gemfile: - Gemfile - Gemfile.rails60 - Gemfile.rails61 - Gemfile.rails70 - Gemfile.railsmaster - Gemfile.mongo_mapper db: - sqlite3 - postgresql - mysql2 exclude: - gemfile: Gemfile.mongo_mapper db: postgresql - ruby-version: '3.0.2' gemfile: Gemfile - ruby-version: '3.0.2' gemfile: Gemfile.mongo_mapper - ruby-version: '2.6' gemfile: Gemfile.rails70 - ruby-version: '2.6' gemfile: Gemfile.railsmaster env: BUNDLE_GEMFILE: "${{ matrix.gemfile }}" DB: "${{ matrix.db }}" steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Run tests run: bundle exec rake env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres MYSQL_ROOT_PASSWORD: mysql ruby-enumerize-2.5.0/.gitignore000066400000000000000000000003521432207762100164740ustar00rootroot00000000000000*.gem *.rbc .bundle .config .ruby-version .yardoc .idea/ enumerize.iml Gemfile*.lock gemfiles/Gemfile-*.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man log/* pkg rdoc spec/reports test/tmp test/version_tmp tmp vendor/bundle ruby-enumerize-2.5.0/.rspec000066400000000000000000000000361432207762100156200ustar00rootroot00000000000000--color --require spec_helper ruby-enumerize-2.5.0/CHANGELOG.md000066400000000000000000000326321432207762100163230ustar00rootroot00000000000000## 2.5.0 (December 24, 2021) ### enhancements * Add support for Rails 7.0.0.alpha. (by [@f-mer](https://github.com/f-mer)) * Add support for negative shallow scopes. (by [@nashby](https://github.com/nashby)) ## 2.4.0 (December 12, 2020) ### enhancements * Show warning when enumerized value name conflicts with existing object's methods. (by [@aki77](https://github.com/aki77)) * Add RSpec support for shallow scopes. (by [@nashby](https://github.com/nashby)) * Drop support for Ruby older than 2.5. Support only Ruby 2.5+. (by [@nashby](https://github.com/nashby)) * Drop support for Rails 4. Support only Rails 5.2+. (by [@nashby](https://github.com/nashby)) * Add support for Rails 6.1 (by [@y-yagi](https://github.com/y-yagi)) ### bug fix * Fix exception when using predicate methods on enumerized value transformed into invalid value. (by [@guigs](https://github.com/guigs)) * Fix issue with RSpec#with_predicates matcher when custom values are used as attribute. (by [@nashby](https://github.com/nashby)) ## 2.3.1 (May 2, 2019) ### enhancements * Add ability to skip validations by passing `:skip_validations` option. (by [@chumakoff](https://github.com/chumakoff)) * Add option `scope: shallow` to extend scopes based on enumerized attribute values (by [@moofkit](https://github.com/moofkit/)) ### bug fix * Fix issue with ActiveRecord and Mongoid `reload` method when enumberized attributes weren't synced from DB. (by [@nashby](https://github.com/nashby) and [@FunkyloverOne](https://github.com/FunkyloverOne)) * Fix issue with ActiveRecord `reload` method not working for ActiveRecord::Store attributes due to `1b776c`. (by [@rickcsong](https://github.com/rickcsong)) ## 2.2.2 (March 6, 2018) ### bug fix * Support non-ActiveModel objects in SimpleForm/Formtastic integration. (by [@nashby](https://github.com/nashby)) ## 2.2.1 (February 15, 2018) ### bug fix * Fix issue with SimpleForm/Formtastic forms without object. (by [@nashby](https://github.com/nashby)) ## 2.2.0 (February 13, 2018) ### enhancements * Add integration with active_interaction. (by [@runephilosof](https://github.com/runephilosof)) * Allow using `plugin :enumerize` with Sequel. (by [@jnylen](https://github.com/jnylen)) * Support ActiveModel::Attributes from Rails 5.2. (by [@troter](https://github.com/troter)) * Support Sequel 5.2.0. (by [@troter](https://github.com/troter)) ### bug fix * Fix RailsAdmin integration when enumerated field used on edit form and enumerated value wasn't set. (by [@nashby](https://github.com/nashby)) * Fallback to a raw passed value instead of nil if AR type can't find value in the attribute. (by [@nashby](https://github.com/nashby)) ## 2.1.2 (May 18, 2017) ### bug fix * Support YAML serialization for the custom AR type. (by [@lest](https://github.com/lest)) ## 2.1.1 (May 1, 2017) ### enhancements * Run tests with multiple DBs (SQLite and PostgreSQL). (by [tkawa](https://github.com/tkawa)) ### bug fix * Support deserialize and Rails 4.2 methods in the custom AR::Type class. (by [@lest](https://github.com/lest)) * Support dumping custom AR type to JSON. (by [@lest](https://github.com/lest)) ## 2.1.0 (March 31, 2017) ### enhancements * Support Active Record types serialization. (by [@lest](https://github.com/lest)) ## 2.0.1 (October 18, 2016) ### bug fix * Support enumerized attributes in #update_all on relation objects. (by [@lest](https://github.com/lest)) ## 2.0.0 (August 10, 2016) ### enhancements * Drop support for Ruby older than 2.2. Support only Ruby 2.2+. (by [@nashby](https://github.com/nashby)) * Drop support for Rails 4.0 and 4.1. Support only Rails 4.2 and newer. (by [@lest](https://github.com/lest)) * Support Rails 5.0. (by [@nashby](https://github.com/nashby) and [@lest](https://github.com/lest)) * Allow to pass enumerize values to `ActiveRecord#update_all` (by [@DmitryTsepelev](https://github.com/DmitryTsepelev) and [@ianwhite](https://github.com/ianwhite)) ```ruby User.update_all(status: :blocked) ``` ### bug fix * Rescue MissingAttributeError on attribute writing. (by [@embs](https://github.com/embs)) * Fix presence validation for multiple attributes when the list contains a blank string. (by [@smoriwaki](https://github.com/smoriwaki)) * Replace deprecated alias_method_chain with Module#prepend. (by [@koenpunt](https://github.com/koenpunt) and [@akm](https://github.com/akm)) * Make it compatible with `globalize` gem. (by [@falm](https://github.com/falm)) * Prevent method getter from being called when no default_value is being set. (by [@arjan0307](https://github.com/arjan0307)) ## 1.1.1 (January 25, 2016) ### bug fix * Fix exception when using predicate methods and enumerized values have dash in it. (by [@nashby](https://github.com/nashby)) ## 1.1.0 (November 15, 2015) ### enhancements * Add Sequel support. (by [@mrbrdo](https://github.com/mrbrdo)) * Add qualifiers to RSpec matcher. (by [@maurogeorge](https://github.com/maurogeorge)) * Support hash in the RSpec matcher. (by [@maurogeorge](https://github.com/maurogeorge)) ### bug fix ## 1.0.0 (August 2, 2015) ### enhancements * Add `texts` method for getting an array of text values of the enumerized field with multiple type. (by [@huynhquancam](https://github.com/huynhquancam)) * Drop Rails 3.2 support. (by [@nashby](https://github.com/nashby)) ### bug fix * Fix conflicts when Active Record and Mongoid are used at the same time. (by [@matsu911](https://github.com/matsu911)) ## 0.11.0 (March 29, 2015) ## ### enhancements * Add ability to set default value for enumerized field with multiple type. (by [@nashby](https://github.com/nashby)) * Support Rails 4.2. (by [@lest](https://github.com/lest)) ### bug fix * Use Mongoid's `:in` method for generated scopes, fix chained scopes. (by [@nashby](https://github.com/nashby)) * Use `after_initialize` callback to set default value in Mongoid documents. (by [@nashby](https://github.com/nashby)) ## 0.10.1 (March 4, 2015) ## ### bug fix * Use method_missing instead of defining singleton class methods to allow Marshal serialization (by [@lest](https://github.com/lest)) ## 0.10.0 (February 17, 2015) ## ### enhancements * Add scopes support to mongoid documents (by [@nashby](https://github.com/nashby)) * Use underscore.humanize in #text to make use of Inflector acronyms (by [@mintuhouse](https://github.com/mintuhouse)) * Raise an exception when :scope option is used together with :multiple option (by [@maurogeorge](https://github.com/maurogeorge)) * Use alias_method_chain instead of overriding Class#inherited (by [@yuroyoro](https://github.com/yuroyoro)) * Shortcut methods to retrieve enumerize values (by [@CyborgMaster](https://github.com/CyborgMaster)) * Extend equality operator to support comparing with symbols and custom values (e.g. integers) (by [@CyborgMaster](https://github.com/CyborgMaster)) ## 0.9.0 (December 11, 2014) ## ### enhancements * Add :value_class option (by [@lest](https://github.com/lest)) * Use 'defaults' scope in the localization file for the attributes that used across several models. This will help to avoid conflicting keys with model names and attribute names. Example: ```yml en: enumerize: defaults: sex: male: Male female: Female ``` You still can use the old solution without "default" scope: ```yml en: enumerize: sex: male: Male female: Female ``` (by [@nashby](https://github.com/nashby)) ### bug fix * Store values for validation using string keys (by [@nagyt234](https://github.com/nagyt234)) * Store custom values for multiple attributes (by [@lest](https://github.com/lest)) * Support validations after using AR#becomes (by [@lest](https://github.com/lest)) * Do not try to set attribute for not selected attributes (by [@dany1468](https://github.com/dany1468)) ## 0.8.0 (March 4, 2014) ## ### enhancements * Integration with SimpleForm's `input_field` (by [@nashby](https://github.com/nashby)) * Support multiple attributes in Active Record #becomes method (by [@lest](https://github.com/lest)) * Add ability to specify localization scope with `i18n_scope` option (by [@dreamfall](https://github.com/dreamfall)) ### bug fix * Fix Rails Admin integration when custom values are used (by [@brenes](https://github.com/brenes)) * Fix RSpec integration using enumerize with Spring (by [@winston](https://github.com/winston)) * Return proper RSpec failure message for enumerized attribute with default value (by [@nashby](https://github.com/nashby)) * Return proper RSpec description for enumerized attribute without default value (by [@andreygerasimchuk](https://github.com/andreygerasimchuk)) * Do not try to set default value for not selected attributes (by [@nashby](https://github.com/nashby)) * Fix uniqueness validation with Active Record (by [@lest](https://github.com/lest)) * Fix loading of attributes with multiple: true in mongoid (by [glebtv](https://github.com/glebtv)) * Serialize value as scalar type (by [@ka8725](https://github.com/ka8725)) ## 0.7.0 (August 21, 2013) ## ### enhancements * Give priority to model specific translation definition. See example [here](https://github.com/brainspec/enumerize/pull/96) (by [@labocho](https://github.com/labocho)) * Allow lambda in default value (by [@adie](https://github.com/adie)) * Add predicate methods to the multiple attributes (by [@nashby](https://github.com/nashby)) * Add RSpec matcher (by [@nashby](https://github.com/nashby)) * Add `*_value` method that returns actual value of the enumerized attribute (useful for attributes with custom values) (by [@tkyowa](https://github.com/tkyowa)) ### bug fix * Make validation work when `write_attribute` is using for setting enumerized values (by [@nashby](https://github.com/nashby)) * Validates enumerized values when enumeration is included via module (by [@nashby](https://github.com/nashby)) and (by [@lest](https://github.com/lest)) ## 0.6.1 (May 20, 2013) ## ### bug fix * Don't raise error when enumerized attribute is already defined. (by [@lest](https://github.com/lest)) ## 0.6.0 (May 16, 2013) ## ### enhancements * Use inclusion error message for invalid values (by [@lest](https://github.com/lest)) * Add `:only` and `except` options to the `Attribute#options` method. (by [@thehappycoder](https://github.com/thehappycoder) and [@randoum](https://github.com/randoum)) * ActiveRecord scopes. (by [@lest](https://github.com/lest), [@banyan](https://github.com/banyan) and [@nashby](https://github.com/nashby)) * Support for RailsAdmin (by [@drewda](https://github.com/drewda)) ### bug fix * Return correct default value for enumerized attribute using `default_scope` with generated scope [@nashby](https://github.com/nashby) * Allow either key or value as valid (by [aghull](https://github.com/aghull) and [@lest](https://github.com/lest)) * Use default enum value from db column (by [@lest](https://github.com/lest)) ## 0.5.1 (December 10, 2012) ## ### bug fix * Always return Enumerize::Set for multiple attributes (by [@nashby](https://github.com/nashby)) ## 0.5.0 (October 31, 2012) ## The previous method of adding enumerize to a class was deprecated. Please use `extend Enumerize` instead of `include Enumerize`. ### enhancements * SimpleForm support for multiple attributes. (by [@nashby](https://github.com/nashby)) * Formtastic support for multiple attributes. (by [@nashby](https://github.com/nashby)) * Array-like multiple attributes. (by [@lest](https://github.com/lest)) ## 0.4.0 (September 6, 2012) ## Legacy support was dropped. The following versions are supported: * Ruby 1.9.3+ (including JRuby and Rubinius) * Rails 3.2+ * Formtastic 2.2+ * SimpleForm 2+ * Mongoid 3+ ### enhancements * Ability to define predicate methods on enumerized object. (by [@lest](https://github.com/lest)) ## 0.3.0 (July 9, 2012) ## ### enhancements * Accept a values hash to store an attribute using custom values (e.g. integers) (by [@lest](https://github.com/lest)) ## 0.2.2 (May 22, 2012) ## ### bug fix * Correctly assign default value to handle mass assignment in Active Record (by [@lest](https://github.com/lest)) ## 0.2.1 (May 21, 2012) ## ### bug fix * Call super in attribute accessors if available (by [@lest](https://github.com/lest)) ## 0.2.0 (March 29, 2012) ## ### enhancements * Ability to enumerize attributes in a module and then include it into classes (by [@lest](https://github.com/lest)) * Add error to a model when attribute value is not included in allowed list (by [@lest](https://github.com/lest)) ### bug fix * Inheriting enumerized attributes (by [@cgunther](https://github.com/cgunther) and [@nashby](https://github.com/nashby)) * Don't cast nil to string (by [@jimryan](https://github.com/jimryan)) ## 0.1.1 (March 6, 2012) ## ### bug fix * I18n regression: Multiple calls to value #text return different results (by [@cgunther](https://github.com/cgunther) and [@lest](https://github.com/lest)) ## 0.1.0 (March 5, 2012) ## ### enhancements * Return humanized value if there are no translations (by [@nashby](https://github.com/nashby)) * Integration with SimpleForm (by [@nashby](https://github.com/nashby)) * Integration with Formtastic (by [@lest](https://github.com/lest)) ## 0.0.4 (February 8, 2012) ## ### bug fix * Make attribute accessors to work with ActiveRecord 3.1.x (by [@lest](https://github.com/lest)) ## 0.0.3 (February 8, 2012) ## ### enhancements * Mongoid support (by [@lest](https://github.com/lest)) * Boolean methods (by [@Dreamfa11](https://github.com/Dreamfa11)) ruby-enumerize-2.5.0/Gemfile000066400000000000000000000002621432207762100157770ustar00rootroot00000000000000eval_gemfile('Gemfile.global') gem 'minitest', '~> 5.8' gem 'rails', '~> 5.2.4', require: false gem 'mongoid' gem 'sqlite3', '~> 1.3.6', :platform => [:ruby, :mswin, :mingw] ruby-enumerize-2.5.0/Gemfile.global000066400000000000000000000003131432207762100172330ustar00rootroot00000000000000source 'https://rubygems.org' gemspec gem 'rake' gem 'rspec', :require => false gem 'pg', '~> 1.2.3', :platform => [:ruby, :mswin, :mingw] gem 'sequel' gem 'simple_form' gem 'formtastic' gem 'mysql2' ruby-enumerize-2.5.0/Gemfile.mongo_mapper000066400000000000000000000002721432207762100204620ustar00rootroot00000000000000eval_gemfile('Gemfile.global') gem 'minitest', '~> 5.8' gem 'rails', '~> 5.2.4', :require => false gem 'mongo_mapper' gem 'sqlite3', '~> 1.3.6', :platform => [:ruby, :mswin, :mingw] ruby-enumerize-2.5.0/Gemfile.rails60000066400000000000000000000003021432207762100172510ustar00rootroot00000000000000eval_gemfile('Gemfile.global') gem 'minitest', '~> 5.8' gem 'rails', '~> 6.0.0', require: false gem 'mongoid', github: 'mongodb/mongoid' gem 'sqlite3', :platform => [:ruby, :mswin, :mingw] ruby-enumerize-2.5.0/Gemfile.rails61000066400000000000000000000003431432207762100172570ustar00rootroot00000000000000eval_gemfile('Gemfile.global') gem 'minitest', '~> 5.8' gem 'rails', github: 'rails/rails', branch: '6-1-stable', require: false gem 'mongoid', github: 'mongodb/mongoid' gem 'sqlite3', :platform => [:ruby, :mswin, :mingw] ruby-enumerize-2.5.0/Gemfile.rails70000066400000000000000000000005331432207762100172600ustar00rootroot00000000000000eval_gemfile('Gemfile.global') gem 'minitest', '~> 5.8' gem 'rails', github: 'rails/rails', branch: '7-0-stable', require: false # TODO: Mongoid doesn't support Rails 7 yet. Uncomment when it's fixed https://jira.mongodb.org/browse/MONGOID-5193 # gem 'mongoid', github: 'mongodb/mongoid' gem 'sqlite3', :platform => [:ruby, :mswin, :mingw] ruby-enumerize-2.5.0/Gemfile.railsmaster000066400000000000000000000002631432207762100203250ustar00rootroot00000000000000eval_gemfile('Gemfile.global') gem 'minitest', '~> 5.8' gem 'rails', github: 'rails/rails', branch: 'main', require: false gem 'sqlite3', :platform => [:ruby, :mswin, :mingw] ruby-enumerize-2.5.0/MIT-LICENSE000066400000000000000000000020521432207762100161370ustar00rootroot00000000000000Copyright (c) 2012 Brainspec MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-enumerize-2.5.0/README.md000066400000000000000000000312701432207762100157660ustar00rootroot00000000000000# Enumerize [![TravisCI](https://secure.travis-ci.org/brainspec/enumerize.svg?branch=master)](http://travis-ci.org/brainspec/enumerize) Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper/Sequel support ## Table of Contents - [Installation](#installation) - [Supported Versions](#supported-versions) - [Usage](#usage) - [Database support](#database-support) - [ActiveRecord](#activerecord) - [Mongoid](#mongoid) - [MongoMapper](#mongomapper) - [I18n Support](#i18n-support) - [I18n Helper Methods](#i18n-helper-methods) - [Boolean Helper Methods](#boolean-helper-methods) - [Basic](#basic) - [Predicate Methods](#predicate-methods) - [Optimzations and Tips](#optimzations-and-tips) - [Extendable Module](#extendable-module) - [Customizing Enumerize Value](#customizing-enumerize-value) - [ActiveRecord scopes](#activerecord-scopes) - [Array-like Attributes](#array-like-attributes) - [Forms](#forms) - [SimpleForm](#simpleform) - [Formtastic](#formtastic) - [Testing](#testing) - [RSpec](#rspec) - [Minitest with Shoulda](#minitest-with-shoulda) - [Other Integrations](#other-integrations) - [Contributing](#contributing) ## Installation Add this line to your application's Gemfile: gem 'enumerize' And then execute: $ bundle Or install it yourself as: $ gem install enumerize ## Supported Versions - Ruby 2.6+ - Rails 5.2+ ## Usage Basic: ```ruby class User extend Enumerize enumerize :role, in: [:user, :admin] end ``` Note that enumerized values are just identificators so if you want to use multi-word, etc. values then you should use `I18n` feature. --- ## Database support ### ActiveRecord ```ruby class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :status t.string :role t.timestamps end end end class User < ActiveRecord::Base extend Enumerize enumerize :status, in: [:student, :employed, :retired], default: lambda { |user| StatusIdentifier.status_for_age(user.age).to_sym } enumerize :role, in: [:user, :admin], default: :user end ``` :warning: By default, `enumerize` adds `inclusion` validation to the model. You can skip validations by passing `skip_validations` option. :warning: ```ruby class User < ActiveRecord::Base extend Enumerize enumerize :status, in: [:student, :employed, :retired], skip_validations: lambda { |user| user.new_record? } enumerize :role, in: [:user, :admin], skip_validations: true end ``` ### Mongoid ```ruby class User include Mongoid::Document extend Enumerize field :role enumerize :role, in: [:user, :admin], default: :user end ``` ### MongoMapper ```ruby class User include MongoMapper::Document extend Enumerize key :role enumerize :role, in: [:user, :admin], default: :user end ``` --- ## I18n Support ```ruby en: enumerize: user: status: student: "Student" employed: "Employed" retired: "Retiree" ``` or if you use `status` attribute across several models you can use `defaults` scope: ```ruby en: enumerize: defaults: status: student: "Student" employed: "Employed" retired: "Retiree" ``` You can also pass `i18n_scope` option to specify scope (or array of scopes) storing the translations. ```ruby class Person extend Enumerize extend ActiveModel::Naming enumerize :status, in: %w[student employed retired], i18n_scope: "status" enumerize :roles, in: %w[user admin], i18n_scope: ["user.roles", "roles"] end # localization file en: status: student: "Student" employed: "Employed" retired: "Retiree" user: roles: user: "User" roles: admin: "Admin" ``` Note that if you want to use I18n feature with plain Ruby object don't forget to extend it with `ActiveModel::Naming`: ```ruby class User extend Enumerize extend ActiveModel::Naming end ``` ### I18n Helper Methods #### \*\_text / .text Attribute's I18n text value: ```ruby @user.status_text # or @user.status.text ``` #### values List of possible values for an enumerized attribute: ```ruby User.status.values # or User.enumerized_attributes[:status].values # => ['student', 'employed', 'retired'] ``` #### I18n text values List of possible I18n text values for an enumerized attribute: ```ruby User.status.values.collect(&:text) # => ['Student', 'Employed', 'Retiree'] ``` #### Form example Use it with forms (it supports `:only` and `:except` options): ```erb <%= form_for @user do |f| %> <%= f.select :status, User.status.options %> <% end %> ``` --- ## Boolean Helper Methods ### Basic ```ruby user.status = :student user.status.student? #=> true user.status.retired? #=> false ``` ### Predicate Methods ```ruby class User extend Enumerize enumerize :status, in: %w(student employed retired), predicates: true end user = User.new user.student? # => false user.employed? # => false user.status = :student user.student? # => true user.employed? # => false ``` :warning: If `enumerize` is used with Mongoid, it's not recommended to use `"writer"` as a field value since `writer?` is defined by Mongoid. [See more](https://github.com/brainspec/enumerize/issues/235). :warning: #### Predicate Prefixes ```ruby class User extend Enumerize enumerize :status, in: %w(student employed retired), predicates: { prefix: true } end user = User.new user.status = 'student' user.status_student? # => true ``` Use `:only` and `:except` options to specify what values create predicate methods for. --- ## Optimzations and Tips ### Extendable Module To make some attributes shared across different classes it's possible to define them in a separate module and then include it into classes: ```ruby module RoleEnumerations extend Enumerize enumerize :roles, in: %w[user admin] end class Buyer include RoleEnumerations end class Seller include RoleEnumerations end ``` ### Customizing Enumerize Value It's also possible to store enumerized attribute value using custom values (e.g. integers). You can pass a hash as `:in` option to achieve this: ```ruby class User < ActiveRecord::Base extend Enumerize enumerize :role, in: {:user => 1, :admin => 2} end user = User.new user.role = :user user.role #=> 'user' user.role_value #=> 1 User.role.find_value(:user).value #=> 1 User.role.find_value(:admin).value #=> 2 ``` ### ActiveRecord scopes: #### Basic ```ruby class User < ActiveRecord::Base extend Enumerize enumerize :role, :in => [:user, :admin], scope: true enumerize :status, :in => { student: 1, employed: 2, retired: 3 }, scope: :having_status end User.with_role(:admin) # SELECT "users".* FROM "users" WHERE "users"."role" IN ('admin') User.without_role(:admin) # SELECT "users".* FROM "users" WHERE "users"."role" NOT IN ('admin') User.having_status(:employed).with_role(:user, :admin) # SELECT "users".* FROM "users" WHERE "users"."status" IN (2) AND "users"."role" IN ('user', 'admin') ``` #### Shallow Scopes Adds named scopes to the class directly. ```ruby class User < ActiveRecord::Base extend Enumerize enumerize :status, :in => [:student, :employed, :retired], scope: :shallow enumerize :role, :in => { user: 1, admin: 2 }, scope: :shallow end User.student # SELECT "users".* FROM "users" WHERE "users"."status" = 'student' User.admin # SELECT "users".* FROM "users" WHERE "users"."role" = 2 ``` :warning: It is not possible to define a scope when using the `:multiple` option. :warning: ### Array-like Attributes Array-like attributes with plain ruby objects: ```ruby class User extend Enumerize enumerize :interests, in: [:music, :sports], multiple: true end user = User.new user.interests << :music user.interests << :sports ``` and with ActiveRecord: ```ruby class User < ActiveRecord::Base extend Enumerize serialize :interests, Array enumerize :interests, in: [:music, :sports], multiple: true end ``` get an array of all text values: ```ruby @user.interests.texts # shortcut for @user.interests.map(&:text) ``` Also, the reader method can be overridden, referencing the enumerized attribute value using `super`: ```ruby def status if current_user.admin? "Super #{super}" else super end end ``` --- ## Forms ### SimpleForm If you are using SimpleForm gem you don't need to specify input type (`:select` by default) and collection: ```erb <%= simple_form_for @user do |f| %> <%= f.input :status %> <% end %> ``` and if you want it as radio buttons: ```erb <%= simple_form_for @user do |f| %> <%= f.input :status, :as => :radio_buttons %> <% end %> ``` Please note that Enumerize overwrites the I18n keys of SimpleForm collections. The enumerized keys are used instead of the SimpleForm ones for inputs concerning enumerized attributes. If you don't want this just pass `:collection` option to the `input` call. ### Formtastic If you are using Formtastic gem you also don't need to specify input type (`:select` by default) and collection: ```erb <%= semantic_form_for @user do |f| %> <%= f.input :status %> <% end %> ``` and if you want it as radio buttons: ```erb <%= semantic_form_for @user do |f| %> <%= f.input :status, :as => :radio %> <% end %> ``` --- ## Testing ### RSpec Also you can use builtin RSpec matcher: ```ruby class User extend Enumerize enumerize :status, in: [:student, :employed, :retired] end describe User do it { should enumerize(:status) } # or with RSpec 3 expect syntax it { is_expected.to enumerize(:status) } end ``` #### Qualifiers ##### in Use `in` to test usage of the `:in` option. ```ruby class User extend Enumerize enumerize :status, in: [:student, :employed, :retired] end describe User do it { should enumerize(:status).in(:student, :employed, :retired) } end ``` You can test enumerized attribute value using custom values with the `in` qualifier. ```ruby class User extend Enumerize enumerize :role, in: { user: 0, admin: 1 } end describe User do it { should enumerize(:role).in(user: 0, admin: 1) } end ``` ##### with_default Use `with_default` to test usage of the `:default` option. ```ruby class User extend Enumerize enumerize :role, in: [:user, :admin], default: :user end describe User do it { should enumerize(:user).in(:user, :admin).with_default(:user) } end ``` ##### with_i18n_scope Use `with_i18n_scope` to test usage of the `:i18n_scope` option. ```ruby class User extend Enumerize enumerize :status, in: [:student, :employed, :retired], i18n_scope: 'status' end describe User do it { should enumerize(:status).in(:student, :employed, :retired).with_i18n_scope('status') } end ``` ##### with_predicates Use `with_predicates` to test usage of the `:predicates` option. ```ruby class User extend Enumerize enumerize :status, in: [:student, :employed, :retired], predicates: true end describe User do it { should enumerize(:status).in(:student, :employed, :retired).with_predicates(true) } end ``` You can text prefixed predicates with the `with_predicates` qualifiers. ```ruby class User extend Enumerize enumerize :status, in: [:student, :employed, :retired], predicates: { prefix: true } end describe User do it { should enumerize(:status).in(:student, :employed, :retired).with_predicates(prefix: true) } end ``` ##### with_scope Use `with_scope` to test usage of the `:scope` option. ```ruby class User extend Enumerize enumerize :status, in: [:student, :employed, :retired], scope: true end describe User do it { should enumerize(:status).in(:student, :employed, :retired).with_scope(true) } end ``` You can test a custom scope with the `with_scope` qualifiers. ```ruby class User extend Enumerize enumerize :status, in: [:student, :employed], scope: :employable end describe User do it { should enumerize(:status).in(:student, :employed, :retired).with_scope(scope: :employable) } end ``` ##### with_multiple Use `with_multiple` to test usage of the `:multiple` option. ```ruby class User extend Enumerize enumerize :status, in: [:student, :employed, :retired], multiple: true end describe User do it { should enumerize(:status).in(:student, :employed, :retired).with_multiple(true) } end ``` ### Minitest with Shoulda You can use the RSpec matcher with shoulda in your tests by adding two lines in your `test_helper.rb` inside `class ActiveSupport::TestCase` definition: ```ruby class ActiveSupport::TestCase ActiveRecord::Migration.check_pending! require 'enumerize/integrations/rspec' extend Enumerize::Integrations::RSpec ... end ``` ### Other Integrations Enumerize integrates with the following automatically: - [RailsAdmin](https://github.com/sferik/rails_admin/) --- ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Added some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request ruby-enumerize-2.5.0/Rakefile000066400000000000000000000004471432207762100161560ustar00rootroot00000000000000#!/usr/bin/env rake # frozen_string_literal: true require "bundler/gem_tasks" require 'rake/testtask' require 'rspec/core/rake_task' Rake::TestTask.new do |t| t.libs << 'test' t.pattern = 'test/*_test.rb' t.verbose = true end RSpec::Core::RakeTask.new task :default => [:test, :spec] ruby-enumerize-2.5.0/enumerize.gemspec000066400000000000000000000016251432207762100200600ustar00rootroot00000000000000# -*- encoding: utf-8 -*- require File.expand_path('../lib/enumerize/version', __FILE__) Gem::Specification.new do |gem| gem.authors = ["Sergey Nartimov"] gem.email = "team@brainspec.com" gem.licenses = ['MIT'] gem.description = %q{Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support} gem.summary = %q{Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support} gem.homepage = "https://github.com/brainspec/enumerize" gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } gem.files = `git ls-files`.split("\n") gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") gem.name = "enumerize" gem.require_paths = ["lib"] gem.version = Enumerize::VERSION gem.required_ruby_version = '>= 1.9.3' gem.add_dependency('activesupport', '>= 3.2') end ruby-enumerize-2.5.0/lib/000077500000000000000000000000001432207762100152525ustar00rootroot00000000000000ruby-enumerize-2.5.0/lib/enumerize.rb000066400000000000000000000046501432207762100176070ustar00rootroot00000000000000# frozen_string_literal: true require 'active_support/concern' require 'active_support/core_ext/object/blank' require 'enumerize/version' module Enumerize autoload :Attribute, 'enumerize/attribute' autoload :AttributeMap, 'enumerize/attribute_map' autoload :Value, 'enumerize/value' autoload :Set, 'enumerize/set' autoload :Base, 'enumerize/base' autoload :Module, 'enumerize/module' autoload :Predicates, 'enumerize/predicates' autoload :Predicatable, 'enumerize/predicatable' autoload :Utils, 'enumerize/utils' autoload :ModuleAttributes, 'enumerize/module_attributes' autoload :ActiveModelAttributesSupport, 'enumerize/activemodel' autoload :ActiveRecordSupport, 'enumerize/activerecord' autoload :SequelSupport, 'enumerize/sequel' autoload :MongoidSupport, 'enumerize/mongoid' module Scope autoload :ActiveRecord, 'enumerize/scope/activerecord' autoload :Sequel, 'enumerize/scope/sequel' autoload :Mongoid, 'enumerize/scope/mongoid' end def self.included(base) ActiveSupport::Deprecation.warn '`include Enumerize` was deprecated. Please use `extend Enumerize`.', caller extended(base) end def self.extended(base) base.send :include, Enumerize::Base base.extend Enumerize::Predicates if defined?(::ActiveModel::Attributes) base.extend Enumerize::ActiveModelAttributesSupport end if defined?(::ActiveRecord::Base) base.extend Enumerize::ActiveRecordSupport base.extend Enumerize::Scope::ActiveRecord end if defined?(::Mongoid::Document) base.extend Enumerize::MongoidSupport base.extend Enumerize::Scope::Mongoid end if defined?(::Sequel::Model) base.extend Enumerize::SequelSupport base.extend Enumerize::Scope::Sequel end if defined?(::RailsAdmin) require 'enumerize/integrations/rails_admin' base.extend Enumerize::Integrations::RailsAdmin end if ::Module === base base.extend Enumerize::Base::ClassMethods base.extend Enumerize::ModuleAttributes end super end begin require 'simple_form' require 'enumerize/hooks/simple_form' require 'enumerize/form_helper' rescue LoadError end begin require 'formtastic' require 'enumerize/hooks/formtastic' rescue LoadError end begin require 'rspec/matchers' rescue LoadError else require 'enumerize/integrations/rspec' end end ruby-enumerize-2.5.0/lib/enumerize/000077500000000000000000000000001432207762100172555ustar00rootroot00000000000000ruby-enumerize-2.5.0/lib/enumerize/activemodel.rb000066400000000000000000000020351432207762100220760ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module ActiveModelAttributesSupport def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self.included_modules.include? ::ActiveModel::Attributes include InstanceMethods attribute name, Enumerize::ActiveModelAttributesSupport::Type.new(enumerized_attributes[name]) end end end module InstanceMethods # https://github.com/brainspec/enumerize/issues/74 def write_attribute(attr_name, value, *options) if self.class.enumerized_attributes[attr_name] _enumerized_values_for_validation[attr_name.to_s] = value end super end end class Type < ActiveModel::Type::Value def type :enumerize end def initialize(attr) @attr = attr end def serialize(value) v = @attr.find_value(value) v && v.value end def deserialize(value) @attr.find_value(value) end end end end ruby-enumerize-2.5.0/lib/enumerize/activerecord.rb000066400000000000000000000103351432207762100222560ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module ActiveRecordSupport def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self < ::ActiveRecord::Base include InstanceMethods const_get(:ActiveRecord_Relation).include(RelationMethods) const_get(:ActiveRecord_AssociationRelation).include(RelationMethods) const_get(:ActiveRecord_Associations_CollectionProxy).include(RelationMethods) # Since Rails use `allocate` method on models and initializes them with `init_with` method. # This way `initialize` method is not being called, but `after_initialize` callback always gets triggered. after_initialize :_set_default_value_for_enumerized_attributes # https://github.com/brainspec/enumerize/issues/111 require 'enumerize/hooks/uniqueness' unless options[:multiple] if ::ActiveRecord.version >= ::Gem::Version.new("7.0.0.alpha") attribute(name) do |subtype| Type.new(enumerized_attributes[name], subtype) end elsif ::ActiveRecord.version >= ::Gem::Version.new("6.1.0.alpha") decorate_attribute_type(name.to_s) do |subtype| Type.new(enumerized_attributes[name], subtype) end else decorate_attribute_type(name, :enumerize) do |subtype| Type.new(enumerized_attributes[name], subtype) end end end end end end module InstanceMethods # https://github.com/brainspec/enumerize/issues/74 def write_attribute(attr_name, value, *options) if self.class.enumerized_attributes[attr_name] _enumerized_values_for_validation[attr_name.to_s] = value end super end # Support multiple enumerized attributes def becomes(klass) became = super klass.enumerized_attributes.each do |attr| # Rescue when column associated to the enum does not exist. begin became.send("#{attr.name}=", send(attr.name)) rescue ActiveModel::MissingAttributeError end end became end def reload(options = nil) reloaded = super reloaded.class.enumerized_attributes.each do |attr| begin # Checks first if the enumerized attribute is in ActiveRecord::Store store_attr, _ = reloaded.class.stored_attributes.detect do |_store_attr, keys| keys.include?(attr.name) end if store_attr.present? reloaded.send("#{attr.name}=", reloaded.send(store_attr).with_indifferent_access[attr.name]) else reloaded.send("#{attr.name}=", reloaded[attr.name]) end rescue ActiveModel::MissingAttributeError end end reloaded end end module RelationMethods def update_all(updates) if updates.is_a?(Hash) enumerized_attributes.each do |attr| next if updates[attr.name].blank? || attr.kind_of?(Enumerize::Multiple) enumerize_value = attr.find_value(updates[attr.name]) updates[attr.name] = enumerize_value && enumerize_value.value end end super(updates) end end class Type < ActiveRecord::Type::Value delegate :type, to: :@subtype def initialize(attr, subtype) @attr = attr @subtype = subtype end def serialize(value) v = @attr.find_value(value) (v && v.value) || value end alias type_cast_for_database serialize def deserialize(value) @attr.find_value(value) end alias type_cast_from_database deserialize def as_json(options = nil) {attr: @attr.name, subtype: @subtype}.as_json(options) end def encode_with(coder) coder[:class_name] = @attr.klass.name coder[:attr_name] = @attr.name coder[:subtype] = @subtype end def init_with(coder) initialize( coder[:class_name].constantize.enumerized_attributes[coder[:attr_name]], coder[:subtype] ) end end end end ruby-enumerize-2.5.0/lib/enumerize/attribute.rb000066400000000000000000000124361432207762100216130ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize class Attribute attr_reader :klass, :name, :values, :default_value, :i18n_scope, :skip_validations_value def initialize(klass, name, options={}) raise ArgumentError, ':in option is required' unless options[:in] raise ArgumentError, ':scope option does not work with option :multiple' if options[:multiple] && options[:scope] extend Multiple if options[:multiple] @klass = klass @name = name.to_sym if options[:i18n_scope] raise ArgumentError, ':i18n_scope option accepts only String or Array of strings' unless Array(options[:i18n_scope]).all? { |s| s.is_a?(String) } @i18n_scope = options[:i18n_scope] end value_class = options.fetch(:value_class, Value) @values = Array(options[:in]).map { |v| value_class.new(self, *v).freeze } @value_hash = Hash[@values.map { |v| [v.value.to_s, v] }] @value_hash.merge! Hash[@values.map { |v| [v.to_s, v] }] if options[:default] @default_value = find_default_value(options[:default]) raise ArgumentError, 'invalid default value' unless @default_value end @skip_validations_value = options.fetch(:skip_validations, false) end def find_default_value(value) if value.respond_to?(:call) value else find_value(value) end end def find_value(value) @value_hash[value.to_s] unless value.nil? end def find_values(*values) values.map { |value| find_value(value) }.compact end def each_value values.each { |value| yield value } end def i18n_scopes @i18n_scopes ||= if i18n_scope Array(i18n_scope) elsif @klass.respond_to?(:model_name) ["enumerize.#{@klass.model_name.i18n_key}.#{name}"] else [] end end def options(options = {}) values = if options.empty? @values else raise ArgumentError, 'Options cannot have both :only and :except' if options[:only] && options[:except] only = Array(options[:only]).map(&:to_s) except = Array(options[:except]).map(&:to_s) @values.reject do |value| if options[:only] !only.include?(value) elsif options[:except] except.include?(value) end end end values.map { |v| [v.text, v.to_s] } end def respond_to_missing?(method, include_private=false) @value_hash.include?(method.to_s) || super end def define_methods!(mod) mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} if defined?(super) self.class.enumerized_attributes[:#{name}].find_value(super) elsif respond_to?(:read_attribute) self.class.enumerized_attributes[:#{name}].find_value(read_attribute(:#{name})) else if defined?(@#{name}) self.class.enumerized_attributes[:#{name}].find_value(@#{name}) else @#{name} = nil end end end def #{name}=(new_value) allowed_value_or_nil = self.class.enumerized_attributes[:#{name}].find_value(new_value) allowed_value_or_nil = allowed_value_or_nil.value unless allowed_value_or_nil.nil? if defined?(super) super allowed_value_or_nil elsif respond_to?(:write_attribute, true) write_attribute '#{name}', allowed_value_or_nil else @#{name} = allowed_value_or_nil end _enumerized_values_for_validation['#{name}'] = new_value.nil? ? nil : new_value.to_s allowed_value_or_nil end def #{name}_text self.#{name} && self.#{name}.text end def #{name}_value self.#{name} && self.#{name}.value end RUBY end private def method_missing(method) if @value_hash.include?(method.to_s) find_value(method) else super end end end module Multiple def find_default_value(value) if value.respond_to?(:call) value else find_values(*value) end end def define_methods!(mod) mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} unless defined?(@_#{name}_enumerized_set) if defined?(super) self.#{name} = super elsif respond_to?(:read_attribute) self.#{name} = read_attribute(:#{name}) else if defined?(@#{name}) self.#{name} = @#{name} else self.#{name} = [] end end end @_#{name}_enumerized_set end def #{name}=(values) @_#{name}_enumerized_set = Enumerize::Set.new(self, self.class.enumerized_attributes[:#{name}], values) raw_values = self.#{name}.values.map(&:value) if defined?(super) super raw_values elsif respond_to?(:write_attribute, true) write_attribute '#{name}', raw_values else @#{name} = raw_values end _enumerized_values_for_validation['#{name}'] = values.respond_to?(:map) ? values.reject(&:blank?).map(&:to_s) : values self.#{name} end RUBY end end end ruby-enumerize-2.5.0/lib/enumerize/attribute_map.rb000066400000000000000000000012141432207762100224400ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize class AttributeMap attr_reader :attributes def initialize @attributes = {} @dependants = [] end def [](name) @attributes[name.to_s] end def <<(attr) @attributes[attr.name.to_s] = attr @dependants.each do |dependant| dependant << attr end end def each @attributes.each_pair do |_name, attr| yield attr end end def empty? @attributes.empty? end def add_dependant(dependant) @dependants << dependant each do |attr| dependant << attr end end end end ruby-enumerize-2.5.0/lib/enumerize/base.rb000066400000000000000000000055621432207762100205240ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Base def self.included(base) base.extend ClassMethods base.singleton_class.prepend ClassMethods::Hook if base.respond_to?(:validate) base.validate :_validate_enumerized_attributes end end module ClassMethods def enumerize(name, options={}) attr = Attribute.new(self, name, options) enumerized_attributes << attr unless methods.include?(attr.name) _enumerize_module._class_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{attr.name} enumerized_attributes[:#{attr.name}] end RUBY end attr.define_methods!(_enumerize_module) end def enumerized_attributes @enumerized_attributes ||= AttributeMap.new end module Hook def inherited(subclass) enumerized_attributes.add_dependant subclass.enumerized_attributes super subclass end end private def _enumerize_module @_enumerize_module ||= begin mod = Module.new include mod mod end end end def initialize(*) super _set_default_value_for_enumerized_attributes end def read_attribute_for_validation(key) key = key.to_s if _enumerized_values_for_validation.has_key?(key) _enumerized_values_for_validation[key] elsif defined?(super) super else send(key) end end private def _enumerized_values_for_validation @_enumerized_values_for_validation ||= {} end def _validate_enumerized_attributes self.class.enumerized_attributes.each do |attr| skip_validations = Utils.call_if_callable(attr.skip_validations_value, self) next if skip_validations value = read_attribute_for_validation(attr.name) next if value.blank? if attr.kind_of? Multiple errors.add attr.name unless value.respond_to?(:all?) && value.all? { |v| v.blank? || attr.find_value(v) } else errors.add attr.name, :inclusion unless attr.find_value(value) end end end def _set_default_value_for_enumerized_attributes self.class.enumerized_attributes.each do |attr| next if attr.default_value.nil? begin if respond_to?(attr.name) attr_value = public_send(attr.name) else next end value_for_validation = _enumerized_values_for_validation[attr.name.to_s] if (!attr_value || attr_value.empty?) && (!value_for_validation || value_for_validation.empty?) value = Utils.call_if_callable(attr.default_value, self) public_send("#{attr.name}=", value) end rescue ActiveModel::MissingAttributeError end end end end end ruby-enumerize-2.5.0/lib/enumerize/hooks/000077500000000000000000000000001432207762100204005ustar00rootroot00000000000000ruby-enumerize-2.5.0/lib/enumerize/hooks/formtastic.rb000066400000000000000000000014001432207762100230730ustar00rootroot00000000000000# frozen_string_literal: true require 'active_support/concern' module Enumerize module Hooks module FormtasticFormBuilderExtension def input(method, options={}) enumerized_object = convert_to_model(object) klass = enumerized_object.class if klass.respond_to?(:enumerized_attributes) && (attr = klass.enumerized_attributes[method]) options[:collection] ||= attr.options if attr.kind_of?(Enumerize::Multiple) && options[:as] != :check_boxes options[:input_html] = options.fetch(:input_html, {}).merge(:multiple => true) end end super(method, options) end end end end ::Formtastic::FormBuilder.send :prepend, Enumerize::Hooks::FormtasticFormBuilderExtension ruby-enumerize-2.5.0/lib/enumerize/hooks/sequel_dataset.rb000066400000000000000000000005131432207762100237270ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Hooks module SequelDataset def literal_append(sql, v) if v.is_a?(Enumerize::Value) super(sql, v.value) else super(sql, v) end end end end end ::Sequel::Dataset.send :prepend, Enumerize::Hooks::SequelDataset ruby-enumerize-2.5.0/lib/enumerize/hooks/simple_form.rb000066400000000000000000000022031432207762100232360ustar00rootroot00000000000000# frozen_string_literal: true require 'active_support/concern' module Enumerize module Hooks module SimpleFormBuilderExtension def input(attribute_name, options={}, &block) add_input_options_for_enumerized_attribute(attribute_name, options) super(attribute_name, options, &block) end def input_field(attribute_name, options={}) add_input_options_for_enumerized_attribute(attribute_name, options) super(attribute_name, options) end private def add_input_options_for_enumerized_attribute(attribute_name, options) enumerized_object = convert_to_model(object) klass = enumerized_object.class if klass.respond_to?(:enumerized_attributes) && (attr = klass.enumerized_attributes[attribute_name]) options[:collection] ||= attr.options if attr.kind_of?(Enumerize::Multiple) && options[:as] != :check_boxes options[:input_html] = options.fetch(:input_html, {}).merge(:multiple => true) end end end end end end ::SimpleForm::FormBuilder.send :prepend, Enumerize::Hooks::SimpleFormBuilderExtension ruby-enumerize-2.5.0/lib/enumerize/hooks/uniqueness.rb000066400000000000000000000010401432207762100231170ustar00rootroot00000000000000# frozen_string_literal: true require 'active_support/concern' module Enumerize module Hooks module UniquenessValidator def validate_each(record, name, value) klass = record.to_model.class if klass.respond_to?(:enumerized_attributes) && (attr = klass.enumerized_attributes[name]) value = attr.find_value(value).try(:value) end super(record, name, value) end end end end ::ActiveRecord::Validations::UniquenessValidator.send :prepend, Enumerize::Hooks::UniquenessValidator ruby-enumerize-2.5.0/lib/enumerize/integrations/000077500000000000000000000000001432207762100217635ustar00rootroot00000000000000ruby-enumerize-2.5.0/lib/enumerize/integrations/rails_admin.rb000066400000000000000000000005511432207762100245730ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Integrations module RailsAdmin def enumerize(name, options={}) super _enumerize_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name}_enum self.class.enumerized_attributes[:#{name}].options end RUBY end end end end ruby-enumerize-2.5.0/lib/enumerize/integrations/rspec.rb000066400000000000000000000005161432207762100234260ustar00rootroot00000000000000# frozen_string_literal: true require 'enumerize/integrations/rspec/matcher' module Enumerize module Integrations module RSpec def enumerize(attr) ::Enumerize::Integrations::RSpec::Matcher.new(attr) end end end end module RSpec module Matchers include Enumerize::Integrations::RSpec end end ruby-enumerize-2.5.0/lib/enumerize/integrations/rspec/000077500000000000000000000000001432207762100230775ustar00rootroot00000000000000ruby-enumerize-2.5.0/lib/enumerize/integrations/rspec/matcher.rb000066400000000000000000000112321432207762100250460ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Integrations module RSpec class Matcher def initialize(expected_attr) self.expected_attr = expected_attr end def in(*expected_values) self.expected_values = expected_values.flatten self end def with_default(expected_default) self.expected_default = expected_default.to_s self end def with_i18n_scope(expected_i18n_scope) self.expected_i18n_scope = expected_i18n_scope self end def with_predicates(expected_predicates) self.expected_predicates = expected_predicates self end def with_multiple(expected_multiple) self.expected_multiple = expected_multiple self end def with_scope(expected_scope) self.expected_scope = expected_scope self end def failure_message "Expected #{expectation}" end def failure_message_when_negated "Did not expect #{expectation}" end def description description = "define enumerize :#{expected_attr}" description += " in: #{quote_values(expected_values)}" if expected_values description += " with #{expected_default.inspect} as default value" if expected_default description += " i18n_scope: #{expected_i18n_scope.inspect}" if expected_i18n_scope description += " predicates: #{expected_predicates.inspect}" if expected_predicates description += " multiple: #{expected_multiple.inspect}" if expected_multiple description += " scope: #{expected_scope.inspect}" if expected_scope description end def matches?(subject) self.subject = subject matches = true matches &= matches_attribute? matches &= matches_values? if expected_values matches &= matches_default_value? if expected_default matches &= matches_i18n_scope? if expected_i18n_scope matches &= matches_predicates? if expected_predicates matches &= matches_multiple? if expected_multiple matches &= matches_scope? if expected_scope matches end private attr_accessor :expected_attr, :expected_values, :subject, :expected_default, :expected_i18n_scope, :expected_predicates, :expected_multiple, :expected_scope def expectation "#{subject.class.name} to #{description}" end def matches_attribute? attributes.present? end def matches_values? matches_array_values? || matches_hash_values? end def matches_array_values? sorted_values == enumerized_values end def matches_hash_values? return unless expected_values.first.is_a?(Hash) expected_values.first.all? { |k, v| enumerized_value_hash[k.to_s] == v; } end def matches_default_value? expected_default == enumerized_default end def matches_i18n_scope? attributes.i18n_scope == expected_i18n_scope end def matches_predicates? if expected_predicates.is_a?(TrueClass) subject.respond_to?("#{enumerized_values.first}?") else subject.respond_to?("#{expected_attr}_#{attributes.values.first}?") end end def matches_multiple? subject.public_send(expected_attr).is_a?(Enumerize::Set) end def matches_scope? case expected_scope when TrueClass subject_class.respond_to?("with_#{expected_attr}") when :shallow enumerized_values.all? { |value| subject_class.respond_to?(value) } else subject_class.respond_to?(expected_scope[:scope]) end end def sorted_values @sorted_values ||=expected_values.map(&:to_s).sort end def enumerized_values @enumerized_values ||= attributes.values.sort end def enumerized_default @enumerized_default ||= attributes.default_value end def enumerized_value_hash @enumerized_value_hash ||= attributes.instance_variable_get('@value_hash') end def attributes subject_class.enumerized_attributes.attributes[expected_attr.to_s] end def subject_class @subject_class ||= subject.class end def quote_values(values) sorted_values.map(&:inspect).join(', ') end end end end end ruby-enumerize-2.5.0/lib/enumerize/module.rb000066400000000000000000000011201432207762100210610ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize class Module < ::Module attr_reader :_class_methods def initialize super @_class_methods = ::Module.new @_dependents = [] @_dependent_evals = [] end def included(klass) klass.extend _class_methods @_dependent_evals.each do |block| klass.instance_eval(&block) end @_dependents << klass end def dependent_eval(&block) @_dependents.each do |klass| klass.instance_eval(&block) end @_dependent_evals << block end end end ruby-enumerize-2.5.0/lib/enumerize/module_attributes.rb000066400000000000000000000004141432207762100233340ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module ModuleAttributes def included(base) base.extend Enumerize base.send :include, _enumerize_module enumerized_attributes.add_dependant base.enumerized_attributes super end end end ruby-enumerize-2.5.0/lib/enumerize/mongoid.rb000066400000000000000000000011161432207762100212350ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module MongoidSupport def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self < ::Mongoid::Document include InstanceMethods after_initialize :_set_default_value_for_enumerized_attributes end end end module InstanceMethods def reload reloaded = super reloaded.class.enumerized_attributes.each do |attr| reloaded.send("#{attr.name}=", reloaded[attr.name]) end reloaded end end end end ruby-enumerize-2.5.0/lib/enumerize/predicatable.rb000066400000000000000000000007571432207762100222320ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Predicatable def respond_to_missing?(method, include_private=false) predicate_method?(method) || super end private def method_missing(method, *args, &block) if predicate_method?(method) predicate_call(method[0..-2], *args, &block) else super end end def predicate_method?(method) method[-1] == '?' && @attr && @attr.values.include?(method[0..-2]) end end end ruby-enumerize-2.5.0/lib/enumerize/predicates.rb000066400000000000000000000032041432207762100217240ustar00rootroot00000000000000# frozen_string_literal: true require 'active_support/core_ext/module/delegation' module Enumerize # Predicate methods. # # Basic usage: # # class User # extend Enumerize # enumerize :sex, in: %w(male female), predicates: true # end # # user = User.new # # user.male? # => false # user.female? # => false # # user.sex = 'male' # # user.male? # => true # user.female? # => false # # Using prefix: # # class User # extend Enumerize # enumerize :sex, in: %w(male female), predicates: { prefix: true } # end # # user = User.new # user.sex = 'female' # user.sex_female? # => true # # Use only and except options to specify what values create # predicate methods for. module Predicates def enumerize(name, options={}) super if options[:predicates] Builder.new(enumerized_attributes[name], options[:predicates]).build(_enumerize_module) end end class Builder def initialize(attr, options) @attr = attr @options = options.is_a?(Hash) ? options : {} end def values values = @attr.values if @options[:only] values &= Array(@options[:only]).map(&:to_s) end if @options[:except] values -= Array(@options[:except]).map(&:to_s) end values end def names values.map { |v| "#{v.tr('-', '_')}?" } end def build(klass) klass.delegate(*names, to: @attr.name, prefix: @options[:prefix], allow_nil: true) end end end end ruby-enumerize-2.5.0/lib/enumerize/scope/000077500000000000000000000000001432207762100203665ustar00rootroot00000000000000ruby-enumerize-2.5.0/lib/enumerize/scope/activerecord.rb000066400000000000000000000030121432207762100233610ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Scope module ActiveRecord def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self < ::ActiveRecord::Base if options[:scope] _define_activerecord_scope_methods!(name, options) end end end end private def _define_activerecord_scope_methods!(name, options) return _define_activerecord_shallow_scopes!(name) if options[:scope] == :shallow scope_name = options[:scope] == true ? "with_#{name}" : options[:scope] define_singleton_method scope_name do |*values| values = enumerized_attributes[name].find_values(*values).map(&:value) values = values.first if values.size == 1 where(name => values) end if options[:scope] == true define_singleton_method "without_#{name}" do |*values| values = enumerized_attributes[name].find_values(*values).map(&:value) where(arel_table[name].not_in(values)) end end end def _define_activerecord_shallow_scopes!(attribute_name) enumerized_attributes[attribute_name].each_value do |value_obj| define_singleton_method(value_obj) do where(attribute_name => value_obj.value) end define_singleton_method("not_#{value_obj}") do where.not(attribute_name => value_obj.value) end end end end end end ruby-enumerize-2.5.0/lib/enumerize/scope/mongoid.rb000066400000000000000000000026601432207762100223530ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Scope module Mongoid def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self < ::Mongoid::Document if options[:scope] _define_mongoid_scope_methods!(name, options) end end end end private def _define_mongoid_scope_methods!(name, options) return _define_mongoid_shallow_scopes!(name) if options[:scope] == :shallow scope_name = options[:scope] == true ? "with_#{name}" : options[:scope] define_singleton_method scope_name do |*values| values = enumerized_attributes[name].find_values(*values).map(&:value) self.in(name => values) end if options[:scope] == true define_singleton_method "without_#{name}" do |*values| values = enumerized_attributes[name].find_values(*values).map(&:value) not_in(name => values) end end end def _define_mongoid_shallow_scopes!(attribute_name) enumerized_attributes[attribute_name].each_value do |value_obj| define_singleton_method(value_obj) do self.in(attribute_name => value_obj.value) end define_singleton_method("not_#{value_obj}") do self.not_in(attribute_name => value_obj.value) end end end end end end ruby-enumerize-2.5.0/lib/enumerize/scope/sequel.rb000066400000000000000000000031321432207762100222100ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Scope module Sequel def enumerize(name, options={}) super _enumerize_module.dependent_eval do if defined?(::Sequel::Model) && self < ::Sequel::Model if options[:scope] _define_sequel_scope_methods!(name, options) end require 'enumerize/hooks/sequel_dataset' end end end private def _define_sequel_scope_methods!(name, options) return _define_sequel_shallow_scopes!(name) if options[:scope] == :shallow klass = self scope_name = options[:scope] == true ? "with_#{name}" : options[:scope] def_dataset_method scope_name do |*values| values = values.map { |value| klass.enumerized_attributes[name].find_value(value).value } values = values.first if values.size == 1 where(name => values) end if options[:scope] == true def_dataset_method "without_#{name}" do |*values| values = values.map { |value| klass.enumerized_attributes[name].find_value(value).value } exclude(name => values) end end end def _define_sequel_shallow_scopes!(attribute_name) enumerized_attributes[attribute_name].each_value do |value_obj| def_dataset_method(value_obj) do where(attribute_name => value_obj.value.to_s) end def_dataset_method("not_#{value_obj}") do exclude(attribute_name => value_obj.value.to_s) end end end end end end ruby-enumerize-2.5.0/lib/enumerize/sequel.rb000066400000000000000000000036641432207762100211110ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module SequelSupport def enumerize(name, options={}) super _enumerize_module.dependent_eval do if defined?(::Sequel::Model) && self < ::Sequel::Model include InstanceMethods require 'enumerize/hooks/sequel_dataset' end end end private module InstanceMethods def validate super self.class.enumerized_attributes.each do |attr| skip_validations = Utils.call_if_callable(attr.skip_validations_value, self) next if skip_validations value = read_attribute_for_validation(attr.name) next if value.blank? if attr.kind_of? Multiple errors.add attr.name, "is invalid" unless value.respond_to?(:all?) && value.all? { |v| v.blank? || attr.find_value(v) } else errors.add attr.name, "is not included in the list" unless attr.find_value(value) end end end def _set_default_value_for_enumerized_attributes _enumerized_values_for_validation.delete_if do |k, v| v.nil? end if defined?(Sequel::Plugins::Serialization::InstanceMethods) modules = self.class.ancestors plugin_idx = modules.index(Sequel::Plugins::Serialization::InstanceMethods) if plugin_idx && plugin_idx < modules.index(Enumerize::SequelSupport::InstanceMethods) abort "ERROR: You need to enable the Sequel serialization plugin before calling any enumerize methods on a model." end plugin_idx = modules.index(Sequel::Plugins::ValidationHelpers::InstanceMethods) if plugin_idx && plugin_idx < modules.index(Enumerize::SequelSupport::InstanceMethods) abort "ERROR: You need to enable the Sequel validation_helpers plugin before calling any enumerize methods on a model." end end super end end end end ruby-enumerize-2.5.0/lib/enumerize/set.rb000066400000000000000000000026761432207762100204100ustar00rootroot00000000000000# frozen_string_literal: true require 'active_support/core_ext/module/delegation' module Enumerize class Set include Enumerable include Predicatable attr_reader :values def initialize(obj, attr, values) @obj = obj @attr = attr @values = [] if values.respond_to?(:each) values.each do |input| value = @attr.find_value(input) if value && !@values.include?(value) @values << value end end end end def <<(value) @values << value mutate! end alias_method :push, :<< delegate :each, :empty?, :size, to: :values def to_ary @values.to_a end def texts @values.map(&:text) end delegate :join, to: :to_ary def ==(other) return false unless other.respond_to?(:each) other.size == size && other.all? { |v| @values.include?(@attr.find_value(v)) } end alias_method :eql?, :== def include?(value) @values.include?(@attr.find_value(value)) end def delete(value) @values.delete(@attr.find_value(value)) mutate! end def inspect "#" end def encode_with(coder) coder.represent_object(Array, @values) end private def predicate_call(value) include?(value) end def mutate! @values = @obj.public_send("#{@attr.name}=", @values).values end end end ruby-enumerize-2.5.0/lib/enumerize/utils.rb000066400000000000000000000004131432207762100207400ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize module Utils class << self def call_if_callable(value, param = nil) return value unless value.respond_to?(:call) value.arity == 0 ? value.call : value.call(param) end end end end ruby-enumerize-2.5.0/lib/enumerize/value.rb000066400000000000000000000022501432207762100207150ustar00rootroot00000000000000# frozen_string_literal: true require 'i18n' require 'active_support/inflector' module Enumerize class Value < String include Predicatable attr_reader :value def initialize(attr, name, value=nil) if self.class.method_defined?("#{name}?") warn("It's not recommended to use `#{name}` as a field value since `#{name}?` is defined. (#{attr.klass.name}##{attr.name})") end @attr = attr @value = value.nil? ? name.to_s : value super(name.to_s) @i18n_keys = @attr.i18n_scopes.map { |s| :"#{s}.#{self}" } @i18n_keys << :"enumerize.defaults.#{@attr.name}.#{self}" @i18n_keys << :"enumerize.#{@attr.name}.#{self}" @i18n_keys << ActiveSupport::Inflector.humanize(ActiveSupport::Inflector.underscore(self)) # humanize value if there are no translations @i18n_keys end def text I18n.t(@i18n_keys[0], :default => @i18n_keys[1..-1]) if @i18n_keys end def ==(other) super(other.to_s) || value == other end def encode_with(coder) coder.represent_object(self.class.superclass, @value) end private def predicate_call(value) value == self end end end ruby-enumerize-2.5.0/lib/enumerize/version.rb000066400000000000000000000001101432207762100212570ustar00rootroot00000000000000# frozen_string_literal: true module Enumerize VERSION = '2.5.0' end ruby-enumerize-2.5.0/lib/sequel/000077500000000000000000000000001432207762100165505ustar00rootroot00000000000000ruby-enumerize-2.5.0/lib/sequel/plugins/000077500000000000000000000000001432207762100202315ustar00rootroot00000000000000ruby-enumerize-2.5.0/lib/sequel/plugins/enumerize.rb000066400000000000000000000006111432207762100225570ustar00rootroot00000000000000# frozen_string_literal: true module Sequel module Plugins module Enumerize # Depend on the def_dataset_method plugin def self.apply(model) model.plugin(:def_dataset_method) unless model.respond_to?(:def_dataset_method) end module InstanceMethods def self.included(base) base.extend ::Enumerize end end end end end ruby-enumerize-2.5.0/spec/000077500000000000000000000000001432207762100154365ustar00rootroot00000000000000ruby-enumerize-2.5.0/spec/enumerize/000077500000000000000000000000001432207762100174415ustar00rootroot00000000000000ruby-enumerize-2.5.0/spec/enumerize/integrations/000077500000000000000000000000001432207762100221475ustar00rootroot00000000000000ruby-enumerize-2.5.0/spec/enumerize/integrations/rspec/000077500000000000000000000000001432207762100232635ustar00rootroot00000000000000ruby-enumerize-2.5.0/spec/enumerize/integrations/rspec/matcher_spec.rb000066400000000000000000000203261432207762100262500ustar00rootroot00000000000000# frozen_string_literal: true require 'active_record' silence_warnings do ActiveRecord::Migration.verbose = false ActiveRecord::Base.logger = Logger.new(nil) ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:") end ActiveRecord::Base.connection.instance_eval do create_table :users do |t| t.string :sex t.string :role t.string :account_type t.string :status end end class User < ActiveRecord::Base extend Enumerize enumerize :sex, :in => [:male, :female], scope: true enumerize :role, :in => [:user, :admin], scope: :having_role enumerize :account_type, :in => [:basic, :premium] enumerize :status, :in => [:active, :disabled], scope: :shallow end RSpec.describe Enumerize::Integrations::RSpec::Matcher do let(:model) do Class.new do extend Enumerize def self.name 'Model' end end end subject do model.new end describe 'without qualifier' do it 'accepts when has defined a enumerize' do model.enumerize(:sex, :in => [:male, :female]) expect(subject).to enumerize(:sex) end it 'rejects when has not defined a enumerize' do message = 'Expected Model to define enumerize :sex' expect do expect(subject).to enumerize(:sex) end.to fail_with(message) end end describe '#in' do context 'defined as array' do before do model.enumerize(:sex, :in => [:male, :female]) end it 'accepts the right params as an array' do expect(subject).to enumerize(:sex).in([:male, :female]) end it 'accepts the right params as regular params' do expect(subject).to enumerize(:sex).in(:male, :female) end it 'accepts the the right params in a different order' do expect(subject).to enumerize(:sex).in(:female, :male) end it 'rejects wrong params' do message = 'Expected Model to define enumerize :sex in: "boy", "girl"' expect do expect(subject).to enumerize(:sex).in(:boy, :girl) end.to fail_with(message) end it 'has the right message when negated' do message = 'Did not expect Model to define enumerize :sex in: "female", "male"' expect do expect(subject).to_not enumerize(:sex).in(:male, :female) end.to fail_with(message) end end context 'defined as hash' do before do model.enumerize(:sex, :in => { male: 0, female: 1 }) end it 'accepts the right params as an array' do expect(subject).to enumerize(:sex).in(:male, :female) end it 'accepts the right params as a hash' do expect(subject).to enumerize(:sex).in(male: 0, female: 1) end it 'accepts the right params as a hash in a different order' do expect(subject).to enumerize(:sex).in(female: 1, male: 0) end it 'rejects wrong keys' do message = 'Expected Model to define enumerize :sex in: "{:boy=>0, :girl=>1}"' expect do expect(subject).to enumerize(:sex).in(boy: 0, girl: 1) end.to fail_with(message) end it 'rejects wrong values' do message = 'Expected Model to define enumerize :sex in: "{:male=>2, :female=>3}"' expect do expect(subject).to enumerize(:sex).in(male: 2, female: 3) end.to fail_with(message) end end it 'has the right description' do matcher = enumerize(:sex).in(:male, :female) expect(matcher.description).to eq('define enumerize :sex in: "female", "male"') end end describe '#with_default' do before do model.enumerize(:sex, :in => [:male, :female], default: :female) end it 'accepts the right default value' do expect(subject).to enumerize(:sex).in(:male, :female).with_default(:female) end it 'rejects the wrong default value' do message = 'Expected Model to define enumerize :sex in: "female", "male" with "male" as default value' expect do expect(subject).to enumerize(:sex).in(:male, :female).with_default(:male) end.to fail_with(message) end it 'rejects if the `in` is wrong with a correct default value' do message = 'Expected Model to define enumerize :sex in: "boy", "girl" with "female" as default value' expect do expect(subject).to enumerize(:sex).in(:boy, :girl).with_default(:female) end.to fail_with(message) end it 'has the right description' do matcher = enumerize(:sex).in(:male, :female).with_default(:female) message = 'define enumerize :sex in: "female", "male" with "female" as default value' expect(matcher.description).to eq(message) end end describe '#with_i18n_scope' do context 'defined as string' do before do model.enumerize(:sex, :in => [:male, :female], i18n_scope: 'sex') end it 'accepts the right i18n_scope' do expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope('sex') end it 'rejects the wrong i18n_scope' do message = 'Expected Model to define enumerize :sex in: "female", "male" i18n_scope: "gender"' expect do expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope('gender') end.to fail_with(message) end end context 'defined as array' do before do model.enumerize(:sex, :in => [:male, :female], i18n_scope: ['sex', 'more.sex']) end it 'accepts the wrong i18n_scope' do expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope(['sex', 'more.sex']) end it 'rejects the wrong i18n_scope' do message = 'Expected Model to define enumerize :sex in: "female", "male" i18n_scope: ["sex"]' expect do expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope(['sex']) end.to fail_with(message) end end end describe '#with_predicates' do it 'accepts when predicates is defined as a boolean' do model.enumerize(:sex, :in => [:male, :female], predicates: true) expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true) end it 'accepts when predicates is defined as a hash' do model.enumerize(:sex, :in => [:male, :female], predicates: { prefix: true }) expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(prefix: true) end it 'accepts when custom values are used as attribute' do model.enumerize(:sex, :in => { male: 0, female: 1 }, predicates: true) expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true) end it 'rejects when predicates is not defined' do model.enumerize(:sex, :in => [:male, :female]) message = 'Expected Model to define enumerize :sex in: "female", "male" predicates: true' expect do expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true) end.to fail_with(message) end end describe '#with_multiple' do it 'accepts when has defined the multiple' do model.enumerize(:sex, :in => [:male, :female], multiple: true) expect(subject).to enumerize(:sex).in(:male, :female).with_multiple(true) end it 'rejects when has not defined the multiple' do model.enumerize(:sex, :in => [:male, :female]) message = 'Expected Model to define enumerize :sex in: "female", "male" multiple: true' expect do expect(subject).to enumerize(:sex).in(:male, :female).with_multiple(true) end.to fail_with(message) end end describe '#with_scope' do subject do User.new end it 'accepts when scope is defined as a boolean' do expect(subject).to enumerize(:sex).in(:male, :female).with_scope(true) end it 'accepts when scope is defined as a hash' do expect(subject).to enumerize(:role).in(:user, :admin).with_scope(scope: :having_role) end it 'accepts shallow scope' do expect(subject).to enumerize(:status).in(:active, :disabled).with_scope(:shallow) end it 'rejects when scope is not defined' do message = 'Expected User to define enumerize :account_type in: "basic", "premium" scope: true' expect do expect(subject).to enumerize(:account_type).in(:basic, :premium).with_scope(true) end.to fail_with(message) end end end ruby-enumerize-2.5.0/spec/spec_helper.rb000066400000000000000000000013301432207762100202510ustar00rootroot00000000000000# frozen_string_literal: true require 'rails' require 'enumerize' require 'rspec/matchers/fail_matchers' RSpec.configure do |config| config.disable_monkey_patching! config.order = :random Kernel.srand config.seed config.filter_run focus: true config.run_all_when_everything_filtered = true config.expect_with :rspec do |expectations| expectations.syntax = :expect expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.syntax = :expect mocks.verify_partial_doubles = true end if config.files_to_run.one? config.default_formatter = 'doc' end config.warnings = true config.include RSpec::Matchers::FailMatchers end ruby-enumerize-2.5.0/test/000077500000000000000000000000001432207762100154635ustar00rootroot00000000000000ruby-enumerize-2.5.0/test/activemodel_test.rb000066400000000000000000000056011432207762100213450ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' if defined?(::ActiveModel::Attributes) describe Enumerize do class ActiveModelUser include ActiveModel::Model include ActiveModel::Attributes extend Enumerize attribute :name, :string enumerize :sex, :in => %w[male female] enumerize :role, :in => %w[admin user], :default => 'user' enumerize :interests, :in => [:music, :sports, :dancing, :programming], :multiple => true end class InterestsRequiredActiveModelUser < ActiveModelUser validates :interests, presence: true end let(:model) { ActiveModelUser } it 'initialize value' do user = model.new(:name => 'active_model_user', :sex => :male, :role => :user, :interests => [:music, :programming]) expect(user.sex).must_equal 'male' expect(user.sex_text).must_equal 'Male' expect(user.role).must_equal 'user' expect(user.role_text).must_equal 'User' expect(user.interests).must_equal %w(music programming) end it 'sets nil if invalid value is passed' do user = model.new user.sex = :invalid expect(user.sex).must_be_nil end it 'stores value' do user = model.new user.sex = :female expect(user.sex).must_equal 'female' end it 'has default value' do expect(model.new.role).must_equal 'user' end it 'validates inclusion' do user = model.new user.role = 'wrong' expect(user).wont_be :valid? end it 'supports multiple attributes' do user = ActiveModelUser.new expect(user.interests).must_be_instance_of Enumerize::Set expect(user.interests).must_be_empty user.interests << :music expect(user.interests).must_equal %w(music) user.interests << :sports expect(user.interests).must_equal %w(music sports) user.interests = [] interests = user.interests interests << :music expect(interests).must_equal %w(music) interests << :dancing expect(interests).must_equal %w(music dancing) end it 'returns invalid multiple value for validation' do user = ActiveModelUser.new user.interests << :music user.interests << :invalid values = user.read_attribute_for_validation(:interests) expect(values).must_equal %w(music invalid) end it 'validates multiple attributes' do user = ActiveModelUser.new user.interests << :invalid expect(user).wont_be :valid? user.interests = Object.new expect(user).wont_be :valid? user.interests = ['music', ''] expect(user).must_be :valid? end it 'validates presence with multiple attributes' do user = InterestsRequiredActiveModelUser.new user.interests = [] user.valid? expect(user.errors[:interests]).wont_be :empty? user.interests = [''] user.valid? expect(user.errors[:interests]).wont_be :empty? user.interests = [:dancing, :programming] user.valid? expect(user.errors[:interests]).must_be_empty end end else # Skip end ruby-enumerize-2.5.0/test/activerecord_test.rb000066400000000000000000000437531432207762100215350ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' require 'active_record' require 'logger' db = (ENV['DB'] || 'sqlite3').to_sym silence_warnings do ActiveRecord::Migration.verbose = false ActiveRecord::Base.logger = Logger.new(nil) ActiveRecord::Base.configurations = { 'sqlite3' => { 'adapter' => 'sqlite3', 'database' => ':memory:' }, 'mysql2' => { 'adapter' => 'mysql2', 'host' => '127.0.0.1', 'username' => 'root', 'password' => ENV['MYSQL_ROOT_PASSWORD'], 'database' => 'enumerize_test', 'encoding' => 'utf8mb4', 'charset' => 'utf8mb4' }, 'postgresql' => { 'adapter' => 'postgresql', 'host' => 'localhost', 'username' => ENV['POSTGRES_USER'], 'password' => ENV['POSTGRES_PASSWORD'] }, 'postgresql_master' => { 'adapter' => 'postgresql', 'host' => 'localhost', 'username' => ENV['POSTGRES_USER'], 'password' => ENV['POSTGRES_PASSWORD'], 'database' => 'template1', 'schema_search_path' => 'public' } } case db when :postgresql ActiveRecord::Base.establish_connection(:postgresql_master) ActiveRecord::Base.connection.recreate_database('enumerize_test') when :mysql2 if ActiveRecord::Base.configurations.respond_to?(:[]) ActiveRecord::Tasks::DatabaseTasks.create ActiveRecord::Base.configurations[db.to_s] else ActiveRecord::Tasks::DatabaseTasks.create ActiveRecord::Base.configurations.find_db_config(db.to_s) end ActiveRecord::Base.establish_connection(db) else ActiveRecord::Base.establish_connection(db) end end ActiveRecord::Base.connection.instance_eval do create_table :users do |t| t.string :sex t.string :role t.string :lambda_role t.string :name t.string :interests t.integer :status t.text :settings t.integer :skill t.string :account_type, :default => :basic t.string :foo end create_table :documents do |t| t.integer :user_id t.string :visibility t.integer :status t.timestamps null: true end end class BaseEntity < ActiveRecord::Base self.abstract_class = true extend Enumerize enumerize :visibility, :in => [:public, :private, :protected], :scope => true, :default => :public end class Document < BaseEntity belongs_to :user enumerize :status, in: {draft: 1, release: 2} end module RoleEnum extend Enumerize enumerize :role, :in => [:user, :admin], :default => :user, scope: :having_role enumerize :lambda_role, :in => [:user, :admin], :default => lambda { :admin } end class User < ActiveRecord::Base extend Enumerize include RoleEnum store :settings, accessors: [:language] enumerize :sex, :in => [:male, :female], scope: :shallow enumerize :language, :in => [:en, :jp] serialize :interests, Array enumerize :interests, :in => [:music, :sports, :dancing, :programming], :multiple => true enumerize :status, :in => { active: 1, blocked: 2 }, scope: true enumerize :skill, :in => { noob: 0, casual: 1, pro: 2 }, scope: :shallow enumerize :account_type, :in => [:basic, :premium] # There is no column for relationship enumeration for testing purposes: model # should not be broken even if the associated column does not exist yet. enumerize :relationship, :in => [:single, :married] has_many :documents end class UniqStatusUser < User validates :status, uniqueness: true validates :sex, presence: true end class InterestsRequiredUser < User validates :interests, presence: true end class SkipValidationsUser < ActiveRecord::Base self.table_name = "users" include SkipValidationsEnum end class DoNotSkipValidationsUser < ActiveRecord::Base self.table_name = "users" include DoNotSkipValidationsEnum end class SkipValidationsLambdaUser < ActiveRecord::Base self.table_name = "users" include SkipValidationsLambdaEnum end class SkipValidationsLambdaWithParamUser < ActiveRecord::Base self.table_name = "users" include SkipValidationsLambdaWithParamEnum end describe Enumerize::ActiveRecordSupport do it 'sets nil if invalid value is passed' do user = User.new user.sex = :invalid expect(user.sex).must_be_nil end it 'saves value' do User.delete_all user = User.new user.sex = :female user.save! expect(user.sex).must_equal 'female' end it 'loads value' do User.delete_all User.create!(:sex => :male) store_translations(:en, :enumerize => {:sex => {:male => 'Male'}}) do user = User.first expect(user.sex).must_equal 'male' expect(user.sex_text).must_equal 'Male' end end it 'sets nil if invalid stored attribute value is passed' do user = User.new user.language = :invalid expect(user.language).must_be_nil end it 'saves stored attribute value' do User.delete_all user = User.new user.language = :en user.save! user.reload expect(user.language).must_equal 'en' end it 'has default value' do expect(User.new.role).must_equal 'user' expect(User.new.attributes['role']).must_equal 'user' end it 'does not set default value for not selected attributes' do User.delete_all User.create!(:sex => :male) user = User.select(:id).first expect(user.attributes['role']).must_be_nil expect(user.attributes['lambda_role']).must_be_nil end it 'has default value with lambda' do expect(User.new.lambda_role).must_equal 'admin' expect(User.new.attributes['lambda_role']).must_equal 'admin' end it 'uses after_initialize callback to set default value' do User.delete_all User.create!(sex: 'male', lambda_role: nil) user = User.where(:sex => 'male').first expect(user.lambda_role).must_equal 'admin' end it 'uses default value from db column' do expect(User.new.account_type).must_equal 'basic' end it 'has default value with default scope' do UserWithDefaultScope = Class.new(User) do default_scope -> { having_role(:user) } end expect(UserWithDefaultScope.new.role).must_equal 'user' expect(UserWithDefaultScope.new.attributes['role']).must_equal 'user' end it 'validates inclusion' do user = User.new user.role = 'wrong' expect(user).wont_be :valid? expect(user.errors[:role]).must_include 'is not included in the list' end it 'sets value to enumerized field from db when record is reloaded' do user = User.create!(interests: [:music]) User.find(user.id).update(interests: %i[music dancing]) expect(user.interests).must_equal %w[music] user.reload expect(user.interests).must_equal %w[music dancing] end it 'validates inclusion when using write_attribute with string attribute' do user = User.new user.send(:write_attribute, 'role', 'wrong') expect(user.read_attribute_for_validation(:role)).must_equal 'wrong' expect(user).wont_be :valid? expect(user.errors[:role]).must_include 'is not included in the list' end it 'validates inclusion when using write_attribute with symbol attribute' do user = User.new user.send(:write_attribute, :role, 'wrong') expect(user.read_attribute_for_validation(:role)).must_equal 'wrong' expect(user).wont_be :valid? expect(user.errors[:role]).must_include 'is not included in the list' end it 'validates inclusion on mass assignment' do assert_raises ActiveRecord::RecordInvalid do User.create!(role: 'wrong') end end it "uses persisted value for validation if it hasn't been set" do user = User.create! :sex => :male expect(User.find(user.id).read_attribute_for_validation(:sex)).must_equal 'male' end it 'is valid with empty string assigned' do user = User.new user.role = '' expect(user).must_be :valid? end it 'stores nil when empty string assigned' do user = User.new user.role = '' expect(user.read_attribute(:role)).must_be_nil end it 'validates inclusion when :skip_validations = false' do user = DoNotSkipValidationsUser.new user.foo = 'wrong' expect(user).wont_be :valid? expect(user.errors[:foo]).must_include 'is not included in the list' end it 'does not validate inclusion when :skip_validations = true' do user = SkipValidationsUser.new user.foo = 'wrong' expect(user).must_be :valid? end it 'supports :skip_validations option as lambda' do user = SkipValidationsLambdaUser.new user.foo = 'wrong' expect(user).must_be :valid? end it 'supports :skip_validations option as lambda with a parameter' do user = SkipValidationsLambdaWithParamUser.new user.foo = 'wrong' expect(user).must_be :valid? end it 'supports multiple attributes' do user = User.new expect(user.interests).must_be_empty user.interests << :music expect(user.interests).must_equal %w(music) user.save! user = User.find(user.id) expect(user.interests).must_be_instance_of Enumerize::Set expect(user.interests).must_equal %w(music) user.interests << :sports expect(user.interests).must_equal %w(music sports) user.interests = [] interests = user.interests interests << :music expect(interests).must_equal %w(music) interests << :dancing expect(interests).must_equal %w(music dancing) end it 'stores multiple value passed passed to new' do user = User.new(interests: [:music, :dancing]) user.save! expect(user.interests).must_equal %w(music dancing) expect(User.find(user.id).interests).must_equal %w(music dancing) end it 'returns invalid multiple value for validation' do user = User.new user.interests << :music user.interests << :invalid values = user.read_attribute_for_validation(:interests) expect(values).must_equal %w(music invalid) end it 'validates multiple attributes' do user = User.new user.interests << :invalid expect(user).wont_be :valid? user.interests = Object.new expect(user).wont_be :valid? user.interests = ['music', ''] expect(user).must_be :valid? end it 'stores custom values for multiple attributes' do User.delete_all klass = Class.new(User) do def self.name 'UserSubclass' end end klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true user = klass.new user.interests << :music expect(user.read_attribute(:interests)).must_equal [0] expect(user.interests).must_equal %w(music) user.save user = klass.find(user.id) expect(user.interests).must_equal %w(music) end it 'adds scope' do User.delete_all user_1 = User.create!(sex: :female, skill: :noob, status: :active, role: :admin) user_2 = User.create!(sex: :female, skill: :casual, status: :blocked) user_3 = User.create!(sex: :male, skill: :pro) expect(User.with_status(:active)).must_equal [user_1] expect(User.with_status(:blocked)).must_equal [user_2] expect(User.with_status(:active, :blocked).to_set).must_equal [user_1, user_2].to_set expect(User.without_status(:active)).must_equal [user_2] expect(User.without_status(:active, :blocked)).must_equal [] expect(User.male).must_equal [user_3] expect(User.pro).must_equal [user_3] expect(User.not_male.to_set).must_equal [user_1, user_2].to_set expect(User.not_pro.to_set).must_equal [user_1, user_2].to_set end it 'ignores not enumerized values that passed to the scope method' do User.delete_all expect(User.with_status(:foo)).must_equal [] end it 'allows either key or value as valid' do user_1 = User.new(status: :active) user_2 = User.new(status: 1) user_3 = User.new(status: '1') expect(user_1.status).must_equal 'active' expect(user_2.status).must_equal 'active' expect(user_3.status).must_equal 'active' expect(user_1).must_be :valid? expect(user_2).must_be :valid? expect(user_3).must_be :valid? end it 'supports defining enumerized attributes on abstract class' do Document.delete_all document = Document.new document.visibility = :protected expect(document.visibility).must_equal 'protected' end it 'supports defining enumerized scopes on abstract class' do Document.delete_all document_1 = Document.create!(visibility: :public) document_2 = Document.create!(visibility: :private) expect(Document.with_visibility(:public)).must_equal [document_1] end it 'validates uniqueness' do user = User.new user.status = :active user.save! user = UniqStatusUser.new user.status = :active user.valid? expect(user.errors[:status]).wont_be :empty? end it 'validates presence with multiple attributes' do user = InterestsRequiredUser.new user.interests = [] user.valid? expect(user.errors[:interests]).wont_be :empty? user.interests = [''] user.valid? expect(user.errors[:interests]).wont_be :empty? user.interests = [:dancing, :programming] user.valid? expect(user.errors[:interests]).must_be_empty end it 'is valid after #becomes' do User.delete_all user = User.new user.sex = :male user.save! uniq_user = User.find(user.id).becomes(UniqStatusUser) uniq_user.valid? expect(uniq_user.errors).must_be_empty end it 'supports multiple attributes in #becomes' do User.delete_all uniq_user = UniqStatusUser.new uniq_user.interests = [:sports, :dancing] uniq_user.sex = :male uniq_user.save! user = uniq_user.becomes(User) expect(user.sex).must_equal uniq_user.sex expect(user.interests).must_equal uniq_user.interests end it "doesn't update record" do Document.delete_all expected = Time.utc(2010, 10, 10) document = Document.new document.updated_at = expected document.save! document = Document.last document.save! assert_equal expected, document.updated_at end it 'changes from dirty should be serialized as scalar values' do user = User.create(:status => :active) user.status = :blocked assert_equal [1, 2], YAML.load(user.changes.to_yaml)[:status] end it 'does not change by the practical same value' do user = User.create!(status: 'active') user.reload user.status = 'active' expect(user.changes).must_be_empty end it 'allows using update_all' do User.delete_all user = User.create(status: :active, account_type: :premium) User.update_all(status: :blocked) user.reload expect(user.status).must_equal 'blocked' User.update_all(status: :active, account_type: :basic) user.reload expect(user.status).must_equal 'active' expect(user.account_type).must_equal 'basic' end it 'allows using update_all for multiple enumerize' do User.delete_all klass = Class.new(User) do def self.name 'UserSubclass' end end klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true user = klass.create(status: :active) klass.update_all(status: :blocked, interests: [:music, :dancing]) user = klass.find(user.id) expect(user.status).must_equal 'blocked' expect(user.interests).must_equal %w(music dancing) end it 'allows using update_all with values' do User.delete_all user = User.create(status: :active) User.update_all(status: 2) user.reload expect(user.status).must_equal 'blocked' end it 'allows using update_all on relation objects' do User.delete_all user = User.create(status: :active, account_type: :premium) User.all.update_all(status: :blocked) user.reload expect(user.status).must_equal 'blocked' end it 'allows using update_all on association relation objects' do User.delete_all Document.delete_all user = User.create document = Document.create(user: user, status: :draft) user.documents.update_all(status: :release) document.reload expect(document.status).must_equal 'release' end it 'preserves string usage of update_all' do User.delete_all user = User.create(name: "Fred") User.update_all("name = 'Frederick'") user.reload expect(user.name).must_equal 'Frederick' end it 'preserves interpolated array usage of update_all' do User.delete_all user = User.create(name: "Fred") User.update_all(["name = :name", {name: 'Frederick'}]) user.reload expect(user.name).must_equal 'Frederick' end it 'sets attribute to nil if given one is not valid' do User.delete_all user = User.create(status: :active) User.update_all(status: :foo) user.reload expect(user.status).must_be_nil end it 'supports AR types serialization' do type = User.type_for_attribute('status') expect(type).must_be_instance_of Enumerize::ActiveRecordSupport::Type serialized = type.serialize('blocked') expect(serialized).must_equal 2 end it 'has AR type itself JSON serializable' do type = User.type_for_attribute('status') expect(type.as_json['attr']).must_equal 'status' end it "doesn't break YAML serialization" do user = YAML.load(User.create(status: :blocked).to_yaml) expect(user.status).must_equal 'blocked' end # https://github.com/brainspec/enumerize/issues/304 it "fallbacks to a raw passed value if AR type can't find value in the attribute" do table = User.arel_table sql = User.where(table[:account_type].matches '%foo%').to_sql expect(sql).must_include 'LIKE \'%foo%\'' end if Rails::VERSION::MAJOR >= 6 it 'supports AR#insert_all' do User.delete_all User.insert_all([{ sex: :male }]) User.insert_all([{ status: :active }]) User.insert_all([{ interests: [:music, :sports] }]) expect(User.exists?(sex: :male)).must_equal true expect(User.exists?(status: :active)).must_equal true expect(User.exists?(interests: [:music, :sports])).must_equal true end it 'supports AR#upsert_all' do User.delete_all User.upsert_all([{ sex: :male }]) User.upsert_all([{ status: :active }]) User.upsert_all([{ interests: [:music, :sports] }]) expect(User.exists?(sex: :male)).must_equal true expect(User.exists?(status: :active)).must_equal true expect(User.exists?(interests: [:music, :sports])).must_equal true end end end ruby-enumerize-2.5.0/test/attribute_map_test.rb000066400000000000000000000027501432207762100217130ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' module Enumerize class AttributeMapTest < MiniTest::Spec subject { AttributeMap.new } def make_attr(name) Attribute.new(nil, name, :in => %[a b]) end it 'empty when no attrs' do expect(subject).must_be_empty end it 'not empty when attr added' do subject << make_attr(:a) expect(subject).wont_be_empty end it 'iterates over added attrs' do attr_1 = make_attr(:a) attr_2 = make_attr(:b) subject << attr_1 subject << attr_2 count = 0 actual = [] subject.each do |element| count += 1 actual << element end expect(count).must_equal 2 expect(actual).must_equal [attr_1, attr_2] end it 'reads attribute by name' do attr = make_attr(:a) subject << attr expect(subject[:a]).must_equal attr end it 'reads attribute by name using string' do attr = make_attr(:a) subject << attr expect(subject['a']).must_equal attr end it 'updates dependants' do attr = make_attr(:a) dependant = MiniTest::Mock.new dependant.expect(:<<, nil, [attr]) subject.add_dependant dependant subject << attr dependant.verify end it 'adds attrs to dependant' do attr = make_attr(:a) subject << attr dependant = AttributeMap.new subject.add_dependant dependant expect(dependant[:a]).must_equal attr end end end ruby-enumerize-2.5.0/test/attribute_test.rb000066400000000000000000000102751432207762100210570ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' describe Enumerize::Attribute do def attr @attr ||= nil end def build_attr(*args, &block) @attr = Enumerize::Attribute.new(*args, &block) end it 'returns values' do build_attr nil, :foo, :in => [:a, :b] expect(attr.values).must_equal %w[a b] end it 'returns frozen values' do build_attr nil, :foo, :in => [:a, :b] expect(attr.values.map(&:frozen?)).must_equal [true, true] end it 'converts name to symbol' do build_attr nil, 'foo', :in => %w[a b] expect(attr.name).must_equal :foo end it 'uses custom value class' do value_class = Class.new(Enumerize::Value) build_attr nil, 'foo', :in => %w[a b], :value_class => value_class expect(attr.values.first).must_be_instance_of value_class end describe 'i18n scopes' do it 'returns scopes from options' do build_attr nil, 'foo', :in => %w[a b], :i18n_scope => %w[bar buzz] expect(attr.i18n_scopes).must_equal %w[bar buzz] end it 'accepts only string scopes' do expect(proc { build_attr nil, 'foo', :in => %w[a b], :i18n_scope => [%w[bar buzz], "bar.buzz"] }).must_raise ArgumentError end end describe 'options for select' do it 'returns all options for select' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do build_attr nil, :foo, :in => %w[a b] expect(attr.options).must_equal [['a text', 'a'], ['b text', 'b']] end end it 'returns requested options for select via :only' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do build_attr nil, :foo, :in => %w[a b] expect(attr.options(:only => :a)).must_equal [['a text', 'a']] expect(attr.options(:only => [:b])).must_equal [['b text', 'b']] expect(attr.options(:only => [])).must_equal [] end end it 'returns requested options for select via :except' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do build_attr nil, :foo, :in => %w[a b] expect(attr.options(:except => :a)).must_equal [['b text', 'b']] expect(attr.options(:except => :b)).must_equal [['a text', 'a']] expect(attr.options(:except => [])).must_equal [['a text', 'a'], ['b text', 'b']] end end it 'does not work with both :only and :except' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do build_attr nil, :foo, :in => %w[a b] expect(proc { attr.options(:except => [], :only => []) }).must_raise ArgumentError end end end describe 'values hash' do before do build_attr nil, :foo, :in => {:a => 1, :b => 2} end it 'returns hash keys as values' do expect(attr.values).must_equal %w[a b] end it 'finds values by hash values' do expect(attr.find_value(1)).must_equal 'a' expect(attr.find_value(2)).must_equal 'b' end end it 'sets up shortcut methods for each value' do build_attr nil, :foo, :in => {:a => 1, :b => 2} expect(attr).must_respond_to :a expect(attr).must_respond_to :b expect(attr.a.value).must_equal 1 expect(attr.b.value).must_equal 2 expect(attr.a.text).must_equal 'A' expect(attr.b.text).must_equal 'B' end describe 'values hash with zero' do before do build_attr nil, :foo, :in => {:a => 1, :b => 2, :c => 0} end it 'returns hash keys as values' do expect(attr.values).must_equal %w[a b c] end it 'finds values by hash values' do expect(attr.find_value(1)).must_equal 'a' expect(attr.find_value(2)).must_equal 'b' expect(attr.find_value(0)).must_equal 'c' end it 'finds all values by hash values' do expect(attr.find_values(1, 2, 0)).must_equal ['a', 'b', 'c'] end end describe 'boolean values hash' do before do build_attr nil, :foo, :in => {:a => true, :b => false} end it 'returns hash keys as values' do expect(attr.values).must_equal %w[a b] end it 'finds values by hash values' do expect(attr.find_value(true)).must_equal 'a' expect(attr.find_value(false)).must_equal 'b' end end end ruby-enumerize-2.5.0/test/base_test.rb000066400000000000000000000127611432207762100177700ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' describe Enumerize::Base do let(:kklass) do Class.new do extend Enumerize end end let(:subklass) do Class.new(kklass) end let(:object) { kklass.new } it 'returns nil when not set' do kklass.enumerize(:foo, :in => [:a, :b]) expect(object.foo).must_be_nil end it 'returns value that was set' do kklass.enumerize(:foo, :in => [:a, :b]) object.foo = :a expect(object.foo).must_equal 'a' end it 'returns translation' do store_translations(:en, :enumerize => {:foo => {:a => 'a text'}}) do kklass.enumerize(:foo, :in => [:a, :b]) object.foo = :a expect(object.foo.text).must_equal 'a text' expect(object.foo_text).must_equal 'a text' expect(object.foo_text).must_equal 'a text' end end it 'returns nil as translation when value is nil' do store_translations(:en, :enumerize => {:foo => {:a => 'a text'}}) do kklass.enumerize(:foo, :in => [:a, :b]) expect(object.foo_text).must_be_nil end end it 'scopes translation by i18n key' do def kklass.model_name name = String.new("ExampleClass") def name.i18n_key 'example_class' end name end store_translations(:en, :enumerize => {:example_class => {:foo => {:a => 'a text scoped'}}}) do kklass.enumerize(:foo, :in => [:a, :b]) object.foo = :a expect(object.foo.text).must_equal 'a text scoped' expect(object.foo_text).must_equal 'a text scoped' end end it 'returns humanized value if there are no translations' do store_translations(:en, :enumerize => {}) do kklass.enumerize(:foo, :in => [:a, :b]) object.foo = :a expect(object.foo_text).must_equal 'A' end end it 'stores value as string' do kklass.enumerize(:foo, :in => [:a, :b]) object.foo = :a expect(object.instance_variable_get(:@foo)).must_be_instance_of String end it 'handles default value' do kklass.enumerize(:foo, :in => [:a, :b], :default => :b) expect(object.foo).must_equal 'b' end it 'handles default value with lambda' do kklass.enumerize(:foo, :in => [:a, :b], :default => lambda { :b }) expect(object.foo).must_equal 'b' end it 'injects object instance into lamda default value' do kklass.enumerize(:foo, :in => [:a, :b], :default => lambda { |obj| :b if obj.is_a? kklass }) expect(object.foo).must_equal 'b' end it 'raises exception on invalid default value' do expect(proc { kklass.enumerize(:foo, :in => [:a, :b], :default => :c) }).must_raise ArgumentError end it 'has enumerized attributes' do expect(kklass.enumerized_attributes).must_be_empty kklass.enumerize(:foo, :in => %w[a b]) expect(kklass.enumerized_attributes[:foo]).must_be_instance_of Enumerize::Attribute end it "doesn't override existing method" do method = kklass.method(:name) kklass.enumerize(:name, :in => %w[a b], :default => 'a') expect(kklass.method(:name)).must_equal method end it "inherits enumerized attributes from a parent class" do kklass.enumerize(:foo, :in => %w[a b]) expect(subklass.enumerized_attributes[:foo]).must_be_instance_of Enumerize::Attribute end it "inherits enumerized attributes from a grandparent class" do kklass.enumerize(:foo, :in => %w[a b]) expect(Class.new(subklass).enumerized_attributes[:foo]).must_be_instance_of Enumerize::Attribute end it "doesn't add enumerized attributes to parent class" do kklass.enumerize(:foo, :in => %w[a b]) subklass.enumerize(:bar, :in => %w[c d]) expect(kklass.enumerized_attributes[:bar]).must_be_nil end it 'adds new parent class attributes to subclass' do subklass = Class.new(kklass) kklass.enumerize :foo, :in => %w[a b] expect(subklass.enumerized_attributes[:foo]).must_be_instance_of Enumerize::Attribute end it 'stores nil value' do kklass.enumerize(:foo, :in => [:a, :b]) object.foo = nil expect(object.instance_variable_get(:@foo)).must_be_nil end it 'casts value to string for validation' do kklass.enumerize(:foo, :in => [:a, :b]) object.foo = :c expect(object.read_attribute_for_validation(:foo)).must_equal 'c' end it "doesn't cast nil to string for validation" do kklass.enumerize(:foo, :in => [:a, :b]) object.foo = nil expect(object.read_attribute_for_validation(:foo)).must_be_nil end it 'calls super in the accessor method' do accessors = Module.new do def attributes @attributes ||= {} end def foo attributes[:foo] end def foo=(v) attributes[:foo] = v end end klass = Class.new do include accessors extend Enumerize enumerize :foo, :in => %w[test] end object = klass.new expect(object.foo).must_be_nil expect(object.attributes).must_equal({}) object.foo = 'test' expect(object.foo).must_equal 'test' expect(object.attributes).must_equal(:foo => 'test') end it 'stores hash values' do kklass.enumerize(:foo, :in => {:a => 1, :b => 2}) object.foo = :a expect(object.instance_variable_get(:@foo)).must_equal 1 expect(object.foo).must_equal 'a' object.foo = :b expect(object.instance_variable_get(:@foo)).must_equal 2 expect(object.foo).must_equal 'b' end it 'returns custom value' do kklass.enumerize(:foo, :in => {:a => 1, :b => 2}) object.foo = :a expect(object.foo_value).must_equal 1 object.foo = :b expect(object.foo_value).must_equal 2 end end ruby-enumerize-2.5.0/test/formtastic_test.rb000066400000000000000000000072301432207762100212240ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' Formtastic::FormBuilder.action_class_finder = Formtastic::ActionClassFinder Formtastic::FormBuilder.input_class_finder = Formtastic::InputClassFinder class FormtasticSpec < MiniTest::Spec include ViewTestHelper include Formtastic::Helpers::FormHelper class Thing < Struct.new(:name) extend ActiveModel::Naming include ActiveModel::Conversion def persisted? false end end class User < Struct.new(:sex, :age) extend ActiveModel::Naming include ActiveModel::Conversion extend Enumerize enumerize :sex, :in => [:male, :female] def persisted? false end end class Post < Struct.new(:category, :title) extend ActiveModel::Naming include ActiveModel::Conversion extend Enumerize enumerize :categories, :in => [:music, :games], :multiple => true def persisted? false end end class Registration < Struct.new(:sex) extend Enumerize enumerize :sex, in: [:male, :female] end before { $VERBOSE = nil } after { $VERBOSE = true } let(:user) { User.new } let(:post) { Post.new } it 'renders select with enumerized values' do concat(semantic_form_for(user) do |f| f.input :sex end) assert_select 'select option[value=male]' assert_select 'select option[value=female]' end it 'renders multiple select with enumerized values' do concat(semantic_form_for(post) do |f| f.input(:categories) end) assert_select 'select[multiple=multiple]' assert_select 'select option[value=music]' assert_select 'select option[value=games]' end it 'renders multiple select with selected enumerized value' do post.categories << :music concat(semantic_form_for(post) do |f| f.input(:categories) end) assert_select 'select[multiple=multiple]' assert_select 'select option[value=music][selected=selected]' assert_select 'select option[value=games][selected=selected]', count: 0 end it 'renders checkboxes with enumerized values' do concat(semantic_form_for(post) do |f| f.input(:categories, as: :check_boxes) end) assert_select 'select[multiple=multiple]', count: 0 assert_select 'input[type=checkbox][value=music]' assert_select 'input[type=checkbox][value=games]' end it 'renders checkboxes with selected enumerized value' do post.categories << :music concat(semantic_form_for(post) do |f| f.input(:categories, as: :check_boxes) end) assert_select 'input[type=checkbox][value=music][checked=checked]' assert_select 'input[type=checkbox][value=games][checked=checked]', count: 0 end it 'renders radio buttons with enumerized values' do concat(semantic_form_for(user) do |f| f.input :sex, :as => :radio end) assert_select 'input[type=radio][value=male]' assert_select 'input[type=radio][value=female]' end it 'does not affect not enumerized attributes' do concat(semantic_form_for(user) do |f| f.input(:age) end) assert_select 'input[type=text]' end it 'does not affect not enumerized classes' do concat(semantic_form_for(Thing.new) do |f| f.input(:name) end) assert_select 'input[type=text]' end it 'renders select with enumerized values for non-ActiveModel object' do concat(semantic_form_for(Registration.new, as: 'registration', url: '/') do |f| f.input(:sex) end) assert_select 'select option[value=male]' assert_select 'select option[value=female]' end it 'does not affect forms without object' do concat(semantic_form_for('') do |f| f.input(:name) end) assert_select 'input[type=text]' end end ruby-enumerize-2.5.0/test/module_attributes_test.rb000066400000000000000000000026061432207762100226060ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' class ModuleAttributesSpec < MiniTest::Spec it 'inherits attribute from the module' do mod = Module.new do extend Enumerize enumerize :sex, :in => %w[male female], :default => 'male' end klass = Class.new klass.send :include, mod expect(klass.enumerized_attributes[:sex]).must_be_instance_of Enumerize::Attribute expect(klass.new.sex).must_equal 'male' expect(klass.sex).must_be_instance_of Enumerize::Attribute end it 'uses new attributes from the module' do mod = Module.new do extend Enumerize end klass = Class.new klass.send :include, mod mod.enumerize :sex, :in => %w[male female], :default => 'male' expect(klass.enumerized_attributes[:sex]).must_be_instance_of Enumerize::Attribute expect(klass.new.sex).must_equal 'male' expect(klass.sex).must_be_instance_of Enumerize::Attribute end it 'validates attributes' do mod = Module.new do extend Enumerize enumerize :sex, :in => %w[male female] end klass = Class.new do include ActiveModel::Validations include mod def self.model_name ActiveModel::Name.new(self, nil, 'name') end end object = klass.new object.sex = 'wrong' expect(object).wont_be :valid? expect(object.errors[:sex]).must_include 'is not included in the list' end end ruby-enumerize-2.5.0/test/mongo_mapper_test.rb000066400000000000000000000033611432207762100215350ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' begin silence_warnings do require 'mongo_mapper' end MongoMapper.connection = Mongo::Client.new(['localhost:27017'], database: 'enumerize-test-suite-of-mongomapper') describe Enumerize do class MongoMapperUser include MongoMapper::Document extend Enumerize key :sex key :role key :foo enumerize :sex, :in => %w[male female] enumerize :role, :in => %w[admin user], :default => 'user' enumerize :foo, :in => %w[bar baz], :skip_validations => true end before { $VERBOSE = nil } after { $VERBOSE = true } let(:model) { MongoMapperUser } it 'sets nil if invalid value is passed' do user = model.new user.sex = :invalid expect(user.sex).must_be_nil end it 'saves value' do model.delete_all user = model.new user.sex = :female user.save! expect(user.sex).must_equal 'female' end it 'loads value' do model.delete_all model.create!(:sex => :male) store_translations(:en, :enumerize => {:sex => {:male => 'Male'}}) do user = model.first expect(user.sex).must_equal 'male' expect(user.sex_text).must_equal 'Male' end end it 'has default value' do expect(model.new.role).must_equal 'user' end it 'validates inclusion' do user = model.new user.role = 'wrong' expect(user).wont_be :valid? end it 'does not validate inclusion when :skip_validations option passed' do user = model.new user.foo = 'wrong' expect(user).must_be :valid? end it 'assigns value on loaded record' do model.delete_all model.create!(:sex => :male) user = model.first user.sex = :female expect(user.sex).must_equal 'female' end end rescue LoadError # Skip end ruby-enumerize-2.5.0/test/mongoid_test.rb000066400000000000000000000110751432207762100205070ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' begin silence_warnings do require 'mongoid' end Mongoid.configure do |config| config.connect_to('enumerize-test-suite') config.options = { use_utc: true, include_root_in_json: true } end describe Enumerize do class MongoidUser include Mongoid::Document extend Enumerize field :sex field :role field :foo field :skill enumerize :sex, :in => %w[male female], scope: true enumerize :status, :in => %w[notice warning error], scope: true enumerize :role, :in => %w[admin user], :default => 'user', scope: :having_role enumerize :mult, :in => %w[one two three four], :multiple => true enumerize :foo, :in => %w[bar baz], :skip_validations => true enumerize :skill, :in => { noob: 0, casual: 1, pro: 2 }, scope: :shallow enumerize :account_type, :in => %w[basic premium], scope: :shallow end before { $VERBOSE = nil } after { $VERBOSE = true } let(:model) { MongoidUser } it 'sets nil if invalid value is passed' do user = model.new user.sex = :invalid expect(user.sex).must_be_nil end it 'saves value' do model.delete_all user = model.new user.sex = :female user.save! expect(user.sex).must_equal 'female' end it 'loads value' do model.delete_all model.create!(:sex => :male) store_translations(:en, :enumerize => {:sex => {:male => 'Male'}}) do user = model.first expect(user.sex).must_equal 'male' expect(user.sex_text).must_equal 'Male' end end it 'has default value' do expect(model.new.role).must_equal 'user' end it 'uses after_initialize callback to set default value' do model.delete_all model.create!(sex: 'male', role: nil) user = model.where(sex: 'male').first expect(user.role).must_equal 'user' end it 'does not set default value for not selected attributes' do model.delete_all model.create!(sex: :male) assert_equal ['_id'], model.only(:id).first.attributes.keys end it 'validates inclusion' do user = model.new user.role = 'wrong' expect(user).wont_be :valid? end it 'does not validate inclusion when :skip_validations option passed' do user = model.new user.foo = 'wrong' expect(user).must_be :valid? end it 'sets value to enumerized field from db when record is reloaded' do user = model.create!(mult: [:one]) model.find(user.id).update(mult: %i[two three]) expect(user.mult).must_equal %w[one] user.reload expect(user.mult).must_equal %w[two three] end it 'assigns value on loaded record' do model.delete_all model.create!(:sex => :male) user = model.first user.sex = :female expect(user.sex).must_equal 'female' end it 'loads multiple properly' do model.delete_all model.create!(:mult => ['one', 'two']) user = model.first expect(user.mult.to_a).must_equal ['one', 'two'] end it 'adds scope' do model.delete_all user_1 = model.create!(sex: :male, skill: :noob, role: :admin, account_type: :basic) user_2 = model.create!(sex: :female, skill: :noob, role: :user, account_type: :basic) user_3 = model.create!(skill: :pro, account_type: :premium) expect(model.with_sex(:male).to_a).must_equal [user_1] expect(model.with_sex(:female).to_a).must_equal [user_2] expect(model.with_sex(:male, :female).to_set).must_equal [user_1, user_2].to_set expect(model.without_sex(:male).to_set).must_equal [user_2, user_3].to_set expect(model.without_sex(:female).to_set).must_equal [user_1, user_3].to_set expect(model.without_sex(:male, :female).to_a).must_equal [user_3] expect(model.having_role(:admin).to_a).must_equal [user_1] expect(model.having_role(:user).to_a).must_equal [user_2, user_3] expect(model.pro.to_a).must_equal [user_3] expect(model.premium.to_a).must_equal [user_3] expect(model.not_pro.to_set).must_equal [user_1, user_2].to_set expect(model.not_premium.to_set).must_equal [user_1, user_2].to_set end it 'chains scopes' do model.delete_all user_1 = model.create!(status: :notice) user_2 = model.create!(status: :warning) user_3 = model.create!(status: :error) expect(model.with_status(:notice, :warning).with_status(:notice, :error).to_a).must_equal [user_1] expect(model.with_status(:notice, :warning).union.with_status(:notice, :error).to_a).must_equal [user_1, user_2, user_3] end it 'ignores not enumerized values that passed to the scope method' do model.delete_all expect(model.with_sex(:foo)).must_equal [] end end rescue LoadError # Skip end ruby-enumerize-2.5.0/test/multiple_test.rb000066400000000000000000000032711432207762100207050ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' describe Enumerize::Base do let(:kklass) do Class.new do extend Enumerize end end let(:subklass) do Class.new(kklass) end let(:object) { kklass.new } it 'returns [] when not set' do kklass.enumerize :foos, in: %w(a b), multiple: true expect(object.foos).must_equal [] end it 'returns setted array' do kklass.enumerize :foos, in: %w(a b c), multiple: true object.foos = %w(a c) expect(object.foos).must_equal %w(a c) end it 'sets default value as single value' do kklass.enumerize :foos, in: %w(a b c), default: 'b', multiple: true expect(object.foos).must_equal %w(b) end it 'sets default value as array of one element' do kklass.enumerize :foos, in: %w(a b c), default: %w(b), multiple: true expect(object.foos).must_equal %w(b) end it 'sets default value as array of several elements' do kklass.enumerize :foos, in: %w(a b c), default: %w(b c), multiple: true expect(object.foos).must_equal %w(b c) end it "doesn't define _text method" do kklass.enumerize :foos, in: %w(a b c), multiple: true expect(object).wont_respond_to :foos_text end it "doesn't define _value method" do kklass.enumerize :foos, in: %w(a b c), multiple: true expect(object).wont_respond_to :foos_value end it "cannot define multiple with scope" do assert_raises ArgumentError do kklass.enumerize :foos, in: %w(a b c), multiple: true, scope: true end end it 'assign a name with the first letter capitalized' do kklass.enumerize :Foos, in: %w(a b c), multiple: true object.Foos = %w(a c) expect(object.Foos).must_equal %w(a c) end end ruby-enumerize-2.5.0/test/predicates_test.rb000066400000000000000000000035301432207762100211730ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' describe Enumerize::Predicates do let(:kklass) do Class.new do extend Enumerize end end let(:object) { kklass.new } it 'creates predicate methods' do kklass.enumerize(:foo, in: %w(a b), predicates: true) expect(object).must_respond_to :a? expect(object).must_respond_to :b? end it 'creates predicate methods when enumerized values have dash in it' do kklass.enumerize(:foo, in: %w(foo-bar bar-foo), predicates: true) expect(object).must_respond_to :foo_bar? expect(object).must_respond_to :bar_foo? end it 'creates predicate methods on multiple attribute' do kklass.enumerize(:foo, in: %w(a b), predicates: true, multiple: true) expect(object).must_respond_to :a? expect(object).must_respond_to :b? end it 'checks values' do kklass.enumerize(:foo, in: %w(a b), predicates: true) object.foo = 'a' expect(object.a?).must_equal true expect(object.b?).must_equal false end it 'checks values on multiple attribute' do kklass.enumerize(:foo, in: %w(a b), predicates: true, multiple: true) object.foo << :a expect(object.a?).must_equal true expect(object.b?).must_equal false end it 'prefixes methods' do kklass.enumerize(:foo, in: %w(a b), predicates: { prefix: 'bar' }) expect(object).wont_respond_to :a? expect(object).wont_respond_to :b? expect(object).must_respond_to :bar_a? expect(object).must_respond_to :bar_b? end it 'accepts only option' do kklass.enumerize(:foo, in: %w(a b), predicates: { only: :a }) expect(object).must_respond_to :a? expect(object).wont_respond_to :b? end it 'accepts except option' do kklass.enumerize(:foo, in: %w(a b), predicates: { except: :a }) expect(object).wont_respond_to :a? expect(object).must_respond_to :b? end end ruby-enumerize-2.5.0/test/rails_admin_test.rb000066400000000000000000000013541432207762100213340ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' class RailsAdminSpec < MiniTest::Spec let(:kklass) do Class.new do extend Enumerize end end let(:object) { kklass.new } it 'defines enum method' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do kklass.enumerize(:foo, in: [:a, :b]) expect(object.foo_enum).must_equal [['a text', 'a'], ['b text', 'b']] end end it 'defines enum properly for custom values enumerations' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do kklass.enumerize(:foo, in: {:a => 1, :b => 2}) expect(object.foo_enum).must_equal [['a text', 'a'], ['b text', 'b']] end end end ruby-enumerize-2.5.0/test/sequel_test.rb000066400000000000000000000230751432207762100203540ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' require 'sequel' require 'logger' require 'jdbc/sqlite3' if RUBY_PLATFORM == 'java' module SequelTest silence_warnings do DB = if RUBY_PLATFORM == 'java' Sequel.connect('jdbc:sqlite::memory:') else Sequel.sqlite end DB.loggers << Logger.new(nil) end DB.create_table :users do primary_key :id String :sex String :role String :lambda_role String :name String :interests String :status Integer :skill String :account_type, default: "basic" String :foo end DB.create_table :documents do primary_key :id String :visibility Time :created_at Time :updated_at end class Document < Sequel::Model plugin :enumerize enumerize :visibility, :in => [:public, :private, :protected], :scope => true, :default => :public end module RoleEnum extend Enumerize enumerize :role, :in => [:user, :admin], :default => :user, scope: :having_role enumerize :lambda_role, :in => [:user, :admin], :default => lambda { :admin } end class User < Sequel::Model plugin :serialization, :json, :interests plugin :dirty plugin :defaults_setter plugin :validation_helpers plugin :enumerize include RoleEnum enumerize :sex, :in => [:male, :female], scope: :shallow enumerize :interests, :in => [:music, :sports, :dancing, :programming], :multiple => true enumerize :status, :in => { active: 1, blocked: 2 }, scope: true enumerize :skill, :in => { noob: 0, casual: 1, pro: 2 }, scope: :shallow enumerize :account_type, :in => [:basic, :premium] end class UniqStatusUser < User def validate super validates_unique :status validates_presence :sex end end class SkipValidationsUser < Sequel::Model(:users) include SkipValidationsEnum end class DoNotSkipValidationsUser < Sequel::Model(:users) include DoNotSkipValidationsEnum end class SkipValidationsLambdaUser < Sequel::Model(:users) include SkipValidationsLambdaEnum end class SkipValidationsLambdaWithParamUser < Sequel::Model(:users) include SkipValidationsLambdaWithParamEnum end describe Enumerize::SequelSupport do it 'sets nil if invalid value is passed' do user = User.new user.sex = :invalid expect(user.sex).must_be_nil end it 'saves value' do User.filter{ true }.delete user = User.new user.sex = :female user.save expect(user.sex).must_equal 'female' end it 'loads value' do User.filter{ true }.delete User.create(:sex => :male) store_translations(:en, :enumerize => {:sex => {:male => 'Male'}}) do user = User.first expect(user.sex).must_equal 'male' expect(user.sex_text).must_equal 'Male' end end it 'has default value' do expect(User.new.role).must_equal 'user' expect(User.new.values[:role]).must_equal 'user' end it 'does not set default value for not selected attributes' do User.filter{ true }.delete User.create(:sex => :male) assert_equal [:id], User.select(:id).first.values.keys end it 'has default value with lambda' do expect(User.new.lambda_role).must_equal 'admin' expect(User.new.values[:lambda_role]).must_equal 'admin' end it 'uses after_initialize callback to set default value' do User.filter{ true }.delete User.create(sex: 'male', lambda_role: nil) user = User.where(:sex => 'male').first expect(user.lambda_role).must_equal 'admin' end it 'uses default value from db column' do expect(User.new.account_type).must_equal 'basic' end it 'validates inclusion' do user = User.new user.role = 'wrong' expect(user).wont_be :valid? expect(user.errors[:role]).must_include 'is not included in the list' end it 'validates inclusion on mass assignment' do assert_raises Sequel::ValidationFailed do User.create(role: 'wrong') end end it "uses persisted value for validation if it hasn't been set" do user = User.create :sex => :male expect(User[user.id].read_attribute_for_validation(:sex)).must_equal 'male' end it 'is valid with empty string assigned' do user = User.new user.role = '' expect(user).must_be :valid? end it 'stores nil when empty string assigned' do user = User.new user.role = '' expect(user.values[:role]).must_be_nil end it 'validates inclusion when :skip_validations = false' do user = DoNotSkipValidationsUser.new user.foo = 'wrong' expect(user).wont_be :valid? expect(user.errors[:foo]).must_include 'is not included in the list' end it 'does not validate inclusion when :skip_validations = true' do user = SkipValidationsUser.new user.foo = 'wrong' expect(user).must_be :valid? end it 'supports :skip_validations option as lambda' do user = SkipValidationsLambdaUser.new user.foo = 'wrong' expect(user).must_be :valid? end it 'supports :skip_validations option as lambda with a parameter' do user = SkipValidationsLambdaWithParamUser.new user.foo = 'wrong' expect(user).must_be :valid? end it 'supports multiple attributes' do user = User.new user.interests ||= [] expect(user.interests).must_be_empty user.interests << "music" expect(user.interests).must_equal %w(music) user.save user = User[user.id] expect(user.interests).must_be_instance_of Enumerize::Set expect(user.interests).must_equal %w(music) user.interests << "sports" expect(user.interests).must_equal %w(music sports) user.interests = [] interests = user.interests interests << "music" expect(interests).must_equal %w(music) interests << "dancing" expect(interests).must_equal %w(music dancing) end it 'returns invalid multiple value for validation' do user = User.new user.interests << :music user.interests << :invalid values = user.read_attribute_for_validation(:interests) expect(values).must_equal %w(music invalid) end it 'validates multiple attributes' do user = User.new user.interests << :invalid expect(user).wont_be :valid? user.interests = Object.new expect(user).wont_be :valid? user.interests = ['music', ''] expect(user).must_be :valid? end it 'stores custom values for multiple attributes' do User.filter{ true }.delete klass = Class.new(User) klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true user = klass.new user.interests << :music expect(user.interests).must_equal %w(music) user.save user = klass[user.id] expect(user.interests).must_equal %w(music) end it 'adds scope' do User.filter{ true }.delete user_1 = User.create(sex: :female, skill: :noob, status: :active, role: :admin) user_2 = User.create(sex: :female, skill: :casual, status: :blocked) user_3 = User.create(sex: :male, skill: :pro) expect(User.with_status(:active).to_a).must_equal [user_1] expect(User.with_status(:blocked).to_a).must_equal [user_2] expect(User.with_status(:active, :blocked).to_set).must_equal [user_1, user_2].to_set expect(User.without_status(:active).to_a).must_equal [user_2] expect(User.without_status(:active, :blocked).to_a).must_equal [] expect(User.having_role(:admin).to_a).must_equal [user_1] expect(User.male.to_a).must_equal [user_3] expect(User.pro.to_a).must_equal [user_3] expect(User.not_male.to_set).must_equal [user_1, user_2].to_set expect(User.not_pro.to_set).must_equal [user_1, user_2].to_set end it 'allows either key or value as valid' do user_1 = User.new(status: :active) user_2 = User.new(status: 1) user_3 = User.new(status: '1') expect(user_1.status).must_equal 'active' expect(user_2.status).must_equal 'active' expect(user_3.status).must_equal 'active' expect(user_1).must_be :valid? expect(user_2).must_be :valid? expect(user_3).must_be :valid? end it 'supports defining enumerized attributes on abstract class' do Document.filter{ true }.delete document = Document.new document.visibility = :protected expect(document.visibility).must_equal 'protected' end it 'supports defining enumerized scopes on abstract class' do Document.filter{ true }.delete document_1 = Document.create(visibility: :public) document_2 = Document.create(visibility: :private) expect(Document.with_visibility(:public).to_a).must_equal [document_1] end it 'validates uniqueness' do user = User.create(status: :active, sex: "male") user = UniqStatusUser.new user.sex = "male" user.status = :active expect(user.valid?).must_equal false expect(user.errors[:status]).wont_be :empty? end it "doesn't update record" do Document.filter{ true }.delete expected = Time.new(2010, 10, 10) document = Document.new document.updated_at = expected document.save document = Document.last document.save assert_equal expected, document.updated_at end it 'changes from dirty should be serialized as scalar values' do user = User.create(:status => :active) user.status = :blocked expected = { status: [1, 2] }.to_yaml assert_equal expected, user.column_changes.to_yaml end end end ruby-enumerize-2.5.0/test/set_test.rb000066400000000000000000000064161432207762100176510ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' require 'yaml' describe Enumerize::Set do let(:kklass) do Class.new do extend Enumerize enumerize :foo, :in => %w(a b c), :multiple => true end end let(:object) { kklass.new } def build_set(values) @set = Enumerize::Set.new(object, kklass.foo, values) end def set @set end def assert_called(object, method) called = false object.singleton_class.class_eval do define_method method do |*args, &block| called = true super(*args, &block) end end yield assert called, "Expected ##{method} to be called" end before do build_set %w(a) end it 'equals to other set' do expect(set).must_equal Enumerize::Set.new(nil, kklass.foo, %w(a)) end it 'equals to array' do expect(set).must_equal %w(a) end it 'equals to array of symbols' do expect(set).must_equal [:a] end it 'has unique values' do set << :a expect(set).must_equal %w(a) end it 'equals to array with different value order' do set << :b expect(set).must_equal %w(b a) end it "isn't equal to a part of values" do set << :b expect(set).wont_equal %w(a) end describe '#push' do it 'appends values' do set.push :b expect(set).must_include :b end it 'reassigns attribute' do assert_called object, :foo= do set.push :b end end end describe '#delete' do it 'deletes value' do set.delete :a expect(set).wont_include :a end it 'reassigns attribute' do assert_called object, :foo= do set.delete :a end end end describe '#inspect' do it 'returns custom string' do set << :b expect(set.inspect).must_equal '#' end end describe '#to_ary' do it 'returns array' do expect(set.to_ary).must_be_instance_of Array end end describe '#texts' do it 'returns array of text values' do expect(set.texts).must_equal ['A'] end end describe '#join' do it 'joins values' do set << :b expect(set.join(', ')).must_equal 'a, b' end end describe 'boolean methods comparison' do it 'returns true if value equals method' do set << :a expect(set.a?).must_equal true end it 'returns false if value does not equal method' do set << :a expect(set.b?).must_equal false end it 'raises NoMethodError if there are no values like boolean method' do expect(proc { set.some_method? }).must_raise NoMethodError end it 'raises ArgumentError if arguments are passed' do expect(proc { set.a?('<3') }).must_raise ArgumentError end it 'responds to methods for existing values' do expect(set).must_respond_to :a? expect(set).must_respond_to :b? expect(set).must_respond_to :c? end it 'returns a method object' do expect(set.method(:a?)).must_be_instance_of Method end it 'does not respond to a method for not existing value' do expect(set).wont_respond_to :some_method? end end describe 'serialization' do it 'is serialized to yaml as array' do set << :a assert_equal YAML.dump(%w(a)), YAML.dump(set) end end end ruby-enumerize-2.5.0/test/simple_form_test.rb000066400000000000000000000073161432207762100213720ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' require 'simple_form/version' class SimpleFormSpec < MiniTest::Spec include ViewTestHelper include SimpleForm::ActionViewExtensions::FormHelper class Thing < Struct.new(:name) extend ActiveModel::Naming include ActiveModel::Conversion def persisted? false end end class User < Struct.new(:sex, :age) extend ActiveModel::Naming include ActiveModel::Conversion extend Enumerize enumerize :sex, :in => [:male, :female] def persisted? false end end class Post < Struct.new(:category, :title) extend ActiveModel::Naming include ActiveModel::Conversion extend Enumerize enumerize :categories, :in => [:music, :games], :multiple => true def persisted? false end end class Registration < Struct.new(:sex) extend Enumerize enumerize :sex, in: [:male, :female] end let(:user) { User.new } let(:post) { Post.new } it 'renders select with enumerized values using input_field' do concat(simple_form_for(user) do |f| f.input_field(:sex) end) assert_select 'select option[value=male]' assert_select 'select option[value=female]' end it 'renders select with enumerized values' do concat(simple_form_for(user) do |f| f.input(:sex) end) assert_select 'select option[value=male]' assert_select 'select option[value=female]' end it 'renders multiple select with enumerized values' do concat(simple_form_for(post) do |f| f.input(:categories) end) assert_select 'select[multiple=multiple]' assert_select 'select option[value=music]' assert_select 'select option[value=games]' end it 'renders multiple select with selected enumerized value' do post.categories << :music concat(simple_form_for(post) do |f| f.input(:categories) end) assert_select 'select[multiple=multiple]' assert_select 'select option[value=music][selected=selected]' assert_select 'select option[value=games][selected=selected]', count: 0 end it 'renders checkboxes with enumerized values' do concat(simple_form_for(post) do |f| f.input(:categories, as: :check_boxes) end) assert_select 'select[multiple=multiple]', count: 0 assert_select 'input[type=checkbox][value=music]' assert_select 'input[type=checkbox][value=games]' end it 'renders checkboxes with selected enumerized value' do post.categories << :music concat(simple_form_for(post) do |f| f.input(:categories, as: :check_boxes) end) assert_select 'input[type=checkbox][value=music][checked=checked]' assert_select 'input[type=checkbox][value=games][checked=checked]', count: 0 end it 'renders radio buttons with enumerated values' do concat(simple_form_for(user) do |f| f.input(:sex, :as => :radio_buttons) end) assert_select 'input[type=radio][value=male]' assert_select 'input[type=radio][value=female]' end it 'does not affect not enumerized attributes' do concat(simple_form_for(user) do |f| f.input(:age) end) assert_select 'input.string' end it 'does not affect not enumerized classes' do concat(simple_form_for(Thing.new) do |f| f.input(:name) end) assert_select 'input.string' end it 'renders select with enumerized values for non-ActiveModel object' do concat(simple_form_for(Registration.new, as: 'registration', url: '/') do |f| f.input(:sex) end) assert_select 'select option[value=male]' assert_select 'select option[value=female]' end it 'does not affect forms without object' do concat(simple_form_for('') do |f| f.input(:name) end) assert_select 'input.string' end end ruby-enumerize-2.5.0/test/support/000077500000000000000000000000001432207762100171775ustar00rootroot00000000000000ruby-enumerize-2.5.0/test/support/mock_controller.rb000066400000000000000000000006001432207762100227140ustar00rootroot00000000000000# frozen_string_literal: true class MockController attr_writer :action_name def _routes self end def action_name defined?(@action_name) ? @action_name : "edit" end def url_for(*args) "http://example.com" end def url_helpers self end def url_options {} end def hash_for_users_path(*); end def polymorphic_mappings {} end end ruby-enumerize-2.5.0/test/support/shared_enums.rb000066400000000000000000000017741432207762100222120ustar00rootroot00000000000000# frozen_string_literal: true require 'active_record' require 'sequel' module EnumerizeExtention def self.included(base) case when base < ActiveRecord::Base base.extend Enumerize when base < Sequel::Model base.plugin :enumerize end end end module SkipValidationsEnum def self.included(base) base.include EnumerizeExtention base.enumerize :foo, :in => [:bar, :baz], :skip_validations => true end end module DoNotSkipValidationsEnum def self.included(base) base.include EnumerizeExtention base.enumerize :foo, :in => [:bar, :baz], :skip_validations => false end end module SkipValidationsLambdaEnum def self.included(base) base.include EnumerizeExtention base.enumerize :foo, :in => [:bar, :baz], :skip_validations => lambda { true } end end module SkipValidationsLambdaWithParamEnum def self.included(base) base.include EnumerizeExtention base.enumerize :foo, :in => [:bar, :baz], :skip_validations => lambda { |record| true } end end ruby-enumerize-2.5.0/test/support/view_test_helper.rb000066400000000000000000000016331432207762100230770ustar00rootroot00000000000000# frozen_string_literal: true require 'active_support/concern' require 'active_support/testing/setup_and_teardown' if defined?(ActionView::RoutingUrlFor) ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor) end module SetupAndTeardownHelper extend ActiveSupport::Concern include ActiveSupport::Testing::SetupAndTeardown included do include ActiveSupport::Callbacks define_callbacks :setup, :teardown end end module ViewTestHelper extend ActiveSupport::Concern include SetupAndTeardownHelper include ActionView::TestCase::Behavior included do setup :set_controller end def set_controller @controller = MockController.new end def method_missing(method, *args) super unless method.to_s =~ /_path$/ end def respond_to?(method, include_private=false) method.to_s =~ /_path$/ || super end def protect_against_forgery? false end end ruby-enumerize-2.5.0/test/test_helper.rb000066400000000000000000000016701432207762100203320ustar00rootroot00000000000000# frozen_string_literal: true require 'minitest/autorun' require 'minitest/spec' require 'active_support/core_ext/kernel/reporting' require 'active_model' require 'rails' begin require 'mongoid' rescue LoadError end module RailsAdmin end require 'simple_form' SimpleForm.setup {} require 'formtastic' module EnumerizeTest class Application < Rails::Application config.active_support.deprecation = :stderr config.active_support.test_order = :random config.eager_load = false config.secret_key_base = 'secret' end end EnumerizeTest::Application.initialize! $VERBOSE=true require 'enumerize' Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file| require file end module MiscHelpers def store_translations(locale, translations, &block) begin I18n.backend.store_translations locale, translations yield ensure I18n.reload! end end end class MiniTest::Spec include MiscHelpers end ruby-enumerize-2.5.0/test/value_test.rb000066400000000000000000000114231432207762100201640ustar00rootroot00000000000000# frozen_string_literal: true require 'test_helper' require 'yaml' describe Enumerize::Value do class Model end class Attr < Struct.new(:values, :name, :i18n_scopes, :klass) end let(:attr) { Attr.new([], "attribute_name", [], Model) } let(:val) { Enumerize::Value.new(attr, 'test_value', 1) } it 'is a string' do expect(val).must_be_kind_of String end describe 'equality' do it 'is compared to string' do expect(val).must_be :==, 'test_value' expect(val).wont_be :==, 'not_value' end it 'is compared to symbol' do expect(val).must_be :==, :test_value expect(val).wont_be :==, :not_value end it 'is compared to integer' do expect(val).must_be :==, 1 expect(val).wont_be :==, 2 end end describe 'translation' do it 'uses common translation' do store_translations(:en, :enumerize => {:attribute_name => {:test_value => "Common translation"}}) do expect(val.text).must_be :==, "Common translation" end end it 'uses default translation from the "default" section if its present' do store_translations(:en, :enumerize => {:defaults => {:attribute_name => {:test_value => "Common translation"}}}) do expect(val.text).must_be :==, "Common translation" end end it 'uses model specific translation' do attr.i18n_scopes = ["enumerize.model_name.attribute_name"] store_translations(:en, :enumerize => {:model_name => {:attribute_name => {:test_value => "Model Specific translation"}}}) do expect(val.text).must_be :==, "Model Specific translation" end end it 'uses model specific translation rather than common translation' do attr.i18n_scopes = ["enumerize.model_name.attribute_name"] store_translations(:en, :enumerize => {:attribute_name => {:test_value => "Common translation"}, :model_name => {:attribute_name => {:test_value => "Model Specific translation"}}}) do expect(val.text).must_be :==, "Model Specific translation" end end it 'uses simply humanized value when translation is undefined' do store_translations(:en, :enumerize => {}) do expect(val.text).must_be :==, "Test value" end end it 'uses specified in options translation scope' do attr.i18n_scopes = ["other.scope"] store_translations(:en, :other => {:scope => {:test_value => "Scope specific translation"}}) do expect(val.text).must_be :==, "Scope specific translation" end end it 'uses first found translation scope from options' do attr.i18n_scopes = ["nonexistent.scope", "other.scope"] store_translations(:en, :other => {:scope => {:test_value => "Scope specific translation"}}) do expect(val.text).must_be :==, "Scope specific translation" end end end describe 'boolean methods comparison' do before do attr.values = [val, Enumerize::Value.new(attr, 'other_value')] end it 'returns true if value equals method' do expect(val.test_value?).must_equal true end it 'returns false if value does not equal method' do expect(val.other_value?).must_equal false end it 'raises NoMethodError if there are no values like boolean method' do expect(proc { val.some_method? }).must_raise NoMethodError end it 'raises ArgumentError if arguments are passed' do expect(proc { val.other_value?('<3') }).must_raise ArgumentError end it 'responds to methods for existing values' do expect(val).must_respond_to :test_value? expect(val).must_respond_to :other_value? end it 'returns a method object' do expect(val.method(:test_value?)).must_be_instance_of Method end it "doesn't respond to a method for not existing value" do expect(val).wont_respond_to :some_method? end it "doesn't respond to methods is value was modified" do modified_value = val.upcase expect(modified_value.upcase).wont_respond_to :some_method? expect(modified_value.upcase).wont_respond_to :test_value? expect(modified_value.upcase).wont_respond_to :other_value? end end describe 'serialization' do let(:val) { Enumerize::Value.new(attr, 'test_value') } it 'should be serialized to yaml as string value' do assert_equal YAML.dump('test_value'), YAML.dump(val) end it 'serializes with Marshal' do dump_value = Marshal.dump(val) expect(Marshal.load(dump_value)).must_equal 'test_value' end end describe 'initialize' do it 'no output if undefined boolean method' do assert_silent() { Enumerize::Value.new(attr, 'test_value') } end it 'error output if defined boolean method' do assert_output(nil, /`empty\?` is defined/) { Enumerize::Value.new(attr, 'empty') } end end end