Quick Start: Your First Extension
Time: 15 minutes | Difficulty: Beginner | Prerequisites: Installation complete
Let's build a working Ruby gem with a Rust-powered native extension. We'll create a FastStrings gem that showcases Rust's performance and safety for string manipulation.
What We're Building
A FastStrings gem that provides a fast, Unicode-aware string reversal method.
require "fast_strings"
FastStrings.reverse("Hello, world! 🦀")
# => "🦀 !dlrow ,olleH"
Step 1: Create Your Gem
We'll use Bundler to generate the gem skeleton with Rust support.
bundle gem --ext=rust fast_strings
cd fast_strings
This creates a standard gem structure with an ext/fast_strings directory for our Rust code.
Step 2: Write Your Rust Code
Replace the placeholder code in ext/fast_strings/src/lib.rs with our string reversal implementation.
We will use the magnus library for high-level, safe bindings to Ruby, and unicode-segmentation to correctly handle Unicode grapheme clusters.
First, add the dependencies to ext/fast_strings/Cargo.toml:
# ext/fast_strings/Cargo.toml
[package]
name = "fast_strings"
version = "0.1.0"
edition = "2021"
[dependencies]
magnus = "0.7"
unicode-segmentation = "1.10"
[lib]
name = "fast_strings"
crate-type = ["cdylib"]
Now, the Rust code:
// ext/fast_strings/src/lib.rs
use magnus::{function, prelude::*, Error, Ruby};
use unicode_segmentation::UnicodeSegmentation;
/// Reverses a string, correctly handling Unicode grapheme clusters.
fn reverse_string(input: String) -> String {
input.graphemes(true).rev().collect()
}
#[magnus::init]
fn init(ruby: &Ruby) -> Result<(), Error> {
let module = ruby.define_module("FastStrings")?;
module.define_singleton_method("reverse", function!(reverse_string, 1))?;
Ok(())
}
Why this approach?
- Safety:
magnusprovides a safe API, avoidingunsafeblocks and ensuring memory safety. - Correctness: The
unicode-segmentationcrate ensures that we correctly reverse strings with complex Unicode characters, like emoji. - Maintainability: The code is clean, idiomatic Rust, making it easier to understand and maintain.
Step 3: Build and Test
-
Install dependencies and compile:
bundle install
bundle exec rake compile -
Write a test: Create a test file
test/test_fast_strings.rbto verify the implementation:# test/test_fast_strings.rb
require "test_helper"
class TestFastStrings < Minitest::Test
def test_reverse_simple
assert_equal "dlrow olleh", FastStrings.reverse("hello world")
end
def test_reverse_unicode
assert_equal "🦀!dlroW ,olleH", FastStrings.reverse("Hello, World!🦀")
end
end -
Run the tests:
bundle exec rake test
Step 4: Try It in the Console
bundle exec bin/console
require "fast_strings"
FastStrings.reverse("Hello, World! 🦀")
# => "🦀 !dlroW ,olleH"
What You've Learned
- You've created a Ruby gem with a Rust native extension.
- You've written safe, performant, and correct Rust code using
magnus. - You've learned how to handle Unicode strings properly.
- You've tested your gem to ensure it works as expected.
This quick-start provides a solid foundation for building your own high-performance, reliable Ruby gems with Rust.