Adaptor

Build Status Coverage Status Maintainability

Adaptor makes it easy to implement the Adapter pattern in Ruby.

Installation

Add this line to your application's Gemfile:

gem 'adaptor'

And then execute:

$ bundle

Or install it yourself as:

$ gem install adaptor

Usage

Single adaptor mode

You can use the library in single-adaptor mode:

module DocumentProcessor
  class Pdf
    include Adaptor

    def self.supports?(document)
      document.mime_type == 'application/pdf'
    end

    def initialize(document)
      @document = document
    end

    def build_thumbnail
      # something with @document
    end
  end

  class Word
    include Adaptor

    def self.supports?(document)
      document.mime_type == 'application/msword'
    end

    def initialize(document)
      @document = document
    end

    def build_thumbnail
      # something with @document
    end
  end
end

module DocumentProcessor
  include Adaptor::Loader
  register Pdf, Word
end

# You can use #load_adaptor! if you want to raise an
# Adaptor::NoAdaptorError when no adaptor is found.
thumbnail = DocumentProcessor.load_adaptor(document).build_thumbnail

Multiple adaptor mode

If it suits your use case, you can use multiple-adaptor mode:

module NotificationProcessor
  class Email
    include Adaptor

    def self.supports?(notification)
      notification.user.email.present?
    end

    def initialize(notification)
      @notification = notification
    end

    def deliver
      # ...
    end
  end

  class Sms
    include Adaptor

    def self.supports?(notification)
      notification.user.phone.present?
    end

    def initialize(notification)
      @notification = notification
    end

    def deliver
      # ...
    end
  end
end

module MultipleAdaptorLoader
  include Adaptor::Loader
  register Email, Sms
end

# You can use #load_adaptors! if you want to raise an
# Adaptor::NoAdaptorError when no adaptors are found.
NotificationProcessor.load_adaptors(notification).each(&:deliver)

Multiple arguments

Note that there is no limit to the number of arguments you can pass to the adaptors' .supports? and .new methods. Here's an example that checks support only with one argument, but initializes with multiple:

module DocumentProcessor
  class Pdf
    include Adaptor

    def self.supports?(document)
      document.mime_type == 'application/pdf'
    end

    def initialize(document, options)
      @document = document
      @options = options
    end

    def build_thumbnail
      # something with @document and @options
    end
  end

  class Word
    include Adaptor

    def self.supports?(document)
      document.mime_type == 'application/msword'
    end

    def initialize(document, options)
      @document = document
      @options = options
    end

    def build_thumbnail
      # something with @document and @options
    end
  end
end

module DocumentProcessor
  include Adaptor::Loader
  register Pdf, Word
end

# You can use #load_adaptor! if you want to raise an
# Adaptor::NoAdaptorError when no adaptor is found.
thumbnail = DocumentProcessor.load_adaptor(document, stamp: true).build_thumbnail

As you can see, whatever you pass to .load_adaptor or .load_adaptors will be forwarded to .supports? and .new, according to the methods' respective arity.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/aldesantis/adaptor. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

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

Code of Conduct

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