diff --git a/.rubocop.yml b/.rubocop.yml index 07e6562..2d32269 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -21,6 +21,9 @@ Lint/RaiseException: Lint/StructNewOverride: Enabled: true +Style/Documentation: + Enabled: false + Style/HashEachMethods: Enabled: true @@ -38,20 +41,5 @@ Style/TrailingCommaInArrayLiteral: Enabled: true EnforcedStyleForMultiline: consistent_comma -Metrics/BlockLength: +Metrics: Enabled: false - -Metrics/AbcSize: - Enabled: false - -Metrics/CyclomaticComplexity: - Enabled: false - -Metrics/MethodLength: - Max: 30 - -Metrics/ModuleLength: - Max: 300 - -Metrics/ClassLength: - Max: 300 diff --git a/Gemfile.lock b/Gemfile.lock index 4e0c969..b8a38ce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,9 @@ PATH remote: . specs: - enumbler (0.3.0) - activerecord (>= 6.0) - activesupport (>= 6.0) + enumbler (0.3.1) + activerecord (~> 6.0.2) + activesupport (~> 6.0.2) GEM remote: https://rubygems.org/ diff --git a/README.md b/README.md index 0eb50ac..e7f5f95 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,56 @@ # Enumbler -`Enums` are terrific, but they lack integrity. Enumbler! +`Enums` are terrific, but they lack integrity. Enumbler! The _enum enabler_! The goal is to allow one to maintain a true foreign_key database driven relationship that also behaves a little bit like an `enum`. Best of both worlds? We hope so. + + +## Example + +Suppose you have a `House` and you want to add some `colors` to the house. You are tempted to use an `enum` but the `Enumbler` is calling! + +```ruby +ActiveRecord::Schema.define do + create_table :colors|t| + t.string :label, null: false + end + + create_table :houses|t| + t.references :color, foreign_key: true, null: false + end +end + +class ApplicationRecord < ActiveRecord::Base + include Enumbler + self.abstract_class = true +end + +# Our Color has been Enumbled with some basic colors. +class Color < ApplicationRecord + include Enumbler::Enabler + + enumble :black, 1 + enumble :white, 2 + enumble :dark_brown, 3 + enumble :infinity, 4, label: 'Infinity - and beyond!' +end + +# Our House class, it has a color of course! +class House < ApplicationRecord + enumbled_to :color +end + +# This gives you some power: +Color::BLACK # => 1 +Color.black # => equivalent to Color.find(1) +Color.black.black? # => true +Color.black.is_black # => true +Color.white.not_black? # => true + +house = House.create!(color: Color.black) +house.black? +house.not_black? + +House.color(:black) # => [house] +``` ## Installation diff --git a/enumbler.gemspec b/enumbler.gemspec index 14efcfe..37e8e5c 100644 --- a/enumbler.gemspec +++ b/enumbler.gemspec @@ -29,8 +29,8 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] - spec.add_dependency 'activerecord', '>= 6.0' - spec.add_dependency 'activesupport', '>= 6.0' + spec.add_dependency 'activerecord', '~> 6.0.2' + spec.add_dependency 'activesupport', '~> 6.0.2' spec.add_development_dependency 'database_cleaner-active_record', '~> 1.8.0' spec.add_development_dependency 'fuubar', '~> 2.5' diff --git a/lib/enumbler/enabler.rb b/lib/enumbler/enabler.rb index 4b6870d..a07e517 100644 --- a/lib/enumbler/enabler.rb +++ b/lib/enumbler/enabler.rb @@ -72,9 +72,24 @@ def enumble(enum, id, label: nil, **options) @enumbles << enumble end - # Return the record id(s) based on different argument types. Can accept an - # Integer, a Symbol, or an instance of Enumbled model. This lookup is a - # databse-free lookup. + # Return the record id for a given argument. Can accept an Integer, a + # Symbol, or an instance of Enumbled model. This lookup is a database-free + # lookup. + # + # Color.id_from_enumbler(1) # => 1 + # Color.id_from_enumbler(:black) # => 1 + # Color.id_from_enumbler(Color.black) # => 1 + # + # @raise [Error] when there is no enumble to be found + # @param arg [Integer, Symbol, Class] + # @return [Integer] + def id_from_enumbler(arg) + ids_from_enumbler(arg).first + end + + # Return the record id(s) based on different argument types. Can accept + # an Integer, a Symbol, or an instance of Enumbled model. This lookup is + # a database-free lookup. # # Color.ids_from_enumbler(1, 2) # => [1, 2] # Color.ids_from_enumbler(:black, :white) # => [1, 2] diff --git a/lib/enumbler/version.rb b/lib/enumbler/version.rb index f7e68f7..9a2be9b 100644 --- a/lib/enumbler/version.rb +++ b/lib/enumbler/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Enumbler - VERSION = '0.3.0' + VERSION = '0.3.1' end diff --git a/spec/enumbler_spec.rb b/spec/enumbler_spec.rb index b23d91e..21addae 100644 --- a/spec/enumbler_spec.rb +++ b/spec/enumbler_spec.rb @@ -14,13 +14,16 @@ end class ApplicationRecord < ActiveRecord::Base + # @!parse extend Enumbler::ClassMethods + include Enumbler + self.abstract_class = true end # Our Color has been Enumbled with some basic colors. class Color < ApplicationRecord - # @!parse extend Enumbler::ClassMethods - include Enumbler + # @!parse extend Enumbler::Enabler::ClassMethods + include Enumbler::Enabler enumble :black, 1 enumble :white, 2 @@ -30,8 +33,6 @@ class Color < ApplicationRecord # Our House class, it has a color of course! class House < ApplicationRecord - # @!parse extend Enumbler::ClassMethods - include Enumbler enumbled_to :color end @@ -69,11 +70,11 @@ class House < ApplicationRecord it 'creates the query methods', :seed do expect(Color.black).to be_black expect(Color.black.is_black).to be true + expect(Color.white).to be_not_black end end describe '.enumbled_to', :seed do - after(:example) { House.enumbled_to(:color) } it 'raises an error when the class does not exist' do expect { House.enumbled_to(:bob) }.to raise_error(Enumbler::Error, /cannot be found/) end @@ -92,11 +93,28 @@ class House < ApplicationRecord it 'raises an error when the Enumble is not defined' do expect { House.color(100, 1) }.to raise_error(Enumbler::Error, /Unable to find/) end - it 'allows a prefix to be set' do + it 'allows a scope prefix to be set' do house = House.create! color: Color.black - House.enumbled_to(:color, prefix: 'where_by') + House.enumbled_to(:color, scope_prefix: 'where_by') expect(House.where_by_color(:black)).to contain_exactly(house) end + it 'adds instance methods to query the enumble' do + house = House.new color: Color.black + expect(house).to be_black + expect(house).not_to be_white + + expect(house).to be_not_white + expect(house).not_to be_not_black + end + it 'can add a prefix if requested' do + House.enumbled_to(:color, prefix: true) + house = House.new color: Color.black + expect(house).to be_color_black + expect(house).not_to be_color_white + + expect(house).to be_color_not_white + expect(house).not_to be_color_not_black + end end end @@ -112,12 +130,14 @@ class House < ApplicationRecord describe '.ids_from_enumbler', :seed do it 'returns a numeric id' do + expect(Color.id_from_enumbler(1)).to eq 1 expect(Color.ids_from_enumbler(1)).to contain_exactly(1) end it 'raises an error when the id is not defined' do expect { Color.ids_from_enumbler(100, 1) }.to raise_error(Enumbler::Error, /Unable to find/) end it 'returns an id from a symbol' do + expect(Color.id_from_enumbler(:black)).to eq 1 expect(Color.ids_from_enumbler(:black)).to contain_exactly(1) expect(Color.ids_from_enumbler(:black, :white)).to contain_exactly(1, 2) end