Published 2023-06-03.
Time to read: 3 minutes.
ruby
collection.
The Ruby language allows modules and classes to be redefined and/or enhanced at runtime. This may seem strange to programmers who work with other computer languages.
Modularity
Similar to the Python language, Ruby classes and modules are mutable.
Class and module methods are just attributes of the enclosing class or module,
and they can be changed.
New methods can be added to a pre-existing module
or class
.
Modifying Ruby libraries in this way is called monkey patching, and this powerful feature can be dangerous.
However, for your own code,
reopening your own module
s and class
es
to add new methods and variables can be a terrific way to write in a modular fashion,
and this code is generally quite maintainable.
Case Study: Git_tree
My git_tree
Ruby gem
takes advantage of mutable modules
to provide a simple and
flexible mechanism for organizing code in a manageable manner.
Git_tree
mostly consists of one module
, GitTree
,
that contains common code for all the git-tree
subcommands
(git-tree-evars
, git-tree-exec
, and git-tree-replicate
).
module GitTree def self.directories_to_process(root) # implementation end end
In the above code, the self.
prefix for the method name marks this method as being
a module-level method.
Module methods can be invoked without having to include
or extend
the containing module.
When a subcommand is launched,
the GitTree
module
is re-opened,
and methods are added that are specific to that subcommand,
then the code is executed.
The above GitTree
module is re-opened in the following 3 files.
In each of them:
-
The
require_relative
statement reads the original definition of theGitTree
module
, shown above. -
The
module GitTree
statement re-opens the module definition and adds new methods to it for the subcommand that the file implements. Two kinds of methods are common to each subcommand:command_xxx
methods contain the top-level logic for thexxx
subcommand.help_xxx
methods display the help message for thexxx
subcommand.
Notice that no Ruby class
es are used for modularity purposes.
require_relative 'git_tree' module GitTree def self.command_evars(root) # implementation end def self.help_evars(msg = nil) # implementation end # Other methods also end
require_relative 'git_tree' module GitTree def self.command_exec(root) # implementation end def self.help_exec(msg = nil) # implementation end # Other methods also end
require_relative 'git_tree' module GitTree def self.command_replicate(root) # implementation end def self.help_replicate(msg = nil) # implementation end # Other methods also end
Debug Stubs
Stubs are used for debugging command-line invocations because it is
awkward to repeatedly compile-edit-debug installed gems.
There is one debug stub for each of the three git-tree
subcommands.
The debug stubs are not included in the gem.
require_relative '../lib/git_tree_evars' GitTree.command_evars
require_relative '../lib/git_tree_exec' GitTree.command_exec
require_relative '../lib/git_tree_replicate' GitTree.command_replicate
The Visual Studio Code launch.json
entries for debugging are also simple.
Each of the above three stubs can be debugged separately.
{ "version": "0.2.0", "configurations": [ { "args": [ "$jekyll_img $jekyll_pre", "version" ], "name": "Debug git-tree-exec", "type": "Ruby", "request": "launch", "program": "${workspaceRoot}/test/git_tree_exec.rb" }, { "args": [ "$work" ], "name": "Debug git-tree-evars", "type": "Ruby", "request": "launch", "program": "${workspaceRoot}/test/git_tree_evars.rb" }, { "args": [ "$work" ], "name": "Debug git-tree-replicate", "type": "Ruby", "request": "launch", "program": "${workspaceRoot}/test/git_tree_replicate.rb" }, } }
Simple, elegant, flexible and easy to understand modularity.
About the Author
I, Mike Slinn, have been working with Ruby for a long time now. Back in 2005, I was the product marketing manager at CodeGear (the company was formerly known as Borland) for their 3rd Rail IDE. 3rd Rail supported Ruby and Ruby on Rails at launch.
In 2006, I co-chaired the Silicon Valley Ruby Conference on behalf of the SD Forum in Silicon Valley. As you can see, I have the t-shirt. I was the sole chairman of the 2007 Silicon Valley Ruby Conference.
Several court cases have come my way over the years in my capacity as a software expert witness. The court cases featured questions about IP misappropriation for Ruby on Rails programs. You can read about my experience as a software expert if that interests you.
I currently enjoy writing Jekyll plugins in Ruby for this website and others, as well as Ruby utilities.