roll 0.8.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. data/{LICENSE → COPYING} +1 -1
  2. data/HISTORY +62 -0
  3. data/README.rdoc +169 -0
  4. data/TODO +4 -0
  5. data/bin/roll +3 -44
  6. data/lib/oll.rb +1 -2
  7. data/lib/roll.rb +87 -0
  8. data/lib/roll/command.rb +207 -0
  9. data/lib/roll/config.rb +80 -0
  10. data/lib/roll/environment.rb +317 -0
  11. data/lib/roll/errors.rb +13 -0
  12. data/lib/roll/kernel.rb +41 -0
  13. data/lib/roll/ledger.rb +299 -0
  14. data/lib/roll/library.rb +241 -558
  15. data/lib/roll/locals.rb +96 -0
  16. data/lib/roll/metadata.rb +112 -0
  17. data/lib/roll/original.rb +10 -0
  18. data/lib/roll/version.rb +91 -101
  19. data/meta/active +1 -0
  20. data/meta/authors +1 -0
  21. data/meta/contact +1 -0
  22. data/meta/created +1 -0
  23. data/meta/description +5 -0
  24. data/meta/homepage +1 -0
  25. data/meta/maintainer +1 -0
  26. data/meta/name +1 -0
  27. data/meta/repository +1 -0
  28. data/meta/ruby +2 -0
  29. data/meta/suite +1 -0
  30. data/meta/summary +1 -0
  31. data/meta/version +1 -0
  32. data/script/rdoc +4 -0
  33. data/script/setup +1344 -0
  34. data/script/test +23 -0
  35. data/test/benchmarks/vsgems.rb +11 -0
  36. data/test/benchmarks/vsgems_bm.rb +17 -0
  37. data/test/demonstrations/01_library.rdoc +33 -0
  38. data/test/demonstrations/04_version.rdoc +56 -0
  39. data/test/fixtures/env.list +1 -0
  40. data/{demo/sample → test/fixtures}/inspect.rb +0 -0
  41. data/test/fixtures/tryme/1.0/lib/tryme.rb +1 -0
  42. data/test/fixtures/tryme/1.0/meta/homepage +1 -0
  43. data/test/fixtures/tryme/1.0/meta/name +1 -0
  44. data/test/fixtures/tryme/1.0/meta/version +1 -0
  45. data/test/fixtures/tryme/1.1/lib/tryme.rb +1 -0
  46. data/test/fixtures/tryme/1.1/meta/homepage +1 -0
  47. data/test/fixtures/tryme/1.1/meta/name +1 -0
  48. data/test/fixtures/tryme/1.1/meta/version +1 -0
  49. data/test/{test_version.rb → unit/version_test.rb} +21 -21
  50. data/test/unitcases/version_case.rb +69 -0
  51. metadata +102 -65
  52. data/README +0 -17
  53. data/demo/bench/bench_load.rb +0 -7
  54. data/demo/sample/tryme/1.0/lib/tryme.rb +0 -1
  55. data/demo/sample/tryme/1.1/lib/tryme.rb +0 -1
  56. data/lib/roll/attributes.rb +0 -72
  57. data/lib/roll/package.rb +0 -300
  58. data/lib/roll/remote.rb +0 -37
  59. data/meta/ROLL-0.8.0.roll +0 -21
  60. data/task/rdoc +0 -9
  61. data/task/setup +0 -1616
  62. data/task/test +0 -5
  63. data/test/test_library.rb +0 -10
@@ -0,0 +1,299 @@
1
+ module Roll
2
+ require 'roll/original'
3
+ require 'roll/environment'
4
+ require 'roll/library'
5
+
6
+ # = Ledger class
7
+ #
8
+ class Ledger
9
+
10
+ include Enumerable
11
+
12
+ #
13
+ def initialize
14
+ @index = Hash.new{|h,k| h[k] = []}
15
+
16
+ @environment = Environment.new
17
+
18
+ @environment.each do |name, paths|
19
+ paths.each do |path|
20
+ unless File.directory?(path)
21
+ warn "roll: invalid path for #{name} -- #{path}"
22
+ next
23
+ end
24
+ lib = Library.new(path, name)
25
+ @index[name] << lib if lib.active?
26
+ end
27
+ end
28
+
29
+ @load_stack = []
30
+ @load_monitor = Hash.new{ |h,k| h[k]=[] }
31
+ end
32
+
33
+ #
34
+ def enironment
35
+ @environment
36
+ end
37
+
38
+ #
39
+ def [](name)
40
+ @index[name]
41
+ end
42
+
43
+ #
44
+ def []=(name, value)
45
+ @index[name] = value
46
+ end
47
+
48
+ #
49
+ def include?(name)
50
+ @index.include?(name)
51
+ end
52
+
53
+ #
54
+ def names
55
+ @index.keys
56
+ end
57
+
58
+ #
59
+ def each(&block)
60
+ @index.each(&block)
61
+ end
62
+
63
+ #
64
+ def size
65
+ @index.size
66
+ end
67
+
68
+ #
69
+ def load_stack
70
+ @load_stack
71
+ end
72
+
73
+ # NOTE: Not used yet.
74
+ def load_monitor
75
+ @load_monitor
76
+ end
77
+
78
+ #--
79
+ # TODO: Should Ruby's underlying require be tried first,
80
+ # then fallback to Rolls. Or vice-versa?
81
+ #++
82
+
83
+ #
84
+ def require(path)
85
+ #begin
86
+ # original_require(path)
87
+ #rescue LoadError => load_error
88
+ # lib, file = *match(path)
89
+ # if lib && file
90
+ # constrain(lib)
91
+ # lib.require_absolute(file)
92
+ # else
93
+ # raise clean_backtrace(load_error)
94
+ # end
95
+ #end
96
+ lib, file = *match(path)
97
+ if lib && file
98
+ constrain(lib)
99
+ lib.require_absolute(file)
100
+ else
101
+ begin
102
+ original_require(path)
103
+ rescue LoadError => load_error
104
+ raise clean_backtrace(load_error)
105
+ end
106
+ end
107
+
108
+ end
109
+
110
+ #
111
+ def load(path, wrap=nil)
112
+ lib, file = *match(path, false)
113
+ if lib && file
114
+ constrain(lib)
115
+ lib.load_absolute(file, wrap)
116
+ else
117
+ begin
118
+ original_load(path, wrap)
119
+ rescue LoadError => load_error
120
+ raise clean_backtrace(load_error)
121
+ end
122
+ end
123
+ end
124
+
125
+ # Use acquire to use Roll-style loading. This first
126
+ # looks for a specific library via ':'. If ':' is
127
+ # not present it then tries the current library.
128
+ # Failing that it fallsback to Ruby itself.
129
+ #
130
+ # acquire('facets:string/margin')
131
+ #
132
+ # To "load" the library, rather than "require" it set
133
+ # the +:load+ option to true.
134
+ #
135
+ # acquire('facets:string/margin', :load=>true)
136
+ #
137
+ def acquire(file, opts={})
138
+ if file.index(':') # a specific library
139
+ name, file = file.split(':')
140
+ lib = Library.open(name)
141
+ else # try the current library
142
+ cur = load_stack.last
143
+ if cur && cur.include?(file)
144
+ lib = cur
145
+ elsif !file.index('/') # is this a library name?
146
+ if cur = Library.instance(file)
147
+ lib = cur
148
+ file = lib.default # default file to load
149
+ end
150
+ end
151
+ end
152
+ if opts[:load]
153
+ lib ? lib.load(file) : original_load(file)
154
+ else
155
+ lib ? lib.require(file) : original_require(file)
156
+ end
157
+ end
158
+
159
+ #
160
+ def constrain(lib)
161
+ cmp = self[lib.name]
162
+ if Array === cmp
163
+ self[lib.name] = lib
164
+ else
165
+ if lib.version != cmp.version
166
+ raise VersionError
167
+ end
168
+ end
169
+ end
170
+
171
+ private
172
+
173
+ # Find require matches.
174
+ def match(path, suffix=true)
175
+ path = path.to_s
176
+
177
+ return nil if /^\// =~ path # absolute path
178
+
179
+ if path.index(':') # a specified library
180
+ name, path = path.split(':')
181
+ lib = Library.open(name)
182
+ if lib.active?
183
+ file = lib.find(path, suffix)
184
+ return lib, file
185
+ end
186
+ end
187
+
188
+ matches = []
189
+
190
+ # try the load stack first
191
+ load_stack.reverse_each do |lib|
192
+ if file = lib.find(path, suffix)
193
+ return [lib, file] unless $VERBOSE
194
+ matches << [lib, file]
195
+ end
196
+ end
197
+
198
+ # TODO: Perhaps the selected and unselected should be kept in separate lists?
199
+ unselected, selected = *@index.partition{ |name, libs| Array === libs }
200
+
201
+ selected.each do |(name, lib)|
202
+ if file = lib.find(path, suffix)
203
+ #matches << [lib, file]
204
+ #return matches.first unless $VERBOSE
205
+ return [lib, file] unless $VERBOSE
206
+ matches << [lib, file]
207
+ end
208
+ end
209
+
210
+ unselected.each do |(name, libs)|
211
+ pos = []
212
+ libs.each do |lib|
213
+ if file = lib.find(path, suffix)
214
+ pos << [lib, file]
215
+ end
216
+ end
217
+ unless pos.empty?
218
+ latest = pos.sort{ |a,b| b[0].version <=> a[0].version }.first
219
+ return latest unless $VERBOSE
220
+ matches << latest
221
+ #return matches.first unless $VERBOSE
222
+ end
223
+ end
224
+
225
+ matches.uniq!
226
+
227
+ if matches.size > 1
228
+ warn_multiples(path, matches)
229
+ end
230
+
231
+ matches.first
232
+ end
233
+
234
+ #
235
+ def warn_multiples(path, matches)
236
+ warn "multiple matches for same request -- #{path}"
237
+ matches.each do |lib, file|
238
+ warn " #{file}"
239
+ end
240
+ end
241
+
242
+ #
243
+ def clean_backtrace(error)
244
+ if $DEBUG
245
+ error
246
+ else
247
+ bt = error.backtrace
248
+ bt = bt.reject{ |e| /roll/ =~ e }
249
+ error.set_backtrace(bt)
250
+ error
251
+ end
252
+ end
253
+
254
+ end#class Ledger
255
+
256
+ #--
257
+ # Ledger augments the Library metaclass.
258
+ #++
259
+ class << Library
260
+
261
+ #
262
+ def ledger
263
+ @ledger ||= Ledger.new
264
+ end
265
+
266
+ # Current environment
267
+ def environment
268
+ ledger.environment
269
+ end
270
+
271
+ # List of library names.
272
+ def list
273
+ ledger.names
274
+ end
275
+
276
+ #
277
+ def require(path)
278
+ ledger.require(path)
279
+ end
280
+
281
+ #
282
+ def load(path, wrap=nil)
283
+ ledger.load(path, wrap)
284
+ end
285
+
286
+ #
287
+ def load_stack
288
+ ledger.load_stack
289
+ end
290
+
291
+ # NOTE: Not used yet.
292
+ def load_monitor
293
+ ledger.load_monitor
294
+ end
295
+
296
+ end
297
+
298
+ end#module Roll
299
+
@@ -1,635 +1,318 @@
1
- # TITLE:
2
- #
3
- # library.rb
4
- #
5
- # LICENSE:
6
- #
7
- # Copyright (c)2007 Thomas Sawyer, Ruby License
8
- #
9
- # TODO:
10
- #
11
- # - Commented out #import for now. Facets' module_require and module_load
12
- # are probably better. Implement those for Rolls instead. (Yes?)
13
- # - Maybe add autopackage install system?
14
- # - What about remotes? What about version tiers when remote requiring?
15
-
16
- require 'rbconfig'
17
- require 'fileutils'
18
- require 'roll/package'
1
+ #require 'rbconfig'
19
2
  require 'roll/version'
20
- #require 'roll/sign'
21
-
22
- # We need to hold a copy of the original $LOAD_PATH
23
- # for specified "ruby: ..." loads.
24
-
25
- $RUBY_PATH = $LOAD_PATH.dup
26
-
27
- # Locations of rolls-ready libraries.
28
- # # We could use the site_ruby locations instead, but that creates an odd sort of overlap in
29
- # # the load paths, and would also promote putting the information file in the lib/ dir. So
30
- # # I think it's better to use a separate location. (After all site_ruby may just fade away.)
31
- # $LOAD_SITE = $LOAD_PATH - Config::CONFIG.values_at('rubylibdir', 'archdir') - ['.']
32
-
33
- rolldir = 'ruby_library'
34
- sitedir = ::Config::CONFIG['sitedir']
35
- version = ::Config::CONFIG['ruby_version']
3
+ require 'roll/metadata'
4
+ require 'roll/errors'
36
5
 
37
- $LOAD_SITE = [File.join(File.dirname(sitedir), rolldir, version)] + ENV['ROLL_PATH'].to_s.split(':')
38
-
39
- # = Library Class
40
- #
41
- # The Library class serves as an objecified location in Ruby's load paths.
42
- #
43
- # The Library qua class also serves as the library manager, storing a ledger of
44
- # available libraries.
45
- #
46
- # A library is roll-ready when it supplies a {name}-{verison}.roll file in either its
47
- # base directory or in the base's meta/ directory. The roll file name is specifically
48
- # designed to make library lookup fast. There is no need for Rolls to open the roll
49
- # file until an actual version is used. It also gives the most flexability in repository
50
- # layout. Rolls searches up to three subdirs deep looking for roll files. This is
51
- # suitable to non-versioned libs, versioned libs, non-versioned subprojects and subprojects,
52
- # including typical Subversion repository layouts.
53
-
54
- class Library
55
-
56
- # Dynamic link extension.
57
- def self.dlext
58
- @dlext ||= '.' + ::Config::CONFIG['DLEXT']
59
- end
60
-
61
- # Location of rolls-ready libs.
62
- def self.load_site
63
- $LOAD_SITE
64
- end
6
+ module Roll
65
7
 
8
+ # = Library class
66
9
  #
67
- def self.load_path
68
- $LOAD_PATH
69
- end
10
+ class Library
70
11
 
71
- #
72
- def self.ruby_path
73
- $RUBY_PATH
74
- end
75
-
76
- # Name of library.
77
- attr_reader :name
78
-
79
- # Version of library. This is a VersionNumber object.
80
- attr_reader :version
12
+ # Dynamic link extension.
13
+ #DLEXT = '.' + ::Config::CONFIG['DLEXT']
81
14
 
82
- # Path to library.
83
- attr_reader :location
15
+ #
16
+ #SUFFIXES = ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
17
+ SUFFIXES = ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
84
18
 
85
- # New libray.
86
- def initialize(location, identity=nil) #name, version, location=nil)
87
- @location = location
88
-
89
- if identity
90
- @name = identity[:name]
91
- @version = identity[:version]
92
- @load_path = identity[:load_path] || identity[:load_paths]
93
- else
94
- identify(location)
95
- end
19
+ #
20
+ SUFFIX_PATTERN = "{#{SUFFIXES.join(',')}}"
96
21
 
97
- raise unless @name
98
- raise unless @version
22
+ # Get an instance of a library by name, or name and version.
23
+ # Libraries are singleton, so once loaded the same object is
24
+ # always returned.
99
25
 
100
- @identity = identity
26
+ def self.instance(name, constraint=nil)
27
+ name = name.to_s
28
+ #raise "no library -- #{name}" unless ledger.include?(name)
29
+ return nil unless ledger.include?(name)
101
30
 
102
- # TODO Version number needs to be more flexiable in handling non-numeric tuples.
103
- @version = VersionNumber.new(@version) unless VersionNumber === @version
104
- end
31
+ library = ledger[name]
105
32
 
106
- # Identify a library based on it's location.
107
- def identify(location)
108
- file = File.join(location,'{,meta/}*.roll')
109
- if file = Dir.glob(file).first
110
- @name, @version = file.chomp('.roll').split('-')
111
- end
112
- end
113
-
114
- # Inspection.
115
- def inspect
116
- if version
117
- "#<Library #{name}/#{version}>"
118
- else
119
- "#<Library #{name}>"
33
+ if Library===library
34
+ if constraint # TODO: it's okay if constraint fits current
35
+ raise VersionConflict, "previously selected version -- #{ledger[name].version}"
36
+ else
37
+ library
38
+ end
39
+ else # library is an array of versions
40
+ if constraint
41
+ compare = Version.constraint_lambda(constraint)
42
+ library = library.select(&compare).max
43
+ else
44
+ library = library.max
45
+ end
46
+ unless library
47
+ raise VersionError, "no library version -- #{name} #{constraint}"
48
+ end
49
+ #ledger[name] = library
50
+ #library.activate
51
+ return library
52
+ end
120
53
  end
121
- end
122
54
 
123
- def roll_file
124
- find = "{,meta/}*.roll" # "{,meta/}#{name}-#{version}.roll"
125
- file = Dir.glob(File.join(location, find), File::FNM_CASEFOLD).first
126
- end
55
+ # A shortcut for #instance.
127
56
 
128
- # Read roll file.
129
- def load_roll
130
- return unless location # NEED TO DO THIS BETTER. THIS IS HERE FOR THE ONE 'ruby' CASE.
131
- raise LoadError unless File.directory?(location)
132
- glob = File.join(location, "{,meta/}*.roll") # "{,meta/}#{name}-#{version}.roll"
133
- file = Dir.glob(glob, File::FNM_CASEFOLD).first
134
- if file
135
- @roll_file = file
136
- @roll = Roll::Package.open(file, :name=>name, :version=>version.to_s)
137
- else
138
- raise "THIS SHOULD NOT POSSIBLE!"
139
- #@roll = false #Roll::Package.new # THIS IN NO LONGER POSSIBLE
57
+ def self.[](name, constraint=nil)
58
+ instance(name, constraint)
140
59
  end
141
- #use #?
142
- return @roll
143
- end
144
-
145
- # Does this library have an roll file?
146
- #def rolled?
147
- # roll ? true : false
148
- #end
149
-
150
- # Does this library have a remote source?
151
-
152
- #def remote?
153
- # rolled? and source and pubkey
154
- #end
155
-
156
- # Meta information about the libray.
157
- def roll
158
- @roll = load_roll if @roll.nil? # If it's false, we don't have one.
159
- @roll
160
- end
161
- alias_method :info, :roll
162
60
 
163
- # Compare by version.
164
- def <=>(other)
165
- version <=> other.verison
166
- end
61
+ # Same as #instance but will raise and error if the library is
62
+ # not found. This can also take a block to yield on the library.
167
63
 
168
- # List of subdirectories that are searched when loading libs.
169
- # In general this should include all the libs internal load paths,
170
- # so long as there will be no name conflicts between directories.
171
- def lib_path
172
- return unless roll # NEED TO DO THIS BETTER. THIS IS HERE FOR THE ONE 'ruby' CASE.
173
- return @load_path if @load_path
174
- if roll.load_path
175
- @load_path = roll.load_path.collect{ |path| File.join(location, path) }
176
- else
177
- @load_path = ['lib'] # ["lib/#{name}"]
178
- end
179
- end
180
- alias_method :load_path, :lib_path
181
- alias_method :load_paths, :lib_path
182
-
183
- # List of subdirectories that are searched for binaries.
184
- #++
185
- # TODO I think it would be better just to make this a fix
186
- # convention that bin/ is always the place to put these.
187
- # (Unlike lib/ which needs to be more flexable.)
188
- #--
189
- def bin_path
190
- return @bin_path if @bin_path
191
- return [] unless location # NEED TO DO THIS BETTER.
192
- if roll.bin_path
193
- @bin_path = roll.bin_path.collect{ |path| File.join(location, path) }
194
- else
195
- if File.directory?(File.join(location, 'bin'))
196
- @bin_path = [File.join(location, 'bin')]
197
- else
198
- @bin_path = []
64
+ def self.open(name, constraint=nil) #:yield:
65
+ lib = instance(name, constraint)
66
+ unless lib
67
+ raise LoadError, "no library -- #{name}"
199
68
  end
69
+ yield(lib) if block_given?
70
+ lib
200
71
  end
201
- return @bin_path
202
- end
203
72
 
204
- # Return the path to the data directory associated with the given
205
- # package name. Normally this is just
206
- # "#{Config::CONFIG['datadir']}/#{package_name}", but may be
207
- # modified by packages like RubyGems and Rolls to handle
208
- # versioned data directories.
209
- def datadir(versionless=false)
210
- if version and not versionless
211
- File.join(Config::CONFIG['datadir'], name, version)
212
- else
213
- File.join(Config::CONFIG['datadir'], name)
73
+ #
74
+ def initialize(location, name=nil)
75
+ @location = location
76
+ @name = name
214
77
  end
215
- end
216
-
217
- # Return the path to the configuration directory.
218
- #--
219
- # Can or should configuration directories be versioned?
220
- #++
221
- def confdir
222
- File.join(location, 'data')
223
- #if version
224
- # File.join(Config::CONFIG['confdir'], name, version)
225
- #else
226
- # File.join(Config::CONFIG['datadir'], name)
227
- #end
228
- end
229
-
230
- # Require find.
231
- def require_find(file)
232
- file = roll.index_file if (file.nil? or file.empty?)
233
- glob = File.join('{' + load_path.join(',') + '}', file + "{.rb,#{Library.dlext},}")
234
- Dir.glob(glob).first
235
- end
236
-
237
- # Load find.
238
- def load_find(file)
239
- file = roll.index_file if (file.nil? or file.empty?)
240
- glob = File.join('{' + load_path.join(',') + '}', file)
241
- Dir.glob(glob).first
242
- end
243
78
 
244
- # Library specific #require.
245
- def require(file)
246
- if path = require_find(file)
247
- Kernel.require(path)
248
- else
249
- raise LoadError, "no such file to load -- #{name}:#{file}"
79
+ #
80
+ def location
81
+ @location
250
82
  end
251
- end
252
83
 
253
- # Library specific load.
254
- def load(file, wrap=nil)
255
- if path = load_find(file)
256
- Kernel.load(path, wrap)
257
- else
258
- raise LoadError, "no such file to load -- #{name}:#{file}"
84
+ #
85
+ def name
86
+ @name ||= metadata.name
259
87
  end
260
- end
261
88
 
262
- # Library specific autoload.
263
- def autoload(base, file)
264
- if path = require_find(file)
265
- Kernel.autoload(base, file)
266
- else
267
- raise LoadError, "no such file to autoload -- #{name}:#{file}"
89
+ #
90
+ def version
91
+ @version ||= metadata.version
268
92
  end
269
- end
270
93
 
271
- # Require into module.
272
- def module_require(mod, file)
273
- if path = require_find(file)
274
- mod.module_require(path) # FIXME
275
- else
276
- raise LoadError, "no such file to load -- #{name}:#{file}"
94
+ #
95
+ def active?
96
+ @active ||= metadata.active
277
97
  end
278
- end
279
98
 
280
- # Load into module.
281
- def module_load(mod, file)
282
- if path = load_find(file)
283
- mod.module_load(path) # FIXME
284
- else
285
- raise LoadError, "no such file to load -- #{name}:#{file}"
99
+ #
100
+ def loadpath
101
+ @loadpath ||= metadata.loadpath
286
102
  end
287
- end
288
103
 
289
- # Library specific autoload for module.
290
- def module_autoload(mod, base, file)
291
- if path = require_find(file)
292
- mod.autoload_without_roll(base, file)
293
- else
294
- raise LoadError, "no such file to autoload -- #{name}:#{file}"
104
+ #
105
+ def requires
106
+ @requires ||= metadata.requires
295
107
  end
296
- end
297
108
 
298
- # Put the libs load paths into the global lookup.
299
- #--
300
- # TODO Maybe call 'import' instead?
301
- #++
302
- def utilize
303
- lib_path.each do |path|
304
- Library.load_path.unshift(path)
109
+ #
110
+ def released
111
+ @released ||= metadata.released
305
112
  end
306
- Library.load_path.uniq!
307
- self
308
- end
309
-
310
- # Class instance variable @ledger stores the library references.
311
113
 
312
- @ledger = {}
313
-
314
- class << self
315
-
316
- # Scan the site locations for libraries.
317
- def scan
318
- # First we add Ruby core and standard libraries.
319
- @ledger['ruby'] = Library.new(nil, :name=>'ruby', :version=>VERSION, :load_path=>Library.ruby_path)
320
-
321
- scan_working() if $DEBUG
322
-
323
- projs1 = Dir.glob( '{' + $LOAD_SITE.join(',') + '}/*{/meta,}/*.roll', File::FNM_CASEFOLD )
324
- projs2 = Dir.glob( '{' + $LOAD_SITE.join(',') + '}/*/*{/meta,}/*.roll', File::FNM_CASEFOLD )
325
- projs3 = Dir.glob( '{' + $LOAD_SITE.join(',') + '}/*/*/*{/meta,}/*.roll', File::FNM_CASEFOLD )
326
-
327
- projs = projs1 + projs2 + projs3
328
-
329
- #dirs = projs.collect do |prj|
330
- # metafile = File.basename(prj)
331
- # dir = File.dirname(prj)
332
- # dir = File.dirname(dir) if dir =~ /meta$/
333
- # dir
334
- #end
335
-
336
- projs.uniq!
337
-
338
- #dirs -= $LOAD_SITE
114
+ #
115
+ def verify
116
+ requires.each do |(name, constraint)|
117
+ Library.open(name, constraint)
118
+ end
119
+ end
339
120
 
340
- projs.each do |proj|
341
- name, ver = *File.basename(proj).chomp('.roll').split('-')
342
- dir = File.dirname(proj)
343
- dir = File.dirname(dir) if File.basename(dir) == 'meta'
121
+ # Find first matching +file+.
344
122
 
345
- name = name.downcase
123
+ #def find(file, suffix=true)
124
+ # case File.extname(file)
125
+ # when *SUFFIXES
126
+ # find = File.join(lookup_glob, file)
127
+ # else
128
+ # find = File.join(lookup_glob, file + SUFFIX_PATTERN) #'{' + ".rb,#{DLEXT}" + '}')
129
+ # end
130
+ # Dir[find].first
131
+ #end
346
132
 
347
- #if versions.empty?
348
- # @ledger[name] ||= Library.new(dir, :name=>name, :version=>'0') #Version.new('0', dir)
349
- #else
350
- @ledger[name] ||= []
351
- @ledger[name] << Library.new(dir, :name=>name, :version=>ver)
352
- #end
133
+ # Standard loadpath search.
134
+ #
135
+ def find(file, suffix=true)
136
+ if suffix
137
+ SUFFIXES.each do |ext|
138
+ loadpath.each do |lpath|
139
+ f = File.join(location, lpath, file + ext)
140
+ return f if File.file?(f)
141
+ end
142
+ end
143
+ else
144
+ loadpath.each do |lpath|
145
+ f = File.join(location, lpath, file)
146
+ return f if File.file?(f)
147
+ end
353
148
  end
149
+ nil
354
150
  end
355
151
 
356
- # Scan current working location to see if there's
357
- # a library. This will ascend from the current
358
- # working directy to one level below root looking
359
- # for a lib/ directory.
360
- #--
361
- # TODO CHANGE TO LOOK FRO INDEX FILE.
362
- #++
363
- def scan_working
364
- paths = Dir.pwd.split('/')
365
- (paths.size-1).downto(1) do |n|
366
- dir = File.join( *(paths.slice(0..n) << 'lib') )
367
- if File.directory? dir
368
- $LOAD_SITE.unshift dir
152
+ # Does this library have a matching +file+? If so, the full-path
153
+ # of the file is returned.
154
+ #
155
+ # Unlike #find, this also matches within the library directory
156
+ # itself, eg. <tt>lib/foo/*</tt>. It is used by #aquire.
157
+ #
158
+ def include?(file, suffix=true)
159
+ if suffix
160
+ SUFFIXES.each do |ext|
161
+ loadpath.each do |lpath|
162
+ f = File.join(location, lpath, name, file + ext)
163
+ return f if File.file?(f)
164
+ f = File.join(location, lpath, file + ext)
165
+ return f if File.file?(f)
166
+ end
167
+ end
168
+ else
169
+ loadpath.each do |lpath|
170
+ f = File.join(location, lpath, name, file)
171
+ return f if File.file?(f)
172
+ f = File.join(location, lpath, file)
173
+ return f if File.file?(f)
369
174
  end
370
175
  end
176
+ nil
371
177
  end
372
178
 
373
- # Return a list of library names.
374
- def list
375
- @ledger.keys
376
- end
179
+ #def include?(file)
180
+ # case File.extname(file)
181
+ # when *SUFFIXES
182
+ # find = File.join(lookup_glob, "{#{name}/,}" + file)
183
+ # else
184
+ # find = File.join(lookup_glob, "{#{name}/,}" + file + SUFFIX_PATTERN) #'{' + ".rb,#{DLEXT}" + '}')
185
+ # end
186
+ # Dir[find].first
187
+ #end
377
188
 
378
- # Libraries are Singleton pattern.
379
- def instance(name, constraint=nil)
380
- name = name.to_s
381
- #raise "no library -- #{name}" unless @ledger.include?( name )
382
- return nil unless @ledger.include?(name)
383
- case lib = @ledger[name]
384
- when Library
385
- return lib unless constraint
386
- raise VersionConflict, "previously selected library version" # -- #{lib.version}"
387
- #when Version
388
- # @ledger[name] = new(lib.location, :name=>name, :version=>lib) #new(name, lib, lib.location)
389
- when Array
390
- if constraint
391
- compare = VersionNumber.constrant_lambda(constraint)
392
- version = lib.select(&compare).max
393
- else
394
- version = lib.max
395
- end
396
- unless version
397
- raise VersionError, "no library version -- #{name} #{constraint}"
398
- end
399
- @ledger[name] = version #new(version.location, :name=>name, :version=>version) #new(name, version, version.location)
189
+ #
190
+ def require(file)
191
+ if path = include?(file)
192
+ require_absolute(path)
400
193
  else
401
- raise "this should never happen"
194
+ load_error = LoadError.new("no such file to require -- #{name}:#{file}")
195
+ raise clean_backtrace(load_error)
402
196
  end
403
- @ledger[name].roll # Make sure the roll file is loaded.
404
- @ledger[name]
405
197
  end
406
198
 
407
- # A shortcut for #instance.
408
- alias_method :[], :instance
409
-
410
- # Same as #instance but will raise and error if the library is not found.
411
- def open(name, constraint=nil, &yld)
412
- lib = instance(name, constraint)
413
- unless lib
414
- raise LoadError, "no library -- #{name}"
199
+ # NOT SURE ABOUT USING THIS
200
+ def require_absolute(file)
201
+ #Library.load_monitor[file] << caller if $LOAD_MONITOR
202
+ Library.load_stack << self
203
+ begin
204
+ success = original_require(file)
205
+ #rescue LoadError => load_error
206
+ # raise clean_backtrace(load_error)
207
+ ensure
208
+ Library.load_stack.pop
415
209
  end
416
- yield(lib) if yld
417
- lib
210
+ success
418
211
  end
419
212
 
420
- end
421
-
422
- # VersionError is raised when a requested version cannot be found.
423
- class VersionError < ::RangeError # :nodoc:
424
- end
213
+ #
214
+ def load(file, wrap=nil)
215
+ if path = include?(file, false)
216
+ load_absolute(path, wrap)
217
+ else
218
+ load_error = LoadError.new("no such file to load -- #{name}:#{file}")
219
+ clean_backtrace(load_error)
220
+ end
221
+ end
425
222
 
426
- # VersionConflict is raised when selecting another version
427
- # of a library when a previous version has already been selected.
428
- class VersionConflict < ::LoadError # :nodoc:
429
- end
430
- end
223
+ #
224
+ def load_absolute(file, wrap=nil)
225
+ #Library.load_monitor[file] << caller if $LOAD_MONITOR
226
+ Library.load_stack << self
227
+ begin
228
+ success = original_load(file, wrap)
229
+ #rescue LoadError => load_error
230
+ # raise clean_backtrace(load_error)
231
+ ensure
232
+ Library.load_stack.pop
233
+ end
234
+ success
235
+ end
431
236
 
237
+ # Inspection.
238
+ def inspect
239
+ if @version
240
+ %[#<Library #{name}/#{@version} @location="#{location}">]
241
+ else
242
+ %[#<Library #{name} @location="#{location}">]
243
+ end
244
+ end
432
245
 
433
- module ::Config
434
- # Return the path to the data directory associated with the given
435
- # package name. Normally this is just
436
- # "#{Config::CONFIG['datadir']}/#{package_name}", but may be
437
- # modified by packages like RubyGems and Rolls to handle
438
- # versioned data directories.
439
- def self.datadir(name, versionless=false)
440
- if lib = Library.instance( name )
441
- lib.datadir( versionless )
442
- else
443
- File.join(CONFIG['datadir'], name)
246
+ def to_s
247
+ inspect
444
248
  end
445
- end
446
249
 
447
- # Return the path to the configuration directory.
448
- def self.confdir(name)
449
- if lib = Library.instance( name )
450
- lib.confdir
451
- else
452
- File.join(CONFIG['datadir'], name)
250
+ # Compare by version.
251
+ def <=>(other)
252
+ version <=> other.version
453
253
  end
454
- end
455
- end
456
254
 
255
+ # # List of subdirectories that are searched when loading.
256
+ # #--
257
+ # # This defualts to ['lib/{name}', 'lib']. The first entry is
258
+ # # usually proper location; the latter is added for default
259
+ # # compatability with the traditional require system.
260
+ # #++
261
+ # def libdir
262
+ # loadpath.map{ |path| File.join(location, path) }
263
+ # end
264
+ #
265
+ # # Does the library have any lib directories?
266
+ # def libdir?
267
+ # lib.any?{ |d| File.directory?(d) }
268
+ # end
457
269
 
458
- module ::Kernel
270
+ # Location of executable. This is alwasy bin/. This is a fixed
271
+ # convention, unlike lib/ which needs to be more flexable.
272
+ def bindir ; File.join(location, 'bin') ; end
459
273
 
460
- # Activate a library.
461
- def library(name, constraint=nil)
462
- Library.open(name, constraint)
463
- end
464
- module_function :library
465
-
466
- # Use library. This activates a library, and adds
467
- # it's load_path to the global $LOAD_PATH.
468
- #--
469
- # Maybe call #import instead ?
470
- #++
471
- def use(name, constraint=nil)
472
- Library.open(name, constraint).utilize
473
- end
274
+ # Is there a <tt>bin/</tt> location?
275
+ def bindir? ; File.exist?(bindir) ; end
474
276
 
277
+ # Location of library system configuration files.
278
+ # This is alwasy the <tt>etc/</tt> directory.
279
+ def confdir ; File.join(location, 'etc') ; end
475
280
 
476
- def self.parse_load_parameters(file)
477
- if must = file.index(':')
478
- name, path = file.split(':')
479
- else
480
- name, *rest = file.split('/')
481
- path = File.join(*rest)
482
- end
483
- name = nil if name == ''
484
- lib = name ? Library.instance(name) : nil
485
- raise LoadError, "no library found -- #{file}" if must && !lib
486
- return lib, path
487
- end
281
+ # Is there a <tt>etc/</tt> location?metadata.name
282
+ def confdir? ; File.exist?(confdir) ; end
488
283
 
489
- # Rolls requires a modification to #require and #load.
490
- # So that it is not neccessary to make the library() call
491
- # if you just want the latest version.
492
- #
493
- # This would be a bit simpler if we mandated the
494
- # use of the ':' notation when specifying the library
495
- # name. Use of the ':' is robust. But we cannot do this
496
- # w/o loosing backward-compatability. Using '/' in its
497
- # place has the potential for pathname clashing, albeit
498
- # the likelihood is small. There are two ways to bypass
499
- # the problem if it arises. Use 'ruby:{path}' if the
500
- # conflicting lib is a ruby core or standard library.
501
- # Use ':{path}' to bypass Roll system altogether.
502
-
503
- # # Require script.
504
- # def require(file)
505
- # if file.index(':')
506
- # name, file = file.split(':')
507
- # if name == ''
508
- # Kernel.require(file)
509
- # #if lib == 'ruby'
510
- # # Ruby.require(file)
511
- # elsif lib = Library.instance(name)
512
- # lib.require(file)
513
- # else
514
- # raise LoadError, "no library found -- #{name}"
515
- # end
516
- # else
517
- # name, *rest = file.split('/')
518
- # if lib = Library.instance(name)
519
- # lib.require(File.join(*rest))
520
- # else
521
- # Kernel.require(file)
522
- # end
523
- # end
524
- # end
525
-
526
- # Require script.
527
- def require(file)
528
- lib, path = *Kernel.parse_load_parameters(file)
529
- if lib
530
- lib.require(path)
531
- else
532
- Kernel.require(file)
533
- end
534
- end
284
+ # Location of library shared data directory.
285
+ # This is always the <tt>data/</tt> directory.
286
+ def datadir ; File.join(location, 'data') ; end
535
287
 
536
- # # Load script.
537
- # def load(file, wrap=nil)
538
- # if file.index(':')
539
- # name, file = file.split(':')
540
- # if name == ''
541
- # Kernel.require(file)
542
- # #if lib == 'ruby'
543
- # # Ruby.load(file, safe)
544
- # elsif lib = Library.instance(name)
545
- # lib.load(file, wrap)
546
- # else
547
- # raise LoadError, "no library found -- #{name}"
548
- # end
549
- # else
550
- # name, *rest = file.split('/')
551
- # if lib = Library.instance(name)
552
- # lib.load(File.join(*rest))
553
- # else
554
- # Kernel.load(file, wrap)
555
- # end
556
- # end
557
- # end
558
-
559
- # Require script.
560
- def load(file, wrap=false)
561
- lib, path = *Kernel.parse_load_parameters(file)
562
- if lib
563
- lib.load(path, wrap)
564
- else
565
- Kernel.load(file, wrap)
566
- end
567
- end
288
+ # Is there a <tt>data/</tt> location?
289
+ def datadir? ; File.exist?(datadir) ; end
568
290
 
569
- # #
570
- # def autoload(base, file)
571
- # if file.index(':')
572
- # name, file = file.split(':')
573
- # if name == ''
574
- # Kernel.autoload(base, file)
575
- # elsif lib = Library.instance(name)
576
- # lib.autoload(base, file)
577
- # else
578
- # raise LoadError, "no library found -- #{name}"
579
- # end
580
- # else
581
- # name, *rest = file.split('/')
582
- # if lib = Library.instance(name)
583
- # lib.autoload(base, File.join(*rest))
584
- # else
585
- # Kernel.autoload(base, file)
586
- # end
587
- # end
588
- # end
589
-
590
- =begin
591
- # Autoload script.
592
- def autoload(base, file)
593
- lib, path = *Kernel.parse_load_parameters(file)
594
- if lib
595
- lib.autoload(base, path)
596
- else
597
- Kernel.autoload(base, file)
291
+ # Access to secondary metadata.
292
+ def metadata
293
+ @metadata ||= Metadata.new(location)
598
294
  end
599
- end
600
- =end
601
295
 
602
- end
603
-
604
- # TODO
605
- class ::Module
296
+ private
606
297
 
607
- =begin
608
- alias_method :autoload_without_roll, :autoload
298
+ #
299
+ #def lookup_glob
300
+ # @lookup_glob ||= File.join(location, '{' + loadpath.join(',') + '}')
301
+ #end
609
302
 
610
- #
611
- def autoload(base, file)
612
- lib, path = *Kernel.parse_load_parameters(file)
613
- if lib
614
- lib.module_autoload(self, base, path)
615
- else
616
- autoload_without_roll(base, file)
303
+ #
304
+ def clean_backtrace(error)
305
+ if $DEBUG
306
+ error
307
+ else
308
+ bt = error.backtrace
309
+ bt = bt.reject{ |e| /roll/ =~ e } if bt
310
+ error.set_backtrace(bt)
311
+ error
312
+ end
617
313
  end
618
- end
619
- =end
620
-
621
- # TODO
622
314
 
623
- # Adds importing to Module class called against +self+ as default.
624
-
625
- # def module_require()
626
- # end
627
-
628
- # def module_load()
629
- # end
315
+ end
630
316
 
631
317
  end
632
318
 
633
- # Prime the library ledger.
634
- Library.scan
635
-