Accord is a gem providing basic object interface and adaptation support for Ruby. An interface represents a protocol or contract (an API), and this gem allows you to label your objects/classes/modules as being compliant with a given API by declaring them as implementing/providing interfaces. Thus, one would call this an implementation of Design by Contract in Ruby.
Object adaptation is also supported. Given an object which claims to provide some API, and in a specific point of the code another API is needed, Accord will allow adapting from the object API to the desired one (provided that an adapter which can adapt the APIs is known by Accord).
This gem was largely inspired by the Python package zope.interface
,
maintained by the Zope Toolkit Project.
zope.interface
source can be found here.
Disclaimer: this is not used in any real world project yet. The API is still changing (and will, while this gem is not in the 1.0 version). Not ready for prime time.
Declare some interfaces:
Labelled = Accord::Interface(:Labelled) do responds_to :label end PersonAPI = Accord::Interface(:PersonAPI)
Implement them:
class Person attr_reader :name def initialize(name) @name = name end end class PersonLabel def initialize(person) @person = person end def label @person.name end end
Declare that your classes are implementations of the interfaces:
Accord::Declarations.implements(Person, PersonAPI) Accord::Declarations.implements(PersonLabel, Labelled)
Tell Accord that people can have labels (that is, they can be adapted to Labelled):
Accord.default_adapter_registry.register([PersonAPI], Labelled) do |person| PersonLabel.new(person) end
Now, in a piece of code which needs a label:
def show(object) Labelled.adapt!(object).label end
When a person is given to #show, its name will be used to provide a label:
person = Person.new('John') show(person) #=> 'John'
By registering more adapters, #show can be reused to show the labels of other types of objects, without changing its source. #show doesn't rely on receiving a person, but depends only on an interface. Also, everything could have been added in the application after the Person class (as if that class were legacy code), without modifying its source. Or Person could be a class in a third party library.
This gem is MIT-licensed. See LICENSE.txt in the root of this repository.