🌓 TreeHaver: cross-Ruby AST parsing adapter for tree-sitter, parslet, & citrus
Published on December 19, 2025 by Peter Boling

🌻 Synopsis

TreeHaver is a cross-Ruby adapter for the tree-sitter, Citrus, and Parslet parsing libraries and other dedicated parsing tools that works seamlessly across MRI Ruby, JRuby, and TruffleRuby. It provides a unified API for parsing source code using grammars, regardless of your Ruby implementation.

The Adapter Pattern: Like Faraday, but for Parsing

Ā 
If you've used Faraday, multi_json, or multi_xml, you'll feel right at home with TreeHaver. These gems share a common philosophy:

Gem Unified API for Backend Examples

| FaradayĀ  | HTTP requestsĀ  | Net::HTTP, Typhoeus, Patron, Excon
| multi_jsonĀ  | JSON parsingĀ  | Oj, Yajl, JSON gem
| multi_xmlĀ  | XML parsingĀ  | Nokogiri, LibXML, Ox
| TreeHaverĀ  | Code parsingĀ  | MRI, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus, Parslet

Learn once, write anywhere.

Write once, run anywhere.
Ā 
Just as Faraday lets you swap HTTP adapters without changing your code, TreeHaver lets you swap tree-sitter backends. Your parsing code remains the same whether you're running on MRI with native C extensions, JRuby with FFI, or TruffleRuby.
Ā 
# Your code stays the same regardless of backend
parser = TreeHaver::Parser.new
parser.language = TreeHaver::Language.from_library("/path/to/grammar.so")
tree = parser.parse(source_code)

# TreeHaver automatically picks the best available backend:
# - MRI: ruby_tree_sitter, tree_stump, ffi, prism, psych, commonmarker, markly, citrus, parslet
# - JRuby: ffi, java-tree-sitter (not a gem, but the jtreesitter maven package), prism, psych, commonmarker, markly, citrus, parslet
# - TruffleRuby: prism, psych, commonmarker, markly, citrus, parslet
#   (tree-sitter backends don't work on Truffleruby with ffi gem due to FFI STRUCT_BY_VALUE limitation)


Key Features

Ā 
  • Universal Ruby Support: Works on MRI Ruby, JRuby, and TruffleRuby
  • 10 Parsing Backends - Choose the right backend for your needs:
    • Tree-sitter Backends (high-performance, incremental parsing):
      • MRI Backend: Leverages ruby_tree_sitter gem (C extension, fastest on MRI)
        • Note: ruby_tree_sitter currently requires unreleased fixes in the pboling fork, tree_haver branch.
      • Rust Backend: Uses tree_stump gem (Rust with precompiled binaries)Ā 
        • Note: Use tree_stump v0.2.0 or newer (fixes are released).
      • FFI Backend: Pure Ruby FFI bindings to libtree-sitter (JRuby only; TruffleRuby's FFI doesn't support tree-sitter's struct-by-value returns)
      • Java Backend: Native Java integration for JRuby with java-tree-sitter / jtreesitter grammar JARs
    • Language-Specific Backends (native parser integration):
      • Prism Backend: Ruby's official parser (stdlib in Ruby 3.4+)
      • Psych Backend: Ruby's YAML parser (stdlib)
      • Commonmarker Backend: Fast Markdown parser (comrak-based, Rust)
      • Markly Backend: GitHub Flavored Markdown (cmark-gfm-based, C)
    • Pure Ruby Fallback:Ā 
      • Citrus Backend: Pure Ruby PEG parsing via citrus (no native dependencies)
      • Parslet Backend: Pure Ruby PEG parsing via parslet (no native dependencies)
  • Automatic Backend Selection: Intelligently selects the best backend for your Ruby implementation
  • Language Agnostic: Parse any language - Ruby, Markdown, YAML, JSON, Bash, TOML, JavaScript, etc.
  • Grammar Discovery: Built-in GrammarFinder utility for platform-aware grammar library discovery
  • Unified Position API: Consistent start_line, end_line, source_position across all backends
  • Thread-Safe: Built-in language registry with thread-safe caching
  • Minimal API Surface: Simple, focused API that covers the most common use cases

TruffleRuby LimitationsĀ 

TruffleRuby has no working tree-sitter backend:Ā 
  • FFI: TruffleRuby's FFI doesn't support STRUCT_BY_VALUE return types (used by ts_tree_root_node, ts_node_child, etc.)
  • MRI/Rust: C and Rust extensions require MRI's C API internals (RBasic.flags, rb_gc_writebarrier, etc.) that TruffleRuby doesn't expose
    TruffleRuby users should use: Prism (Ruby), Psych (YAML), Citrus/Parslet (e.g., TOML via toml-rb/toml), or potentially Commonmarker/Markly (Markdown).

JRuby Limitations

JRuby runs on the JVM and cannot load native .so extensions via Ruby's C API:
Ā 
  • MRI/Rust: C and Rust extensions simply cannot be loaded
  • FFI: Works! JRuby has excellent FFI support
  • Java: Works! The Java backend uses jtreesitter (requires >= 0.26.0)
    JRuby users should use: Java backend (best performance, full API) or FFI backend for tree-sitter, plus Prism, Psych, Citrus/Parslet for other formats.

Why TreeHaver?

tree-sitter is a powerful parser generator that creates incremental parsers for many programming languages. However, integrating it into Ruby applications can be challenging:
Ā 
  • MRI-based C extensions don't work on JRuby
  • FFI-based solutions may not be optimal for MRI
  • Managing different backends for different Ruby implementations is cumbersome
    TreeHaver solves these problems by providing a unified API that automatically selects the appropriate backend for your Ruby implementation, allowing you to write code once and run it anywhere.