library 0.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.
- data/.ruby +57 -0
- data/.yardopts +6 -0
- data/COPYING.rdoc +30 -0
- data/HISTORY.rdoc +13 -0
- data/README.md +177 -0
- data/lib/library.rb +532 -0
- data/lib/library/autoload.rb +14 -0
- data/lib/library/core_ext.rb +34 -0
- data/lib/library/domain.rb +244 -0
- data/lib/library/errors.rb +49 -0
- data/lib/library/feature.rb +207 -0
- data/lib/library/kernel.rb +81 -0
- data/lib/library/ledger.rb +642 -0
- data/lib/library/metadata.rb +398 -0
- data/lib/library/rbconfig.rb +65 -0
- data/lib/library/rubygems.rb +19 -0
- data/lib/library/rubylib.rb +206 -0
- data/lib/library/version.rb +387 -0
- data/lib/ubylibs.rb +8 -0
- data/qed/01_loading.rdoc +14 -0
- data/qed/02_library.rdoc +55 -0
- data/qed/03_ledger.rdoc +30 -0
- data/qed/04_version.rdoc +101 -0
- data/qed/applique/check.rb +11 -0
- data/qed/applique/project.rb +34 -0
- data/qed/fixtures/foo/.ruby +5 -0
- data/qed/fixtures/foo/lib/foo.rb +1 -0
- data/qed/fixtures/tryme/1.0/.ruby +6 -0
- data/qed/fixtures/tryme/1.0/lib/tryme.rb +1 -0
- data/qed/fixtures/tryme/1.1/.ruby +7 -0
- data/qed/fixtures/tryme/1.1/lib/tryme.rb +1 -0
- data/qed/helpers/new_project.rdoc +29 -0
- data/qed/helpers/projects.rdoc +56 -0
- data/test/case_ledger.rb +23 -0
- data/test/case_library.rb +13 -0
- data/test/case_version.rb +89 -0
- data/test/fixture/.ruby +56 -0
- data/test/fixture/lib/foo.rb +7 -0
- data/test/helper.rb +2 -0
- metadata +144 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# Ruby's autoload method does not use the normal require
|
2
|
+
# mechanisms, therefore if we wish to support it we will
|
3
|
+
# have to override and create our own system. OTOH Matz
|
4
|
+
# has said autoload will go away in Ruby 2.0, so maybe
|
5
|
+
# we can just let this go and not worry about it.
|
6
|
+
|
7
|
+
module Kernel
|
8
|
+
#alias __autoload__ autoload
|
9
|
+
end
|
10
|
+
|
11
|
+
#class ::Module
|
12
|
+
# alias __autoload__ autoload
|
13
|
+
#end
|
14
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class File
|
2
|
+
|
3
|
+
#
|
4
|
+
RE_PATH_SEPERATOR = Regexp.new('[' + Regexp.escape(File::Separator) + %q{\\\/} + ']')
|
5
|
+
|
6
|
+
#
|
7
|
+
def self.split_root(path)
|
8
|
+
path.split(RE_PATH_SEPERATOR, 2)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class Hash
|
14
|
+
|
15
|
+
#
|
16
|
+
# Transform keys of hash returning a new hash.
|
17
|
+
#
|
18
|
+
def rekey #:yield:
|
19
|
+
if block_given?
|
20
|
+
inject({}){|h,(k,v)| h[yield(k)]=v; h}
|
21
|
+
else
|
22
|
+
inject({}){|h,(k,v)| h[k.to_sym]=v; h}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# In-place rekey.
|
28
|
+
#
|
29
|
+
def rekey! #:yield:
|
30
|
+
replace(rekey{|k| yield(k) })
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,244 @@
|
|
1
|
+
class Library
|
2
|
+
|
3
|
+
# This extension encapsulates Library's class methods.
|
4
|
+
#
|
5
|
+
module Domain
|
6
|
+
|
7
|
+
#
|
8
|
+
# Access to library ledger.
|
9
|
+
#
|
10
|
+
# @return [Array] The `$LEDGER` array.
|
11
|
+
#
|
12
|
+
def ledger
|
13
|
+
$LEDGER
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Library names from ledger.
|
18
|
+
#
|
19
|
+
# @return [Array] The keys from `$LEDGER` array.
|
20
|
+
#
|
21
|
+
def names
|
22
|
+
$LEDGER.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
alias_method :list, :names
|
26
|
+
|
27
|
+
#
|
28
|
+
# Find matching library features. This is the "mac daddy" method used by
|
29
|
+
# the #require and #load methods to find the specified +path+ among
|
30
|
+
# the various libraries and their load paths.
|
31
|
+
#
|
32
|
+
def find(path, options={})
|
33
|
+
$LEDGER.find_feature(path, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Brute force variation of `#find` looks through all libraries for a
|
38
|
+
# matching features. This serves as the fallback method if `#find` comes
|
39
|
+
# up empty.
|
40
|
+
#
|
41
|
+
# @param [String] path
|
42
|
+
# path name for which to search
|
43
|
+
#
|
44
|
+
# @param [Hash] options
|
45
|
+
# Search options.
|
46
|
+
#
|
47
|
+
# @option options [Boolean] :latest
|
48
|
+
# Search only the active or most current version of any library.
|
49
|
+
#
|
50
|
+
# @option options [Boolean] :suffix
|
51
|
+
# Automatically try standard extensions if pathname has none.
|
52
|
+
#
|
53
|
+
# @option options [Boolean] :legacy
|
54
|
+
# Do not match within library's +name+ directory, eg. `lib/foo/*`.
|
55
|
+
#
|
56
|
+
# @return [Feature,Array] Matching feature(s).
|
57
|
+
#
|
58
|
+
def find_any(path, options={})
|
59
|
+
$LEDGER.find_any(path, options)
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Brute force search looks through all libraries for matching features.
|
64
|
+
# This is the same as #find_any, but returns a list of matches rather
|
65
|
+
# then the first matching feature found.
|
66
|
+
#
|
67
|
+
# @param [String] path
|
68
|
+
# path name for which to search
|
69
|
+
#
|
70
|
+
# @param [Hash] options
|
71
|
+
# Search options.
|
72
|
+
#
|
73
|
+
# @option options [Boolean] :latest
|
74
|
+
# Search only the active or most current version of any library.
|
75
|
+
#
|
76
|
+
# @option options [Boolean] :suffix
|
77
|
+
# Automatically try standard extensions if pathname has none.
|
78
|
+
#
|
79
|
+
# @option options [Boolean] :legacy
|
80
|
+
# Do not match within library's +name+ directory, eg. `lib/foo/*`.
|
81
|
+
#
|
82
|
+
# @return [Feature,Array] Matching feature(s).
|
83
|
+
#
|
84
|
+
def search(path, options={})
|
85
|
+
$LEDGER.search(path, options)
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Search for all matching library files that match the given pattern.
|
90
|
+
# This could be of useful for plugin loader.
|
91
|
+
#
|
92
|
+
# @param [Hash] options
|
93
|
+
# Glob matching options.
|
94
|
+
#
|
95
|
+
# @option options [Boolean] :latest
|
96
|
+
# Search only activated libraries or the most recent version
|
97
|
+
# of a given library.
|
98
|
+
#
|
99
|
+
# @return [Array] Matching file paths.
|
100
|
+
#
|
101
|
+
# @todo Should this return list of Feature objects instead of file paths?
|
102
|
+
#
|
103
|
+
def glob(match, options={})
|
104
|
+
$LEDGER.glob(match, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# @deprecated
|
109
|
+
#
|
110
|
+
def find_files(match, options={})
|
111
|
+
glob(match, options)
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Access to global load stack.
|
116
|
+
#
|
117
|
+
# @return [Array] The `$LOAD_STACK` array.
|
118
|
+
#
|
119
|
+
def load_stack
|
120
|
+
$LOAD_STACK
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Require a feature from the library.
|
125
|
+
#
|
126
|
+
# @param [String] pathname
|
127
|
+
# The pathname of feature relative to library's loadpath.
|
128
|
+
#
|
129
|
+
# @param [Hash] options
|
130
|
+
#
|
131
|
+
# @return [true,false] If feature was newly required or successfully loaded.
|
132
|
+
#
|
133
|
+
def require(pathname, options={})
|
134
|
+
if file = $LOAD_CACHE[pathname]
|
135
|
+
if options[:load]
|
136
|
+
return file.load
|
137
|
+
else
|
138
|
+
return false
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
if feature = Library.find(pathname, options)
|
143
|
+
#file.library_activate
|
144
|
+
$LOAD_CACHE[pathname] = feature
|
145
|
+
return feature.acquire(options)
|
146
|
+
end
|
147
|
+
|
148
|
+
# fallback to Ruby's own load mechinisms
|
149
|
+
if options[:load]
|
150
|
+
__load__(pathname, options[:wrap])
|
151
|
+
else
|
152
|
+
__require__(pathname)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Load file path. This is just like #require except that previously
|
158
|
+
# loaded files will be reloaded and standard extensions will not be
|
159
|
+
# automatically appended.
|
160
|
+
#
|
161
|
+
# @param pathname [String]
|
162
|
+
# pathname of feature relative to library's loadpath
|
163
|
+
#
|
164
|
+
# @return [true,false] if feature was successfully loaded
|
165
|
+
#
|
166
|
+
def load(pathname, options={}) #, &block)
|
167
|
+
#options.merge!(block.call) if block
|
168
|
+
|
169
|
+
if !Hash === options
|
170
|
+
options = {}
|
171
|
+
options[:wrap] = options
|
172
|
+
end
|
173
|
+
|
174
|
+
options[:load] = true
|
175
|
+
options[:suffix] = false
|
176
|
+
options[:local] = false
|
177
|
+
|
178
|
+
require(pathname, options)
|
179
|
+
|
180
|
+
#if file = $LOAD_CACHE[path]
|
181
|
+
# return file.load
|
182
|
+
#end
|
183
|
+
|
184
|
+
#if file = Library.find(path, options)
|
185
|
+
# #file.library_activate
|
186
|
+
# $LOAD_CACHE[path] = file
|
187
|
+
# return file.load(options) #acquire(options)
|
188
|
+
#end
|
189
|
+
|
190
|
+
##if options[:load]
|
191
|
+
# __load__(path, options[:wrap])
|
192
|
+
##else
|
193
|
+
## __require__(path)
|
194
|
+
##end
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# Roll-style loading. First it looks for a specific library via `:`.
|
199
|
+
# If `:` is not present it then tries the current loading library.
|
200
|
+
# Failing that it fallsback to Ruby itself.
|
201
|
+
#
|
202
|
+
# require('facets:string/margin')
|
203
|
+
#
|
204
|
+
# To "load" the library, rather than "require" it, set the +:load+
|
205
|
+
# option to true.
|
206
|
+
#
|
207
|
+
# require('facets:string/margin', :load=>true)
|
208
|
+
#
|
209
|
+
# @param pathname [String]
|
210
|
+
# pathname of feature relative to library's loadpath
|
211
|
+
#
|
212
|
+
# @return [true, false] if feature was newly required
|
213
|
+
#
|
214
|
+
def acquire(pathname, options={}) #, &block)
|
215
|
+
#options.merge!(block.call) if block
|
216
|
+
options[:local] = true
|
217
|
+
require(pathname, options)
|
218
|
+
end
|
219
|
+
|
220
|
+
#
|
221
|
+
# Load up the ledger with a given set of paths.
|
222
|
+
#
|
223
|
+
def prime(*paths)
|
224
|
+
$LEDGER.prime(*paths)
|
225
|
+
end
|
226
|
+
|
227
|
+
#
|
228
|
+
# Go thru each library and make sure bin path is in path.
|
229
|
+
#
|
230
|
+
# @todo Should this be defined on Ledger?
|
231
|
+
#
|
232
|
+
def PATH()
|
233
|
+
path = []
|
234
|
+
list.each do |name|
|
235
|
+
lib = Library[name]
|
236
|
+
path << lib.bindir if lib.bindir?
|
237
|
+
end
|
238
|
+
path.join(RbConfig.windows_platform? ? ';' : ':')
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
extend Domain
|
244
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Library
|
2
|
+
|
3
|
+
# Library LoadError is a subclass of Ruby's standard LoadError class.
|
4
|
+
#
|
5
|
+
class LoadError < ::LoadError
|
6
|
+
|
7
|
+
#
|
8
|
+
# Setup new LoadError instance.
|
9
|
+
#
|
10
|
+
def initialize(failed_path, library_name=nil)
|
11
|
+
super()
|
12
|
+
|
13
|
+
@failed_path = failed_path
|
14
|
+
@library_name = library_name
|
15
|
+
|
16
|
+
if library_name
|
17
|
+
@message = "#{@library_name}:#{@failed_path}"
|
18
|
+
else
|
19
|
+
@message = failed_path
|
20
|
+
end
|
21
|
+
|
22
|
+
clean_backtrace
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Error message string.
|
27
|
+
#
|
28
|
+
def to_s
|
29
|
+
"LoadError: cannot load such file -- #{@message}"
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Take an +error+ and remove any mention of 'library' from it's backtrace.
|
34
|
+
# Will leaving the backtrace untouched if $DEBUG is set to true.
|
35
|
+
#
|
36
|
+
def clean_backtrace
|
37
|
+
return if ENV['debug'] || $DEBUG
|
38
|
+
bt = backtrace
|
39
|
+
bt = bt.reject{ |e| $RUBY_IGNORE_CALLERS.any?{ |re| re =~ e } } if bt
|
40
|
+
set_backtrace(bt)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Library ValidationError is raised when library metadata is not conforming.
|
45
|
+
#
|
46
|
+
class ValidationError < ::RuntimeError
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
class Library
|
2
|
+
|
3
|
+
# The Feature class represents a single file within a library.
|
4
|
+
#
|
5
|
+
# This class had been called `Script` until it occured to me that
|
6
|
+
# Ruby choose the name "feature" by it's use of tem in the global
|
7
|
+
# variable `$LOADED_FEATURES`.
|
8
|
+
#
|
9
|
+
class Feature
|
10
|
+
|
11
|
+
#
|
12
|
+
# Create a new Feature instance.
|
13
|
+
#
|
14
|
+
# @param library [Library]
|
15
|
+
# The Library object to which the feature belongs.
|
16
|
+
#
|
17
|
+
# @param loadpath [String]
|
18
|
+
# The loadpath within the library in which the feature resides.
|
19
|
+
#
|
20
|
+
# @param filename [String]
|
21
|
+
# The file path of the feature relative to the loadpath.
|
22
|
+
#
|
23
|
+
# @param extension [Boolean]
|
24
|
+
# File extension to append to the feature filename.
|
25
|
+
#
|
26
|
+
def initialize(library, loadpath, filename, extension=nil)
|
27
|
+
@library = library
|
28
|
+
@loadpath = loadpath
|
29
|
+
@filename = filename
|
30
|
+
@extension = extension
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# The Library object to which the file belongs.
|
35
|
+
#
|
36
|
+
attr_reader :library
|
37
|
+
|
38
|
+
#
|
39
|
+
# The loadpath within the library in which the feature resides.
|
40
|
+
#
|
41
|
+
# @return [Array] Load path relative to library location.
|
42
|
+
#
|
43
|
+
attr_reader :loadpath
|
44
|
+
|
45
|
+
#
|
46
|
+
# The file path of the feature relative to the loadpath.
|
47
|
+
#
|
48
|
+
attr_reader :filename
|
49
|
+
|
50
|
+
#
|
51
|
+
# Extension of feature file, e.g. `.rb`.
|
52
|
+
#
|
53
|
+
attr_reader :extension
|
54
|
+
|
55
|
+
#
|
56
|
+
# Name of the library to which the feature belongs.
|
57
|
+
#
|
58
|
+
# @return [String] name of the feature's library
|
59
|
+
#
|
60
|
+
def library_name
|
61
|
+
Library === library ? library.name : nil
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
#
|
66
|
+
#
|
67
|
+
def library_activate
|
68
|
+
library.activate if Library === library
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Library location.
|
73
|
+
#
|
74
|
+
# @return [String] location of library
|
75
|
+
#
|
76
|
+
def location
|
77
|
+
Library===library ? library.location : library
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Full path name of of feature.
|
82
|
+
#
|
83
|
+
# @return [String] expanded file path of feature
|
84
|
+
#
|
85
|
+
def fullname
|
86
|
+
@fullname ||= ::File.join(location, loadpath, filename + (extension || ''))
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# The path of the feature relative to the loadpath.
|
91
|
+
#
|
92
|
+
# @return [String] file path less location and loadpath
|
93
|
+
#
|
94
|
+
def localname
|
95
|
+
@localname ||= ::File.join(filename + (extension || ''))
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# Acquire the feature --Roll's advanced require/load method.
|
100
|
+
#
|
101
|
+
# @return [true,false] true if loaded, false if it already has been loaded.
|
102
|
+
#
|
103
|
+
def acquire(options={})
|
104
|
+
if options[:load] # TODO: .delete(:load) ?
|
105
|
+
load(options)
|
106
|
+
else
|
107
|
+
require(options)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Require feature.
|
113
|
+
#
|
114
|
+
# @return [true,false] true if loaded, false if it already has been loaded.
|
115
|
+
#
|
116
|
+
def require(options={})
|
117
|
+
if library_name == 'ruby' or library_name == 'site_ruby'
|
118
|
+
return false if $".include?(localname) # ruby 1.8 does not use absolutes
|
119
|
+
$" << localname # ruby 1.8 does not use absolutes
|
120
|
+
end
|
121
|
+
|
122
|
+
Library.load_stack << self #library
|
123
|
+
begin
|
124
|
+
library_activate unless options[:force]
|
125
|
+
success = __require__(fullname)
|
126
|
+
#rescue ::LoadError => load_error # TODO: deativeate this if $DEBUG ?
|
127
|
+
# raise LoadError.new(localname, library_name)
|
128
|
+
ensure
|
129
|
+
Library.load_stack.pop
|
130
|
+
end
|
131
|
+
success
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
# Load feature.
|
136
|
+
#
|
137
|
+
# @return [true,false] true if loaded, false if it already has been loaded.
|
138
|
+
#
|
139
|
+
def load(options={})
|
140
|
+
if library_name == 'ruby' or library_name == 'site_ruby'
|
141
|
+
$" << localname # ruby 1.8 does not use absolutes
|
142
|
+
end
|
143
|
+
|
144
|
+
Library.load_stack << self #library
|
145
|
+
begin
|
146
|
+
library_activate unless options[:force]
|
147
|
+
success = __load__(fullname, options[:wrap])
|
148
|
+
#rescue ::LoadError => load_error
|
149
|
+
# raise LoadError.new(localname, library_name)
|
150
|
+
ensure
|
151
|
+
Library.load_stack.pop
|
152
|
+
end
|
153
|
+
success
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Compare this features full path name to another using `#==`.
|
158
|
+
#
|
159
|
+
# @param [Feature,String] another feature or file path.
|
160
|
+
#
|
161
|
+
# @return [true,false] do the features represent the the same file
|
162
|
+
#
|
163
|
+
def ==(other)
|
164
|
+
fullname == other.to_s
|
165
|
+
end
|
166
|
+
|
167
|
+
#
|
168
|
+
# Same as `#==`.
|
169
|
+
#
|
170
|
+
# @param [Feature, String] another feature or file path.
|
171
|
+
#
|
172
|
+
# @return [true, false] if features are the same file
|
173
|
+
#
|
174
|
+
def eql?(other)
|
175
|
+
fullname == other.to_s
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Same a fullname.
|
180
|
+
#
|
181
|
+
# @return [String] expanded file path
|
182
|
+
#
|
183
|
+
def to_s
|
184
|
+
fullname
|
185
|
+
end
|
186
|
+
|
187
|
+
#
|
188
|
+
# Same a fullname.
|
189
|
+
#
|
190
|
+
# @return [String] expanded file path
|
191
|
+
#
|
192
|
+
def to_str
|
193
|
+
fullname
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# Use `#fullname` to calculate a hash value for the feature file.
|
198
|
+
#
|
199
|
+
# @return [Integer] hash value
|
200
|
+
#
|
201
|
+
def hash
|
202
|
+
fullname.hash
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|