Capsule

A Capsule is subclass of Module. It encapsulates an extenal script as a funcitons module.

A module which is an instance of the Capsule class encapsulates in its scope the top-level methods, top-level constants, and instance variables defined in a ruby script file (and its subfiles) loaded by a ruby program. This allows use of script files to define objects that can be loaded into a program in much the same way that objects can be loaded from YAML or Marshal files.

See intro.txt for an overview.

Methods
include include_script load load load_in_module load_path_lookup new require
Classes and Modules
Class Capsule::MissingFile
Attributes
[R] load_path An array of paths to search for scripts. This has the same semantics as $:, alias $LOAD_PATH, excpet that it is local to this script. The path of the current script is added automatically (equivalent to ’.’)
[R] loaded_features A hash that maps filename=>true for each file that has been required locally by the script. This has the same semantics as $", alias $LOADED_FEATURES, except that it is local to this script.
[R] main_file The script file with which the Import was instantiated.
Public Class methods
load(main_file, options=nil, &block)

As with new but will search Ruby‘s $LOAD_PATH first.

# File lib/more/facets/capsule.rb, line 78
    def load(main_file, options=nil, &block)
      file = nil
      $LOAD_PATH.each do |path|
        break if file = File.file?(File.join(path, main_file))
        #break if file = Dir.glob(File.join(path, main_file)+'{,.rb,.'+DLEXT+'}')[0]
      end
      new(file || main_file, options=nil, &block)
    end
new(main_file, options=nil, &block)

Creates new Capsule, and loads main_file in the scope of the script. If a block is given, the script is passed to it before loading from the file, and constants can be defined as inputs to the script.

# File lib/more/facets/capsule.rb, line 92
  def initialize(main_file, options=nil, &block)
    extend self

    options ||= {}

    @main_file       = File.expand_path(main_file)
    @load_path       = options[:load_path] || []
    #@load_path |= [File.dirname(@main_file)]  # before or after?
    @loaded_features = options[:loaded_features] || {}

    # TODO In order to load/require at the instance level.
    # This needs to be in a separate namespace however
    # b/c it can interfere with what is expected.
    #[ :require, :load ].each{ |meth|
    #  m = method(meth)
    #  define_method(meth) do |*args| m.call(*args) end
    #}

    module_eval(&block) if block
    extend self

    load_in_module(main_file)
  end
Public Instance methods
include(*mods)
# File lib/more/facets/capsule.rb, line 204
  def include(*mods)
    super
    extend self
  end
include_script(file)
# File lib/more/facets/capsule.rb, line 193
  def include_script(file)
    include self.class.new(file, :load_path=>load_path, :loaded_features=>loaded_features)
  rescue Errno::ENOENT => e
    if /#{file}$/ =~ e.message
      raise MissingFile, e.message
    else
      raise
    end
  end
load(file, wrap = false)

Loads file into the capsule. Searches relative to the local dir, that is, the dir of the file given in the original call to Capsule.load(file), loads the file, if found, into this Capsule‘s scope, and returns true. If the file is not found, falls back to Kernel.load, which searches on $LOAD_PATH, loads the file, if found, into global scope, and returns true. Otherwise, raises LoadError.

The wrap argument is passed to Kernel.load in the fallback case, when the file is not found locally.

Typically called from within the main file to load additional sub files, or from those sub files.

# File lib/more/facets/capsule.rb, line 143
  def load(file, wrap = false)
    load_in_module(File.join(@dir, file))
    true
  rescue MissingFile
    super
  end
load_in_module(file)

Loads file in this module‘s context. Note that __FILE__ and __LINE__ work correctly in file. Called by load and require; not normally called directly.

# File lib/more/facets/capsule.rb, line 183
  def load_in_module(file)
    module_eval(IO.read(file), File.expand_path(file))
  rescue Errno::ENOENT => e
    if /#{file}$/ =~ e.message
      raise MissingFile, e.message
    else
      raise
    end
  end
load_path_lookup(feature)

Lookup feature in load path.

# File lib/more/facets/capsule.rb, line 118
  def load_path_lookup(feature)
    paths = File.join('{' + @load_path.join(',') + '}', feature + '{,.rb,.rbs}')
    files = Dir.glob(paths)
    match = files.find{ |f| ! @loaded_features.include?(f) }
    return match
  end
require(feature)

Analogous to Kernel#require. First tries the local dir, then falls back to Kernel#require. Will load a given feature only once.

Note that extensions (*.so, *.dll) can be required in the global scope, as usual, but not in the local scope. (This is not much of a limitation in practice—you wouldn‘t want to load an extension more than once.) This implementation falls back to Kernel#require when the argument is an extension or is not found locally.

# File lib/more/facets/capsule.rb, line 164
  def require(feature)
    file = load_path_lookup(feature)
    return super unless file
    begin
      @loaded_features[file] = true
      load_in_module(file)
    rescue MissingFile
      @loaded_features[file] = false
      super
    end
  end