Skip to content

Commit a7a087e

Browse files
committed
Working relative_path_from
1 parent 6e10e9e commit a7a087e

13 files changed

+133
-111
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ crate-type = ["dylib"]
1515
[dependencies]
1616
ruby-sys = { git = "https://github.com/danielpclark/ruby-sys", branch = "playground" }
1717
ruru = { git = "https://github.com/danielpclark/ruru", branch = "playground" }
18-
array_tool = "0.4.1"
18+
array_tool = "1.0"
1919
lazy_static = "1.0"
2020
memchr = "2.0.1"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ Current methods implemented:
151151
| `FasterPath.plus` | `Pathname#join` | 66.4% |
152152
| `FasterPath.plus` | `Pathname#plus` | 81.4% |
153153
| `FasterPath.relative?` | `Pathname#relative?` | 84.1% |
154+
| `FasterPath.relative_path_from` | `Pathname#relative_path_from` | 69.8% |
154155

155156
You may choose to use the methods directly, or scope change to rewrite behavior on the
156157
standard library with the included refinements, or even call a method to monkeypatch

lib/faster_path/optional/monkeypatches.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ def plus(pth, pth2)
8787
def relative?
8888
FasterPath.relative?(@path)
8989
end
90+
91+
def relative_path_from(other)
92+
FasterPath.relative_path_from(@path, Pathname(other))
93+
end
9094
end
9195
end
9296
end

lib/faster_path/optional/refinements.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ def plus(pth, pth2)
8282
def relative?
8383
FasterPath.relative?(@path)
8484
end
85+
86+
def relative_path_from(other)
87+
FasterPath.relative_path_from(@path, Pathname(other))
88+
end
8589
end
8690
end
8791
end

src/debug.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use ruru::{
2+
RString,
3+
AnyObject,
4+
Object,
5+
};
6+
7+
#[derive(Debug)]
8+
pub struct RubyDebugInfo {
9+
object_id: String,
10+
class: String,
11+
inspect: String,
12+
}
13+
14+
impl From<AnyObject> for RubyDebugInfo {
15+
fn from(ao: AnyObject) -> Self {
16+
let object_id = ao.send("object_id", None).send("to_s", None).
17+
try_convert_to::<RString>().unwrap_or(RString::new("Failed to get object_id!")).to_string();
18+
let class = ao.send("class", None).send("to_s", None).
19+
try_convert_to::<RString>().unwrap_or(RString::new("Failed to get class!")).to_string();
20+
let inspect = ao.send("inspect", None).
21+
try_convert_to::<RString>().unwrap_or(RString::new("Failed to get inspect!")).to_string();
22+
23+
RubyDebugInfo {
24+
object_id: object_id,
25+
class: class,
26+
inspect: inspect,
27+
}
28+
}
29+
}

src/helpers.rs

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use ruru::{RString, Object, Class, AnyObject};
2-
use pathname::Pathname;
2+
use debug::RubyDebugInfo;
33

44
#[inline]
55
pub fn is_same_path(a: &str, b: &str) -> bool {
@@ -33,40 +33,3 @@ pub fn anyobject_to_string(item: AnyObject) -> Result<String, RubyDebugInfo> {
3333

3434
Ok(RString::from(result.send("to_s", None).value()).to_string())
3535
}
36-
37-
#[allow(dead_code)]
38-
pub fn into_pathname(itself: AnyObject) -> Result<AnyObject, RubyDebugInfo> {
39-
if Class::from_existing("String").case_equals(&itself) {
40-
Ok(Pathname::new(
41-
&RString::from(itself.value()).to_string()
42-
).to_any_object())
43-
} else if Class::from_existing("Pathname").case_equals(&itself) {
44-
Ok(itself)
45-
} else {
46-
Err(RubyDebugInfo::from(itself))
47-
}
48-
}
49-
50-
#[derive(Debug)]
51-
pub struct RubyDebugInfo {
52-
object_id: String,
53-
class: String,
54-
inspect: String,
55-
}
56-
57-
impl From<AnyObject> for RubyDebugInfo {
58-
fn from(ao: AnyObject) -> Self {
59-
let object_id = ao.send("object_id", None).send("to_s", None).
60-
try_convert_to::<RString>().unwrap_or(RString::new("Failed to get object_id!")).to_string();
61-
let class = ao.send("class", None).send("to_s", None).
62-
try_convert_to::<RString>().unwrap_or(RString::new("Failed to get class!")).to_string();
63-
let inspect = ao.send("inspect", None).
64-
try_convert_to::<RString>().unwrap_or(RString::new("Failed to get inspect!")).to_string();
65-
66-
RubyDebugInfo {
67-
object_id: object_id,
68-
class: class,
69-
inspect: inspect,
70-
}
71-
}
72-
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
55
// http://opensource.org/licenses/MIT>, at your option. This file may not be
66
// copied, modified, or distributed except according to those terms.
7+
#![feature(try_from)]
8+
79
#[macro_use]
810
extern crate ruru;
911

@@ -12,6 +14,7 @@ extern crate lazy_static;
1214

1315
module!(FasterPath);
1416

17+
mod debug;
1518
mod helpers;
1619
mod pathname;
1720
mod basename;

src/pathname.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use dirname;
77
use extname;
88
use plus;
99
use relative_path_from;
10+
use debug;
11+
use std::convert::TryFrom;
1012

1113
use ruru;
1214
use ruru::{
@@ -51,6 +53,19 @@ impl From<Value> for Pathname {
5153
}
5254
}
5355

56+
impl TryFrom<AnyObject> for Pathname {
57+
type Error = debug::RubyDebugInfo;
58+
fn try_from(obj: AnyObject) -> Result<Pathname, Self::Error> {
59+
if Class::from_existing("String").case_equals(&obj) {
60+
Ok(Pathname::new(&RString::from(obj.value()).to_string()))
61+
} else if Class::from_existing("Pathname").case_equals(&obj) {
62+
Ok(Pathname::from(obj.value()))
63+
} else {
64+
Err(Self::Error::from(obj))
65+
}
66+
}
67+
}
68+
5469
impl Object for Pathname {
5570
#[inline]
5671
fn value(&self) -> Value {

src/relative_path_from.rs

Lines changed: 14 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use helpers::is_same_path;
22
use path_parsing::SEP_STR;
33
extern crate array_tool;
44
use self::array_tool::vec::{Shift, Join};
5+
use self::array_tool::iter::ZipOpt;
56
use pathname;
67
use ruru;
78
use chop_basename;
@@ -53,11 +54,20 @@ pub fn relative_path_from(itself: MaybeString, base_directory: MaybeString) -> R
5354

5455
let (dest_names, base_names): (Vec<String>, Vec<String>) = dest_names.
5556
iter().
56-
zip(base_names.iter()).
57-
skip_while(|&(a, b)| is_same_path(a,b) ).
57+
zip_option(base_names.iter()).
58+
skip_while(|&(a, b)| {
59+
match (a, b) {
60+
(Some(x), Some(y)) => is_same_path(x,y),
61+
_ => false,
62+
}
63+
}).
5864
fold((vec![], vec![]), |mut acc, (a, b)| {
59-
acc.0.push(a.to_string());
60-
acc.1.push(b.to_string());
65+
if let Some(v) = a {
66+
acc.0.push(v.to_string());
67+
}
68+
if let Some(v) = b {
69+
acc.1.push(v.to_string());
70+
}
6171
acc
6272
});
6373

@@ -78,56 +88,3 @@ pub fn relative_path_from(itself: MaybeString, base_directory: MaybeString) -> R
7888
Ok(Pathname::new(&base_names.iter().chain(dest_names.iter()).collect::<Vec<&String>>().join(&SEP_STR)))
7989
}
8090
}
81-
82-
// #[allow(dead_code)]
83-
// fn rpf(a: &str, b: &str) -> String {
84-
// relative_path_from(a.to_string(), b.to_string()).
85-
// unwrap_or(Pathname::new("WRONG_ANSWER")).
86-
// send("to_s", None).
87-
// try_convert_to::<RString>().
88-
// unwrap().
89-
// to_string()
90-
// }
91-
//
92-
// #[allow(dead_code)]
93-
// fn rpfe(a: &str, b: &str) -> Result<Pathname, Exception> {
94-
// relative_path_from(a.to_string(), b.to_string())
95-
// }
96-
//
97-
// #[test]
98-
// fn it_checks_relative_path() {
99-
// assert_eq!(rpf("a", "b"), "../a" );
100-
// assert_eq!(rpf("a", "b/"), "../a" );
101-
// assert_eq!(rpf("a/", "b"), "../a" );
102-
// assert_eq!(rpf("a/", "b/"), "../a" );
103-
// assert_eq!(rpf("/a", "/b"), "../a" );
104-
// assert_eq!(rpf("/a", "/b/"), "../a" );
105-
// assert_eq!(rpf("/a/", "/b"), "../a" );
106-
// assert_eq!(rpf("/a/", "/b/"), "../a" );
107-
// assert_eq!(rpf("a/b", "a/c"), "../b" );
108-
// assert_eq!(rpf("../a", "../b"), "../a" );
109-
// assert_eq!(rpf("a", "."), "a" );
110-
// assert_eq!(rpf(".", "a"), ".." );
111-
// assert_eq!(rpf(".", "."), "." );
112-
// assert_eq!(rpf("..", ".."), "." );
113-
// assert_eq!(rpf("..", "."), ".." );
114-
// assert_eq!(rpf("/a/b/c/d", "/a/b"), "c/d" );
115-
// assert_eq!(rpf("/a/b", "/a/b/c/d"), "../.." );
116-
// assert_eq!(rpf("/e", "/a/b/c/d"), "../../../../e");
117-
// assert_eq!(rpf("a/b/c", "a/d"), "../b/c" );
118-
// assert_eq!(rpf("/../a", "/b"), "../a" );
119-
// assert_eq!(rpf("../a", "b"), "../../a" );
120-
// assert_eq!(rpf("/a/../../b", "/b"), "." );
121-
// assert_eq!(rpf("a/..", "a"), ".." );
122-
// assert_eq!(rpf("a/../b", "b"), "." );
123-
// assert_eq!(rpf("a", "b/.."), "a" );
124-
// assert_eq!(rpf("b/c", "b/.."), "b/c" );
125-
// }
126-
//
127-
// #[test]
128-
// fn relative_path_can_raise_exceptions() {
129-
// assert!(rpfe("/", ".").is_err());
130-
// assert!(rpfe(".", "/").is_err());
131-
// assert!(rpfe("a", "..").is_err());
132-
// assert!(rpfe(".", "..").is_err());
133-
// }
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
require "benchmark_helper"
2+
3+
class RelativePathFromBenchmark < BenchmarkHelper
4+
def setup
5+
@file ||= __FILE__
6+
@one = "/a/b/c/d"
7+
@two = "/a/b"
8+
end
9+
10+
def teardown
11+
super
12+
graph_benchmarks
13+
end
14+
15+
def bench_rust_relative_path_from
16+
benchmark :rust do
17+
FasterPath.relative_path_from "/a/b/c/d", "/a/b"
18+
FasterPath.relative_path_from "/a/b", "/a/b/c/d"
19+
end
20+
end
21+
22+
def bench_ruby_relative_path_from
23+
one = Pathname.new(@one)
24+
two = Pathname.new(@two)
25+
benchmark :ruby do
26+
one.relative_path_from two
27+
two.relative_path_from one
28+
end
29+
end
30+
end

test/pbench/pbench_suite.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,4 +298,20 @@
298298
end
299299
end
300300
}
301+
PATHNAME_AB = Pathname("/a/b")
302+
PATHNAME_ABCD = Pathname("/a/b/c/d")
303+
PBENCHES[:relative_path_from] = {
304+
new: lambda do |x|
305+
x.times do
306+
FasterPath.relative_path_from "/a/b/c/d", "/a/b"
307+
FasterPath.relative_path_from "/a/b", "/a/b/c/d"
308+
end
309+
end,
310+
old: lambda do |x|
311+
x.times do
312+
PATHNAME_ABCD.relative_path_from PATHNAME_AB
313+
PATHNAME_AB.relative_path_from PATHNAME_ABCD
314+
end
315+
end
316+
}
301317
Pbench.new(nil).run(PBENCHES)

test/relative_path_from_test.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,25 @@ def test_relative_path_from
1111
assert_equal FasterPath.relative_path_from("/a/", "/b/").to_s, "../a"
1212
assert_equal FasterPath.relative_path_from("a/b", "a/c").to_s, "../b"
1313
assert_equal FasterPath.relative_path_from("../a", "../b").to_s, "../a"
14-
#assert_equal FasterPath.relative_path_from("a", ".").to_s, "a"
15-
#assert_equal FasterPath.relative_path_from(".", "a").to_s, ".."
14+
assert_equal FasterPath.relative_path_from("a", ".").to_s, "a"
15+
assert_equal FasterPath.relative_path_from(".", "a").to_s, ".."
1616
assert_equal FasterPath.relative_path_from(".", ".").to_s, "."
1717
assert_equal FasterPath.relative_path_from("..", "..").to_s, "."
18-
#assert_equal FasterPath.relative_path_from("..", ".").to_s, ".."
19-
#assert_equal FasterPath.relative_path_from("/a/b/c/d", "/a/b").to_s, "c/d"
20-
#assert_equal FasterPath.relative_path_from("/a/b", "/a/b/c/d").to_s, "../.."
21-
#assert_equal FasterPath.relative_path_from("/e", "/a/b/c/d").to_s, "../../../../e"
22-
#assert_equal FasterPath.relative_path_from("a/b/c", "a/d").to_s, "../b/c"
18+
assert_equal FasterPath.relative_path_from("..", ".").to_s, ".."
19+
assert_equal FasterPath.relative_path_from("/a/b/c/d", "/a/b").to_s, "c/d"
20+
assert_equal FasterPath.relative_path_from("/a/b", "/a/b/c/d").to_s, "../.."
21+
assert_equal FasterPath.relative_path_from("/e", "/a/b/c/d").to_s, "../../../../e"
22+
assert_equal FasterPath.relative_path_from("a/b/c", "a/d").to_s, "../b/c"
2323
assert_equal FasterPath.relative_path_from("/../a", "/b").to_s, "../a"
24-
#assert_equal FasterPath.relative_path_from("../a", "b").to_s, "../../a"
24+
assert_equal FasterPath.relative_path_from("../a", "b").to_s, "../../a"
2525
assert_equal FasterPath.relative_path_from("/a/../../b", "/b").to_s, "."
26-
#assert_equal FasterPath.relative_path_from("a/..", "a").to_s, ".."
26+
assert_equal FasterPath.relative_path_from("a/..", "a").to_s, ".."
2727
assert_equal FasterPath.relative_path_from("a/../b", "b").to_s, "."
28-
#assert_equal FasterPath.relative_path_from("a", "b/..").to_s, "a"
29-
#assert_equal FasterPath.relative_path_from("b/c", "b/..").to_s, "b/c"
28+
assert_equal FasterPath.relative_path_from("a", "b/..").to_s, "a"
29+
assert_equal FasterPath.relative_path_from("b/c", "b/..").to_s, "b/c"
3030
assert_raises(ArgumentError) { FasterPath.relative_path_from("/", ".") }
3131
assert_raises(ArgumentError) { FasterPath.relative_path_from(".", "/") }
3232
assert_raises(ArgumentError) { FasterPath.relative_path_from("a", "..") }
33-
#assert_raises(ArgumentError) { FasterPath.relative_path_from(".", "..") }
33+
assert_raises(ArgumentError) { FasterPath.relative_path_from(".", "..") }
3434
end
3535
end

0 commit comments

Comments
 (0)