Skip to content

Commit 4e3fc25

Browse files
committed
Add file-locator function, analogous to subdirectory-locator
1 parent 6ca4e26 commit 4e3fc25

File tree

5 files changed

+83
-3
lines changed

5 files changed

+83
-3
lines changed

documentation/library-reference/source/system/locators.rst

+19
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,25 @@ The locators Module
453453
454454
let build-dir = subdirectory-locator(working-directory(), "_build");
455455
456+
.. generic-function:: file-locator
457+
:open:
458+
459+
Returns a file locator for a file in a subdirectory of the given directory.
460+
461+
:signature: file-locator (directory, name, #rest more-names) => (file)
462+
463+
:parameter directory: An instance of :class:`<directory-locator>`.
464+
:parameter name: An instance of :drm:`<string>`.
465+
:parameter #rest more-names: Instances of :drm:`<string>`.
466+
:value file: An instance of :class:`<file-locator>`.
467+
468+
:example:
469+
470+
.. code-block:: dylan
471+
472+
let temp = file-locator(temp-directory(), "my-subdir", "my-test.json");
473+
ensure-directories-exist(temp); // Create "my-subdir" directory.
474+
456475
.. generic-function:: supports-list-locator?
457476
:open:
458477

documentation/release-notes/source/2022.1.rst

+3
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ system Library
104104

105105
* A segmentation fault when using ``list-locator`` was fixed (`bug 1372 <https://github.com/dylan-lang/opendylan/issues/1372>`_).
106106

107+
* Function ``file-locator``, to create a file locator as a child of a directory
108+
locator, is now exported from the locators module.
109+
107110
c-ffi Library
108111
-------------
109112

sources/system/library.dylan

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ define module locators
142142

143143
// Utilities
144144
create
145+
file-locator,
145146
merge-locators,
146147
relative-locator,
147148
resolve-locator,

sources/system/locators/locators.dylan

+29-3
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ define open generic locator-directory
1717
define open generic locator-relative?
1818
(locator :: <locator>) => (relative? :: <boolean>);
1919

20-
// For locator /a/b/c.d this will return #("a", "b").
20+
// For file locator /a/b/c this returns #["a", "b"].
21+
// For directory locator /a/b/c/ this returns #["a", "b", "c"].
2122
define open generic locator-path
2223
(locator :: <locator>) => (path :: <sequence>);
2324

24-
// The locator name, e.g. for locator /a/b/c.d
25-
// this will return "c.d"
25+
// For file locator /a/b/c this returns "c".
26+
// For directory locator /a/b/c/ this returns "c".
2627
define open generic locator-name
2728
(locator :: <locator>) => (name :: false-or(<string>));
2829

@@ -238,6 +239,31 @@ define method subdirectory-locator
238239
relative?: locator.locator-relative?)
239240
end method subdirectory-locator;
240241

242+
243+
/// File locator
244+
245+
// Make a <file-locator> that is a child of `directory`. If more than one name
246+
// is supplied, the last name is the name of the file and earlier names are
247+
// subdirectories.
248+
define open generic file-locator
249+
(directory :: <directory-locator>, name, #rest more-names)
250+
=> (file :: <file-locator>);
251+
252+
define method file-locator
253+
(directory :: <directory-locator>, name :: <string>, #rest more-names)
254+
=> (file :: <file-locator>)
255+
let length = more-names.size;
256+
if (length == 0)
257+
make(<file-locator>, directory: directory, name: name)
258+
else
259+
make(<file-locator>,
260+
directory: apply(subdirectory-locator, directory, name,
261+
copy-sequence(more-names, end: length - 1)),
262+
name: last(more-names))
263+
end
264+
end method;
265+
266+
241267

242268
/// Relative locator
243269

sources/system/tests/locators.dylan

+31
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,36 @@ define test test-subdirectory-locator ()
443443
$microsoft-subdirectory-tests)
444444
end test;
445445

446+
define test test-file-locator ()
447+
// file-locator calls make(<file-locator>) which calls
448+
// make(<native-file-locator>) passing `dir` (below) as the directory, which
449+
// crashes if passed a locator for another platform. That's why this code
450+
// doesn't attempt to test both Microsoft locators and POSIX locators on all
451+
// platforms and instead branches based on $os-name. This could be fixed if
452+
// we want to but I don't think it's a goal of the locators code be able to
453+
// use all platform-specific locator types on all platforms, even if it does
454+
// work for some of the other locators tests. --cgay
455+
let posix-args
456+
= #[#["/a/b/", #["c"], "/a/b/c"],
457+
#["/a/b/", #["c", "d"], "/a/b/c/d"],
458+
#["/a/b/", #["c", "d", "e"], "/a/b/c/d/e"]];
459+
let windows-args
460+
= #[#["c:\\a\\b\\", #["c"], "c:\\a\\b\\c"],
461+
#["c:\\a\\b\\", #["c", "d"], "c:\\a\\b\\c\\d"],
462+
#["\\\\a\\b\\", #["c", "d", "e"], "\\\\a\\b\\c\\d\\e"]];
463+
for (args in if ($os-name == #"win32")
464+
windows-args
465+
else
466+
posix-args
467+
end)
468+
let dir = as(<directory-locator>, args[0]);
469+
let names = args[1];
470+
let want = as(<file-locator>, args[2]);
471+
check-equal(format-to-string("file-locator(%=, %=) = %=", dir, names, want),
472+
want, apply(file-locator, dir, names));
473+
end;
474+
end test;
475+
446476
define constant $relative-tests
447477
= #[#["a", "a", "a"],
448478
#["a", "b", "a"],
@@ -603,6 +633,7 @@ define suite more-locators-test-suite ()
603633
test test-string-as-locator;
604634
test test-simplify-locator;
605635
test test-subdirectory-locator;
636+
test test-file-locator;
606637
test test-relative-locator;
607638
test test-merge-locators;
608639
test test-resolve-locator;

0 commit comments

Comments
 (0)