It's common to execute glob patterns within the context of a specific base path. By default, patterns are relative to the current working directory (Dir.current). But when you want a different base path, there are a couple of choices but none of them is really easy to use:
Dir.cd(path) { Dir.glob("foo/*) }: Changing the working directory is effective, but it applies for the entire process and can have unintended side effects.
Dir.glob("#{path}/foo/*): Trivially expanding the base path into the pattern is not portable: Glob patterns use forward slash (/) as path separators, so we must convert Windows paths with back slash (\).
Dir.glob(Path[path].to_posix.join("foo/*")): A portable path join with POSIX conversion is very verbose, and it's easy to miss.
I'm proposing to add a new parameter to Dir.glob (and related methods) to define a context path for resolving the pattern: Dir.glob("foo/*", base: path). It should behave similar to choice 3., but with a dedicated parameter for convenience. The default value continues to be the current working directory.
In conjunction with that change, we should narrow the type restriction of the pattern parameter to String (instead of Path | String). It's a glob pattern, not a pathname. The Path overload is useful when the pattern itself must contain the base path. But since we're pulling that out into a different parameter, there is no need for that anymore.
In fact, the behaviour is slightly weird because Dir.glob("foo\\*") and Dir.glob(Path.windows("foo\\*")) behave differently: The latter is automatically converted to a posix path and interpreted as a glob pattern with wildcard whereas the former is not. Dropping Path support removes this inconsistency.
Regarding the behaviour there is the question about whether matched paths should contain the base path as a prefix or not.
Dir.glob("foo/*", base: path)
"foo/bar": Without the base path, all matched paths would be implicitly considered relative to the base. This would reflect the behaviour of Dir.cd. Users need to remember expanding in the base path in order to be able to resolve the path to a file.
File.join(path, "foo/bar"): With the base path prefix, all matched paths would be absolute paths and work right out of the box. It requires extra work of removing the path prefix if you're interested in only the local path inside the base.
The latter is more user-friendly and offers an easier migration path when the results are to be used for other file operations (which is commonly the case).
So I believe we should use that behaviour. The new parameter overload would be a drop-in replacement for existing calls of the forms 2. and 3. in most (if not all) use cases.
A draft implementation is available in #16842
Add a 👍 reaction to issues you find important.
It's common to execute glob patterns within the context of a specific base path. By default, patterns are relative to the current working directory (
Dir.current). But when you want a different base path, there are a couple of choices but none of them is really easy to use:Dir.cd(path) { Dir.glob("foo/*) }: Changing the working directory is effective, but it applies for the entire process and can have unintended side effects.Dir.glob("#{path}/foo/*): Trivially expanding the base path into the pattern is not portable: Glob patterns use forward slash (/) as path separators, so we must convert Windows paths with back slash (\).Dir.glob(Path[path].to_posix.join("foo/*")): A portable path join with POSIX conversion is very verbose, and it's easy to miss.I'm proposing to add a new parameter to
Dir.glob(and related methods) to define a context path for resolving the pattern:Dir.glob("foo/*", base: path). It should behave similar to choice 3., but with a dedicated parameter for convenience. The default value continues to be the current working directory.In conjunction with that change, we should narrow the type restriction of the
patternparameter toString(instead ofPath | String). It's a glob pattern, not a pathname. ThePathoverload is useful when the pattern itself must contain the base path. But since we're pulling that out into a different parameter, there is no need for that anymore.In fact, the behaviour is slightly weird because
Dir.glob("foo\\*")andDir.glob(Path.windows("foo\\*"))behave differently: The latter is automatically converted to a posix path and interpreted as a glob pattern with wildcard whereas the former is not. DroppingPathsupport removes this inconsistency.Regarding the behaviour there is the question about whether matched paths should contain the base path as a prefix or not.
Dir.glob("foo/*", base: path)"foo/bar": Without the base path, all matched paths would be implicitly considered relative to the base. This would reflect the behaviour ofDir.cd. Users need to remember expanding in the base path in order to be able to resolve the path to a file.File.join(path, "foo/bar"): With the base path prefix, all matched paths would be absolute paths and work right out of the box. It requires extra work of removing the path prefix if you're interested in only the local path inside the base.The latter is more user-friendly and offers an easier migration path when the results are to be used for other file operations (which is commonly the case).
So I believe we should use that behaviour. The new parameter overload would be a drop-in replacement for existing calls of the forms 2. and 3. in most (if not all) use cases.
A draft implementation is available in #16842
Add a 👍 reaction to issues you find important.