You need to ensure inputs are of a core type with context-specific extra semantics.
Define new implicit conversion protocols mimicking Ruby’s native protocols such as
Ruby defines a number of protocols for converting objects into core types such as
Integer. But there may come a time when the core protocols don’t capture the conversion semantics your apps or libraries need.
Consider a 2D drawing library. Points on the canvas are identified by X/Y pairs. For simplicity, these pairs are simply two-element arrays of integers.
#to_ary for converting to =Array=s. But that doesn’t really capture intent of converting to an X/Y pair. Just like the
#to_path conversion used by
File.open, even though we are converting to a core type we’d like to add a little more meaning to the conversion call. We’d also like to make it possible for an object to have a coordinate conversion even if otherwise it doesn’t really make sense for it to have a general
In order to capture this input requirement, we define the
#to_coords conversion protocol. Here’s a method which uses the protocol:
# origin and ending should both be [x,y] pairs, or should # define #to_coords to convert to an [x,y] pair def draw_line(start, endpoint) start = start.to_coords if start.respond_to?(:to_coords) start = start.to_ary # ... end
Later, we decide to encapsulate coordinate points in their own
Point class, enabling us to attach extra information like the
name of the point. We define a
#to_coords method on this class:
class Point attr_reader :x, :y, :name def initialize(x, y, name=nil) @x, @y, @name = x, y, name end def to_coords [x,y] end end
We can now use either raw X/Y pairs or
Point objects interchangeably:
start = Point.new(23, 37) endpoint = [45,89] draw_line(start, endpoint)
#to_coords protocol isn’t limited to classes defined in our own library. Client code which defines classes with coordinates can also define
#to_coords conversions. By documenting the protocol, we open up our methods to interoperate with client objects which we had no inkling of at the time of writing.