jacoblockard99/middlegem

View on GitHub
lib/middlegem/middleware.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module Middlegem
  # {Middleware} is an abstract representation of a single "middleware". A middleware is a
  # transforming function that accepts arbitrary input and produces arbitrary output.
  # Middlewares can be chained with {Stack} to produce powerful, flexible data-transforming
  # layers.
  #
  # One important concept to note is that middlewares in +middlegem+ are "one-way". In other
  # words, they cannot transform both a "request" and a "response". For this functionality,
  # please see other gems such as {https://github.com/Ibsciss/ruby-middleware ruby-middleware} or
  # (for web requests) {https://github.com/rack/rack rack}.
  #
  # Middlewares in +middlegem+ are also slightly different in exactly what they operate upon.
  # Whereas the middlewares in +ruby-middleware+ simply transform a single +env+
  # variable, +middlegem+ middlewares transform an entire argument list. This may or may not be
  # desirable, as it requires all middlewares to return an array, but it highlights the primary
  # use case for +middlegem+. While it can be used for a variety of purposes, +middlegem+ was
  # specifically designed for filtering and changing arguments passed to a method.
  #
  # Finally, you might notice that {Middleware} contains no actual instance method
  # implementations. In other words, for all intents and pruposes, it is empty! This is
  # intentional. A middleware is *any* object that implements a {#call} method (you read that
  # right---a proc is a valid middleware!). You may extend this class, however, to explicitly
  # mark your middleware classes as middlewares.
  #
  # @author Jacob Lockard
  # @since 0.1.0
  # @abstract
  # @see Middlegem::Stack
  class Middleware
    # Determines whether the given object is a valid middleware. Currently, any object that
    # responds to the +call+ method is valid.
    #
    # @param middleware [Object] the middleware to check.
    # @return [bool] whether the given object is a valid middleware.
    def self.valid?(middleware)
      middleware.respond_to?(:call)
    end

    # @!method call(*args)
    #   The method called to actually execute the middleware. It is passed the output of the
    #   previous middleware in the chain and should return the appropriately transformed output
    #   to be passed to the next middleware. Note that the splat operator is intentional! This
    #   method will be called with actual arguments, not an array. This means that you can
    #   simply define the arguments you expect directly in the method signature, rather than
    #   accepting a splatted array and accessing its elements. For example, the following is
    #   possible:
    #     class MyMiddleware
    #       def call(first, last, email)
    #         return "#{email} <#{first} #{last}>"
    #       end
    #     end
    #   @param args [Array<Object>] the input to be transformed, usually the output of the
    #     previous middleware in a middleware chain.
    #   @return [Object, Array<Object>] the transformed output. Note that if an array is
    #     returned, it will be splatted before being passed to the next middleware.
    #   @note This method must be implemented by all middleware!
  end
end