Skip to content

Commit

Permalink
Merge pull request #80 from glebm/basename-fixes
Browse files Browse the repository at this point in the history
basename: Improve performance and style
danielpclark authored Jun 23, 2016

Verified

This commit was signed with the committer’s verified signature.
ludelafo Ludovic Delafontaine
2 parents 60a266a + f8a31f5 commit 3acbdac
Showing 4 changed files with 28 additions and 87 deletions.
4 changes: 2 additions & 2 deletions lib/faster_path/optional/monkeypatches.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module FasterPath
def self.sledgehammer_everything!
::File.class_eval do
def self.basename(pth)
FasterPath.basename(pth)
def self.basename(pth, ext = '')
FasterPath.basename(pth, ext)
end if ENV['WITH_REGRESSION']

def self.extname(pth)
4 changes: 2 additions & 2 deletions lib/faster_path/optional/refinements.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module FasterPath
module RefineFile
refine File do
def self.basename(pth)
FasterPath.basename(pth)
def self.basename(pth, ext = '')
FasterPath.basename(pth, ext)
end if ENV['WITH_REGRESSION']

def self.extname(pth)
94 changes: 17 additions & 77 deletions src/basename.rs
Original file line number Diff line number Diff line change
@@ -1,86 +1,26 @@
use std::path::MAIN_SEPARATOR;
use libc::c_char;
use std::ffi::{CStr,CString};
use std::str;
use std::ffi::{CStr, CString};

#[allow(dead_code)]
fn rubyish_basename(string: &str, globish_string: &str) -> String {
let result = if globish_string == ".*" {
let base = string.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("");
let index = base.rfind(".");
let (first, _) = base.split_at(index.unwrap());
first
} else {
if &string[string.len()-globish_string.len()..] == globish_string {
&string[0..string.len()-globish_string.len()]
} else {
string
}.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("")
};
result.to_string()
}
#[no_mangle]
pub extern "C" fn basename(c_pth: *const c_char, c_ext: *const c_char) -> *const c_char {
// TODO: rb_raise on type or encoding errors
// TODO: support objects that respond to `to_path`
if c_pth.is_null() || c_ext.is_null() {
return c_pth;
}
let pth = unsafe { CStr::from_ptr(c_pth) }.to_str().unwrap();
let ext = unsafe { CStr::from_ptr(c_ext) }.to_str().unwrap();

#[test]
fn it_chomps_strings_correctly(){
assert_eq!(rubyish_basename("","") , "");
assert_eq!(rubyish_basename("ruby","") , "ruby");
assert_eq!(rubyish_basename("ruby.rb",".rb") , "ruby");
assert_eq!(rubyish_basename("ruby.rb",".*") , "ruby");
assert_eq!(rubyish_basename(".ruby/ruby.rb",".rb") , "ruby");
assert_eq!(rubyish_basename(".ruby/ruby.rb.swp",".rb") , "ruby.rb.swp");
assert_eq!(rubyish_basename(".ruby/ruby.rb.swp",".swp") , "ruby.rb");
assert_eq!(rubyish_basename(".ruby/ruby.rb.swp",".*") , "ruby.rb");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp","") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".*") , "asdf.rb");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", "*") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".*") , "asdf.rb");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".rb") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".swp") , "asdf.rb");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".sw") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".sw*") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".rb.s*") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".s*") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".s**") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".**") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".*") , "asdf.rb");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".*.*") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".rb.swp") , "asdf");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".rb.s*p") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".r*.s*p") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".r*.sw*p") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", ".r*b.sw*p") , "asdf.rb.swp");
assert_eq!(rubyish_basename("asdf/asdf.rb.swp", "rb.swp") , "asdf.");
}
let mut name = pth.trim_right_matches(MAIN_SEPARATOR).rsplit(MAIN_SEPARATOR).next().unwrap_or("");

#[no_mangle]
pub extern fn basename(str_pth: *const c_char, comp_ext: *const c_char) -> *const c_char {
let c_str1 = unsafe {
if str_pth.is_null(){
return str_pth;
}
CStr::from_ptr(str_pth)
};
let c_str2 = unsafe {
if comp_ext.is_null() {
return str_pth;
if ext == ".*" {
if let Some(dot_i) = name.rfind('.') {
name = &name[0..dot_i];
}
CStr::from_ptr(comp_ext)
} else if name.ends_with(ext) {
name = &name[..name.len() - ext.len()];
};
let string = str::from_utf8(c_str1.to_bytes()).unwrap();
let globish_string = str::from_utf8(c_str2.to_bytes()).unwrap();

let result = if globish_string == ".*" {
let base = string.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("");
let index = base.rfind(".");
let (first, _) = base.split_at(index.unwrap());
first
} else {
if &string[string.len()-globish_string.len()..] == globish_string {
&string[0..string.len()-globish_string.len()]
} else {
string
}.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("")
};
CString::new(result).unwrap().into_raw()
CString::new(name).unwrap().into_raw()
}
13 changes: 7 additions & 6 deletions test/basename_test.rb
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

class BasenameTest < Minitest::Test
def test_nil_inputs
assert_nil FasterPath.basename(nil,nil)
assert_nil FasterPath.basename(nil,nil)
assert_equal FasterPath.basename('',nil), ""
assert_nil FasterPath.basename(nil,'')
assert_equal FasterPath.basename('asdf',nil), "asdf"
@@ -21,18 +21,19 @@ def test_it_creates_basename_correctly
assert_equal FasterPath.basename('ruby.rb', ''), 'ruby.rb'
assert_equal FasterPath.basename('ruby.rbx', '.rb*'), 'ruby.rbx'
assert_equal FasterPath.basename('ruby.rbx'), 'ruby.rbx'

# Try some extensions w/o a '.'
assert_equal FasterPath.basename('ruby.rbx', 'rbx'), 'ruby.'
assert_equal FasterPath.basename('ruby.rbx', 'x'), 'ruby.rb'
assert_equal FasterPath.basename('ruby.rbx', '*'), 'ruby.rbx'

# A couple of regressions:
assert_equal FasterPath.basename('', ''), ''
assert_equal FasterPath.basename('/'), '/'
assert_equal FasterPath.basename('//'), '/'
assert_equal FasterPath.basename('//dir///base//'), 'base'
end
assert_equal FasterPath.basename('.x', '.x'), '.x'
end

def test_it_does_the_same_as_file_basename
assert_equal File.basename('/home/gumby/work/ruby.rb'), 'ruby.rb'
@@ -45,12 +46,12 @@ def test_it_does_the_same_as_file_basename
assert_equal File.basename('ruby.rb', ''), 'ruby.rb'
assert_equal File.basename('ruby.rbx', '.rb*'), 'ruby.rbx'
assert_equal File.basename('ruby.rbx'), 'ruby.rbx'

# Try some extensions w/o a '.'
assert_equal File.basename('ruby.rbx', 'rbx'), 'ruby.'
assert_equal File.basename('ruby.rbx', 'x'), 'ruby.rb'
assert_equal File.basename('ruby.rbx', '*'), 'ruby.rbx'

# A couple of regressions:
assert_equal File.basename('', ''), ''
assert_equal File.basename('/'), '/'

0 comments on commit 3acbdac

Please sign in to comment.