faster_path 0.3.8 → 0.3.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Cargo.lock +9 -9
- data/README.md +17 -17
- data/Rakefile +17 -47
- data/lib/faster_path.rb +23 -0
- data/lib/faster_path/optional/monkeypatches.rb +23 -2
- data/lib/faster_path/optional/refinements.rb +20 -0
- data/lib/faster_path/thermite_initialize.rb +5 -0
- data/lib/faster_path/version.rb +1 -1
- data/src/basename.rs +82 -8
- data/src/helpers.rs +8 -5
- data/src/path_parsing.rs +0 -6
- data/src/relative_path_from.rs +35 -57
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a5d299440e18a99c763e17b085b7962bfca0f2555b0adf8eb053c77b2d8d282
|
4
|
+
data.tar.gz: fee3ac374b164a25d1af43e0e8cd36ea68f57421db38637b7275a504e38bb391
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79d7b3931800982e78cc7f00c2fd2281932a2ac3775784f5f9d5c59bf974cd41f30d2d03c6216ce210fdc1754659b714cda6c19cca84e39a464e2bb62f7afa9c
|
7
|
+
data.tar.gz: 1a5b56dff703996bdcf60838ad9881528e51867aa2e9c5d996ff9c28996fb1297e7dacc9380a42def9ff9358e87ac4576a2f7536d5c73b685332b73b9e687122
|
data/Cargo.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
[[package]]
|
2
2
|
name = "array_tool"
|
3
|
-
version = "1.0.
|
3
|
+
version = "1.0.3"
|
4
4
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
5
5
|
|
6
6
|
[[package]]
|
7
7
|
name = "faster_path"
|
8
8
|
version = "0.0.1"
|
9
9
|
dependencies = [
|
10
|
-
"array_tool 1.0.
|
10
|
+
"array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
11
11
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
12
12
|
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
13
13
|
"ruby-sys 0.3.0 (git+https://github.com/danielpclark/ruby-sys?branch=playground)",
|
@@ -26,7 +26,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
26
26
|
|
27
27
|
[[package]]
|
28
28
|
name = "libc"
|
29
|
-
version = "0.2.
|
29
|
+
version = "0.2.39"
|
30
30
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
31
31
|
|
32
32
|
[[package]]
|
@@ -34,31 +34,31 @@ name = "memchr"
|
|
34
34
|
version = "2.0.1"
|
35
35
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
36
36
|
dependencies = [
|
37
|
-
"libc 0.2.
|
37
|
+
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
38
38
|
]
|
39
39
|
|
40
40
|
[[package]]
|
41
41
|
name = "ruby-sys"
|
42
42
|
version = "0.3.0"
|
43
|
-
source = "git+https://github.com/danielpclark/ruby-sys?branch=playground#
|
43
|
+
source = "git+https://github.com/danielpclark/ruby-sys?branch=playground#a3d47da5f9d1e597c62a8f03fb7d3a3596393c47"
|
44
44
|
dependencies = [
|
45
|
-
"libc 0.2.
|
45
|
+
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
46
46
|
]
|
47
47
|
|
48
48
|
[[package]]
|
49
49
|
name = "ruru"
|
50
50
|
version = "0.9.3"
|
51
|
-
source = "git+https://github.com/danielpclark/ruru?branch=playground#
|
51
|
+
source = "git+https://github.com/danielpclark/ruru?branch=playground#ab84ad4b97c41bfe6fd6d0f8540b2efd77583561"
|
52
52
|
dependencies = [
|
53
53
|
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
54
54
|
"ruby-sys 0.3.0 (git+https://github.com/danielpclark/ruby-sys?branch=playground)",
|
55
55
|
]
|
56
56
|
|
57
57
|
[metadata]
|
58
|
-
"checksum array_tool 1.0.
|
58
|
+
"checksum array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
|
59
59
|
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
60
60
|
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
61
|
-
"checksum libc 0.2.
|
61
|
+
"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
|
62
62
|
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
|
63
63
|
"checksum ruby-sys 0.3.0 (git+https://github.com/danielpclark/ruby-sys?branch=playground)" = "<none>"
|
64
64
|
"checksum ruru 0.9.3 (git+https://github.com/danielpclark/ruru?branch=playground)" = "<none>"
|
data/README.md
CHANGED
@@ -140,23 +140,23 @@ Current methods implemented:
|
|
140
140
|
|
141
141
|
|FasterPath Rust Implementation|Ruby 2.5.0 Implementation|Time Shaved Off|
|
142
142
|
|---|---|:---:|
|
143
|
-
| `FasterPath.absolute?` | `Pathname#absolute?` | 95.
|
144
|
-
| `FasterPath.add_trailing_separator` | `Pathname#add_trailing_separator` |
|
145
|
-
| `FasterPath.basename` | `File.basename` |
|
146
|
-
| `FasterPath.children` | `Pathname#children` |
|
147
|
-
| `FasterPath.chop_basename` | `Pathname#chop_basename` |
|
148
|
-
| `FasterPath.cleanpath_aggressive` | `Pathname#cleanpath_aggressive` |
|
149
|
-
| `FasterPath.cleanpath_conservative` | `Pathname#cleanpath_conservative` |
|
150
|
-
| `FasterPath.del_trailing_separator` | `Pathname#del_trailing_separator` |
|
151
|
-
| `FasterPath.directory?` | `Pathname#directory?` |
|
152
|
-
| `FasterPath.dirname` | `File.dirname` |
|
153
|
-
| `FasterPath.entries` | `Pathname#entries` |
|
154
|
-
| `FasterPath.extname` | `File.extname` |
|
155
|
-
| `FasterPath.has_trailing_separator?` | `Pathname#has_trailing_separator` |
|
156
|
-
| `FasterPath.plus` | `Pathname#join` |
|
157
|
-
| `FasterPath.plus` | `Pathname#plus` |
|
158
|
-
| `FasterPath.relative?` | `Pathname#relative?` |
|
159
|
-
| `FasterPath.relative_path_from` | `Pathname#relative_path_from` |
|
143
|
+
| `FasterPath.absolute?` | `Pathname#absolute?` | 95.3% |
|
144
|
+
| `FasterPath.add_trailing_separator` | `Pathname#add_trailing_separator` | 48.4% |
|
145
|
+
| `FasterPath.basename` | `File.basename` | 12.0% |
|
146
|
+
| `FasterPath.children` | `Pathname#children` | 34.4% |
|
147
|
+
| `FasterPath.chop_basename` | `Pathname#chop_basename` | 83.4% |
|
148
|
+
| `FasterPath.cleanpath_aggressive` | `Pathname#cleanpath_aggressive` | 94.1% |
|
149
|
+
| `FasterPath.cleanpath_conservative` | `Pathname#cleanpath_conservative` | 93.5% |
|
150
|
+
| `FasterPath.del_trailing_separator` | `Pathname#del_trailing_separator` | 85.4% |
|
151
|
+
| `FasterPath.directory?` | `Pathname#directory?` | 6.4% |
|
152
|
+
| `FasterPath.dirname` | `File.dirname` | 55.4% |
|
153
|
+
| `FasterPath.entries` | `Pathname#entries` | 41.0% |
|
154
|
+
| `FasterPath.extname` | `File.extname` | 63.1% |
|
155
|
+
| `FasterPath.has_trailing_separator?` | `Pathname#has_trailing_separator` | 88.9% |
|
156
|
+
| `FasterPath.plus` | `Pathname#join` | 72.0% |
|
157
|
+
| `FasterPath.plus` | `Pathname#plus` | 87.7% |
|
158
|
+
| `FasterPath.relative?` | `Pathname#relative?` | 92.6% |
|
159
|
+
| `FasterPath.relative_path_from` | `Pathname#relative_path_from` | 93.3% |
|
160
160
|
|
161
161
|
You may choose to use the methods directly, or scope change to rewrite behavior on the
|
162
162
|
standard library with the included refinements, or even call a method to monkeypatch
|
data/Rakefile
CHANGED
@@ -5,24 +5,21 @@ require 'faster_path/thermite_initialize'
|
|
5
5
|
|
6
6
|
desc 'System Details'
|
7
7
|
task :sysinfo do
|
8
|
-
puts "faster_path #{FasterPath::VERSION}"
|
9
|
-
puts
|
8
|
+
puts "** FasterPath - faster_path v#{FasterPath::VERSION} **"
|
9
|
+
puts RUBY_DESCRIPTION
|
10
10
|
puts `rustc -Vv`
|
11
|
+
puts `ldd --version`.scan(/(.*)\n/).first if RbConfig::CONFIG["host_os"].to_s[/linux/]
|
11
12
|
puts `cargo -Vv`
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
puts "
|
19
|
-
|
20
|
-
puts "
|
21
|
-
|
22
|
-
puts "%s\t%s" % IO.read('Gemfile.lock').match(/(mspec) \(([\d\.]+)\)/).captures
|
23
|
-
rescue Errno::ENOENT => _
|
24
|
-
puts "\nNo Gemfile.lock"
|
25
|
-
end
|
13
|
+
deps = Regexp.new(/name = "([\w\-]+)"\nversion = "(\d+\.\d+\.\d+)"/)
|
14
|
+
puts "** Rust dependencies **"
|
15
|
+
IO.read("Cargo.lock").
|
16
|
+
scan(deps).
|
17
|
+
delete_if {|i| i[0] == "faster_path" }.
|
18
|
+
each {|name, version| puts "#{name.ljust(20)}#{version}"}
|
19
|
+
puts "** Ruby dependencies **"
|
20
|
+
deps = IO.read("Gemfile.lock")
|
21
|
+
puts deps[(deps =~ /DEPENDENCIES/)..-1].sub("\n\n", "\n")
|
22
|
+
puts "RAKE\n #{Rake::VERSION}"
|
26
23
|
end
|
27
24
|
|
28
25
|
thermite = Thermite::Tasks.new
|
@@ -34,36 +31,6 @@ task :contrib do
|
|
34
31
|
' > Contributors.md;git shortlog -s -n -e | sed 's/^......./- /' >> Contributors.md"
|
35
32
|
end
|
36
33
|
|
37
|
-
desc "Add libruby to deps"
|
38
|
-
task :libruby_release do
|
39
|
-
filename = RbConfig::CONFIG["LIBRUBY_ALIASES"].split(" ").first
|
40
|
-
libfile = File.join(RbConfig::CONFIG["libdir"], filename)
|
41
|
-
deps = "target/release/deps"
|
42
|
-
|
43
|
-
printf "Copying libruby.so ... "
|
44
|
-
unless File.exist? "#{deps}/#{filename}"
|
45
|
-
FileUtils.mkdir_p deps
|
46
|
-
FileUtils.cp libfile, deps
|
47
|
-
end
|
48
|
-
exit 1 unless File.exist? "#{deps}/#{filename}"
|
49
|
-
puts "libruby.so copied."
|
50
|
-
end
|
51
|
-
|
52
|
-
desc "Add libruby to debug deps"
|
53
|
-
task :libruby_debug do
|
54
|
-
filename = RbConfig::CONFIG["LIBRUBY_ALIASES"].split(" ").first
|
55
|
-
libfile = File.join(RbConfig::CONFIG["libdir"], filename)
|
56
|
-
deps = "target/debug/deps"
|
57
|
-
|
58
|
-
printf "Copying libruby.so ... "
|
59
|
-
unless File.exist? "#{deps}/#{filename}"
|
60
|
-
FileUtils.mkdir_p deps
|
61
|
-
FileUtils.cp libfile, deps
|
62
|
-
end
|
63
|
-
exit 1 unless File.exist? "#{deps}/#{filename}"
|
64
|
-
puts "libruby.so copied."
|
65
|
-
end
|
66
|
-
|
67
34
|
desc 'Build + clean up Rust extension'
|
68
35
|
task build_lib: 'thermite:build' do
|
69
36
|
thermite.run_cargo 'clean'
|
@@ -78,7 +45,7 @@ task :lint do
|
|
78
45
|
end
|
79
46
|
|
80
47
|
desc "Run Rust Tests"
|
81
|
-
task cargo
|
48
|
+
task :cargo do
|
82
49
|
sh "cargo test -- --nocapture"
|
83
50
|
end
|
84
51
|
|
@@ -117,6 +84,9 @@ Rake::TestTask.new(bench: :build_lib) do |t|
|
|
117
84
|
end
|
118
85
|
|
119
86
|
Rake::TestTask.new(pbench: :build_lib) do |t|
|
87
|
+
if ARGV.last == '--long-run'
|
88
|
+
ENV['LONG_RUN'] = '10'
|
89
|
+
end
|
120
90
|
t.libs = %w[lib test test/pbench]
|
121
91
|
t.pattern = 'test/pbench/pbench_suite.rb'
|
122
92
|
end
|
data/lib/faster_path.rb
CHANGED
@@ -5,6 +5,9 @@ require 'faster_path/thermite_initialize'
|
|
5
5
|
require 'fiddle'
|
6
6
|
require 'fiddle/import'
|
7
7
|
|
8
|
+
# FasterPath module behaves as a singleton object with the alternative method
|
9
|
+
# implementations for Pathname, and some for File, available directly on it.
|
10
|
+
#
|
8
11
|
module FasterPath
|
9
12
|
FFI_LIBRARY = begin
|
10
13
|
toplevel_dir = File.dirname(__dir__)
|
@@ -23,30 +26,50 @@ module FasterPath
|
|
23
26
|
private_class_method :children_compat
|
24
27
|
end
|
25
28
|
|
29
|
+
# The Rust architecture bit width: 64bits or 32bits
|
30
|
+
# @return [Integer]
|
26
31
|
def self.rust_arch_bits
|
27
32
|
Rust.rust_arch_bits
|
28
33
|
end
|
29
34
|
|
35
|
+
# The Ruby architecture bit width: 64bits or 32bits
|
36
|
+
# @return [Integer]
|
30
37
|
def self.ruby_arch_bits
|
31
38
|
1.size * 8
|
32
39
|
end
|
33
40
|
|
41
|
+
# A very fast way to check if a string is blank
|
42
|
+
# @param str [#to_s]
|
43
|
+
# @return [true, false]
|
34
44
|
def self.blank?(str)
|
35
45
|
"#{str}".strip.empty?
|
36
46
|
end
|
37
47
|
|
48
|
+
# Rust implementation of File.basename
|
49
|
+
# @param pth [String] the path to evaluate
|
50
|
+
# @param ext [String] any extension to remove
|
51
|
+
# @return [String]
|
38
52
|
def self.basename(pth, ext="")
|
39
53
|
Public.send(:basename, pth, ext)
|
40
54
|
end
|
41
55
|
|
56
|
+
# Rust implementation of Pathname.children
|
57
|
+
# @param pth [String] the path to evaluate
|
58
|
+
# @param with_directory [true, false] whether to include directory in results
|
59
|
+
# @return [Array<String>]
|
42
60
|
def self.children(pth, with_directory=true)
|
43
61
|
Public.send(:children, pth, with_directory)
|
44
62
|
end
|
45
63
|
|
64
|
+
# Rust implementation of Pathname.children
|
65
|
+
# @param pth [String] the path to evaluate
|
66
|
+
# @param with_directory [true, false] whether to include directory in results
|
67
|
+
# @return [Array<Pathname>]
|
46
68
|
def self.children_compat(pth, with_directory=true)
|
47
69
|
Public.send(:children_compat, pth, with_directory)
|
48
70
|
end
|
49
71
|
|
72
|
+
# @private
|
50
73
|
module Rust
|
51
74
|
extend Fiddle::Importer
|
52
75
|
dlload FFI_LIBRARY
|
@@ -1,23 +1,29 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
|
3
|
+
# :nodoc:
|
3
4
|
module FasterPath
|
5
|
+
# Core module for applying monkeypatches to `Pathname` and `File`
|
4
6
|
module MonkeyPatches
|
7
|
+
# Monkeypatch just `File` specific methods
|
5
8
|
# rubocop:disable Metrics/CyclomaticComplexity
|
6
9
|
# rubocop:disable Metrics/PerceivedComplexity
|
7
10
|
def self._ruby_core_file!
|
8
11
|
::File.class_eval do
|
12
|
+
# @private :nodoc:
|
9
13
|
def self.basename(pth, ext = '')
|
10
14
|
pth = pth.to_path if pth.respond_to? :to_path
|
11
15
|
raise TypeError unless pth.is_a?(String) && ext.is_a?(String)
|
12
16
|
FasterPath.basename(pth, ext)
|
13
17
|
end
|
14
18
|
|
19
|
+
# @private :nodoc:
|
15
20
|
def self.extname(pth)
|
16
21
|
pth = pth.to_path if pth.respond_to? :to_path
|
17
22
|
raise TypeError unless pth.is_a? String
|
18
23
|
FasterPath.extname(pth)
|
19
24
|
end
|
20
25
|
|
26
|
+
# @private :nodoc:
|
21
27
|
def self.dirname(pth)
|
22
28
|
pth = pth.to_path if pth.respond_to? :to_path
|
23
29
|
raise TypeError unless pth.is_a? String
|
@@ -26,68 +32,83 @@ module FasterPath
|
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
35
|
+
# Monkeypatch just `Pathname` specific methods
|
29
36
|
# rubocop:disable Metrics/MethodLength
|
30
37
|
def self._ruby_library_pathname!
|
31
38
|
::Pathname.class_eval do
|
39
|
+
# @private :nodoc:
|
32
40
|
def absolute?
|
33
41
|
FasterPath.absolute?(@path)
|
34
42
|
end
|
35
43
|
|
44
|
+
# @private :nodoc:
|
36
45
|
def add_trailing_separator(pth)
|
37
46
|
FasterPath.add_trailing_separator(pth)
|
38
47
|
end
|
39
48
|
private :add_trailing_separator
|
40
49
|
|
50
|
+
# @private :nodoc:
|
41
51
|
def children(with_dir=true)
|
42
52
|
FasterPath.children_compat(@path, with_dir)
|
43
53
|
end if !!ENV['WITH_REGRESSION']
|
44
54
|
|
55
|
+
# @private :nodoc:
|
45
56
|
def chop_basename(pth)
|
46
57
|
FasterPath.chop_basename(pth)
|
47
58
|
end
|
48
59
|
private :chop_basename
|
49
60
|
|
61
|
+
# @private :nodoc:
|
50
62
|
def cleanpath_aggressive
|
51
63
|
Pathname.new(FasterPath.cleanpath_aggressive(@path))
|
52
64
|
end
|
53
65
|
private :cleanpath_aggressive
|
54
66
|
|
67
|
+
# @private :nodoc:
|
55
68
|
def cleanpath_conservative
|
56
69
|
Pathname.new(FasterPath.cleanpath_conservative(@path))
|
57
70
|
end
|
58
71
|
private :cleanpath_conservative
|
59
72
|
|
73
|
+
# @private :nodoc:
|
60
74
|
def del_trailing_separator(pth)
|
61
75
|
FasterPath.del_trailing_separator(pth)
|
62
76
|
end
|
63
77
|
private :del_trailing_separator
|
64
78
|
|
79
|
+
# @private :nodoc:
|
65
80
|
def directory?
|
66
81
|
FasterPath.directory?(@path)
|
67
82
|
end
|
68
83
|
|
84
|
+
# @private :nodoc:
|
69
85
|
def entries
|
70
86
|
FasterPath.entries_compat(@path)
|
71
87
|
end if !!ENV['WITH_REGRESSION']
|
72
88
|
|
89
|
+
# @private :nodoc:
|
73
90
|
def has_trailing_separator?(pth)
|
74
91
|
FasterPath.has_trailing_separator?(pth)
|
75
92
|
end
|
76
93
|
private :has_trailing_separator?
|
77
94
|
|
95
|
+
# @private :nodoc:
|
78
96
|
def join(*args)
|
79
97
|
FasterPath.join(self, *args)
|
80
98
|
end
|
81
99
|
|
100
|
+
# @private :nodoc:
|
82
101
|
def plus(pth, pth2)
|
83
102
|
FasterPath.plus(pth, pth2)
|
84
103
|
end
|
85
104
|
private :plus
|
86
105
|
|
106
|
+
# @private :nodoc:
|
87
107
|
def relative?
|
88
108
|
FasterPath.relative?(@path)
|
89
109
|
end
|
90
110
|
|
111
|
+
# @private :nodoc:
|
91
112
|
def relative_path_from(other)
|
92
113
|
FasterPath.relative_path_from(@path, other)
|
93
114
|
end
|
@@ -96,9 +117,9 @@ module FasterPath
|
|
96
117
|
end
|
97
118
|
private_constant :MonkeyPatches
|
98
119
|
|
99
|
-
|
120
|
+
# Applies all performant monkeypatches to both `Pathname` and `File`
|
121
|
+
def self.sledgehammer_everything!
|
100
122
|
MonkeyPatches._ruby_core_file!
|
101
123
|
MonkeyPatches._ruby_library_pathname!
|
102
|
-
"CAUTION: Monkey patching effects everything! Be very sure you want this!"
|
103
124
|
end
|
104
125
|
end
|
@@ -1,20 +1,25 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
|
3
|
+
# @private :nodoc:
|
3
4
|
module FasterPath
|
5
|
+
# @private :nodoc:
|
4
6
|
module RefineFile
|
5
7
|
refine File do
|
8
|
+
# @private :nodoc:
|
6
9
|
def self.basename(pth, ext = '')
|
7
10
|
pth = pth.to_path if pth.respond_to? :to_path
|
8
11
|
raise TypeError unless pth.is_a?(String) && ext.is_a?(String)
|
9
12
|
FasterPath.basename(pth, ext)
|
10
13
|
end
|
11
14
|
|
15
|
+
# @private :nodoc:
|
12
16
|
def self.extname(pth)
|
13
17
|
pth = pth.to_path if pth.respond_to? :to_path
|
14
18
|
raise TypeError unless pth.is_a? String
|
15
19
|
FasterPath.extname(pth)
|
16
20
|
end
|
17
21
|
|
22
|
+
# @private :nodoc:
|
18
23
|
def self.dirname(pth)
|
19
24
|
pth = pth.to_path if pth.respond_to? :to_path
|
20
25
|
raise TypeError unless pth.is_a? String
|
@@ -23,66 +28,81 @@ module FasterPath
|
|
23
28
|
end
|
24
29
|
end
|
25
30
|
|
31
|
+
# @private :nodoc:
|
26
32
|
module RefinePathname
|
27
33
|
refine Pathname do
|
34
|
+
# @private :nodoc:
|
28
35
|
def absolute?
|
29
36
|
FasterPath.absolute?(@path)
|
30
37
|
end
|
31
38
|
|
39
|
+
# @private :nodoc:
|
32
40
|
def add_trailing_separator(pth)
|
33
41
|
FasterPath.add_trailing_separator(pth)
|
34
42
|
end
|
35
43
|
private :add_trailing_separator
|
36
44
|
|
45
|
+
# @private :nodoc:
|
37
46
|
def children(with_dir=true)
|
38
47
|
FasterPath.children_compat(@path, with_dir)
|
39
48
|
end if !!ENV['WITH_REGRESSION']
|
40
49
|
|
50
|
+
# @private :nodoc:
|
41
51
|
def chop_basename(pth)
|
42
52
|
FasterPath.chop_basename(pth)
|
43
53
|
end
|
44
54
|
private :chop_basename
|
45
55
|
|
56
|
+
# @private :nodoc:
|
46
57
|
def cleanpath_aggressive
|
47
58
|
Pathname.new(FasterPath.cleanpath_aggressive(@path))
|
48
59
|
end
|
49
60
|
private :cleanpath_aggressive
|
50
61
|
|
62
|
+
# @private :nodoc:
|
51
63
|
def cleanpath_conservative
|
52
64
|
Pathname.new(FasterPath.cleanpath_conservative(@path))
|
53
65
|
end
|
54
66
|
private :cleanpath_conservative
|
55
67
|
|
68
|
+
# @private :nodoc:
|
56
69
|
def del_trailing_separator(pth)
|
57
70
|
FasterPath.del_trailing_separator(pth)
|
58
71
|
end
|
59
72
|
private :del_trailing_separator
|
60
73
|
|
74
|
+
# @private :nodoc:
|
61
75
|
def directory?
|
62
76
|
FasterPath.directory?(@path)
|
63
77
|
end
|
64
78
|
|
79
|
+
# @private :nodoc:
|
65
80
|
def entries
|
66
81
|
FasterPath.entries_compat(@path)
|
67
82
|
end if !!ENV['WITH_REGRESSION']
|
68
83
|
|
84
|
+
# @private :nodoc:
|
69
85
|
def has_trailing_separator?(pth)
|
70
86
|
FasterPath.has_trailing_separator?(pth)
|
71
87
|
end
|
72
88
|
|
89
|
+
# @private :nodoc:
|
73
90
|
def join(*args)
|
74
91
|
FasterPath.join(self, *args)
|
75
92
|
end
|
76
93
|
|
94
|
+
# @private :nodoc:
|
77
95
|
def plus(pth, pth2)
|
78
96
|
FasterPath.plus(pth, pth2)
|
79
97
|
end
|
80
98
|
private :plus
|
81
99
|
|
100
|
+
# @private :nodoc:
|
82
101
|
def relative?
|
83
102
|
FasterPath.relative?(@path)
|
84
103
|
end
|
85
104
|
|
105
|
+
# @private :nodoc:
|
86
106
|
def relative_path_from(other)
|
87
107
|
FasterPath.relative_path_from(@path, other)
|
88
108
|
end
|
@@ -2,14 +2,19 @@ require 'rubygems'
|
|
2
2
|
require 'rake/tasklib'
|
3
3
|
require_relative './version'
|
4
4
|
|
5
|
+
# @private :nodoc:
|
5
6
|
module Thermite
|
7
|
+
# @private :nodoc:
|
6
8
|
class Config
|
9
|
+
# @private :nodoc:
|
7
10
|
def ruby_version
|
8
11
|
"ruby#{RUBY_VERSION}"
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
15
|
+
# @private :nodoc:
|
12
16
|
class Tasks < Rake::TaskLib
|
17
|
+
# @private :nodoc:
|
13
18
|
def github_download_uri(_tag, version)
|
14
19
|
"#{github_uri}/releases/download/v#{FasterPath::VERSION}/#{config.tarball_filename(version)}"
|
15
20
|
end
|
data/lib/faster_path/version.rb
CHANGED
data/src/basename.rs
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
extern crate memchr;
|
2
2
|
|
3
|
-
use
|
3
|
+
use self::memchr::memrchr;
|
4
|
+
|
5
|
+
use path_parsing::{find_last_sep_pos, find_last_non_sep_pos};
|
4
6
|
|
5
7
|
pub fn basename<'a>(path: &'a str, ext: &str) -> &'a str {
|
6
8
|
let bytes: &[u8] = path.as_bytes();
|
@@ -20,15 +22,87 @@ pub fn basename<'a>(path: &'a str, ext: &str) -> &'a str {
|
|
20
22
|
left = last_slash_pos + 1;
|
21
23
|
}
|
22
24
|
}
|
25
|
+
&path[left..left + ext_end(&bytes[left..right], ext)]
|
26
|
+
}
|
27
|
+
|
28
|
+
fn ext_end(slice: &[u8], ext: &str) -> usize {
|
29
|
+
if ext.len() >= slice.len() || slice == b"." || slice == b".." {
|
30
|
+
return slice.len();
|
31
|
+
}
|
23
32
|
let ext_bytes = ext.as_bytes();
|
24
|
-
if ext_bytes == b
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
33
|
+
if ext_bytes.len() == 2 && *ext_bytes.get(1).unwrap() == b'*' {
|
34
|
+
match memrchr(*ext_bytes.get(0).unwrap(), slice) {
|
35
|
+
Some(end) if end != 0 => return end,
|
36
|
+
_ => {}
|
37
|
+
};
|
38
|
+
} else if slice.ends_with(ext_bytes) {
|
39
|
+
return slice.len() - ext_bytes.len();
|
30
40
|
}
|
31
|
-
|
41
|
+
slice.len()
|
42
|
+
}
|
43
|
+
|
44
|
+
#[test]
|
45
|
+
fn non_dot_asterisk_ext() {
|
46
|
+
// This is undocumented Ruby functionality. We match it in case some code out there relies on it.
|
47
|
+
assert_eq!(basename("abc", "b*"), "a");
|
48
|
+
assert_eq!(basename("abc", "abc"), "abc");
|
49
|
+
assert_eq!(basename("abc", "a*"), "abc");
|
50
|
+
assert_eq!(basename("playlist", "l*"), "play");
|
51
|
+
// Treated as literal "*":
|
52
|
+
assert_eq!(basename("playlist", "yl*"), "playlist");
|
53
|
+
assert_eq!(basename("playl*", "yl*"), "pla");
|
54
|
+
}
|
55
|
+
|
56
|
+
#[test]
|
57
|
+
fn empty() {
|
58
|
+
assert_eq!(basename("", ""), "");
|
59
|
+
assert_eq!(basename("", ".*"), "");
|
60
|
+
assert_eq!(basename("", ".a"), "");
|
61
|
+
}
|
62
|
+
|
63
|
+
#[test]
|
64
|
+
fn sep() {
|
65
|
+
assert_eq!(basename("/", ""), "/");
|
66
|
+
assert_eq!(basename("//", ""), "/");
|
67
|
+
}
|
68
|
+
|
69
|
+
#[test]
|
70
|
+
fn trailing_dot() {
|
71
|
+
assert_eq!(basename("file.test.", ""), "file.test.");
|
72
|
+
assert_eq!(basename("file.test.", "."), "file.test");
|
73
|
+
assert_eq!(basename("file.test.", ".*"), "file.test");
|
74
|
+
}
|
75
|
+
|
76
|
+
#[test]
|
77
|
+
fn trailing_dot_dot() {
|
78
|
+
assert_eq!(basename("a..", ".."), "a");
|
79
|
+
assert_eq!(basename("a..", ".*"), "a.");
|
80
|
+
}
|
81
|
+
|
82
|
+
#[test]
|
83
|
+
fn dot() {
|
84
|
+
assert_eq!(basename(".", ""), ".");
|
85
|
+
assert_eq!(basename(".", "."), ".");
|
86
|
+
assert_eq!(basename(".", ".*"), ".");
|
87
|
+
}
|
88
|
+
|
89
|
+
#[test]
|
90
|
+
fn dot_dot() {
|
91
|
+
assert_eq!(basename("..", ""), "..");
|
92
|
+
assert_eq!(basename("..", ".*"), "..");
|
93
|
+
assert_eq!(basename("..", ".."), "..");
|
94
|
+
assert_eq!(basename("..", "..."), "..");
|
95
|
+
}
|
96
|
+
|
97
|
+
#[test]
|
98
|
+
fn non_dot_ext() {
|
99
|
+
assert_eq!(basename("abc", "bc"), "a");
|
100
|
+
}
|
101
|
+
|
102
|
+
#[test]
|
103
|
+
fn basename_eq_ext() {
|
104
|
+
assert_eq!(basename(".x", ".x"), ".x");
|
105
|
+
assert_eq!(basename(".x", ".*"), ".x");
|
32
106
|
}
|
33
107
|
|
34
108
|
#[test]
|
data/src/helpers.rs
CHANGED
@@ -11,13 +11,16 @@ pub trait TryFrom<T>: Sized {
|
|
11
11
|
fn try_from(value: T) -> Result<Self, Self::Error>;
|
12
12
|
}
|
13
13
|
|
14
|
+
#[cfg(windows)]
|
14
15
|
#[inline]
|
15
16
|
pub fn is_same_path(a: &str, b: &str) -> bool {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
a.to_uppercase() == b.to_uppercase()
|
18
|
+
}
|
19
|
+
|
20
|
+
#[cfg(not(windows))]
|
21
|
+
#[inline]
|
22
|
+
pub fn is_same_path(a: &str, b: &str) -> bool {
|
23
|
+
a == b
|
21
24
|
}
|
22
25
|
|
23
26
|
pub fn anyobject_to_string(item: AnyObject) -> Result<String, RubyDebugInfo> {
|
data/src/path_parsing.rs
CHANGED
@@ -10,12 +10,6 @@ lazy_static! {
|
|
10
10
|
pub static ref SEP_STR: &'static str = str::from_utf8(&[SEP]).unwrap();
|
11
11
|
}
|
12
12
|
|
13
|
-
// Returns the byte offset of the last byte that equals MAIN_SEPARATOR.
|
14
|
-
#[inline(always)]
|
15
|
-
pub fn find_last_dot_pos(bytes: &[u8]) -> Option<usize> {
|
16
|
-
memrchr(b'.', bytes)
|
17
|
-
}
|
18
|
-
|
19
13
|
// Returns the byte offset of the last byte that equals MAIN_SEPARATOR.
|
20
14
|
#[inline(always)]
|
21
15
|
pub fn find_last_sep_pos(bytes: &[u8]) -> Option<usize> {
|
data/src/relative_path_from.rs
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
+
use std::iter;
|
1
2
|
use helpers::{is_same_path, to_str};
|
2
3
|
use path_parsing::SEP_STR;
|
3
4
|
use cleanpath_aggressive::cleanpath_aggressive;
|
4
|
-
|
5
|
-
use self::array_tool::iter::ZipOpt;
|
6
|
-
use ruru;
|
7
|
-
use chop_basename;
|
5
|
+
use chop_basename::chop_basename;
|
8
6
|
use pathname::Pathname;
|
7
|
+
use ruru;
|
9
8
|
use ruru::{Exception as Exc, AnyException as Exception};
|
10
9
|
|
11
10
|
type MaybeString = Result<ruru::RString, ruru::result::Error>;
|
@@ -14,79 +13,58 @@ pub fn relative_path_from(itself: MaybeString, base_directory: MaybeString) -> R
|
|
14
13
|
let dest_directory = cleanpath_aggressive(to_str(&itself));
|
15
14
|
let base_directory = cleanpath_aggressive(to_str(&base_directory));
|
16
15
|
|
17
|
-
let mut
|
18
|
-
let mut
|
19
|
-
loop {
|
20
|
-
match chop_basename::chop_basename(&dest_prefix.clone()) {
|
21
|
-
Some((ref dest, ref basename)) => {
|
22
|
-
dest_prefix = dest;
|
23
|
-
if basename != &"." {
|
24
|
-
dest_names.push(basename)
|
25
|
-
}
|
26
|
-
},
|
27
|
-
None => break,
|
28
|
-
}
|
29
|
-
}
|
30
|
-
dest_names.reverse();
|
31
|
-
|
32
|
-
let mut base_prefix = base_directory.as_ref();
|
33
|
-
let mut base_names: Vec<&str> = vec![];
|
34
|
-
loop {
|
35
|
-
match chop_basename::chop_basename(&base_prefix) {
|
36
|
-
Some((ref base, ref basename)) => {
|
37
|
-
base_prefix = base;
|
38
|
-
if basename != &"." {
|
39
|
-
base_names.push(basename)
|
40
|
-
}
|
41
|
-
},
|
42
|
-
None => break,
|
43
|
-
}
|
44
|
-
}
|
45
|
-
base_names.reverse();
|
16
|
+
let (dest_prefix, mut dest_names) = to_names(dest_directory.as_ref());
|
17
|
+
let (base_prefix, mut base_names) = to_names(base_directory.as_ref());
|
46
18
|
|
47
19
|
if !is_same_path(&dest_prefix, &base_prefix) {
|
48
20
|
return Err(
|
49
21
|
Exception::new(
|
50
22
|
"ArgumentError",
|
51
|
-
Some(&format!("different prefix: {} and {}", dest_prefix, base_prefix)
|
23
|
+
Some(&format!("different prefix: {} and {}", dest_prefix, base_prefix)),
|
52
24
|
)
|
53
25
|
);
|
54
26
|
}
|
55
27
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
fold((vec![], vec![]), |mut acc, (a, b)| {
|
66
|
-
if let Some(v) = a {
|
67
|
-
acc.0.push(v.to_string());
|
68
|
-
}
|
69
|
-
if let Some(v) = b {
|
70
|
-
acc.1.push(v.to_string());
|
71
|
-
}
|
72
|
-
acc
|
73
|
-
});
|
28
|
+
// Remove shared tail
|
29
|
+
{
|
30
|
+
let num_same = dest_names.iter().rev().zip(base_names.iter().rev()).
|
31
|
+
take_while(|&(dest, base)| dest == base).count();
|
32
|
+
let num_dest_names = dest_names.len();
|
33
|
+
dest_names.truncate(num_dest_names - num_same);
|
34
|
+
let num_base_names = base_names.len();
|
35
|
+
base_names.truncate(num_base_names - num_same);
|
36
|
+
};
|
74
37
|
|
75
|
-
if base_names.contains(&".."
|
38
|
+
if base_names.contains(&"..") {
|
76
39
|
return Err(
|
77
40
|
Exception::new(
|
78
41
|
"ArgumentError",
|
79
|
-
Some(&format!("base_directory has ..: {}", base_directory)
|
42
|
+
Some(&format!("base_directory has ..: {}", base_directory)),
|
80
43
|
)
|
81
44
|
);
|
82
45
|
}
|
83
46
|
|
84
|
-
let base_names: Vec<String> = base_names.into_iter().map(|_| "..".to_string()).collect();
|
85
|
-
|
86
47
|
if base_names.is_empty() && dest_names.is_empty() {
|
87
48
|
Ok(Pathname::new("."))
|
88
49
|
} else {
|
89
|
-
Ok(Pathname::new(&base_names.
|
50
|
+
Ok(Pathname::new(&iter::repeat("..").take(base_names.len()).chain(dest_names.into_iter().rev()).
|
90
51
|
collect::<Vec<&str>>().join(&SEP_STR)))
|
91
52
|
}
|
92
53
|
}
|
54
|
+
|
55
|
+
#[inline(always)]
|
56
|
+
fn to_names(path: &str) -> (&str, Vec<&str>) {
|
57
|
+
let mut result: Vec<&str> = vec![];
|
58
|
+
let mut prefix = path;
|
59
|
+
loop {
|
60
|
+
match chop_basename(&prefix) {
|
61
|
+
Some((ref dest, ref basename)) => {
|
62
|
+
prefix = dest;
|
63
|
+
if basename != &"." {
|
64
|
+
result.push(basename);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
None => return (prefix, result),
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faster_path
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel P. Clark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|