Как получить список файлов, которые были "обязательны" в Ruby?
Это чисто эксперимент, но мне интересно, можно ли получить список require
бы жемчужины во время выполнения с помощью какого-то метапрограммирования. Например, скажем, у меня есть:
require 'rubygems'
require 'sinatra'
require 'nokogiri'
# don't know what to do here
Как я могу распечатать следующее во время выполнения?
this app needs rubygems, sinatra, nokogiri
2 ответа
Вы не можете сделать это точно, потому что для запроса одного файла могут потребоваться другие, а Ruby не может определить разницу между файлом, который вам нужен, и файлом, который требуется кому-то другому.
Вы можете проверить $LOADED_FEATURES
для списка каждой вещи, которая требовалась. Но вы должны использовать Bundler, если вы хотите явно указать зависимости.
Вот совершенно несовершенный способ угадать имена драгоценных камней и перечислить все:
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"]
Вот способ получить все звонки по требованию. Создайте этот файл: show_requires.rb
alias :orig_require :require
def require s
print "Requires #{s}\n" if orig_require(s)
end
Затем запустите ваше приложение с
ruby -r show_requires.rb myapp.rb
Это производит что-то вроде:
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
Если вы хотите только требования верхнего уровня, добавьте глобальный для отслеживания уровня вложенности:
$_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
Тогда вы получите:
C:\code\test>ruby -r require_test.rb test.rb
Requires yaml
Requires readline
Просто небольшое дополнение к предыдущему - учтите, что для точной замены поведения #require вы также должны вернуть логическое значение, так что это более точное переопределение:
module Kernel
alias :orig_require :require
def require(name)
print "Requiring #{name}"
is_okay = orig_require(name)
puts " - #{is_okay ? 'Yup!' : 'Nope :('}"
is_okay
end
end
Что интересно, когда я проводил некоторое тестирование - отслеживая цепочку взрывающихся вещей, когда требовался модуль - тогда это стало необходимым!