CommonJS Module System in Ruby
This post has been updated at 16/05/2013.
I really like the CommonJS module system, which is explicit, rather than implicit as Kernel#require in Ruby. So rather than putting everything into the global namespace, require in CommonJS simply returns an object which contains the stuff you explicitly exported from the required file. For example:
I really like the CommonJS module system, which is explicit, rather than implicit as Kernel#require in Ruby. So rather than putting everything into the global namespace, require in CommonJS simply returns an object which contains the stuff you explicitly exported from the required file. For example:
var sys = require("sys");
sys.puts("Hello there!");
And in the sys.js can be something like:
exports.puts = function (foo) {
process.stdout.puts(foo);
};
Surprisingly, it's really easy to implement the same in Ruby using method_missing and singleton_method_added. The first hook method is used for registering properties via exports.a_variable = a_value, where method a_variable= obviously doesn't exist and the second hook for registering methods:
def exports.foo; end
This is the best syntax for defining methods on modules, but then a_module.foo obviously won't trigger method_missing because it actually exists. But we want to register it into a container with all the properties and methods, so we can iterate over it etc. Fortunately the solution is really simple:
def exports.singleton_method_added(method)
@data[method] = self.method(method)
end
This will be called each time a method will be added into the exports metaclass. So then when we'll call import, we'll get something like:
require "import"
sys = import("example")
# => #<CommonJS::Proxy @data={:language => "Ruby", :VERSION_ => "0.0.1", :say_hello=>#<Method: #<CommonJS::Proxy>.say_hello>}>
Nice, is it? You can check the code at my GitHub account, I named it commonjs_require. It's definitely worthy to take a look even if you aren't interested in CommonJS, because it's a really good example of Ruby flexibility.
Anyway it could be interesting to implement some more Node.js stuff in Ruby, mainly because it's asynchronous and therefore waaay better. Consider for example this:
fs = import("fs")
fs.watch_file("/etc/hosts") do
puts "Hosts file changed!"
end
I'd definitely utilize this kind of stuff. Since this kind of stuff is already implemented in EventMachine, it could be +/- just a simple DSL around it. Is anyone interested?
blog comments powered by Disqus