From: ara.t.howard@... Date: 2007-01-04T07:52:35+09:00 Subject: Re: File-based Code Encapsulation On Thu, 4 Jan 2007, Trans wrote: > Hi-- > > I'm having a little debate with myself. On my current project I have a > bunch of little reusable task scripts that a command line tool runs. > The scripts are written as the top-level (although I actually simulate > the top-level when running them). So for example a script would just be > something like: > > # example.rb > > def example > puts "This is an example!" > end > > Then on the command line I would do: > > % mytool example > This is an example! > > That's all well and good, but many of the scripts have generally useful > routines and I would like them to be accessible by other programs too, > not just my command line tool. So I thoght maybe it would be better if > a module were required to wrap the defs. > > # another.rb > > module MyToolAnother > > def another > puts "This is another!" > end > > end > > That works, of course, but it adds an additonal layer of essentially > redundant code, which IMHO is ugly. > > Then I got to thinking. Why don't we write resuable lib in this fashion > anyway and just create our own containers on the fly when loading them? > > MyToolExample = load_as_module "example.rb" > > What intersting about that is then we could determine in what capacity > it is to be used. For example: > > # adds module_function > MyToolExample = load_as_function_module "example.rb" > > # adds self extend > MyToolExample = load_as_self_extended_module "example.rb" > > Or even > > MyToolExample = load_as_class "example.rb" > > We could even have include and extend take a lib path. > > include "example.rb" > > Of course this effectively puts encapsulation, at least at the top > level, on a per-file basis. But in many respects that seems kind of > nice. It increases flexability and reduces configuration complexity. > > So what do your think? Is this technique worth promoting? Or am I being > silly and should just wrap all my scripts in modules? > > T. wrap up the functionality into a lib, require that from your scripts, and make accessing instance methods from the command-line easy. i've used this pattern many times. here is an example from our NRT (near-real-time) system which allows me to call any module function from the command line: mussel: ~ > cat nrtlib.rb module NRT def self.foobar(*a) p a end # many, many, many lines of code end now i have a single command line program which loads this lib then takes the first command line argument as a method to send to the module. remaining command-line parms are parsed in a sensible way allowing ints, strings, floats, bools, lists, hashes, and combinations of those. whatever value is returned by the function is dumped on stdout. examples. mussel:~ > nrt foobar --- [] mussel:~ > nrt foobar 42 --- - 42 mussel:~ > nrt foobar 1,2,3 --- - - 1 - 2 - 3 mussel:~ > nrt foobar 1,2,3 k:v --- - - 1 - 2 - 3 - k: v mussel:~ > nrt foobar 1,2,3 k:v a:b --- - - 1 - 2 - 3 - k: v a: b mussel:~ > nrt foobar 42.0 string --- - 42.0 - string mussel:~ > nrt foobar 42.0 string key:val --- - 42.0 - string - key: val now, yaml input is also allows by giving '--' as a commnad line arg mussel:~ > nrt foobar 42.0 string key:val | nrt foobar -- --- - 42.0 - string - key: val and the arg '-' indicates a simple unix style list, one element per line, on stdin: mussel:~ > printf "a \n b \n c \n" | nrt foobar - --- - a - b - c the result is that any library/module routine is instantly availible from the command line - makes testing a breeze! obviously not all routines are easy to use this way but, by sticking to simple interfaces/function call signatures many of them can be. it's a useful pattern. food for thought. -a -- if you find yourself slandering anybody, first imagine that your mouth is filled with excrement. it will break you of the habit quickly enough. - the dalai lama