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
    })
}

Exit with Ruby VM with status code.

Examples

extern crate rutie;
use rutie::VM;

VM::exit(0)

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

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Performs the conversion.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.