From: lovro-bikic via ruby-core Date: 2025-06-01T14:03:19+00:00 Subject: [ruby-core:122361] [Ruby Bug#21391] Inconsistent trailing slash behavior of File.join and Pathname#join with empty strings Issue #21391 has been updated by lovro-bikic (Lovro Biki��). Dan0042 (Daniel DeLorme) wrote in #note-2: > It's not the only inconsistent behavior: (absolute and relative paths example) To clarify, I don't expect the result of the two to be equivalent in all cases, it's clearly documented what each method does. What I am reporting is that there's undocumented and possibly inconsistent behavior when it comes to empty strings. Furthermore, the example with a whitespace string shows that `Pathname#join` is capable of adding trailing slashes under certain conditions. [`File.join` behavior has been tested for empty strings](https://github.com/ruby/spec/blob/f3a071a0fea213c6e909e253e43144a8c49483c6/core/file/join_spec.rb#L67-L101), but [`Pathname#join` hasn't](https://github.com/ruby/spec/blob/f3a071a0fea213c6e909e253e43144a8c49483c6/library/pathname/join_spec.rb), so it's unclear if this is a bug or an expected difference in behavior. Dan0042 (Daniel DeLorme) wrote in #note-2: > That being said, I feel that Pathname.new('/usr').join('') is a nonsensical operation. It seems to result in a no-op, but it might be better to warn or raise an error. Perhaps, [but it's already a common pattern with `File.join`](https://github.com/search?q=%2FFile%5C.join%5C(%5B%5Cw._()%5D%2B%2C%20(%22%22%7C%27%27)%5C)%2F%20lang%3Aruby&type=code). Whether it's a nonsensical operation is up for debate, but I think there should be a clear way for `Pathname#join` to allow appending trailing slashes to pathnames. ---------------------------------------- Bug #21391: Inconsistent trailing slash behavior of File.join and Pathname#join with empty strings https://bugs.ruby-lang.org/issues/21391#change-113504 * Author: lovro-bikic (Lovro Biki��) * Status: Open * ruby -v: ruby 3.4.4 (2025-05-14 revision a38531fd3f) +PRISM [x86_64-darwin23] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- ```ruby File.join('/usr', '') # => "/usr/" Pathname.new('/usr').join('').to_s # => "/usr" # no trailing slash File.join('/usr', ' ') # => "/usr/ " Pathname.new('/usr').join(' ').to_s # => "/usr/ " ``` `File.join` with an empty string adds a trailing slash, `Pathname#join` doesn't. When `Pathname#join` argument is a string with empty whitespace, a trailing slash is added (plus whitespace). I think it's a common use-case to append a trailing slash to `Pathname`, and currently you have to resort to other methods such as string interpolation (e.g. in Rails, `"#{Rails.root}/"`) or `File.join` (e.g. `File.join(Rails.root, '')`). In other popular languages, both approaches have been taken: - [`os.path.join` in Python](https://docs.python.org/3.12/library/os.path.html#os.path.join) adds a trailing slash: ```python import os os.path.join('/usr', '') # '/usr/' ``` - [Path.join in Rust](https://doc.rust-lang.org/std/path/struct.Path.html#method.join) adds a trailing slash: ```rust use std::path::{Path}; fn main() { println!("{}", Path::new("/usr").join("").display()); // prints "/usr/" } ``` - [path.join in Node](https://nodejs.org/api/path.html#pathjoinpaths) doesn't add a trailing slash: ```js const path = require('path'); path.join('/usr', ''); // '/usr' ``` - [filepath.Join in Go](https://pkg.go.dev/path/filepath#Join) doesn't add a trailing slash: ```go package main import ("fmt"; "path/filepath") func main() { fmt.Println(filepath.Join("/usr", "")) // prints "/usr" } ``` -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/