pub struct VM;
Expand description
Virtual Machine and helpers
Implementations
sourceimpl VM
impl VM
sourcepub fn init()
pub fn init()
Initializes Ruby virtual machine.
This function should ONLY be used if you write a standalone application which calls Ruby itself, for example:
-
Sidekiq-like background processing
-
Unicorn-like web server
In these cases it should be called before any interaction with Ruby.
If you write a library which is being connected to Ruby in runtime (e.g. some gem), this function should not be used.
Examples
use rutie::{Class, VM};
VM::init();
// VM started, able to use Ruby now
// ...
Class::new("SomeClass", None); // etc
sourcepub fn init_loadpath()
pub fn init_loadpath()
Initializes Ruby load path.
This enables more of Ruby’s internal features such as making additional encodings available.
This function, like VM::init
, should ONLY be used if you write a standalone
application which calls Ruby itself.
If you write a library which is being connected to Ruby in runtime (e.g. some gem), this function should not be used.
Examples
use rutie::{RString, Encoding, EncodingSupport, VM, Object};
VM::init_loadpath(); // Needed for alternate encodings
VM::require("enc/encdb");
VM::require("enc/trans/transdb");
let bytes = [254, 255, 1, 65, 0, 97, 1, 66] ;
let enc = Encoding::find("UTF-16").unwrap();
let mut string = RString::from_bytes(&bytes, &enc);
assert_eq!(string.to_bytes_unchecked(), bytes);
assert!(string.encoding().equals(&enc), "not equal!");
sourcepub fn require(name: &str)
pub fn require(name: &str)
Requires Ruby source file.
Examples
use rutie::VM;
VM::require("some_ruby_file");
Ruby:
require 'some_ruby_file'
sourcepub fn raise(exception: Class, message: &str)
pub fn raise(exception: Class, message: &str)
Raises an exception.
Examples
Built-in exceptions
use rutie::{Class, VM};
VM::raise(Class::from_existing("ArgumentError"), "Wrong argument");
Ruby:
raise ArgumentError, 'Wrong argument'
Custom exceptions
use rutie::{Class, VM};
let standard_error = Class::from_existing("StandardError");
let custom_exception = Class::new("CustomException", Some(&standard_error));
VM::raise(custom_exception, "Something went wrong");
Ruby:
class CustomException < StandardError
end
raise CustomException, 'Something went wrong'
sourcepub fn raise_ex(exception: AnyException)
pub fn raise_ex(exception: AnyException)
Raises an exception from a native AnyException
object.
Examples
Built-in exceptions
use rutie::{Class, VM, Exception, AnyException};
VM::raise_ex(AnyException::new("StandardError", Some("something went wrong")));
Ruby:
raise StandardError, 'something went wrong'
Custom exceptions
use rutie::{Class, VM, Exception, AnyException};
let standard_error = Class::from_existing("StandardError");
Class::new("CustomException", Some(&standard_error));
let exception = AnyException::new("CustomException", Some("something went wrong"));
VM::raise_ex(exception);
Ruby:
class CustomException < StandardError
end
raise CustomException, 'Something went wrong'
sourcepub fn eval(string: &str) -> Result<AnyObject, AnyException>
pub fn eval(string: &str) -> Result<AnyObject, AnyException>
Evals string and returns an Result<AnyObject, c_int>
Examples
#[macro_use]
extern crate rutie;
use rutie::{Class, Fixnum, Object, VM};
fn main() {
// Successful example
let result = VM::eval("2+2").ok().unwrap().try_convert_to::<Fixnum>();
assert_eq!(result, Ok(Fixnum::new(4)));
// Error example
let result = VM::eval("raise 'flowers'");
assert!(result.is_err());
}
Err
will return an AnyObject
of the exception class raised.
#[macro_use]
extern crate rutie;
use rutie::{Class, Fixnum, Object, Exception, RString, VM};
fn main() {
let result = VM::eval("raise IndexError, 'flowers'");
match result {
Err(ao) => {
let err = ao.message();
assert_eq!(err, "flowers");
},
_ => { unreachable!() }
}
}
Be aware when checking for equality amongst types like strings, that even with the same content in Ruby, they will evaluate to different values in C/Rust.
sourcepub unsafe fn eval_str(string: &str) -> AnyObject
pub unsafe fn eval_str(string: &str) -> AnyObject
Evals string and returns an AnyObject
Examples
#[macro_use]
extern crate rutie;
use rutie::{Class, Fixnum, Object, VM};
fn main() {
let result = unsafe { VM::eval_str("2+2").try_convert_to::<Fixnum>() };
assert_eq!(result, Ok(Fixnum::new(4)));
}
Be aware when checking for equality amongst types like strings, that even with the same content in Ruby, they will evaluate to different values in C/Rust.
Marked unsafe because “evaluation can raise an exception.”
sourcepub fn block_proc() -> Proc
pub fn block_proc() -> Proc
Converts a block given to current method to a Proc
It works similarly to def method(&block)
which converts block to Proc
Examples
#[macro_use]
extern crate rutie;
use rutie::{Class, Object, Proc, RString, VM};
class!(Greeter);
methods!(
Greeter,
itself,
fn greet_rust_with() -> RString {
let greeting_template = VM::block_proc();
let name = RString::new_utf8("Rust").to_any_object();
greeting_template.call(Some(&[name])).try_convert_to::<RString>().unwrap()
}
);
fn main() {
Class::new("Greeter", None).define(|itself| {
itself.def_self("greet_rust_with", greet_rust_with);
});
}
Ruby:
class Greeter
def self.greet_rust_with(&greeting_template)
greeting_template.call('Rust')
end
end
Greeter.greet_rust_with do |name|
"Hello, #{name}!"
end
sourcepub fn is_block_given() -> bool
pub fn is_block_given() -> bool
Checks if a block is given to current method.
Examples
#[macro_use] extern crate rutie;
use rutie::{Class, Fixnum, Object, VM};
class!(Calculator);
methods!(
Calculator,
itself,
fn calculate(a: Fixnum, b: Fixnum) -> Fixnum {
let a = a.unwrap();
let b = b.unwrap();
if VM::is_block_given() {
let arguments = [a.to_any_object(), b.to_any_object()];
let result = VM::block_proc().call(Some(&arguments));
result.try_convert_to::<Fixnum>().unwrap()
} else {
Fixnum::new(a.to_i64() + b.to_i64())
}
}
);
fn main() {
Class::new("Calculator", None).define(|itself| {
itself.def("calculate", calculate);
});
}
Ruby:
class Calculator
def calculate(a, b, &block)
if block_given?
block.call(a, b)
else
a + b
end
end
end
sourcepub fn yield_object(object: impl Object) -> AnyObject
pub fn yield_object(object: impl Object) -> AnyObject
Yield object to block
Examples
#[macro_use] extern crate rutie;
use rutie::{Class, Fixnum, Object, VM};
class!(Calculator);
methods!(
Calculator,
itself,
fn calculate(a: Fixnum) -> Fixnum {
let a = a.map_err(|e| VM::raise_ex(e) ).unwrap();
if VM::is_block_given() {
let argument = a.to_any_object();
let result = VM::yield_object(a);
result.try_convert_to::<Fixnum>().unwrap()
} else {
VM::raise(Class::from_existing("LocalJumpError"), "no block given (yield)");
unreachable!();
}
}
);
fn main() {
Class::new("Calculator", None).define(|itself| {
itself.def("calculate", calculate);
});
let result = VM::eval(" Calculator.new().calculate(4) { |n| n * n } ").unwrap();
let num = result.try_convert_to::<Fixnum>().unwrap().to_i64();
assert_eq!(num, 16);
}
Ruby:
class Calculator
def calculate(a)
if block_given?
yield a
else
raise LocalJumpError, "no block given (yield)"
end
end
end
result = Calculator.new.calculate(4) { |n| n * n }
result == 16
sourcepub fn yield_splat(objects: Array) -> AnyObject
pub fn yield_splat(objects: Array) -> AnyObject
Yield splat from array of Ruby objects to block
Examples
#[macro_use] extern crate rutie;
use rutie::{Array, Class, Fixnum, Object, VM};
class!(Calculator);
methods!(
Calculator,
itself,
fn calculate(a: Array) -> Fixnum {
let a = a.map_err(|e| VM::raise_ex(e) ).unwrap();
if VM::is_block_given() {
let argument = a.to_any_object();
let result = VM::yield_splat(a);
result.try_convert_to::<Fixnum>().unwrap()
} else {
VM::raise(Class::from_existing("LocalJumpError"), "no block given (yield)");
unreachable!();
}
}
);
fn main() {
Class::new("Calculator", None).define(|itself| {
itself.def("calculate", calculate);
});
let result = VM::eval(" Calculator.new().calculate([4,6,8]) { |a,b,c| a*b-c } ").unwrap();
let num = result.try_convert_to::<Fixnum>().unwrap().to_i64();
assert_eq!(num, 16);
}
Ruby:
class Calculator
def calculate(a)
if block_given?
yield a
else
raise LocalJumpError, "no block given (yield)"
end
end
end
result = Calculator.new.calculate([4,6,8]) { |a,b,c| a*b-c }
result == 16
sourcepub fn protect<F>(func: F) -> Result<AnyObject, i32>where
F: FnMut() -> Value,
pub fn protect<F>(func: F) -> Result<AnyObject, i32>where
F: FnMut() -> Value,
Run a closure
and protect from panic during raised excpetions
by returning Err<i32>
.
Examples
fn protect_send(&self, method: &str, arguments: Option<&[AnyObject]>) -> Result<AnyObject, AnyException> {
let closure = || { self.send(&method, arguments).value() };
let result = VM::protect(closure);
result.map_err(|_| {
let output = VM::error_info().unwrap();
// error cleanup
VM::clear_error_info();
output
})
}
sourcepub fn error_info() -> Result<AnyException, NilClass>
pub fn error_info() -> Result<AnyException, NilClass>
Get current VM error info.
Examples
fn protect_send(&self, method: &str, arguments: Option<&[AnyObject]>) -> Result<AnyObject, AnyException> {
let closure = || { self.send(&method, arguments).value() };
let result = VM::protect(closure);
result.map_err(|_| {
let output = VM::error_info().unwrap();
// error cleanup
VM::clear_error_info();
output
})
}
sourcepub fn clear_error_info()
pub fn clear_error_info()
Clear current VM error info.
Examples
fn protect_send(&self, method: &str, arguments: Option<&[AnyObject]>) -> Result<AnyObject, AnyException> {
let closure = || { self.send(&method, arguments).value() };
let result = VM::protect(closure);
result.map_err(|_| {
let output = VM::error_info().unwrap();
// error cleanup
VM::clear_error_info();
output
})
}