// // Created by ZekeXiao on 2025/10/18. // #include #include #include class Point { public: Point(int x, int y) : x_(x), y_(y) {} void set_values(int x, int y) { x_ = x; y_ = y; } int get_x() const { return x_; } void set_x(int x) { x_ = x; } int get_y() const { return y_; } void set_y(int y) { y_ = y; } void add(const Point &other) { this->x_ += other.x_; this->y_ += other.y_; } static int none() { return 1; } private: int x_; int y_; }; static mrb_value point_native_init(mrb_state* mrb, mrb_value self) { auto count = mrb_get_argc(mrb); Point* p = nullptr; if (count == 0) { p = new Point(0, 0); } else if (count == 1) { auto argv = mrb_get_argv(mrb); p = new Point(mrb_as_float(mrb, argv[0]), 0); } else if (count == 2) { auto argv = mrb_get_argv(mrb); p = new Point(mrb_as_float(mrb, argv[0]), mrb_as_float(mrb, argv[1])); } else { mrb_raise(mrb, E_ARGUMENT_ERROR, "Point wrong number of arguments"); } DATA_PTR(self) = p; DATA_TYPE(self) = &mrubypp::bind_class::data_type; return self; } static mrb_value point_native_div(mrb_state *mrb, mrb_value self) { auto point = mrubypp::bind_class::get_this(mrb, self); auto divisor = mrubypp::converter::from_mrb(mrb, mrb_get_arg1(mrb)); point->set_x(point->get_x() / divisor); point->set_y(point->get_y() / divisor); return self; } template <> struct mrubypp::converter { static mrb_value to_mrb(mrb_state *mrb, const Point &var) { mrb_value obj = mrb_obj_value( mrb_data_object_alloc(mrb, mrb->object_class, new Point(var), &mrubypp::bind_class::data_type)); return obj; } static Point from_mrb(mrb_state *mrb, mrb_value value) { if (mrb_type(value) == MRB_TT_DATA) { Point *point = static_cast(DATA_PTR(value)); return *point; } return Point(0, 0); } }; class Point3D { public: Point3D(int x, int y, int z) : x_(x), y_(y), z_(z) {} void set_values(int x, int y, int z) { x_ = x; y_ = y; z_ = z; } int get_x() const { return x_; } void set_x(int x) { x_ = x; } int get_y() const { return y_; } void set_y(int y) { y_ = y; } int get_z() const { return z_; } void set_z(int y) { z_ = y; } void add(const Point3D& other) { this->x_ += other.x_; this->y_ += other.y_; this->z_ += other.z_; } static int none() { return 1; } private: int x_; int y_; int z_; }; template <> struct mrubypp::converter { static mrb_value to_mrb(mrb_state* mrb, const Point3D& var) { mrb_value obj = mrb_obj_value( mrb_data_object_alloc(mrb, mrb->object_class, new Point3D(var), &mrubypp::bind_class::data_type)); return obj; } static Point3D from_mrb(mrb_state* mrb, mrb_value value) { if (mrb_type(value) == MRB_TT_DATA) { Point3D* point = static_cast(DATA_PTR(value)); return *point; } return Point3D(0, 0,0 ); } }; TEST_CASE("bind_class", "[class]") { mrubypp::engine engine; mrubypp::bind_class(engine.get_mrb(), "Point") .def_constructor(point_native_init, MRB_ARGS_OPT(2)) .def_method("add", &Point::add) .def_class_method("none", &Point::none) .def_property("x", &Point::get_x, &Point::set_x) .def_property("y", &Point::get_y, &Point::set_y) .def_native("div", point_native_div, MRB_ARGS_REQ(1)); mrubypp::bind_class(engine.get_mrb(), "Point3D") .def_constructor() .def_property("x", &Point3D::get_x, &Point3D::set_x) .def_property("y", &Point3D::get_y, &Point3D::set_y) .def_property("z", &Point3D::get_z, &Point3D::set_z); engine.load(R"( def test_method() p = Point.new(3, 4) p.add(p) return p end def test_property() p = Point.new(3, 4) p.x = 10 p.y = p.y + p.y return p end def test_native() p = Point.new(4, 8) p.div(2) return p end def test_class_method() return Point::none() end def test_class_init() return Point.new(10) end def test_point3d_init() p = Point.new(10, 11) p3d = Point3D.new(p.x, p.y, 5) return p3d end )"); SECTION("test_method") { auto point_result = engine.call("test_method"); REQUIRE(point_result.get_x() == 6); REQUIRE(point_result.get_y() == 8); } SECTION("test_property") { auto point_result = engine.call("test_property"); REQUIRE(point_result.get_x() == 10); REQUIRE(point_result.get_y() == 8); } SECTION("test_native") { auto point_result = engine.call("test_native"); REQUIRE(point_result.get_x() == 2); REQUIRE(point_result.get_y() == 4); } SECTION("test_class_method") { auto result = engine.call("test_class_method"); REQUIRE(result == 1); } SECTION("test_class_init") { auto result = engine.call("test_class_init"); REQUIRE(result.get_x() == 10); REQUIRE(result.get_y() == 0); } SECTION("test_point3d_init") { auto result = engine.call("test_point3d_init"); REQUIRE(result.get_x() == 10); REQUIRE(result.get_y() == 11); REQUIRE(result.get_z() == 5); } }