Project

operatic

0.0
Low commit activity in last 3 years
No release in over a year
A minimal standard interface for your operations
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 0
~> 3.0
 Project Readme

Operatic

GitHub Actions status

A minimal standard interface for your operations.

Installation

Add Operatic to your application's Gemfile and run bundle install.

gem 'operatic'

Usage

An Operatic class encapsulates an operation and communicates its status via a result object. As well as being a #success? or #failure? data can also be attached to the result via #success!, #failure!, or during the operation's execution.

class SayHello
  include Operatic

  # Readers for instance variables defined in `.call`.
  attr_reader :name

  # Declare convenience data accessors.
  data_attr :message

  def call
    # Exit the method and mark the operation as a failure.
    return failure! unless name

    # Mark the operation as a success and attach further data.
    success!(message: "Hello #{name}")
  end
end

result = SayHello.call(name: 'Dave')
result.class     # => Operatic::Success
result.failure?  # => false
result.success?  # => true
result.message   # => "Hello Dave"
result[:message] # => "Hello Dave"
result.to_h      # => {:message=>"Hello Dave"}

result = SayHello.call
result.class     # => Operatic::Failure
result.failure?  # => true
result.success?  # => false
result.message   # => nil
result[:message] # => nil
result.to_h      # => {}

A Rails controller might use Operatic like this:

class HellosController < ApplicationController
  def create
    result = SayHello.call(name: params[:name])

    if result.success?
      render plain: result.message
    else
      render :new
    end
  end
end

Pattern matching

An Operatic result also supports pattern matching allowing you to match over a tuple of the result class and its data:

case SayHello.call(name: 'Dave')
in [Operatic::Success, { message: }]
  # Result is a success, do something with the `message` variable.
in [Operatic::Failure, _]
  # Result is a failure, do something else.
end

Or match solely against its data:

case SayHello.call(name: 'Dave')
in message:
  # Result has the `message` key, do something with the variable.
else
  # Do something else.
end

Which might be consumed in Rails like this:

class HellosController < ApplicationController
  def create
    case SayHello.call(name: params[:name])
    in [Operatic::Success, { message: }]
      render plain: message
    in [Operatic::Failure, _]
      render :new
    end
  end
end

Development

Run the tests with:

bundle exec rspec

Generate Yard documentation with:

bundle exec yardoc

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Operatic project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.