In Files
Parent
- Module
Information
Bezel
The idea of Bezel is to overcome the limitations of using different versions of the same package in the same Ruby proccess.
It works like this. Let’s say I wrote a library called TomsLib. Now I want to use TomsLib in my new fancy app, FancyApp. In my FancyApp namespace I have to create a reference to TomsLib.
module FancyApp
TomsLib = lib('tomslib', '1.5')
...
Now I have access to TomsLib, but it is localized to my application. If Jane comes along and wants to use a different version of TomsLib but also utilizes my FancyApp, she could do so:
module JanesProgram
TomsLib = lib('tomslib', '1.0')
FancyApp = lib('fancyapp') # use newest available
...
How does this work? When you call lib(), Bezel looks for the package in the current gem paths (and, in the future, Roll ledger) then it reads the primary package file (eg. tomslib.rb) fro the package and evals it into an anonymous module.
This has a some important effects on how you write your Ruby programs:
-
Any reference to core/standard libraries must be referenced via
prefix (eg. ::Enumerable).
-
Core extensions are not version controlled. So avoid them when possible, or depend on highly stable standardized bases such as Facets and ActiveSupport.
-
Since Bezel is a completely different alternative to Ruby’s normal load system, your program will require Bezel be installed by your users.
Despite these necessary practices for its use, Bezel is highly advantageous to the developers and end-users alike in that it puts an end to the dreaded Dependency Hell.
TODO: Consider how best to support alternate loadpaths beyond ‘lib/’.
Constants
Public Class Methods
# File lib/bezel.rb, line 123 def self.find(name, version=nil) path = nil path ||= gem_find(name, version) if defined?(::Gem) path ||= roll_find(name, version) if defined?(::Roll) path end
# File lib/bezel.rb, line 131 def self.gem_find(name, version) raise ArgumentError, "version must be explicit" unless version basename = "#{name}-#{version}" gem_paths.find do |path| File.basename(path) == basename end end
# File lib/bezel.rb, line 141 def self.gem_paths @gem_paths ||= ( Gem.path.map do |dir| Dir[File.join(dir, 'gems', '*')] end.flatten ) end
# File lib/bezel.rb, line 83 def self.import(fname) ## lookup most recent Bezel module mod = STACK.last ## if Bezel module is returned if mod ## TODO: Hadle loadpath? file = File.join(mod.__path__, 'lib', fname) ## TODO: Support other extensions, like .rbx and .so? file = file + '.rb' unless file[-3,3] == '.rb' ## raise load error if file does not exist raise LoadError, "no such file to load -- #{file}" unless File.exist?(file) ## evaluate script in the context of module mod.module_eval(File.read(file), file, 0) else ## if no Bezel module is returned ## fallback to regular require require(fname) end end
Load library into a module namespace.
# File lib/bezel.rb, line 57 def self.lib(name, version=nil) path = find(name, version) ## load error if no gem found raise LoadError, "#{name}-#{version} not found" unless path ## location of bezel file main = File.join(path, 'lib', name + '.bezel') #TODO:LOADPATH ## check cache return TABLE[main] if TABLE.key?(main) ## load error if no bezel file raise LoadError, "#{name}-#{version} has no bezel!" unless File.exist?(main) ## read in bezel file script = File.read(main) # create new Bezel module for file mod = new(name, version, path) ## put module on STACK STACK.push mod ## evaluate script in the context of module mod.module_eval(script, main, 0) # r = ## pop module off STACK STACK.pop ## add module to cache, and return module TABLE[main] = mod # if Module === r ? r : mod end
Construct new Bezel module.
# File lib/bezel.rb, line 155 def initialize(name, version, path) @__name__ = name @__version__ = version @__path__ = path super() end
Disabled; run with --debug to generate this.