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.
Fil-C is a memory-safe C compiler. Ruby's VALUE type becomes a pointer (struct rb_value_unit_struct *) instead of an integer. This breaks code that:
switch on VALUE (case labels must be integer constants)Each command runs independently (no persistent shell). Use ruby_3_3 not ruby.
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
ls /tmp/gem-port/*/ext/
Note: Some gems have ext/<name>/, others have files directly in ext/.
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>
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
Edit files in /tmp/gem-port/*/ext/ directly, then re-run step 4. No need to re-unpack or re-run extconf.
# Always capture stderr and check exit code
nix build .#pkgsFilc.ruby_3_3.gems.<name> 2>&1; echo "EXIT: $?"
ls result/ 2>&1
ALWAYS use ast-grep for pattern-based code fixes. It handles whitespace variations that break string replacement.
Different C constructs need different selectors:
call_expression - function calls like rb_attr($A, $B, Qfalse)switch_statement - switch blocks with case labelsdeclaration - variable declarationsFunction 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 .
# 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...")
| 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.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer