### Define Ruby Class with Subclassing Support in Rust Source: https://github.com/matsadler/magnus/blob/main/README.md Implement `Default`, an allocator, and an initializer for Rust types to support subclassing in Ruby. This example defines a `Point` struct and a `MutPoint` wrapper. ```rust #[derive(Default)] struct Point { x: isize, y: isize, } #[derive(Default)] #[wrap(class = "Point")] struct MutPoint(RefCell); impl MutPoint { fn initialize(&self, x: isize, y: isize) { let mut this = self.0.borrow_mut(); this.x = x; this.y = y; } } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { let class = ruby.define_class("Point", ruby.class_object()).unwrap(); class.define_alloc_func::(); class.define_method("initialize", method!(MutPoint::initialize, 2))?; Ok(()) } ``` -------------------------------- ### Rust Error Handling for Ruby Extensions Source: https://github.com/matsadler/magnus/blob/main/README.md Propagate errors from Rust to Ruby using `magnus::Error`. This example shows how to return a `RangeError` for out-of-range calculations. ```rust #[magnus::wrap(class = "Point")] struct MutPoint(RefCell); impl MutPoint { fn add_x(ruby: &Ruby, rb_self: &Self, val: isize) -> Result { if let Some(sum) = rb_self.0.borrow().x.checked_add(val) { rb_self.0.borrow_mut().x = sum; Ok(sum) } else { return Err(Error::new(ruby.exception_range_error(), "result out of range")); } } } ``` -------------------------------- ### Raise Ruby Exceptions from Rust Source: https://context7.com/matsadler/magnus/llms.txt Return `magnus::Error` from Rust functions to raise specific Ruby exceptions. This example shows how to raise `ZeroDivisionError`, `ArgumentError`, and `RangeError`. ```rust use magnus::{function, prelude::*, Error, Exception, Ruby}; fn divide(ruby: &Ruby, a: i64, b: i64) -> Result { if b == 0 { return Err(Error::new( ruby.exception_zero_div_error(), "divided by 0" )); } Ok(a / b) } fn validate_age(ruby: &Ruby, age: i64) -> Result<(), Error> { if age < 0 { return Err(Error::new( ruby.exception_arg_error(), format!("age must be non-negative, got {}", age) )); } if age > 150 { return Err(Error::new( ruby.exception_range_error(), "age out of valid range" )); } Ok(()) } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { ruby.define_global_function("divide", function!(divide, 2)); ruby.define_global_function("validate_age", function!(validate_age, 1)); // Define custom exception class let my_error = ruby.define_error("MyCustomError", ruby.exception_standard_error())?; Ok(()) } // Usage from Ruby: // divide(10, 2) # => 5 // divide(10, 0) # raises ZeroDivisionError: divided by 0 // validate_age(-1) # raises ArgumentError ``` -------------------------------- ### Create and Manipulate Ruby Hashes in Rust Source: https://context7.com/matsadler/magnus/llms.txt Work with Ruby hashes using the `RHash` type. Supports creation from iterators of tuples, setting and getting values, looking up with defaults, deleting entries, and iterating over key-value pairs. ```rust use magnus::{prelude::*, Error, RHash, Ruby, r_hash::ForEach}; fn example(ruby: &Ruby) -> Result<(), Error> { // Create empty hash let hash = ruby.hash_new(); // Create from iterator of tuples let hash = ruby.hash_from_iter([ ("name", "Alice"), ("city", "Boston"), ]); // Set and get values hash.aset("key", "value")?; let val: String = hash.aref("key")?; // Lookup with default let val: Option = hash.lookup("missing"); // Delete entry let removed: Option = hash.delete("key")?; // Iterate over hash hash.foreach(|key: String, value: String| { println!("{}: {}", key, value); Ok(ForEach::Continue) })?; // Check size let len = hash.len(); let is_empty = hash.is_empty(); Ok(()) } ``` -------------------------------- ### Create and Manipulate Ruby Strings in Rust Source: https://context7.com/matsadler/magnus/llms.txt Handle Ruby strings using the `RString` type. Supports creating UTF-8 strings, strings with capacity, and performing operations like getting byte/character length, concatenation, appending, conversion to Rust strings, and splitting. ```rust use magnus::{prelude::*, Error, RString, Ruby}; fn example(ruby: &Ruby) -> Result<(), Error> { // Create UTF-8 string from Rust &str let s = ruby.str_new("Hello, world!"); // Create string with capacity let buf = ruby.str_buf_new(1024); // String operations let len = s.len(); // Byte length let char_len = s.length()?; // Concatenate let combined = s.plus(ruby.str_new(" More"))?; // Append bytes buf.cat(b"Hello"); buf.buf_append(ruby.str_new(" World"))?; // Convert to Rust String (safe, validates UTF-8) let rust_string: String = s.to_string()?; // Get string as bytes unsafe { let bytes: &[u8] = s.as_slice(); } // Split string let parts: Vec = s.split(" ")? .into_iter() .map(|v| RString::try_convert(v).unwrap()) .collect(); Ok(()) } ``` -------------------------------- ### Wrap Rust Struct as Ruby Object with Methods Source: https://github.com/matsadler/magnus/blob/main/README.md Expose a Rust struct as a Ruby object using the `#[magnus::wrap]` macro. This allows creating instances of the Rust struct in Ruby and calling its methods. The example defines a `Point` struct with `new`, `x`, `y`, and `distance` methods. ```rust use magnus::{function, method, prelude::*, Error, Ruby}; #[magnus::wrap(class = "Point")] struct Point { x: isize, y: isize, } impl Point { fn new(x: isize, y: isize) -> Self { Self { x, y } } fn x(&self) -> isize { self.x } fn y(&self) -> isize { self.y } fn distance(&self, other: &Point) -> f64 { (((other.x - self.x).pow(2) + (other.y - self.y).pow(2)) as f64).sqrt() } } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { let class = ruby.define_class("Point", ruby.class_object())?; class.define_singleton_method("new", function!(Point::new, 2))?; class.define_method("x", method!(Point::x, 0))?; class.define_method("y", method!(Point::y, 0))?; class.define_method("distance", method!(Point::distance, 1))?; Ok(()) } ``` -------------------------------- ### Define Ruby Method in Rust for String Class Source: https://github.com/matsadler/magnus/blob/main/README.md Define a Rust function as a method on an existing Ruby class, such as String. The `self` argument is implicitly handled by Ruby. This example adds a `blank?` method to the String class. ```rust fn is_blank(rb_self: String) -> bool { !rb_self.contains(|c: char| !c.is_whitespace()) } #[magnus::init] fn init(ruby: &magnus::Ruby) -> Result<(), Error> { // returns the existing class if already defined let class = ruby.define_class("String", ruby.class_object())?; // 0 as self doesn't count against the number of arguments class.define_method("blank?", magnus::method!(is_blank, 0))?; Ok(()) } ``` -------------------------------- ### Handle Mutability in Wrapped Rust Structs with RefCell Source: https://github.com/matsadler/magnus/blob/main/README.md To allow mutable fields in Rust structs wrapped by Magnus, use the `RefCell` newtype pattern. This is necessary because Ruby's garbage collector manages memory, and Magnus cannot bind mutable references directly. This example shows how to implement a `set_x` method for a mutable point. ```rust use std::cell::RefCell; struct Point { x: isize, y: isize, } #[magnus::wrap(class = "Point")] struct MutPoint(RefCell); impl MutPoint { fn set_x(&self, i: isize) { self.0.borrow_mut().x = i; } } ``` -------------------------------- ### Rust Extension Gem Configuration (extconf.rb) Source: https://context7.com/matsadler/magnus/llms.txt Set up the `extconf.rb` file for a Rust-based Ruby extension gem using `rb_sys/mkmf` to create the necessary Makefile. ```ruby # ext/my_gem/extconf.rb require "mkmf" require "rb_sys/mkmf" create_rust_makefile("my_gem/my_gem") ``` -------------------------------- ### Create Rust Makefile for Gem Extension Source: https://github.com/matsadler/magnus/blob/main/README.md Use `rb_sys/mkmf` in `extconf.rb` to generate the necessary Makefile for compiling the Rust extension when the gem is built. ```ruby require "mkmf" require "rb_sys/mkmf" create_rust_makefile("my_example_gem/my_example_gem") ``` -------------------------------- ### Rust Extension Gem Configuration (Cargo.toml) Source: https://context7.com/matsadler/magnus/llms.txt Configure a Rust-based Ruby extension gem by specifying the `cdylib` crate type and including the `magnus` dependency in `Cargo.toml`. ```toml # Cargo.toml [package] name = "my_gem" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] magnus = "0.8" ``` -------------------------------- ### Define Ruby Modules and Module Functions Source: https://context7.com/matsadler/magnus/llms.txt Create Ruby modules using `define_module` and expose functions using `define_module_function`. These functions can be called as class methods or private instance methods when the module is included. ```rust use magnus::{function, prelude::*, Error, RString, Ruby}; fn greet(ruby: &Ruby) -> RString { ruby.str_new("Hello, world!") } fn add(a: i64, b: i64) -> i64 { a + b } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { let module = ruby.define_module("MyMath")?; module.define_module_function("greet", function!(greet, 0))?; module.define_module_function("add", function!(add, 2))?; Ok(()) } // Usage from Ruby: // MyMath.greet # => "Hello, world!" // MyMath.add(2, 3) # => 5 // include MyMath // add(2, 3) # => 5 (private method) ``` -------------------------------- ### Initialize Ruby Extension in Rust Source: https://github.com/matsadler/magnus/blob/main/README.md Mark the `init` function with `#[magnus::init]` to expose it to Ruby. This function defines Ruby classes and binds Rust functions to Ruby methods. ```rust use magnus::{function, Error, Ruby}; fn distance(a: (f64, f64), b: (f64, f64)) -> f64 { ((b.0 - a.0).powi(2) + (b.1 - a.1).powi(2)).sqrt() } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { ruby.define_global_function("distance", function!(distance, 2)); } ``` -------------------------------- ### Initialize and Evaluate Ruby Code from Rust Source: https://github.com/matsadler/magnus/blob/main/README.md Call `magnus::Ruby::init` to initialize the Ruby interpreter and use `magnus::eval` to execute Ruby code within your Rust program. ```rust use magnus::eval; fn main() { magnus::Ruby::init(|ruby| { let val: f64 = eval!(ruby, "a + rand", a = 1)?; println!("{}", val); Ok(()) }).unwrap(); } ``` -------------------------------- ### Enable Static Ruby Linking in Cargo.toml Source: https://github.com/matsadler/magnus/blob/main/README.md To statically link Ruby with your project, add the `rb-sys` crate to your `Cargo.toml` with the `ruby-static` feature enabled. Ensure the `rb-sys` version matches Magnus'. ```toml # * should select the same version used by Magnus ruby-sys = { version = "*", default-features = false, features = ["ruby-static"] } ``` -------------------------------- ### Rust Extension Gem Source (lib.rs) Source: https://context7.com/matsadler/magnus/llms.txt Define Rust functions and use `#[magnus::init]` to expose them to Ruby when building a Ruby extension gem. ```rust // src/lib.rs use magnus::{function, prelude::*, Error, Ruby}; fn hello(name: String) -> String { format!("Hello, {}!", name) } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { ruby.define_global_function("hello", function!(hello, 1)); Ok(()) } ``` -------------------------------- ### Define Global Rust Functions for Ruby Source: https://context7.com/matsadler/magnus/llms.txt Use the `function!` macro to expose Rust functions as global Ruby methods. Ensure the function signature matches the expected argument count. ```rust use magnus::{function, Error, Ruby}; fn greet(subject: String) -> String { format!("Hello, {}!", subject) } fn fib(n: usize) -> usize { match n { 0 => 0, 1 | 2 => 1, _ => fib(n - 1) + fib(n - 2), } } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { ruby.define_global_function("greet", function!(greet, 1)); ruby.define_global_function("fib", function!(fib, 1)); Ok(()) } // Usage from Ruby: // greet("world") # => "Hello, world!" // fib(10) # => 55 ``` -------------------------------- ### Configure Cargo for Static Linking Source: https://github.com/matsadler/magnus/blob/main/README.md Instructs Cargo not to strip code when linking static libruby. This is necessary to prevent 'symbol not found' errors when using the 'embed' feature with static Ruby. ```toml [build] # Without this flag, when linking static libruby, the linker removes symbols # (such as `_rb_ext_ractor_safe`) which it thinks are dead code... but they are # not, and they need to be included for the `embed` feature to work with static # Ruby. rustflags = ["-C", "link-dead-code=on"] ``` -------------------------------- ### Ruby Gemspec for Rust Extension Source: https://github.com/matsadler/magnus/blob/main/README.md Configure the `.gemspec` file to include extension compilation and dependencies like `rb_sys` for building Rust extensions. ```ruby spec.extensions = ["ext/my_example_gem/extconf.rb"] # needed until rubygems supports Rust support is out of beta spec.add_dependency "rb_sys", "~> 0.9.39" # only needed when developing or packaging your gem spec.add_development_dependency "rake-compiler", "~> 1.2.0" ``` -------------------------------- ### Ruby Gem Usage (lib/my_gem.rb) Source: https://context7.com/matsadler/magnus/llms.txt Require the compiled Rust extension in your Ruby gem's main file to make the exposed functions available. ```ruby # lib/my_gem.rb require_relative "my_gem/my_gem" # Now `hello("World")` is available ``` -------------------------------- ### Define Ruby Classes with Rust Structs Source: https://context7.com/matsadler/magnus/llms.txt Wrap Rust structs with `#[magnus::wrap]` to create Ruby classes. Use `method!` for instance methods and `function!` for class methods. ```rust use magnus::{function, method, prelude::*, wrap, Error, Ruby}; #[wrap(class = "Point")] struct Point { x: isize, y: isize, } impl Point { fn new(x: isize, y: isize) -> Self { Self { x, y } } fn x(&self) -> isize { self.x } fn y(&self) -> isize { self.y } fn distance(&self, other: &Point) -> f64 { (((other.x - self.x).pow(2) + (other.y - self.y).pow(2)) as f64).sqrt() } } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { let class = ruby.define_class("Point", ruby.class_object())?; class.define_singleton_method("new", function!(Point::new, 2))?; class.define_method("x", method!(Point::x, 0))?; class.define_method("y", method!(Point::y, 0))?; class.define_method("distance", method!(Point::distance, 1))?; Ok(()) } // Usage from Ruby: // a = Point.new(0, 0) // b = Point.new(3, 4) // a.distance(b) # => 5.0 ``` -------------------------------- ### Load Ruby Extension in Ruby Source: https://github.com/matsadler/magnus/blob/main/README.md Require the compiled extension file in your Ruby code to make the Rust functions and classes available. ```ruby require_relative "my_example_gem/my_example_gem" ``` -------------------------------- ### Embed Ruby in a Rust Application Source: https://context7.com/matsadler/magnus/llms.txt Initialize a Ruby interpreter within a Rust application using `magnus::Ruby::init`. This enables calling Rust functions from Ruby and evaluating Ruby code within the Rust application. ```rust // Cargo.toml: // [dependencies] // magnus = { version = "0.8", features = ["embed"] } use magnus::{Error, Ruby}; fn main() -> Result<(), String> { magnus::Ruby::init(|ruby| { // Define Rust functions callable from Ruby ruby.define_global_function("rust_add", magnus::function!( |a: i64, b: i64| a + b, 2 )); // Evaluate Ruby code let result: i64 = ruby.eval(r#" puts "Hello from Ruby!" rust_add(10, 20) "#)?; println!("Result: {}", result); // Result: 30 Ok(()) }) } ``` -------------------------------- ### Evaluate Ruby Code from Rust Source: https://context7.com/matsadler/magnus/llms.txt Evaluate Ruby code strings directly from Rust using `ruby.eval()` or the `eval!` macro. This allows for dynamic execution of Ruby code and calling Ruby methods from Rust. ```rust use magnus::{eval, Error, Ruby, Value}; fn example(ruby: &Ruby) -> Result<(), Error> { // Simple evaluation let result: i64 = ruby.eval("1 + 2 + 3")?; assert_eq!(result, 6); // Evaluate with local variables using eval! macro let a = 10; let b = 20; let sum: i64 = magnus::eval!("a + b", a, b)?; assert_eq!(sum, 30); // Evaluate Ruby class definition ruby.eval::(r#" class Calculator def self.add(a, b) a + b end end "#)?; // Call the defined method let calc: Value = ruby.eval("Calculator")?; let result: i64 = calc.funcall("add", (5, 3))?; assert_eq!(result, 8); Ok(()) } ``` -------------------------------- ### Call Ruby Methods from Rust Source: https://context7.com/matsadler/magnus/llms.txt Use `funcall` to invoke Ruby methods on objects. Return values are automatically converted to Rust types. Supports methods with no arguments, one argument, multiple arguments, and blocks. ```rust use magnus::{prelude::*, Error, Ruby, Value}; fn example(ruby: &Ruby) -> Result<(), Error> { let val: Value = ruby.eval("[1, 2, 3]")?; // Call method with no arguments let len: i64 = val.funcall("length", ())?; assert_eq!(len, 3); // Call method with one argument let includes: bool = val.funcall("include?", (2,))?; assert!(includes); // Call method with multiple arguments let joined: String = val.funcall("join", ("-",))?; assert_eq!(joined, "1-2-3"); // Call with block using block_call let doubled: Vec = val.funcall("map", ()) .and_then(|e: Value| e.funcall("to_a", ()))?; Ok(()) } ``` -------------------------------- ### Create and Manipulate Ruby Arrays in Rust Source: https://context7.com/matsadler/magnus/llms.txt Utilize the `RArray` type and `Ruby` methods to create and manage Ruby arrays. Supports creation from iterators and vectors, and common array operations like push, unshift, shift, pop, and element access. ```rust use magnus::{prelude::*, Error, RArray, Ruby}; fn example(ruby: &Ruby) -> Result<(), Error> { // Create empty array let ary = ruby.ary_new(); // Create array with capacity let ary = ruby.ary_new_capa(10); // Create from Rust iterator let ary = ruby.ary_from_iter(1..=5); // [1, 2, 3, 4, 5] // Create from vector let ary = ruby.ary_from_vec(vec![1, 2, 3]); // Array operations ary.push(4)?; ary.unshift(0)?; let first: i64 = ary.shift()?; let last: i64 = ary.pop()?; let len = ary.len(); let elem: i64 = ary.entry(0)?; ary.store(0, 100)?; // Iterate over array for item in ary.into_iter() { let val: i64 = item.try_convert()?; println!("{}", val); } Ok(()) } ``` -------------------------------- ### Enable Ruby Embedding in Rust Source: https://github.com/matsadler/magnus/blob/main/README.md Add the `embed` feature to the `magnus` dependency in `Cargo.toml` to enable embedding the Ruby interpreter in your Rust application. ```toml [dependencies] magnus = { version = "0.8", features = ["embed"] } ``` -------------------------------- ### Define Global Function in Rust for Ruby Source: https://github.com/matsadler/magnus/blob/main/README.md Define a regular Rust function to be callable as a global Ruby method. Magnus handles automatic type conversion for arguments and return values, raising standard Ruby errors for invalid inputs. ```rust fn fib(n: usize) -> usize { match n { 0 => 0, 1 | 2 => 1, _ => fib(n - 1) + fib(n - 2), } } #[magnus::init] fn init(ruby: &magnus::Ruby) -> Result<(), Error> { ruby.define_global_function("fib", magnus::function!(fib, 1)); Ok(()) } ``` -------------------------------- ### Call Ruby Methods from Rust Source: https://github.com/matsadler/magnus/blob/main/README.md Call arbitrary Ruby methods from Rust using the `funcall` method available on Magnus Ruby wrapper types. This handles argument passing and return type conversion, raising errors if the call fails or the conversion is impossible. ```rust let s: String = value.funcall("test", ())?; let x: bool = value.funcall("example", ("foo",))?; let i: i64 = value.funcall("other", (42, false))?; ``` -------------------------------- ### Mutable Wrapped Types with RefCell Source: https://context7.com/matsadler/magnus/llms.txt Use `RefCell` for interior mutability in wrapped Rust types to allow modifications through Ruby, as direct `&mut` references are not feasible with Ruby's GC. ```rust use std::cell::RefCell; use magnus::{function, method, prelude::*, wrap, Error, Ruby}; struct Point { x: isize, y: isize } #[wrap(class = "Point")] struct MutPoint(RefCell); impl MutPoint { fn new(x: isize, y: isize) -> Self { Self(RefCell::new(Point { x, y })) } fn x(&self) -> isize { self.0.borrow().x } fn set_x(&self, val: isize) { self.0.borrow_mut().x = val; } fn add_x(ruby: &Ruby, rb_self: &Self, val: isize) -> Result { match rb_self.0.borrow().x.checked_add(val) { Some(sum) => { rb_self.0.borrow_mut().x = sum; Ok(sum) } None => Err(Error::new(ruby.exception_range_error(), "result out of range")), } } } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { let class = ruby.define_class("Point", ruby.class_object())?; class.define_singleton_method("new", function!(MutPoint::new, 2))?; class.define_method("x", method!(MutPoint::x, 0))?; class.define_method("x=", method!(MutPoint::set_x, 1))?; class.define_method("add_x", method!(MutPoint::add_x, 1))?; Ok(()) } // Usage from Ruby: // p = Point.new(10, 20) // p.x = 15 // p.add_x(5) # => 20 ``` -------------------------------- ### Ensure UTF-8 String Input in Rust Source: https://github.com/matsadler/magnus/blob/main/README.md Use `RString::from_value` to check if a `magnus::Value` is a String and `is_utf8_compatible_encoding` to validate its encoding. This avoids unnecessary allocations and potential errors. ```rust fn example(ruby: &Ruby, val: magnus::Value) -> Result<(), magnus::Error> { // checks value is a String, does not call #to_str let r_string = RString::from_value(val) .ok_or_else(|| magnus::Error::new(ruby.exception_type_error(), "expected string"))?; // error on encodings that would otherwise need converting to utf-8 if !r_string.is_utf8_compatible_encoding() { return Err(magnus::Error::new( ruby.exception_encoding_error(), "string must be utf-8", )); } // RString::as_str is unsafe as it's possible for Ruby to invalidate the // str as we hold a reference to it. The easiest way to ensure the &str // stays valid is to avoid any other calls to Ruby for the life of the // reference (the rest of the unsafe block). unsafe { let s = r_string.as_str()?; // ... } Ok(()) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.