Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,17 @@ task :init_mspec do |_t|
end

task test: [:cargo, :minitest, :lint, :pbench, :init_mspec] do |_t|
exec 'spec/mspec/bin/mspec --format spec core/file/basename core/file/extname core/file/dirname library/pathname'
exec 'bundle exec spec/mspec/bin/mspec --format spec core/file/basename core/file/extname core/file/dirname library/pathname'
end

desc "Full mspec results w/o encoding"
task mspec_full: :init_mspec do
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")
exec %(bash -c "TEST_MONKEYPATCHES=true WITH_REGRESSION=true bundle exec spec/mspec/bin/mspec --format spec core/file/basename core/file/extname core/file/dirname library/pathname")
end

desc "Full mspec results w/ encoding"
task mspec_encoding_full: :init_mspec do
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")
exec %(bash -c "ENCODING=1 TEST_MONKEYPATCHES=true WITH_REGRESSION=true bundle exec spec/mspec/bin/mspec --format spec core/file/basename core/file/extname core/file/dirname library/pathname")
end

Rake::TestTask.new(bench: :build_lib) do |t|
Expand Down
83 changes: 41 additions & 42 deletions src/basename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,24 @@ use self::memchr::memrchr;

use path_parsing::{find_last_sep_pos, find_last_non_sep_pos};

pub fn basename<'a>(path: &'a str, ext: &str) -> &'a str {
let bytes: &[u8] = path.as_bytes();
pub fn basename<'a>(path: &'a [u8], ext: &str) -> &'a [u8] {
let mut left: usize = 0;
let mut right: usize = bytes.len();
if let Some(last_slash_pos) = find_last_sep_pos(bytes) {
let mut right: usize = path.len();
if let Some(last_slash_pos) = find_last_sep_pos(path) {
if last_slash_pos == right - 1 {
if let Some(pos) = find_last_non_sep_pos(&bytes[..last_slash_pos]) {
if let Some(pos) = find_last_non_sep_pos(&path[..last_slash_pos]) {
right = pos + 1;
} else {
return "/";
return "/".as_bytes();
}
if let Some(pos) = find_last_sep_pos(&bytes[..right]) {
if let Some(pos) = find_last_sep_pos(&path[..right]) {
left = pos + 1;
}
} else {
left = last_slash_pos + 1;
}
}
&path[left..left + ext_end(&bytes[left..right], ext)]
&path[left..left + ext_end(&path[left..right], ext)]
}

fn ext_end(slice: &[u8], ext: &str) -> usize {
Expand All @@ -44,103 +43,103 @@ fn ext_end(slice: &[u8], ext: &str) -> usize {
#[test]
fn non_dot_asterisk_ext() {
// This is undocumented Ruby functionality. We match it in case some code out there relies on it.
assert_eq!(basename("abc", "b*"), "a");
assert_eq!(basename("abc", "abc"), "abc");
assert_eq!(basename("abc", "a*"), "abc");
assert_eq!(basename("playlist", "l*"), "play");
assert_eq!(basename("abc".as_bytes(), "b*"), b"a");
assert_eq!(basename("abc".as_bytes(), "abc"), b"abc");
assert_eq!(basename("abc".as_bytes(), "a*"), b"abc");
assert_eq!(basename("playlist".as_bytes(), "l*"), b"play");
// Treated as literal "*":
assert_eq!(basename("playlist", "yl*"), "playlist");
assert_eq!(basename("playl*", "yl*"), "pla");
assert_eq!(basename("playlist".as_bytes(), "yl*"), b"playlist");
assert_eq!(basename("playl*".as_bytes(), "yl*"), b"pla");
}

#[test]
fn empty() {
assert_eq!(basename("", ""), "");
assert_eq!(basename("", ".*"), "");
assert_eq!(basename("", ".a"), "");
assert_eq!(basename("".as_bytes(), ""), b"");
assert_eq!(basename("".as_bytes(), ".*"), b"");
assert_eq!(basename("".as_bytes(), ".a"), b"");
}

#[test]
fn sep() {
assert_eq!(basename("/", ""), "/");
assert_eq!(basename("//", ""), "/");
assert_eq!(basename("/".as_bytes(), ""), b"/");
assert_eq!(basename("//".as_bytes(), ""), b"/");
}

#[test]
fn trailing_dot() {
assert_eq!(basename("file.test.", ""), "file.test.");
assert_eq!(basename("file.test.", "."), "file.test");
assert_eq!(basename("file.test.", ".*"), "file.test");
assert_eq!(basename("file.test.".as_bytes(), ""), b"file.test.");
assert_eq!(basename("file.test.".as_bytes(), "."), b"file.test");
assert_eq!(basename("file.test.".as_bytes(), ".*"), b"file.test");
}

#[test]
fn trailing_dot_dot() {
assert_eq!(basename("a..", ".."), "a");
assert_eq!(basename("a..", ".*"), "a.");
assert_eq!(basename("a..".as_bytes(), ".."), b"a");
assert_eq!(basename("a..".as_bytes(), ".*"), b"a.");
}

#[test]
fn dot() {
assert_eq!(basename(".", ""), ".");
assert_eq!(basename(".", "."), ".");
assert_eq!(basename(".", ".*"), ".");
assert_eq!(basename(".".as_bytes(), ""), b".");
assert_eq!(basename(".".as_bytes(), "."), b".");
assert_eq!(basename(".".as_bytes(), ".*"), b".");
}

#[test]
fn dot_dot() {
assert_eq!(basename("..", ""), "..");
assert_eq!(basename("..", ".*"), "..");
assert_eq!(basename("..", ".."), "..");
assert_eq!(basename("..", "..."), "..");
assert_eq!(basename("..".as_bytes(), ""), b"..");
assert_eq!(basename("..".as_bytes(), ".*"), b"..");
assert_eq!(basename("..".as_bytes(), ".."), b"..");
assert_eq!(basename("..".as_bytes(), "..."), b"..");
}

#[test]
fn non_dot_ext() {
assert_eq!(basename("abc", "bc"), "a");
assert_eq!(basename("abc".as_bytes(), "bc"), b"a");
}

#[test]
fn basename_eq_ext() {
assert_eq!(basename(".x", ".x"), ".x");
assert_eq!(basename(".x", ".*"), ".x");
assert_eq!(basename(".x".as_bytes(), ".x"), b".x");
assert_eq!(basename(".x".as_bytes(), ".*"), b".x");
}

#[test]
fn absolute() {
assert_eq!(basename("/a/b///c", ""), "c");
assert_eq!(basename("/a/b///c".as_bytes(), ""), b"c");
}

#[test]
fn trailing_slashes_absolute() {
assert_eq!(basename("/a/b///c//////", ""), "c");
assert_eq!(basename("/a/b///c//////".as_bytes(), ""), b"c");
}

#[test]
fn relative() {
assert_eq!(basename("b///c", ""), "c");
assert_eq!(basename("b///c".as_bytes(), ""), b"c");
}

#[test]
fn trailing_slashes_relative() {
assert_eq!(basename("b/c//", ""), "c");
assert_eq!(basename("b/c//".as_bytes(), ""), b"c");
}

#[test]
fn root() {
assert_eq!(basename("//c", ""), "c");
assert_eq!(basename("//c".as_bytes(), ""), b"c");
}

#[test]
fn trailing_slashes_root() {
assert_eq!(basename("//c//", ""), "c");
assert_eq!(basename("//c//".as_bytes(), ""), b"c");
}

#[test]
fn trailing_slashes_relative_root() {
assert_eq!(basename("c//", ""), "c");
assert_eq!(basename("c//".as_bytes(), ""), b"c");
}

#[test]
fn edge_case_all_seps() {
assert_eq!("/", basename("///", ".*"));
assert_eq!(b"/", basename("///".as_bytes(), ".*"));
}
2 changes: 1 addition & 1 deletion src/cleanpath_aggressive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn cleanpath_aggressive(path: &str) -> Cow<str> {
// pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
// ```
//
if contains_sep(basename(&prefix, "").as_bytes()) {
if contains_sep(basename(&prefix.as_bytes(), "")) {
let len = names.iter().rposition(|&c| c != "..").map_or(0, |pos| pos + 1);
names.truncate(len);
}
Expand Down
4 changes: 2 additions & 2 deletions src/cleanpath_conservative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn cleanpath_conservative(path: &str) -> Cow<str> {
// pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
// ```
//
if contains_sep(basename(&prefix, "").as_bytes()) {
if contains_sep(basename(&prefix.as_bytes(), "")) {
let len = names.iter().rposition(|&c| c != "..").map_or(0, |pos| pos + 1);
names.truncate(len);
}
Expand All @@ -31,7 +31,7 @@ pub fn cleanpath_conservative(path: &str) -> Cow<str> {
None => return dirname(&prefix).into(),
};

if last_name != ".." && basename(&path, "") == "." {
if last_name != ".." && basename(&path.as_bytes(), "") == ".".as_bytes() {
names.reverse();
names.push(".");
} else if last_name != "." && last_name != ".." &&
Expand Down
9 changes: 8 additions & 1 deletion src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,14 @@ pub fn anyobject_to_string(item: AnyObject) -> Result<String, RubyDebugInfo> {

pub fn to_str(maybe_string: &MaybeString) -> &str {
match maybe_string {
&Ok(ref rutie_string) => rutie_string.to_str(),
&Ok(ref rutie_string) => rutie_string.to_str_unchecked(),
&Err(_) => "",
}
}

pub fn to_bytes(maybe_string: &MaybeString) -> &[u8] {
match maybe_string {
&Ok(ref rutie_string) => rutie_string.to_bytes_unchecked(),
&Err(_) => &[],
}
}
5 changes: 3 additions & 2 deletions src/pathname.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use extname;
use plus;
use relative_path_from;
use debug;
use helpers::{TryFrom, to_str};
use helpers::{TryFrom, to_str, to_bytes};
use path_parsing::{SEP, find_last_non_sep_pos};

use rutie;
Expand All @@ -23,6 +23,7 @@ use rutie::{
VerifiedObject,
Exception as Exc,
AnyException as Exception,
Encoding,
};
use rutie::types::{Value, ValueType};
use std::borrow::Cow;
Expand Down Expand Up @@ -105,7 +106,7 @@ pub fn pn_is_absolute(pth: MaybeString) -> Boolean {
// pub fn pn_ascend(){}

pub fn pn_basename(pth: MaybeString, ext: MaybeString) -> RString {
RString::new_utf8(basename::basename(to_str(&pth), to_str(&ext)))
RString::from_bytes(basename::basename(to_bytes(&pth), to_str(&ext)), &Encoding::utf8())
}

pub fn pn_children(pth: MaybeString, with_dir: MaybeBoolean) -> Result<AnyObject, Exception> {
Expand Down