https://github.com/xord/rucy
A Ruby C++ Extension Helper Library
https://github.com/xord/rucy
cpp gem ruby
Last synced: 22 days ago
JSON representation
A Ruby C++ Extension Helper Library
- Host: GitHub
- URL: https://github.com/xord/rucy
- Owner: xord
- License: mit
- Created: 2015-03-15T15:10:10.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2026-05-15T18:43:58.000Z (about 2 months ago)
- Last Synced: 2026-05-15T20:59:31.763Z (about 2 months ago)
- Topics: cpp, gem, ruby
- Language: C++
- Homepage:
- Size: 141 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: ChangeLog.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# Rucy - A Ruby C++ extension helper library
[](https://deepwiki.com/xord/rucy)



## ⚠️ Notice
This repository is a read-only mirror of our monorepo.
We do not accept pull requests or direct contributions here.
### 🔄 Where to Contribute?
All development happens in our [xord/all](https://github.com/xord/all) monorepo, which contains all our main libraries.
If you'd like to contribute, please submit your changes there.
For more details, check out our [Contribution Guidelines](./CONTRIBUTING.md).
Thanks for your support! 🙌
## 🚀 About
**Rucy** is a thin C++ layer on top of Ruby's C API. It reduces the boilerplate involved in writing a Ruby extension in C++ by wrapping `VALUE`, providing exception-safe method definitions, and converting between native types and Ruby values.
It is used by the native extensions in the `xord/*` family — [Beeps](https://github.com/xord/beeps), [Rays](https://github.com/xord/rays), and [Reflex](https://github.com/xord/reflex). It depends on [Xot](https://github.com/xord/xot) for low-level utilities such as reference counting, the pimpl idiom, and the string / exception classes.
Like Xot, Rucy exists primarily for our own gems. The API is stable enough for us to build on, but it is not a general-purpose extension framework — feel free to read it and learn from it, but pin a specific version if you depend on it directly.
## 📋 Requirements
- Ruby **3.0.0** or later
- A C++ compiler with C++20 support
- [Xot](https://rubygems.org/gems/xot) (declared as a runtime dependency)
- Rake and test-unit (development only)
## 📦 Installation
Add this line to your Gemfile:
```ruby
gem 'rucy'
```
Then install:
```bash
$ bundle install
```
Or install it directly:
```bash
$ gem install rucy
```
When linking against Rucy from your own extension, point `extconf.rb` at the gem's `include/` and `lib/` directories — `Rucy::Extension.inc_dir` and `Rucy::Extension.lib_dir` return the right paths.
## 📚 What's Included
### C++ headers (`include/rucy/`)
| Header | Provides |
| ------------- | ---------------------------------------------------------------------------------------- |
| `rucy.h` | `Rucy::init()`, the `Rucy` module, and the error class hierarchy |
| `ruby.h` | A safe `` wrapper plus the `RubyValue` / `RubySymbol` typedefs |
| `value.h` | `Rucy::Value` — wraps `VALUE` with type predicates, conversions, and method calls |
| `module.h` | `Rucy::Module` — `define_module`, `define_class`, `define_method`, ... |
| `class.h` | `Rucy::Class` — adds `define_alloc_func` on top of `Module` |
| `function.h` | `Rucy::call("method", ...)`, `eval`, `protect` — invoke Ruby code with C++ exception safety |
| `symbol.h` | `Rucy::Symbol` plus the `RUCY_SYM`, `RUCY_SYM_Q`, `RUCY_SYM_B` macros |
| `exception.h` | `RubyException`, `RubyJumpTag`, and `raise` / `*_error` throw helpers |
| `extension.h` | Method definition macros (`RUCY_DEF0` ... `RUCY_DEFN`) and `VALUE` ↔ native converters |
### Method definition macros
| Macro | Purpose |
| ---------------------------- | ----------------------------------------------------------------------- |
| `RUCY_DEF0` ... `RUCY_DEF12` | Define a Ruby method that takes 0–12 arguments |
| `RUCY_DEFN` | Define a variadic Ruby method (`int argc, const Value* argv`) |
| `RUCY_DEF_ALLOC` | Define an allocator function for a class |
| `RUCY_DEF_END` | Close a method definition; converts C++ exceptions into Ruby exceptions |
| `RUCY_TRY` / `RUCY_CATCH` | Wrap any block of C++ code in Ruby-safe exception translation |
### Type conversion macros
`RUCY_DECLARE_VALUE_FROM_TO` / `RUCY_DEFINE_VALUE_FROM_TO` (and the `WRAPPER` / `ARRAY` variants) generate `Rucy::value(...)` and `Rucy::value_to(...)` overloads so you can move data between Ruby and a native class with one line of declaration plus one line of definition.
### Ruby side (`lib/rucy/`)
| Module | Purpose |
| ----------------- | ----------------------------------------------------------------------------------------------- |
| `Rucy::Extension` | Path / name / version helpers, mirroring `Xot::Extension` for Rucy-based gems |
| `Rucy::Rake` | Rake DSL extensions used by `xord/*` gems (`build_native_library`, `build_ruby_extension`, ...) |
### Tools (`bin/`)
| Tool | Purpose |
| ----------- | ------------------------------------------------------------------------------------- |
| `rucy2rdoc` | Extract doc comments from C++ files using `RUCY_DEF*` macros into RDoc-friendly stubs |
## 💡 Usage
### A minimal extension
```cpp
// ext/hello/hello.cpp
#include
#include
using namespace Rucy;
/*
Returns a friendly greeting.
*/
RUCY_DEF1(greet, name)
{
return value(Xot::String("hello, ") + name.c_str());
}
RUCY_DEF_END
extern "C" void
Init_hello ()
{
RUCY_TRY
Module mHello = define_module("Hello");
mHello.define_module_function("greet", greet);
RUCY_CATCH
}
```
```ruby
# ext/hello/extconf.rb
require 'rucy/extension'
require 'mkmf'
$INCFLAGS << " -I#{Xot::Extension.inc_dir} -I#{Rucy::Extension.inc_dir}"
$LDFLAGS << " -L#{Xot::Extension.lib_dir} -L#{Rucy::Extension.lib_dir} -lxot -lrucy"
create_makefile 'hello/hello'
```
```ruby
# Use it from Ruby
require 'hello/hello'
Hello.greet 'world' # => "hello, world"
```
### Exception-safe method bodies
Anything you throw inside a `RUCY_DEF*` body — `Rucy::RubyException`, `std::exception`, `Xot::XotError`, or even a `const char*` — is caught by `RUCY_DEF_END` and re-raised as the corresponding Ruby exception. You can also raise directly:
```cpp
RUCY_DEF1(divide, n)
{
if (n.as_i() == 0)
argument_error(__FILE__, __LINE__, "divide by zero");
return value(100 / n.as_i());
}
RUCY_DEF_END
```
### Calling Ruby from C++
```cpp
Value ary = eval("[1, 2, 3]");
Value n = ary.call("sum"); // => Value(6)
```
For more examples, see `ext/rucy/tester.cpp` (used by the test suite) and the native extensions in [Beeps](https://github.com/xord/beeps), [Rays](https://github.com/xord/rays), and [Reflex](https://github.com/xord/reflex).
## 🛠️ Development
```bash
$ rake lib # build the native C++ library (librucy)
$ rake ext # build the test extension
$ rake test # run the test suite
$ rake doc # generate RDoc from C++ sources via rucy2rdoc
$ rake # default: builds the extension
```
Several headers and sources are ERB templates (`*.erb`) expanded automatically at build time. `NPARAM_MAX = 12` in the Rakefile auto-generates `RUCY_DEF0` ... `RUCY_DEF12` and the matching overloads of `call`, `protect`, and friends.
## 📜 License
**Rucy** is licensed under the MIT License.
See the [LICENSE](./LICENSE) file for details.