Class Capsule
In: lib/more/facets/capsule.rb
Parent: Module

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

Classes and Modules

Class Capsule::MissingFile

Attributes

load_path  [R]  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 ’.’)
loaded_features  [R]  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.
main_file  [R]  The script file with which the Import was instantiated.

Public Class methods

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

[Source]

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

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.

[Source]

     # File lib/more/facets/capsule.rb, line 92
 92:   def initialize(main_file, options=nil, &block)
 93:     extend self
 94: 
 95:     options ||= {}
 96: 
 97:     @main_file       = File.expand_path(main_file)
 98:     @load_path       = options[:load_path] || []
 99:     #@load_path |= [File.dirname(@main_file)]  # before or after?
100:     @loaded_features = options[:loaded_features] || {}
101: 
102:     # TODO In order to load/require at the instance level.
103:     # This needs to be in a separate namespace however
104:     # b/c it can interfere with what is expected.
105:     #[ :require, :load ].each{ |meth|
106:     #  m = method(meth)
107:     #  define_method(meth) do |*args| m.call(*args) end
108:     #}
109: 
110:     module_eval(&block) if block
111:     extend self
112: 
113:     load_in_module(main_file)
114:   end

Public Instance methods

[Source]

     # File lib/more/facets/capsule.rb, line 204
204:   def include(*mods)
205:     super
206:     extend self
207:   end

[Source]

     # File lib/more/facets/capsule.rb, line 193
193:   def include_script(file)
194:     include self.class.new(file, :load_path=>load_path, :loaded_features=>loaded_features)
195:   rescue Errno::ENOENT => e
196:     if /#{file}$/ =~ e.message
197:       raise MissingFile, e.message
198:     else
199:       raise
200:     end
201:   end

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.

[Source]

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

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.

[Source]

     # File lib/more/facets/capsule.rb, line 183
183:   def load_in_module(file)
184:     module_eval(IO.read(file), File.expand_path(file))
185:   rescue Errno::ENOENT => e
186:     if /#{file}$/ =~ e.message
187:       raise MissingFile, e.message
188:     else
189:       raise
190:     end
191:   end

Lookup feature in load path.

[Source]

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

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.

[Source]

     # File lib/more/facets/capsule.rb, line 164
164:   def require(feature)
165:     file = load_path_lookup(feature)
166:     return super unless file
167:     begin
168:       @loaded_features[file] = true
169:       load_in_module(file)
170:     rescue MissingFile
171:       @loaded_features[file] = false
172:       super
173:     end
174:   end

[Validate]