From: Scott Parkerson Date: 2007-01-20T07:27:53+09:00 Subject: Re: Automatically Determining "Requires" and "Provides" information for a Ruby script or library On 1/19/07, gwtmp01@mac.com wrote: > I don't think this is technically possible because of the dynamic > nature of Ruby. That is to say that I think the task you describe > is equivalent to the halting problem as it requires the ability to > divine the intent of executable code by simply examining the code > as opposed to running it and seeing what happens. I think you are right, so let me amend my request a bit. * I don't need to get the exact signature of every method provided or required. File-based provides should be enough for what we need. Anything more complex can be synthesized manually. In most cases, Ruby provide would essentially be the filepath, with the $LOAD_PATH chopped off the front and the extension removed. Thus, /usr/lib/ruby/1.8/yaml.rb provides 'yaml'. * Requires could be whatever was required at require time. I wrote a quick and dirty requires generator that essentially overrode Kernel.require to stuff the argument to require into a Set. Thus, for yaml: /usr/lib/ruby/1.8/yaml.rb requires the following modules: "yaml/constants" "yaml/ypath" "yaml/error" "yaml/rubytypes" "stringio" "date" "rational" "syck" "yaml/syck" "yaml/basenode" "date/format" "yaml/tag" "yaml/stream" "yaml/types" The big question is whether Ruby C extensions are always required by filename (i.e. if you have a C extension called big/foo.so, require 'big/foo' will load it). In Python, this is tricky, as the shared library name may not be the thing you use with import at all. The bottom line is to have a "good enough" provides/requires mechanism that automates packaging information. It's obviously not perfect, as two foo.rb's might do wildly different things. Here's the code snippet, so far (quick and dirty is probably a vast understatement): require 'set' $required = Set.new module Kernel alias_method :old_require, :require def require(m) begin result = old_require(m) rescue LoadError => blargh print "warning: #{blargh}\n" rescue NameError true end $required = $required.add(m) result end end require(ARGV[0]) print "#{ARGV[0]} requires the following modules:\n" $required.each { |file| p file } -- scott parkerson. geek, erstwhile prophet and fool. just a cog in the machinery: http://www.smerpology.org/sprocket/