How do I get a list of files that have been `required` in Ruby?

前端 未结 3 1173
遥遥无期
遥遥无期 2020-12-28 13:37

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

相关标签:
3条回答
  • 2020-12-28 14:14

    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"] 
    
    0 讨论(0)
  • 2020-12-28 14:14

    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
    
    0 讨论(0)
  • 2020-12-28 14:25

    Just a slight touch to add to the previous -- consider that in order to precisely replace the behaviour of #require then you must also return a boolean value, so this is a more faithful override:

    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
    

    Interestingly with some testing I was doing -- tracking down a chain of stuff blowing up when requiring a module -- then this became necessary!

    0 讨论(0)
提交回复
热议问题