Skip to content

Sage/handler_registerable

Repository files navigation

HandlerRegisterable

Build Status Maintainability Test Coverage Gem Version

Description

Registered handlers allow common code to collaborate with a handler which is designed to meet a more concrete requirement.

The basic premise is that a registry is created for a particular concern, and this registry allows each specific handler to be added. The registry handlers will conform to a documented API, and may often provide a base class or default implementations.

Your application and context specific details can be written in a specific handler, and then added to the registry. At run time, code that needs to collaborate with the appropriate handler from the registry is correctly given the appropriate handler.

Demo Gif

Installation

Add to your project's Gemfile:

gem 'handler_registerable'

Run in your project root:

bundle install

Usage

This gem provides a Ruby module which can be extended into a class/module to provide the following class methods:

registered_handlers - returns a hash which can be modified obtain - loops through all registered handlers and returns the first one that handles the given condition (tested by calling the handles? class method on each handler)

Creating your registry

A registry is usually a module within a given namespace. For example let's create a welcome handler:

module WelcomeHandlers
end
module WelcomeHandlers
  extend HandlerRegisterable::Registry
end

Base classes and registering

To make life easier you can provide a base class which allows users to subclass and register themselves within the registry:

module WelcomeHandlers
  class Base
    def initialize(context)
      @context = context
    end

    # Registers a handler with the given identifier.
    #
    # @param [Symbol] handler the identifier to represent this handler class.
    def self.register(handler)
      WelcomeHandlers.register self, handler
    end
  end
end

It's important to document the public API which handlers are required to implement. These methods will be dependant on the purpose of the registry, but all will require the appropriate handles? API for that registry.

module WelcomeHandlers
  class Example < Base
    register :first_time_user

    def self.handles?(context)
      context.some_attribute == 'example'
    end
  end
end

Note: Handlers don't necessarily need to be within the registry's namespace (in fact in application code it will be in your own namespaces).

The exact arguments and conditions for the handles? class method in the handlers is specific to the purpose of the registry. This should always be a single arg, but if you need more than one, you can use a hash. However, you should look to keep the details to a minimum.

Defining and Registering

Let's now define the public API for our Welcome handlers

  • welcome_message - returns the string for this type of business
  • expiry_reminders - array of time periods from trial expiration to email reminders

Here's a couple of example handlers:

class ProductOneWelcome < WelcomeHandler::Base
  register :product_one

  def self.handles?(user)
    user.product == 'product_one'
  end

  def welcome_message
    'Thanks for choosing product one'
  end

  def expiry_reminders
    [2.weeks, 1.week, 2.days]
  end
end

class ProductTwoeWelcome < WelcomeHandler::Base
  register :product_two

  def self.handles?(user)
    user.product == 'product_two'
  end

  def welcome_message
    'Thanks for choosing product two'
  end

  def expiry_reminders
    [1.week, 2.days, 1.day]
  end
end

Setting a Default

When no handler is found, it is possible to specify a default handler to use instead:

module WelcomeHandlers
  class Default < Base
    WelcomeHandlers.default = self

    def welcome_message
      'A default welcome message'
    end
  end
end

Using the registry

The way the registry is used is through the obtain method:

# code in a signup to a service object

def complete_signup(user)
  welcome = WelcomeHandlers.obtain(user)
  user.send_message(welcome.welcome_message)
  ReminderJob.schedule_for_user(user, welcome.expiry_reminders)
end

License

Handler Registerable is available as open source under the terms of the Apache-2.0 licence.

Copyright (c) 2018 Sage Group Plc. All rights reserved.

About

A ruby gem which provides a mechanism for common code to collaborate with a handler which is designed to meet a more concrete requirement

Resources

License

Stars

Watchers

Forks

Packages

No packages published