views:

262

answers:

2

In ruby, if I do "require foo", is there a way to subsequently determine the name of the module or modules defined in foo.rb?

For example, say I have a ruby file named foo.rb that looks like this:

# foo.rb
module MyModule
    def self.summary
        "this does something useful"
    end
    ...
end

In another script, after I do "require foo", how can I determine that I now have a module named MyModule?

Ultimate what I'm after is to be able to do something like this:

file = someComputedFileName()
require file
puts "summary of #{file}: #{???::summary}

While I could force myself to make module names and file names identical, I'd rather not. I want a bit more freedom in making short filenames but more expressive module names. However, I am guaranteeing to myself that each file will only define a single module (think: plugins).

+2  A: 

One approach would be to use ObjectSpace.each_object(Module) to find all defined modules before requiring the file. Then, after you require the file, loop over all defined modules again and see if there are any new ones.

require "set"
old_modules = SortedSet.new
ObjectSpace.each_object(Module) {|m| old_modules.add(m) }

file = someComputedFileName()
require file

new_modules = SortedSet.new
ObjectSpace.each_object(Module) {|m| new_modules.add(m) unless old_modules.include?(m) }

puts "summary of #{file}: #{new_modules.to_a.map{|m|m.summary}.join(',')}"

That would also let you define more than one module in the file.

Jordan Liggitt
Or just use Sets and examine what's left after new_modules.subtract(old_modules) ?
Mike Woodhouse
+1  A: 

I don't know if this is the best solution, but off the top of my head this seems to work:

all_constants = Object.constants
require 'foo'

foo_constants = Object.constants - all_constants

foo_constants should give you only the modules, classes or other constants that were defined by foo.rb.

Matt Ephraim
that works great for top-level modules, but not for sub-modules.if top-level modules are all you care about, that's a much cleaner solution
Jordan Liggitt
Ah, you're right, I hadn't thought of that. I didn't see your solution before I posted this, but it looks a lot more robust.
Matt Ephraim
Another problem with this is that if my sub-module requires other modules those will show up in the results. I think my solution will be for each plugin to write their name to a global variable. Not the best solution, but I don't need the best, just one that works.
Bryan Oakley