Crystal: File.join should handle "" separately

Created on 3 Apr 2018  路  7Comments  路  Source: crystal-lang/crystal

When using File.join with empty strings, some unexpected results can be seen:

File.join("", "file.cr")
File.join(["dir", "", "file.cr"])

These should evaluate to "file.cr" and "dir/file.cr" respectively, but instead they evaluate to "/file.cr" (whoops, absolute path out of nowhere) and "dir//file.cr".

bug stdlib

Most helpful comment

The empty path "" equals to the current directory ".". Joining "", "file.cr" should be equivalent to joining ".", "file.cr". Otherwise you could end up with really be unexpected behaviour, if an empty path as first argument would somehow turn into the root directory.

Both behaviours are currently wrong. Thy are fixed in #5635, although it includes a bigger refactoring.

All 7 comments

  1. the behavior is identical to Ruby's, but maybe we should change it, the absolute path is probably unexpected;
  2. double file separator is wrong, yes.

I'm not sure 1 is unexpected. 2 can be fixed though.

The empty path "" equals to the current directory ".". Joining "", "file.cr" should be equivalent to joining ".", "file.cr". Otherwise you could end up with really be unexpected behaviour, if an empty path as first argument would somehow turn into the root directory.

Both behaviours are currently wrong. Thy are fixed in #5635, although it includes a bigger refactoring.

@straight-shoota can you extract a pull request to just fix these 2 behaviors? We could merge it quickly :)

The empty path "" equals to the current directory ".".

No. Looks like "a" equals to "b".

What does File.join do?

Returns a new string formed by joining the strings using File::SEPARATOR.

What ["", "file"].join(File::SEPARATOR) will return? "/file".

This is expected behavior.

I'm using this for web-paths in Ruby framework (File.join(nil, static_dir, file_name))

Why would "" equal to "/"? That's as much "a" equals "b". And it's not even universally applicable.

If File.join("", "file") equals to "/file", what would File.join("foo", "", "file") equal to? One could argue, it should also be "/file" if "" refers to the root "/". That doesn't make sense.

In fact, it is very logical to treat the path component "" equal to ".", as for example foo//bar consists of three components: ["foo", "", "bar"]. The second one is empty and semantically equivalent to ". That applies anywhere in a path. Interpreting an empty path at the beginning ofFile.joinas referring to the file system root"/"` is a hack. It's inconsistent and platform-specific. This would not work as expected on a windows system.

If you want to join an absolute path, just use an explicit root. It's simply "/" instead of "".

Please be aware that nil isn't even a valid path component for File.join in Crystal.

Why would "" equal to "/"

It's not equal. "" is member of parameters (Array), "/" is separator. Yeah, you're joining a-like things (path parts) with b-like separator.

If File.join("", "file") equals to "/file", what would File.join("foo", "", "file") equal to?

foo/file, because File.join doesn't allow multiple / in a row. It's a feature.

if "" refers to the root "/"

Yeah, your root is empty-named: %root_like_""%/file

Please be aware that nil isn't even a valid path component for File.join in Crystal.

I know, it's just an example.

It's inconsistent and platform-specific.

OK, maybe it's argument.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MakeNowJust picture MakeNowJust  路  64Comments

straight-shoota picture straight-shoota  路  91Comments

asterite picture asterite  路  78Comments

akzhan picture akzhan  路  67Comments

fridgerator picture fridgerator  路  79Comments