I'm writing a small Ruby command-line application that uses fileutils
from the standard library for file operations. Depending on how the user invokes the application, I will want to include either FileUtils
, FileUtils::DryRun
or FileUtils::Verbose
.
Since include
is private, though, I can't put the logic to choose into the object's initialize
method. (That was my first thought, since then I could just pass the information about the user's choice as a parameter to new
.) I've come up with two options that seem to work, but I'm not happy with either:
Set a global variable in the app's namespace based on the user's choice, and then do a conditional include in the class:
class Worker case App::OPTION when "dry-run" include FileUtils::DryRun etc.
Create sub-classes, where the only difference is which version of
FileUtils
they include. Choose the appropriate one, depending on the user's choice.class Worker include FileUtils # shared Worker methods go here end class Worker::DryRun < Worker include FileUtils::DryRun end class Worker::Verbose < Worker include FileUtils::Verbose end
The first method seems DRY-er, but I'm hoping that there's something more straightforward that I haven't thought of.
If you would like to avoid the "switch" and inject the module, the
syntax won't work (the injected_module variable is out of scope). You could use the self.class.send trick, but per object instance extending seems more reasonable to me, not only because it is shorter to write:
but also it minimizes the side effects - the shared and easily changable state of the class, which can result in an unexpected behavior in a larger project. In Ruby the is no real "privacy" so to say, but some methods are marked private not without a reason.
So what if it's private?
This includes
FileUtils::something
in particular'sWorker
's metaclass - not in the mainWorker
class. Different workers can use differentFileUtils
this way.Conditionally including the module through the send methods works for me as in the below tested example: