Bug #14891
closedPathname#join has different behaviour to File.join
Description
Pathname.new('/a').join('/b').to_s
# => "/b"
File.join(Pathname.new('/a'), '/b').to_s
# => "/a/b"
in my case '/b'
was in a variable and it wasn't immediately obvious why it wasn't working when I moved to use Pathname
This seems to not be desired behaviour as it's different to File.join
, and this case isn't document anywhere.
Can we either change the behaviour to treat the "other" of Pathname#+
as always relative (possibly just removing a leading slash), or add this case to the documentation?
Updated by robotdana (Dana Sherson) over 6 years ago
- ruby -v set to 2.6.0-preview2, and before
Updated by shevegen (Robert A. Heiler) over 6 years ago
This behaviour surprised me too. Is it expected that the information from "/a"
is lost? I have no idea but the documentation does not mention this; perhaps
the above could be added as an example OR the behaviour changed (or both).
I have little to none experience with pathname these days as I seem to handle
paths ... without pathname. :D
Documentation to Pathname .join is at:
https://ruby-doc.org/stdlib-2.5.1/libdoc/pathname/rdoc/Pathname.html#method-i-join
Updated by Hanmac (Hans Mackowiak) over 6 years ago
More examples:
Pathname.new('/a').join('c', 'b').to_s #=> "/a/c/b"
Pathname.new('/a').join('/c', 'b').to_s #=> "/c/b"
Pathname.new('/a').join('/c', '/b').to_s #=> "/b"
Why it does this?
because "/c"
means start of an absolute path there
Updated by znz (Kazuhiro NISHIYAMA) over 6 years ago
I think it is expected behavior.
defassert(:plus, '/b', 'a', '/b')
Updated by funny_falcon (Yura Sokolov) over 6 years ago
I'd rather say that File.join is currently broken, and it should behave like Pathname.join. But probably I'm missing something.
Updated by jnchito (Junichi Ito) almost 5 years ago
I am wondering about the current behavior of Pathname#join, too. Are there any useful use cases for Pathname.new('/a').join('/c', '/b').to_s #=> "/b"
? I think it should be Pathname.new('/a').join('/c', '/b').to_s #=> "/a/c/b
like File#join. I'd like to know the basic idea behind this design.
Updated by zverok (Victor Shepelev) almost 5 years ago
I am wondering about the current behavior of Pathname#join, too. Are there any useful use cases for
Pathname.new('/a').join('/c', '/b').to_s #=> "/b"
I believe that Pathname#join
acts kinda like cd
in the shell: cd x
is "go deeper to x
level" while cd /x
si "go to the root, then into /x
folder".
I believe it can be useful and desired behavior when working with configs for some authoring systems and devops tools, where you take from config "do 'action' by path 'path'", and config can specify lot of actions relative to app folder (like touch: "tmp/restart.txt"
), but eventually want to specify something to do in relative-from-root folder (like read: "/etc/myapp/settings.ini"
). Without following the specification "/
at the beginning means go to root" it becomes rather ugly.
In other words, this:
# I am just trying to merge pathes explicitly, and receive "unexpected" result:
Pathname.new('foo').merge('/bar')
— might seem "weird", while this:
@app_path = Path.new(__dir__)
# ...
@app_path.join(action.target_path) # when target_path is "/foo/bar", it allows to act outside of base dir
— is desirable (and is NOT achievable if Pathname's
behavior will be changed)
I assume that those finding the behavior less logical think about paths about "just some abstract strings" and Pathname#join
as a fancy way to write Array#join(SYSTEM_PATH_DELIMITER)
. But Pathname
tries to represent "filesystem path object" in a meaningful way, consistent with filesystem's intuitions.
Updated by jnchito (Junichi Ito) almost 5 years ago
zverok (Victor Shepelev) wrote in #note-7:
I am wondering about the current behavior of Pathname#join, too. Are there any useful use cases for
Pathname.new('/a').join('/c', '/b').to_s #=> "/b"
I believe that
Pathname#join
acts kinda likecd
in the shell:cd x
is "go deeper tox
level" whilecd /x
si "go to the root, then into/x
folder".
Thank you for your explanation. It is easy to understand the behavior if I think Pathname.new('/a').join('/c', '/b')
means cd /a
then cd /c
then cd /b
. (params can be both directories and files, though.)
I assume that those finding the behavior less logical think about paths about "just some abstract strings" and
Pathname#join
as a fancy way to writeArray#join(SYSTEM_PATH_DELIMITER)
. ButPathname
tries to represent "filesystem path object" in a meaningful way, consistent with filesystem's intuitions.
That is me who thought "Pathname#join
as a fancy way to write Array#join(SYSTEM_PATH_DELIMITER)
". However, Rails developers like me often see Rails.root.join('foo/bar.jpg')
as main use case of Pathname#join
. So I guess many of them might misunderstand it just joins two strings in a readable way.
In addition, it is very confusing File#join
has the same name and different behavior, and File and Pathname are also close idea. Many people might misunderstand they act in the same way. So probably Pathname#join
should have been given an another good name. (Pathname#merge
might not be a bad idea.)
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
- Status changed from Open to Closed