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.
@@ -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