From: Christian Pedaschus Date: 2011-09-14T18:08:49+09:00 Subject: Re: [Q] recommended way to support multiple APIs from one codebase On 09/13/2011 11:41 PM, Chuck Remes wrote: > I am the author of the ffi-rzmq gem. It wraps the 0mq [1] (libzmq) library for use by all of the major Ruby runtimes. > > Recently, the 0mq project developers used their 2.x branch to create a 3.x and a 4.x branch. These new branches are changing the API of the library; it will *not* be backward compatible with the version 2.x API. > > I would like to continue shipping a single gem that can support libzmq 2.x, 3.x and 4.x out of the box without requiring the end user to do anything fancy. The library supports a function call to retrieve major, minor and patch version information, so I know I can detect the correct version at runtime and load the appropriate code. > > My question stems from one of organization. The 3.x and 4.x APIs share many of the same characteristics as the 2.x API, so I'd like to be able to share that code amongst all of the versions. In the places where they differ, I don't know if I should do an if/else kind of structure within the class definition, subclass it from another file and make the changes, make the sharable pieces into a module that I can include, use if/else to require entire files, etc. I have *so many* choices for how to approach this that I'm frozen. > > The approach I am leaning towards right now requires the creation of a base class that conforms to the version 2.x API. The 3.x and 4.x APIs will reopen it and override the appropriate methods to inject the correct method signature and behavior. So, as the gem loads it will always load the version2 API and then as it detects either version 3 or 4 it will require another file that essentially reopens the class and overwrites the appropriate methods. > > How do other gem authors solve this issue? Can anyone point to a gem (or 2 or 3) that currently handles this problem? > > Thank you... > > cr > > > [1] http://zeromq.org > Sorry dont have a gem at hand which does it (but i guess many if not most use this technic), but in principle your thinking was correct. I'd just use modules instead of directly changing the base class, a search for "ruby included hook" will show the implementation. Have fun, Chris PS. Modules can be 'stacked', so put the basic functionality into say api_abc_common.rb and version specifics into api_abc_v1.rb and api_abc_v2.rb. By including api_common from inside api_v1/api_v2, ruby will call the methods in order, so there is no need for if/else (except in the part which detects the version to mixin, but using a good naming scheme for dynamic 'module-name-generation' can remove these, too.