Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify documentation on Path#join and #== #10455

Merged
merged 3 commits into from
Jun 13, 2021

Conversation

straight-shoota
Copy link
Member

Copy link

@Leximatica Leximatica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding "the second to last component is returned."

What about the patholexical edge case:

Path["/foo/bar/././././."].basename

If "bar" is the second-to-last component of Path["/foo/bar/."], then it is the sixth-to-last component of Path["/foo/bar/././././."], and thus the documentation is rendered literally wrong.

I wonder if we are converging on an understanding that Path[p].basename should be an alias for Path[p].normalize.basename.

This suggests a possible:

Path#basename(normalize : Boolean = true)

... which "does no harm", and provides a capability to handle (i.e. decompose and explore) strangely formed paths within Path, without having to export "to_s" and write custom (potentially platform dependent) parsers.

@straight-shoota
Copy link
Member Author

The first part of the sentence clearly applies it to the "case the last component is the empty string". . is not an empty string. So Path["a/."].basename == "." and the documentation is correct.

I wonder if we are converging on an understanding that Path[p].basename should be an alias for Path[p].normalize.basename.

I don't think #basename nor any other method should implicitly normalize the path unless necessary (for example in #relative_to?). Not even if you can opt-out of normalization. You can simply opt-in by a calling #normalize. Ideally as soon as a potentially de-normalized path enters the system, which means only once instead of every time you call a method #basename.

... which "does no harm", and provides a capability to handle (i.e. decompose and explore) strangely formed paths within Path, without having to export "to_s" and write custom (potentially platform dependent) parsers.

"strangely formed paths" are already handled by #normalize. There's no need for to_s or custom parsers. Just a single method.

@Leximatica
Copy link

Leximatica commented Feb 28, 2021 via email

@straight-shoota
Copy link
Member Author

Ah, sorry I didn't catch what you mean. That's just a typo. It should be Path["/foo/bar/."].basename # => ".".

Comment on lines +1121 to +1124
# Path["foo"] == Path["foo"] # => true
# Path["foo"] == Path["./foo"] # => false
# Path["foo"] == Path["foo/"] # => false
# Path.posix("foo") == Path.windows("foo") # => false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm this sample code is a bit misleading because it says == but then only after a big chunk of whitespace it says "actually that's false".

On the other hand, if you change this to !=, then adding # => true at the end is also misleading.

Maybe just have to drop the comments at the end..

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean, but IMO this is the least surprising variant. Besides, we use this pattern everywhere for documentation. I don't think we should change anything. Using != doesn't help, because the visual difference is even less than with == and false.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK that's fine.
Could still try to minimize the whitespace.

Suggested change
# Path["foo"] == Path["foo"] # => true
# Path["foo"] == Path["./foo"] # => false
# Path["foo"] == Path["foo/"] # => false
# Path.posix("foo") == Path.windows("foo") # => false
# Path["foo"] == Path["foo"] # => true
# Path["foo"] == Path["./foo"] # => false
# Path["foo"] == Path["foo/"] # => false
#
# Path.posix("foo") == Path.windows("foo") # => false

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. Is the whitespace really such a visual barrier in the rendered API docs? IMO adding different indents might add confusion, as well as the random empty line, just to force the formatted.
All these expressions form a set. The last one is just visually different because it uses explicitly named constructor methods. But semantically, there should be no distance to the previous ones.

We could consider using explicit .new methods instead of the .[] short form. That would reduce the difference in lenght between the lines.

src/path.cr Outdated Show resolved Hide resolved
Co-authored-by: Jonne Haß <me@jhass.eu>
@straight-shoota straight-shoota added this to the 1.1.0 milestone Jun 10, 2021
@straight-shoota straight-shoota merged commit 10e5c25 into crystal-lang:master Jun 13, 2021
@straight-shoota straight-shoota deleted the docs/path-join branch June 13, 2021 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants