From faac99b872c05cf43cd87813330eb45c922299c6 Mon Sep 17 00:00:00 2001 From: Damon Timm Date: Thu, 21 May 2020 06:56:35 -0700 Subject: [PATCH] Add .enumber_label_column_name class method Allows you to specify which underlying column in the database is reflected by the `label` that the Enumbler relies on. --- Gemfile.lock | 2 +- README.md | 48 ++++++++++++++++++++++++++++------------- lib/enumbler/enabler.rb | 29 +++++++++++++++++++++++-- lib/enumbler/enumble.rb | 7 +++--- lib/enumbler/version.rb | 2 +- spec/enumbler_spec.rb | 26 +++++++++++++++++++++- 6 files changed, 91 insertions(+), 23 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b8a38ce..f7d9ad4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - enumbler (0.3.1) + enumbler (0.4.0) activerecord (~> 6.0.2) activesupport (~> 6.0.2) diff --git a/README.md b/README.md index e7f5f95..49d812c 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,30 @@ `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. +## Installation -## Example +Add this line to your application's Gemfile: + +```ruby +gem 'enumbler' +``` + +And then execute: + + $ bundle install + +Or install it yourself as: + + $ gem install enumbler + +## Usage 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 + t.string :label, null: false, index: { unique: true } end create_table :houses|t| @@ -52,25 +67,28 @@ house.not_black? House.color(:black) # => [house] ``` -## Installation +### Use a column other than `label` -Add this line to your application's Gemfile: +By default, the Enumbler expects a table in the database with a column `label`. However, you can change this to another underlying column name. Note that the enumbler still treats it as a `label` column; however it will be saved to the correct place in the database. ```ruby -gem 'enumbler' -``` - -And then execute: - - $ bundle install - -Or install it yourself as: +ActiveRecord::Schema.define do + create_table :feelings, force: true do |t| + t.string :emotion, null: false, index: { unique: true } + end +end - $ gem install enumbler +class Feeling < ApplicationRecord + # @!parse extend Enumbler::Enabler::ClassMethods + include Enumbler::Enabler -## Usage + enumbler_label_column_name :emotion -TODO: Write usage instructions here + enumble :sad, 1 + enumble :happy, 2 + enumble :verklempt, 3, label: 'overcome with emotion' +end +``` ## Development diff --git a/lib/enumbler/enabler.rb b/lib/enumbler/enabler.rb index a07e517..dd7fcbe 100644 --- a/lib/enumbler/enabler.rb +++ b/lib/enumbler/enabler.rb @@ -34,7 +34,7 @@ module ClassMethods # # # in your migration # create_table :colors, force: true do |t| - # t.string :label, null: false + # t.string :label, null: false, index: { unique: true } # end # # class Color < ApplicationRecord @@ -60,8 +60,9 @@ module ClassMethods def enumble(enum, id, label: nil, **options) @enumbles ||= [] @enumbled_model = self + @enumbler_label_column_name ||= :label - enumble = Enumble.new(enum, id, label: label, **options) + enumble = Enumble.new(enum, id, label: label, label_column_name: @enumbler_label_column_name, **options) if @enumbles.include?(enumble) raise Error, "You cannot add the same Enumble twice! Attempted to add: #{enum}, #{id}." @@ -72,6 +73,30 @@ def enumble(enum, id, label: nil, **options) @enumbles << enumble end + # By default, the Enumbler is expecting a table with an underlying column + # named `label` that represents the enum in the database. You can change + # this by calling `enumber_label_column_name` before you `enumble`! + # + # ActiveRecord::Schema.define do + # create_table :feelings, force: true do |t| + # t.string :emotion, null: false, index: { unique: true } + # end + # end + # + # class Feeling < ApplicationRecord + # # @!parse extend Enumbler::Enabler::ClassMethods + # include Enumbler::Enabler + # + # enumbler_label_column_name :emotion + # + # enumble :sad, 1 + # enumble :happy, 2 + # enumble :verklempt, 3, label: 'overcome with emotion' + # end + def enumbler_label_column_name(label_column_name) + @enumbler_label_column_name = label_column_name + end + # 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. diff --git a/lib/enumbler/enumble.rb b/lib/enumbler/enumble.rb index 331f1ad..3188351 100644 --- a/lib/enumbler/enumble.rb +++ b/lib/enumbler/enumble.rb @@ -3,12 +3,13 @@ module Enumbler # Class that holds each row of Enumble data. class Enumble - attr_reader :id, :enum, :label, :options + attr_reader :id, :enum, :label, :label_column_name, :options - def initialize(enum, id, label: nil, **options) + def initialize(enum, id, label: nil, label_column_name: :label, **options) @id = id @enum = enum @label = label || enum.to_s.dasherize + @label_column_name = label_column_name @options = options end @@ -20,7 +21,7 @@ def ==(other) def attributes { id: id, - label: label, + label_column_name => label, } end diff --git a/lib/enumbler/version.rb b/lib/enumbler/version.rb index 9a2be9b..f8ca6e8 100644 --- a/lib/enumbler/version.rb +++ b/lib/enumbler/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Enumbler - VERSION = '0.3.1' + VERSION = '0.4.0' end diff --git a/spec/enumbler_spec.rb b/spec/enumbler_spec.rb index 21addae..bcc7663 100644 --- a/spec/enumbler_spec.rb +++ b/spec/enumbler_spec.rb @@ -5,7 +5,11 @@ # ----------------------------------------------------------------------------- ActiveRecord::Schema.define do create_table :colors, force: true do |t| - t.string :label, null: false + t.string :label, null: false, index: { unique: true } + end + + create_table :feelings, force: true do |t| + t.string :emotion, null: false, index: { unique: true } end create_table :houses, force: true do |t| @@ -31,6 +35,17 @@ class Color < ApplicationRecord enumble :infinity, 4, label: 'This is a made-up color' end +class Feeling < ApplicationRecord + # @!parse extend Enumbler::Enabler::ClassMethods + include Enumbler::Enabler + + enumbler_label_column_name :emotion + + enumble :sad, 1 + enumble :happy, 2 + enumble :verklempt, 3, label: 'overcome with emotion' +end + # Our House class, it has a color of course! class House < ApplicationRecord enumbled_to :color @@ -118,6 +133,15 @@ class House < ApplicationRecord end end + describe '.enumbler_label_column_name' do + before { Feeling.seed_the_enumbler! } + it 'adds the label to the correct column' do + expect(Feeling.verklempt.emotion).to eq 'overcome with emotion' + expect(Feeling.sad).to be_sad + expect(Feeling.enumbles.first).to have_attributes(label: 'sad') + end + end + describe '.enumbles', :seed do it 'contains the enumbles' do expect(Color.enumbles.map(&:id)).to contain_exactly(1, 2, 3, 4)