Project

subroutine

0.07
A long-lived project that still receives updates
An interface for creating feature-driven operations.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

Subroutine

A gem that provides an interface for creating feature-driven operations. You've probably heard at least one of these terms: "service objects", "form objects", "intentions", or "commands". Subroutine calls these "ops" and really it's just about enabling clear, concise, testable, and meaningful code.

Example

So you need to sign up a user? or maybe update one's account? or change a password? or maybe you need to sign up a business along with a user, associate them, send an email, and queue a worker in a single request? Not a problem, create an op for any of these use cases. Here's the signup example.

class SignupOp < ::Subroutine::Op

  string :name
  string :email
  string :password

  string :company_name

  validates :name, presence: true
  validates :email, presence: true
  validates :password, presence: true
  validates :company_name, presence: true

  outputs :user
  outputs :business, type: Business # validate that output type is an instance of Business

  protected

  def perform
    u = create_user!
    b = create_business!(u)

    deliver_welcome_email(u)

    output :user, u
    output :business, b
  end

  def create_user!
    User.create!(name: name, email: email, password: password)
  end

  def create_business!(owner)
    Business.create!(company_name: company_name, owner: owner)
   end

  def deliver_welcome_email(u)
    UserMailer.welcome(u.id).deliver_later
  end
end

So why use this?

  • Avoid cluttering models or controllers with logic only applicable to one intention. You also don't need strong parameters because the inputs to the Op are well-defined.
  • Test the Op in isolation
  • Clear and concise intention in a single file
  • Multi-model operations become simple

Continue Reading

Development

Run the test suite against current Rails version:

bundle exec rake test

Run the test suite against all supported Rails versions using appraisal:

bundle exec appraisal rake test

For help updating the Gemfile or changing supported Rails versions, see the appraisal gem README.

Note that the gemfiles in gemfiles/* are auto-generated by appraisal and should not be modified directly.