smithery.ai

gem-port

Port Ruby gems with native C extensions to Fil-C. Use when fixing gem compilation errors, VALUE/int type mismatches, rb_attr/rb_protect issues, or using ast-grep for Ruby C extensions.

First seen Apr 1, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 3,762 B
  • docs SUMMARY.md 200 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Fil-C Ruby Gem Porting

Context

Fil-C is a memory-safe C compiler. Ruby's VALUE type becomes a pointer (struct rbvalueunit_struct *) instead of an integer. This breaks code that:

  • Passes int literals where VALUE expected (Qfalse, Qtrue, ERROR_TOKEN)
  • Stores VALUE in int variables
  • Does bitwise ops on VALUE
  • Mixes VALUE and ID types
  • Uses switch on VALUE (case labels must be integer constants)

Workflow

Each command runs independently (no persistent shell). Use ruby33 not ruby.

1. Unpack gem

rm -rf /tmp/gem-port && mkdir -p /tmp/gem-port
nix develop .#pkgsFilc.ruby_3_3.gems.<name> --command bash -c 'gem unpack $src'
# Move to /tmp if unpacked in current dir
mv *<name>* /tmp/gem-port/ 2>/dev/null || true

2. Find ext structure

ls /tmp/gem-port/*/ext/

Note: Some gems have ext/<name>/, others have files directly in ext/.

3. Run extconf.rb

nix develop .#pkgsFilc.ruby_3_3.gems.<name> --command bash -c \
  'cd /tmp/gem-port/*/ext && ruby extconf.rb'
# Or if nested: cd /tmp/gem-port/*/ext/<name>

4. Build and capture errors

nix develop .#pkgsFilc.ruby_3_3.gems.<name> --command bash -c \
  'cd /tmp/gem-port/*/ext && make 2>&1' > /tmp/build.log
cat /tmp/build.log | head -100

5. Fix and iterate

Edit files in /tmp/gem-port/*/ext/ directly, then re-run step 4. No need to re-unpack or re-run extconf.

6. Add to rubyports.nix and verify

# Always capture stderr and check exit code
nix build .#pkgsFilc.ruby_3_3.gems.<name> 2>&1; echo "EXIT: $?"
ls result/ 2>&1

ast-grep Usage

ALWAYS use ast-grep for pattern-based code fixes. It handles whitespace variations that break string replacement.

Selectors

Different C constructs need different selectors:

  • callexpression - function calls like rbattr($A, $B, Qfalse)
  • switch_statement - switch blocks with case labels
  • declaration - variable declarations

Examples

Function call replacement:

ast-grep run -p 'rb_attr($A, $B, $C, $D, Qfalse)' \
             -r 'rb_attr($A, $B, $C, $D, 0)' \
             -l c --selector call_expression -U .

Switch to if-else (VALUE can't be case label):

ast-grep run \
  -p 'switch (rb_range_beg_len($A, $B, $L, $S, $F)) { case Qfalse: break; case Qnil: return Qnil; default: return subseq($X, $Y, $Z); }' \
  -r '{ VALUE r = rb_range_beg_len($A, $B, $L, $S, $F); if (r == Qfalse) { } else if (r == Qnil) { return Qnil; } else { return subseq($X, $Y, $Z); } }' \
  -l c --selector switch_statement -U .

Finding patterns (no -U):

ast-grep run -p 'static VALUE $NAME;' -l c .
ast-grep run -p 'case Q$CONST:' -l c .

rubyports.nix Helpers

# String replacement (fragile - prefer ast-grep)
(replace "path/to/file.c" "old string" "new string")

# ast-grep with call_expression selector
(astGrep "pattern($A)" "replacement($A)")

# ast-grep with custom selector
(astGrepSel "switch_statement" "switch(...)" "if-else...")

Common Patterns

Issue Pattern Fix
VALUE→ID for rb_intern static VALUE id = rb_intern(...) static ID id = ...
int→VALUE in switch case Qfalse: case Qnil: Convert to if-else
VALUE reused for int arg = ... (bitwise op) Use separate int variable
int return from VALUE func return 1; in VALUE function return Qtrue;

See REFERENCE.md for full patterns, FIXES.md for per-gem solutions, and AST_GREP.md for comprehensive ast-grep documentation.