Skip to content

Commit

Permalink
Add boolean methods to outputs (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
rockwellll committed Apr 27, 2022
1 parent 50f1858 commit ff769b7
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Expand Up @@ -70,3 +70,6 @@ Style/StringLiterals:

Style/TrailingCommaInArguments:
EnforcedStyleForMultiline: comma

Style/DoubleNegation:

This comment has been minimized.

Copy link
@dorianmariecom

dorianmariecom Apr 28, 2022

looks like a rubocop bug, because the default is allowed_in_returns and here it's in the return of a define_method

https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/DoubleNegation

This comment has been minimized.

Copy link
@sunny

sunny Apr 29, 2022

Owner

Oooh, nice catch!

This comment has been minimized.

Copy link
@sunny

sunny Apr 29, 2022

Owner

And already an issue and a PR to fix that 😍
rubocop/rubocop#10586

Enabled: false
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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:
Expand Down
13 changes: 13 additions & 0 deletions README.md
Expand Up @@ -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:
Expand Down
23 changes: 23 additions & 0 deletions lib/service_actor/result.rb
Expand Up @@ -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

This comment has been minimized.

Copy link
@dorianmariecom

dorianmariecom Apr 28, 2022

curious, why define_singleton_method and not define_method?

This comment has been minimized.

Copy link
@rockwellll

rockwellll Apr 28, 2022

Author Contributor

I guess define_method isn't callable within a method?. Because the specs are failing when using it within the method_missing. It seems that define_method is only available on the class(not it's instances).

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
97 changes: 97 additions & 0 deletions 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

0 comments on commit ff769b7

Please sign in to comment.