Dylan mode
x
1
Module: locators-internals
2
Synopsis: Abstract modeling of locations
3
Author: Andy Armstrong
4
Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc.
5
All rights reserved.
6
License: See License.txt in this distribution for details.
7
Warranty: Distributed WITHOUT WARRANTY OF ANY KIND
8
9
define open generic locator-server
10
(locator :: <locator>) => (server :: false-or(<server-locator>));
11
define open generic locator-host
12
(locator :: <locator>) => (host :: false-or(<string>));
13
define open generic locator-volume
14
(locator :: <locator>) => (volume :: false-or(<string>));
15
define open generic locator-directory
16
(locator :: <locator>) => (directory :: false-or(<directory-locator>));
17
define open generic locator-relative?
18
(locator :: <locator>) => (relative? :: <boolean>);
19
define open generic locator-path
20
(locator :: <locator>) => (path :: <sequence>);
21
define open generic locator-base
22
(locator :: <locator>) => (base :: false-or(<string>));
23
define open generic locator-extension
24
(locator :: <locator>) => (extension :: false-or(<string>));
25
26
/// Locator classes
27
28
define open abstract class <directory-locator> (<physical-locator>)
29
end class <directory-locator>;
30
31
define open abstract class <file-locator> (<physical-locator>)
32
end class <file-locator>;
33
34
define method as
35
(class == <directory-locator>, string :: <string>)
36
=> (locator :: <directory-locator>)
37
as(<native-directory-locator>, string)
38
end method as;
39
40
define method make
41
(class == <directory-locator>,
42
#key server :: false-or(<server-locator>) = #f,
43
path :: <sequence> = #[],
44
relative? :: <boolean> = #f,
45
name :: false-or(<string>) = #f)
46
=> (locator :: <directory-locator>)
47
make(<native-directory-locator>,
48
server: server,
49
path: path,
50
relative?: relative?,
51
name: name)
52
end method make;
53
54
define method as
55
(class == <file-locator>, string :: <string>)
56
=> (locator :: <file-locator>)
57
as(<native-file-locator>, string)
58
end method as;
59
60
define method make
61
(class == <file-locator>,
62
#key directory :: false-or(<directory-locator>) = #f,
63
base :: false-or(<string>) = #f,
64
extension :: false-or(<string>) = #f,
65
name :: false-or(<string>) = #f)
66
=> (locator :: <file-locator>)
67
make(<native-file-locator>,
68
directory: directory,
69
base: base,
70
extension: extension,
71
name: name)
72
end method make;
73
74
/// Locator coercion
75
76
//---*** andrewa: This caching scheme doesn't work yet, so disable it.
77
define constant $cache-locators? = #f;
78
define constant $cache-locator-strings? = #f;
79
80
define constant $locator-to-string-cache = make(<object-table>, weak: #"key");
81
define constant $string-to-locator-cache = make(<string-table>, weak: #"value");
82
83
define open generic locator-as-string
84
(class :: subclass(<string>), locator :: <locator>)
85
=> (string :: <string>);
86
87
define open generic string-as-locator
88
(class :: subclass(<locator>), string :: <string>)
89
=> (locator :: <locator>);
90
91
define sealed sideways method as
92
(class :: subclass(<string>), locator :: <locator>)
93
=> (string :: <string>)
94
let string = element($locator-to-string-cache, locator, default: #f);
95
if (string)
96
as(class, string)
97
else
98
let string = locator-as-string(class, locator);
99
if ($cache-locator-strings?)
100
element($locator-to-string-cache, locator) := string;
101
else
102
string
103
end
104
end
105
end method as;
106
107
define sealed sideways method as
108
(class :: subclass(<locator>), string :: <string>)
109
=> (locator :: <locator>)
110
let locator = element($string-to-locator-cache, string, default: #f);
111
if (instance?(locator, class))
112
locator
113
else
114
let locator = string-as-locator(class, string);
115
if ($cache-locators?)
116
element($string-to-locator-cache, string) := locator;
117
else
118
locator
119
end
120
end
121
end method as;
122
123
/// Locator conditions
124
125
define class <locator-error> (<format-string-condition>, <error>)
126
end class <locator-error>;
127
128
define function locator-error
129
(format-string :: <string>, #rest format-arguments)
130
error(make(<locator-error>,
131
format-string: format-string,
132
format-arguments: format-arguments))
133
end function locator-error;
134
135
/// Useful locator protocols
136
137
define open generic locator-test
138
(locator :: <directory-locator>) => (test :: <function>);
139
140
define method locator-test
141
(locator :: <directory-locator>) => (test :: <function>)
142
\=
143
end method locator-test;
144
145
define open generic locator-might-have-links?
146
(locator :: <directory-locator>) => (links? :: <boolean>);
147
148
define method locator-might-have-links?
149
(locator :: <directory-locator>) => (links? :: singleton(#f))
150
#f
151
end method locator-might-have-links?;
152
153
define method locator-relative?
154
(locator :: <file-locator>) => (relative? :: <boolean>)
155
let directory = locator.locator-directory;
156
~directory | directory.locator-relative?
157
end method locator-relative?;
158
159
define method current-directory-locator?
160
(locator :: <directory-locator>) => (current-directory? :: <boolean>)
161
locator.locator-relative?
162
& locator.locator-path = #[#"self"]
163
end method current-directory-locator?;
164
165
define method locator-directory
166
(locator :: <directory-locator>) => (parent :: false-or(<directory-locator>))
167
let path = locator.locator-path;
168
unless (empty?(path))
169
make(object-class(locator),
170
server: locator.locator-server,
171
path: copy-sequence(path, end: path.size - 1),
172
relative?: locator.locator-relative?)
173
end
174
end method locator-directory;
175
176
/// Simplify locator
177
178
define open generic simplify-locator
179
(locator :: <physical-locator>)
180
=> (simplified-locator :: <physical-locator>);
181
182
define method simplify-locator
183
(locator :: <directory-locator>)
184
=> (simplified-locator :: <directory-locator>)
185
let path = locator.locator-path;
186
let relative? = locator.locator-relative?;
187
let resolve-parent? = ~locator.locator-might-have-links?;
188
let simplified-path
189
= simplify-path(path,
190
resolve-parent?: resolve-parent?,
191
relative?: relative?);
192
if (path ~= simplified-path)
193
make(object-class(locator),
194
server: locator.locator-server,
195
path: simplified-path,
196
relative?: locator.locator-relative?)
197
else
198
locator
199
end
200
end method simplify-locator;
201
202
define method simplify-locator
203
(locator :: <file-locator>) => (simplified-locator :: <file-locator>)
204
let directory = locator.locator-directory;
205
let simplified-directory = directory & simplify-locator(directory);
206
if (directory ~= simplified-directory)
207
make(object-class(locator),
208
directory: simplified-directory,
209
base: locator.locator-base,
210
extension: locator.locator-extension)
211
else
212
locator
213
end
214
end method simplify-locator;
215
216
/// Subdirectory locator
217
218
define open generic subdirectory-locator
219
(locator :: <directory-locator>, #rest sub-path)
220
=> (subdirectory :: <directory-locator>);
221
222
define method subdirectory-locator
223
(locator :: <directory-locator>, #rest sub-path)
224
=> (subdirectory :: <directory-locator>)
225
let old-path = locator.locator-path;
226
let new-path = concatenate-as(<simple-object-vector>, old-path, sub-path);
227
make(object-class(locator),
228
server: locator.locator-server,
229
path: new-path,
230
relative?: locator.locator-relative?)
231
end method subdirectory-locator;
232
233
/// Relative locator
234
235
define open generic relative-locator
236
(locator :: <physical-locator>, from-locator :: <physical-locator>)
237
=> (relative-locator :: <physical-locator>);
238
239
define method relative-locator
240
(locator :: <directory-locator>, from-locator :: <directory-locator>)
241
=> (relative-locator :: <directory-locator>)
242
let path = locator.locator-path;
243
let from-path = from-locator.locator-path;
244
case
245
~locator.locator-relative? & from-locator.locator-relative? =>
246
locator-error
247
("Cannot find relative path of absolute locator %= from relative locator %=",
248
locator, from-locator);
249
locator.locator-server ~= from-locator.locator-server =>
250
locator;
251
path = from-path =>
252
make(object-class(locator),
253
path: vector(#"self"),
254
relative?: #t);
255
otherwise =>
256
make(object-class(locator),
257
path: relative-path(path, from-path, test: locator.locator-test),
258
relative?: #t);
259
end
260
end method relative-locator;
261
262
define method relative-locator
263
(locator :: <file-locator>, from-directory :: <directory-locator>)
264
=> (relative-locator :: <file-locator>)
265
let directory = locator.locator-directory;
266
let relative-directory = directory & relative-locator(directory, from-directory);
267
if (relative-directory ~= directory)
268
simplify-locator
269
(make(object-class(locator),
270
directory: relative-directory,
271
base: locator.locator-base,
272
extension: locator.locator-extension))
273
else
274
locator
275
end
276
end method relative-locator;
277
278
define method relative-locator
279
(locator :: <physical-locator>, from-locator :: <file-locator>)
280
=> (relative-locator :: <physical-locator>)
281
let from-directory = from-locator.locator-directory;
282
case
283
from-directory =>
284
relative-locator(locator, from-directory);
285
~locator.locator-relative? =>
286
locator-error
287
("Cannot find relative path of absolute locator %= from relative locator %=",
288
locator, from-locator);
289
otherwise =>
290
locator;
291
end
292
end method relative-locator;
293
294
/// Merge locators
295
296
define open generic merge-locators
297
(locator :: <physical-locator>, from-locator :: <physical-locator>)
298
=> (merged-locator :: <physical-locator>);
299
300
/// Merge locators
301
302
define method merge-locators
303
(locator :: <directory-locator>, from-locator :: <directory-locator>)
304
=> (merged-locator :: <directory-locator>)
305
if (locator.locator-relative?)
306
let path = concatenate(from-locator.locator-path, locator.locator-path);
307
simplify-locator
308
(make(object-class(locator),
309
server: from-locator.locator-server,
310
path: path,
311
relative?: from-locator.locator-relative?))
312
else
313
locator
314
end
315
end method merge-locators;
316
317
define method merge-locators
318
(locator :: <file-locator>, from-locator :: <directory-locator>)
319
=> (merged-locator :: <file-locator>)
320
let directory = locator.locator-directory;
321
let merged-directory
322
= if (directory)
323
merge-locators(directory, from-locator)
324
else
325
simplify-locator(from-locator)
326
end;
327
if (merged-directory ~= directory)
328
make(object-class(locator),
329
directory: merged-directory,
330
base: locator.locator-base,
331
extension: locator.locator-extension)
332
else
333
locator
334
end
335
end method merge-locators;
336
337
define method merge-locators
338
(locator :: <physical-locator>, from-locator :: <file-locator>)
339
=> (merged-locator :: <physical-locator>)
340
let from-directory = from-locator.locator-directory;
341
if (from-directory)
342
merge-locators(locator, from-directory)
343
else
344
locator
345
end
346
end method merge-locators;
347
348
/// Locator protocols
349
350
define sideways method supports-open-locator?
351
(locator :: <file-locator>) => (openable? :: <boolean>)
352
~locator.locator-relative?
353
end method supports-open-locator?;
354
355
define sideways method open-locator
356
(locator :: <file-locator>, #rest keywords, #key, #all-keys)
357
=> (stream :: <stream>)
358
apply(open-file-stream, locator, keywords)
359
end method open-locator;
360
MIME types defined: text/x-dylan
.