Class: Bezel
- Inherits:
-
Module
- Object
- Module
- Bezel
- Defined in:
- lib/bezel.rb
Overview
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 bezel file (e.g. lib/tomslib.rbz) from 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 toplevel ‘::` 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 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/’.
Constant Summary collapse
- TABLE =
Cache of loaded modules. This speeds things up if two libraries load the same third library.
Hash.new
- SCRIPT =
Script cache.
{}
- STACK =
Load stack keeps track of what modules are in the process of being loaded.
[]
Class Method Summary collapse
-
.development=(boolean) ⇒ Object
When in development mode, Bezel uses the latest and greatest available version regardless of version settings.
- .development? ⇒ Boolean
-
.lib(name, version = nil) ⇒ Object
Load library into a module namespace.
- .require(path) ⇒ Object
Instance Method Summary collapse
- #__features__ ⇒ Object
- #__load_feature__(path) ⇒ Object
-
#__name__ ⇒ Object
Name of library.
-
#__version__ ⇒ Object
Version of library.
-
#initialize(name, version) ⇒ Bezel
constructor
Construct new Bezel module.
Constructor Details
#initialize(name, version) ⇒ Bezel
Construct new Bezel module.
130 131 132 133 134 135 136 |
# File 'lib/bezel.rb', line 130 def initialize(name, version) #, path) @__name__ = name @__version__ = version #@__path__ = path @__features__ = [] super() end |
Class Method Details
.development=(boolean) ⇒ Object
When in development mode, Bezel uses the latest and greatest available version regardless of version settings.
63 64 65 |
# File 'lib/bezel.rb', line 63 def self.development=(boolean) @development = !!boolean end |
.development? ⇒ Boolean
68 69 70 |
# File 'lib/bezel.rb', line 68 def self.development? @development end |
.lib(name, version = nil) ⇒ Object
Load library into a module namespace.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/bezel.rb', line 73 def self.lib(name, version=nil) version = nil if development? ##path = find(name, version) ##raise LoadError, "#{name}-#{version} not found" unless path ## location of main requirement file ## TODO: should we require a dedicated bezel file instead? e.g. `*.rbz`. #main = File.join(path, 'lib', name + '.rb') #.rbz #TODO: LOADPATH main = Find.feature(name, :from=>name, :version=>version, :absolute=>true).first ## check cache return TABLE[main] if TABLE.key?(main) ## load error if no bezel file raise LoadError, "#{name}-#{version} has no bezel!" unless main && File.exist?(main) ## read in bezel file #script = File.read(main) ## create new Bezel module for file mod = new(name, version) #, main) ## put module on STACK STACK.push mod ## evaluate script in the context of module #mod.module_eval(script, main, 0) # r = mod.__load_feature__(main) ## pop module off STACK STACK.pop ## add module to cache, and return module TABLE[main] = mod end |
.require(path) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/bezel.rb', line 111 def self.require(path) if current = STACK.last begin current.__load_feature__(path) ? true : false rescue LoadError require_without_bezel(path) end else require_without_bezel(path) end end |
Instance Method Details
#__features__ ⇒ Object
154 155 156 |
# File 'lib/bezel.rb', line 154 def __features__ @__features__ end |
#__load_feature__(path) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/bezel.rb', line 159 def __load_feature__(path) if path =~ /^[\.\/]/ # if absolute path file = File.(path) else file = Find.feature(path, :from=>__name__, :version=>__version__, :absolute=>true).first end raise LoadError, "no such file to load -- #{file}" unless file if __features__.include?(file) return false else __features__ << file script = File.read(file) #(SCRIPT[file] ||= File.read(file)) module_eval(script, file, 0) end return file end |
#__name__ ⇒ Object
Name of library.
139 140 141 |
# File 'lib/bezel.rb', line 139 def __name__ @__name__ end |
#__version__ ⇒ Object
Version of library.
144 145 146 |
# File 'lib/bezel.rb', line 144 def __version__ @__version__ end |