Command object Interface for Ruby
Serviz
provides a minimal interface to unify and homogenize your Service or Command objects in your Ruby code.
Looking for a JavaScript version? Check out π Serviz-JS.
Add this line to your application's Gemfile:
gem 'serviz'
And then execute:
> bundle install
Or install it yourself as:
> gem install serviz
- Your class should inherit from
Serviz::Base
- Your class should implement a
#call
method - Return the result via
self.result=
- Add errors via
self.errors<<
- Check the status via the provided
#success?
or#failure?
methods
First, you should create a Serviz class:
class RegisterUser < Serviz::Base
def initialize(user)
@user = user
end
def call
if @user.valid?
@user.register_and_notify
self.result = @user
else
self.errors << 'Invalid user'
end
end
end
Now, you can run it by using the call
method:
operation = RegisterUser.call(user)
if operation.success?
user = operation.result
puts "Success! #{user.name} registered!"
else
puts "Error! #{operation.error_messages}"
end
As you can see in the example above, you can use the success?
method to check if your operation succeed. You can also use the ok?
alias.
In case you want to check if the run failed, you can use the failure?
method (or the alias error?
):
if operation.failure?
puts "Error! Please try again ..."
return
end
You may like to use the block syntax:
RegisterUser.call(user) do |operation|
puts "Success!" if operation.ok?
end
Serviz
also provides a Workflow
class that allows you to compose multiple service objects together using a clean, declarative DSL for orchestrating complex multi-step operations.
class UserOnboarding < Serviz::Workflow
step RegisterUser
step SendWelcomeEmail, if: ->(last_step) { last_step.success? }
step LogOnboarding
end
# Usage
operation = UserOnboarding.call(user_params)
puts operation.success? # => true
puts operation.result # => result from LogOnboarding
# Handles failures gracefully
operation = UserOnboarding.call(invalid_params)
puts operation.failure? # => true
puts operation.errors # => ["Registration failed"]
- Conditional execution using the
if:
option to control whether steps run based on previous results - Error accumulation from all failed steps in the workflow
- Result chaining where the last successful step's result becomes the workflow result
- Full compatibility with the existing Serviz interface (
success?
,failure?
,errors
,result
)
You can also pass custom parameters to individual steps:
class OrderProcessing < Serviz::Workflow
step ValidateOrder
step ChargePayment, params: { gateway: 'stripe' }, if: ->(last_step) { last_step.success? }
step ShipOrder, if: ->(last_step) { last_step.success? }
end
Any kind of feedback, bug report or enhancement are really welcome!
To contribute, just fork the repo, hack on it and send a pull request. Don't forget to add specs for behaviour changes and run the test suite:
> bundle exec rspec
Copyright (c) Marc Anguera. Serviz
is released under the MIT License.