diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..072bbc6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "spec/ruby_spec"] + path = spec/ruby_spec + url = https://github.com/ruby/spec diff --git a/Gemfile b/Gemfile index b806447..a9dfb0a 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,6 @@ source 'https://rubygems.org' # Specify your gem's dependencies in faster_path.gemspec gemspec + +# https://github.com/ruby/spec dependencies +eval_gemfile File.expand_path('spec/ruby_spec/Gemfile', File.dirname(__FILE__)) diff --git a/README.md b/README.md index f492bb9..3be48dd 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ And then execute: Or install it yourself as: $ gem install faster_path - + **MAC USERS:** At the moment Mac users need to install the extension manualy. Go to the gem directory and run `cargo build --release` . There is an issue opened for this and I'm looking for people who have Macs to help on this. ## Usage @@ -134,7 +134,7 @@ Current methods implemented: | `FasterPath.add_trailing_separator` | `Pathname#add_trailing_separator` | 46.8% | You may choose to use the methods directly, or scope change to rewrite behavior on the -standard library with the included refinements, or even call a method to monkeypatch +standard library with the included refinements, or even call a method to monkeypatch everything everywhere. **Note:** `Pathname#chop_basename` in Ruby STDLIB has a bug with blank strings, that is the @@ -169,6 +169,42 @@ Whenever feasible implement it in Rust. After checking out the repo, make sure you have Rust installed. Then run `bundle && rake build_lib` . Then, run `rake test` to run the tests, and `rake bench` for benchmarks. +### Building and running tests + +First, bundle the gem's development dependencies by running `bundle`. + +Then, build the rust code: + +```sh +rake build_src +``` + +FasterPath is tested with [The Ruby Spec Suite](https://github.com/ruby/spec) to ensure it is compatible with the +native implementation, and also has its own test suite testing its monkey-patching and refinements functionality. + +To run all the tests at once, simply run `rake`. +To run all the ruby spec tests, run `mspec`. + +To run an individual test or benchmark from FasterPath's own suite: + +```sh +# An individual test file: +ruby -I lib:test test/benches/absolute_benchmark.rb +# All tests: +rake minitest +``` + +To run an individual ruby spec test, run `mspec` with a path relative to `spec/ruby_spec`, e.g.: + +```sh +# A path to a file or a directory: +mspec core/file/basename_spec.rb +# Tests most relevant to FasterPath: +mspec core/file library/pathname +# All tests: +mspec +``` + ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/danielpclark/faster_path. diff --git a/Rakefile b/Rakefile index 304c1a1..45c037c 100644 --- a/Rakefile +++ b/Rakefile @@ -27,12 +27,16 @@ task :build_lib => [:build_src, :clean_src] do puts "Completed build!" end -Rake::TestTask.new(:test) do |t| +Rake::TestTask.new(:minitest) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList['test/**/*_test.rb'] end +task :test => :minitest do |t| + exec 'mspec' +end + Rake::TestTask.new(:bench) do |t| t.libs = %w(lib test) t.pattern = 'test/**/*_benchmark.rb' diff --git a/lib/faster_path/optional/monkeypatches.rb b/lib/faster_path/optional/monkeypatches.rb index 58373fa..a210ec7 100644 --- a/lib/faster_path/optional/monkeypatches.rb +++ b/lib/faster_path/optional/monkeypatches.rb @@ -1,10 +1,12 @@ +require 'pathname' + module FasterPath def self.sledgehammer_everything! - ::File.class_eval do - def basename(pth) - FasterPath.basename(pth) - end - end + ::File.module_eval do + def self.basename(pth, ext = '') + FasterPath.basename(pth, ext) + end + end ::Pathname.class_eval do def absolute? diff --git a/lib/faster_path/optional/refinements.rb b/lib/faster_path/optional/refinements.rb index d9056a3..a4bb3af 100644 --- a/lib/faster_path/optional/refinements.rb +++ b/lib/faster_path/optional/refinements.rb @@ -1,11 +1,11 @@ module FasterPath module RefineFile refine File do - def basename(pth) - FasterPath.basename(pth) + def self.basename(pth, ext = '') + FasterPath.basename(pth, ext) end end - end + end module RefinePathname refine Pathname do diff --git a/spec/default.mspec b/spec/default.mspec new file mode 100644 index 0000000..717d504 --- /dev/null +++ b/spec/default.mspec @@ -0,0 +1,5 @@ +load 'spec/ruby_spec/default.mspec' + +MSpecScript.set :requires, ["-r#{File.expand_path('init', File.dirname(__FILE__))}"] + +Dir.chdir('spec/ruby_spec') diff --git a/spec/init.rb b/spec/init.rb new file mode 100644 index 0000000..afe0b11 --- /dev/null +++ b/spec/init.rb @@ -0,0 +1,5 @@ +ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__)) +$LOAD_PATH.unshift File.expand_path('../lib', File.dirname(__FILE__)) +require 'faster_path' +require 'faster_path/optional/monkeypatches' +FasterPath.sledgehammer_everything! diff --git a/spec/ruby_spec b/spec/ruby_spec new file mode 160000 index 0000000..8190a7c --- /dev/null +++ b/spec/ruby_spec @@ -0,0 +1 @@ +Subproject commit 8190a7c915fbcf4776b99390418fe63fc6086c02 diff --git a/src/basename.rs b/src/basename.rs index 7d69f89..2174240 100644 --- a/src/basename.rs +++ b/src/basename.rs @@ -30,15 +30,15 @@ fn it_chomps_strings_correctly(){ 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","") , "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"); @@ -58,7 +58,7 @@ pub extern fn basename(str_pth: *const c_char, comp_ext: *const c_char) -> *cons let c_str1 = unsafe { if str_pth.is_null(){ return str_pth; - } + } CStr::from_ptr(str_pth) }; let c_str2 = unsafe { @@ -72,15 +72,20 @@ pub extern fn basename(str_pth: *const c_char, comp_ext: *const c_char) -> *cons 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 + match base.rfind(".") { + Some(index) => &base[0..index], + _ => base, + } } else { - if &string[string.len()-globish_string.len()..] == globish_string { - &string[0..string.len()-globish_string.len()] - } else { + if string == "/" { string - }.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("") + } 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() }