Trait rutie::Object[][src]

pub trait Object: From<Value> {
    fn value(&self) -> Value;

    fn class(&self) -> Class { ... }
fn singleton_class(&self) -> Class { ... }
fn get_data<'a, T>(&'a self, wrapper: &'a DataTypeWrapper<T>) -> &T { ... }
fn get_data_mut<'a, T>(
        &'a mut self,
        wrapper: &'a DataTypeWrapper<T>
    ) -> &mut T { ... }
fn define<F: Fn(&mut Self)>(&mut self, f: F) -> &Self { ... }
fn define_method<I: Object, O: Object>(
        &mut self,
        name: &str,
        callback: Callback<I, O>
    ) { ... }
fn define_private_method<I: Object, O: Object>(
        &mut self,
        name: &str,
        callback: Callback<I, O>
    ) { ... }
fn define_singleton_method<I: Object, O: Object>(
        &mut self,
        name: &str,
        callback: Callback<I, O>
    ) { ... }
fn def<I: Object, O: Object>(
        &mut self,
        name: &str,
        callback: Callback<I, O>
    ) { ... }
fn def_private<I: Object, O: Object>(
        &mut self,
        name: &str,
        callback: Callback<I, O>
    ) { ... }
fn def_self<I: Object, O: Object>(
        &mut self,
        name: &str,
        callback: Callback<I, O>
    ) { ... }
fn send(&self, method: &str, arguments: Option<&[AnyObject]>) -> AnyObject { ... }
fn equals<T: Object>(&self, other: &T) -> bool { ... }
fn case_equals<T: Object>(&self, other: &T) -> bool { ... }
fn is_eql<T: Object>(&self, other: &T) -> bool { ... }
fn is_equal<T: Object>(&self, other: &T) -> bool { ... }
fn respond_to(&self, method: &str) -> bool { ... }
fn protect_send(
        &self,
        method: String,
        arguments: Option<&[AnyObject]>
    ) -> Result<AnyObject, AnyObject> { ... }
fn protect_public_send(
        &self,
        method: String,
        arguments: Option<&[AnyObject]>
    ) -> Result<AnyObject, AnyObject> { ... }
fn is_nil(&self) -> bool { ... }
fn to_any_object(&self) -> AnyObject { ... }
fn instance_variable_get(&self, variable: &str) -> AnyObject { ... }
fn instance_variable_set<T: Object>(
        &mut self,
        variable: &str,
        value: T
    ) -> AnyObject { ... }
fn is_frozen(&self) -> bool { ... }
fn freeze(&mut self) -> Self { ... }
unsafe fn to<T: Object>(&self) -> T { ... }
fn try_convert_to<T: VerifiedObject>(&self) -> RuruResult<T> { ... }
fn ty(&self) -> ValueType { ... } }

Object

Trait consists methods of Ruby Object class. Every struct like Array, Hash etc implements this trait.

class! macro automatically implements this trait for custom classes.

Required Methods

Returns internal value of current object.

Examples

use rutie::types::Value;
use rutie::Object;

struct Array {
    value: Value
}

impl From<Value> for Array {
    fn from(value: Value) -> Self {
        Array {
            value: value
        }
    }
}

impl Object for Array {
    fn value(&self) -> Value {
        self.value
    }
}

Provided Methods

Returns a class of current object.

Examples

use rutie::{Array, Object, VM};

assert_eq!(Array::new().class(), Array::new().class());

Returns a singleton class of current object.

Examples

Getting singleton class

use rutie::{Array, Object, VM};

let array = Array::new();
let another_array = Array::new();

assert!(array.singleton_class() != another_array.singleton_class());

Ruby:

array = []
another_array = []

array.singleton_class != another_array.singleton_class

Modifying singleton class

use rutie::{Array, Object, VM};

let array = Array::new();
let another_array = Array::new();

array.singleton_class().define(|itself| {
    itself.attr_reader("modified");
});

assert!(array.respond_to("modified"));
assert!(!another_array.respond_to("modified"));

Ruby:

array = []

class << array
  attr_reader :modified
end

array.respond_to?(:modified)
Important traits for &'a mut R

Gets an immutable reference to the Rust structure which is wrapped into a Ruby object.

See the documentation for wrappable_struct! macro for more information.

Examples

Wrap Server structs to RubyServer objects

#[macro_use] extern crate rutie;
#[macro_use] extern crate lazy_static;

use rutie::{AnyObject, Class, Fixnum, Object, RString, VM};

// The structure which we want to wrap
pub struct Server {
    host: String,
    port: u16,
}

impl Server {
    fn new(host: String, port: u16) -> Self {
        Server {
            host: host,
            port: port,
        }
    }

    fn host(&self) -> &str {
        &self.host
    }

    fn port(&self) -> u16 {
        self.port
    }
}

wrappable_struct!(Server, ServerWrapper, SERVER_WRAPPER);

class!(RubyServer);

methods!(
    RubyServer,
    itself,

    fn ruby_server_new(host: RString, port: Fixnum) -> AnyObject {
        let server = Server::new(host.unwrap().to_string(),
                                 port.unwrap().to_i64() as u16);

        Class::from_existing("RubyServer").wrap_data(server, &*SERVER_WRAPPER)
    }

    fn ruby_server_host() -> RString {
        let host = itself.get_data(&*SERVER_WRAPPER).host();

        RString::new(host)
    }

    fn ruby_server_port() -> Fixnum {
        let port = itself.get_data(&*SERVER_WRAPPER).port();

        Fixnum::new(port as i64)
    }
);

fn main() {
    let data_class = Class::from_existing("Data");

    Class::new("RubyServer", Some(&data_class)).define(|itself| {
        itself.def_self("new", ruby_server_new);

        itself.def("host", ruby_server_host);
        itself.def("port", ruby_server_port);
    });
}

To use the RubyServer class in Ruby:

server = RubyServer.new("127.0.0.1", 3000)

server.host == "127.0.0.1"
server.port == 3000
Important traits for &'a mut R

Gets a mutable reference to the Rust structure which is wrapped into a Ruby object.

Important traits for &'a mut R

Wraps calls to the object.

Mostly used to have Ruby-like class definition DSL.

Examples

Defining class

#[macro_use] extern crate rutie;

use rutie::{Class, Fixnum, Object, RString};

class!(Hello);
class!(Nested);

methods!(
    Hello,
    itself,

    fn greeting() -> RString {
        RString::new("Greeting from class")
    }

    fn many_greetings() -> RString {
        RString::new("Many greetings from instance")
    }
);

methods!(
    Nested,
    itself,

    fn nested_greeting() -> RString {
        RString::new("Greeting from nested class")
    }
);

fn main() {
    Class::new("Hello", None).define(|itself| {
        itself.attr_reader("reader");

        itself.def_self("greeting", greeting);
        itself.def("many_greetings", many_greetings);

        itself.define_nested_class("Nested", None).define(|itself| {
            itself.def_self("nested_greeting", nested_greeting);
        });
    });
}

Ruby:

class Hello
  attr_reader :reader

  def self.greeting
    'Greeting from class'
  end

  def many_greetings
    'Many greetings from instance'
  end

  class Nested
    def self.nested_greeting
      'Greeting from nested class'
    end
  end
end

Defining singleton method for an object

#[macro_use] extern crate rutie;

use rutie::{AnyObject, Class, Fixnum, Object, RString, VM};

methods!(
    RString,
    itself,

    fn greeting() -> RString {
        RString::new("Greeting!")
    }
);

fn main() {
    let mut string = RString::new("Some string");

    // The same can be done by modifying `string.singleton_class()`
    // or using `string.define_singleton_method("greeting", greeting)`
    string.define(|itself| {
        itself.define_singleton_method("greeting", greeting);
    });

    assert!(string.respond_to("greeting"));
}

Ruby:

string = "Some string"

class << string
  def greeting
    'Greeting!'
  end
end

string.respond_to?("greeting")

Defines an instance method for the given class or object.

Use methods! macro to define a callback.

You can also use def() alias for this function combined with Class::define() for a nicer DSL.

Panics

Ruby can raise an exception if you try to define instance method directly on an instance of some class (like Fixnum, String, Array etc).

Use this method only on classes (or singleton classes of objects).

Examples

The famous String#blank? method

#[macro_use] extern crate rutie;

use rutie::{Boolean, Class, Object, RString, VM};

methods!(
   RString,
   itself,

   fn is_blank() -> Boolean {
       Boolean::new(itself.to_str().chars().all(|c| c.is_whitespace()))
   }
);

fn main() {
    Class::from_existing("String").define(|itself| {
        itself.def("blank?", is_blank);
    });
}

Ruby:

class String
  def blank?
    # simplified
    self.chars.all? { |c| c == ' ' }
  end
end

Receiving arguments

Raise Fixnum to the power of exp.

#[macro_use] extern crate rutie;

use std::error::Error;

use rutie::{Class, Fixnum, Object, VM};

methods!(
    Fixnum,
    itself,

    fn pow(exp: Fixnum) -> Fixnum {
        // `exp` is not a valid `Fixnum`, raise an exception
        if let Err(ref error) = exp {
            VM::raise(error.to_exception(), error.description());
        }

        // We can safely unwrap here, because an exception was raised if `exp` is `Err`
        let exp = exp.unwrap().to_i64() as u32;

        Fixnum::new(itself.to_i64().pow(exp))
    }

    fn pow_with_default_argument(exp: Fixnum) -> Fixnum {
        let default_exp = 0;
        let exp = exp.map(|exp| exp.to_i64()).unwrap_or(default_exp);

        let result = itself.to_i64().pow(exp as u32);

        Fixnum::new(result)
    }
);

fn main() {
    Class::from_existing("Fixnum").define(|itself| {
        itself.def("pow", pow);
        itself.def("pow_with_default_argument", pow_with_default_argument);
    });
}

Ruby:

class Fixnum
  def pow(exp)
    raise ArgumentError unless exp.is_a?(Fixnum)

    self ** exp
  end

  def pow_with_default_argument(exp)
    default_exp = 0
    exp = default_exp unless exp.is_a?(Fixnum)

    self ** exp
  end
end

Defines a private instance method for the given class or object.

Use methods! macro to define a callback.

You can also use def_private() alias for this function combined with Class::define() for a nicer DSL.

Panics

Ruby can raise an exception if you try to define instance method directly on an instance of some class (like Fixnum, String, Array etc).

Use this method only on classes (or singleton classes of objects).

Examples

The famous String#blank? method

#[macro_use] extern crate rutie;

use rutie::{Boolean, Class, Object, RString, VM};

methods!(
   RString,
   itself,

   fn is_blank() -> Boolean {
       Boolean::new(itself.to_str().chars().all(|c| c.is_whitespace()))
   }
);

fn main() {
    Class::from_existing("String").define(|itself| {
        itself.def_private("blank?", is_blank);
    });
}

Ruby:

class String
  private def blank?
    # simplified
    self.chars.all? { |c| c == ' ' }
  end
end

Receiving arguments

Raise Fixnum to the power of exp.

#[macro_use] extern crate rutie;

use std::error::Error;

use rutie::{Class, Fixnum, Object, VM};

methods!(
    Fixnum,
    itself,

    fn pow(exp: Fixnum) -> Fixnum {
        // `exp` is not a valid `Fixnum`, raise an exception
        if let Err(ref error) = exp {
            VM::raise(error.to_exception(), error.description());
        }

        // We can safely unwrap here, because an exception was raised if `exp` is `Err`
        let exp = exp.unwrap().to_i64() as u32;

        Fixnum::new(itself.to_i64().pow(exp))
    }

    fn pow_with_default_argument(exp: Fixnum) -> Fixnum {
        let default_exp = 0;
        let exp = exp.map(|exp| exp.to_i64()).unwrap_or(default_exp);

        let result = itself.to_i64().pow(exp as u32);

        Fixnum::new(result)
    }
);

fn main() {
    Class::from_existing("Fixnum").define(|itself| {
        itself.def_private("pow", pow);
        itself.def_private("pow_with_default_argument", pow_with_default_argument);
    });
}

Ruby:

class Fixnum
  private
  def pow(exp)
    raise ArgumentError unless exp.is_a?(Fixnum)

    self ** exp
  end

  def pow_with_default_argument(exp)
    default_exp = 0
    exp = default_exp unless exp.is_a?(Fixnum)

    self ** exp
  end
end

Defines a class method for given class or singleton method for object.

Use methods! macro to define a callback.

You can also use def_self() alias for this function combined with Class::define() a for nicer DSL.

Examples

Defining a class method

#[macro_use] extern crate rutie;

use std::error::Error;

use rutie::{Class, Object, RString, Symbol, VM};

methods!(
    Symbol,
    itself,

    fn from_string(string: RString) -> Symbol {
        // `string` is not a valid `String`, raise an exception
        if let Err(ref error) = string {
            VM::raise(error.to_exception(), error.description());
        }

        Symbol::new(&string.unwrap().to_string())
    }
);

fn main() {
    Class::from_existing("Symbol").define(|itself| {
        itself.def_self("from_string", from_string);
    });
}

Ruby:

class Symbol
  def self.from_string(string)
    raise ArgumentError unless string.is_a?(String)

    # simplified
    string.to_sym
  end
end

Defining a singleton method for an object

#[macro_use] extern crate rutie;

use rutie::{AnyObject, Class, Fixnum, Object, RString, VM};

methods!(
    RString,
    itself,

    fn greeting() -> RString {
        RString::new("Greeting!")
    }
);

fn main() {
    let mut string = RString::new("Some string");

    // The same can be done by modifying `string.singleton_class()`
    // or using `string.define_singleton_method("greeting", greeting)`
    string.define(|itself| {
        itself.define_singleton_method("greeting", greeting);
    });

    assert!(string.respond_to("greeting"));
}

Ruby:


string = "Some string"

class << string
  def greeting
    'Greeting!'
  end
end

string.respond_to?("greeting")

An alias for define_method (similar to Ruby syntax def some_method).

An alias for define_private_method (similar to Ruby syntax private def some_method).

An alias for define_singleton_method (similar to Ruby def self.some_method).

Calls a given method on an object similarly to Ruby Object#send method

Examples

use rutie::{Array, Fixnum, Object, RString, VM};

let array = Array::new().push(Fixnum::new(1));
let array_string =
    array
        .send("to_s", None)
        .try_convert_to::<RString>()
        .unwrap();

assert_eq!(array_string.to_str(), "[1]");

Alias for Ruby's ==

Examples

use rutie::{Fixnum, Object, VM};

let a = Fixnum::new(4);
let b = Fixnum::new(7);
let c = Fixnum::new(4);

assert!(!a.equals(&b));
assert!(a.equals(&c));

Ruby:

a = 4
b = 7
c = 4

a == b # false
a == c # true

Alias for Ruby's ===

Examples

use rutie::{Fixnum, Object, Class, VM};

let a = Fixnum::new(4);
let b = Class::from_existing("Integer");

assert!(!a.case_equals(&b));
assert!(b.case_equals(&a));

Ruby:

a = 4

a === Integer # false
Integer === a # true

Alias for Ruby's eql?

Examples

use rutie::{Fixnum, Object, VM};

let a = Fixnum::new(4);
let b = Fixnum::new(7);
let c = Fixnum::new(4);

assert!(!a.is_eql(&b));
assert!(a.is_eql(&c));

Ruby:

a = 4
b = 7
c = 4


a.eql?(b)
a.eql?(c)

Alias for Ruby's equal?

Examples

use rutie::{Fixnum, Object, VM};

let a = Fixnum::new(4);
let b = Fixnum::new(7);
let c = Fixnum::new(4);

assert!(!a.is_equal(&b));
assert!(a.is_equal(&c));

Ruby:

a = 4
b = 7
c = 4


a.equal?(b)
a.eqlua?(c)

Checks whether the object responds to given method

Examples

use rutie::{Array, Object, VM};

let array = Array::new();

assert!(array.respond_to("push"));
assert!(!array.respond_to("something_else"));

protect_send returns Result<AnyObject, AnyObject>

Protects against crash with send when exception object raised which will be returned in the Err result.

Examples

use rutie::{RString, Fixnum, Object, Class, VM};
 
let kernel = Class::from_existing("Kernel");
 
let result = kernel.protect_send("nil?".to_string(), None);
 
if let Ok(r) = result {
    assert!(!r.value().is_true());
} else {
    unreachable!()
}
 
let kernel = Class::from_existing("Kernel");
 
let result = kernel.protect_send(
    "raise".to_string(),
    Some(&vec![RString::new("flowers").to_any_object()])
);
 
if let Err(error) = result {
    assert_eq!(
        Class::from(error.value()).
            send("message", None).
            try_convert_to::<RString>().
            ok().
            unwrap().
            to_str(),
        "flowers"
    );
} else {
    unreachable!()
}

protect_public_send returns Result<AnyObject, AnyObject>

Protects against crash with public_send when exception object raised which will be returned in the Err result.

Examples

use rutie::{RString, Fixnum, Object, Class, VM};
 
let kernel = Class::from_existing("Kernel");
 
let result = kernel.protect_public_send("nil?".to_string(), None);
 
if let Ok(r) = result {
    assert!(!r.value().is_true());
} else {
    unreachable!()
}
 
let kernel = Class::from_existing("Kernel");
 
let result = kernel.protect_public_send(
    "raise".to_string(),
    Some(&vec![RString::new("flowers").to_any_object()])
);
 
if let Err(error) = result {
    assert_eq!(
        Class::from(error.value()).
            send("message", None).
            try_convert_to::<RString>().
            ok().
            unwrap().
            to_str(),
        "flowers"
    );
} else {
    unreachable!()
}

Checks whether the object is nil

Examples

use rutie::{Hash, NilClass, Object, VM};

assert!(NilClass::new().is_nil());
assert!(!Hash::new().is_nil());

Ruby:

nil.nil? == true
{}.nil? == false

Converts struct to AnyObject

See docs for AnyObject class for more details.

Examples

use rutie::{Array, Fixnum, Object, VM};

let array = Array::new().push(Fixnum::new(1));
let args = [Fixnum::new(1).to_any_object()];
let index =
    array
        .send("find_index", Some(&args))
        .try_convert_to::<Fixnum>();

assert_eq!(index, Ok(Fixnum::new(0)));

Gets an instance variable of object

Examples

#[macro_use]
extern crate rutie;

use rutie::{AnyObject, Class, Fixnum, Object, VM};

class!(Counter);

methods!(
    Counter,
    itself,

    fn counter_initialize() -> AnyObject {
        itself.instance_variable_set("@state", Fixnum::new(0))
    }

    fn counter_increment() -> AnyObject {
        // Using unsafe conversion, because we are sure that `@state` is always a `Fixnum`
        // and we don't provide an interface to set the value externally
        let state = unsafe {
            itself.instance_variable_get("@state").to::<Fixnum>().to_i64()
        };

        itself.instance_variable_set("@state", Fixnum::new(state + 1))
    }

    fn counter_state() -> Fixnum {
        unsafe { itself.instance_variable_get("@state").to::<Fixnum>() }
    }
);

fn main() {
    let counter = Class::new("Counter", None).define(|itself| {
        itself.def("initialize", counter_initialize);
        itself.def("increment!", counter_increment);
        itself.def("state", counter_state);
    }).new_instance(None);

    counter.send("increment!", None);

    let new_state = counter.send("state", None).try_convert_to::<Fixnum>();

    assert_eq!(new_state, Ok(Fixnum::new(1)));
}

Ruby:

class Counter
  def initialize
    @state = 0
  end

  def increment!
    @state += 1
  end

  def state
    @state
  end
end

counter = Counter.new
counter.increment!

new_state = counter.state

new_state == 1

Sets an instance variable for object

Examples

#[macro_use]
extern crate rutie;

use rutie::{AnyObject, Class, Fixnum, Object, VM};

class!(Counter);

methods!(
    Counter,
    itself,

    fn counter_initialize() -> AnyObject {
        itself.instance_variable_set("@state", Fixnum::new(0))
    }

    fn counter_increment() -> AnyObject {
        // Using unsafe conversion, because we are sure that `@state` is always a `Fixnum`
        // and we don't provide an interface to set the value externally
        let state = unsafe {
            itself.instance_variable_get("@state").to::<Fixnum>().to_i64()
        };

        itself.instance_variable_set("@state", Fixnum::new(state + 1))
    }

    fn counter_state() -> Fixnum {
        unsafe { itself.instance_variable_get("@state").to::<Fixnum>() }
    }
);

fn main() {
    let counter = Class::new("Counter", None).define(|itself| {
        itself.def("initialize", counter_initialize);
        itself.def("increment!", counter_increment);
        itself.def("state", counter_state);
    }).new_instance(None);

    counter.send("increment!", None);

    let new_state = counter.send("state", None).try_convert_to::<Fixnum>();

    assert_eq!(new_state, Ok(Fixnum::new(1)));
}

Ruby:

class Counter
  def initialize
    @state = 0
  end

  def increment!
    @state += 1
  end

  def state
    @state
  end
end

counter = Counter.new
counter.increment!

new_state = counter.state

new_state == 1

Returns the freeze status of the object.

Examples

use rutie::{Object, RString, VM};

let frozen_string = RString::new("String").freeze();

assert!(frozen_string.is_frozen());

Ruby:

frozen_string = 'String'.freeze

frozen_string.frozen? == true

Prevents further modifications to the object.

Examples

use rutie::{Object, RString, VM};

let frozen_string = RString::new("String").freeze();

assert!(frozen_string.is_frozen());

Ruby:

frozen_string = 'String'.freeze

frozen_string.frozen? == true

Unsafely casts current object to the specified Ruby type

This operation in unsafe, because it does not perform any validations on the object, but it is faster than try_convert_to().

Use it when:

  • you own the Ruby code which passes the object to Rust;
  • you are sure that the object always has correct type;
  • Ruby code has a good test coverage.

This function is used by unsafe_methods! macro for argument casting.

Examples

use rutie::{AnyObject, Fixnum, Object, VM};

let fixnum_as_any_object = Fixnum::new(1).to_any_object();

let fixnum = unsafe { fixnum_as_any_object.to::<Fixnum>() };

assert_eq!(fixnum.to_i64(), 1);

Safely casts current object to the specified Ruby type

This function is used by methods! macro for argument casting.

See documentation for VerifiedObject trait to enable safe conversions for custom classes.

Examples

Basic conversions

use rutie::result::Error;
use rutie::{Fixnum, Object, RString, VM};

let fixnum_as_any_object = Fixnum::new(1).to_any_object();
let converted_fixnum = fixnum_as_any_object.try_convert_to::<Fixnum>();

assert_eq!(converted_fixnum, Ok(Fixnum::new(1)));

let string = RString::new("string");
let string_as_fixnum = string.try_convert_to::<Fixnum>();
let expected_error = Error::TypeError("Error converting to Fixnum".to_string());

assert_eq!(string_as_fixnum, Err(expected_error));

Method arguments

To launch a server in Rust, you plan to write a simple Server class

class Server
  def start(address)
    # ...
  end
end

The address must be Hash with the following structure:

{
  host: 'localhost',
  port: 8080,
}

You want to extract port from it. Default port is 8080 in case when:

  • address is not a Hash
  • address[:port] is not present
  • address[:port] is not a Fixnum
#[macro_use]
extern crate rutie;

use rutie::{Class, Fixnum, Hash, NilClass, Object, Symbol, VM};

class!(Server);

methods!(
    Server,
    itself,

    fn start(address: Hash) -> NilClass {
        let default_port = 8080;

        let port = address
            .map(|hash| hash.at(&Symbol::new("port")))
            .and_then(|port| port.try_convert_to::<Fixnum>())
            .map(|port| port.to_i64())
            .unwrap_or(default_port);

        // Start server...

        NilClass::new()
    }
);

fn main() {
    Class::new("Server", None).define(|itself| {
        itself.def("start", start);
    });
}

Ruby:

class Server
  def start(address)
    default_port = 8080

    port =
      if address.is_a?(Hash) && address[:port].is_a?(Fixnum)
        address[:port]
      else
        default_port
      end

    # Start server...
  end
end

Determines the value type of the object

Example

use rutie::{AnyObject, Fixnum, Object, VM};
use rutie::types::ValueType;

let any_object = Fixnum::new(1).to_any_object();

assert_eq!(any_object.ty(), ValueType::Fixnum);

Implementors