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 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: