faster_path 0.2.2 → 0.2.3
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 +21 -5
- data/Cargo.toml +2 -1
- data/MIT-LICENSE.txt +1 -1
- data/README.md +6 -7
- data/Rakefile +20 -3
- data/faster_path.gemspec +3 -3
- data/lib/faster_path.rb +31 -26
- data/lib/faster_path/optional/monkeypatches.rb +7 -0
- data/lib/faster_path/optional/refinements.rb +5 -0
- data/lib/faster_path/version.rb +1 -1
- data/src/basename.rs +20 -14
- data/src/cleanpath_aggressive.rs +104 -0
- data/src/dirname.rs +18 -23
- data/src/extname.rs +3 -3
- data/src/helpers.rs +2 -14
- data/src/lib.rs +24 -16
- data/src/path_parsing.rs +11 -34
- data/src/pathname.rs +13 -7
- data/src/plus.rs +1 -1
- data/src/prepend_prefix.rs +18 -0
- metadata +6 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8487e703f71a357f9d42a04c8f4ba2b98291bad4
|
4
|
+
data.tar.gz: 4c2c24ac1f470bfddbae8ccbfec0447961476e07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57e7745e69f3f30b32981731c250ffa001e4f4f58b5a4b44a0b6558ea786a0a741dc0ce225c959998055ed99c8070dcc78f995ec3c3bb538258cee9429bb71bc
|
7
|
+
data.tar.gz: b30307165e8fbdee36a2dd62bf92618af2f062d8bd93d94c4324c650d6c282fc45778508930d77e2f991a6a998ba6281dad53a742dca4c45751d346e42b3714f
|
data/Cargo.lock
CHANGED
@@ -1,20 +1,26 @@
|
|
1
|
-
[
|
1
|
+
[[package]]
|
2
|
+
name = "array_tool"
|
3
|
+
version = "0.4.1"
|
4
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
5
|
+
|
6
|
+
[[package]]
|
2
7
|
name = "faster_path"
|
3
8
|
version = "0.0.1"
|
4
9
|
dependencies = [
|
5
10
|
"array_tool 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
6
|
-
"
|
11
|
+
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
12
|
+
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
7
13
|
"ruru 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
8
14
|
]
|
9
15
|
|
10
16
|
[[package]]
|
11
|
-
name = "
|
12
|
-
version = "0.
|
17
|
+
name = "lazy_static"
|
18
|
+
version = "0.2.8"
|
13
19
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
14
20
|
|
15
21
|
[[package]]
|
16
22
|
name = "lazy_static"
|
17
|
-
version = "0.
|
23
|
+
version = "1.0.0"
|
18
24
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
19
25
|
|
20
26
|
[[package]]
|
@@ -22,6 +28,14 @@ name = "libc"
|
|
22
28
|
version = "0.2.30"
|
23
29
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
24
30
|
|
31
|
+
[[package]]
|
32
|
+
name = "memchr"
|
33
|
+
version = "2.0.1"
|
34
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
35
|
+
dependencies = [
|
36
|
+
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
37
|
+
]
|
38
|
+
|
25
39
|
[[package]]
|
26
40
|
name = "ruby-sys"
|
27
41
|
version = "0.2.20"
|
@@ -42,6 +56,8 @@ dependencies = [
|
|
42
56
|
[metadata]
|
43
57
|
"checksum array_tool 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a07ccb27c611e5cda99e498e99ba71b3ecdb7db5df02096cef42a3df5b84542"
|
44
58
|
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
|
59
|
+
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
45
60
|
"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915"
|
61
|
+
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
|
46
62
|
"checksum ruby-sys 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e71509f17ce93733dc196258e168b58050490a156b04563816a8120a74ba04c7"
|
47
63
|
"checksum ruru 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6486d6c50b7a08246a492a61893635c1977d41c138041d443eb603f6298e0273"
|
data/Cargo.toml
CHANGED
data/MIT-LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2016 Daniel P. Clark
|
3
|
+
Copyright (c) 2016-2017 Daniel P. Clark & FasterPath Contributors
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[](https://travis-ci.org/danielpclark/faster_path)
|
4
4
|
[](https://ci.appveyor.com/project/danielpclark/faster-path/branch/master)
|
5
5
|
[](https://github.com/danielpclark/faster_path/tags)
|
6
|
-
[](https://github.com/danielpclark/faster_path/pulse)
|
7
7
|
[](https://github.com/danielpclark/faster_path/releases)
|
8
8
|
[](https://coveralls.io/github/danielpclark/faster_path)
|
9
9
|
[](http://inch-ci.org/github/danielpclark/faster_path)
|
@@ -113,7 +113,7 @@ curl -sSf https://static.rust-lang.org/rustup.sh | sh
|
|
113
113
|
Add this line to your application's Gemfile:
|
114
114
|
|
115
115
|
```ruby
|
116
|
-
gem 'faster_path', '~> 0.
|
116
|
+
gem 'faster_path', '~> 0.2.3'
|
117
117
|
```
|
118
118
|
|
119
119
|
And then execute:
|
@@ -124,8 +124,6 @@ Or install it yourself as:
|
|
124
124
|
|
125
125
|
$ gem install faster_path
|
126
126
|
|
127
|
-
**MAC USERS:** At the moment Mac users need to install the extension manualy. Go to the gem directory and run `cargo build --release` . There is an issue opened for this and I'm looking for people who have Macs to help on this.
|
128
|
-
|
129
127
|
## Visual Benchmarks
|
130
128
|
|
131
129
|
Benchmarks in Faster Path now produce visual graph charts of performance improvements.
|
@@ -142,12 +140,13 @@ Current methods implemented:
|
|
142
140
|
|---|---|:---:|
|
143
141
|
| `FasterPath.absolute?` | `Pathname#absolute?` | 88.5% |
|
144
142
|
| `FasterPath.add_trailing_separator` | `Pathname#add_trailing_separator` | 31.1% |
|
145
|
-
| `FasterPath.children` | `Pathname#children` |
|
146
|
-
| `FasterPath.chop_basename` | `Pathname#chop_basename` |
|
143
|
+
| `FasterPath.children` | `Pathname#children` | 14.6% |
|
144
|
+
| `FasterPath.chop_basename` | `Pathname#chop_basename` | 56.7% |
|
145
|
+
| `FasterPath.cleanpath_aggressive` | `Pathname#cleanpath_aggressive` | 69.8% |
|
147
146
|
| `FasterPath.directory?` | `Pathname#directory?` | 12.7% |
|
148
147
|
| `FasterPath.entries` | `Pathname#entries` | 7.7% |
|
149
148
|
| `FasterPath.has_trailing_separator?` | `Pathname#has_trailing_separator` | 59.2% |
|
150
|
-
| `FasterPath.plus` | `Pathname#plus` | 77.
|
149
|
+
| `FasterPath.plus` | `Pathname#plus` | 77.9% |
|
151
150
|
| `FasterPath.relative?` | `Pathname#relative?` | 83.1% |
|
152
151
|
|
153
152
|
You may choose to use the methods directly, or scope change to rewrite behavior on the
|
data/Rakefile
CHANGED
@@ -24,6 +24,13 @@ task :sysinfo do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
desc "Generate Contriburs.md Manifest"
|
28
|
+
task :contrib do
|
29
|
+
puts "Generating Contriburs.md Manifest"
|
30
|
+
exec "printf '# Contributors\n
|
31
|
+
' > Contributors.md;git shortlog -s -n -e | sed 's/^......./- /' >> Contributors.md"
|
32
|
+
end
|
33
|
+
|
27
34
|
desc "Add libruby to deps"
|
28
35
|
task :libruby_release do
|
29
36
|
filename = RbConfig::CONFIG["LIBRUBY_ALIASES"].split(" ").first
|
@@ -98,21 +105,31 @@ Rake::TestTask.new(minitest: :build_lib) do |t|
|
|
98
105
|
t.test_files = FileList['test/**/*_test.rb']
|
99
106
|
end
|
100
107
|
|
101
|
-
task
|
108
|
+
task :init_mspec do |_t|
|
109
|
+
if Dir.open('spec/mspec').entries.-([".", ".."]).empty?
|
110
|
+
`git submodule init`
|
111
|
+
`git submodule update`
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
task test: [:cargo, :minitest, :lint, :pbench, :init_mspec] do |_t|
|
102
116
|
exec 'spec/mspec/bin/mspec --format spec core/file/basename core/file/extname core/file/dirname library/pathname'
|
103
117
|
end
|
104
118
|
|
105
119
|
desc "Full mspec results w/o encoding"
|
106
|
-
task :
|
120
|
+
task mspec_full: :init_mspec do
|
107
121
|
exec %(bash -c "TEST_MONKEYPATCHES=true WITH_REGRESSION=true spec/mspec/bin/mspec --format spec core/file/basename core/file/extname core/file/dirname library/pathname")
|
108
122
|
end
|
109
123
|
|
110
124
|
desc "Full mspec results w/ encoding"
|
111
|
-
task :
|
125
|
+
task mspec_encoding_full: :init_mspec do
|
112
126
|
exec %(bash -c "ENCODING=1 TEST_MONKEYPATCHES=true WITH_REGRESSION=true mspec --format spec core/file/basename core/file/extname core/file/dirname library/pathname")
|
113
127
|
end
|
114
128
|
|
115
129
|
Rake::TestTask.new(bench: :build_lib) do |t|
|
130
|
+
if ENV['GRAPH']
|
131
|
+
`bundle install`
|
132
|
+
end
|
116
133
|
t.libs = %w[lib test]
|
117
134
|
t.pattern = 'test/**/*_benchmark.rb'
|
118
135
|
end
|
data/faster_path.gemspec
CHANGED
@@ -31,9 +31,9 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency "minitest", "~> 5.10"
|
32
32
|
spec.add_development_dependency "minitest-reporters", "~> 1.1"
|
33
33
|
spec.add_development_dependency "color_pound_spec_reporter", "~> 0.0.9"
|
34
|
-
spec.add_development_dependency "rubocop", "~> 0.
|
35
|
-
|
36
|
-
|
34
|
+
spec.add_development_dependency "rubocop", "~> 0.51"
|
35
|
+
spec.add_development_dependency "stop_watch", "~> 1.0.0"
|
36
|
+
if !ENV['CI'] && ENV['GRAPH']
|
37
37
|
spec.add_development_dependency "gruff", "~> 0.7.0"
|
38
38
|
end
|
39
39
|
end
|
data/lib/faster_path.rb
CHANGED
@@ -15,20 +15,21 @@ module FasterPath
|
|
15
15
|
call
|
16
16
|
|
17
17
|
FasterPathname::Public.class_eval do
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
18
|
+
private_class_method :absolute?
|
19
|
+
private_class_method :add_trailing_separator
|
20
|
+
private_class_method :basename
|
21
|
+
private_class_method :children # String results
|
22
|
+
private_class_method :children_compat # wrap Pathname on each
|
23
|
+
private_class_method :chop_basename
|
24
|
+
private_class_method :cleanpath_aggressive
|
25
|
+
private_class_method :directory?
|
26
|
+
private_class_method :dirname
|
27
|
+
private_class_method :entries # String results
|
28
|
+
private_class_method :entries_compat # wrap Pathname on each
|
29
|
+
private_class_method :extname
|
30
|
+
private_class_method :has_trailing_separator?
|
31
|
+
private_class_method :plus
|
32
|
+
private_class_method :relative?
|
32
33
|
end
|
33
34
|
|
34
35
|
FasterPathname.class_eval do
|
@@ -60,11 +61,11 @@ module FasterPath
|
|
60
61
|
end
|
61
62
|
|
62
63
|
def self.absolute?(pth)
|
63
|
-
FasterPathname::Public.
|
64
|
+
FasterPathname::Public.send(:absolute?, pth)
|
64
65
|
end
|
65
66
|
|
66
67
|
def self.add_trailing_separator(pth)
|
67
|
-
FasterPathname::Public.
|
68
|
+
FasterPathname::Public.send(:add_trailing_separator, pth)
|
68
69
|
end
|
69
70
|
|
70
71
|
def self.blank?(str)
|
@@ -72,44 +73,48 @@ module FasterPath
|
|
72
73
|
end
|
73
74
|
|
74
75
|
def self.basename(pth, ext="")
|
75
|
-
FasterPathname::Public.
|
76
|
+
FasterPathname::Public.send(:basename, pth, ext)
|
76
77
|
end
|
77
78
|
|
78
79
|
def self.children(pth, with_directory=true)
|
79
|
-
FasterPathname::Public.
|
80
|
+
FasterPathname::Public.send(:children, pth, with_directory)
|
80
81
|
end
|
81
82
|
|
82
83
|
def self.chop_basename(pth)
|
83
|
-
result = FasterPathname::Public.
|
84
|
+
result = FasterPathname::Public.send(:chop_basename, pth)
|
84
85
|
result unless result.empty?
|
85
86
|
end
|
86
87
|
|
88
|
+
def self.cleanpath_aggressive(pth)
|
89
|
+
FasterPathname::Public.send(:cleanpath_aggressive, pth)
|
90
|
+
end
|
91
|
+
|
87
92
|
def self.directory?(pth)
|
88
|
-
FasterPathname::Public.
|
93
|
+
FasterPathname::Public.send(:directory?, pth)
|
89
94
|
end
|
90
95
|
|
91
96
|
def self.dirname(pth)
|
92
|
-
FasterPathname::Public.
|
97
|
+
FasterPathname::Public.send(:dirname, pth)
|
93
98
|
end
|
94
99
|
|
95
100
|
def self.entries(pth)
|
96
|
-
FasterPathname::Public.
|
101
|
+
FasterPathname::Public.send(:entries, pth)
|
97
102
|
end
|
98
103
|
|
99
104
|
def self.extname(pth)
|
100
|
-
FasterPathname::Public.
|
105
|
+
FasterPathname::Public.send(:extname, pth)
|
101
106
|
end
|
102
107
|
|
103
108
|
def self.has_trailing_separator?(pth)
|
104
|
-
FasterPathname::Public.
|
109
|
+
FasterPathname::Public.send(:has_trailing_separator?, pth)
|
105
110
|
end
|
106
111
|
|
107
112
|
def self.plus(pth, pth2)
|
108
|
-
FasterPathname::Public.
|
113
|
+
FasterPathname::Public.send(:plus, pth, pth2)
|
109
114
|
end
|
110
115
|
|
111
116
|
def self.relative?(pth)
|
112
|
-
FasterPathname::Public.
|
117
|
+
FasterPathname::Public.send(:relative?, pth)
|
113
118
|
end
|
114
119
|
|
115
120
|
module Rust
|
@@ -25,6 +25,8 @@ module FasterPath
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
|
+
|
29
|
+
# rubocop:disable Metrics/MethodLength
|
28
30
|
def self._ruby_library_pathname!
|
29
31
|
::Pathname.class_eval do
|
30
32
|
def absolute?
|
@@ -46,6 +48,11 @@ module FasterPath
|
|
46
48
|
end
|
47
49
|
private :chop_basename
|
48
50
|
|
51
|
+
def cleanpath_aggressive
|
52
|
+
Pathname.new(FasterPath.cleanpath_aggressive(@path))
|
53
|
+
end
|
54
|
+
private :cleanpath_aggressive
|
55
|
+
|
49
56
|
def directory?
|
50
57
|
FasterPath.directory?(@path)
|
51
58
|
end
|
data/lib/faster_path/version.rb
CHANGED
data/src/basename.rs
CHANGED
@@ -1,23 +1,29 @@
|
|
1
|
-
extern crate
|
2
|
-
use
|
3
|
-
use
|
1
|
+
extern crate memchr;
|
2
|
+
use self::memchr::memrchr;
|
3
|
+
use path_parsing::{SEP, last_non_sep_i};
|
4
4
|
|
5
|
-
pub fn basename(pth: &str, ext: &str) ->
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
pub fn basename<'a>(pth: &'a str, ext: &str) -> &'a str {
|
6
|
+
let name_end = (last_non_sep_i(pth) + 1) as usize;
|
7
|
+
// Known edge case, all '/'.
|
8
|
+
if !pth.is_empty() && name_end == 0 {
|
9
|
+
return &pth[..1];
|
10
10
|
}
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
let name_start = match memrchr(SEP, &pth.as_bytes()[..name_end]) {
|
12
|
+
Some(i) => i + 1,
|
13
|
+
_ => 0
|
14
|
+
};
|
15
|
+
let mut name = &pth[name_start..name_end];
|
14
16
|
if ext == ".*" {
|
15
|
-
if let Some(dot_i) =
|
16
|
-
name = &name[
|
17
|
+
if let Some(dot_i) = memrchr('.' as u8, name.as_bytes()) {
|
18
|
+
name = &name[..dot_i];
|
17
19
|
}
|
18
20
|
} else if name.ends_with(ext) {
|
19
21
|
name = &name[..name.len() - ext.len()];
|
20
22
|
};
|
21
|
-
name
|
23
|
+
name
|
22
24
|
}
|
23
25
|
|
26
|
+
#[test]
|
27
|
+
fn edge_case_all_seps() {
|
28
|
+
assert_eq!("/", basename("///", ".*"));
|
29
|
+
}
|
@@ -0,0 +1,104 @@
|
|
1
|
+
use prepend_prefix::prepend_prefix;
|
2
|
+
use basename::basename;
|
3
|
+
use chop_basename::chop_basename;
|
4
|
+
extern crate array_tool;
|
5
|
+
use self::array_tool::vec::Shift;
|
6
|
+
use std::path::MAIN_SEPARATOR;
|
7
|
+
|
8
|
+
pub fn cleanpath_aggressive(path: &str) -> String {
|
9
|
+
let sep = MAIN_SEPARATOR.to_string();
|
10
|
+
let mut names: Vec<String> = vec![];
|
11
|
+
let mut pre = path.to_string();
|
12
|
+
loop {
|
13
|
+
match chop_basename(&pre) {
|
14
|
+
Some((ref p, ref base)) => {
|
15
|
+
pre = p.to_string();
|
16
|
+
match base.as_ref() {
|
17
|
+
"." => {},
|
18
|
+
".." => names.unshift(base.to_string()),
|
19
|
+
_ => {
|
20
|
+
if names.first() == Some(&"..".to_string()) {
|
21
|
+
names.shift();
|
22
|
+
} else {
|
23
|
+
names.unshift(base.to_string())
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
}
|
28
|
+
},
|
29
|
+
None => break,
|
30
|
+
}
|
31
|
+
}
|
32
|
+
// // Windows Feature
|
33
|
+
//
|
34
|
+
// ```ruby
|
35
|
+
// pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
|
36
|
+
// ```
|
37
|
+
//
|
38
|
+
if basename(&pre, "").contains(&sep) {
|
39
|
+
loop {
|
40
|
+
if names.first() == Some(&"..".to_string()) {
|
41
|
+
let _ = names.shift();
|
42
|
+
} else {
|
43
|
+
break
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
prepend_prefix(&pre, &names.join(&sep)[..])
|
48
|
+
}
|
49
|
+
|
50
|
+
#[test]
|
51
|
+
fn it_aggressively_cleans_the_path() {
|
52
|
+
assert_eq!(cleanpath_aggressive("/") , "/");
|
53
|
+
assert_eq!(cleanpath_aggressive("") , ".");
|
54
|
+
assert_eq!(cleanpath_aggressive(".") , ".");
|
55
|
+
assert_eq!(cleanpath_aggressive("..") , "..");
|
56
|
+
assert_eq!(cleanpath_aggressive("a") , "a");
|
57
|
+
assert_eq!(cleanpath_aggressive("/.") , "/");
|
58
|
+
assert_eq!(cleanpath_aggressive("/..") , "/");
|
59
|
+
assert_eq!(cleanpath_aggressive("/a") , "/a");
|
60
|
+
assert_eq!(cleanpath_aggressive("./") , ".");
|
61
|
+
assert_eq!(cleanpath_aggressive("../") , "..");
|
62
|
+
assert_eq!(cleanpath_aggressive("a/") , "a");
|
63
|
+
assert_eq!(cleanpath_aggressive("a//b") , "a/b");
|
64
|
+
assert_eq!(cleanpath_aggressive("a/.") , "a");
|
65
|
+
assert_eq!(cleanpath_aggressive("a/./") , "a");
|
66
|
+
assert_eq!(cleanpath_aggressive("a/..") , ".");
|
67
|
+
assert_eq!(cleanpath_aggressive("a/../") , ".");
|
68
|
+
assert_eq!(cleanpath_aggressive("/a/.") , "/a");
|
69
|
+
assert_eq!(cleanpath_aggressive("./..") , "..");
|
70
|
+
assert_eq!(cleanpath_aggressive("../.") , "..");
|
71
|
+
assert_eq!(cleanpath_aggressive("./../") , "..");
|
72
|
+
assert_eq!(cleanpath_aggressive(".././") , "..");
|
73
|
+
assert_eq!(cleanpath_aggressive("/./..") , "/");
|
74
|
+
assert_eq!(cleanpath_aggressive("/../.") , "/");
|
75
|
+
assert_eq!(cleanpath_aggressive("/./../") , "/");
|
76
|
+
assert_eq!(cleanpath_aggressive("/.././") , "/");
|
77
|
+
assert_eq!(cleanpath_aggressive("a/b/c") , "a/b/c");
|
78
|
+
assert_eq!(cleanpath_aggressive("./b/c") , "b/c");
|
79
|
+
assert_eq!(cleanpath_aggressive("a/./c") , "a/c");
|
80
|
+
assert_eq!(cleanpath_aggressive("a/b/.") , "a/b");
|
81
|
+
assert_eq!(cleanpath_aggressive("a/../.") , ".");
|
82
|
+
assert_eq!(cleanpath_aggressive("/../.././../a") , "/a");
|
83
|
+
assert_eq!(cleanpath_aggressive("a/b/../../../../c/../d"), "../../d");
|
84
|
+
}
|
85
|
+
|
86
|
+
// Future Windows Support
|
87
|
+
//
|
88
|
+
// DOSISH = File::ALT_SEPARATOR != nil
|
89
|
+
// DOSISH_DRIVE_LETTER = File.dirname("A:") == "A:."
|
90
|
+
// DOSISH_UNC = File.dirname("//") == "//"
|
91
|
+
//
|
92
|
+
// if DOSISH_UNC
|
93
|
+
// defassert(:cleanpath_aggressive, '//a/b/c', '//a/b/c/')
|
94
|
+
// else
|
95
|
+
// defassert(:cleanpath_aggressive, '/', '///')
|
96
|
+
// defassert(:cleanpath_aggressive, '/a', '///a')
|
97
|
+
// defassert(:cleanpath_aggressive, '/', '///..')
|
98
|
+
// defassert(:cleanpath_aggressive, '/', '///.')
|
99
|
+
// defassert(:cleanpath_aggressive, '/', '///a/../..')
|
100
|
+
// end
|
101
|
+
//
|
102
|
+
// if DOSISH
|
103
|
+
// defassert(:cleanpath_aggressive, 'c:/foo/bar', 'c:\\foo\\bar')
|
104
|
+
// end
|
data/src/dirname.rs
CHANGED
@@ -1,27 +1,22 @@
|
|
1
|
-
|
2
|
-
use
|
1
|
+
extern crate memchr;
|
2
|
+
use self::memchr::memrchr;
|
3
|
+
use path_parsing::{SEP, SEP_STR, last_non_sep_i, last_non_sep_i_before};
|
3
4
|
|
4
|
-
pub fn dirname(path: &str) ->
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
}
|
20
|
-
let non_sep_i2 = last_non_sep_i_before(r_str, sep_i);
|
21
|
-
if non_sep_i2 != -1 {
|
22
|
-
return r_str[..(non_sep_i2 + 1) as usize].to_string();
|
23
|
-
} else {
|
24
|
-
return MAIN_SEPARATOR.to_string();
|
5
|
+
pub fn dirname(path: &str) -> &str {
|
6
|
+
if path.is_empty() { return "."; }
|
7
|
+
let non_sep_i = last_non_sep_i(path);
|
8
|
+
if non_sep_i == -1 { return *SEP_STR; }
|
9
|
+
return match memrchr(SEP, &path.as_bytes()[..non_sep_i as usize]) {
|
10
|
+
None => ".",
|
11
|
+
Some(0) => *SEP_STR,
|
12
|
+
Some(sep_i) => {
|
13
|
+
let non_sep_i2 = last_non_sep_i_before(path, sep_i as isize);
|
14
|
+
if non_sep_i2 != -1 {
|
15
|
+
&path[..(non_sep_i2 + 1) as usize]
|
16
|
+
} else {
|
17
|
+
*SEP_STR
|
18
|
+
}
|
19
|
+
}
|
25
20
|
}
|
26
21
|
}
|
27
22
|
|
data/src/extname.rs
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
use path_parsing::extract_last_path_segment;
|
2
2
|
|
3
|
-
pub fn extname(pth: &str) ->
|
3
|
+
pub fn extname(pth: &str) -> &str {
|
4
4
|
let name = extract_last_path_segment(pth);
|
5
5
|
|
6
6
|
if let Some(dot_i) = name.rfind('.') {
|
7
7
|
if dot_i > 0 && dot_i < name.len() - 1 && name[..dot_i].chars().rev().next().unwrap() != '.' {
|
8
|
-
return
|
8
|
+
return &name[dot_i..]
|
9
9
|
}
|
10
10
|
}
|
11
11
|
|
12
|
-
|
12
|
+
""
|
13
13
|
}
|
data/src/helpers.rs
CHANGED
@@ -1,19 +1,7 @@
|
|
1
|
-
|
2
|
-
use self::ruby_sys::string;
|
3
|
-
|
4
|
-
use ruru::{AnyObject, Class};
|
5
|
-
use ruru::types::{c_char, c_long, Value};
|
6
|
-
|
7
|
-
#[inline]
|
8
|
-
pub fn str_to_value(string: &str) -> Value {
|
9
|
-
let str_ptr = string.as_ptr() as *const c_char;
|
10
|
-
let len = string.len() as c_long;
|
11
|
-
|
12
|
-
unsafe { string::rb_str_new(str_ptr, len) }
|
13
|
-
}
|
1
|
+
use ruru::{AnyObject, Class, Object, RString};
|
14
2
|
|
15
3
|
pub fn str_to_any_obj(str_var: &str) -> AnyObject {
|
16
|
-
|
4
|
+
RString::new(str_var).to_any_object()
|
17
5
|
}
|
18
6
|
|
19
7
|
pub fn class_new(klass: &str, params: Vec<AnyObject>) -> AnyObject {
|
data/src/lib.rs
CHANGED
@@ -7,15 +7,20 @@
|
|
7
7
|
#[macro_use]
|
8
8
|
extern crate ruru;
|
9
9
|
|
10
|
+
#[macro_use]
|
11
|
+
extern crate lazy_static;
|
12
|
+
|
10
13
|
class!(FasterPathname);
|
11
14
|
|
12
15
|
mod helpers;
|
13
16
|
mod pathname;
|
14
17
|
mod basename;
|
15
18
|
mod chop_basename;
|
19
|
+
mod cleanpath_aggressive;
|
16
20
|
mod dirname;
|
17
21
|
mod extname;
|
18
22
|
mod plus;
|
23
|
+
mod prepend_prefix;
|
19
24
|
pub mod rust_arch_bits;
|
20
25
|
mod path_parsing;
|
21
26
|
|
@@ -56,7 +61,9 @@ methods!(
|
|
56
61
|
// fn r_cleanpath(){ pub_cleanpath(r_to_path()) }
|
57
62
|
// fn pub_cleanpath(pth: RString){}
|
58
63
|
|
59
|
-
|
64
|
+
fn pub_cleanpath_aggressive(pth: RString) -> RString {
|
65
|
+
pathname::pn_cleanpath_aggressive(pth)
|
66
|
+
}
|
60
67
|
|
61
68
|
// fn r_cleanpath_conservative(pth: RString){}
|
62
69
|
|
@@ -95,7 +102,7 @@ methods!(
|
|
95
102
|
|
96
103
|
// fn r_find(ignore_error: Boolean){}
|
97
104
|
// fn pub_find(pth: RString ,ignore_error: Boolean){}
|
98
|
-
|
105
|
+
|
99
106
|
fn pub_has_trailing_separator(pth: RString) -> Boolean {
|
100
107
|
pathname::pn_has_trailing_separator(pth)
|
101
108
|
}
|
@@ -147,19 +154,20 @@ pub extern "C" fn Init_faster_pathname(){
|
|
147
154
|
// * methods for refinements, monkeypatching
|
148
155
|
// * methods that need all values as parameters
|
149
156
|
Class::from_existing("FasterPathname").get_nested_class("Public").define(|itself| {
|
150
|
-
itself.
|
151
|
-
itself.
|
152
|
-
itself.
|
153
|
-
itself.
|
154
|
-
itself.
|
155
|
-
itself.
|
156
|
-
itself.
|
157
|
-
itself.
|
158
|
-
itself.
|
159
|
-
itself.
|
160
|
-
itself.
|
161
|
-
itself.
|
162
|
-
itself.
|
163
|
-
itself.
|
157
|
+
itself.def_self("absolute?", pub_is_absolute);
|
158
|
+
itself.def_self("add_trailing_separator", pub_add_trailing_separator);
|
159
|
+
itself.def_self("basename", pub_basename);
|
160
|
+
itself.def_self("children", pub_children);
|
161
|
+
itself.def_self("children_compat", pub_children_compat);
|
162
|
+
itself.def_self("chop_basename", pub_chop_basename);
|
163
|
+
itself.def_self("cleanpath_aggressive", pub_cleanpath_aggressive);
|
164
|
+
itself.def_self("directory?", pub_is_directory);
|
165
|
+
itself.def_self("dirname", pub_dirname);
|
166
|
+
itself.def_self("entries", pub_entries);
|
167
|
+
itself.def_self("entries_compat", pub_entries_compat);
|
168
|
+
itself.def_self("extname", pub_extname);
|
169
|
+
itself.def_self("has_trailing_separator?", pub_has_trailing_separator);
|
170
|
+
itself.def_self("plus", pub_plus);
|
171
|
+
itself.def_self("relative?", pub_is_relative);
|
164
172
|
});
|
165
173
|
}
|
data/src/path_parsing.rs
CHANGED
@@ -1,30 +1,18 @@
|
|
1
|
+
extern crate memchr;
|
2
|
+
use self::memchr::memrchr;
|
1
3
|
use std::path::MAIN_SEPARATOR;
|
4
|
+
use std::str;
|
2
5
|
|
3
|
-
|
6
|
+
pub const SEP: u8 = MAIN_SEPARATOR as u8;
|
7
|
+
lazy_static! {
|
8
|
+
pub static ref SEP_STR: &'static str = str::from_utf8(&[SEP]).unwrap();
|
9
|
+
}
|
4
10
|
|
5
11
|
pub fn extract_last_path_segment(path: &str) -> &str {
|
6
|
-
|
7
|
-
|
8
|
-
// See src/benches/path_parsing.rs for benchmarks of different approaches.
|
9
|
-
let ptr = path.as_ptr();
|
10
|
-
let mut i = path.len() as isize - 1;
|
11
|
-
while i >= 0 {
|
12
|
-
let c = unsafe { *ptr.offset(i) };
|
13
|
-
if c != SEP { break; };
|
14
|
-
i -= 1;
|
15
|
-
}
|
16
|
-
let end = (i + 1) as usize;
|
17
|
-
while i >= 0 {
|
18
|
-
let c = unsafe { *ptr.offset(i) };
|
19
|
-
if c == SEP {
|
20
|
-
return &path[(i + 1) as usize..end];
|
21
|
-
};
|
22
|
-
i -= 1;
|
23
|
-
}
|
24
|
-
&path[..end]
|
12
|
+
let end = (last_non_sep_i(path) + 1) as usize;
|
13
|
+
&path[memrchr(SEP, &path.as_bytes()[..end]).unwrap_or(0)..end]
|
25
14
|
}
|
26
15
|
|
27
|
-
|
28
16
|
// Returns the byte offset of the last byte preceding a MAIN_SEPARATOR.
|
29
17
|
pub fn last_non_sep_i(path: &str) -> isize {
|
30
18
|
last_non_sep_i_before(path, path.len() as isize - 1)
|
@@ -32,6 +20,8 @@ pub fn last_non_sep_i(path: &str) -> isize {
|
|
32
20
|
|
33
21
|
// Returns the byte offset of the last byte preceding a MAIN_SEPARATOR before the given end offset.
|
34
22
|
pub fn last_non_sep_i_before(path: &str, end: isize) -> isize {
|
23
|
+
// Works with bytes directly because MAIN_SEPARATOR is always in the ASCII 7-bit range so we can
|
24
|
+
// avoid the overhead of full UTF-8 processing.
|
35
25
|
let ptr = path.as_ptr();
|
36
26
|
let mut i = end;
|
37
27
|
while i >= 0 {
|
@@ -40,16 +30,3 @@ pub fn last_non_sep_i_before(path: &str, end: isize) -> isize {
|
|
40
30
|
}
|
41
31
|
i
|
42
32
|
}
|
43
|
-
|
44
|
-
// Returns the byte offset of the last MAIN_SEPARATOR before the given end offset.
|
45
|
-
pub fn last_sep_i(path: &str, end: isize) -> isize {
|
46
|
-
let ptr = path.as_ptr();
|
47
|
-
let mut i = end - 1;
|
48
|
-
while i >= 0 {
|
49
|
-
if unsafe { *ptr.offset(i) } == SEP {
|
50
|
-
return i;
|
51
|
-
};
|
52
|
-
i -= 1;
|
53
|
-
}
|
54
|
-
-1
|
55
|
-
}
|
data/src/pathname.rs
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
use helpers::*;
|
2
2
|
use basename;
|
3
3
|
use chop_basename;
|
4
|
+
use cleanpath_aggressive;
|
4
5
|
use dirname;
|
5
6
|
use extname;
|
6
7
|
use plus;
|
@@ -33,10 +34,10 @@ pub fn pn_is_absolute(pth: MaybeString) -> Boolean {
|
|
33
34
|
|
34
35
|
pub fn pn_basename(pth: MaybeString, ext: MaybeString) -> RString {
|
35
36
|
RString::new(
|
36
|
-
|
37
|
+
basename::basename(
|
37
38
|
pth.ok().unwrap_or(RString::new("")).to_str(),
|
38
39
|
ext.ok().unwrap_or(RString::new("")).to_str()
|
39
|
-
)
|
40
|
+
)
|
40
41
|
)
|
41
42
|
}
|
42
43
|
|
@@ -115,7 +116,13 @@ pub fn pn_chop_basename(pth: MaybeString) -> Array {
|
|
115
116
|
|
116
117
|
// pub fn pn_cleanpath(pth: MaybeString){}
|
117
118
|
|
118
|
-
|
119
|
+
pub fn pn_cleanpath_aggressive(pth: MaybeString) -> RString {
|
120
|
+
let path = cleanpath_aggressive::cleanpath_aggressive(
|
121
|
+
pth.ok().unwrap_or(RString::new("")).to_str()
|
122
|
+
);
|
123
|
+
|
124
|
+
RString::new(&path)
|
125
|
+
}
|
119
126
|
|
120
127
|
// pub fn pn_cleanpath_conservative(pth: MaybeString){}
|
121
128
|
|
@@ -133,9 +140,9 @@ pub fn pn_is_directory(pth: MaybeString) -> Boolean {
|
|
133
140
|
|
134
141
|
pub fn pn_dirname(pth: MaybeString) -> RString {
|
135
142
|
RString::new(
|
136
|
-
|
143
|
+
dirname::dirname(
|
137
144
|
pth.ok().unwrap_or(RString::new("")).to_str()
|
138
|
-
)
|
145
|
+
)
|
139
146
|
)
|
140
147
|
}
|
141
148
|
|
@@ -177,7 +184,7 @@ pub fn pn_entries_compat(pth: MaybeString) -> Array {
|
|
177
184
|
|
178
185
|
pub fn pn_extname(pth: MaybeString) -> RString {
|
179
186
|
RString::new(
|
180
|
-
|
187
|
+
extname::extname(pth.ok().unwrap_or(RString::new("")).to_str())
|
181
188
|
)
|
182
189
|
}
|
183
190
|
|
@@ -228,4 +235,3 @@ pub fn pn_is_relative(pth: MaybeString) -> Boolean {
|
|
228
235
|
// pub fn pn_rmtree(pth: MaybeString) -> NilClass {
|
229
236
|
// NilClass::new()
|
230
237
|
// }
|
231
|
-
|
data/src/plus.rs
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
use dirname::dirname;
|
2
|
+
use basename::basename;
|
3
|
+
use std::path::MAIN_SEPARATOR as SEP;
|
4
|
+
|
5
|
+
pub fn prepend_prefix(prefix: &str, relpath: &str) -> String {
|
6
|
+
let mut prefix: String = prefix.to_string();
|
7
|
+
if relpath.is_empty() {
|
8
|
+
dirname(&prefix).to_string()
|
9
|
+
} else if prefix.contains(&SEP.to_string()[..]) {
|
10
|
+
prefix = dirname(&prefix).to_string();
|
11
|
+
if basename(&format!("{}{}", &prefix, "a"), "") != "a" {
|
12
|
+
prefix = format!("{}{}", prefix, &SEP);
|
13
|
+
}
|
14
|
+
format!("{}{}", prefix, relpath)
|
15
|
+
} else {
|
16
|
+
format!("{}{}", prefix, relpath)
|
17
|
+
}
|
18
|
+
}
|
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.2.
|
4
|
+
version: 0.2.3
|
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:
|
11
|
+
date: 2018-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -114,14 +114,14 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0.
|
117
|
+
version: '0.51'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '0.
|
124
|
+
version: '0.51'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: stop_watch
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,20 +136,6 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 1.0.0
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: gruff
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - "~>"
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: 0.7.0
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - "~>"
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: 0.7.0
|
153
139
|
description: FasterPath is a reimplementation of Pathname for better performance.
|
154
140
|
email:
|
155
141
|
- 6ftdan@gmail.com
|
@@ -175,6 +161,7 @@ files:
|
|
175
161
|
- lib/faster_path/version.rb
|
176
162
|
- src/basename.rs
|
177
163
|
- src/chop_basename.rs
|
164
|
+
- src/cleanpath_aggressive.rs
|
178
165
|
- src/dirname.rs
|
179
166
|
- src/extname.rs
|
180
167
|
- src/helpers.rs
|
@@ -182,6 +169,7 @@ files:
|
|
182
169
|
- src/path_parsing.rs
|
183
170
|
- src/pathname.rs
|
184
171
|
- src/plus.rs
|
172
|
+
- src/prepend_prefix.rs
|
185
173
|
- src/rust_arch_bits.rs
|
186
174
|
homepage: https://github.com/danielpclark/faster_path
|
187
175
|
licenses:
|