faster_path 0.3.9 → 0.3.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Cargo.lock +0 -7
- data/Cargo.toml +0 -1
- data/Gemfile +1 -0
- data/README.md +16 -7
- data/faster_path.gemspec +1 -1
- data/lib/faster_path.rb +6 -1
- data/lib/faster_path/version.rb +1 -1
- data/src/pathname.rs +11 -50
- data/src/pathname_sys.rs +1 -15
- data/src/plus.rs +54 -56
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32af4c3fa17e05003792d14b3e8a34ce26fd206395f345fc58a13c8cc63b37b7
|
4
|
+
data.tar.gz: 7ec503bf0957f176fa5daa1d4910a67af9c3b06bb391e573586fcaadc1157a88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff3f4a219cb46f561eec9a2138d1282773ad2ceddcd0664202c2396202efbb1ecb2b8839347dd65bcf595faf93b6d6d6b85d6a912c18380b8ff10ccd878379ab
|
7
|
+
data.tar.gz: 27e3886927a1479b5d28e1b2a5d96cb5bb86c240b87664010b1be9d181afebf456476a43c1e7843f890b2af581ccd398dca91c3dd6f1021380e156402f2d90ab
|
data/Cargo.lock
CHANGED
@@ -1,13 +1,7 @@
|
|
1
|
-
[[package]]
|
2
|
-
name = "array_tool"
|
3
|
-
version = "1.0.3"
|
4
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
5
|
-
|
6
1
|
[[package]]
|
7
2
|
name = "faster_path"
|
8
3
|
version = "0.0.1"
|
9
4
|
dependencies = [
|
10
|
-
"array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
11
5
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
12
6
|
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
13
7
|
"ruby-sys 0.3.0 (git+https://github.com/danielpclark/ruby-sys?branch=playground)",
|
@@ -55,7 +49,6 @@ dependencies = [
|
|
55
49
|
]
|
56
50
|
|
57
51
|
[metadata]
|
58
|
-
"checksum array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
|
59
52
|
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
60
53
|
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
61
54
|
"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
|
data/Cargo.toml
CHANGED
@@ -18,6 +18,5 @@ crate-type = ["dylib"]
|
|
18
18
|
[dependencies]
|
19
19
|
ruby-sys = { git = "https://github.com/danielpclark/ruby-sys", branch = "playground" }
|
20
20
|
ruru = { git = "https://github.com/danielpclark/ruru", branch = "playground" }
|
21
|
-
array_tool = "1.0"
|
22
21
|
lazy_static = "1.0"
|
23
22
|
memchr = "2.0.1"
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,12 +3,11 @@
|
|
3
3
|
[![TravisCI Build Status](https://travis-ci.org/danielpclark/faster_path.svg?branch=master)](https://travis-ci.org/danielpclark/faster_path)
|
4
4
|
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/10ul0gk3cwhlt2lj/branch/master?svg=true)](https://ci.appveyor.com/project/danielpclark/faster-path/branch/master)
|
5
5
|
[![Latest Tag](https://img.shields.io/github/tag/danielpclark/faster_path.svg)](https://github.com/danielpclark/faster_path/tags)
|
6
|
-
[![Commits Since Last Release](https://img.shields.io/github/commits-since/danielpclark/faster_path/v0.3.
|
6
|
+
[![Commits Since Last Release](https://img.shields.io/github/commits-since/danielpclark/faster_path/v0.3.10.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?branch=master)](https://coveralls.io/github/danielpclark/faster_path?branch=master)
|
9
9
|
[![Inline docs](http://inch-ci.org/github/danielpclark/faster_path.svg?branch=master)](http://inch-ci.org/github/danielpclark/faster_path)
|
10
10
|
[![Code Triagers Badge](https://www.codetriage.com/danielpclark/faster_path/badges/users.svg)](https://www.codetriage.com/danielpclark/faster_path)
|
11
|
-
[![Tweet This](https://raw.githubusercontent.com/danielpclark/faster_path/master/assets/tweet.png)](https://twitter.com/share?url=https%3A%2F%2Fgithub.com%2Fdanielpclark%2Ffaster_path&via=6ftdan&hashtags=Ruby&text=You%20could%20save%2015%25%20or%20more%20on%20website%20page%20load%20time%20by%20switching%20to%20the%20FasterPath%20gem.)
|
12
11
|
|
13
12
|
#### This gem shaves off more than 30% of my Rails application page load time.
|
14
13
|
|
@@ -94,6 +93,18 @@ I've said this about Sprockets but this required two other gems to be updated as
|
|
94
93
|
|sass 3.2.19|sass 5.0.4|
|
95
94
|
|bootstrap-sass 3.3.4.1|bootstrap-sass 3.3.6|
|
96
95
|
|
96
|
+
## Performance Specifics
|
97
|
+
|
98
|
+
The headline for the amount for improvement on this library is specific to only the improvement made with the method `chop_basename`. Just so you know; in my initial release I had a bug in which that method immediately returned nothing. Now the good thing about this is that it gave me some very valuable information. First I found that all my Rails site tests still passed. Second I found that all my assets no longer loaded in the website. And third, and most importantly, I found my Rails web pages loaded just more than 66% faster without the cost of time that `chop_basename` took.
|
99
|
+
|
100
|
+
**That's right; the path handling for assets in your website \*consumes more than 2/3rds of your websites page load time.**
|
101
|
+
|
102
|
+
So now we have some real numbers to work with We can be generoues and use 66% as our margin of area to improve over _(for `chop_basename` specifically, not counting the benefit from improving the performance in other file path related methods)_. That means we want to remove as much of that percentage from the overall systems page load time. The original headline boasts over 33% performance improvement — that was when `chop_basename` was improved by just over 50%. Now `chop_basename` is improved by 83.4%. That alone should make your site run 55.044% faster now _(given your performance profile stats are similar to mine)_.
|
103
|
+
|
104
|
+
## What Rails Versions Will This Apply To?
|
105
|
+
|
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.
|
107
|
+
|
97
108
|
## Status
|
98
109
|
|
99
110
|
* Rust compilation is working
|
@@ -115,7 +126,7 @@ curl -sSf https://static.rust-lang.org/rustup.sh | sh
|
|
115
126
|
Add this line to your application's Gemfile:
|
116
127
|
|
117
128
|
```ruby
|
118
|
-
gem 'faster_path', '~> 0.3.
|
129
|
+
gem 'faster_path', '~> 0.3.10'
|
119
130
|
```
|
120
131
|
|
121
132
|
And then execute:
|
@@ -153,8 +164,8 @@ Current methods implemented:
|
|
153
164
|
| `FasterPath.entries` | `Pathname#entries` | 41.0% |
|
154
165
|
| `FasterPath.extname` | `File.extname` | 63.1% |
|
155
166
|
| `FasterPath.has_trailing_separator?` | `Pathname#has_trailing_separator` | 88.9% |
|
156
|
-
| `FasterPath.plus` | `Pathname#join` |
|
157
|
-
| `FasterPath.plus` | `Pathname#plus` |
|
167
|
+
| `FasterPath.plus` | `Pathname#join` | 79.1% |
|
168
|
+
| `FasterPath.plus` | `Pathname#plus` | 94.7% |
|
158
169
|
| `FasterPath.relative?` | `Pathname#relative?` | 92.6% |
|
159
170
|
| `FasterPath.relative_path_from` | `Pathname#relative_path_from` | 93.3% |
|
160
171
|
|
@@ -205,8 +216,6 @@ Whenever feasible implement it in Rust.
|
|
205
216
|
After checking out the repo, make sure you have Rust installed, then run `bundle`.
|
206
217
|
Run `rake test` to run the tests, and `rake bench` for benchmarks.
|
207
218
|
|
208
|
-
Learn and share performance tips on the [wiki](https://github.com/danielpclark/faster_path/wiki)!
|
209
|
-
|
210
219
|
### Building and running tests
|
211
220
|
|
212
221
|
First, bundle the gem's development dependencies by running `bundle`. Rust compilation is included in the current rake commands.
|
data/faster_path.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.require_paths = ['lib']
|
26
26
|
|
27
27
|
spec.add_dependency 'bundler', '~> 1.12'
|
28
|
-
spec.add_dependency 'rake', '~> 12.
|
28
|
+
spec.add_dependency 'rake', '~> 12.3'
|
29
29
|
spec.add_dependency 'thermite', '0.13.0'
|
30
30
|
spec.add_development_dependency 'read_source', '~> 0.2.6'
|
31
31
|
spec.add_development_dependency 'minitest', '~> 5.10'
|
data/lib/faster_path.rb
CHANGED
@@ -6,8 +6,13 @@ require 'fiddle'
|
|
6
6
|
require 'fiddle/import'
|
7
7
|
|
8
8
|
# FasterPath module behaves as a singleton object with the alternative method
|
9
|
-
# implementations for Pathname
|
9
|
+
# implementations for `Pathname`, and some for `File`, available directly on it.
|
10
10
|
#
|
11
|
+
# New projects are recommend to reference methods defined directly on `FasterPath`.
|
12
|
+
# Existing websites may use the `FasterPath.sledgehammer_everything!` method to
|
13
|
+
# directly injet the more performant implementations of path handling in to their
|
14
|
+
# existing code ecosystem. To do so you will need to
|
15
|
+
# `require 'faster_path/optional/monkeypatches'` beforehand.
|
11
16
|
module FasterPath
|
12
17
|
FFI_LIBRARY = begin
|
13
18
|
toplevel_dir = File.dirname(__dir__)
|
data/lib/faster_path/version.rb
CHANGED
data/src/pathname.rs
CHANGED
@@ -9,7 +9,6 @@ use plus;
|
|
9
9
|
use relative_path_from;
|
10
10
|
use debug;
|
11
11
|
use helpers::{TryFrom, to_str};
|
12
|
-
use pathname_sys::null_byte_check;
|
13
12
|
use path_parsing::{SEP, find_last_non_sep_pos};
|
14
13
|
|
15
14
|
use ruru;
|
@@ -23,10 +22,11 @@ use ruru::{
|
|
23
22
|
Class,
|
24
23
|
VerifiedObject,
|
25
24
|
Exception as Exc,
|
26
|
-
AnyException as Exception
|
25
|
+
AnyException as Exception,
|
27
26
|
};
|
28
27
|
use ruru::types::{Value, ValueType};
|
29
|
-
use std::
|
28
|
+
use std::borrow::Cow;
|
29
|
+
use std::path::{MAIN_SEPARATOR, Path};
|
30
30
|
use std::fs;
|
31
31
|
|
32
32
|
type MaybeArray = Result<ruru::Array, ruru::result::Error>;
|
@@ -45,31 +45,6 @@ impl Pathname {
|
|
45
45
|
Pathname { value: instance.value() }
|
46
46
|
}
|
47
47
|
|
48
|
-
pub fn new_checked(path: AnyObject) -> Result<Pathname, Exception> {
|
49
|
-
let pth: Value = if Class::from_existing("String").case_equals(&path) {
|
50
|
-
path.value()
|
51
|
-
} else if path.respond_to("to_path") {
|
52
|
-
path.send("to_path", None).value()
|
53
|
-
} else {
|
54
|
-
return Err(
|
55
|
-
Exception::new(
|
56
|
-
"ArgumentError",
|
57
|
-
Some("The type for the argument provided to Pathname.new was invalid.")
|
58
|
-
)
|
59
|
-
)
|
60
|
-
};
|
61
|
-
|
62
|
-
if null_byte_check(path.value()) {
|
63
|
-
return Err( Exception::new("ArgumentError", Some("pathname contains null byte")) )
|
64
|
-
}
|
65
|
-
|
66
|
-
// if it crashes then dup the path string here before assigning to @path
|
67
|
-
let mut instance = Class::from_existing("Pathname").allocate();
|
68
|
-
instance.instance_variable_set("@path", RString::from(pth).to_any_object());
|
69
|
-
|
70
|
-
Ok(Pathname { value: instance.value() })
|
71
|
-
}
|
72
|
-
|
73
48
|
pub fn to_any_object(&self) -> AnyObject {
|
74
49
|
AnyObject::from(self.value())
|
75
50
|
}
|
@@ -77,7 +52,7 @@ impl Pathname {
|
|
77
52
|
|
78
53
|
impl From<Value> for Pathname {
|
79
54
|
fn from(value: Value) -> Self {
|
80
|
-
Pathname { value
|
55
|
+
Pathname { value }
|
81
56
|
}
|
82
57
|
}
|
83
58
|
|
@@ -302,29 +277,15 @@ pub fn pn_has_trailing_separator(pth: MaybeString) -> Boolean {
|
|
302
277
|
}
|
303
278
|
|
304
279
|
pub fn pn_join(args: MaybeArray) -> AnyObject {
|
305
|
-
let
|
306
|
-
let
|
307
|
-
let mut
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
let mut result = String::new();
|
313
|
-
|
314
|
-
loop {
|
315
|
-
if qty == 0 { break; }
|
316
|
-
|
317
|
-
let item = args.pop();
|
318
|
-
result = plus::plus_paths(&anyobject_to_string(item).unwrap(), &result);
|
319
|
-
if result.as_bytes().get(0) == Some(&SEP) {
|
320
|
-
return Pathname::new(&result).to_any_object()
|
280
|
+
let paths = args.unwrap().into_iter().map(|arg| anyobject_to_string(arg).unwrap()).collect::<Vec<_>>();
|
281
|
+
let mut paths_iter = paths.iter().rev();
|
282
|
+
let mut result = Cow::Borrowed(paths_iter.next().unwrap().as_str());
|
283
|
+
for part in paths_iter {
|
284
|
+
result = plus::plus_paths(&part, result.as_ref());
|
285
|
+
if result.as_bytes().first() == Some(&SEP) {
|
286
|
+
break;
|
321
287
|
}
|
322
|
-
|
323
|
-
qty -= 1;
|
324
288
|
}
|
325
|
-
|
326
|
-
let result = plus::plus_paths(&path_self, &result);
|
327
|
-
|
328
289
|
Pathname::new(&result).to_any_object()
|
329
290
|
}
|
330
291
|
|
data/src/pathname_sys.rs
CHANGED
@@ -2,23 +2,9 @@ use ruru::{AnyObject, Array, Object, AnyException};
|
|
2
2
|
use ruru::types::{Argc, Value, CallbackPtr};
|
3
3
|
use ruru::util::str_to_cstring;
|
4
4
|
extern crate ruby_sys;
|
5
|
-
use self::ruby_sys::{class, util, vm
|
5
|
+
use self::ruby_sys::{class, util, vm};
|
6
6
|
use ::pathname;
|
7
7
|
extern crate memchr;
|
8
|
-
use self::memchr::memchr;
|
9
|
-
use std::slice;
|
10
|
-
|
11
|
-
pub fn null_byte_check(value: Value) -> bool {
|
12
|
-
unsafe {
|
13
|
-
let str = string::rb_string_value_ptr(&value) as *const u8;
|
14
|
-
|
15
|
-
// `rb_str_len` is a ruby_sys specific thing. Consider:
|
16
|
-
// extern { fn rb_str_strlen(value: Value) -> c_long } as isize
|
17
|
-
let len = string::rb_str_len(value) as usize;
|
18
|
-
|
19
|
-
memchr(b'\0', slice::from_raw_parts(str, len)).is_some()
|
20
|
-
}
|
21
|
-
}
|
22
8
|
|
23
9
|
pub fn raise(exception: AnyException) {
|
24
10
|
unsafe { vm::rb_exc_raise(exception.value()); }
|
data/src/plus.rs
CHANGED
@@ -1,83 +1,80 @@
|
|
1
|
-
|
2
|
-
use std::path::Path;
|
1
|
+
use std::borrow::Cow;
|
3
2
|
use std::str;
|
3
|
+
use std::path::MAIN_SEPARATOR;
|
4
|
+
|
4
5
|
use chop_basename::chop_basename;
|
5
|
-
use
|
6
|
-
use dirname::dirname;
|
7
|
-
use self::array_tool::vec::Shift;
|
8
|
-
use std::ops::Index;
|
6
|
+
use path_parsing::SEP;
|
9
7
|
|
10
|
-
pub fn plus_paths(path1: &str, path2: &str) ->
|
11
|
-
let mut prefix2 = path2
|
8
|
+
pub fn plus_paths<'a>(path1: &'a str, path2: &str) -> Cow<'a, str> {
|
9
|
+
let mut prefix2 = path2;
|
12
10
|
let mut index_list2: Vec<usize> = vec![];
|
13
|
-
let mut basename_list2: Vec
|
14
|
-
|
11
|
+
let mut basename_list2: Vec<&str> = vec![];
|
15
12
|
loop {
|
16
|
-
match chop_basename(
|
17
|
-
None => { break }
|
13
|
+
match chop_basename(prefix2) {
|
14
|
+
None => { break; }
|
18
15
|
Some((pfx2, basename2)) => {
|
19
|
-
prefix2 = pfx2
|
20
|
-
index_list2.
|
21
|
-
basename_list2.
|
22
|
-
}
|
16
|
+
prefix2 = pfx2;
|
17
|
+
index_list2.push(pfx2.len());
|
18
|
+
basename_list2.push(basename2);
|
19
|
+
}
|
23
20
|
}
|
24
21
|
}
|
25
22
|
if !prefix2.is_empty() {
|
26
|
-
return path2.to_string()
|
23
|
+
return path2.to_string().into();
|
27
24
|
};
|
28
25
|
|
29
|
-
let
|
30
|
-
|
26
|
+
let result_prefix: Cow<str>;
|
27
|
+
let mut prefix1 = path1;
|
31
28
|
loop {
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
29
|
+
let mut new_len = basename_list2.len() - count_trailing(".", &basename_list2);
|
30
|
+
index_list2.truncate(new_len);
|
31
|
+
basename_list2.truncate(new_len);
|
32
|
+
match chop_basename(prefix1) {
|
33
|
+
None => {
|
34
|
+
result_prefix = prefix1.into();
|
35
|
+
break;
|
36
|
+
}
|
38
37
|
Some((pfx1, basename1)) => {
|
39
|
-
prefix1 = pfx1
|
40
|
-
if basename1 == "." { continue };
|
41
|
-
if basename1 == ".." || basename_list2.
|
42
|
-
prefix1.
|
43
|
-
break
|
44
|
-
}
|
38
|
+
prefix1 = pfx1;
|
39
|
+
if basename1 == "." { continue; };
|
40
|
+
if basename1 == ".." || basename_list2.last() != Some(&"..") {
|
41
|
+
result_prefix = [prefix1, basename1].concat().into();
|
42
|
+
break;
|
45
43
|
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
if new_len > 0 {
|
47
|
+
new_len -= 1;
|
48
|
+
index_list2.truncate(new_len);
|
49
|
+
basename_list2.truncate(new_len);
|
46
50
|
}
|
47
|
-
index_list2.shift();
|
48
|
-
basename_list2.shift();
|
49
51
|
}
|
50
52
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
if !r1 {
|
56
|
-
r1 = basename(&prefix1[..], "").contains("/");
|
57
|
-
if r1 {
|
58
|
-
while !basename_list2.is_empty() && basename_list2.first().unwrap() == ".." {
|
59
|
-
index_list2.shift();
|
60
|
-
basename_list2.shift();
|
61
|
-
}
|
62
|
-
}
|
53
|
+
if !result_prefix.is_empty() && result_prefix.as_bytes().iter().cloned().all(|b| b == SEP) {
|
54
|
+
let new_len = basename_list2.len() - count_trailing("..", &basename_list2);
|
55
|
+
index_list2.truncate(new_len);
|
56
|
+
basename_list2.truncate(new_len);
|
63
57
|
}
|
64
|
-
if
|
65
|
-
let
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
58
|
+
if let Some(last_index2) = index_list2.last() {
|
59
|
+
let suffix = &path2[*last_index2..];
|
60
|
+
match (result_prefix.as_bytes().last(), suffix.as_bytes().first()) {
|
61
|
+
(Some(&SEP), Some(&SEP)) => [&result_prefix, &suffix[1..]].concat().into(),
|
62
|
+
(Some(&SEP), Some(_)) | (Some(_), Some(&SEP)) => [&result_prefix, suffix].concat().into(),
|
63
|
+
(None, Some(_)) => suffix.to_string().into(),
|
64
|
+
_ => format!("{}{}{}", result_prefix.as_ref(), MAIN_SEPARATOR, suffix).into(),
|
71
65
|
}
|
72
66
|
} else {
|
73
|
-
if
|
74
|
-
|
67
|
+
if result_prefix.is_empty() {
|
68
|
+
".".into()
|
75
69
|
} else {
|
76
|
-
|
70
|
+
result_prefix
|
77
71
|
}
|
78
72
|
}
|
73
|
+
}
|
79
74
|
|
80
|
-
|
75
|
+
#[inline(always)]
|
76
|
+
fn count_trailing(x: &str, xs: &Vec<&str>) -> usize {
|
77
|
+
xs.iter().rev().take_while(|&c| c == &x).count()
|
81
78
|
}
|
82
79
|
|
83
80
|
#[test]
|
@@ -90,6 +87,7 @@ fn it_will_plus_same_as_ruby() {
|
|
90
87
|
assert_eq!("/b" , plus_paths("a" , "/b"));
|
91
88
|
|
92
89
|
assert_eq!("/" , plus_paths("/" , ".."));
|
90
|
+
assert_eq!("////" , plus_paths("////", ""));
|
93
91
|
assert_eq!("." , plus_paths("a" , ".."));
|
94
92
|
assert_eq!("a" , plus_paths("a/b", ".."));
|
95
93
|
assert_eq!("../.." , plus_paths(".." , ".."));
|
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.3.
|
4
|
+
version: 0.3.10
|
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: 2018-03-
|
11
|
+
date: 2018-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '12.
|
33
|
+
version: '12.3'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '12.
|
40
|
+
version: '12.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: thermite
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|