https://wiki.mozilla.org/ServerJS/API/file
Ondras had expressed in IRC that the proposal didn't feel object
oriented enough, in that I hadn't written in a type that would
represent a path to a file or directory. To entertain the idea, I
threw a Path type into the filesystem root object, so you can create
references to paths without committing to opening a stream, listing a
directory's contents, or manipulating its metadata. I am now prepared
to concede that it was wrong to omit a Path type.
I called it Path in contrast to Java io's and Spidermonkey's File
since File is too easy for a polyglot to confuse for a stream object,
rather than an inert noncommittal path reference. Java seems to have
taken the same turn with its new "nio" package.
What I like about the path object is that it is possible to "chain"
path manipulation functions. I set it up so that Path objects were
loose wrappers around a file system root object and a path string,
with a suite of member functions that were simply shortcuts for the
members on the file system, where the first path argument was
implicitly filled in. So, the following were equivalent:
fs.read(path)
fs.open(path).read()
fs.path(path).open().read()
And here's a more fun example from packages.js in Narwhal:
var packagesDir = fs.path(system.env.NARWHAL_HOME).join('packages');
packagesDir.list().forEach(function (packageName) {
var packageJson = packagesDir.join(packageName, 'package.json');
if (packageJson.exists()) {
packageJson.read();
}
});
I think that these Path objects offer a really nice workflow.
In the process of doing the prototype, I found words to articulate the
difference between "join" and "resolve". "join" is as simple as
delimiting arguments with the directory separator, which is nice
because you can use it in cases where the base path is known to be a
directory. "resolve" is very handy for implementing other functions
like "absolute", "normal", and "dirname". The difference is that
resolve, like URL resolution, treats a leaf directory of a path
differently if it ends with a directory separator "/" than if it does
not. That is, if there's a "/" you're referring to the location
inside the directory, and without the "/", you're referring to the
directory containing the leaf. So, when you resolve "bar" relative to
"foo", you'll get "bar", but if you resolve "bar" relative to "foo/",
you'll get "foo/bar". With "join", you would get "foo/bar" in both
cases.
Path and resolve are pure-JavaScript, so they're suitable for sharing
in the standard library file.js module, while functions like
"canonical" will need to be platform-specific. Here's "resolve" and
you can find "Path" in the same file.
http://github.com/kriskowal/narwhal/blob/b5cfcd8416847660028046d2df0d80593a407cbc/lib/file.js#L85
I've attached an illustration of the channels, by way of method calls,
through which you can go from a file system root to a directory
listing, a stat object, or a stream. This is in the abstract, so
"root" is meant to depict a file system root object, albeith
"system.fs" or that returned by require("file") in the proposal.
"open" can naturally open both input and output streams for both byte
and character string data. It's meant to illustrate that creating a
Path object is equivalent to returning a new object for which all the
same functions as are available on a file system root are supplied,
but partially applied on given path.
One interesting turn with the Path API I threw in Narwhal: When you
get a Path object, all of the methods that return paths are chainable
Path instances, on which toString() returns the wrapped String of the
Path. However, all of the file system root methods return plain old
Strings. I think this is a good compromise and will yield few
surprises.
assert typeof fs.canonical("/") == "/"
assert fs.path("/").canonical() instanceof fs.Path
Kris Kowal
Ondras had expressed in IRC that the proposal didn't feel object
oriented enough, in that I hadn't written in a type that would
represent a path to a file or directory. To entertain the idea, I
threw a Path type into the filesystem root object, so you can create
references to paths without committing to opening a stream, listing a
directory's contents, or manipulating its metadata. I am now prepared
to concede that it was wrong to omit a Path type.
fs.read(path)
fs.open(path).read()
fs.path(path).open().read()