Quick Start: Your First Extension
Time: 15 minutes | Difficulty: Beginner | Prerequisites: Installation complete
Let's build a working Ruby gem with Rust. We'll create a string manipulation library that showcases Rust's speed and safety.
What We're Building
A FastStrings
gem that provides:
- String reversal
- Safe Unicode handling
require "fast_strings"
FastStrings.reverse("Hello World!")
# => "!dlroW olleH"
Step 1: Create Your Gem
# Create a new gem with Rust support
bundle gem --ext=rust fast_strings
cd fast_strings
What did Bundler create?
fast_strings/
├── Gemfile # Ruby dependencies
├── fast_strings.gemspec # Gem metadata
├── Rakefile # Build tasks
├── ext/fast_strings/ # Rust extension
│ ├── Cargo.toml # Rust dependencies
│ ├── extconf.rb # Build configuration
│ └── src/
│ └── lib.rs # Rust code
└── lib/
└── fast_strings.rb # Ruby wrapper
Step 2: Write Your Rust Code
Replace the default code with our fast string implementation:
// ext/fast_strings/src/lib.rs
use magnus::{function, prelude::*, Error, Ruby};
use unicode_segmentation::UnicodeSegmentation;
/// Reverses a string preserving Unicode grapheme clusters
fn reverse_string(input: String) -> String {
input
.graphemes(true) // true = extended grapheme clusters
.rev()
.collect()
}
#[magnus::init]
fn init(ruby: &Ruby) -> Result<(), Error> {
let module = ruby.define_module("FastStrings")?;
// Define our module methods
module.define_singleton_method("reverse", function!(reverse_string, 1))?;
Ok(())
}
Add the Unicode dependency:
# ext/fast_strings/Cargo.toml
[package]
name = "fast_strings"
version = "0.1.0"
edition = "2021"
[dependencies]
magnus = { version = "0.7" }
unicode-segmentation = "1.10"
[lib]
name = "fast_strings"
crate-type = ["cdylib"]
Step 3: Build Your Extension
# Install dependencies and compile
bundle install
bundle exec rake compile
Compilation Steps
- Ruby reads
extconf.rb
create_rust_makefile
generates a Makefile- Cargo compiles your Rust code
- The compiled library is copied to
lib/fast_strings/
Step 4: Add Tests
Create a test file to verify our 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
Step 5: Run Tests
# Run the tests
bundle exec rake test
Step 6: Try It Yourself
# Open an interactive console
bundle exec bin/console
# Try the reverse function
FastStrings.reverse("Hello, World!")
# => "!dlroW ,olleH"
Publishing Your Gem
Ready to share your creation with the world?
# Update version in version.rb
# Update gemspec with description and homepage
# Build the gem
gem build fast_strings.gemspec
# Push to RubyGems.org
gem push fast_strings-0.1.0.gem
What You Learned
- Created a Ruby gem with a Rust extension
- Wrote safe, fast Rust code
- Handled Unicode correctly
- Added tests