pub trait Class: Module {
type Instance;
// Required methods
fn new(superclass: Self) -> Result<Self, Error>;
fn new_instance<T>(self, args: T) -> Result<Self::Instance, Error>
where T: ArgList;
fn obj_alloc(self) -> Result<Self::Instance, Error>;
// Provided methods
fn superclass(self) -> Result<RClass, Error> { ... }
unsafe fn name(&self) -> Cow<'_, str> { ... }
fn as_r_class(self) -> RClass { ... }
fn define_alloc_func<T>(self)
where T: Default + TypedData { ... }
fn undef_default_alloc_func(self) { ... }
}
Expand description
Functions available on all types representing a Ruby class.
Required Associated Types§
Required Methods§
sourcefn new(superclass: Self) -> Result<Self, Error>
fn new(superclass: Self) -> Result<Self, Error>
Create a new anonymous class.
§Examples
use magnus::{class, prelude::*, RClass};
let class = RClass::new(class::object()).unwrap();
assert!(class.is_kind_of(class::class()));
use magnus::{exception, prelude::*, ExceptionClass};
assert!(ExceptionClass::new(exception::standard_error()).is_ok());
sourcefn new_instance<T>(self, args: T) -> Result<Self::Instance, Error>where
T: ArgList,
fn new_instance<T>(self, args: T) -> Result<Self::Instance, Error>where
T: ArgList,
Create a new object, an instance of self
, passing the arguments
args
to the initialiser.
§Examples
use magnus::{class, prelude::*};
let s = class::string().new_instance(()).unwrap();
assert!(s.is_kind_of(class::string()));
assert_eq!(s.to_string(), "");
use magnus::{eval, kwargs, prelude::*, RClass};
let cls: RClass = eval!(
r#"
class Foo
def initialize(bar, baz:)
@bar = bar
@baz = baz
end
attr_reader(:bar, :baz)
end
Object.const_get(:Foo)
"#
)
.unwrap();
let instance = cls.new_instance((1, kwargs!("baz" => 2))).unwrap();
assert!(instance.is_kind_of(cls));
let bar: i32 = instance.funcall("bar", ()).unwrap();
assert_eq!(bar, 1);
let baz: i32 = instance.funcall("baz", ()).unwrap();
assert_eq!(baz, 2);
use magnus::{exception, prelude::*};
let s = exception::standard_error()
.new_instance(("bang!",))
.unwrap();
assert!(s.is_kind_of(exception::standard_error()));
use magnus::{eval, ExceptionClass, kwargs, prelude::*};
let exc: ExceptionClass = eval!(
r#"
class MyError < StandardError
def initialize(message:)
super(message)
end
end
Object.const_get(:MyError)
"#
).unwrap();
let s = exc.new_instance((kwargs!("message" => "bang!"),)).unwrap();
assert!(s.is_kind_of(exc));
let message: String = s.funcall("message", ()).unwrap();
assert_eq!(message, "bang!");
sourcefn obj_alloc(self) -> Result<Self::Instance, Error>
fn obj_alloc(self) -> Result<Self::Instance, Error>
Create a new object, an instance of self
, without calling the class’s
initialize
method.
§Examples
use magnus::{class, prelude::*};
let s = class::string().obj_alloc().unwrap();
assert!(s.is_kind_of(class::string()));
use magnus::{exception, prelude::*};
let s = exception::standard_error().obj_alloc().unwrap();
assert!(s.is_kind_of(exception::standard_error()));
Provided Methods§
sourcefn superclass(self) -> Result<RClass, Error>
fn superclass(self) -> Result<RClass, Error>
Returns the parent class of self
.
Returns Err
if self
can not have a parent class.
§Examples
use magnus::{class, prelude::*};
let klass = class::hash().superclass().unwrap();
assert!(klass.equal(class::object()).unwrap());
use magnus::{class, exception, prelude::*};
let klass = exception::exception().superclass().unwrap();
assert!(klass.equal(class::object()).unwrap());
sourceunsafe fn name(&self) -> Cow<'_, str>
unsafe fn name(&self) -> Cow<'_, str>
Return the name of self
.
§Safety
Ruby may modify or free the memory backing the returned str, the caller must ensure this does not happen.
This can be used safely by immediately calling
into_owned
on the return value.
§Examples
use magnus::{class, prelude::*};
let value = class::hash();
// safe as we neve give Ruby a chance to free the string.
let s = unsafe { value.name() }.into_owned();
assert_eq!(s, "Hash");
use magnus::{exception, prelude::*};
let value = exception::standard_error();
// safe as we neve give Ruby a chance to free the string.
let s = unsafe { value.name() }.into_owned();
assert_eq!(s, "StandardError");
sourcefn as_r_class(self) -> RClass
fn as_r_class(self) -> RClass
Return self
as an RClass
.
sourcefn define_alloc_func<T>(self)
fn define_alloc_func<T>(self)
Define an allocator function for self
using T
’s Default
implementation.
In Ruby creating a new object has two steps, first the object is
allocated, and then it is initialised. Allocating the object is handled
by the new
class method, which then also calls initialize
on the
newly allocated object.
This does not map well to Rust, where data is allocated and initialised
in a single step. For this reason most examples in this documentation
show defining the new
class method directly, opting out of the two
step allocate and then initialise process. However, this means the
class can’t be subclassed in Ruby.
Defining an allocator function allows a class be subclassed with the
normal Ruby behaviour of calling the initialize
method.
Be aware when creating an instance of once of a class with an allocator
function from Rust it must be done with Class::new_instance
to call
the allocator and then the initialize
method.
§Panics
Panics if self
and <T as TypedData>::class()
are not the same class.
§Examples
use std::cell::RefCell;
use magnus::{
class, define_class, embed, eval, function, method, prelude::*, wrap, Error, RClass, Value,
};
#[derive(Default)]
struct Point {
x: isize,
y: isize,
}
#[derive(Default)]
#[wrap(class = "Point")]
struct MutPoint(RefCell<Point>);
impl MutPoint {
fn initialize(&self, x: isize, y: isize) {
let mut this = self.0.borrow_mut();
this.x = x;
this.y = y;
}
// bypasses initialize
fn create(x: isize, y: isize) -> MutPoint {
MutPoint(RefCell::new(Point { x, y }))
}
// calls initialize
fn call_new(class: RClass, x: isize, y: isize) -> Result<Value, Error> {
class.new_instance((x, y))
}
fn distance(&self, other: &MutPoint) -> f64 {
let a = self.0.borrow();
let b = other.0.borrow();
(((b.x - a.x).pow(2) + (b.y - a.y).pow(2)) as f64).sqrt()
}
}
let class = define_class("Point", class::object()).unwrap();
class.define_alloc_func::<MutPoint>();
class
.define_singleton_method("create", function!(MutPoint::create, 2))
.unwrap();
class
.define_singleton_method("call_new", method!(MutPoint::call_new, 2))
.unwrap();
class
.define_method("initialize", method!(MutPoint::initialize, 2))
.unwrap();
class
.define_method("distance", method!(MutPoint::distance, 1))
.unwrap();
let d: f64 = eval(
"class OffsetPoint < Point
def initialize(offset, x, y)
super(x + offset, y + offset)
end
end
a = Point.new(1, 1)
b = OffsetPoint.new(2, 3, 3)
a.distance(b).round(2)",
)
.unwrap();
assert_eq!(d, 5.66);
sourcefn undef_default_alloc_func(self)
fn undef_default_alloc_func(self)
Remove the allocator function of a class if it is Ruby’s default allocator function.
Useful for RTypedData, where instances should not be allocated by
the default allocate function. #[derive(TypedData)]
and #[wrap]
take care of undefining the allocator function, you do not need
to use undef_default_alloc_func
if you’re using one of those.
§Examples
use magnus::{class, Class};
let class = magnus::define_class("Point", class::object()).unwrap();
class.undef_default_alloc_func();
let instance = class.new_instance(());
assert_eq!(
"allocator undefined for Point",
instance.err().unwrap().to_string()
);