Module: Loadable

Included in:
GemLoader, OriginalLoader, RollLoader, RubyLoader, VendorLoader
Defined in:
lib/loadable/mixin.rb,
lib/loadable/domain.rb,
lib/loadable/loaders/gem_loader.rb,
lib/loadable/loaders/roll_loader.rb,
lib/loadable/loaders/ruby_loader.rb,
lib/loadable/loaders/vendor_loader.rb,
lib/loadable/loaders/original_loader.rb

Overview

First, it can be used as a mixin for loaders (also called load wedges). Loaders are used to safely inject new import logic into Ruby’s require/load system.

Secondly, Loadable’s class methods are used to override Ruby’s built-in require and load Kernel methods.

Active load wedges are stored in ‘$LOADERS` global variable.

IMPORTANT: This must be loaded before ‘loadable/kernel.rb`.

Defined Under Namespace

Classes: GemLoader, OriginalLoader, RollLoader, RubyLoader, VendorLoader

Constant Summary collapse

RB_EXTS =

Script extensions recognized by Ruby (MRI and variants).

['.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.call(fname, options = {}) ⇒ Object

Require/load script.

Parameters:

  • fname (String)

    The script to require/load.



11
12
13
14
15
16
17
18
# File 'lib/loadable/domain.rb', line 11

def self.call(fname, options={})
  success = nil
  $LOADERS.each do |wedge| 
    success = wedge.call(fname, options)
    break unless success.nil?
  end
  return success
end

.each(options = {}, &block) ⇒ Object

Iterate over all requirable files.

Loadable.each{ |file| p file }

Note that esoteric load wedges may return a symbolic path rather than an actual file path.



27
28
29
30
31
# File 'lib/loadable/domain.rb', line 27

def self.each(options={}, &block)
  $LOADERS.each do |wedge| 
    wedge.each(options, &block)
  end
end

.register(loader) ⇒ Object

Add a loader to the $LOADERS global variable.



60
61
62
# File 'lib/loadable/domain.rb', line 60

def self.register(loader)
  $LOADERS.unshift(loader)
end

.search(glob, options = {}, &criteria) ⇒ Object

Search wedges for all matching paths.

Loadable.search('detroit-*.rb')

Note that “esoteric” wedges might return a symbolic identifier rather than an actual file path.

TODO: Handle default ruby extensions in search.



41
42
43
44
45
46
47
48
49
50
# File 'lib/loadable/domain.rb', line 41

def self.search(glob, options={}, &criteria)
  matches = []
  $LOADERS.each do |wedge| 
    wedge.each do |path|
      next unless criteria.call(path) if criteria
      matches << path if File.fnmatch?(glob, path.to_s)  # TODO: add `options[:flags].to_i` ?
    end
  end
  matches
end

.vendor(*directory) ⇒ Object

Vendor location.



54
55
56
# File 'lib/loadable/domain.rb', line 54

def self.vendor(*directory)
  $LOADERS.unshift(VendorLoader.new(*directory))
end

Instance Method Details

#call(fname, options = {}) ⇒ Object



25
26
27
28
29
30
31
# File 'lib/loadable/mixin.rb', line 25

def call(fname, options={})
  if options[:load]
    load(fname, options[:wrap])
  else
    require(fname)
  end
end

#default_file_extensionsObject (private)

This method is used by ‘#lookup` to handle defualt file extensions. By default it returns the value of the `RB_EXTS` constant.



89
90
91
# File 'lib/loadable/mixin.rb', line 89

def default_file_extensions
  RB_EXTS
end

#each(options = {}, &block) ⇒ Object

A load wedge should provide a means for iterating over all requirable files that its ‘#call` method could load.

If a load wedge is “esoteric”, in that it doesn’t actually load a file, then it’s ‘#each` method can iterate over a list of suitable symbolic identifiers, or if otherwise necessary nothing at all. But be sure to document this prominantly!!!



41
42
# File 'lib/loadable/mixin.rb', line 41

def each(options={}, &block)
end

#lookup(base_path, relative_path, options = {}) ⇒ Object (private)

Given a base-path, and a path relative to it determine if a matching file exists. Unless :load option is true, this will check for each viable Ruby suffix. If a match is found the full path to the file is returned, otherwise nil.



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/loadable/mixin.rb', line 56

def lookup(base_path, relative_path, options={})
  exts = default_file_extensions
  if options[:load] or exts.include?(File.extname(relative_path))
    abspath = File.join(base_path, relative_path)
    File.exist?(abspath) ? abspath : nil
  else
    exts.each do |ext|
      abspath = File.join(base_path, relative_path + ext)
      return abspath if File.exist?(abspath)
    end
    nil
  end
end

#nameObject

Name of wedge. By default it is simply the class name.



45
46
47
# File 'lib/loadable/mixin.rb', line 45

def name
  self.class.name
end

#raise_load_error(fname) ⇒ Object (private)

Raise LoadError with an error message patterned after Ruby’s standard error message when a script can’t be required or loaded.

Raises:

  • (LoadError)


96
97
98
# File 'lib/loadable/mixin.rb', line 96

def raise_load_error(fname)
  raise LoadError, "no such file to load -- #{fname}"
end

#traverse(dir, base = dir, &block) ⇒ Object (private)

This helper method provides a fast way to traverse a directory recursively iteratating over each file.



73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/loadable/mixin.rb', line 73

def traverse(dir, base=dir, &block)
  return unless File.directory?(dir)
  Dir.new(dir).each do |file|
    next if file == '.' or file == '..'
    path = File.join(dir, file)
    if File.directory?(path)
      traverse(path, base, &block)
    else
      block.call(path.sub(base+'/',''))
    end
  end
end