WrapInModule
This is a Ruby gem I created to house the functionality to be able to wrap various things inside modules. The primary focus of it was to be able to load a ruby file in using a module as namespace for all the top level Constants, Methods, Classes, Modules, etc. This does the same for any sub ruby scripts that are required as well.
I found this functionality in a ruby script, supprisingly called script.rb written by Joel VanderWerf released under the Ruby license in 2004. I have simply wrapped his script inside a gem so that this functionality can be easily accessed. The following is the description provided with Joel's script with my gem namespacing.
WrapInModule::Script
is a subclass of Module. A module which is an instance
of the WrapInModule::Script
class encapsulates in its scope the top-level
methods, top-level constants, and instance variables defined in a ruby script
file (and its dependent files) loaded by a ruby program. This allows use of
script files to define objects that can be loaded into a program in much the
same way that objects can be loaded from YAML or Marshal files.
Installation
Add this line to your application's Gemfile:
gem 'wrap_in_module'
And then execute:
$ bundle
Or install it yourself as:
$ gem install wrap_in_module
Synopsis
program.rb:
require 'wrap_in_module'
my_script = WrapInModule::Script.load("my-script.rb")
p my_script::VALUE
my_script.run
my-script.rb:
VALUE = [1,2,3]
def run
puts "#{self} running."
end
output:
$ ruby program.rb
[1, 2, 3]
#<Script:/tmp/my-script.rb> running.
Usage
WrapInModule::Script
modules are instantiated with
WrapInModule::Script.new(main_file) or the alias
WrapInModule::Script.load(main_file). All the top-level constants and
top-level methods that are defined in the +main_file+ and its dependent local
files (see below) are scoped in the same Script module, and are thereby
available to the calling program.
The +main_file+ can load or require other files with +load+ and +require+, as
usual. These methods, in the WrapInModule::Script
context, add some behavior
to the +Kernel+ +load+ and +require+ methods:
WrapInModule::Script#load and WrapInModule::Script#require
first search for files relative to the +main_file+'s dir. Files loaded in this
way ("dependent local files") are treated like the script file itself:
top-level definitions are added to the script module that is returned by +load+
or +require+.
Both WrapInModule::Script#load and WrapInModule::Script#require fall back to the Kernel versions if the file is not found locally. Hence, other ruby libraries can be loaded and required as usual, assuming their names do not conflict with local file names. Definitions from those files go into the usual scope (typically global). The normal ruby +load+ and +require+ behavior can be forced by calling Kernel.load and Kernel.require.
A WrapInModule::Script
immitates the way the top-level ruby context works, so
a ruby file that was originally intended to be run from the top level, defining
top-level constants and top-level methods, can also be run as a
WrapInModule::Script
, and its top-level constants and top-level methods are
wrapped in the script's scope. The difference between this behavior and simply
wrapping the loaded definitions in an anonymous module using
Kernel.load(main_file, true) is that the top-level methods and
top-level constants defined in the script are accessible using the
WrapInModule::Script
instance.
The top-level definitions of a WrapInModule::Script
can be accessed after it
has been loaded, as follows:
script.meth
- Call a method defined using def meth or def self.meth in the script file.
script::K
- Access a class, module, or constant defined using K = val in the script file.
An "input" can be passed to the script before loading. Simply call
WrapInModule::Script.new
(or WrapInModule::Script.load
) with a block. The
block is passed a single argument, the WrapInModule::Script
module, and
executed before the files are loaded into the Script's scope. Setting a
constant in this block makes the constant available to the script during
loading. For example:
script = Script.load("my-script.rb") { |script| script::INPUT = 3 }
Note that all methods defined in the script file are both instance methods of the module and methods of the module instance (the effect of Module#module_function). So include-ing a Script module in a class will give instances of the class all the methods and constants defined in the script, and they will reference the instance's instance variables, rather than the Script module's instance variables.
The Script class was inspired by Nobu Nokada's suggestion in http://ruby-talk.org/62727, in a thread (started in http://ruby-talk.org/62660) about how to use ruby script files as specifications of objects.
Legal and Contact Information
Usable under the Ruby license. Copyright (C)2004 Joel VanderWerf. Questions to mailto:[email protected].
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Added some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request