From 8bae2377cdbf7f336d4c9dc61da633b6bdc9ea5f Mon Sep 17 00:00:00 2001 From: Ermolaev Andrey Date: Sun, 15 Dec 2024 20:50:26 +0300 Subject: [PATCH 1/2] feat: add question predicate method for check in severals values --- lib/enum_machine/build_value_class.rb | 21 ++++++++++++++++++- spec/enum_machine/driver_simple_class_spec.rb | 17 +++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/enum_machine/build_value_class.rb b/lib/enum_machine/build_value_class.rb index 99552cd..0544947 100644 --- a/lib/enum_machine/build_value_class.rb +++ b/lib/enum_machine/build_value_class.rb @@ -8,7 +8,9 @@ def self.call(enum_values:, i18n_scope:, value_decorator:, machine: nil) Class.new(String) do include(value_decorator) if value_decorator - define_method(:machine) { machine } if machine + define_method(:machine) { machine } + define_method(:enum_values) { enum_values } + private :enum_values, :machine def inspect "#" @@ -73,6 +75,23 @@ def human_name end RUBY end + + def respond_to_missing?(method_name, include_private = false) + method_name = method_name.name if method_name.is_a?(Symbol) + + method_name.end_with?("?") && + method_name.include?("__") && + (m_enums = method_name.delete_suffix("?").split("__")) && + (m_enums & enum_values) == m_enums + end + + def method_missing(method_name) + return super unless respond_to_missing?(method_name) + + m_enums = method_name.name.delete_suffix("?").split("__") + self.class.define_method(method_name) { m_enums.include?(self) } + send(method_name) + end end end end diff --git a/spec/enum_machine/driver_simple_class_spec.rb b/spec/enum_machine/driver_simple_class_spec.rb index cb3703b..d7682c3 100644 --- a/spec/enum_machine/driver_simple_class_spec.rb +++ b/spec/enum_machine/driver_simple_class_spec.rb @@ -7,7 +7,7 @@ def initialize(state) @state = state end - include EnumMachine[state: { enum: %w[choice in_delivery] }] + include EnumMachine[state: { enum: %w[choice in_delivery lost] }] end module ValueDecorator @@ -23,14 +23,17 @@ def initialize(state) @state = state end - include EnumMachine[state: { enum: %w[choice in_delivery], value_decorator: ValueDecorator }] + include EnumMachine[state: { enum: %w[choice in_delivery lost], value_decorator: ValueDecorator }] end RSpec.describe "DriverSimpleClass" do subject(:item) { TestClass.new("choice") } - it { expect(item.state).to be_choice } - it { expect(item.state).not_to be_in_delivery } + it { expect(item.state.choice?).to eq true } + it { expect(item.state.in_delivery?).to eq false } + it { expect(item.state.choice__in_delivery?).to eq true } + it { expect(item.state.lost__in_delivery?).to eq false } + it { expect { item.state.last__in_delivery? }.to raise_error(NoMethodError) } it { expect(item.state).to eq "choice" } it { expect(item.state.frozen?).to be true } @@ -68,13 +71,15 @@ def initialize(state) describe "TestClass::STATE const" do it "#values" do - expect(TestClass::STATE.values).to eq(%w[choice in_delivery]) + expect(TestClass::STATE.values).to eq(%w[choice in_delivery lost]) end it "#[]" do expect(TestClass::STATE["in_delivery"]).to eq "in_delivery" expect(TestClass::STATE["in_delivery"].in_delivery?).to be(true) expect(TestClass::STATE["in_delivery"].choice?).to be(false) + expect(TestClass::STATE["in_delivery"].in_delivery__choice?).to be(true) + expect(TestClass::STATE["in_delivery"].lost__choice?).to be(false) expect(TestClass::STATE["wrong"]).to be_nil end @@ -118,7 +123,7 @@ def initialize(state) end it "decorates enum values in enum const" do - expect(TestClassWithDecorator::STATE.values.map(&:am_i_choice?)).to eq([true, false]) + expect(TestClassWithDecorator::STATE.values.map(&:am_i_choice?)).to eq([true, false, false]) expect((TestClassWithDecorator::STATE.values & ["in_delivery"]).map(&:am_i_choice?)).to eq([false]) end From 6d7161c3402955eacb8b9aed0cfce57bdb5f6029 Mon Sep 17 00:00:00 2001 From: Ermolaev Andrey Date: Sun, 15 Dec 2024 21:53:28 +0300 Subject: [PATCH 2/2] rubocop --- .rubocop.yml | 3 +++ Gemfile.lock | 12 ++++++------ lib/enum_machine/build_enum_class.rb | 2 +- lib/enum_machine/build_value_class.rb | 5 ++--- lib/enum_machine/machine.rb | 2 +- spec/enum_machine/driver_simple_class_spec.rb | 8 ++++---- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 81b56c8..4d701a8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -24,3 +24,6 @@ Gp/UnsafeYamlMarshal: Enabled: true Exclude: - spec/**/*.rb + +Gp/OptArgParameters: + Enabled: false diff --git a/Gemfile.lock b/Gemfile.lock index 57f5938..0550707 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -73,7 +73,7 @@ GEM zeitwerk (~> 2.6) i18n (1.14.6) concurrent-ruby (~> 1.0) - json (2.8.2) + json (2.9.0) language_server-protocol (3.17.0.3) logger (1.6.1) method_source (1.1.0) @@ -89,7 +89,7 @@ GEM rack (3.1.8) rainbow (3.1.1) rake (13.2.1) - regexp_parser (2.9.2) + regexp_parser (2.9.3) rspec (3.13.0) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) @@ -103,17 +103,17 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-support (3.13.1) - rubocop (1.69.0) + rubocop (1.69.2) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rubocop-ast (>= 1.36.1, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.36.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.36.1) + rubocop-ast (1.37.0) parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) diff --git a/lib/enum_machine/build_enum_class.rb b/lib/enum_machine/build_enum_class.rb index 3ee116a..87d30d6 100644 --- a/lib/enum_machine/build_enum_class.rb +++ b/lib/enum_machine/build_enum_class.rb @@ -20,7 +20,7 @@ def self.call(enum_values:, i18n_scope:, value_class:, machine: nil) end if i18n_scope - def self.values_for_form(specific_values = nil) # rubocop:disable Gp/OptArgParameters + def self.values_for_form(specific_values = nil) (specific_values || values).map { |v| [human_name_for(v), v] } end diff --git a/lib/enum_machine/build_value_class.rb b/lib/enum_machine/build_value_class.rb index 0544947..339b18a 100644 --- a/lib/enum_machine/build_value_class.rb +++ b/lib/enum_machine/build_value_class.rb @@ -76,13 +76,12 @@ def human_name RUBY end - def respond_to_missing?(method_name, include_private = false) + def respond_to_missing?(method_name, _include_private = false) method_name = method_name.name if method_name.is_a?(Symbol) method_name.end_with?("?") && method_name.include?("__") && - (m_enums = method_name.delete_suffix("?").split("__")) && - (m_enums & enum_values) == m_enums + (method_name.delete_suffix("?").split("__") - enum_values).empty? end def method_missing(method_name) diff --git a/lib/enum_machine/machine.rb b/lib/enum_machine/machine.rb index 7e5dea5..85764ca 100644 --- a/lib/enum_machine/machine.rb +++ b/lib/enum_machine/machine.rb @@ -4,7 +4,7 @@ module EnumMachine class Machine attr_reader :enum_values, :base_klass, :enum_const_name, :attr_name - def initialize(enum_values, base_klass = nil, enum_const_name = nil, attr_name = nil) # rubocop:disable Gp/OptArgParameters + def initialize(enum_values, base_klass = nil, enum_const_name = nil, attr_name = nil) @enum_values = enum_values @base_klass = base_klass @enum_const_name = enum_const_name diff --git a/spec/enum_machine/driver_simple_class_spec.rb b/spec/enum_machine/driver_simple_class_spec.rb index d7682c3..f2e8311 100644 --- a/spec/enum_machine/driver_simple_class_spec.rb +++ b/spec/enum_machine/driver_simple_class_spec.rb @@ -29,10 +29,10 @@ def initialize(state) RSpec.describe "DriverSimpleClass" do subject(:item) { TestClass.new("choice") } - it { expect(item.state.choice?).to eq true } - it { expect(item.state.in_delivery?).to eq false } - it { expect(item.state.choice__in_delivery?).to eq true } - it { expect(item.state.lost__in_delivery?).to eq false } + it { expect(item.state.choice?).to be true } + it { expect(item.state.in_delivery?).to be false } + it { expect(item.state.choice__in_delivery?).to be true } + it { expect(item.state.lost__in_delivery?).to be false } it { expect { item.state.last__in_delivery? }.to raise_error(NoMethodError) } it { expect(item.state).to eq "choice" } it { expect(item.state.frozen?).to be true }