faster_path 0.3.8 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|