Skip to content

Commit

Permalink
Improve usage documentation (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
federicoaldunate authored Nov 17, 2024
1 parent c36980c commit 277cafd
Showing 1 changed file with 191 additions and 0 deletions.
191 changes: 191 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,197 @@ end
```
It will raise an `ArgumentError`.


### Handling Success and Failure
#### Using success and fail
`success(data):` Marks the service result as successful and optionally provides data.
`fail(data):` Marks the service result as a failure but continues executing the call method.
`fail!(data):` Marks the service result as a failure and immediately exits the call method.
#### Example: Using fail followed by success
```ruby
class TestFailService < SeaFood::Service
def initialize(email:)
@email = email
end

def call
fail(email: '[email protected]')
success(email: @email)
end
end

result = TestFailService.call(email: '[email protected]')

puts result.success? # => true
puts result.email # => '[email protected]'
```
In this example:

The fail method sets the result to failure but allows the method to continue.
The subsequent success call overrides the failure, resulting in a successful outcome.

#### Example: Using fail! to Exit Early
```ruby
class TestFailBangService < SeaFood::Service
def initialize(email:)
@email = email
end

def call
fail!(email: '[email protected]')
success(email: @email) # This line is not executed
end
end

result = TestFailBangService.call(email: '[email protected]')

puts result.success? # => false
puts result.email # => '[email protected]'
```

The `fail!` method immediately exits the call method.
The service result is a failure, and subsequent code in call is not executed.
Nested Services
You can call other services within a service. The behavior depends on whether you use `call` or `call!`.
#### Summary of call vs. call!
`call`: Executes the service and returns the result. Does not raise an exception if the service fails.

`call!`: Executes the service and raises an exception if the service fails. Useful for propagating failures in nested services.

#### Using call (Non-Bang Method)
Failures in nested services do not automatically propagate to the parent service.


```ruby
class InnerService < SeaFood::Service
def initialize(email:)
@email = email
end

def call
fail!(email: @email)
end
end

class OuterService < SeaFood::Service
def initialize(email:)
@email = email
end

def call
InnerService.call(email: '[email protected]')
success(email: @email)
end
end

result = OuterService.call(email: '[email protected]')

puts result.success? # => true
puts result.email # => '[email protected]'
```
*Explanation:*

`InnerService` fails using `fail!`.
`OuterService` calls `InnerService` using `call`.
Since `call` does not raise an exception on failure, `OuterService` continues and succeeds.

#### Using `call!` (Bang Method)
Failures in nested services propagate to the parent service when using `call!`.

```ruby
class InnerService < SeaFood::Service
def initialize(email:)
@email = email
end

def call
fail!(email: @email)
end
end

class OuterService < SeaFood::Service
def initialize(email:)
@email = email
end

def call
InnerService.call!(email: '[email protected]')
success(email: @email) # This line is not executed
end
end

result = OuterService.call(email: '[email protected]')

puts result.success? # => false
puts result.email # => '[email protected]'
```
*Explanation:*

`InnerService` fails using `fail!`.
`OuterService` calls `InnerService` using call!.
The failure from `InnerService` propagates, causing `OuterService` to fail.
#### Handling Failures in Nested Services
You can handle failures from nested services by checking their result.

```ruby
class InnerService < SeaFood::Service
def initialize(value:)
@value = value
end

def call
if @value < 0
fail!(error: 'Negative value')
else
success(value: @value)
end
end
end

class OuterService < SeaFood::Service
def initialize(value:)
@value = value
end

def call
result = InnerService.call(value: @value)

if result.fail?
fail!(error: result.error)
else
success(value: result.value * 2)
end
end
end

result = OuterService.call(value: -1)

puts result.success? # => false
puts result.error # => 'Negative value'
```
*Explanation:*

`OuterService` checks the result of `InnerService`.
If `InnerService` fails, `OuterService` handles it accordingly.

#### Accessing Result Data
The result object allows you to access data provided in success or fail calls using method syntax.

```ruby
class ExampleService < SeaFood::Service
def call
success(message: 'Operation successful', value: 42)
end
end

result = ExampleService.call

puts result.success? # => true
puts result.message # => 'Operation successful'
puts result.value # => 42
```


## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
Expand Down

0 comments on commit 277cafd

Please sign in to comment.