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 modules and classes
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_relativestatement reads the original definition of theGitTreemodule, shown above. -
The
module GitTreestatement 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_xxxmethods contain the top-level logic for thexxxsubcommand.help_xxxmethods display the help message for thexxxsubcommand.
Notice that no Ruby classes 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.