faster_path 0.3.7 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -24
- data/lib/faster_path.rb +2 -26
- data/lib/faster_path/optional/monkeypatches.rb +2 -2
- data/lib/faster_path/thermite_initialize.rb +2 -1
- data/lib/faster_path/version.rb +1 -1
- data/src/basename.rs +63 -20
- data/src/chop_basename.rs +12 -13
- data/src/cleanpath_aggressive.rs +21 -33
- data/src/cleanpath_conservative.rs +27 -41
- data/src/dirname.rs +59 -19
- data/src/extname.rs +19 -57
- data/src/helpers.rs +13 -8
- data/src/lib.rs +14 -9
- data/src/memrnchr.rs +70 -0
- data/src/path_parsing.rs +23 -14
- data/src/pathname.rs +79 -122
- data/src/prepend_prefix.rs +12 -11
- data/src/relative_path_from.rs +17 -15
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71e809651aa4aa3df08645c40f0d616e3f061648ddeeb0e29086e578003df395
|
4
|
+
data.tar.gz: ded1645695ee0ddfd84261e25be66ed6f96b5386f45e093ecb46c0a6301f8896
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad20f8a279a81ccff6ce068f7c778649d3f71b59576d625e82e4bd1713c78d44dd10eb859b96b925f14c44f64171449c2fd17b46710a53a8e238f75ec17b5195
|
7
|
+
data.tar.gz: 0f2135684d07b33503b4ef62b4f6a750b5648d3b450d8ad0a55f9bdd54853355b86ba9e3e2fd546eb24a9148d9eace955b3642ad9bfeba4ca55c52e8de262bce
|
data/README.md
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
[![TravisCI Build Status](https://travis-ci.org/danielpclark/faster_path.svg?branch=master)](https://travis-ci.org/danielpclark/faster_path)
|
4
4
|
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/10ul0gk3cwhlt2lj/branch/master?svg=true)](https://ci.appveyor.com/project/danielpclark/faster-path/branch/master)
|
5
5
|
[![Latest Tag](https://img.shields.io/github/tag/danielpclark/faster_path.svg)](https://github.com/danielpclark/faster_path/tags)
|
6
|
-
[![Commits Since Last Release](https://img.shields.io/github/commits-since/danielpclark/faster_path/v0.3.
|
6
|
+
[![Commits Since Last Release](https://img.shields.io/github/commits-since/danielpclark/faster_path/v0.3.8.svg)](https://github.com/danielpclark/faster_path/pulse)
|
7
7
|
[![Binary Release](https://img.shields.io/github/release/danielpclark/faster_path.svg)](https://github.com/danielpclark/faster_path/releases)
|
8
|
-
[![Coverage Status](https://coveralls.io/repos/github/danielpclark/faster_path/badge.svg)](https://coveralls.io/github/danielpclark/faster_path)
|
8
|
+
[![Coverage Status](https://coveralls.io/repos/github/danielpclark/faster_path/badge.svg?branch=master)](https://coveralls.io/github/danielpclark/faster_path?branch=master)
|
9
9
|
[![Inline docs](http://inch-ci.org/github/danielpclark/faster_path.svg?branch=master)](http://inch-ci.org/github/danielpclark/faster_path)
|
10
10
|
[![Code Triagers Badge](https://www.codetriage.com/danielpclark/faster_path/badges/users.svg)](https://www.codetriage.com/danielpclark/faster_path)
|
11
11
|
[![Tweet This](https://raw.githubusercontent.com/danielpclark/faster_path/master/assets/tweet.png)](https://twitter.com/share?url=https%3A%2F%2Fgithub.com%2Fdanielpclark%2Ffaster_path&via=6ftdan&hashtags=Ruby&text=You%20could%20save%2015%25%20or%20more%20on%20website%20page%20load%20time%20by%20switching%20to%20the%20FasterPath%20gem.)
|
@@ -115,7 +115,7 @@ curl -sSf https://static.rust-lang.org/rustup.sh | sh
|
|
115
115
|
Add this line to your application's Gemfile:
|
116
116
|
|
117
117
|
```ruby
|
118
|
-
gem 'faster_path', '~> 0.3.
|
118
|
+
gem 'faster_path', '~> 0.3.8'
|
119
119
|
```
|
120
120
|
|
121
121
|
And then execute:
|
@@ -129,7 +129,7 @@ Or install it yourself as:
|
|
129
129
|
## Visual Benchmarks
|
130
130
|
|
131
131
|
Benchmarks in Faster Path now produce visual graph charts of performance improvements.
|
132
|
-
When you run `rake bench` the graph art will be placed in `doc/graph/`. Here's the performance
|
132
|
+
When you run `export GRAPH=1; bundle && rake bench` the graph art will be placed in `doc/graph/`. Here's the performance
|
133
133
|
improvement result for the `chop_basename` method.
|
134
134
|
|
135
135
|
![Visual Benchmark](https://raw.githubusercontent.com/danielpclark/faster_path/master/assets/chop_basename_benchmark.jpg "Visual Benchmark")
|
@@ -140,21 +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?` |
|
144
|
-
| `FasterPath.add_trailing_separator` | `Pathname#add_trailing_separator` |
|
145
|
-
| `FasterPath.
|
146
|
-
| `FasterPath.
|
147
|
-
| `FasterPath.
|
148
|
-
| `FasterPath.
|
149
|
-
| `FasterPath.
|
150
|
-
| `FasterPath.
|
151
|
-
| `FasterPath.
|
152
|
-
| `FasterPath.
|
153
|
-
| `FasterPath.
|
154
|
-
| `FasterPath.
|
155
|
-
| `FasterPath.
|
156
|
-
| `FasterPath.
|
157
|
-
| `FasterPath.
|
143
|
+
| `FasterPath.absolute?` | `Pathname#absolute?` | 95.8% |
|
144
|
+
| `FasterPath.add_trailing_separator` | `Pathname#add_trailing_separator` | 68.7% |
|
145
|
+
| `FasterPath.basename` | `File.basename` | 49.4% |
|
146
|
+
| `FasterPath.children` | `Pathname#children` | 39.2% |
|
147
|
+
| `FasterPath.chop_basename` | `Pathname#chop_basename` | 76.6% |
|
148
|
+
| `FasterPath.cleanpath_aggressive` | `Pathname#cleanpath_aggressive` | 78.2% |
|
149
|
+
| `FasterPath.cleanpath_conservative` | `Pathname#cleanpath_conservative` | 74.1% |
|
150
|
+
| `FasterPath.del_trailing_separator` | `Pathname#del_trailing_separator` | 87.7% |
|
151
|
+
| `FasterPath.directory?` | `Pathname#directory?` | 16.8% |
|
152
|
+
| `FasterPath.dirname` | `File.dirname` | 28.9% |
|
153
|
+
| `FasterPath.entries` | `Pathname#entries` | 36.1% |
|
154
|
+
| `FasterPath.extname` | `File.extname` | 66.2% |
|
155
|
+
| `FasterPath.has_trailing_separator?` | `Pathname#has_trailing_separator` | 86.3% |
|
156
|
+
| `FasterPath.plus` | `Pathname#join` | 67.9% |
|
157
|
+
| `FasterPath.plus` | `Pathname#plus` | 86.6% |
|
158
|
+
| `FasterPath.relative?` | `Pathname#relative?` | 87.2% |
|
159
|
+
| `FasterPath.relative_path_from` | `Pathname#relative_path_from` | 74.0% |
|
158
160
|
|
159
161
|
You may choose to use the methods directly, or scope change to rewrite behavior on the
|
160
162
|
standard library with the included refinements, or even call a method to monkeypatch
|
@@ -176,17 +178,17 @@ FasterPath.sledgehammer_everything!
|
|
176
178
|
|
177
179
|
## Optional Rust implementations
|
178
180
|
|
179
|
-
**These are stable, not performant, and not included in `
|
181
|
+
**These are stable, not performant, and not included in `Pathname` by default.**
|
180
182
|
|
181
|
-
These will **not** be included by default in monkey-patches.
|
183
|
+
These will **not** be included by default in monkey-patches. To try them with monkeypatching use the environment flag of `WITH_REGRESSION`. These methods are here to be improved upon.
|
182
184
|
|
183
185
|
|FasterPath Implementation|Ruby Implementation|
|
184
186
|
|---|---|
|
185
|
-
| `FasterPath.
|
186
|
-
| `FasterPath.
|
187
|
+
| `FasterPath.entries_compat` | `Pathname.entries` |
|
188
|
+
| `FasterPath.children_compat` | `Pathname.children` |
|
187
189
|
|
188
190
|
It's been my observation (and some others) that the Rust implementation of the C code for `File` has similar results but
|
189
|
-
performance seems to vary based on CPU cache on possibly 64bit/32bit system environments.
|
191
|
+
performance seems to vary based on CPU cache on possibly 64bit/32bit system environments. These are not included by default when the monkey patch method `FasterPath.sledgehammer_everything!` is executed.
|
190
192
|
|
191
193
|
## Getting Started with Development
|
192
194
|
|
data/lib/faster_path.rb
CHANGED
@@ -21,9 +21,6 @@ module FasterPath
|
|
21
21
|
private_class_method :basename
|
22
22
|
private_class_method :children
|
23
23
|
private_class_method :children_compat
|
24
|
-
private_class_method :chop_basename
|
25
|
-
private_class_method :entries
|
26
|
-
private_class_method :entries_compat
|
27
24
|
end
|
28
25
|
|
29
26
|
def self.rust_arch_bits
|
@@ -43,32 +40,11 @@ module FasterPath
|
|
43
40
|
end
|
44
41
|
|
45
42
|
def self.children(pth, with_directory=true)
|
46
|
-
|
47
|
-
return result if result
|
48
|
-
raise Errno::NOENT, "No such file or directory @ dir_initialize - #{pth}"
|
43
|
+
Public.send(:children, pth, with_directory)
|
49
44
|
end
|
50
45
|
|
51
46
|
def self.children_compat(pth, with_directory=true)
|
52
|
-
|
53
|
-
return result if result
|
54
|
-
raise Errno::NOENT, "No such file or directory @ dir_initialize - #{pth}"
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.chop_basename(pth)
|
58
|
-
result = Public.send(:chop_basename, pth)
|
59
|
-
result unless result.empty?
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.entries(pth)
|
63
|
-
result = Public.send(:entries, pth)
|
64
|
-
return result if result
|
65
|
-
raise Errno::NOENT, "No such file or directory @ dir_initialize - #{pth}"
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.entries_compat(pth)
|
69
|
-
result = Public.send(:entries_compat, pth)
|
70
|
-
return result if result
|
71
|
-
raise Errno::NOENT, "No such file or directory @ dir_initialize - #{pth}"
|
47
|
+
Public.send(:children_compat, pth, with_directory)
|
72
48
|
end
|
73
49
|
|
74
50
|
module Rust
|
@@ -10,7 +10,7 @@ module FasterPath
|
|
10
10
|
pth = pth.to_path if pth.respond_to? :to_path
|
11
11
|
raise TypeError unless pth.is_a?(String) && ext.is_a?(String)
|
12
12
|
FasterPath.basename(pth, ext)
|
13
|
-
end
|
13
|
+
end
|
14
14
|
|
15
15
|
def self.extname(pth)
|
16
16
|
pth = pth.to_path if pth.respond_to? :to_path
|
@@ -22,7 +22,7 @@ module FasterPath
|
|
22
22
|
pth = pth.to_path if pth.respond_to? :to_path
|
23
23
|
raise TypeError unless pth.is_a? String
|
24
24
|
FasterPath.dirname(pth)
|
25
|
-
end
|
25
|
+
end
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'rake/tasklib'
|
2
3
|
require_relative './version'
|
3
4
|
|
4
5
|
module Thermite
|
@@ -8,7 +9,7 @@ module Thermite
|
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
11
|
-
class Tasks
|
12
|
+
class Tasks < Rake::TaskLib
|
12
13
|
def github_download_uri(_tag, version)
|
13
14
|
"#{github_uri}/releases/download/v#{FasterPath::VERSION}/#{config.tarball_filename(version)}"
|
14
15
|
end
|
data/lib/faster_path/version.rb
CHANGED
data/src/basename.rs
CHANGED
@@ -1,26 +1,69 @@
|
|
1
1
|
extern crate memchr;
|
2
|
-
|
3
|
-
use path_parsing::{
|
4
|
-
|
5
|
-
pub fn basename<'a>(
|
6
|
-
let
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
|
3
|
+
use path_parsing::{find_last_sep_pos, find_last_non_sep_pos, find_last_dot_pos};
|
4
|
+
|
5
|
+
pub fn basename<'a>(path: &'a str, ext: &str) -> &'a str {
|
6
|
+
let bytes: &[u8] = path.as_bytes();
|
7
|
+
let mut left: usize = 0;
|
8
|
+
let mut right: usize = bytes.len();
|
9
|
+
if let Some(last_slash_pos) = find_last_sep_pos(bytes) {
|
10
|
+
if last_slash_pos == right - 1 {
|
11
|
+
if let Some(pos) = find_last_non_sep_pos(&bytes[..last_slash_pos]) {
|
12
|
+
right = pos + 1;
|
13
|
+
} else {
|
14
|
+
return "/";
|
15
|
+
}
|
16
|
+
if let Some(pos) = find_last_sep_pos(&bytes[..right]) {
|
17
|
+
left = pos + 1;
|
18
|
+
}
|
19
|
+
} else {
|
20
|
+
left = last_slash_pos + 1;
|
21
|
+
}
|
10
22
|
}
|
11
|
-
let
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
let mut name = &pth[name_start..name_end];
|
16
|
-
if ext == ".*" {
|
17
|
-
if let Some(dot_i) = memrchr('.' as u8, name.as_bytes()) {
|
18
|
-
name = &name[..dot_i];
|
23
|
+
let ext_bytes = ext.as_bytes();
|
24
|
+
if ext_bytes == b".*" {
|
25
|
+
if let Some(dot_pos) = find_last_dot_pos(&bytes[left..right]) {
|
26
|
+
right = left + dot_pos;
|
19
27
|
}
|
20
|
-
} else if
|
21
|
-
|
22
|
-
}
|
23
|
-
|
28
|
+
} else if bytes[left..right].ends_with(ext_bytes) {
|
29
|
+
right -= ext_bytes.len();
|
30
|
+
}
|
31
|
+
&path[left..right]
|
32
|
+
}
|
33
|
+
|
34
|
+
#[test]
|
35
|
+
fn absolute() {
|
36
|
+
assert_eq!(basename("/a/b///c", ""), "c");
|
37
|
+
}
|
38
|
+
|
39
|
+
#[test]
|
40
|
+
fn trailing_slashes_absolute() {
|
41
|
+
assert_eq!(basename("/a/b///c//////", ""), "c");
|
42
|
+
}
|
43
|
+
|
44
|
+
#[test]
|
45
|
+
fn relative() {
|
46
|
+
assert_eq!(basename("b///c", ""), "c");
|
47
|
+
}
|
48
|
+
|
49
|
+
#[test]
|
50
|
+
fn trailing_slashes_relative() {
|
51
|
+
assert_eq!(basename("b/c//", ""), "c");
|
52
|
+
}
|
53
|
+
|
54
|
+
#[test]
|
55
|
+
fn root() {
|
56
|
+
assert_eq!(basename("//c", ""), "c");
|
57
|
+
}
|
58
|
+
|
59
|
+
#[test]
|
60
|
+
fn trailing_slashes_root() {
|
61
|
+
assert_eq!(basename("//c//", ""), "c");
|
62
|
+
}
|
63
|
+
|
64
|
+
#[test]
|
65
|
+
fn trailing_slashes_relative_root() {
|
66
|
+
assert_eq!(basename("c//", ""), "c");
|
24
67
|
}
|
25
68
|
|
26
69
|
#[test]
|
data/src/chop_basename.rs
CHANGED
@@ -1,21 +1,14 @@
|
|
1
|
-
use
|
1
|
+
use path_parsing::{find_last_non_sep_pos, find_last_sep_pos};
|
2
2
|
use std::str;
|
3
3
|
|
4
4
|
pub fn chop_basename<'a>(input: &'a str) -> Option<(&'a str, &'a str)> {
|
5
|
-
|
5
|
+
let bytes = input.as_bytes();
|
6
|
+
let len = find_last_non_sep_pos(&bytes)? + 1;
|
7
|
+
let base_start = find_last_sep_pos(&bytes[..len]).map_or(0, |pos| pos + 1);
|
8
|
+
if base_start == len {
|
6
9
|
return None;
|
7
10
|
}
|
8
|
-
|
9
|
-
let input = input.trim_right_matches(MAIN_SEPARATOR);
|
10
|
-
let end = input.rsplitn(2, MAIN_SEPARATOR).nth(0).unwrap().len();
|
11
|
-
let base = &input[input.len()-end..input.len()];
|
12
|
-
let directory = &input[0..input.len()-base.len()];
|
13
|
-
|
14
|
-
if directory.is_empty() && (base.is_empty() || base.chars().next().unwrap() == MAIN_SEPARATOR) {
|
15
|
-
return None
|
16
|
-
};
|
17
|
-
|
18
|
-
Some((directory, base))
|
11
|
+
Some((&input[0..base_start], &input[base_start..len]))
|
19
12
|
}
|
20
13
|
|
21
14
|
#[test]
|
@@ -27,5 +20,11 @@ fn it_chops_the_basename_and_dirname() {
|
|
27
20
|
assert_eq!(chop_basename("asdf.txt"), Some(("", "asdf.txt")) );
|
28
21
|
assert_eq!(chop_basename("asdf/"), Some(("", "asdf")) );
|
29
22
|
assert_eq!(chop_basename("/asdf/"), Some(("/", "asdf")) );
|
23
|
+
assert_eq!(chop_basename("a///b"), Some(("a///", "b")) );
|
24
|
+
assert_eq!(chop_basename("a///b//"), Some(("a///", "b")) );
|
25
|
+
assert_eq!(chop_basename("/a///b//"), Some(("/a///", "b")) );
|
26
|
+
assert_eq!(chop_basename("/a///b//"), Some(("/a///", "b")) );
|
27
|
+
|
28
|
+
assert_eq!(chop_basename("./../..///.../..//"), Some(("./../..///.../", "..")));
|
30
29
|
}
|
31
30
|
|
data/src/cleanpath_aggressive.rs
CHANGED
@@ -1,32 +1,24 @@
|
|
1
|
+
use std::borrow::Cow;
|
1
2
|
use prepend_prefix::prepend_prefix;
|
2
3
|
use basename::basename;
|
3
4
|
use chop_basename::chop_basename;
|
4
|
-
|
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.clone()) {
|
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
|
-
}
|
5
|
+
use path_parsing::{SEP_STR, contains_sep};
|
26
6
|
|
7
|
+
pub fn cleanpath_aggressive(path: &str) -> Cow<str> {
|
8
|
+
let mut names: Vec<&str> = vec![];
|
9
|
+
let mut prefix = path;
|
10
|
+
while let Some((ref p, ref base)) = chop_basename(&prefix) {
|
11
|
+
prefix = p;
|
12
|
+
match base.as_ref() {
|
13
|
+
"." => {}
|
14
|
+
".." => names.push(base),
|
15
|
+
_ => {
|
16
|
+
if names.last() == Some(&"..") {
|
17
|
+
names.pop();
|
18
|
+
} else {
|
19
|
+
names.push(base);
|
27
20
|
}
|
28
|
-
}
|
29
|
-
None => break,
|
21
|
+
}
|
30
22
|
}
|
31
23
|
}
|
32
24
|
// // Windows Feature
|
@@ -35,16 +27,12 @@ pub fn cleanpath_aggressive(path: &str) -> String {
|
|
35
27
|
// pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
|
36
28
|
// ```
|
37
29
|
//
|
38
|
-
if basename(&
|
39
|
-
|
40
|
-
|
41
|
-
let _ = names.shift();
|
42
|
-
} else {
|
43
|
-
break
|
44
|
-
}
|
45
|
-
}
|
30
|
+
if contains_sep(basename(&prefix, "").as_bytes()) {
|
31
|
+
let len = names.iter().rposition(|&c| c != "..").map_or(0, |pos| pos + 1);
|
32
|
+
names.truncate(len);
|
46
33
|
}
|
47
|
-
|
34
|
+
names.reverse();
|
35
|
+
prepend_prefix(&prefix, &names.join(&SEP_STR))
|
48
36
|
}
|
49
37
|
|
50
38
|
#[test]
|
@@ -1,25 +1,18 @@
|
|
1
|
+
use std::borrow::Cow;
|
2
|
+
use std::path::MAIN_SEPARATOR;
|
1
3
|
use prepend_prefix::prepend_prefix;
|
2
4
|
use basename::basename;
|
3
5
|
use dirname::dirname;
|
4
6
|
use chop_basename::chop_basename;
|
5
|
-
|
6
|
-
use self::array_tool::vec::Shift;
|
7
|
-
use std::path::MAIN_SEPARATOR;
|
7
|
+
use path_parsing::{SEP_STR, contains_sep};
|
8
8
|
|
9
|
-
pub fn cleanpath_conservative(path: &str) ->
|
10
|
-
let
|
11
|
-
let mut
|
12
|
-
let
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
pre = p.to_string();
|
17
|
-
match base.as_ref() {
|
18
|
-
"." => {},
|
19
|
-
_ => names.unshift(base.to_string()),
|
20
|
-
}
|
21
|
-
},
|
22
|
-
None => break,
|
9
|
+
pub fn cleanpath_conservative(path: &str) -> Cow<str> {
|
10
|
+
let mut names: Vec<&str> = vec![];
|
11
|
+
let mut prefix = path;
|
12
|
+
while let Some((ref p, ref base)) = chop_basename(&prefix) {
|
13
|
+
prefix = p;
|
14
|
+
if base != &"." {
|
15
|
+
names.push(base);
|
23
16
|
}
|
24
17
|
}
|
25
18
|
// // Windows Feature
|
@@ -28,33 +21,26 @@ pub fn cleanpath_conservative(path: &str) -> String {
|
|
28
21
|
// pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
|
29
22
|
// ```
|
30
23
|
//
|
31
|
-
if basename(&
|
32
|
-
|
33
|
-
|
34
|
-
let _ = names.shift();
|
35
|
-
} else {
|
36
|
-
break
|
37
|
-
}
|
38
|
-
}
|
24
|
+
if contains_sep(basename(&prefix, "").as_bytes()) {
|
25
|
+
let len = names.iter().rposition(|&c| c != "..").map_or(0, |pos| pos + 1);
|
26
|
+
names.truncate(len);
|
39
27
|
}
|
40
28
|
|
41
|
-
|
42
|
-
|
43
|
-
|
29
|
+
let last_name = match names.first() {
|
30
|
+
Some(&name) => name,
|
31
|
+
None => return dirname(&prefix).into(),
|
32
|
+
};
|
44
33
|
|
45
|
-
if
|
46
|
-
names.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
if !(last == Some(&".".to_string()) || last == Some(&"..".to_string())) &&
|
53
|
-
chop_basename(path).map(|(a, b)| a.len() + b.len()).unwrap() < path.len() {
|
54
|
-
format!("{}{}", last.unwrap(), MAIN_SEPARATOR)
|
34
|
+
if last_name != ".." && basename(&path, "") == "." {
|
35
|
+
names.reverse();
|
36
|
+
names.push(".");
|
37
|
+
} else if last_name != "." && last_name != ".." &&
|
38
|
+
chop_basename(path).map(|(a, b)| a.len() + b.len()).unwrap() < path.len() {
|
39
|
+
return format!("{}{}", last_name, MAIN_SEPARATOR).into();
|
55
40
|
} else {
|
56
|
-
|
41
|
+
names.reverse();
|
57
42
|
}
|
43
|
+
prepend_prefix(&prefix, &names.join(&SEP_STR))
|
58
44
|
}
|
59
45
|
|
60
46
|
#[test]
|
@@ -97,11 +83,11 @@ fn it_conservatively_cleans_the_path() {
|
|
97
83
|
// DOSISH_DRIVE_LETTER = File.dirname("A:") == "A:."
|
98
84
|
// DOSISH_UNC = File.dirname("//") == "//"
|
99
85
|
//
|
100
|
-
//
|
86
|
+
//
|
101
87
|
// if DOSISH
|
102
88
|
// assert_eq!(cleanpath_conservative, 'c:/foo/bar', 'c:\\foo\\bar')
|
103
89
|
// end
|
104
|
-
//
|
90
|
+
//
|
105
91
|
// if DOSISH_UNC
|
106
92
|
// assert_eq!(cleanpath_conservative, '//', '//')
|
107
93
|
// else
|