Coercions for Regex

This commit is contained in:
Peter Wagenet 2017-03-13 17:10:53 -07:00
parent bda5141f37
commit 1c6c4ebb5e
7 changed files with 68 additions and 0 deletions

View File

@ -25,6 +25,7 @@ members = ["examples/calculator", "examples/console", "examples/duration", "exam
[dependencies]
libc = "0.2.0"
regex = "0.2.1"
[dependencies.libcruby-sys]
path = "crates/libcruby-sys"

View File

@ -195,11 +195,15 @@ extern "C" {
#[link_name = "HELIX_T_DATA"]
pub static T_DATA: isize;
#[link_name = "HELIX_T_REGEXP"]
pub static T_REGEXP: isize;
// unknown if working?
// fn rb_define_variable(name: c_string, value: *const VALUE);
pub fn rb_obj_class(obj: VALUE) -> VALUE;
pub fn rb_obj_classname(obj: VALUE) -> c_string;
pub fn rb_const_get(class: VALUE, name: ID) -> VALUE;
pub fn rb_class_new_instance(argc: isize, argv: *const VALUE, klass: VALUE) -> VALUE;
pub fn rb_define_global_const(name: c_string, value: VALUE);
pub fn rb_define_module(name: c_string) -> VALUE;
pub fn rb_define_module_under(namespace: VALUE, name: c_string) -> VALUE;

View File

@ -42,6 +42,14 @@ describe "Console" do
expect(console.is_red("hello".colorize(:red))).to eq(true)
end
it "can take a regex" do
expect { console.log_regex(/[a-z]\w+/im) }.to println('(?mi-x:[a-z]\w+)')
end
it "can return a regex" do
expect(console.filter("testing")).to eq(/LOG[(testing)?]:\s+/)
end
[:raise, :raise_panic, :panic].each do |method|
it "can handle #{method}" do
expect { console.send(method) }.to raise_error(RuntimeError, "raised from Rust with `#{method}`")

View File

@ -41,6 +41,14 @@ ruby! {
string.starts_with("\x1B[0;31;49m") && string.ends_with("\x1B[0m")
}
def log_regex(&self, re: helix::regex::Regex) {
self.log(re.to_string());
}
def filter(&self, string: String) -> helix::regex::Regex {
helix::regex::Regex::new(format!("LOG[({})?]:\\s+", string).as_str()).unwrap()
}
def raise(&self) -> Result<(), helix::Error> {
raise!("raised from Rust with `raise`");
}

View File

@ -10,6 +10,7 @@ mod result;
mod slice;
mod vec;
mod hash;
mod regex;
use sys::{VALUE};
use super::{Error, ToError};

43
src/coercions/regex.rs Normal file
View File

@ -0,0 +1,43 @@
use libc;
use std;
use sys;
use regex::Regex;
use sys::{VALUE};
use std::ffi::CString;
use super::{FromRuby, CheckResult, CheckedValue, ToRuby, ToRubyResult};
impl FromRuby for Regex {
type Checked = CheckedValue<Regex>;
fn from_ruby(value: VALUE) -> CheckResult<CheckedValue<Regex>> {
if unsafe { sys::RB_TYPE_P(value, sys::T_REGEXP) } {
Ok(unsafe { CheckedValue::<Regex>::new(value) })
} else {
type_error!(value, "a Regex")
}
}
fn from_checked(checked: CheckedValue<Regex>) -> Regex {
unsafe {
let ruby_str = sys::rb_funcall(checked.inner, sys::rb_intern(CString::new("to_s").unwrap().as_ptr()), 0);
let size = sys::RSTRING_LEN(ruby_str);
let ptr = sys::RSTRING_PTR(ruby_str);
let slice = std::slice::from_raw_parts(ptr as *const u8, size as usize);
Regex::new(std::str::from_utf8(slice).unwrap()).unwrap()
}
}
}
impl ToRuby for Regex {
fn to_ruby(self) -> ToRubyResult {
let string = self.to_string();
let ptr = string.as_ptr();
let len = string.len();
let ruby_str = unsafe { sys::rb_utf8_str_new(ptr as *const libc::c_char, len as libc::c_long) };
let class_id = unsafe { sys::rb_intern(CString::new("Regexp").unwrap().as_ptr()) };
let klass = unsafe { sys::rb_const_get(sys::rb_cObject, class_id) };
let args = [ruby_str];
Ok(unsafe { sys::rb_class_new_instance(args.len() as isize, args.as_ptr(), klass) })
}
}

View File

@ -14,6 +14,9 @@ pub extern crate libc;
pub extern crate libcruby_sys as sys;
// pub use rb;
#[doc(hidden)]
pub extern crate regex;
use std::ffi::CStr;
use sys::{VALUE, ID};