library 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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