Skip to content

Commit

Permalink
Merge branch 'hotfix/0.8.1' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
thornomad committed Dec 14, 2020
2 parents e93aae7 + 974710b commit b98bfcd
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
enumbler (0.8.0)
enumbler (0.8.1)
activerecord (>= 5.2.3, < 6.1)
activesupport (>= 5.2.3, < 6.1)

Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,12 @@ To install this gem onto your local machine, run `bundle exec rake install`. To

## Roadmap

* We need to add in support for additional attributes/columns in the enumbled table. For example, following the `Color` concept, we may want to have a column which is `hex` and stores the colors `hex` value (e.g., `FFFFFF`). This should be supported.
* Ideally, we could make this work more like a traditional `enum`; for example, overriding the `.where` method by allowing something like: `House.where(color: :blue)` instead of `House.where_color(:blue)`. But right now am in a rush and not sure how to go about doing that properly.
* Ideally, we could make this work more like a traditional `enum`; for example, overriding the `.where` method by allowing something like: `House.where(color: :blue)` instead of `House.color(:blue)`. But right now am in a rush and not sure how to go about doing that properly.

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/linguabee/enumbler.


## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
41 changes: 40 additions & 1 deletion lib/enumbler/enabler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,21 @@ def define_dynamic_methods_and_constants_for_enumbled_model(enumble)
method_name = "#{enumble.enum}?"
not_method_name = "not_#{enumble.enum}?"
alias_method_name = "is_#{enumble.enum}"
any_method_name = "any_#{enumble.enum}?"

[method_name, not_method_name, alias_method_name].each do |mname|
detect_enumbler_conflict(enumble.enum, mname)
end

[enumble.enum, any_method_name].each do |mname|
detect_enumbler_conflict(enumble.enum, mname, klass_method: true)
end

const_set(enumble.enum.to_s.upcase, enumble.id)
define_method(method_name) { id == enumble.id }
define_method(not_method_name) { id != enumble.id }
alias_method alias_method_name, method_name

define_singleton_method(enumble.enum) do |attr = nil|
return find(enumble.id) if attr.nil?

Expand All @@ -388,13 +398,42 @@ def define_dynamic_methods_and_constants_for_enumbled_model(enumble)
raise Enumbler::Error, "The attribute #{attr} is not supported on this Enumble."
end

define_singleton_method("any_#{enumble.enum}?") do
define_singleton_method(any_method_name) do
where(id: enumble.id).exists?
rescue NoMethodError
raise Enumbler::Error, "The attribute #{attr} is not supported on this Enumble."
end
end

# This idea sourced lovingly from ActiveRecord::Enum
ENUMBLER_CONFLICT_MESSAGE = <<~TEXT.squish
You tried to define the enumble :%<enum>s on the model %<klass>s, but
this will generate a %<type>s method `%<method>s`, which is already defined
by %<source>s.
TEXT

def detect_enumbler_conflict(enumble_name, method_name, klass_method: false)
if klass_method && dangerous_class_method?(method_name)
raise_conflict_error(enumble_name, method_name, type: 'class')
elsif klass_method && method_defined_within?(method_name, ActiveRecord::Relation)
raise_conflict_error(enumble_name, method_name, type: 'class', source: ActiveRecord::Relation.name)
elsif !klass_method && dangerous_attribute_method?(method_name)
raise_conflict_error(enumble_name, method_name)
end
end

def raise_conflict_error(enumble_name, method_name, type: 'instance', source: 'ActiveRecord')
raise Error,
format(
ENUMBLER_CONFLICT_MESSAGE,
enum: enumble_name,
klass: name,
type: type,
method: method_name,
source: source
)
end

# I accidentally forgot to provide an id one time and it was confusing as
# the last argument became the hash of options. This should help.
def validate_id_is_numeric(enum, id)
Expand Down
2 changes: 1 addition & 1 deletion lib/enumbler/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Enumbler
VERSION = '0.8.0'
VERSION = '0.8.1'
end
23 changes: 23 additions & 0 deletions spec/enumbler_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,36 @@ class Sky < ApplicationRecord
it 'raises an error when the same enumble is added twice' do
expect { Color.enumble(:white, 1) }.to raise_error(Enumbler::Error, /twice/)
end

it 'raises an error when no numeric id is passed as the second argument' do
expect { Color.enumble(:white, label: 'error') }.to raise_error(Enumbler::Error, /numeric/)
end

it 'raises an error when there is a class method naming conflict' do
expect do
Class.new(ApplicationRecord) do
include Enumbler::Enabler

enumble :transaction, 1
end
end.to raise_error(Enumbler::Error, /class method `transaction`/)
end

it 'raises an error when there is a instance method naming conflict' do
expect do
Class.new(ApplicationRecord) do
include Enumbler::Enabler

enumble :persisted, 1
end
end.to raise_error(Enumbler::Error, /instance method `persisted\?`/)
end

it 'creates the constants' do
expect(Color::BLACK).to eq 1
expect(Color::WHITE).to eq 2
end

it 'creates the class finder methods', :seed do
expect(Color.black).to eq Color.find(Color::BLACK)
end
Expand Down

0 comments on commit b98bfcd

Please sign in to comment.