Created
February 4, 2012 03:29
-
-
Save shirosaki/1734954 to your computer and use it in GitHub Desktop.
Fenix patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
With long name conversion. | |
Run options: --seed 40925 | |
# Running tests: | |
...................................S | |
Finished tests in 2.681746s, 13.4241 tests/s, 22.3735 assertions/s. | |
36 tests, 60 assertions, 0 failures, 0 errors, 1 skips | |
File.expand_path: 10000 times. | |
Rehearsal ------------------------------------------------------------- | |
Ruby '' 0.125000 0.312000 0.437000 ( 0.436025) | |
Fenix '' 0.031000 0.000000 0.031000 ( 0.027002) | |
Plain '' 0.016000 0.000000 0.016000 ( 0.027001) | |
Ruby '.' 0.156000 0.297000 0.453000 ( 0.437025) | |
Fenix '.' 0.016000 0.000000 0.016000 ( 0.028002) | |
Plain '.' 0.031000 0.000000 0.031000 ( 0.027001) | |
Ruby 'foo', 'bar' 0.187000 0.436000 0.623000 ( 0.624013) | |
Fenix 'foo', 'bar' 0.047000 0.203000 0.250000 ( 0.262401) | |
Plain 'foo', 'bar' 0.031000 0.000000 0.031000 ( 0.040000) | |
Ruby '', 'C:/' 0.016000 0.000000 0.016000 ( 0.010000) | |
Fenix '', 'C:/' 0.031000 0.000000 0.031000 ( 0.030000) | |
Plain '', 'C:/' 0.015000 0.000000 0.015000 ( 0.020000) | |
Ruby 'foo', 'C:/' 0.125000 0.905000 1.030000 ( 1.029022) | |
Fenix 'foo', 'C:/' 0.031000 0.218000 0.249000 ( 0.246014) | |
Plain 'foo', 'C:/' 0.032000 0.000000 0.032000 ( 0.027002) | |
Ruby '~' 0.249000 0.312000 0.561000 ( 0.570030) | |
Fenix '~' 0.031000 0.000000 0.031000 ( 0.031002) | |
Plain '~' 0.032000 0.000000 0.032000 ( 0.030002) | |
Ruby '~/foo' 0.249000 0.312000 0.561000 ( 0.549031) | |
Fenix '~/foo' 0.125000 0.094000 0.219000 ( 0.229012) | |
Plain '~/foo' 0.047000 0.000000 0.047000 ( 0.037001) | |
Ruby 'foo/' 0.062000 0.343000 0.405000 ( 0.416024) | |
Fenix 'foo/' 0.109000 0.125000 0.234000 ( 0.230013) | |
Plain 'foo/' 0.032000 0.000000 0.032000 ( 0.027002) | |
Ruby '~', 'C:/Foo' 0.171000 0.390000 0.561000 ( 0.571829) | |
Fenix '~', 'C:/Foo' 0.047000 0.000000 0.047000 ( 0.033001) | |
Plain '~', 'C:/Foo' 0.031000 0.000000 0.031000 ( 0.037003) | |
Ruby long_path 0.156000 0.000000 0.156000 ( 0.155008) | |
Fenix long_path 0.109000 0.000000 0.109000 ( 0.114007) | |
Plain long_path 0.110000 0.000000 0.110000 ( 0.104006) | |
Ruby long_path, 'rel' 0.265000 0.296000 0.561000 ( 0.577031) | |
Fenix long_path, 'rel' 0.125000 0.000000 0.125000 ( 0.122007) | |
Plain long_path, 'rel' 0.109000 0.000000 0.109000 ( 0.109006) | |
Ruby long_path, 'C:/Foo' 0.218000 0.952000 1.170000 ( 1.178864) | |
Fenix long_path, 'C:/Foo' 0.125000 0.000000 0.125000 ( 0.118007) | |
Plain long_path, 'C:/Foo' 0.109000 0.000000 0.109000 ( 0.104006) | |
Ruby full_long_path 0.125000 0.000000 0.125000 ( 0.133007) | |
Fenix full_long_path 0.109000 0.000000 0.109000 ( 0.107006) | |
Plain full_long_path 0.094000 0.000000 0.094000 ( 0.097003) | |
Ruby to_path 0.047000 0.218000 0.265000 ( 0.260015) | |
Fenix to_path 0.140000 0.110000 0.250000 ( 0.252014) | |
Plain to_path 0.031000 0.000000 0.031000 ( 0.030002) | |
Ruby to_path, 'rel' 0.141000 0.530000 0.671000 ( 0.666435) | |
Fenix to_path, 'rel' 0.093000 0.156000 0.249000 ( 0.261015) | |
Plain to_path, 'rel' 0.031000 0.000000 0.031000 ( 0.037002) | |
Ruby to_path, 'C:/Foo' 0.125000 1.154000 1.279000 ( 1.284871) | |
Fenix to_path, 'C:/Foo' 0.093000 0.172000 0.265000 ( 0.259213) | |
Plain to_path, 'C:/Foo' 0.032000 0.000000 0.032000 ( 0.037601) | |
Ruby full_to_path 0.062000 0.936000 0.998000 ( 1.020056) | |
Fenix full_to_path 0.031000 0.218000 0.249000 ( 0.251015) | |
Plain full_to_path 0.016000 0.000000 0.016000 ( 0.022001) | |
--------------------------------------------------- total: 13.260000sec | |
user system total real | |
Ruby '' 0.125000 0.312000 0.437000 ( 0.434025) | |
Fenix '' 0.031000 0.000000 0.031000 ( 0.026001) | |
Plain '' 0.031000 0.000000 0.031000 ( 0.026002) | |
Ruby '.' 0.062000 0.375000 0.437000 ( 0.434023) | |
Fenix '.' 0.016000 0.000000 0.016000 ( 0.027001) | |
Plain '.' 0.031000 0.000000 0.031000 ( 0.026002) | |
Ruby 'foo', 'bar' 0.172000 0.468000 0.640000 ( 0.633036) | |
Fenix 'foo', 'bar' 0.093000 0.156000 0.249000 ( 0.253812) | |
Plain 'foo', 'bar' 0.032000 0.000000 0.032000 ( 0.033002) | |
Ruby '', 'C:/' 0.015000 0.000000 0.015000 ( 0.017001) | |
Fenix '', 'C:/' 0.031000 0.000000 0.031000 ( 0.024001) | |
Plain '', 'C:/' 0.032000 0.000000 0.032000 ( 0.023002) | |
Ruby 'foo', 'C:/' 0.093000 0.920000 1.013000 ( 1.022055) | |
Fenix 'foo', 'C:/' 0.063000 0.187000 0.250000 ( 0.248014) | |
Plain 'foo', 'C:/' 0.031000 0.000000 0.031000 ( 0.026002) | |
Ruby '~' 0.218000 0.344000 0.562000 ( 0.570032) | |
Fenix '~' 0.031000 0.000000 0.031000 ( 0.030000) | |
Plain '~' 0.032000 0.000000 0.032000 ( 0.033002) | |
Ruby '~/foo' 0.249000 0.312000 0.561000 ( 0.548031) | |
Fenix '~/foo' 0.031000 0.202000 0.233000 ( 0.235013) | |
Plain '~/foo' 0.032000 0.000000 0.032000 ( 0.031002) | |
Ruby 'foo/' 0.124000 0.281000 0.405000 ( 0.414221) | |
Fenix 'foo/' 0.063000 0.172000 0.235000 ( 0.228013) | |
Plain 'foo/' 0.031000 0.000000 0.031000 ( 0.027001) | |
Ruby '~', 'C:/Foo' 0.218000 0.343000 0.561000 ( 0.572031) | |
Fenix '~', 'C:/Foo' 0.031000 0.000000 0.031000 ( 0.033002) | |
Plain '~', 'C:/Foo' 0.031000 0.000000 0.031000 ( 0.036002) | |
Ruby long_path 0.156000 0.000000 0.156000 ( 0.152009) | |
Fenix long_path 0.110000 0.000000 0.110000 ( 0.112006) | |
Plain long_path 0.109000 0.000000 0.109000 ( 0.099006) | |
Ruby long_path, 'rel' 0.249000 0.312000 0.561000 ( 0.563032) | |
Fenix long_path, 'rel' 0.125000 0.000000 0.125000 ( 0.126006) | |
Plain long_path, 'rel' 0.109000 0.000000 0.109000 ( 0.107006) | |
Ruby long_path, 'C:/Foo' 0.172000 0.998000 1.170000 ( 1.172865) | |
Fenix long_path, 'C:/Foo' 0.125000 0.000000 0.125000 ( 0.115006) | |
Plain long_path, 'C:/Foo' 0.093000 0.000000 0.093000 ( 0.101006) | |
Ruby full_long_path 0.141000 0.000000 0.141000 ( 0.131008) | |
Fenix full_long_path 0.109000 0.000000 0.109000 ( 0.108006) | |
Plain full_long_path 0.094000 0.000000 0.094000 ( 0.093005) | |
Ruby to_path 0.031000 0.219000 0.250000 ( 0.258012) | |
Fenix to_path 0.110000 0.140000 0.250000 ( 0.249014) | |
Plain to_path 0.031000 0.000000 0.031000 ( 0.030002) | |
Ruby to_path, 'rel' 0.140000 0.515000 0.655000 ( 0.660036) | |
Fenix to_path, 'rel' 0.078000 0.187000 0.265000 ( 0.261015) | |
Plain to_path, 'rel' 0.031000 0.000000 0.031000 ( 0.037002) | |
Ruby to_path, 'C:/Foo' 0.078000 1.217000 1.295000 ( 1.285071) | |
Fenix to_path, 'C:/Foo' 0.110000 0.156000 0.266000 ( 0.264015) | |
Plain to_path, 'C:/Foo' 0.031000 0.000000 0.031000 ( 0.031002) | |
Ruby full_to_path 0.062000 0.952000 1.014000 ( 1.012856) | |
Fenix full_to_path 0.031000 0.218000 0.249000 ( 0.250011) | |
Plain full_to_path 0.016000 0.000000 0.016000 ( 0.022001) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Without long name conversion. | |
Run options: --seed 59008 | |
# Running tests: | |
...................................S | |
Finished tests in 0.116007s, 310.3261 tests/s, 517.2102 assertions/s. | |
36 tests, 60 assertions, 0 failures, 0 errors, 1 skips | |
File.expand_path: 10000 times. | |
Rehearsal ------------------------------------------------------------- | |
Ruby '' 0.062000 0.390000 0.452000 ( 0.441023) | |
Fenix '' 0.016000 0.000000 0.016000 ( 0.027002) | |
Plain '' 0.031000 0.000000 0.031000 ( 0.027001) | |
Ruby '.' 0.109000 0.327000 0.436000 ( 0.440025) | |
Fenix '.' 0.031000 0.000000 0.031000 ( 0.027002) | |
Plain '.' 0.032000 0.000000 0.032000 ( 0.027002) | |
Ruby 'foo', 'bar' 0.062000 0.578000 0.640000 ( 0.632833) | |
Fenix 'foo', 'bar' 0.031000 0.000000 0.031000 ( 0.034002) | |
Plain 'foo', 'bar' 0.031000 0.000000 0.031000 ( 0.034002) | |
Ruby '', 'C:/' 0.016000 0.000000 0.016000 ( 0.017001) | |
Fenix '', 'C:/' 0.031000 0.000000 0.031000 ( 0.024002) | |
Plain '', 'C:/' 0.016000 0.000000 0.016000 ( 0.025001) | |
Ruby 'foo', 'C:/' 0.109000 0.920000 1.029000 ( 1.025056) | |
Fenix 'foo', 'C:/' 0.031000 0.000000 0.031000 ( 0.025002) | |
Plain 'foo', 'C:/' 0.016000 0.000000 0.016000 ( 0.027001) | |
Ruby '~' 0.265000 0.312000 0.577000 ( 0.568829) | |
Fenix '~' 0.031000 0.000000 0.031000 ( 0.031001) | |
Plain '~' 0.031000 0.000000 0.031000 ( 0.030002) | |
Ruby '~/foo' 0.297000 0.250000 0.547000 ( 0.547031) | |
Fenix '~/foo' 0.031000 0.000000 0.031000 ( 0.032002) | |
Plain '~/foo' 0.031000 0.000000 0.031000 ( 0.031002) | |
Ruby 'foo/' 0.156000 0.249000 0.405000 ( 0.411021) | |
Fenix 'foo/' 0.031000 0.000000 0.031000 ( 0.028002) | |
Plain 'foo/' 0.032000 0.000000 0.032000 ( 0.028002) | |
Ruby '~', 'C:/Foo' 0.234000 0.328000 0.562000 ( 0.570032) | |
Fenix '~', 'C:/Foo' 0.046000 0.000000 0.046000 ( 0.034002) | |
Plain '~', 'C:/Foo' 0.032000 0.000000 0.032000 ( 0.036002) | |
Ruby long_path 0.140000 0.015000 0.155000 ( 0.155009) | |
Fenix long_path 0.109000 0.000000 0.109000 ( 0.106006) | |
Plain long_path 0.094000 0.000000 0.094000 ( 0.103006) | |
Ruby long_path, 'rel' 0.249000 0.328000 0.577000 ( 0.574033) | |
Fenix long_path, 'rel' 0.110000 0.000000 0.110000 ( 0.113007) | |
Plain long_path, 'rel' 0.124000 0.000000 0.124000 ( 0.109803) | |
Ruby long_path, 'C:/Foo' 0.266000 0.889000 1.155000 ( 1.182464) | |
Fenix long_path, 'C:/Foo' 0.109000 0.000000 0.109000 ( 0.110007) | |
Plain long_path, 'C:/Foo' 0.109000 0.000000 0.109000 ( 0.102006) | |
Ruby full_long_path 0.125000 0.016000 0.141000 ( 0.134007) | |
Fenix full_long_path 0.093000 0.000000 0.093000 ( 0.101006) | |
Plain full_long_path 0.094000 0.000000 0.094000 ( 0.097006) | |
Ruby to_path 0.078000 0.187000 0.265000 ( 0.261015) | |
Fenix to_path 0.031000 0.000000 0.031000 ( 0.025000) | |
Plain to_path 0.031000 0.000000 0.031000 ( 0.038001) | |
Ruby to_path, 'rel' 0.203000 0.468000 0.671000 ( 0.663038) | |
Fenix to_path, 'rel' 0.031000 0.000000 0.031000 ( 0.038002) | |
Plain to_path, 'rel' 0.032000 0.000000 0.032000 ( 0.037002) | |
Ruby to_path, 'C:/Foo' 0.234000 1.061000 1.295000 ( 1.280071) | |
Fenix to_path, 'C:/Foo' 0.031000 0.000000 0.031000 ( 0.031200) | |
Plain to_path, 'C:/Foo' 0.031000 0.000000 0.031000 ( 0.036601) | |
Ruby full_to_path 0.109000 0.905000 1.014000 ( 1.017056) | |
Fenix full_to_path 0.031000 0.000000 0.031000 ( 0.026002) | |
Plain full_to_path 0.016000 0.000000 0.016000 ( 0.022001) | |
--------------------------------------------------- total: 11.544000sec | |
user system total real | |
Ruby '' 0.172000 0.265000 0.437000 ( 0.433025) | |
Fenix '' 0.031000 0.000000 0.031000 ( 0.027002) | |
Plain '' 0.015000 0.000000 0.015000 ( 0.025001) | |
Ruby '.' 0.156000 0.265000 0.421000 ( 0.433025) | |
Fenix '.' 0.031000 0.000000 0.031000 ( 0.025001) | |
Plain '.' 0.016000 0.000000 0.016000 ( 0.020000) | |
Ruby 'foo', 'bar' 0.156000 0.484000 0.640000 ( 0.635834) | |
Fenix 'foo', 'bar' 0.031000 0.000000 0.031000 ( 0.033002) | |
Plain 'foo', 'bar' 0.031000 0.000000 0.031000 ( 0.033002) | |
Ruby '', 'C:/' 0.031000 0.000000 0.031000 ( 0.017001) | |
Fenix '', 'C:/' 0.016000 0.000000 0.016000 ( 0.024001) | |
Plain '', 'C:/' 0.031000 0.000000 0.031000 ( 0.024001) | |
Ruby 'foo', 'C:/' 0.063000 0.951000 1.014000 ( 1.022057) | |
Fenix 'foo', 'C:/' 0.031000 0.000000 0.031000 ( 0.025001) | |
Plain 'foo', 'C:/' 0.031000 0.000000 0.031000 ( 0.025002) | |
Ruby '~' 0.296000 0.265000 0.561000 ( 0.565030) | |
Fenix '~' 0.032000 0.000000 0.032000 ( 0.031002) | |
Plain '~' 0.031000 0.000000 0.031000 ( 0.028001) | |
Ruby '~/foo' 0.265000 0.281000 0.546000 ( 0.545031) | |
Fenix '~/foo' 0.031000 0.000000 0.031000 ( 0.032002) | |
Plain '~/foo' 0.031000 0.000000 0.031000 ( 0.031002) | |
Ruby 'foo/' 0.110000 0.297000 0.407000 ( 0.410821) | |
Fenix 'foo/' 0.031000 0.000000 0.031000 ( 0.027002) | |
Plain 'foo/' 0.031000 0.000000 0.031000 ( 0.027001) | |
Ruby '~', 'C:/Foo' 0.218000 0.358000 0.576000 ( 0.571033) | |
Fenix '~', 'C:/Foo' 0.032000 0.000000 0.032000 ( 0.033001) | |
Plain '~', 'C:/Foo' 0.031000 0.000000 0.031000 ( 0.030001) | |
Ruby long_path 0.156000 0.000000 0.156000 ( 0.160008) | |
Fenix long_path 0.109000 0.000000 0.109000 ( 0.104006) | |
Plain long_path 0.094000 0.000000 0.094000 ( 0.099005) | |
Ruby long_path, 'rel' 0.234000 0.344000 0.578000 ( 0.570032) | |
Fenix long_path, 'rel' 0.109000 0.000000 0.109000 ( 0.111007) | |
Plain long_path, 'rel' 0.093000 0.000000 0.093000 ( 0.107006) | |
Ruby long_path, 'C:/Foo' 0.234000 0.936000 1.170000 ( 1.174064) | |
Fenix long_path, 'C:/Foo' 0.094000 0.000000 0.094000 ( 0.107006) | |
Plain long_path, 'C:/Foo' 0.109000 0.000000 0.109000 ( 0.101006) | |
Ruby full_long_path 0.125000 0.000000 0.125000 ( 0.132007) | |
Fenix full_long_path 0.094000 0.000000 0.094000 ( 0.100006) | |
Plain full_long_path 0.093000 0.000000 0.093000 ( 0.094006) | |
Ruby to_path 0.125000 0.140000 0.265000 ( 0.257014) | |
Fenix to_path 0.031000 0.000000 0.031000 ( 0.033000) | |
Plain to_path 0.032000 0.000000 0.032000 ( 0.030002) | |
Ruby to_path, 'rel' 0.187000 0.468000 0.655000 ( 0.657037) | |
Fenix to_path, 'rel' 0.031000 0.000000 0.031000 ( 0.037003) | |
Plain to_path, 'rel' 0.047000 0.000000 0.047000 ( 0.037002) | |
Ruby to_path, 'C:/Foo' 0.203000 1.061000 1.264000 ( 1.285870) | |
Fenix to_path, 'C:/Foo' 0.046000 0.000000 0.046000 ( 0.034002) | |
Plain to_path, 'C:/Foo' 0.032000 0.000000 0.032000 ( 0.031002) | |
Ruby full_to_path 0.062000 0.936000 0.998000 ( 1.012807) | |
Fenix full_to_path 0.015000 0.000000 0.015000 ( 0.024001) | |
Plain full_to_path 0.031000 0.000000 0.031000 ( 0.021001) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/bench/file_expand_path.rb b/bench/file_expand_path.rb | |
index 47db827..c69f28a 100644 | |
--- a/bench/file_expand_path.rb | |
+++ b/bench/file_expand_path.rb | |
@@ -17,58 +17,76 @@ puts "File.expand_path: #{TESTS} times." | |
Benchmark.bmbm do |results| | |
results.report("Ruby ''") { TESTS.times { File.expand_path('') } } | |
results.report("Fenix ''") { TESTS.times { Fenix::File.expand_path('') } } | |
+ results.report("Plain ''") { TESTS.times { Fenix::File.expand_path_plain('') } } | |
results.report("Ruby '.'") { TESTS.times { File.expand_path('.') } } | |
results.report("Fenix '.'") { TESTS.times { Fenix::File.expand_path('.') } } | |
+ results.report("Plain '.'") { TESTS.times { Fenix::File.expand_path_plain('.') } } | |
results.report("Ruby 'foo', 'bar'") { TESTS.times { File.expand_path('foo', 'bar') } } | |
results.report("Fenix 'foo', 'bar'") { TESTS.times { Fenix::File.expand_path('foo', 'bar') } } | |
+ results.report("Plain 'foo', 'bar'") { TESTS.times { Fenix::File.expand_path_plain('foo', 'bar') } } | |
results.report("Ruby '', 'C:/'") { TESTS.times { File.expand_path('', 'C:/') } } | |
results.report("Fenix '', 'C:/'") { TESTS.times { Fenix::File.expand_path('', 'C:/') } } | |
+ results.report("Plain '', 'C:/'") { TESTS.times { Fenix::File.expand_path_plain('', 'C:/') } } | |
results.report("Ruby 'foo', 'C:/'") { TESTS.times { File.expand_path('foo', 'C:/') } } | |
results.report("Fenix 'foo', 'C:/'") { TESTS.times { Fenix::File.expand_path('foo', 'C:/') } } | |
+ results.report("Plain 'foo', 'C:/'") { TESTS.times { Fenix::File.expand_path_plain('foo', 'C:/') } } | |
# So slow, exclude them | |
if ENV["SLOW"] | |
results.report("Ruby 'D:/Bar', 'C:/Foo'") { TESTS.times { File.expand_path('D:/Bar', 'C:/Foo') } } | |
results.report("Fenix 'D:/Bar', 'C:/Foo'") { TESTS.times { Fenix::File.expand_path('D:/Bar', 'C:/Foo') } } | |
+ results.report("Plain 'D:/Bar', 'C:/Foo'") { TESTS.times { Fenix::File.expand_path_plain('D:/Bar', 'C:/Foo') } } | |
end | |
results.report("Ruby '~'") { TESTS.times { File.expand_path('~') } } | |
results.report("Fenix '~'") { TESTS.times { Fenix::File.expand_path('~') } } | |
+ results.report("Plain '~'") { TESTS.times { Fenix::File.expand_path_plain('~') } } | |
results.report("Ruby '~/foo'") { TESTS.times { File.expand_path('~/foo') } } | |
results.report("Fenix '~/foo'") { TESTS.times { Fenix::File.expand_path('~/foo') } } | |
+ results.report("Plain '~/foo'") { TESTS.times { Fenix::File.expand_path_plain('~/foo') } } | |
results.report("Ruby 'foo/'") { TESTS.times { File.expand_path('foo/') } } | |
results.report("Fenix 'foo/'") { TESTS.times { Fenix::File.expand_path('foo/') } } | |
+ results.report("Plain 'foo/'") { TESTS.times { Fenix::File.expand_path_plain('foo/') } } | |
results.report("Ruby '~', 'C:/Foo'") { TESTS.times { File.expand_path('~', 'C:/Foo') } } | |
results.report("Fenix '~', 'C:/Foo'") { TESTS.times { Fenix::File.expand_path('~', 'C:/Foo') } } | |
+ results.report("Plain '~', 'C:/Foo'") { TESTS.times { Fenix::File.expand_path_plain('~', 'C:/Foo') } } | |
results.report("Ruby long_path") { TESTS.times { File.expand_path(long_path) } } | |
results.report("Fenix long_path") { TESTS.times { Fenix::File.expand_path(long_path) } } | |
+ results.report("Plain long_path") { TESTS.times { Fenix::File.expand_path_plain(long_path) } } | |
results.report("Ruby long_path, 'rel'") { TESTS.times { File.expand_path(long_path, 'rel') } } | |
results.report("Fenix long_path, 'rel'") { TESTS.times { Fenix::File.expand_path(long_path, 'rel') } } | |
+ results.report("Plain long_path, 'rel'") { TESTS.times { Fenix::File.expand_path_plain(long_path, 'rel') } } | |
results.report("Ruby long_path, 'C:/Foo'") { TESTS.times { File.expand_path(long_path, 'C:/Foo') } } | |
results.report("Fenix long_path, 'C:/Foo'") { TESTS.times { Fenix::File.expand_path(long_path, 'C:/Foo') } } | |
+ results.report("Plain long_path, 'C:/Foo'") { TESTS.times { Fenix::File.expand_path_plain(long_path, 'C:/Foo') } } | |
results.report("Ruby full_long_path") { TESTS.times { File.expand_path(full_long_path) } } | |
results.report("Fenix full_long_path") { TESTS.times { Fenix::File.expand_path(full_long_path) } } | |
+ results.report("Plain full_long_path") { TESTS.times { Fenix::File.expand_path_plain(full_long_path) } } | |
results.report("Ruby to_path") { TESTS.times { File.expand_path(to_path) } } | |
results.report("Fenix to_path") { TESTS.times { Fenix::File.expand_path(to_path) } } | |
+ results.report("Plain to_path") { TESTS.times { Fenix::File.expand_path_plain(to_path) } } | |
results.report("Ruby to_path, 'rel'") { TESTS.times { File.expand_path(to_path, 'rel') } } | |
results.report("Fenix to_path, 'rel'") { TESTS.times { Fenix::File.expand_path(to_path, 'rel') } } | |
+ results.report("Plain to_path, 'rel'") { TESTS.times { Fenix::File.expand_path_plain(to_path, 'rel') } } | |
results.report("Ruby to_path, 'C:/Foo'") { TESTS.times { File.expand_path(to_path, 'C:/Foo') } } | |
results.report("Fenix to_path, 'C:/Foo'") { TESTS.times { Fenix::File.expand_path(to_path, 'C:/Foo') } } | |
+ results.report("Plain to_path, 'C:/Foo'") { TESTS.times { Fenix::File.expand_path_plain(to_path, 'C:/Foo') } } | |
results.report("Ruby full_to_path") { TESTS.times { File.expand_path(full_to_path) } } | |
results.report("Fenix full_to_path") { TESTS.times { Fenix::File.expand_path(full_to_path) } } | |
+ results.report("Plain full_to_path") { TESTS.times { Fenix::File.expand_path_plain(full_to_path) } } | |
end | |
diff --git a/ext/fenix/extconf.rb b/ext/fenix/extconf.rb | |
index 17f71cd..a511332 100644 | |
--- a/ext/fenix/extconf.rb | |
+++ b/ext/fenix/extconf.rb | |
@@ -10,6 +10,9 @@ end | |
# define mininum version of Windows (XP SP1) | |
$CFLAGS << " -D_WIN32_WINNT=0x0501" | |
+have_library("shlwapi") | |
+abort "'PathIsRelativeW' is required." unless have_func("PathIsRelativeW", "shlwapi.h") | |
+ | |
have_library("kernel32") | |
NEEDED_FUNCTIONS.each do |f| | |
diff --git a/ext/fenix/fenix.h b/ext/fenix/fenix.h | |
index d19d8e7..0c95427 100644 | |
--- a/ext/fenix/fenix.h | |
+++ b/ext/fenix/fenix.h | |
@@ -2,9 +2,13 @@ | |
#define FENIX_H | |
#include <ruby.h> | |
+#include <ruby/encoding.h> | |
+#include <wchar.h> | |
+#include <shlwapi.h> | |
#include "file.h" | |
#define IS_DIR_SEPARATOR_P(c) (c == L'\\' || c == L'/') | |
+#define IS_DIR_UNC_P(c) (IS_DIR_SEPARATOR_P(c[0]) && IS_DIR_SEPARATOR_P(c[1])) | |
extern VALUE mFenix; | |
diff --git a/ext/fenix/file.c b/ext/fenix/file.c | |
index 616a623..38e881d 100644 | |
--- a/ext/fenix/file.c | |
+++ b/ext/fenix/file.c | |
@@ -94,7 +94,7 @@ fenix_coerce_to_path(VALUE obj) | |
// TODO: can we fail allocating memory? | |
static VALUE | |
-fenix_file_expand_path(int argc, VALUE *argv) | |
+fenix_file_expand_path_plain(int argc, VALUE *argv) | |
{ | |
size_t size = 0, wpath_len = 0, wdir_len = 0, whome_len = 0; | |
size_t buffer_len = 0; | |
@@ -269,6 +269,474 @@ fenix_file_expand_path(int argc, VALUE *argv) | |
return result; | |
} | |
+/* Convert the path from char to wchar with specified code page */ | |
+static inline void | |
+fenix_path_to_wchar(VALUE path, wchar_t **wpath, wchar_t **wpath_pos, size_t *wpath_len, UINT code_page) | |
+{ | |
+ size_t size; | |
+ | |
+ if (NIL_P(path)) | |
+ return; | |
+ | |
+ size = MultiByteToWideChar(code_page, 0, RSTRING_PTR(path), -1, NULL, 0) + 1; | |
+ *wpath = (wchar_t *)malloc(size * sizeof(wchar_t)); | |
+ if (wpath_pos) | |
+ *wpath_pos = *wpath; | |
+ | |
+ MultiByteToWideChar(code_page, 0, RSTRING_PTR(path), -1, *wpath, size); | |
+ *wpath_len = size - 2; // wcslen(*wpath); | |
+} | |
+ | |
+/* Remove trailing invalid ':$DATA' of the path. */ | |
+static inline size_t | |
+fenix_remove_invalid_alternative_data(wchar_t *wfullpath, size_t size) { | |
+ static const wchar_t prime[] = L":$DATA"; | |
+ enum {prime_len = (sizeof(prime) / sizeof(wchar_t)) -1}; | |
+ | |
+ if (size <= prime_len || _wcsnicmp(wfullpath + size - prime_len, prime, prime_len) != 0) | |
+ return size; | |
+ | |
+ // wprintf(L"remove trailng ':$DATA': %s, %s\n", wfullpath, &wfullpath[size - prime_len]); | |
+ /* alias of stream */ | |
+ /* get rid of a bug of x64 VC++ */ | |
+ if (wfullpath[size - (prime_len + 1)] == ':') { | |
+ /* remove trailing '::$DATA' */ | |
+ size -= prime_len + 1; /* prime */ | |
+ wfullpath[size] = L'\0'; | |
+ // wprintf(L"removed trailng '::$DATA': %s\n", wfullpath); | |
+ } else { | |
+ /* remove trailing ':$DATA' of paths like '/aa:a:$DATA' */ | |
+ wchar_t *pos = wfullpath + size - (prime_len + 1); | |
+ while (!IS_DIR_SEPARATOR_P(*pos) && pos != wfullpath) { | |
+ if (*pos == L':') { | |
+ size -= prime_len; /* alternative */ | |
+ wfullpath[size] = L'\0'; | |
+ // wprintf(L"removed trailng ':$DATA': %s\n", wfullpath); | |
+ break; | |
+ } | |
+ pos--; | |
+ } | |
+ } | |
+ return size; | |
+} | |
+ | |
+/* | |
+ Replace the last part of the path to long name. | |
+ We try to avoid to call FindFirstFileW() since it takes long time. | |
+*/ | |
+static inline size_t | |
+fenix_replace_to_long_name(wchar_t **wfullpath, size_t size, int heap) { | |
+ WIN32_FIND_DATAW find_data; | |
+ HANDLE find_handle; | |
+ | |
+ /* | |
+ Skip long name conversion if the path is already long name. | |
+ Short name is 8.3 format. | |
+ http://en.wikipedia.org/wiki/8.3_filename | |
+ This check can be skipped for directory components that have file | |
+ extensions longer than 3 characters, or total lengths longer than | |
+ 12 characters. | |
+ http://msdn.microsoft.com/en-us/library/windows/desktop/aa364980(v=vs.85).aspx | |
+ */ | |
+ size_t const max_short_name_size = 8 + 1 + 3; | |
+ size_t const max_extension_size = 3; | |
+ size_t path_len = 1, extension_len = 0; | |
+ wchar_t *pos = *wfullpath + size - 1; | |
+ while (!IS_DIR_SEPARATOR_P(*pos) && pos != *wfullpath) { | |
+ if (!extension_len && *pos == L'.') { | |
+ extension_len = path_len - 1; | |
+ } | |
+ if (path_len > max_short_name_size || extension_len > max_extension_size) { | |
+ // wprintf(L"skip long name conversion: %s\n", pos); | |
+ return size; | |
+ } | |
+ path_len++; | |
+ pos--; | |
+ } | |
+ | |
+ /* | |
+ Avoid FindFirstFileW over non-existing path. | |
+ GetFileAttributesW is faster to check if path doesn't exists. | |
+ */ | |
+ if (GetFileAttributesW(*wfullpath) == INVALID_FILE_ATTRIBUTES) | |
+ return size; | |
+ | |
+ find_handle = FindFirstFileW(*wfullpath, &find_data); | |
+ if (find_handle != INVALID_HANDLE_VALUE) { | |
+ size_t trail_pos = wcslen(*wfullpath); | |
+ size_t file_len = wcslen(find_data.cFileName); | |
+ | |
+ FindClose(find_handle); | |
+ while (trail_pos > 0) { | |
+ if (IS_DIR_SEPARATOR_P((*wfullpath)[trail_pos])) | |
+ break; | |
+ trail_pos--; | |
+ } | |
+ size = trail_pos + 1 + file_len; | |
+ if ((size + 1) > sizeof(*wfullpath) / sizeof((*wfullpath)[0])) { | |
+ wchar_t *buf = (wchar_t *)malloc((size + 1) * sizeof(wchar_t)); | |
+ wcsncpy(buf, *wfullpath, trail_pos + 1); | |
+ if (heap) | |
+ free(*wfullpath); | |
+ *wfullpath = buf; | |
+ } | |
+ wcsncpy(*wfullpath + trail_pos + 1, find_data.cFileName, file_len + 1); | |
+ } | |
+ return size; | |
+} | |
+ | |
+/* Return system code page. */ | |
+static inline UINT system_code_page() { | |
+ return AreFileApisANSI() ? CP_ACP : CP_OEMCP; | |
+} | |
+ | |
+/* cache 'encoding name' => 'code page' into a hash */ | |
+static VALUE rb_code_page; | |
+ | |
+/* | |
+ Return code page number of the encoding. | |
+ Cache code page into a hash for performance since finding the code page in | |
+ Encoding#names is slow. | |
+*/ | |
+static UINT | |
+fenix_code_page(rb_encoding *enc) | |
+{ | |
+ VALUE code_page_value, name_key; | |
+ VALUE encoding, names_ary = Qundef, name; | |
+ ID names; | |
+ long i; | |
+ | |
+ if (!enc) | |
+ return system_code_page(); | |
+ | |
+ name_key = rb_usascii_str_new2(rb_enc_name(enc)); | |
+ code_page_value = rb_hash_aref(rb_code_page, name_key); | |
+ if (code_page_value != Qnil) { | |
+ // printf("cached code page: %i\n", FIX2INT(code_page_value)); | |
+ if (FIX2INT(code_page_value) == -1) { | |
+ return system_code_page(); | |
+ } else { | |
+ return (UINT)FIX2INT(code_page_value); | |
+ } | |
+ } | |
+ | |
+ encoding = rb_enc_from_encoding(enc); | |
+ if (!NIL_P(encoding)) { | |
+ CONST_ID(names, "names"); | |
+ names_ary = rb_funcall(encoding, names, 0); | |
+ } | |
+ | |
+ if (names_ary != Qundef) { | |
+ for (i = 0; i < RARRAY_LEN(names_ary); i++) { | |
+ name = RARRAY_PTR(names_ary)[i]; | |
+ if (strncmp("CP", RSTRING_PTR(name), 2) == 0) { | |
+ int code_page = atoi(RSTRING_PTR(name) + 2); | |
+ rb_hash_aset(rb_code_page, name_key, INT2FIX(code_page)); | |
+ return (UINT)code_page; | |
+ } | |
+ } | |
+ } | |
+ | |
+ rb_hash_aset(rb_code_page, name_key, INT2FIX(-1)); | |
+ return system_code_page(); | |
+} | |
+ | |
+#define PATH_BUFFER_SIZE MAX_PATH * 2 | |
+ | |
+// TODO: can we fail allocating memory? | |
+static VALUE | |
+fenix_file_expand_path(int argc, VALUE *argv) | |
+{ | |
+ size_t size = 0, wpath_len = 0, wdir_len = 0, whome_len = 0; | |
+ size_t buffer_len = 0; | |
+ char *fullpath = NULL; | |
+ wchar_t *wfullpath = NULL, *wpath = NULL, *wpath_pos = NULL, *wdir = NULL; | |
+ wchar_t *whome = NULL, *buffer = NULL, *buffer_pos = NULL; | |
+ UINT cp; | |
+ VALUE result = Qnil, path = Qnil, dir = Qnil; | |
+ wchar_t wfullpath_buffer[PATH_BUFFER_SIZE]; | |
+ wchar_t path_drive = L'\0', dir_drive = L'\0'; | |
+ int ignore_dir = 0; | |
+ rb_encoding *path_encoding; | |
+ | |
+ // 1: convert to long name | |
+ // 0: not convert to long name | |
+ int to_long_name = 0; | |
+ | |
+ VALUE to_long = Qnil; | |
+ | |
+ // retrieve path and dir from argv | |
+ rb_scan_args(argc, argv, "12", &path, &dir, &to_long); | |
+ | |
+ // convert to_long to int | |
+ if (!NIL_P(to_long)) | |
+ to_long_name = FIX2INT(to_long); | |
+ | |
+ // get path encoding | |
+ if (NIL_P(dir)) { | |
+ path_encoding = rb_enc_get(path); | |
+ } else { | |
+ path_encoding = rb_enc_check(path, dir); | |
+ } | |
+ cp = fenix_code_page(path_encoding); | |
+ // printf("code page: %i\n", cp); | |
+ | |
+ // coerce them to string | |
+ path = fenix_coerce_to_path(path); | |
+ | |
+ // convert char * to wchar_t | |
+ // path | |
+ fenix_path_to_wchar(path, &wpath, &wpath_pos, &wpath_len, cp); | |
+ // wprintf(L"wpath: '%s' with (%i) characters long.\n", wpath, wpath_len); | |
+ | |
+ /* determine if we need the user's home directory */ | |
+ if ((wpath_len == 1 && wpath_pos[0] == L'~') || | |
+ (wpath_len >= 2 && wpath_pos[0] == L'~' && IS_DIR_SEPARATOR_P(wpath_pos[1]))) { | |
+ // wprintf(L"wpath requires expansion.\n"); | |
+ whome = fenix_home_dir(); | |
+ if (whome == NULL) { | |
+ free(wpath); | |
+ rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'"); | |
+ } | |
+ if (PathIsRelativeW(whome)) { | |
+ free(wpath); | |
+ rb_raise(rb_eArgError, "non-absolute home"); | |
+ } | |
+ whome_len = wcslen(whome); | |
+ | |
+ if (wpath_len == 1) | |
+ to_long_name = 0; | |
+ | |
+ // wprintf(L"whome: '%s' with (%i) characters long.\n", whome, whome_len); | |
+ | |
+ /* ignores dir since we are expading home */ | |
+ ignore_dir = 1; | |
+ | |
+ /* exclude ~ from the result */ | |
+ wpath_pos++; | |
+ wpath_len--; | |
+ | |
+ /* exclude separator if present */ | |
+ if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) { | |
+ // wprintf(L"excluding expansion character and separator\n"); | |
+ wpath_pos++; | |
+ wpath_len--; | |
+ } | |
+ } else if (wpath_len >= 2 && wpath_pos[1] == L':') { | |
+ if (wpath_len >= 3 && IS_DIR_SEPARATOR_P(wpath_pos[2])) { | |
+ /* ignore dir since path contains a drive letter and a root slash */ | |
+ // wprintf(L"Ignore dir since we have drive letter and root slash\n"); | |
+ ignore_dir = 1; | |
+ } else { | |
+ /* determine if we ignore dir or not later */ | |
+ path_drive = wpath_pos[0]; | |
+ } | |
+ } else if (wpath_len >= 2 && wpath_pos[0] == L'~') { | |
+ wchar_t *wuser = wpath_pos + 1; | |
+ wchar_t *pos = wuser; | |
+ char *user; | |
+ | |
+ while (!IS_DIR_SEPARATOR_P(*pos) && *pos != '\0') | |
+ pos++; | |
+ | |
+ *pos = '\0'; | |
+ size = WideCharToMultiByte(cp, 0, wuser, -1, NULL, 0, NULL, NULL); | |
+ user = (char *)malloc(size * sizeof(char)); | |
+ WideCharToMultiByte(cp, 0, wuser, -1, user, size, NULL, NULL); | |
+ | |
+ /* convert to VALUE and set the path encoding */ | |
+ result = rb_enc_str_new(user, size - 1, path_encoding); | |
+ | |
+ free(wpath); | |
+ if (user) | |
+ free(user); | |
+ | |
+ rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result)); | |
+ } | |
+ | |
+ /* convert dir */ | |
+ if (!ignore_dir && !NIL_P(dir)) { | |
+ // coerce them to string | |
+ dir = fenix_coerce_to_path(dir); | |
+ | |
+ // convert char * to wchar_t | |
+ // dir | |
+ fenix_path_to_wchar(dir, &wdir, NULL, &wdir_len, cp); | |
+ // wprintf(L"wdir: '%s' with (%i) characters long.\n", wdir, wdir_len); | |
+ | |
+ if (wdir_len >= 2 && wdir[1] == L':') { | |
+ dir_drive = wdir[0]; | |
+ if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) { | |
+ wdir_len = 2; | |
+ } | |
+ } else if (wdir_len >= 2 && IS_DIR_UNC_P(wdir)) { | |
+ /* UNC path */ | |
+ if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) { | |
+ /* cut the UNC path tail to '//host/share' */ | |
+ size_t separators = 0; | |
+ size_t pos = 2; | |
+ while (pos < wdir_len && separators < 2) { | |
+ if (IS_DIR_SEPARATOR_P(wdir[pos])) { | |
+ separators++; | |
+ } | |
+ pos++; | |
+ } | |
+ if (separators == 2) | |
+ wdir_len = pos - 1; | |
+ // wprintf(L"UNC wdir: '%s' with (%i) characters.\n", wdir, wdir_len); | |
+ } | |
+ } | |
+ } | |
+ | |
+ /* determine if we ignore dir or not */ | |
+ if (!ignore_dir && path_drive && dir_drive) { | |
+ if (towupper(path_drive) == towupper(dir_drive)) { | |
+ /* exclude path drive letter to use dir */ | |
+ // wprintf(L"excluding path drive letter\n"); | |
+ wpath_pos += 2; | |
+ wpath_len -= 2; | |
+ } else { | |
+ /* ignore dir since path drive is different from dir drive */ | |
+ ignore_dir = 1; | |
+ wdir_len = 0; | |
+ } | |
+ } | |
+ | |
+ // wprintf(L"wpath_len: %i\n", wpath_len); | |
+ // wprintf(L"wdir_len: %i\n", wdir_len); | |
+ // wprintf(L"whome_len: %i\n", whome_len); | |
+ | |
+ buffer_len = wpath_len + 1 + wdir_len + 1 + whome_len + 1; | |
+ // wprintf(L"buffer_len: %i\n", buffer_len + 1); | |
+ | |
+ buffer = buffer_pos = (wchar_t *)malloc((buffer_len + 1) * sizeof(wchar_t)); | |
+ | |
+ /* add home */ | |
+ if (whome_len) { | |
+ // wprintf(L"Copying whome...\n"); | |
+ wcsncpy(buffer_pos, whome, whome_len); | |
+ buffer_pos += whome_len; | |
+ } | |
+ | |
+ /* Add separator if required */ | |
+ if (whome_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) { | |
+ // wprintf(L"Adding separator after whome\n"); | |
+ buffer_pos[0] = L'\\'; | |
+ buffer_pos++; | |
+ } | |
+ | |
+ if (wdir_len) { | |
+ // wprintf(L"Copying wdir...\n"); | |
+ wcsncpy(buffer_pos, wdir, wdir_len); | |
+ buffer_pos += wdir_len; | |
+ } | |
+ | |
+ /* add separator if required */ | |
+ if (wdir_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) { | |
+ // wprintf(L"Adding separator after wdir\n"); | |
+ buffer_pos[0] = L'\\'; | |
+ buffer_pos++; | |
+ } | |
+ | |
+ /* now deal with path */ | |
+ if (wpath_len) { | |
+ // wprintf(L"Copying wpath...\n"); | |
+ wcsncpy(buffer_pos, wpath_pos, wpath_len); | |
+ buffer_pos += wpath_len; | |
+ } | |
+ | |
+ if ((wpath_len == 1 && buffer[0] == L'.') || (wpath_len == 2 && buffer[1] == L':')) | |
+ to_long_name = 0; | |
+ | |
+ /* GetFullPathNameW requires at least "." to determine current directory */ | |
+ if (wpath_len == 0) { | |
+ // wprintf(L"Adding '.' to buffer\n"); | |
+ buffer_pos[0] = L'.'; | |
+ buffer_pos++; | |
+ to_long_name = 0; | |
+ } | |
+ | |
+ /* Ensure buffer is NULL terminated */ | |
+ buffer_pos[0] = L'\0'; | |
+ | |
+ // wprintf(L"buffer: '%s'\n", buffer); | |
+ | |
+ // FIXME: Make this more robust | |
+ // Determine require buffer size | |
+ size = GetFullPathNameW(buffer, PATH_BUFFER_SIZE, wfullpath_buffer, NULL); | |
+ if (size) { | |
+ if (size > PATH_BUFFER_SIZE) { | |
+ // allocate enough memory to contain the response | |
+ wfullpath = (wchar_t *)malloc(size * sizeof(wchar_t)); | |
+ size = GetFullPathNameW(buffer, size, wfullpath, NULL); | |
+ } else { | |
+ wfullpath = wfullpath_buffer; | |
+ } | |
+ | |
+ | |
+ /* Calculate the new size and leave the garbage out */ | |
+ // size = wcslen(wfullpath); | |
+ | |
+ /* Remove any trailing slashes */ | |
+ if (IS_DIR_SEPARATOR_P(wfullpath[size - 1]) && wfullpath[size - 2] != L':') { | |
+ // wprintf(L"Removing trailing slash\n"); | |
+ size -= 1; | |
+ wfullpath[size] = L'\0'; | |
+ } | |
+ | |
+ /* Remove any trailing dot */ | |
+ if (wfullpath[size - 1] == L'.') { | |
+ // wprintf(L"Removing trailing dot\n"); | |
+ size -= 1; | |
+ wfullpath[size] = L'\0'; | |
+ } | |
+ | |
+ /* removes trailing invalid ':$DATA' */ | |
+ size = fenix_remove_invalid_alternative_data(wfullpath, size); | |
+ | |
+ /* Replace the trailing path to long name */ | |
+ if (to_long_name) | |
+ size = fenix_replace_to_long_name(&wfullpath, size, (wfullpath != wfullpath_buffer)); | |
+ | |
+ | |
+ // sanitize backslashes with forwardslashes | |
+ fenix_replace_wchar(wfullpath, L'\\', L'/'); | |
+ // wprintf(L"wfullpath: '%s'\n", wfullpath); | |
+ | |
+ // What CodePage should we use? | |
+ // cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP; | |
+ | |
+ // convert to char * | |
+ size = WideCharToMultiByte(cp, 0, wfullpath, -1, NULL, 0, NULL, NULL); | |
+ fullpath = (char *)malloc(size * sizeof(char)); | |
+ WideCharToMultiByte(cp, 0, wfullpath, -1, fullpath, size, NULL, NULL); | |
+ | |
+ /* convert to VALUE and set the path encoding */ | |
+ result = rb_enc_str_new(fullpath, size - 1, path_encoding); | |
+ } | |
+ | |
+ // TODO: better cleanup | |
+ if (buffer) | |
+ free(buffer); | |
+ | |
+ if (wpath) | |
+ free(wpath); | |
+ | |
+ if (wdir) | |
+ free(wdir); | |
+ | |
+ if (whome) | |
+ free(whome); | |
+ | |
+ if (wfullpath && wfullpath != wfullpath_buffer) | |
+ free(wfullpath); | |
+ | |
+ if (fullpath) | |
+ free(fullpath); | |
+ | |
+ return result; | |
+} | |
+ | |
static VALUE | |
fenix_file_replace() | |
{ | |
@@ -284,4 +752,10 @@ void Init_fenix_file() | |
rb_define_singleton_method(cFenixFile, "replace!", fenix_file_replace, 0); | |
rb_define_singleton_method(cFenixFile, "expand_path", fenix_file_expand_path, -1); | |
+ rb_define_singleton_method(cFenixFile, "expand_path_plain", fenix_file_expand_path_plain, -1); | |
+ | |
+ rb_code_page = rb_hash_new(); | |
+ | |
+ /* prevent GC removing rb_code_page */ | |
+ rb_gc_register_mark_object(rb_code_page); | |
} | |
diff --git a/spec/fenix/file_spec.rb b/spec/fenix/file_spec.rb | |
index 3184a14..72ef406 100644 | |
--- a/spec/fenix/file_spec.rb | |
+++ b/spec/fenix/file_spec.rb | |
@@ -1,10 +1,22 @@ | |
require "spec_helper" | |
describe Fenix::File do | |
+# subject { File } | |
subject { Fenix::File } | |
let(:base) { Dir.pwd } | |
let(:tmpdir) { "C:/Temporary" } | |
let(:rootdir) { "C:/" } | |
+ let(:drive) { Dir.pwd[%r'\A(?:[a-z]:|//[^/]+/[^/]+)'i] } | |
+ let(:os_version) do | |
+ require 'win32ole' | |
+ locator = WIN32OLE.new("WbemScripting.SWbemLocator") | |
+ server = locator.ConnectServer(".","root/cimv2") | |
+ version = nil | |
+ server.ExecQuery("select * from Win32_OperatingSystem").each do |os| | |
+ version = os.Version | |
+ end | |
+ version | |
+ end | |
describe "expand_path" do | |
it "converts an empty pathname into absolute current pathname" do | |
@@ -34,6 +46,7 @@ describe Fenix::File do | |
# this spec is not valid, a.. is not a valid file or directory name so | |
# b can't be inside of it | |
+ skip "XP doesn't pass the following. Result is '#{base}/a./b'" if os_version =~ /^5\.1/ | |
subject.expand_path('a../b').must_equal File.join(base, 'a../b') | |
end | |
@@ -59,16 +72,70 @@ describe Fenix::File do | |
subject.expand_path("#{rootdir}/foo.rb/").must_equal File.join(rootdir, "foo.rb") | |
end | |
+ it "removes trailing spaces from absolute path" do | |
+ subject.expand_path("#{rootdir}/a ").must_equal File.join(rootdir, "a") | |
+ end | |
+ | |
+ it "removes trailing dots from absolute path" do | |
+ subject.expand_path("#{rootdir}/a.").must_equal File.join(rootdir, "a") | |
+ end | |
+ | |
+ it "removes trailing invalid ':$DATA' from absolute path" do | |
+ subject.expand_path("#{rootdir}/aaa::$DATA").must_equal File.join(rootdir, "aaa") | |
+ subject.expand_path("#{rootdir}/aa:a:$DATA").must_equal File.join(rootdir, "aa:a") | |
+ subject.expand_path("#{rootdir}/aaa:$DATA").must_equal File.join(rootdir, "aaa:$DATA") | |
+ end | |
+ | |
+ it "converts a pathname with a drive letter but no slash [ruby-core:31591]" do | |
+ subject.expand_path('c:').must_match /\Ac:\//i | |
+ end | |
+ | |
+ it "converts a pathname with a drive letter ignoring different drive dir [ruby-core:42177]" do | |
+ subject.expand_path('c:foo', 'd:/bar').must_match /\Ac:\//i | |
+ end | |
+ | |
+ it "converts a pathname with a drive letter using same drive dir [ruby-core:42177]" do | |
+ subject.expand_path('c:foo', 'c:/bar').must_match %r'\Ac:/bar/foo\z'i | |
+ end | |
+ | |
+ it "converts a pathname which starts with a slash using dir's drive" do | |
+ subject.expand_path('/foo', "z:/bar").must_match %r"\Az:/foo\z"i | |
+ end | |
+ | |
+ it "converts a dot with UNC dir" do | |
+ subject.expand_path('.', "//").must_equal "//" | |
+ end | |
+ | |
+ it "converts a pathname which starts with a slash using '//host/share'" do | |
+ subject.expand_path('/foo', "//host/share/bar").must_match %r"\A//host/share/foo\z"i | |
+ end | |
+ | |
+ it "converts a pathname which starts with a slash using a current drive" do | |
+ subject.expand_path('/foo').must_match %r"\A#{drive}/foo\z"i | |
+ end | |
+ | |
describe "~/" do | |
let(:home) { "C:/UserHome" } | |
+ let(:home_drive) { nil } | |
+ let(:home_path) { nil } | |
+ let(:user_profile) { nil } | |
before :each do | |
@old_home = ENV["HOME"] | |
+ @old_home_drive = ENV["HOMEDRIVE"] | |
+ @old_home_path = ENV["HOMEPATH"] | |
+ @old_user_profile = ENV["USERPROFILE"] | |
ENV["HOME"] = home | |
+ ENV["HOMEDRIVE"] = home_drive | |
+ ENV["HOMEPATH"] = home_path | |
+ ENV["USERPROFILE"] = user_profile | |
end | |
after :each do | |
ENV["HOME"] = @old_home if @old_home | |
+ ENV["HOMEDRIVE"] = @old_home_drive if @old_home_drive | |
+ ENV["HOMEPATH"] = @old_home_path if @old_home_path | |
+ ENV["USERPROFILE"] = @old_user_profile if @old_user_profile | |
end | |
it "converts a pathname to an absolute pathname, using ~ (home) as base" do | |
@@ -83,16 +150,25 @@ describe Fenix::File do | |
str.must_equal "~/a" | |
end | |
+ describe "(nil)" do | |
+ let(:home) { nil } | |
+ let(:home_drive) { nil } | |
+ let(:home_path) { nil } | |
+ let(:user_profile) { nil } | |
+ | |
+ it "raises ArgumentError when home is nothing" do | |
+ proc { subject.expand_path("~") }.must_raise ArgumentError | |
+ end | |
+ end | |
+ | |
describe "(non-absolute)" do | |
let(:home) { "." } | |
it "raises ArgumentError when having non-absolute home directories" do | |
- skip "implement me" | |
proc { subject.expand_path("~") }.must_raise ArgumentError | |
end | |
it "raises ArgumentError when having non-absolute home of a specified user" do | |
- skip "implement me" | |
proc { subject.expand_path("~anything") }.must_raise ArgumentError | |
end | |
end | |
@@ -100,7 +176,6 @@ describe Fenix::File do | |
describe "~username" do | |
it "raises ArgumentError for any supplied username [ruby-core:39597]" do | |
- skip "implement me" | |
proc { subject.expand_path("~anything") }.must_raise ArgumentError | |
end | |
end | |
@@ -151,8 +226,33 @@ describe Fenix::File do | |
end | |
it "expands a shortname directory into the full version [ruby-core:39504]" do | |
- skip "implement me" | |
- subject.expand_path(@shortname).must_include long_name | |
+ if subject == Fenix::File | |
+ subject.expand_path(@shortname, nil, 1).must_include long_name | |
+ else | |
+ subject.expand_path(@shortname).must_include long_name | |
+ end | |
+ end | |
+ end | |
+ | |
+ describe "encoding" do | |
+ it "expands using path encoding not file system encoding" do | |
+ if Encoding.find("filesystem") == Encoding::CP1251 | |
+ a = "#{drive}/\u3042\u3044\u3046\u3048\u304a".encode("cp932") | |
+ else | |
+ a = "#{drive}/\u043f\u0440\u0438\u0432\u0435\u0442".encode("cp1251") | |
+ end | |
+ subject.expand_path(a).must_equal a | |
+ end | |
+ | |
+ it "removes trailing backslashes unless it's not in multibyte characters" do | |
+ a = "#{drive}/\225\\\\" | |
+ if File::ALT_SEPARATOR == '\\' | |
+ [%W"cp437 #{drive}/\225", %W"cp932 #{drive}/\225\\"] | |
+ else | |
+ [["cp437", a], ["cp932", a]] | |
+ end.each do |cp, expected| | |
+ subject.expand_path(a.dup.force_encoding(cp)).must_equal expected.force_encoding(cp), cp | |
+ end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment