tree_haver v3.2.0 released!
3.2.0 - 2025-12-30
- TAG: v3.2.0
- COVERAGE: 86.82% – 2167/2496 lines in 22 files
- BRANCH COVERAGE: 66.79% – 734/1099 branches in 22 files
- 90.03% documented
Added
TreeHaver::CITRUS_DEFAULTSconstant with default Citrus configurations for known languages- Enables automatic Citrus fallback for TOML without explicit
citrus_configparameter - Currently includes configuration for
:toml(gem:toml-rb, const:TomlRB::Document)
- Enables automatic Citrus fallback for TOML without explicit
- Regression test suite for Citrus fallback (
spec/integration/citrus_fallback_spec.rb)- Tests
parser_forwith all tree-sitter backends stubbed as unavailable (simulating TruffleRuby) - Tests
CitrusGrammarFinderwith nilgem_nameandrequire_path - Tests explicit Citrus backend usage on MRI via
with_backend(:citrus)
- Tests
- Shared examples for TOML parsing tests (
spec/support/shared_examples/toml_parsing_examples.rb)"toml parsing basics"- tests basic parsing, positions, children, text extraction"toml node navigation"- tests first_child, named_children navigation
- Multi-backend TOML test suite (
spec/integration/multi_backend_toml_spec.rb)- Runs shared examples against both tree-sitter-toml and Citrus/toml-rb backends
- Tests backend equivalence for parsing results and positions
- Tagged appropriately so tests run on whichever backends are available
- Backend Platform Compatibility section to README
- Complete compatibility matrix showing which backends work on MRI, JRuby, TruffleRuby
- Detailed explanations for TruffleRuby and JRuby limitations
FFI.available?method at module level for API consistency with other backendsTreeHaver.resolve_native_backend_modulemethod for resolving only tree-sitter backendsTreeHaver::NATIVE_BACKENDSconstant listing backends that support shared libraries- TruffleRuby short-circuit in
resolve_native_backend_modulefor efficiency- Avoids trying 3 backends that are all known to fail on TruffleRuby
citrus_available?method to check if Citrus backend is available
Fixed
TreeHaver::Node#childnow returnsnilfor out-of-bounds indices on all backends- MRI backend (ruby_tree_sitter) raises
IndexErrorfor invalid indices - Other backends return
nilfor invalid indices - Now consistently returns
nilacross all backends for API compatibility
- MRI backend (ruby_tree_sitter) raises
- Citrus backend
calculate_pointreturns negative column values- When
offsetwas 0,@source.rindex("\n", -1)searched from end of string - This caused
column = 0 - (position_of_last_newline) - 1to be negative (e.g., -34) - Fix: Early return
{row: 0, column: 0}foroffset <= 0 - This bug affected both MRI and TruffleRuby when using Citrus backend
- When
- Citrus fallback fails on TruffleRuby when no explicit
citrus_configprovidedparser_for(:toml)would fail withTypeError: no implicit conversion of nil into String- Root cause:
citrus_configdefaulted to{}, socitrus_config[:gem_name]wasnil CitrusGrammarFinderwas instantiated withgem_name: nil, causingrequire nil- On TruffleRuby, this triggered a bug in
bundled_gems.rbcallingFile.pathon nil - Fix: Added
CITRUS_DEFAULTSwith known Citrus configurations (TOML currently) - Fix:
parser_fornow usesCITRUS_DEFAULTS[name]when no explicit config provided - Fix: Added guard in
CitrusGrammarFinder#available?to return false whenrequire_pathis nil - Fix: Added
TypeErrorto rescue clause for TruffleRuby-specific edge cases
from_libraryno longer falls back to pure-Ruby backends- Previously, calling
Language.from_library(path)on TruffleRuby would fall back to Citrus backend which then raised a confusing error about not supporting shared libraries - Now
from_libraryonly considers native tree-sitter backends (MRI, Rust, FFI, Java) - Clear error message when no native backend is available explaining the situation
- Previously, calling
- Integration specs now use
parser_forinstead of explicit pathstree_edge_cases_spec.rbandnode_edge_cases_spec.rbnow useTreeHaver.parser_for(:toml)which auto-discovers the best available backend (tree-sitter or Citrus fallback)- Tests now work correctly on all platforms (MRI, JRuby, TruffleRuby)
- Tagged with
:toml_parsingwhich passes if ANY toml parser is available
- Core specs now use
parser_forinstead of explicit pathstree_spec.rb,node_spec.rb,parser_spec.rbconverted to useTreeHaver.parser_for(:toml)- All
:toml_grammartags changed to:toml_parsingfor cross-platform compatibility - Tests now run on JRuby and TruffleRuby via Citrus/toml-rb fallback
- FFI backend now properly reports as unavailable on TruffleRuby
ffi_gem_available?returnsfalseon TruffleRuby since tree-sitter uses STRUCT_BY_VALUE return typesFFI.available?added at module level (was only in Native submodule)- Prevents confusing runtime errors (Polyglot::ForeignException) by detecting incompatibility upfront
- Dependency tags now check
truffleruby?before attempting FFI backend tests
- MRI backend now properly reports as unavailable on JRuby and TruffleRuby
available?returnsfalseon non-MRI platforms (C extension only works on MRI)
- Rust backend now properly reports as unavailable on JRuby and TruffleRuby
available?returnsfalseon non-MRI platforms (magnus requires MRI’s C API)
- Backend compatibility matrix spec now properly skips tests for platform-incompatible backends
- MRI and Rust backends skip on JRuby/TruffleRuby with clear skip messages
- FFI backend skips on TruffleRuby with clear skip message
Changed
- BREAKING: RSpec Dependency Tag Naming Convention Overhaul
- All dependency tags now follow consistent naming conventions with suffixes
- Backend tags now use
*_backendsuffix (e.g.,:commonmarker_backend,:markly_backend) - Engine tags now use
*_enginesuffix (e.g.,:mri_engine,:jruby_engine,:truffleruby_engine) - Grammar tags now use
*_grammarsuffix (e.g.,:bash_grammar,:toml_grammar,:json_grammar) - Parsing capability tags now use
*_parsingsuffix (e.g.,:toml_parsing,:markdown_parsing) - Migration required: Update specs using legacy tags:
:commonmarker→:commonmarker_backend:markly→:markly_backend:mri→:mri_engine:jruby→:jruby_engine:truffleruby→:truffleruby_engine:tree_sitter_bash→:bash_grammar:tree_sitter_toml→:toml_grammar:tree_sitter_json→:json_grammar:tree_sitter_jsonc→:jsonc_grammar:toml_backend→:toml_parsing:markdown_backend→:markdown_parsing
- Removed inner-merge dependency tags from tree_haver
- Tags
:toml_merge,:json_merge,:prism_merge,:psych_mergeremoved - These belong in ast-merge gem, not tree_haver
- Use
require "ast/merge/rspec/dependency_tags"for merge gem tags
- Tags
- API Consistency: All backends now have uniform
available?API at module level:TreeHaver::Backends::FFI.available?- checks ffi gem + not TruffleRuby + MRI not loadedTreeHaver::Backends::MRI.available?- checks MRI platform + ruby_tree_sitter gemTreeHaver::Backends::Rust.available?- checks MRI platform + tree_stump gemTreeHaver::Backends::Java.available?- checks JRuby platform + jtreesitter JARTreeHaver::Backends::Prism.available?- checks prism gem (all platforms)TreeHaver::Backends::Psych.available?- checks psych stdlib (all platforms)TreeHaver::Backends::Commonmarker.available?- checks commonmarker gem (all platforms)TreeHaver::Backends::Markly.available?- checks markly gem (all platforms)TreeHaver::Backends::Citrus.available?- checks citrus gem (all platforms)
- README now accurately documents TruffleRuby backend support
- FFI backend doesn’t work on TruffleRuby due to
STRUCT_BY_VALUElimitation in TruffleRuby’s FFI - Rust backend (tree_stump) doesn’t work due to magnus/rb-sys incompatibility with TruffleRuby’s C API
- TruffleRuby users should use Prism, Psych, Commonmarker, Markly, or Citrus backends
- FFI backend doesn’t work on TruffleRuby due to
- Documented confirmed tree-sitter backend limitations:
- TruffleRuby: No tree-sitter backend works (FFI, MRI, Rust all fail)
- JRuby: Only Java and FFI backends work; Rust/MRI don’t
- Updated Rust Backend section with platform compatibility notes
- Updated FFI Backend section with TruffleRuby limitation details
- Use kettle-rb/ts-grammar-setup GHA in CI workflows
Fixed
- Rakefile now properly overrides
testtask afterrequire "kettle/dev"- Works around a bug in kettle-dev where test task runs minitest loader in CI
- Ensures
rake testruns RSpec specs instead of empty minitest suite
TreeHaver::RSpec::DependencyTagsnow catches TruffleRuby FFI exceptions- TruffleRuby’s FFI raises
Polyglot::ForeignExceptionfor unsupported types likeSTRUCT_BY_VALUE ffi_available?andlibtree_sitter_available?now returnfalseinstead of crashing- Fixes spec loading errors on TruffleRuby
- TruffleRuby’s FFI raises
TreeHaver::Backends::FFI::Language.from_librarynow catchesRuntimeErrorfrom TruffleRuby- TruffleRuby raises
RuntimeErrorinstead ofLoadErrorwhen a shared library cannot be opened - Now properly converts to
TreeHaver::NotAvailablewith descriptive message
- TruffleRuby raises
TreeHaver::Backends::FFI::Native.try_load!now only sets@loaded = trueafter allattach_functioncalls succeed- Previously,
loaded?returnedtrueeven whenattach_functionfailed (e.g., on TruffleRuby) - Now
loaded?correctly returnsfalsewhen FFI functions couldn’t be attached - Ensures FFI tests are properly skipped on TruffleRuby
- Previously,
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?