Skip to content

Commit d05dbd4

Browse files
authored
Merge pull request #139 from danielpclark/relative_path_from
Relative path from
2 parents c61d810 + a0f35fa commit d05dbd4

18 files changed

+308
-105
lines changed

Cargo.lock

Lines changed: 9 additions & 9 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, 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, other)
88+
end
8589
end
8690
end
8791
end

src/chop_basename.rs

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,31 @@
11
use std::path::MAIN_SEPARATOR;
22
use std::str;
33

4-
pub fn chop_basename(input: &str) -> Option<(String,String)> {
4+
pub fn chop_basename<'a>(input: &'a str) -> Option<(&'a str, &'a str)> {
55
if input.is_empty() {
66
return None;
77
}
88

9-
let mut offset = 0;
10-
let mut trailing_slashes = input.chars().rev();
11-
loop {
12-
match trailing_slashes.next() {
13-
Some(MAIN_SEPARATOR) => { offset = offset + 1 },
14-
_ => { break },
15-
}
16-
}
17-
18-
let input = &input[0..input.len()-offset];
19-
let base = input.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("");
9+
let input = input.trim_right_matches(MAIN_SEPARATOR);
10+
let end = input.rsplitn(2, MAIN_SEPARATOR).nth(0).unwrap().len();
11+
let base = &input[input.len()-end..input.len()];
2012
let directory = &input[0..input.len()-base.len()];
2113

2214
if directory.is_empty() && (base.is_empty() || base.chars().next().unwrap() == MAIN_SEPARATOR) {
2315
return None
2416
};
2517

26-
Some((directory.to_string(), base.to_string()))
18+
Some((directory, base))
2719
}
2820

2921
#[test]
3022
fn it_chops_the_basename_and_dirname() {
31-
assert_eq!(chop_basename(&""[..]), None);
32-
assert_eq!(chop_basename(&"/"[..]), None);
33-
assert_eq!(
34-
chop_basename(&"."[..]),
35-
Some(("".to_string(), ".".to_string()))
36-
);
37-
assert_eq!(
38-
chop_basename(&"asdf/asdf"[..]),
39-
Some(("asdf/".to_string(), "asdf".to_string()))
40-
);
41-
assert_eq!(
42-
chop_basename(&"asdf.txt"[..]),
43-
Some(("".to_string(), "asdf.txt".to_string()))
44-
);
45-
assert_eq!(
46-
chop_basename(&"asdf/"[..]),
47-
Some(("".to_string(), "asdf".to_string()))
48-
);
49-
assert_eq!(
50-
chop_basename(&"/asdf/"[..]),
51-
Some(("/".to_string(), "asdf".to_string()))
52-
);
23+
assert_eq!(chop_basename(""), None );
24+
assert_eq!(chop_basename("/"), None );
25+
assert_eq!(chop_basename("."), Some(("", ".")) );
26+
assert_eq!(chop_basename("asdf/asdf"), Some(("asdf/", "asdf")) );
27+
assert_eq!(chop_basename("asdf.txt"), Some(("", "asdf.txt")) );
28+
assert_eq!(chop_basename("asdf/"), Some(("", "asdf")) );
29+
assert_eq!(chop_basename("/asdf/"), Some(("/", "asdf")) );
5330
}
5431

src/cleanpath_aggressive.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub fn cleanpath_aggressive(path: &str) -> String {
1010
let mut names: Vec<String> = vec![];
1111
let mut pre = path.to_string();
1212
loop {
13-
match chop_basename(&pre) {
13+
match chop_basename(&pre.clone()) {
1414
Some((ref p, ref base)) => {
1515
pre = p.to_string();
1616
match base.as_ref() {

src/cleanpath_conservative.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub fn cleanpath_conservative(path: &str) -> String {
1111
let mut names: Vec<String> = vec![];
1212
let mut pre = path.to_string();
1313
loop {
14-
match chop_basename(&pre) {
14+
match chop_basename(&pre.clone()) {
1515
Some((ref p, ref base)) => {
1616
pre = p.to_string();
1717
match base.as_ref() {
@@ -90,7 +90,7 @@ fn it_conservatively_cleans_the_path() {
9090
assert_eq!(cleanpath_conservative("a/../."), "a/..");
9191
assert_eq!(cleanpath_conservative("/../.././../a"), "/a");
9292
assert_eq!(cleanpath_conservative("a/b/../../../../c/../d"), "a/b/../../../../c/../d");
93-
;
93+
9494
// Future Windows Support
9595
//
9696
// DOSISH = File::ALT_SEPARATOR != nil

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: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
use ruru::{RString, Object, Class, AnyObject};
2-
use pathname::Pathname;
2+
use debug::RubyDebugInfo;
3+
4+
#[inline]
5+
pub fn is_same_path(a: &str, b: &str) -> bool {
6+
if cfg!(windows) {
7+
a.to_uppercase() == b.to_uppercase()
8+
} else {
9+
a == b
10+
}
11+
}
312

413
pub fn anyobject_to_string(item: AnyObject) -> Result<String, RubyDebugInfo> {
514
let result = &item;
@@ -24,40 +33,3 @@ pub fn anyobject_to_string(item: AnyObject) -> Result<String, RubyDebugInfo> {
2433

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

src/lib.rs

Lines changed: 15 additions & 3 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;
@@ -25,6 +28,10 @@ mod plus;
2528
mod prepend_prefix;
2629
pub mod rust_arch_bits;
2730
mod path_parsing;
31+
mod relative_path_from;
32+
33+
use pathname::Pathname;
34+
use pathname_sys::raise;
2835

2936
use ruru::{Module, Object, RString, Boolean, Array, AnyObject};
3037

@@ -139,8 +146,12 @@ methods!(
139146

140147
// fn r_split_names(pth: RString){}
141148

142-
// fn r_relative_path_from(){}
143-
// fn pub_relative_path_from(){}
149+
fn pub_relative_path_from(itself: RString, base_directory: AnyObject) -> Pathname {
150+
let to_string = |i: AnyObject| { RString::from(i.send("to_s", None).value()) };
151+
152+
pathname::pn_relative_path_from(itself, base_directory.map(to_string)).
153+
map_err(|e| raise(e) ).unwrap()
154+
}
144155

145156
// fn pub_rmtree(pth: RString) -> NilClass {
146157
// pathname::pn_rmtree(pth)
@@ -149,7 +160,7 @@ methods!(
149160

150161
#[allow(non_snake_case)]
151162
#[no_mangle]
152-
pub extern "C" fn Init_faster_pathname(){
163+
pub extern "C" fn Init_faster_pathname() {
153164
Module::from_existing("FasterPath").define(|itself| {
154165
itself.def_self("absolute?", pub_is_absolute);
155166
itself.def_self("add_trailing_separator", pub_add_trailing_separator);
@@ -164,6 +175,7 @@ pub extern "C" fn Init_faster_pathname(){
164175
pathname_sys::define_singleton_method(itself.value(), "join", pub_join);
165176
itself.def_self("plus", pub_plus);
166177
itself.def_self("relative?", pub_is_relative);
178+
itself.def_self("relative_path_from", pub_relative_path_from);
167179
itself.define_nested_class("Public", None);
168180
});
169181

0 commit comments

Comments
 (0)