diff --git a/.rubocop.yml b/.rubocop.yml index bac4e33..aaff50b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -70,3 +70,6 @@ Style/StringLiterals: Style/TrailingCommaInArguments: EnforcedStyleForMultiline: comma + +Style/DoubleNegation: + Enabled: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d47ebd..3955cfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## unreleased +Features: +- Automatically generate "*?" methods for boolean comparison. + ## v3.1.3 Fixes: diff --git a/README.md b/README.md index bf1ca4e..cfa5dee 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,19 @@ result = BuildGreeting.call result.greeting # => "Have a wonderful day!" ``` +For each output a method is generated ending with a `?`, which is useful when the output is used for +conditional control flow, like if-else statements. + +```rb +if result.greeting? + puts "Greetings is a non empty value" +else + puts "Greetings is empty" +end +``` + +The generated method will return the truthy or falsey values of variables. + ### Defaults Inputs can be marked as optional by providing a default: diff --git a/lib/service_actor/result.rb b/lib/service_actor/result.rb index 184c77b..3311cd2 100644 --- a/lib/service_actor/result.rb +++ b/lib/service_actor/result.rb @@ -51,5 +51,28 @@ def [](name) def display to_h.fetch(:display) end + + private + + def respond_to_missing?(method_name, include_private = false) + method_name.to_s.end_with?("?") || super + end + + def method_missing(symbol, *args) + attribute = symbol.to_s.chomp("?") + + if symbol.to_s.end_with?("?") && respond_to?(attribute) + define_singleton_method symbol do + attribute_value = send(attribute.to_sym) + + # Same as ActiveSupport’s #present? + attribute_value.respond_to?(:empty?) ? !attribute_value.empty? : !!attribute_value + end + + return send(symbol) + end + + super symbol, *args + end end end diff --git a/spec/service_actor/result_spec.rb b/spec/service_actor/result_spec.rb new file mode 100644 index 0000000..d9938a4 --- /dev/null +++ b/spec/service_actor/result_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +RSpec.describe ServiceActor::Result do + it "defines a method ending with *? suffix for each attribute" do + result = described_class.new + result.name = "Sunny" + + expect(result.respond_to?(:name?)).to eq true + end + + context "when input is String" do + context "when is empty" do + it "returns false" do + result = described_class.new + result.name = "" + + expect(result.name?).to eq false + end + end + + context "when is not empty" do + it "returns true" do + result = described_class.new + result.name = "Actor" + + expect(result.name?).to eq true + end + end + end + + context "when input is Array" do + context "when is empty" do + it "returns false" do + result = described_class.new + result.options = [] + + expect(result.options?).to eq false + end + end + + context "when is not empty" do + it "returns true" do + result = described_class.new + result.options = [1, 2, 3] + + expect(result.options?).to eq true + end + end + end + + context "when input is Hash" do + context "when empty" do + it "returns false" do + result = described_class.new + result.options = {} + + expect(result.options?).to eq false + end + end + + context "when not empty" do + it "returns true" do + result = described_class.new + result.options = { name: "Actor" } + + expect(result.options?).to eq true + end + end + end + + context "when input is NilClass" do + it "returns false" do + result = described_class.new + result.name = nil + + expect(result.name?).to eq false + end + end + + context "when input is TrueClass" do + it "returns true" do + result = described_class.new + result.name = true + + expect(result.name?).to eq true + end + end + + context "when input is FalseClass" do + it "returns true" do + result = described_class.new + result.name = false + + expect(result.name?).to eq false + end + end +end