Ruby Macros
Procedural macros for Rusty Ruby, simplifying the process of defining Ruby classes and methods in Rust.
🎯 Project Overview
Ruby-Macros is a crate that provides procedural macros for Rusty Ruby, including derive(RubyClass) and related macros to simplify the process of defining Ruby classes and methods in Rust.
🌟 Key Features
derive(RubyClass): Automatically generates Ruby class definitions from Rust structs
#[ruby_method]: Attribute macro for defining Ruby methods
- Seamless Integration: Works smoothly with the Rusty Ruby runtime
- Type Safety: Maintains Rust's type safety while providing Ruby interop
- Minimal Boilerplate: Reduces repetitive code for Ruby class definitions
🚀 Quick Start
Define a Ruby Class
use ruby_macros::RubyClass;
#[derive(RubyClass)]
pub struct MyClass {
value: i32,
}
impl MyClass {
#[ruby_method]
pub fn new(value: i32) -> Self {
Self { value }
}
#[ruby_method]
pub fn get_value(&self) -> i32 {
self.value
}
#[ruby_method]
pub fn set_value(&mut self, value: i32) {
self.value = value;
}
}
Use the Ruby Class
use ruby::Ruby;
use crate::MyClass;
fn main() -> ruby::Result<()> {
let mut ruby = Ruby::new()?;
ruby.execute_script("obj = MyClass.new(42)")?;
ruby.execute_script("puts obj.get_value")?; ruby.execute_script("obj.set_value(100)")?;
ruby.execute_script("puts obj.get_value")?;
Ok(())
}
🏗️ Architecture
Macro Expansion
The derive(RubyClass) macro expands to:
- A Ruby class definition
- Methods for converting between Rust and Ruby types
- Registration code for the Ruby runtime
- Implementation of required traits
The #[ruby_method] macro expands to:
- A Ruby method definition
- Type conversion code for arguments and return values
- Error handling for Ruby method calls
🛠️ Development
cargo build
cargo test
cargo build --release
📚 Advanced Usage
Class Inheritance
use ruby_macros::RubyClass;
#[derive(RubyClass)]
pub struct BaseClass {
base_value: i32,
}
impl BaseClass {
#[ruby_method]
pub fn new(base_value: i32) -> Self {
Self { base_value }
}
#[ruby_method]
pub fn base_method(&self) -> i32 {
self.base_value
}
}
#[derive(RubyClass)]
#[ruby_class(superclass = "BaseClass")]
pub struct SubClass {
#[ruby_class(skip)] rust_only_field: String,
sub_value: i32,
}
impl SubClass {
#[ruby_method]
pub fn new(base_value: i32, sub_value: i32) -> Self {
Self {
base_value,
rust_only_field: "rust-only".to_string(),
sub_value,
}
}
#[ruby_method]
pub fn sub_method(&self) -> i32 {
self.sub_value
}
}
Method Overloading
use ruby_macros::RubyClass;
#[derive(RubyClass)]
pub struct Calculator {
value: i32,
}
impl Calculator {
#[ruby_method]
pub fn new() -> Self {
Self { value: 0 }
}
#[ruby_method(name = "add")]
pub fn add_i32(&mut self, value: i32) {
self.value += value;
}
#[ruby_method(name = "add")]
pub fn add_f64(&mut self, value: f64) {
self.value += value as i32;
}
#[ruby_method]
pub fn get_value(&self) -> i32 {
self.value
}
}
🤝 Contributing
Contributions are welcome! Feel free to open issues or submit pull requests to help improve Ruby-Macros.