I have a command line Ruby app I’m developing and I want to allow a user of it to provide code that will run as a filter on part of the process. Basically, the application does this:
- read in some data
- If a filter is specified, use it to filter data
- process the data
I want the filtering process (step 2) to be as flexible as possible.
My thinking was that the user could provide a Ruby file that set a known constant to point to an object implementing an interface I define, e.g.:
# user's filter class MyFilter def do_filter(array_to_filter) filtered_array = Array.new # do my filtering on array_to_filter filtered_array end FILTER = MyFilter.new
My app’s code would then do something like this:
array_that_might_get_filtered = get_my_array() if (options.filter_file) require options.filter_file array_that_might_get_filtered = FILTER.do_filter(array_that_might_get_filtered) end
While this would work, it feels cheesy and it seems like there should be a better way to do it. I also considered having the filter be in the form of adding a method of a known name to a known class, but that didn’t seem quite right, either.
Is there a better idiom in Ruby for this?
I’d just use a combination of the command line, and convention.
I’m assuming you’d specify a filter on the command line? So you’d invoke the application like this?
If so, you could define an ‘api’ wherein a class name would have to match what was passed in – pretty much exactly how you’ve described in your example.
To take it one step further though, you could have some logic which looked for the
CustomFilterclass using ruby’sdefined?, and if it was not found, go looking forcustom_filter.rb(or any suitable variations) and attempt to load that file, then retry.This gives you great extensibility, as you can write as many filter classes as you like, chuck them in their own .rb files, and put them anywhere that ruby can find them. You won’t have to have an pre-defined constants either, the only constraints will be
do_filtermethodIncidentally, this is pretty similar to what rails does for requiring your models, and is why you can just use
SomeModelwithout having to always dorequire app/models/some_modelfirst :-)`