faster_path 0.3.10 → 0.5.0

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
  SHA256:
3
- metadata.gz: 32af4c3fa17e05003792d14b3e8a34ce26fd206395f345fc58a13c8cc63b37b7
4
- data.tar.gz: 7ec503bf0957f176fa5daa1d4910a67af9c3b06bb391e573586fcaadc1157a88
3
+ metadata.gz: 9fb5780bd8ce8ea17d538b540ac69b1c023118d1351e167cde418ee48a4f8085
4
+ data.tar.gz: b12bc7a5ab8e4e26cfd46328bdb9e4b57eea367a9c40e76aeba74e12f06eb0e7
5
5
  SHA512:
6
- metadata.gz: ff3f4a219cb46f561eec9a2138d1282773ad2ceddcd0664202c2396202efbb1ecb2b8839347dd65bcf595faf93b6d6d6b85d6a912c18380b8ff10ccd878379ab
7
- data.tar.gz: 27e3886927a1479b5d28e1b2a5d96cb5bb86c240b87664010b1be9d181afebf456476a43c1e7843f890b2af581ccd398dca91c3dd6f1021380e156402f2d90ab
6
+ metadata.gz: fa615d0278378e74432832369cf56b16147ecc0e5e27bd12b1fd90c2690fab41dc68fd3042e8dd7c92b8ebb7741f7d08e9db25bd0cec61b384b520f9bd8b400a
7
+ data.tar.gz: 905389671e4062ef0824e7fb7af8d05fefb1df0ad2a5919bc8a54a8506309ba77cea577859ea49da4e15616fd2fb4bf1d025e5082baef6e61bf18c0c9799d000
data/Cargo.lock CHANGED
@@ -1,57 +1,39 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
1
5
  [[package]]
2
6
  name = "faster_path"
3
- version = "0.0.1"
7
+ version = "0.5.0"
4
8
  dependencies = [
5
- "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
6
- "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
7
- "ruby-sys 0.3.0 (git+https://github.com/danielpclark/ruby-sys?branch=playground)",
8
- "ruru 0.9.3 (git+https://github.com/danielpclark/ruru?branch=playground)",
9
+ "memchr",
10
+ "rutie",
9
11
  ]
10
12
 
11
13
  [[package]]
12
14
  name = "lazy_static"
13
- version = "0.2.11"
14
- source = "registry+https://github.com/rust-lang/crates.io-index"
15
-
16
- [[package]]
17
- name = "lazy_static"
18
- version = "1.0.0"
15
+ version = "1.5.1"
19
16
  source = "registry+https://github.com/rust-lang/crates.io-index"
17
+ checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb"
20
18
 
21
19
  [[package]]
22
20
  name = "libc"
23
- version = "0.2.39"
21
+ version = "0.2.189"
24
22
  source = "registry+https://github.com/rust-lang/crates.io-index"
23
+ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
25
24
 
26
25
  [[package]]
27
26
  name = "memchr"
28
- version = "2.0.1"
27
+ version = "2.8.3"
29
28
  source = "registry+https://github.com/rust-lang/crates.io-index"
30
- dependencies = [
31
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
32
- ]
29
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
33
30
 
34
31
  [[package]]
35
- name = "ruby-sys"
36
- version = "0.3.0"
37
- source = "git+https://github.com/danielpclark/ruby-sys?branch=playground#a3d47da5f9d1e597c62a8f03fb7d3a3596393c47"
38
- dependencies = [
39
- "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
40
- ]
41
-
42
- [[package]]
43
- name = "ruru"
44
- version = "0.9.3"
45
- source = "git+https://github.com/danielpclark/ruru?branch=playground#ab84ad4b97c41bfe6fd6d0f8540b2efd77583561"
32
+ name = "rutie"
33
+ version = "0.13.1"
34
+ source = "registry+https://github.com/rust-lang/crates.io-index"
35
+ checksum = "30d1529470ad0b69b81a6d0224632d00c01b46ef671452e24407512165b7ed84"
46
36
  dependencies = [
47
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
48
- "ruby-sys 0.3.0 (git+https://github.com/danielpclark/ruby-sys?branch=playground)",
37
+ "lazy_static",
38
+ "libc",
49
39
  ]
50
-
51
- [metadata]
52
- "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
53
- "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
54
- "checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
55
- "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
56
- "checksum ruby-sys 0.3.0 (git+https://github.com/danielpclark/ruby-sys?branch=playground)" = "<none>"
57
- "checksum ruru 0.9.3 (git+https://github.com/danielpclark/ruru?branch=playground)" = "<none>"
data/Cargo.toml CHANGED
@@ -1,22 +1,18 @@
1
1
  [package]
2
2
  name = "faster_path"
3
- version = "0.0.1"
3
+ version = "0.5.0"
4
4
  authors = ["Daniel P. Clark <6ftdan@gmail.com>"]
5
5
  description = "Alternative to Pathname"
6
6
  homepage = "https://github.com/danielpclark/faster_path"
7
7
  repository = "https://github.com/danielpclark/faster_path"
8
8
  license = "MIT OR Apache-2.0"
9
9
  readme = "README.md"
10
-
11
- [package.metadata.thermite]
12
- github_releases = true
10
+ edition = "2021"
13
11
 
14
12
  [lib]
15
13
  name = "faster_path"
16
- crate-type = ["dylib"]
14
+ crate-type = ["cdylib"]
17
15
 
18
16
  [dependencies]
19
- ruby-sys = { git = "https://github.com/danielpclark/ruby-sys", branch = "playground" }
20
- ruru = { git = "https://github.com/danielpclark/ruru", branch = "playground" }
21
- lazy_static = "1.0"
22
- memchr = "2.0.1"
17
+ rutie = "0.13.1"
18
+ memchr = "2"
data/Gemfile CHANGED
@@ -1,8 +1,4 @@
1
- source 'https://rubygems.org' do
2
- # Specify your gem's dependencies in faster_path.gemspec
3
- gemspec
1
+ source 'https://rubygems.org'
4
2
 
5
- group :test do
6
- gem 'coveralls', require: false
7
- end
8
- end
3
+ # Specify your gem's dependencies in faster_path.gemspec
4
+ gemspec
data/README.md CHANGED
@@ -1,11 +1,8 @@
1
1
  # FasterPath
2
2
  [![Gem Version](https://badge.fury.io/rb/faster_path.svg)](https://badge.fury.io/rb/faster_path)
3
- [![TravisCI Build Status](https://travis-ci.org/danielpclark/faster_path.svg?branch=master)](https://travis-ci.org/danielpclark/faster_path)
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)
3
+ [![CI](https://github.com/danielpclark/faster_path/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/danielpclark/faster_path/actions/workflows/ci.yml)
5
4
  [![Latest Tag](https://img.shields.io/github/tag/danielpclark/faster_path.svg)](https://github.com/danielpclark/faster_path/tags)
6
5
  [![Commits Since Last Release](https://img.shields.io/github/commits-since/danielpclark/faster_path/v0.3.10.svg)](https://github.com/danielpclark/faster_path/pulse)
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?branch=master)](https://coveralls.io/github/danielpclark/faster_path?branch=master)
9
6
  [![Inline docs](http://inch-ci.org/github/danielpclark/faster_path.svg?branch=master)](http://inch-ci.org/github/danielpclark/faster_path)
10
7
  [![Code Triagers Badge](https://www.codetriage.com/danielpclark/faster_path/badges/users.svg)](https://www.codetriage.com/danielpclark/faster_path)
11
8
 
@@ -103,7 +100,7 @@ So now we have some real numbers to work with We can be generoues and use 66% a
103
100
 
104
101
  ## What Rails Versions Will This Apply To?
105
102
 
106
- As mentioned earlier Sprockets, which handles assets, changed away from using `Pathname` at all when moving from major version 2 to 3. So if you're using Sprockets 3 or later you won't reap the biggest performance reqards from using this gem for now _(it's my goal to have this project become a core feature that Rails depends on and yes… that's a big ask)_. That is unless you write you're own implementation to re-integrate the use of `Pathname` and `FasterPath` into your asset handling library. For now just know that the Sprockets 2 series primarily works with Rails 4.1 and earlier. It may work in later Rails versions but I have not investigated this.
103
+ As mentioned earlier Sprockets, which handles assets, changed away from using `Pathname` at all when moving from major version 2 to 3. So if you're using Sprockets 3 or later you won't reap the biggest performance rewards from using this gem for now _(it's my goal to have this project become a core feature that Rails depends on and yes… that's a big ask)_. That is unless you write you're own implementation to re-integrate the use of `Pathname` and `FasterPath` into your asset handling library. For now just know that the Sprockets 2 series primarily works with Rails 4.1 and earlier. It may work in later Rails versions but I have not investigated this.
107
104
 
108
105
  ## Status
109
106
 
@@ -111,22 +108,29 @@ As mentioned earlier Sprockets, which handles assets, changed away from using `P
111
108
  * Methods are stable
112
109
  * Thoroughly tested
113
110
  * Testers and developers are most welcome
114
- * Windows & encoding support is underway!
111
+ * Windows: paths follow Ruby's Windows rules (`\` and `/` separators, drive letters, UNC paths)
112
+ * Paths keep their encoding, as with Ruby's own methods
113
+
114
+ ## Requirements
115
+
116
+ * Ruby 3.2, 3.3 or 3.4 (the Rust extension is built with [Rutie](https://github.com/danielpclark/rutie) 0.13, which supports these)
117
+ * Rust 1.71 or later: `gem install` builds the extension with Cargo (through the
118
+ [rutie](https://rubygems.org/gems/rutie) gem's Rake task) and keeps only the built library
115
119
 
116
120
  ## Installation
117
121
 
118
- Ensure Rust is installed:
122
+ Ensure Rust is installed, with `cargo` on your `PATH`:
119
123
 
120
- [Rust Downloads](https://www.rust-lang.org/downloads.html)
124
+ [Install Rust](https://www.rust-lang.org/tools/install)
121
125
 
122
126
  ```
123
- curl -sSf https://static.rust-lang.org/rustup.sh | sh
127
+ curl -sSf https://sh.rustup.rs | sh
124
128
  ```
125
129
 
126
130
  Add this line to your application's Gemfile:
127
131
 
128
132
  ```ruby
129
- gem 'faster_path', '~> 0.3.10'
133
+ gem 'faster_path', '~> 0.5.0'
130
134
  ```
131
135
 
132
136
  And then execute:
@@ -137,6 +141,12 @@ Or install it yourself as:
137
141
 
138
142
  $ gem install faster_path
139
143
 
144
+ Installing compiles the Rust extension for the Ruby doing the installing ("Building native
145
+ extensions. This could take a while..."), which takes about a minute the first time while Cargo
146
+ fetches and builds the dependencies. If Rust is missing, the install fails at that step with
147
+ Cargo not being found; install Rust and run it again. Nothing is downloaded from GitHub: there are
148
+ no prebuilt binaries.
149
+
140
150
  ## Visual Benchmarks
141
151
 
142
152
  Benchmarks in Faster Path now produce visual graph charts of performance improvements.
@@ -147,27 +157,35 @@ improvement result for the `chop_basename` method.
147
157
 
148
158
  ## Usage
149
159
 
160
+ Add the proper require to your project.
161
+
162
+ ```ruby
163
+ require "faster_path"
164
+ ```
165
+
150
166
  Current methods implemented:
151
167
 
152
- |FasterPath Rust Implementation|Ruby 2.5.0 Implementation|Time Shaved Off|
153
- |---|---|:---:|
154
- | `FasterPath.absolute?` | `Pathname#absolute?` | 95.3% |
155
- | `FasterPath.add_trailing_separator` | `Pathname#add_trailing_separator` | 48.4% |
156
- | `FasterPath.basename` | `File.basename` | 12.0% |
157
- | `FasterPath.children` | `Pathname#children` | 34.4% |
158
- | `FasterPath.chop_basename` | `Pathname#chop_basename` | 83.4% |
159
- | `FasterPath.cleanpath_aggressive` | `Pathname#cleanpath_aggressive` | 94.1% |
160
- | `FasterPath.cleanpath_conservative` | `Pathname#cleanpath_conservative` | 93.5% |
161
- | `FasterPath.del_trailing_separator` | `Pathname#del_trailing_separator` | 85.4% |
162
- | `FasterPath.directory?` | `Pathname#directory?` | 6.4% |
163
- | `FasterPath.dirname` | `File.dirname` | 55.4% |
164
- | `FasterPath.entries` | `Pathname#entries` | 41.0% |
165
- | `FasterPath.extname` | `File.extname` | 63.1% |
166
- | `FasterPath.has_trailing_separator?` | `Pathname#has_trailing_separator` | 88.9% |
167
- | `FasterPath.plus` | `Pathname#join` | 79.1% |
168
- | `FasterPath.plus` | `Pathname#plus` | 94.7% |
169
- | `FasterPath.relative?` | `Pathname#relative?` | 92.6% |
170
- | `FasterPath.relative_path_from` | `Pathname#relative_path_from` | 93.3% |
168
+ |FasterPath Rust Implementation|Ruby Implementation|Time Shaved Off (Ruby 3.4)|Time Shaved Off (Ruby 3.3)|Time Shaved Off (Ruby 3.2)|
169
+ |---|---|:---:|:---:|:---:|
170
+ | `FasterPath.absolute?` | `Pathname#absolute?` | 55.5% | 53.2% | 43.1% |
171
+ | `FasterPath.add_trailing_separator` | `Pathname#add_trailing_separator` | 87.4% | 85.3% | 85.8% |
172
+ | `FasterPath.basename` | `File.basename` | 30.7% | 22.2% | 27.5% |
173
+ | `FasterPath.children` | `Pathname#children` | 65.0% | 55.1% | 55.4% |
174
+ | `FasterPath.chop_basename` | `Pathname#chop_basename` | 75.3% | 73.5% | 72.8% |
175
+ | `FasterPath.cleanpath_aggressive` | `Pathname#cleanpath_aggressive` | 92.4% | 92.2% | 92.4% |
176
+ | `FasterPath.cleanpath_conservative` | `Pathname#cleanpath_conservative` | 91.4% | 91.3% | 91.8% |
177
+ | `FasterPath.del_trailing_separator` | `Pathname#del_trailing_separator` | 89.1% | 87.9% | 87.8% |
178
+ | `FasterPath.directory?` | `Pathname#directory?` | 41.5% | 39.9% | 44.2% |
179
+ | `FasterPath.dirname` | `File.dirname` | 52.0% | 40.3% | 40.8% |
180
+ | `FasterPath.entries` | `Pathname#entries` | 57.8% | 42.4% | 45.9% |
181
+ | `FasterPath.extname` | `File.extname` | 69.4% | 66.7% | 69.2% |
182
+ | `FasterPath.has_trailing_separator?` | `Pathname#has_trailing_separator` | 93.4% | 92.8% | 91.7% |
183
+ | `FasterPath.join` | `Pathname#join` | 89.1% | 89.0% | 88.4% |
184
+ | `FasterPath.plus` | `Pathname#plus` | 95.5% | 94.7% | 94.5% |
185
+ | `FasterPath.relative?` | `Pathname#relative?` | 66.9% | 66.3% | 60.4% |
186
+ | `FasterPath.relative_path_from` | `Pathname#relative_path_from` | 94.4% | 94.6% | 94.2% |
187
+
188
+ See [Benchmarks](#benchmarks) for how these are measured.
171
189
 
172
190
  You may choose to use the methods directly, or scope change to rewrite behavior on the
173
191
  standard library with the included refinements, or even call a method to monkeypatch
@@ -193,14 +211,74 @@ FasterPath.sledgehammer_everything!
193
211
 
194
212
  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.
195
213
 
196
- |FasterPath Implementation|Ruby Implementation|
197
- |---|---|
198
- | `FasterPath.entries_compat` | `Pathname.entries` |
199
- | `FasterPath.children_compat` | `Pathname.children` |
214
+ |FasterPath Implementation|Ruby Implementation|Time Shaved Off (Ruby 3.4)|Time Shaved Off (Ruby 3.3)|Time Shaved Off (Ruby 3.2)|
215
+ |---|---|:---:|:---:|:---:|
216
+ | `FasterPath.entries_compat` | `Pathname.entries` | 35.7% | 22.0% | 15.9% |
217
+ | `FasterPath.children_compat` | `Pathname.children` | 46.7% | 33.6% | 32.3% |
200
218
 
201
219
  It's been my observation (and some others) that the Rust implementation of the C code for `File` has similar results but
202
220
  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.
203
221
 
222
+ ## Benchmarks
223
+
224
+ The "Time Shaved Off" figures come from the project's Pinch-bench (`rake pbench`, in
225
+ `test/pbench`): each method runs against Ruby's own implementation, alternating with it round by
226
+ round, and the result is how much less time FasterPath's best round took than Ruby's best round.
227
+ They are the median of 3 runs of `LONG_RUN=30 rake pbench` (5 rounds of 300,000 calls of each
228
+ method) on Linux x86_64, each run pinned to one CPU core, with Ruby 3.4.6, 3.3.6 and 3.2.9, built
229
+ with Rust 1.97. The three runs agree within a few points for most methods; the ones that touch
230
+ the filesystem (`children`, `directory?`, `entries`) vary the most.
231
+
232
+ The figures are smaller than they were on Ruby 2 for the cheapest methods, `absolute?` and
233
+ `relative?` above all: Ruby 3's own `Pathname#absolute?` is a single regexp match, where Ruby 2's
234
+ walked the path with `chop_basename`, so there is less left to shave off.
235
+
236
+ `rake pbench` is also the performance regression test: each method has a floor in
237
+ `test/pbench/pbench_suite.rb` (about half of its lowest figure in the table above) and the task
238
+ fails when a method measures below it, so a change that makes a method slower shows up in
239
+ `rake test`. On Windows, where `join` is currently slower than Ruby's
240
+ ([#185](https://github.com/danielpclark/faster_path/issues/185)), the floors are reported but not
241
+ enforced.
242
+
243
+ ### Before and after the Rutie 0.10 upgrade
244
+
245
+ The last figures on Ruby 2, from the Rutie 0.10 upgrade (faster_path 0.4.0): Ruby 2.7.8 and
246
+ 2.5.7, alternating runs of the code before the upgrade (built with Rutie 0.6) and after it, with
247
+ the benchmark then measuring the average of 5 rounds run one implementation after the other.
248
+ Higher is better; the change is in percentage points.
249
+
250
+ |Method|Ruby 2.7 before|Ruby 2.7 after|Change|Ruby 2.5 before|Ruby 2.5 after|Change|
251
+ |---|:---:|:---:|:---:|:---:|:---:|:---:|
252
+ | `absolute?` | 93.3% | 95.7% | +2.4 | 96.1% | 96.7% | +0.6 |
253
+ | `add_trailing_separator` | 66.6% | 85.4% | **+18.8** | 64.3% | 83.0% | **+18.7** |
254
+ | `basename` | 42.4% | 42.4% | 0.0 | 32.1% | 39.1% | **+7.0** |
255
+ | `children` | 52.8% | 54.7% | +1.9 | 46.5% | 47.8% | +1.3 |
256
+ | `children_compat` | −1.2% | 32.1% | **+33.3** | 1.1% | 26.6% | **+25.5** |
257
+ | `chop_basename` | 71.2% | 70.4% | −0.8 | 74.7% | 75.1% | +0.4 |
258
+ | `cleanpath_aggressive` | 90.3% | 90.3% | 0.0 | 92.7% | 90.6% | −2.1 |
259
+ | `cleanpath_conservative` | 89.8% | 89.6% | −0.2 | 91.7% | 91.6% | −0.1 |
260
+ | `del_trailing_separator` | 86.5% | 85.3% | −1.2 | 87.0% | 87.6% | +0.6 |
261
+ | `directory?` | 33.2% | 34.3% | +1.1 | 37.2% | 37.5% | +0.3 |
262
+ | `dirname` | 49.8% | 56.8% | **+7.0** | 51.2% | 54.7% | +3.5 |
263
+ | `entries` | 40.4% | 38.0% | −2.4 | 33.6% | 33.9% | +0.3 |
264
+ | `entries_compat` | −29.8% | 16.8% | **+46.6** | −23.3% | 9.2% | **+32.5** |
265
+ | `extname` | 70.3% | 74.0% | +3.7 | 74.0% | 73.1% | −0.9 |
266
+ | `has_trailing_separator?` | 87.5% | 88.5% | +1.0 | 87.1% | 89.1% | +2.0 |
267
+ | `join` | crashes | 88.1% | | crashes | 90.3% | |
268
+ | `plus` | 92.3% | 91.7% | −0.6 | 93.0% | 93.4% | +0.4 |
269
+ | `relative?` | 90.7% | 92.8% | +2.1 | 93.6% | 95.2% | +1.6 |
270
+ | `relative_path_from` | 92.7% | 92.5% | −0.2 | 94.0% | 93.6% | −0.4 |
271
+
272
+ Before the upgrade, `FasterPath.join` segfaulted, so its benchmark can't be measured.
273
+ `add_trailing_separator`, `dirname` and the `_compat` methods gained the most:
274
+ `add_trailing_separator` no longer builds a temporary string, no method checks its arguments
275
+ for valid UTF-8 any more, and the `_compat` methods build `Pathname` objects without calling
276
+ `Pathname.new`. `basename` was re-measured after it was made to take a shorter path on Unix
277
+ and skip an empty extension; it was the one method that first measured slower on Ruby 2.5.
278
+ Its timings vary a lot from run to run (Ruby 2.5 before: 40.0%, 32.1%, 28.7%; after: 29.6%,
279
+ 39.1%, 39.2%), so its instruction counts from `valgrind --tool=callgrind` are a steadier
280
+ measure. They went from 2439 to 2331 per call on Ruby 2.5 and from 2689 to 2561 on Ruby 2.7.
281
+
204
282
  ## Getting Started with Development
205
283
 
206
284
  The primary methods to target are mostly listed in the **Why** section above. You may find the Ruby
@@ -214,7 +292,9 @@ Rust method like `!absolute?` _(not absolute)_ drops 39% of the performance alre
214
292
  Whenever feasible implement it in Rust.
215
293
 
216
294
  After checking out the repo, make sure you have Rust installed, then run `bundle`.
217
- Run `rake test` to run the tests, and `rake bench` for benchmarks.
295
+ Run `rake test` to run the tests, and `rake bench` for benchmarks. Both build the extension
296
+ first (`rake rutie:build`, into `target/release`, which is where `require 'faster_path'` loads it
297
+ from in a checkout).
218
298
 
219
299
  ### Building and running tests
220
300
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rake/testtask'
3
- require 'thermite/tasks'
4
- require 'faster_path/thermite_initialize'
3
+ require 'faster_path/version'
4
+ require 'faster_path/build_task'
5
5
 
6
6
  desc 'System Details'
7
7
  task :sysinfo do
@@ -22,7 +22,7 @@ task :sysinfo do
22
22
  puts "RAKE\n #{Rake::VERSION}"
23
23
  end
24
24
 
25
- thermite = Thermite::Tasks.new
25
+ FasterPath::BuildTask.define
26
26
 
27
27
  desc "Generate Contriburs.md Manifest"
28
28
  task :contrib do
@@ -31,10 +31,8 @@ task :contrib do
31
31
  ' > Contributors.md;git shortlog -s -n -e | sed 's/^......./- /' >> Contributors.md"
32
32
  end
33
33
 
34
- desc 'Build + clean up Rust extension'
35
- task build_lib: 'thermite:build' do
36
- thermite.run_cargo 'clean'
37
- end
34
+ desc 'Build the Rust extension'
35
+ task build_lib: 'rutie:build'
38
36
 
39
37
  desc 'Code Quality Check'
40
38
  task :lint do
@@ -46,7 +44,14 @@ end
46
44
 
47
45
  desc "Run Rust Tests"
48
46
  task :cargo do
49
- sh "cargo test -- --nocapture"
47
+ ruby_lib = RbConfig::CONFIG['libdir']
48
+ sh(
49
+ {
50
+ 'LD_LIBRARY_PATH' => ruby_lib,
51
+ 'DYLD_LIBRARY_PATH' => ruby_lib
52
+ },
53
+ 'cargo -vv test -- --nocapture'
54
+ )
50
55
  end
51
56
 
52
57
  Rake::TestTask.new(minitest: :build_lib) do |t|
@@ -62,7 +67,9 @@ task :init_mspec do |_t|
62
67
  end
63
68
 
64
69
  task test: [:cargo, :minitest, :lint, :pbench, :init_mspec] do |_t|
65
- exec 'spec/mspec/bin/mspec --format spec core/file/basename core/file/extname core/file/dirname library/pathname'
70
+ # Run through Ruby so this also works on Windows
71
+ exec Gem.ruby, 'spec/mspec/bin/mspec', '--format', 'spec',
72
+ 'core/file/basename', 'core/file/extname', 'core/file/dirname', 'library/pathname'
66
73
  end
67
74
 
68
75
  desc "Full mspec results w/o encoding"
@@ -83,10 +90,8 @@ Rake::TestTask.new(bench: :build_lib) do |t|
83
90
  t.pattern = 'test/**/*_benchmark.rb'
84
91
  end
85
92
 
93
+ # LONG_RUN=<1..30> multiplies the calls per round, see test/pbench/pbench.rb
86
94
  Rake::TestTask.new(pbench: :build_lib) do |t|
87
- if ARGV.last == '--long-run'
88
- ENV['LONG_RUN'] = '10'
89
- end
90
95
  t.libs = %w[lib test test/pbench]
91
96
  t.pattern = 'test/pbench/pbench_suite.rb'
92
97
  end
data/ext/Rakefile CHANGED
@@ -1,8 +1,14 @@
1
- require 'thermite/tasks'
2
- require_relative '../lib/faster_path/thermite_initialize'
1
+ require 'fileutils'
2
+ require_relative '../lib/faster_path/build_task'
3
3
 
4
- project_toplevel_dir = File.dirname(__dir__)
5
- Thermite::Tasks.new(cargo_project_path: project_toplevel_dir,
6
- ruby_project_path: project_toplevel_dir)
4
+ FasterPath::BuildTask.define
7
5
 
8
- task default: 'thermite:build'
6
+ # Keeps the built library (in lib/faster_path, where FasterPath loads it from)
7
+ # and removes the rest of Cargo's output from the installed gem.
8
+ task install_library: 'rutie:build' do
9
+ FileUtils.mkdir_p(FasterPath::BuildTask::INSTALLED_LIBRARY_DIR)
10
+ FileUtils.cp(FasterPath::BuildTask.built_library, FasterPath::BuildTask::INSTALLED_LIBRARY_DIR)
11
+ Rake::Task['rutie:clean'].invoke
12
+ end
13
+
14
+ task default: :install_library
data/faster_path.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.files = [
17
17
  'Cargo.lock', 'Cargo.toml', 'Gemfile', 'MIT-LICENSE.txt', 'README.md', 'Rakefile',
18
18
  'bin/console', 'bin/setup', 'ext/Rakefile', 'faster_path.gemspec', 'lib/faster_path.rb',
19
- 'lib/faster_path/version.rb', 'lib/faster_path/thermite_initialize.rb',
19
+ 'lib/faster_path/version.rb', 'lib/faster_path/build_task.rb',
20
20
  'lib/faster_path/optional/monkeypatches.rb', 'lib/faster_path/optional/refinements.rb'
21
21
  ]
22
22
  spec.files += Dir['src/**/*']
@@ -24,14 +24,18 @@ Gem::Specification.new do |spec|
24
24
  spec.extensions = ['ext/Rakefile']
25
25
  spec.require_paths = ['lib']
26
26
 
27
- spec.add_dependency 'bundler', '~> 1.12'
28
- spec.add_dependency 'rake', '~> 12.3'
29
- spec.add_dependency 'thermite', '0.13.0'
27
+ # Rutie 0.13, which the Rust extension is built with, supports Ruby 3.2 to 3.4
28
+ spec.required_ruby_version = ['>= 3.2', '< 3.5']
29
+
30
+ # The extension is built at install time with Rutie's Rake task and loaded with Rutie
31
+ spec.add_dependency 'rake', '>= 12.3'
32
+ spec.add_dependency 'rutie', '~> 0.0.5'
30
33
  spec.add_development_dependency 'read_source', '~> 0.2.6'
31
- spec.add_development_dependency 'minitest', '~> 5.10'
34
+ spec.add_development_dependency 'minitest', '~> 5.11'
32
35
  spec.add_development_dependency 'minitest-reporters', '~> 1.1'
33
36
  spec.add_development_dependency 'color_pound_spec_reporter', '~> 0.0.9'
34
- spec.add_development_dependency 'rubocop', '0.53'
37
+ spec.add_development_dependency 'rubocop', '~> 1.80'
38
+ spec.add_development_dependency 'rubocop-performance', '~> 1.20'
35
39
  spec.add_development_dependency 'stop_watch', '~> 1.0'
36
40
  if !ENV['CI'] && ENV['GRAPH']
37
41
  spec.add_development_dependency 'gruff', '~> 0.7.0'
@@ -0,0 +1,32 @@
1
+ require 'rbconfig'
2
+ require 'rutie'
3
+ require 'rutie/rake_task'
4
+
5
+ module FasterPath
6
+ # Defines `rutie:build` and `rutie:clean`, which build the Rust extension
7
+ # with Cargo. Used by the Rakefile and by ext/Rakefile when the gem is
8
+ # installed; both may run from another directory, so Cargo is pointed at
9
+ # the gem's Cargo.toml.
10
+ #
11
+ # The Rakefile leaves the library in target/release, where Rutie loads it
12
+ # from; ext/Rakefile moves it to lib/faster_path so that the installed gem
13
+ # keeps nothing else of the build.
14
+ module BuildTask
15
+ PROJECT_DIR = File.expand_path('../..', __dir__)
16
+ # Where `gem install` puts the built library
17
+ INSTALLED_LIBRARY_DIR = File.join(PROJECT_DIR, 'lib', 'faster_path')
18
+
19
+ def self.define
20
+ # Rutie's build script links the extension to the Ruby named by RUBY,
21
+ # or the first `ruby` on the PATH; make it the Ruby running Rake.
22
+ ENV['RUBY'] ||= File.join(RbConfig::CONFIG['bindir'],
23
+ RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT'])
24
+ Rutie::RakeTask.new(cargo_args: ['--manifest-path', File.join(PROJECT_DIR, 'Cargo.toml')])
25
+ end
26
+
27
+ # The library `rutie:build` builds, in the project's target/release
28
+ def self.built_library
29
+ Rutie.new(:faster_path).ffi_library(File.join(PROJECT_DIR, 'lib'))
30
+ end
31
+ end
32
+ end
@@ -24,10 +24,10 @@ module FasterPath
24
24
  end
25
25
 
26
26
  # @private :nodoc:
27
- def self.dirname(pth)
27
+ def self.dirname(pth, level = 1)
28
28
  pth = pth.to_path if pth.respond_to? :to_path
29
29
  raise TypeError unless pth.is_a? String
30
- FasterPath.dirname(pth)
30
+ FasterPath.dirname(pth, level)
31
31
  end
32
32
  end
33
33
  end
@@ -20,10 +20,10 @@ module FasterPath
20
20
  end
21
21
 
22
22
  # @private :nodoc:
23
- def self.dirname(pth)
23
+ def self.dirname(pth, level = 1)
24
24
  pth = pth.to_path if pth.respond_to? :to_path
25
25
  raise TypeError unless pth.is_a? String
26
- FasterPath.dirname(pth)
26
+ FasterPath.dirname(pth, level)
27
27
  end
28
28
  end
29
29
  end
@@ -1,3 +1,3 @@
1
1
  module FasterPath
2
- VERSION = "0.3.10"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/faster_path.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'faster_path/version'
2
2
  require 'pathname'
3
- require 'thermite/config'
4
- require 'faster_path/thermite_initialize'
3
+ require 'rutie'
5
4
  require 'fiddle'
6
5
  require 'fiddle/import'
7
6
 
@@ -14,16 +13,12 @@ require 'fiddle/import'
14
13
  # existing code ecosystem. To do so you will need to
15
14
  # `require 'faster_path/optional/monkeypatches'` beforehand.
16
15
  module FasterPath
17
- FFI_LIBRARY = begin
18
- toplevel_dir = File.dirname(__dir__)
19
- config = Thermite::Config.new(cargo_project_path: toplevel_dir,
20
- ruby_project_path: toplevel_dir)
21
- config.ruby_extension_path
22
- end
23
-
24
- Fiddle::Function.
25
- new(Fiddle.dlopen(FFI_LIBRARY)['Init_faster_pathname'], [], Fiddle::TYPE_VOIDP).
26
- call
16
+ # The Rust extension: in the project's target/release after `rake rutie:build`,
17
+ # or in lib/faster_path, where `gem install` puts it (see ext/Rakefile)
18
+ RUTIE = [Rutie.new(:faster_path), Rutie.new(:faster_path, lib_path: 'faster_path')].
19
+ find { |rutie| File.exist?(rutie.ffi_library(__dir__)) } || Rutie.new(:faster_path)
20
+ FFI_LIBRARY = RUTIE.ffi_library(__dir__)
21
+ RUTIE.init('Init_faster_pathname', __dir__)
27
22
 
28
23
  Public.class_eval do
29
24
  private_class_method :basename
@@ -40,7 +35,9 @@ module FasterPath
40
35
  # The Ruby architecture bit width: 64bits or 32bits
41
36
  # @return [Integer]
42
37
  def self.ruby_arch_bits
43
- 1.size * 8
38
+ # The width of a pointer; `1.size` is the width of a C `long`, which is
39
+ # 4 bytes on 64-bit Windows.
40
+ [0].pack('J').bytesize * 8
44
41
  end
45
42
 
46
43
  # A very fast way to check if a string is blank