Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ AllCops:
Rails/ApplicationRecord:
Enabled: false

Rails/Output:
Enabled: false

Metrics/ParameterLists:
CountKeywordArgs: false

Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ GIT
PATH
remote: .
specs:
enum_machine (1.0.0)
enum_machine (2.0.0)
activemodel
activerecord
activesupport
Expand Down Expand Up @@ -138,7 +138,7 @@ GEM
sqlite3 (1.7.3-arm64-darwin)
sqlite3 (1.7.3-x86_64-darwin)
sqlite3 (1.7.3-x86_64-linux)
timeout (0.4.1)
timeout (0.4.2)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (3.1.2)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class Product

include EnumMachine[color: { enum: %w[red green] }]
# or reuse from model
Product::COLOR.decorator_module
Product::COLOR.enum_decorator
end

Product::COLOR.values # => ["red", "green"]
Expand Down Expand Up @@ -122,8 +122,8 @@ class Product
attr_accessor :color

include EnumMachine[color: {
enum: %w[red green],
decorator: ColorDecorator
enum: %w[red green],
value_decorator: ColorDecorator
}]
end

Expand Down
4 changes: 2 additions & 2 deletions lib/enum_machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

require_relative "enum_machine/version"
require_relative "enum_machine/driver_simple_class"
require_relative "enum_machine/build_attribute"
require_relative "enum_machine/build_value_class"
require_relative "enum_machine/attribute_persistence_methods"
require_relative "enum_machine/build_class"
require_relative "enum_machine/build_enum_class"
require_relative "enum_machine/machine"
require "active_support"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module EnumMachine
module BuildClass
module BuildEnumClass
def self.call(enum_values:, i18n_scope:, value_class:, machine: nil)
aliases = machine&.instance_variable_get(:@aliases) || {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# frozen_string_literal: true

module EnumMachine
module BuildAttribute
def self.call(enum_values:, i18n_scope:, decorator:, machine: nil)
module BuildValueClass
def self.call(enum_values:, i18n_scope:, value_decorator:, machine: nil)
aliases = machine&.instance_variable_get(:@aliases) || {}

Class.new(String) do
include(decorator) if decorator
include(value_decorator) if value_decorator

define_method(:machine) { machine } if machine

Expand Down
16 changes: 8 additions & 8 deletions lib/enum_machine/driver_active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module EnumMachine
module DriverActiveRecord
def enum_machine(attr, enum_values, i18n_scope: nil, decorator: nil, &block)
def enum_machine(attr, enum_values, i18n_scope: nil, value_decorator: nil, &block)
klass = self

i18n_scope ||= "#{klass.base_class.to_s.underscore}.#{attr}"
Expand All @@ -11,13 +11,13 @@ def enum_machine(attr, enum_values, i18n_scope: nil, decorator: nil, &block)
machine = Machine.new(enum_values, klass, enum_const_name, attr)
machine.instance_eval(&block) if block

value_class = BuildAttribute.call(enum_values: enum_values, i18n_scope: i18n_scope, machine: machine, decorator: decorator)
enum_klass = BuildClass.call(enum_values: enum_values, i18n_scope: i18n_scope, machine: machine, value_class: value_class)
value_class = BuildValueClass.call(enum_values: enum_values, i18n_scope: i18n_scope, machine: machine, value_decorator: value_decorator)
enum_class = BuildEnumClass.call(enum_values: enum_values, i18n_scope: i18n_scope, machine: machine, value_class: value_class)

value_class.extend(AttributePersistenceMethods[attr, enum_values])

# default_proc for working with custom values not defined in enum list but may exists in db
enum_klass.value_attribute_mapping.default_proc =
enum_class.value_attribute_mapping.default_proc =
proc do |hash, enum_value|
hash[enum_value] = value_class.new(enum_value).freeze
end
Expand Down Expand Up @@ -102,12 +102,12 @@ def initialize_dup(other)

enum_decorator =
Module.new do
define_singleton_method(:included) do |decorating_klass|
decorating_klass.prepend define_methods
decorating_klass.const_set enum_const_name, enum_klass
define_singleton_method(:included) do |decorating_class|
decorating_class.prepend define_methods
decorating_class.const_set enum_const_name, enum_class
end
end
enum_klass.define_singleton_method(:decorator_module) { enum_decorator }
enum_class.define_singleton_method(:enum_decorator) { enum_decorator }

klass.include(enum_decorator)

Expand Down
20 changes: 10 additions & 10 deletions lib/enum_machine/driver_simple_class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,35 @@ def self.call(args)
Module.new do
define_singleton_method(:included) do |klass|
args.each do |attr, params|
enum_values = params.fetch(:enum)
i18n_scope = params.fetch(:i18n_scope, nil)
decorator = params.fetch(:decorator, nil)
enum_values = params.fetch(:enum)
i18n_scope = params.fetch(:i18n_scope, nil)
value_decorator = params.fetch(:value_decorator, nil)

if defined?(ActiveRecord) && klass <= ActiveRecord::Base
klass.enum_machine(attr, enum_values, i18n_scope: i18n_scope)
else
enum_const_name = attr.to_s.upcase
value_class = BuildAttribute.call(enum_values: enum_values, i18n_scope: i18n_scope, decorator: decorator)
enum_klass = BuildClass.call(enum_values: enum_values, i18n_scope: i18n_scope, value_class: value_class)
value_class = BuildValueClass.call(enum_values: enum_values, i18n_scope: i18n_scope, value_decorator: value_decorator)
enum_class = BuildEnumClass.call(enum_values: enum_values, i18n_scope: i18n_scope, value_class: value_class)

define_methods =
Module.new do
define_method(attr) do
enum_value = super()
return unless enum_value

enum_klass.value_attribute_mapping.fetch(enum_value)
enum_class.value_attribute_mapping.fetch(enum_value)
end
end

enum_decorator =
Module.new do
define_singleton_method(:included) do |decorating_klass|
decorating_klass.prepend define_methods
decorating_klass.const_set enum_const_name, enum_klass
define_singleton_method(:included) do |decorating_class|
decorating_class.prepend define_methods
decorating_class.const_set enum_const_name, enum_class
end
end
enum_klass.define_singleton_method(:decorator_module) { enum_decorator }
enum_class.define_singleton_method(:enum_decorator) { enum_decorator }

klass.include(enum_decorator)
enum_decorator
Expand Down
2 changes: 1 addition & 1 deletion lib/enum_machine/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module EnumMachine
VERSION = "1.0.0"
VERSION = "2.0.0"
end
99 changes: 71 additions & 28 deletions spec/enum_machine/active_record_enum_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@
end
end

context "when with decorator" do
let(:decorator_module) do
context "when with value_decorator" do
let(:decorator) do
Module.new do
def am_i_choice?
self == "choice"
Expand All @@ -88,9 +88,9 @@ def am_i_choice?
end

let(:model_with_decorator) do
decorator = decorator_module
value_decorator = decorator
Class.new(TestModel) do
enum_machine :state, %w[choice in_delivery], decorator: decorator
enum_machine :state, %w[choice in_delivery], value_decorator: value_decorator
end
end

Expand All @@ -106,6 +106,73 @@ def am_i_choice?
end
end

describe("#enum_decorator") do
let(:model) do
Class.new(TestModel) do
enum_machine :state, %w[choice in_delivery]
include EnumMachine[color: { enum: %w[red green blue] }]
end
end

let(:klass) do
Class.new(TestModel) do
enum_machine :state, %w[choice in_delivery]
include EnumMachine[color: { enum: %w[red green blue] }]
end
end

it "decorates plain class from ar" do
decorating_model = model
decorated_class =
Class.new do
include decorating_model::STATE.enum_decorator
include decorating_model::COLOR.enum_decorator
attr_accessor :state, :color
end

decorated_item = decorated_class.new
decorated_item.state = "choice"
decorated_item.color = "red"

expect(decorated_item.state).to be_choice
expect(decorated_item.color).to be_red
expect(decorated_class::STATE::CHOICE).to eq "choice"
expect(decorated_class::COLOR::RED).to eq "red"
end

it "decorates ar from plain class" do
decorating_class = klass
decorated_model =
Class.new(TestModel) do
include decorating_class::STATE.enum_decorator
include decorating_class::COLOR.enum_decorator
end

decorated_item = decorated_model.new(state: "choice", color: "red")

expect(decorated_item.state).to be_choice
expect(decorated_item.color).to be_red
expect(decorated_model::STATE::CHOICE).to eq "choice"
expect(decorated_model::COLOR::RED).to eq "red"
end

it "decorates ar from ar" do
decorating_model = model
decorated_model =
Class.new(TestModel) do
include decorating_model::STATE.enum_decorator
include decorating_model::COLOR.enum_decorator
end

decorated_item = decorated_model.new(state: "choice", color: "red")

expect(decorated_item.state).to be_choice
expect(decorated_item.color).to be_red
expect(decorated_model::STATE::CHOICE).to eq "choice"
expect(decorated_model::COLOR::RED).to eq "red"
end
end

it "serialize model" do
Object.const_set(:TestModelSerialize, model)
m = TestModelSerialize.create(state: "choice", color: "wrong")
Expand All @@ -118,30 +185,6 @@ def am_i_choice?
expect(unserialized_m.color.red?).to be(false)
end

it "test decorator" do
decorating_model =
Class.new(TestModel) do
enum_machine :state, %w[choice in_delivery]
include EnumMachine[color: { enum: %w[red green blue] }]
end

decorated_klass =
Class.new do
include decorating_model::STATE.decorator_module
include decorating_model::COLOR.decorator_module
attr_accessor :state, :color
end

decorated_item = decorated_klass.new
decorated_item.state = "choice"
decorated_item.color = "red"

expect(decorated_item.state).to be_choice
expect(decorated_item.color).to be_red
expect(decorated_klass::STATE::CHOICE).to eq "choice"
expect(decorated_klass::COLOR::RED).to eq "red"
end

it "returns state value by []" do
expect(model::STATE["in_delivery"]).to eq "in_delivery"
expect(model::STATE["in_delivery"].in_delivery?).to be(true)
Expand Down
21 changes: 17 additions & 4 deletions spec/enum_machine/driver_simple_class_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def initialize(state)
include EnumMachine[state: { enum: %w[choice in_delivery] }]
end

module Decorator
module ValueDecorator
def am_i_choice?
self == "choice"
end
Expand All @@ -23,7 +23,7 @@ def initialize(state)
@state = state
end

include EnumMachine[state: { enum: %w[choice in_delivery], decorator: Decorator }]
include EnumMachine[state: { enum: %w[choice in_delivery], value_decorator: ValueDecorator }]
end

RSpec.describe "DriverSimpleClass" do
Expand Down Expand Up @@ -78,10 +78,10 @@ def initialize(state)
expect(TestClass::STATE["wrong"]).to be_nil
end

it "#decorator_module" do
it "#enum_decorator" do
decorated_klass =
Class.new do
include TestClass::STATE.decorator_module
include TestClassWithDecorator::STATE.enum_decorator
attr_accessor :state
end

Expand Down Expand Up @@ -127,6 +127,19 @@ def initialize(state)
unserialized_m = Marshal.load(Marshal.dump(m)) # rubocop:disable Gp/UnsafeYamlMarshal
expect(unserialized_m.state.am_i_choice?).to be(true)
end

it "keeps decorating on #enum_decorator" do
decorated_klass =
Class.new do
include TestClassWithDecorator::STATE.enum_decorator
attr_accessor :state
end

decorated_item = decorated_klass.new
decorated_item.state = "choice"

expect(decorated_item.state.am_i_choice?).to be(true)
end
end

it "serialize class" do
Expand Down