Skip to content
Daniel Berger edited this page Feb 13, 2023 · 14 revisions

Description

The win32-xpath library is a custom version of the File.expand_path method for Windows.

Motivation

I wrote this because I noticed that the tests for File.expand_path from my custom test suite were rather slow. When I realized that it was because the underlying code was poor, I decided to rewrite it. I thought this code had been revamped by Luis Lavena once already, but it's not clear to me if his code was simply never integrated or if he just did a crappy job. Either way, the current source code isn't good.

I also decided that it would be nice to allow "~user" notation, which this library supports.

Benefits

This code is much faster than the MRI source code. Here are some benchmarks of 100k iterations on Windows 7 using Ruby 2.2.0 that was built with the MS Visual Studio 2013 compiler:

Old File.expand_path
                                 user     system      total        real
expand_path('foo/bar')           0.780000   1.404000   2.184000 (  2.173918)
expand_path('C:/foo/bar')        0.686000   1.654000   2.340000 (  2.350356)
expand_path('//foo/bar')         1.108000  27.768000  28.876000 ( 31.596080)
expand_path('foo//bar///')       0.764000   1.404000   2.168000 (  2.168984)
expand_path('~')                 1.233000   2.917000   4.150000 (  4.152460)
expand_path('')                  1.014000   3.495000   4.509000 (  4.507877)
expand_path('', '~')             1.201000   2.901000   4.102000 (  4.137849)

New File.expand_path
                                 user     system      total        real
expand_path('foo/bar')           0.530000   0.000000   0.530000 (  0.531334)
expand_path('C:/foo/bar')        0.343000   0.016000   0.359000 (  0.372399)
expand_path('//foo/bar')         0.359000   0.031000   0.390000 (  0.386417)
expand_path('foo//bar///')       0.608000   0.016000   0.624000 (  0.608276)
expand_path('~')                 0.500000   0.109000   0.609000 (  0.623673)
expand_path('')                  0.343000   0.047000   0.390000 (  0.394709)
expand_path('', '~')             0.671000   0.125000   0.796000 (  0.817625)

As you can see, it's about 5x faster than MRI. Note that there's a pathological case in MRI when calling File.expand_path on a UNC root path. In that particular case, my code is 100x faster.

This code is still about 2x faster than JRuby, too.

Caveats

As mentioned in the README, I don't support $DATA mangling, and I don't explicitly support drive-current paths. It is extremely unlikely that you will be affected by either of these things. And no, those things don't explain the 5x performance difference.

Updates

Update 1: As of Ruby 2.5, it seems their benchmarks have improved to parity in the case of expand_path('~') and expand_path('', '~'), but this library is still roughly 5x faster in other cases. And their pathological slowdown for UNC paths still exists.

Update 2: Regarding the pathological slowdown on UNC paths, I have reported it and it has been fixed. You can see details at https://bugs.ruby-lang.org/issues/15633.

Clone this wiki locally