This is purely an experiment, but I'm wondering if it's possible to get a list of the require
'd gems at runtime via some kind of metaprogramming. For example, say I have:
require 'rubygems'
require 'sinatra'
require 'nokogiri'
# don't know what to do here
How can I print out the following at runtime?
this app needs rubygems, sinatra, nokogiri
You can't do this exactly, because requiring one file may require others, and Ruby can't tell the difference between the file that you required and the file that someone else required.
You can check out $LOADED_FEATURES
for a list of every single thing that's been required. But you should use Bundler if you want to specify dependencies explicitly.
Here's a thoroughly imperfect way to guess at the gem names and enumerate everything:
ruby-1.9.2-p180 :001 > $LOADED_FEATURES.
select { |feature| feature.include? 'gems' }.
map { |feature| File.dirname(feature) }.
map { |feature| feature.split('/').last }.
uniq.sort
=> ["1.9.1", "action_dispatch", "action_pack", "action_view", "actions", "active_model", "active_record", "active_support", "addressable", "agent", "array", "aws", "builder", "bundler", "cache_stores", "cancan", "cdn", "class", "client", "common", "compute", "connection", "control", "controllers", "core", "core_ext", "core_extensions", "css", "data_mapper", "decorators", "dependencies", "dependency_detection", "deprecation", "devise", "digest", "dns", "encodings", "encryptor", "engine", "errors", "excon", "ext", "failure", "faraday", "fields", "fog", "formatador", "geographer", "haml", "hash", "helpers", "heroku_san", "hmac", "hooks", "hoptoad_notifier", "html", "http", "i18n", "idna", "importers", "inflector", "initializers", "instrumentation", "integrations", "interpolate", "interval_skip_list", "jquery-rails", "json", "kaminari", "kernel", "lib", "mail", "metric_parser", "mime", "mixins", "model_adapters", "models", "module", "mongo_mapper", "mongoid", "multibyte", "new_relic", "node", "nokogiri", "numeric", "oauth", "object", "omniauth", "orm_adapter", "package", "parser", "parsers", "plugin", "pp", "providers", "queued", "rack", "rails", "railtie", "redis", "request", "request_proxy", "resp ruby-1.9.2-p180 :008 >onse", "resque", "retriever_methods", "routing", "ruby_extensions", "ruby_flipper", "rubygems", "runtime", "samplers", "sass", "sax", "script", "scss", "selector", "sequel", "ses", "shell", "signature", "simple_geo", "state_machine", "stats_engine", "storage", "strategies", "string", "tar_reader", "template", "terremark", "thor", "tokens", "tree", "treetop", "twitter", "us", "util", "vendor", "version_specific", "visitors", "warden", "xml", "xml_mini", "xpath", "xslt"]
Here's a way to get all the calls to require. Create this file: show_requires.rb
alias :orig_require :require
def require s
print "Requires #{s}\n" if orig_require(s)
end
Then start your app with
ruby -r show_requires.rb myapp.rb
This produces something like:
C:\code\test>ruby -r show_requires.rb test.rb
Requires stringio
Requires yaml/error
Requires syck
Requires yaml/ypath
Requires yaml/basenode
Requires yaml/syck
Requires yaml/tag
Requires yaml/stream
Requires yaml/constants
Requires date/format
Requires date
Requires yaml/rubytypes
Requires yaml/types
Requires yaml
Requires etc
Requires dl
Requires rbreadline
Requires readline
If you want only the top-level requires, add a global to track the nesting level:
$_rq_lvl = 0
alias :orig_require :require
def require s
$_rq_lvl+=1
print "Requires #{s}\n" if orig_require(s) and $_rq_lvl == 1
$_rq_lvl -=1
end
Then you get:
C:\code\test>ruby -r require_test.rb test.rb
Requires yaml
Requires readline