faster_path 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9d4375a359961afcc5baa61ac3c67569797e7f2f
4
- data.tar.gz: b73c128d729d3fd37d5b125f584149466463a83b
3
+ metadata.gz: 8487e703f71a357f9d42a04c8f4ba2b98291bad4
4
+ data.tar.gz: 4c2c24ac1f470bfddbae8ccbfec0447961476e07
5
5
  SHA512:
6
- metadata.gz: 42ab2f7cf2f3d45acf871b1169722905bc7bc7081048fc8ec23d74f5163dc4a25c65247c01ca97edd9cb2202886e8a482a9c40518301a59a216c58ed76125ccd
7
- data.tar.gz: 1800e1268585ef4970508199ea494be7aaf5382229dc7d4f1f5486bda8b94c3576144f5afb9783400a555509b8ac485a5d7e1a924049e9baa46ccb8470053958
6
+ metadata.gz: 57e7745e69f3f30b32981731c250ffa001e4f4f58b5a4b44a0b6558ea786a0a741dc0ce225c959998055ed99c8070dcc78f995ec3c3bb538258cee9429bb71bc
7
+ data.tar.gz: b30307165e8fbdee36a2dd62bf92618af2f062d8bd93d94c4324c650d6c282fc45778508930d77e2f991a6a998ba6281dad53a742dca4c45751d346e42b3714f
data/Cargo.lock CHANGED
@@ -1,20 +1,26 @@
1
- [root]
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
- "ruby-sys 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
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 = "array_tool"
12
- version = "0.4.1"
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.2.8"
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
@@ -13,6 +13,7 @@ name = "faster_path"
13
13
  crate-type = ["dylib"]
14
14
 
15
15
  [dependencies]
16
- ruby-sys = "0.2.20"
17
16
  ruru = "0.9.3"
18
17
  array_tool = "0.4.1"
18
+ lazy_static = "1.0"
19
+ memchr = "2.0.1"
@@ -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
  [![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.2.1.svg)](https://github.com/danielpclark/faster_path/pulse)
6
+ [![Commits Since Last Release](https://img.shields.io/github/commits-since/danielpclark/faster_path/v0.2.3.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
8
  [![Coverage Status](https://coveralls.io/repos/github/danielpclark/faster_path/badge.svg)](https://coveralls.io/github/danielpclark/faster_path)
9
9
  [![Inline docs](http://inch-ci.org/github/danielpclark/faster_path.svg?branch=master)](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.1.13'
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` | 13.6% |
146
- | `FasterPath.chop_basename` | `Pathname#chop_basename` | 55.8% |
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.5% |
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 test: [:cargo, :minitest, :lint, :pbench] do |_t|
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 :mspec_full do
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 :mspec_encoding_full do
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
@@ -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.47"
35
- unless ENV['CI']
36
- spec.add_development_dependency "stop_watch", "~> 1.0.0"
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
@@ -15,20 +15,21 @@ module FasterPath
15
15
  call
16
16
 
17
17
  FasterPathname::Public.class_eval do
18
- private :absolute?
19
- private :add_trailing_separator
20
- private :basename
21
- private :children # String results
22
- private :children_compat # wrap Pathname on each
23
- private :chop_basename
24
- private :directory?
25
- private :dirname
26
- private :entries # String results
27
- private :entries_compat # wrap Pathname on each
28
- private :extname
29
- private :has_trailing_separator?
30
- private :plus
31
- private :relative?
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.allocate.send(:absolute?, pth)
64
+ FasterPathname::Public.send(:absolute?, pth)
64
65
  end
65
66
 
66
67
  def self.add_trailing_separator(pth)
67
- FasterPathname::Public.allocate.send(:add_trailing_separator, pth)
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.allocate.send(:basename, pth, ext)
76
+ FasterPathname::Public.send(:basename, pth, ext)
76
77
  end
77
78
 
78
79
  def self.children(pth, with_directory=true)
79
- FasterPathname::Public.allocate.send(:children, pth, with_directory)
80
+ FasterPathname::Public.send(:children, pth, with_directory)
80
81
  end
81
82
 
82
83
  def self.chop_basename(pth)
83
- result = FasterPathname::Public.allocate.send(:chop_basename, pth)
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.allocate.send(:directory?, pth)
93
+ FasterPathname::Public.send(:directory?, pth)
89
94
  end
90
95
 
91
96
  def self.dirname(pth)
92
- FasterPathname::Public.allocate.send(:dirname, pth)
97
+ FasterPathname::Public.send(:dirname, pth)
93
98
  end
94
99
 
95
100
  def self.entries(pth)
96
- FasterPathname::Public.allocate.send(:entries, pth)
101
+ FasterPathname::Public.send(:entries, pth)
97
102
  end
98
103
 
99
104
  def self.extname(pth)
100
- FasterPathname::Public.allocate.send(:extname, pth)
105
+ FasterPathname::Public.send(:extname, pth)
101
106
  end
102
107
 
103
108
  def self.has_trailing_separator?(pth)
104
- FasterPathname::Public.allocate.send(:has_trailing_separator?, pth)
109
+ FasterPathname::Public.send(:has_trailing_separator?, pth)
105
110
  end
106
111
 
107
112
  def self.plus(pth, pth2)
108
- FasterPathname::Public.allocate.send(:plus, pth, pth2)
113
+ FasterPathname::Public.send(:plus, pth, pth2)
109
114
  end
110
115
 
111
116
  def self.relative?(pth)
112
- FasterPathname::Public.allocate.send(:relative?, pth)
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
@@ -44,6 +44,11 @@ module FasterPath
44
44
  end
45
45
  private :chop_basename
46
46
 
47
+ def cleanpath_aggressive
48
+ Pathname.new(FasterPath.cleanpath_aggressive(@path))
49
+ end
50
+ private :cleanpath_aggressive
51
+
47
52
  def directory?
48
53
  FasterPath.directory?(@path)
49
54
  end
@@ -1,3 +1,3 @@
1
1
  module FasterPath
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -1,23 +1,29 @@
1
- extern crate array_tool;
2
- use path_parsing::extract_last_path_segment;
3
- use self::array_tool::string::Squeeze;
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) -> String {
6
- // Known edge case
7
- match &pth.squeeze("/")[..] {
8
- "/" => { return "/".to_string() }
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
- let mut name = extract_last_path_segment(pth);
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) = name.rfind('.') {
16
- name = &name[0..dot_i];
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.to_string()
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
@@ -1,27 +1,22 @@
1
- use std::path::MAIN_SEPARATOR;
2
- use path_parsing::{last_sep_i, last_non_sep_i, last_non_sep_i_before};
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) -> String {
5
- let r_str = path;
6
- if r_str.is_empty() {
7
- return ".".to_string();
8
- }
9
- let non_sep_i = last_non_sep_i(r_str);
10
- if non_sep_i == -1 {
11
- return MAIN_SEPARATOR.to_string();
12
- }
13
- let sep_i = last_sep_i(r_str, non_sep_i);
14
- if sep_i == -1 {
15
- return ".".to_string();
16
- }
17
- if sep_i == 0 {
18
- return MAIN_SEPARATOR.to_string();
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
 
@@ -1,13 +1,13 @@
1
1
  use path_parsing::extract_last_path_segment;
2
2
 
3
- pub fn extname(pth: &str) -> String {
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 String::from(&name[dot_i..])
8
+ return &name[dot_i..]
9
9
  }
10
10
  }
11
11
 
12
- String::from("")
12
+ ""
13
13
  }
@@ -1,19 +1,7 @@
1
- extern crate ruby_sys;
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
- AnyObject::from(str_to_value(str_var))
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
- // fn r_cleanpath_aggressive(pth: RString){}
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.def("absolute?", pub_is_absolute);
151
- itself.def("add_trailing_separator", pub_add_trailing_separator);
152
- itself.def("basename", pub_basename);
153
- itself.def("children", pub_children);
154
- itself.def("children_compat", pub_children_compat);
155
- itself.def("chop_basename", pub_chop_basename);
156
- itself.def("directory?", pub_is_directory);
157
- itself.def("dirname", pub_dirname);
158
- itself.def("entries", pub_entries);
159
- itself.def("entries_compat", pub_entries_compat);
160
- itself.def("extname", pub_extname);
161
- itself.def("has_trailing_separator?", pub_has_trailing_separator);
162
- itself.def("plus", pub_plus);
163
- itself.def("relative?", pub_is_relative);
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
  }
@@ -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
- static SEP: u8 = MAIN_SEPARATOR as u8;
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
- // Works with bytes directly because MAIN_SEPARATOR is always in the ASCII 7-bit range so we can
7
- // avoid the overhead of full UTF-8 processing.
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
- }
@@ -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
- &basename::basename(
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
- // pub fn pn_cleanpath_aggressive(pth: MaybeString){}
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
- &dirname::dirname(
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
- &extname::extname(pth.ok().unwrap_or(RString::new("")).to_str())[..]
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
-
@@ -73,7 +73,7 @@ pub fn plus_paths(path1: &str, path2: &str) -> String {
73
73
  if r1 {
74
74
  result = prefix1.to_string();
75
75
  } else {
76
- result = dirname(&prefix1[..]);
76
+ result = dirname(&prefix1[..]).to_string();
77
77
  }
78
78
  }
79
79
 
@@ -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.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: 2017-09-25 00:00:00.000000000 Z
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.47'
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.47'
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: