cs/Interfacecopyright (c) 2004 Sean O'Dell Purpose cs/Interface is a library which implements a form of type-checking which helps developers understand the purpose of Ruby objects encountered at run-time by tagging classes and objects with type IDs, and enforcing that required methods are present, and take the required number of parameters. Built-in interfaces for many existing Ruby classes and objects include: IString, IArray, IHash, IDate and ITime. More pre-defined interfaces will be added in time.
current version: 0.6.2 |
Table of Contents Quick Lesson Developing Interfaces Tutorial Creating New Interfaces Applying Interfaces Checking Interface Compliance Applying Interfaces To Your Classes Interfaces and Modules Interfaces and Singletons How It Works Interface Class Interface.new interface#add_pattern interface#add_class_patterns Module Class Module.implement Object Class object#implement? Standard Interface Objects IArray IDate IHash IString ITime |
I need your help! This interface library is very useful, but I think for most developers, they just want to check for interfaces on existing Ruby classes and objects, so I need to create as complete an interface library as possible. Please join the discussion here and help me out!
using Ruby Gems
# gem -Ri csinterfacefrom source
Download csinterface-0.6.2.tar.gz to a working directory, then issue the following commands:
$ tar -xzvf csinterface-0.6.2.tar.gz $ ruby setup.rb config $ ruby setup.rb setup # ruby setup.rb install
Ruby Gems
If you installed cs/Interface with gem, be sure to add the following code to the top of your scripts:
require "rubygems" require_gem "csinterface"Example
In the example below, you have a method which takes one parameter. Normally, you would duck-type or check for needed methods with respond_to?. In this case, however, neither of those two ways are reliable enough for your purposes. You need to be sure this object behaves like a Hash before you attempt to use the object. What do you do?
require "celsoft.com/interface/standard" def func(obj) raise "not a hash" if (not obj.implement?(IHash)) end func(Hash.new) func(ENV)Notice the method is called twice, passing both a Hash object and the ENV object. IHash is one of many pre-defined interfaces and is already applied to the Hash class and the ENV object.
You create new interfaces by creating an instance of the Interface class, then adding method patterns to the interface. You can pull method patterns en-masse from existing classes or modules, or add patterns individually.
require "celsoft.com/interface" IHash = Interface.new IHash.add_class_patterns(Hash, :[], :[]=) IHash.add_pattern(:each_pair, proc{||})
You can apply interfaces to classes, giving them the ability to claim that they implement the interface. Compliance will be validated with another call.
class Hash implement IHash end
Using the above example, it's easy to test objects to see if they implement the IHash interface.
h = Hash.new p h.implement?(IHash) == true
Now that IHash is defined above, you can declare that your own objects implement the IHash interface. You can do this by declaring the interface in your class or module definition. Remember to implement all the methods IHash requires.
class MyHashType def [](key) # ... end def []=(key, value) # ... end def each_pair() # ... end implement IHash end m = MyHashType.new p m.implement?(IHash) == true
You can define interfaces in modules or classes, but you may only declare implementations in the class definitions.
module MyHashModule def [](key) # ... end def []=(key, value) # ... end def each_pair() end end IMyHash = Interface.new IMyHash.add_class_patterns(MyHashModule, :[], :[]=, :each_pair) class MyHash include MyHashModule implement IMyHash end m = MyHash.new p m.implement?(IMyHash) == true
Singletons may also be declared as implementing an interface by accessing/creating the object's singleton class. If an object's class becomes a singleton, any existing implementation declarations are copied to the new singleton class.
p ENV.implement?(IHash) == false # (before) class <<ENV implement IHash end p ENV.implement?(IHash) == true # (after)
Method patterns are stored with each Interface object and are used to check against the methods of any given object. The name and number of parameters are important. If an object, or any of its ancestors, never claims to implement an interface, it will always report that it does not implement a given interface, even if it may be capable of it. When an object,or any of its ancestors, claims to implement an interface, a thorough check is performed to verify that it actually does. This check is only performed when necessary for efficiency, when implement? is called. The result of the check is cached and returned quickly on subsequent calls to implement?. If either the interface definition changes, or methods are changed in the class of the object, the cache is dumped and the thorough check is performed the next time implement? is called, and the answer is then again cached.
require "celsoft.com/interface"
interface#add_pattern(idMethod, &block)Adds a single method pattern to the interface by analyzing the block given. Blocks can be proc objects or methods.
interface#add_class_patterns(modObject [, idMethod1 [...]])Adds a series of method patterns contained in the class or module modObject.
require "celsoft.com/interface"Applies to Modules and their derivatives, such as Class.
Module.implement(interface)Declares the module (or class) as an implementation of interface.
require "celsoft.com/interface"
object#implement?(interface)Returns true if the class of the object, or any ancestor, claims the object is an implementation of interface, and if the object's class methods match the patterns of the interface.
require "celsoft.com/interface/standard"Pre-defined interfaces for standard Ruby classes and objects.
For array-like classes, which contain items indexed by number. Pre-applied to Array.
For date-like classes.
For hash-like classes, which get and set values using keys. Pre-applied to Hash and ENV.
For string-like classes which implement the to_str method. Pre-applied to String.
For time-like classes.