File: inheritance.rs

package info (click to toggle)
rust-magnus 0.8.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,756 kB
  • sloc: ruby: 150; sh: 17; makefile: 2
file content (68 lines) | stat: -rw-r--r-- 2,073 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#![cfg(feature = "embed")]

use magnus::{function, method, prelude::*};

/// Building on top of `wrap`, we can rely on Rust's enum to dispatch based on enum variants.
/// Magnus will transform the types between Ruby and Rust.
#[magnus::wrap(class = "Shape")]
enum Shape {
    #[magnus(class = "Circle")]
    Circle { radius: f64 },
    #[magnus(class = "Rectangle")]
    Rectangle { x: f64, y: f64 },
}

impl Shape {
    fn new_circle(radius: f64) -> Self {
        Self::Circle { radius }
    }

    fn new_rectangle(x: f64, y: f64) -> Self {
        Self::Rectangle { x, y }
    }

    fn area(&self) -> f64 {
        match self {
            Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
            Shape::Rectangle { x, y } => x * y,
        }
    }
}

fn print_area(s: &Shape) {
    println!("{}", s.area());
}

fn main() -> Result<(), String> {
    // Normal Rust code
    let a = Shape::Circle { radius: 10.0 };
    let b = Shape::Rectangle { x: 10.0, y: 2.0 };
    print_area(&a);
    print_area(&b);

    // magnus binding running in Ruby
    magnus::Ruby::init(|ruby| {
        let shape_class = ruby.define_class("Shape", ruby.class_object())?;
        shape_class.undef_default_alloc_func();

        // inherit from Shape
        let circle_class = ruby.define_class("Circle", shape_class)?;
        circle_class.define_singleton_method("new", function!(Shape::new_circle, 1))?;
        circle_class.define_method("area", method!(Shape::area, 0))?;

        let rectangle_class = ruby.define_class("Rectangle", shape_class)?;
        rectangle_class.define_singleton_method("new", function!(Shape::new_rectangle, 2))?;
        rectangle_class.define_method("area", method!(Shape::area, 0))?;

        let d: f64 = ruby.eval(
            "a = Circle.new(10.0)
             b = Rectangle.new(10.0, 2.0)
             difference = a.area - b.area
             puts \"The difference of the area between the circle and the rectangle is #{difference}.\"
             difference",
        )?;

        println!("{}", d);
        Ok(())
    })
}