Project

accord

0.0
Repository is archived
No commit activity in last 3 years
No release in over 3 years
Contracts and adaptation for Ruby
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 0
 Project Readme

Accord - object interfaces and adaptation for Ruby

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.

Basic usage

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.

License

This gem is MIT-licensed. See LICENSE.txt in the root of this repository.