Struct rutie::VM [−][src]
pub struct VM;
Expand description
Virtual Machine and helpers
Implementations
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
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!");
Requires Ruby source file.
Examples
use rutie::VM;
VM::require("some_ruby_file");
Ruby:
require 'some_ruby_file'
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'
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'
Evals string and returns an Result<AnyObject, AnyException>
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.
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.”
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,
rtself,
fn greet_rust_with() -> RString {
let greeting_template = VM::block_proc();
let name = RString::new_utf8("Rust").to_any_object();
greeting_template.call(&[name]).try_convert_to::<RString>().unwrap()
}
);
fn main() {
Class::new("Greeter", None).define(|klass| {
klass.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
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,
rtself,
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(&arguments);
result.try_convert_to::<Fixnum>().unwrap()
} else {
Fixnum::new(a.to_i64() + b.to_i64())
}
}
);
fn main() {
Class::new("Calculator", None).define(|klass| {
klass.def("calculate", calculate);
});
}
Ruby:
class Calculator
def calculate(a, b, &block)
if block_given?
block.call(a, b)
else
a + b
end
end
end
Yield object to block
Examples
#[macro_use] extern crate rutie;
use rutie::{Class, Fixnum, Object, VM};
class!(Calculator);
methods!(
Calculator,
rtself,
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(|klass| {
klass.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
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,
rtself,
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(|klass| {
klass.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
Run a closure
and protect from panic during raised excpetions
by returning Err<i32>
.
Examples
fn protect_send(&self, method: &str, arguments: &[AnyObject]) -> Result<AnyObject, AnyException> {
let closure = || self.send(&method, arguments.as_ref());
let result = VM::protect(closure);
result.map_err(|_| {
let output = VM::error_info().unwrap();
// error cleanup
VM::clear_error_info();
output
})
}
Get current VM error info.
Examples
fn protect_send(&self, method: &str, arguments: &[AnyObject]) -> Result<AnyObject, AnyException> {
let closure = || self.send(&method, arguments.as_ref()).into();
let result = VM::protect(closure);
result.map_err(|_| {
let output = VM::error_info().unwrap();
// error cleanup
VM::clear_error_info();
output
})
}
Get current VM error info and reset it. If no error exists
then Err(NilClass::new())
is returned.
use rutie::{VM, Exception, AnyException, Object};
let closure = || unsafe { VM::eval_str("raise 'hello world!'").into() };
let result = VM::protect(closure);
let exception = VM::error_pop().expect("nil should not have occurred here!");
assert_eq!("hello world!", exception.message());
Clear current VM error info.
Examples
fn protect_send(&self, method: &str, arguments: &[AnyObject]) -> Result<AnyObject, AnyException> {
let closure = || self.send(&method, arguments.as_ref()).into();
let result = VM::protect(closure);
result.map_err(|_| {
let output = VM::error_info().unwrap();
// error cleanup
VM::clear_error_info();
output
})
}
Exits the process immediately. No exit handlers are
run. status
is returned to the underlying system as the
exit status.
call-seq:
Process.exit!(status=false)
Note: Because the VM is exiting — having a return object is not a viable option and therefore you must account for any exceptions that may arise yourself.
Examples
extern crate rutie;
use rutie::{VM,Boolean};
unsafe { VM::exit_bang(&[Boolean::new(true).into()]) }
Process.exit!(true)
Since invalid arguments can raise an exception this is marked as unsafe. Simply use VM::protect
and VM::error_pop
to handle potential exceptions.
extern crate rutie;
use rutie::{VM, Symbol, NilClass, Object, AnyException, Exception};
VM::protect(|| {
unsafe { VM::exit_bang(&[Symbol::new("asdf").into()]) };
NilClass::new().into()
});
let error = VM::error_pop();
assert_eq!(error.unwrap().inspect(), "#<TypeError: no implicit conversion of Symbol into Integer>");
Terminate execution immediately, effectively by calling
Kernel.exit(false)
. If msg is given, it is written
to STDERR prior to terminating.
call-seq:
abort
Kernel::abort([msg])
Process.abort([msg])
Note: Because the VM is aborting — having a return object is not a viable option and therefore you must account for any exceptions that may arise yourself.
Examples
extern crate rutie;
use rutie::{VM, NilClass, AnyException, Exception, RString};
VM::protect(|| {
unsafe { VM::abort(&[RString::new_utf8("Goodbye cruel world!").into()]) }
NilClass::new().into()
});
let error = VM::error_pop();
assert_eq!(error.unwrap().inspect(), "#<SystemExit: Goodbye cruel world!>");
abort "Goodbye cruel world!"
Since invalid arguments can raise an exception this is marked as unsafe. Simply use VM::protect
and VM::error_pop
to handle potential exceptions.
extern crate rutie;
use rutie::{VM, Symbol, NilClass, Object, AnyException, Exception};
VM::protect(|| {
unsafe { VM::abort(&[Symbol::new("asdf").into()]) };
NilClass::new().into()
});
let error = VM::error_pop();
assert_eq!(error.unwrap().inspect(), "#<TypeError: no implicit conversion of Symbol into String>");
Specifies the handling of signals. The first parameter is a signal name (a string such as “SIGALRM”, “SIGUSR1”, and so on) or a signal number. The characters “SIG” may be omitted from the signal name. The command or block specifies code to be run when the signal is raised. If the command is the string “IGNORE” or “SIG_IGN”, the signal will be ignored. If the command is “DEFAULT” or “SIG_DFL”, the Ruby’s default handler will be invoked. If the command is “EXIT”, the script will be terminated by the signal. If the command is “SYSTEM_DEFAULT”, the operating system’s default handler will be invoked. Otherwise, the given command or block will be run. The special signal name “EXIT” or signal number zero will be invoked just prior to program termination. trap returns the previous handler for the given signal.
Signal.trap(0, proc { puts "Terminating: #{$$}" })
Signal.trap("CLD") { puts "Child died" }
fork && Process.wait
produces:
Terminating: 27461
Child died
Terminating: 27460
at_exit
is run AFTER the VM is shut down
Examples
use rutie::VM;
let closure = |_vm| {
println!("at_exit worked!");
};
VM::at_exit(closure);
Call super
Examples
#[macro_use] extern crate rutie;
use rutie::{Class, Fixnum, Object, VM, Exception};
class!(Adder);
methods!(
Adder,
rtself,
fn adder_add(a: Fixnum, b: Fixnum) -> Fixnum {
if let Err(ref error) = a {
VM::raise(error.class(), &error.message());
}
if let Err(ref error) = b {
VM::raise(error.class(), &error.message());
}
// We can safely unwrap here
let a = a.unwrap().to_i64();
// We can safely unwrap here
let b = b.unwrap().to_i64();
Fixnum::new(a + b)
}
);
class!(DoAdder);
methods!(
DoAdder,
rtself,
fn do_adder_add(a: Fixnum, b: Fixnum) -> Fixnum {
if let Err(ref error) = a {
VM::raise(error.class(), &error.message());
}
if let Err(ref error) = b {
VM::raise(error.class(), &error.message());
}
unsafe {
VM::call_super(&[
a.unwrap().into(),
b.unwrap().into()
]).to::<Fixnum>()
}
}
);
fn main() {
Class::new("Adder", None).define(|klass| {
klass.def("add", adder_add);
});
Class::new("DoAdder", Some(&Class::from_existing("Adder"))).define(|klass| {
klass.def("add", do_adder_add);
});
let result = VM::eval(" DoAdder.new().add(4, 4) ").unwrap();
let num = result.try_convert_to::<Fixnum>().unwrap().to_i64();
assert_eq!(num, 8);
}
Ruby:
class Adder
def add(a, b)
a + b
end
end
class DoAdder < Adder
def add(a, b)
super(a, b)
end
end
result = DoAdder.new.add(4, 4)
result == 8