Module: TreeHaver::RSpec::DependencyTags

Defined in:
lib/tree_haver/rspec/dependency_tags.rb

Overview

Dependency detection helpers for conditional test execution

Class Method Summary collapse

Class Method Details

.allowed_native_backendsArray<Symbol>

Get allowed native backends from TREE_HAVER_NATIVE_BACKEND

Returns:

  • (Array<Symbol>)

    list of allowed native backends, or [:all] or [:none]



256
257
258
259
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 256

def allowed_native_backends
  return @allowed_native_backends if defined?(@allowed_native_backends)
  @allowed_native_backends = TreeHaver.allowed_native_backends
end

.allowed_ruby_backendsArray<Symbol>

Get allowed Ruby backends from TREE_HAVER_RUBY_BACKEND

Returns:

  • (Array<Symbol>)

    list of allowed Ruby backends, or [:all] or [:none]



264
265
266
267
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 264

def allowed_ruby_backends
  return @allowed_ruby_backends if defined?(@allowed_ruby_backends)
  @allowed_ruby_backends = TreeHaver.allowed_ruby_backends
end

.any_json_backend_available?Boolean

Check if at least one JSON parsing backend is available

Currently only tree-sitter-json is supported for JSON parsing.
Future backends (e.g., pure-Ruby JSON parsers) can be added here.

Returns:

  • (Boolean)

    true if any JSON parsing backend works



766
767
768
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 766

def any_json_backend_available?
  tree_sitter_json_available?
end

.any_jsonc_backend_available?Boolean

Check if at least one JSONC parsing backend is available

Currently only tree-sitter-jsonc is supported for JSONC parsing.
Future backends (e.g., pure-Ruby JSONC parsers) can be added here.

Returns:

  • (Boolean)

    true if any JSONC parsing backend works



776
777
778
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 776

def any_jsonc_backend_available?
  tree_sitter_jsonc_available?
end

.any_markdown_backend_available?Boolean

Check if at least one markdown backend is available

Uses BackendRegistry.tag_available? to check external backends that may
not have their methods defined yet (registered by external gems).

Returns:

  • (Boolean)

    true if any markdown backend works



755
756
757
758
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 755

def any_markdown_backend_available?
  TreeHaver::BackendRegistry.tag_available?(:markly_backend) ||
    TreeHaver::BackendRegistry.tag_available?(:commonmarker_backend)
end

.any_native_grammar_available?Boolean

Returns:

  • (Boolean)


780
781
782
783
784
785
786
787
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 780

def any_native_grammar_available?
  libtree_sitter_available? && (
    tree_sitter_bash_available? ||
      tree_sitter_toml_available? ||
      tree_sitter_json_available? ||
      tree_sitter_jsonc_available?
  )
end

.any_rbs_backend_available?Boolean

Check if at least one RBS backend is available

Returns:

  • (Boolean)

    true if any RBS backend works



699
700
701
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 699

def any_rbs_backend_available?
  rbs_gem_available? || tree_sitter_rbs_available?
end

.any_toml_backend_available?Boolean

Check if at least one TOML backend is available

Returns:

  • (Boolean)

    true if any TOML backend works



745
746
747
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 745

def any_toml_backend_available?
  tree_sitter_toml_available? || toml_rb_gem_available? || toml_gem_available?
end

.backend_allowed?(backend) ⇒ Boolean

Check if a specific backend is allowed based on environment variables

Delegates to TreeHaver.backend_allowed? which handles both
TREE_HAVER_NATIVE_BACKEND and TREE_HAVER_RUBY_BACKEND.

Parameters:

  • backend (Symbol)

    the backend to check (:mri, :ffi, :citrus, etc.)

Returns:

  • (Boolean)

    true if the backend is allowed



276
277
278
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 276

def backend_allowed?(backend)
  TreeHaver.backend_allowed?(backend)
end

.citrus_available?Boolean

Check if Citrus backend is available

This checks if the citrus gem is installed and the backend works.

Returns:

  • (Boolean)

    true if Citrus backend is available



585
586
587
588
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 585

def citrus_available?
  return @citrus_available if defined?(@citrus_available)
  @citrus_available = TreeHaver::BackendRegistry.available?(:citrus)
end

.compute_blocked_backendsSet<Symbol>

Determine which backends are blocked based on environment and ARGV

This replicates the logic from RSpec.configure to determine blocked
backends BEFORE the RSpec.configure block has run. This is necessary
because summary may be called in a before(:suite) hook that runs
before the blocked_backends instance variable is set.

Returns:

  • (Set<Symbol>)

    set of blocked backend symbols



801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 801

def compute_blocked_backends
  blocked = Set.new

  # Check TREE_HAVER_BACKEND environment variable
  env_backend = ENV["TREE_HAVER_BACKEND"]
  if env_backend && !env_backend.empty? && env_backend != "auto"
    backend_sym = env_backend.to_sym
    TreeHaver::Backends::BLOCKED_BY[backend_sym]&.each { |blocker| blocked << blocker }
  end

  # Check ARGV for --tag options that indicate isolated backend testing
  ARGV.each_with_index do |arg, i|
    tag_value = nil
    if arg == "--tag" && ARGV[i + 1]
      tag_str = ARGV[i + 1]
      next if tag_str.start_with?("~")
      tag_value = tag_str.to_sym
    elsif arg.start_with?("--tag=")
      tag_str = arg.sub("--tag=", "")
      next if tag_str.start_with?("~")
      tag_value = tag_str.to_sym
    end

    next unless tag_value

    # Check for standard backend tags (e.g., :ffi_backend)
    TreeHaver::Backends::BLOCKED_BY.each do |backend, blockers|
      standard_tag = :"#{backend}_backend"
      legacy_tag = :"#{backend}_backend_only"
      if tag_value == standard_tag || tag_value == legacy_tag
        blockers.each { |blocker| blocked << blocker }
      end
    end
  end

  blocked
end

.env_summaryHash{String => String}

Get environment variable summary for debugging

Returns:

  • (Hash{String => String})

    relevant environment variables



919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 919

def env_summary
  {
    "TREE_SITTER_BASH_PATH" => ENV["TREE_SITTER_BASH_PATH"],
    "TREE_SITTER_TOML_PATH" => ENV["TREE_SITTER_TOML_PATH"],
    "TREE_SITTER_JSON_PATH" => ENV["TREE_SITTER_JSON_PATH"],
    "TREE_SITTER_JSONC_PATH" => ENV["TREE_SITTER_JSONC_PATH"],
    "TREE_SITTER_RBS_PATH" => ENV["TREE_SITTER_RBS_PATH"],
    "TREE_SITTER_RUNTIME_LIB" => ENV["TREE_SITTER_RUNTIME_LIB"],
    "TREE_HAVER_BACKEND" => ENV["TREE_HAVER_BACKEND"],
    "TREE_HAVER_DEBUG" => ENV["TREE_HAVER_DEBUG"],
    # Library paths used by tree-sitter shared libraries
    "LD_LIBRARY_PATH" => ENV["LD_LIBRARY_PATH"],
    "DYLD_LIBRARY_PATH" => ENV["DYLD_LIBRARY_PATH"],
  }
end

.ffi_available?Boolean

Check if FFI backend is actually usable (live check, not memoized)

This method attempts to actually use the FFI backend by loading a language.
This provides “live” validation of backend availability because:

  • If FFI gem is missing, it will fail
  • If MRI backend was used first, BackendConflict will be raised
  • If libtree-sitter is missing, it will fail

NOT MEMOIZED: Each call re-checks availability. This validates that
backend protection works correctly as tests run. FFI tests should run
first (via rake spec which runs ffi_specs then remaining_specs).

For isolated FFI testing, use bin/rspec-ffi

Returns:

  • (Boolean)

    true if FFI backend is usable



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 299

def ffi_available?
  # If TREE_HAVER_BACKEND explicitly selects a different native backend,
  # FFI is not available for testing
  return false unless backend_allowed?(:ffi)

  # TruffleRuby's FFI doesn't support STRUCT_BY_VALUE return types
  # (used by ts_tree_root_node, ts_node_child, ts_node_start_point, etc.)
  return false if truffleruby?

  # Try to actually use the FFI backend
  path = find_toml_grammar_path
  return false unless path && File.exist?(path)

  TreeHaver.with_backend(:ffi) do
    TreeHaver::Language.from_library(path, symbol: "tree_sitter_toml")
  end
  true
rescue TreeHaver::BackendConflict, TreeHaver::NotAvailable, LoadError
  false
rescue StandardError
  # Catch any other FFI-related errors (e.g., Polyglot::ForeignException)
  false
end

.ffi_backend_only_available?Boolean

Deprecated.

Use :ffi_backend tag instead of :ffi_backend_only

Check if FFI backend is available WITHOUT loading MRI first

This method is primarily for backwards compatibility with the legacy
:ffi_backend_only tag. The preferred approach is to use the standard
:ffi_backend tag, which now also triggers isolated_test_mode when
used with –tag ffi_backend.

Returns:

  • (Boolean)

    true if FFI backend is usable in isolation



362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 362

def ffi_backend_only_available?
  # If TREE_HAVER_BACKEND explicitly selects a different native backend,
  # FFI is not available for testing
  return false unless backend_allowed?(:ffi)

  # TruffleRuby's FFI doesn't support STRUCT_BY_VALUE return types
  return false if truffleruby?

  # Check if FFI gem is available without loading tree_sitter
  begin
    require "ffi"
  rescue LoadError
    return false
  end

  # Try to actually use the FFI backend
  path = find_toml_grammar_path
  return false unless path && File.exist?(path)

  TreeHaver.with_backend(:ffi) do
    TreeHaver::Language.from_library(path, symbol: "tree_sitter_toml")
  end
  true
rescue TreeHaver::BackendConflict, TreeHaver::NotAvailable, LoadError
  false
rescue StandardError
  # Catch any other FFI-related errors
  false
end

.find_toml_grammar_pathString?

Find the path to a TOML grammar library from environment variable

Grammar paths should be configured via TREE_SITTER_TOML_PATH environment variable.
This keeps configuration explicit and avoids magic path guessing.

Returns:

  • (String, nil)

    path to TOML grammar library, or nil if not found



530
531
532
533
534
535
536
537
538
539
540
541
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 530

def find_toml_grammar_path
  # First check environment variable
  env_path = ENV["TREE_SITTER_TOML_PATH"]
  return env_path if env_path && File.exist?(env_path)

  # Use GrammarFinder to search standard paths
  finder = TreeHaver::GrammarFinder.new(:toml, validate: false)
  finder.find_library_path
rescue StandardError
  # GrammarFinder might not be available or might fail
  nil
end

.java_backend_available?Boolean

Check if Java backend is available AND can actually load grammars

The Java backend requires:

  1. Running on JRuby
  2. java-tree-sitter (jtreesitter) JAR available
  3. Grammars built for java-tree-sitter’s Foreign Function Memory API

Note: Standard .so files built for MRI’s tree-sitter C bindings are NOT
compatible with java-tree-sitter. You need grammar JARs from Maven Central
or libraries specifically built for Java FFM API.

Returns:

  • (Boolean)

    true if Java backend is available and can load grammars



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 452

def java_backend_available?
  return @java_backend_available if defined?(@java_backend_available)

  # If TREE_HAVER_BACKEND explicitly selects a different native backend,
  # Java is not available for testing
  return @java_backend_available = false unless backend_allowed?(:java)

  # Must be on JRuby and have java-tree-sitter classes available
  return @java_backend_available = false unless jruby?
  return @java_backend_available = false unless TreeHaver::Backends::Java.available?

  # Try to actually load a grammar to verify the backend works end-to-end
  # This catches the case where Java classes load but grammars fail
  # (e.g., when using MRI-built .so files on JRuby)
  @java_backend_available = java_grammar_loadable?
end

.java_grammar_loadable?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if Java backend can actually load a grammar

This does a live test by trying to load a TOML grammar via the Java backend.
It catches the common failure case where java-tree-sitter is available but
the grammar .so files are incompatible (built for MRI, not java-tree-sitter).

Returns:

  • (Boolean)

    true if a grammar can be loaded via Java backend



477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 477

def java_grammar_loadable?
  return false unless jruby?

  path = find_toml_grammar_path
  return false unless path && File.exist?(path)

  TreeHaver.with_backend(:java) do
    TreeHaver::Backends::Java::Language.from_library(path, symbol: "tree_sitter_toml")
  end
  true
rescue TreeHaver::NotAvailable, TreeHaver::Error, LoadError
  false
rescue StandardError
  # Catch any other Java-related errors
  false
end

.jruby?Boolean

Check if running on JRuby

Returns:

  • (Boolean)

    true if running on JRuby



607
608
609
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 607

def jruby?
  defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
end

.libtree_sitter_available?Boolean

Check if libtree-sitter runtime library is loadable

Returns:

  • (Boolean)

    true if libtree-sitter.so is loadable via FFI



497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 497

def libtree_sitter_available?
  return @libtree_sitter_available if defined?(@libtree_sitter_available)
  @libtree_sitter_available = begin
    if !ffi_available?
      false
    else
      TreeHaver::Backends::FFI::Native.try_load!
      true
    end
  rescue TreeHaver::NotAvailable, LoadError
    false
  rescue StandardError
    # TruffleRuby raises Polyglot::ForeignException when FFI
    # encounters unsupported types like STRUCT_BY_VALUE
    false
  end
end

.mri?Boolean

Check if running on MRI (CRuby)

Returns:

  • (Boolean)

    true if running on MRI



621
622
623
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 621

def mri?
  defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby"
end

.mri_backend_available?Boolean

Check if ruby_tree_sitter gem is available (MRI backend)

The MRI backend only works on MRI Ruby (C extension).
When this returns true, it also records MRI backend usage with
TreeHaver.record_backend_usage(:mri). This is critical for conflict
detection - without it, FFI would not know that MRI has been loaded.

Returns:

  • (Boolean)

    true if ruby_tree_sitter gem is available



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 331

def mri_backend_available?
  return @mri_backend_available if defined?(@mri_backend_available)

  # If TREE_HAVER_BACKEND explicitly selects a different native backend,
  # MRI is not available for testing
  return @mri_backend_available = false unless backend_allowed?(:mri)

  # ruby_tree_sitter is a C extension that only works on MRI
  return @mri_backend_available = false unless mri?

  @mri_backend_available = begin
    # Note: gem is ruby_tree_sitter but requires tree_sitter
    require "tree_sitter"
    # Record that MRI backend is now loaded - this is critical for
    # conflict detection with FFI backend
    TreeHaver.record_backend_usage(:mri)
    true
  rescue LoadError
    false
  end
end

.mri_backend_only_available?Boolean

Check if MRI backend is available WITHOUT checking FFI availability

This is used for the :mri_backend_only tag which runs MRI tests
without triggering any FFI availability checks.

Returns:

  • (Boolean)

    true if MRI backend is usable



398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 398

def mri_backend_only_available?
  return @mri_backend_only_available if defined?(@mri_backend_only_available)

  # If TREE_HAVER_BACKEND explicitly selects a different native backend,
  # MRI is not available for testing
  return @mri_backend_only_available = false unless backend_allowed?(:mri)

  # ruby_tree_sitter is a C extension that only works on MRI
  return @mri_backend_only_available = false unless mri?

  @mri_backend_only_available = begin
    require "tree_sitter"
    TreeHaver.record_backend_usage(:mri)
    true
  rescue LoadError
    false
  end
end

.parslet_available?Boolean

Check if Parslet backend is available

This checks if the parslet gem is installed and the backend works.

Returns:

  • (Boolean)

    true if Parslet backend is available



595
596
597
598
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 595

def parslet_available?
  return @parslet_available if defined?(@parslet_available)
  @parslet_available = TreeHaver::BackendRegistry.available?(:parslet)
end

.prism_available?Boolean

Check if prism gem is available

Returns:

  • (Boolean)

    true if Prism is available



567
568
569
570
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 567

def prism_available?
  return @prism_available if defined?(@prism_available)
  @prism_available = TreeHaver::BackendRegistry.available?(:prism)
end

.psych_available?Boolean

Check if psych is available (stdlib, should always be true)

Returns:

  • (Boolean)

    true if Psych is available



575
576
577
578
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 575

def psych_available?
  return @psych_available if defined?(@psych_available)
  @psych_available = TreeHaver::BackendRegistry.available?(:psych)
end

.rbs_gem_available?Boolean Also known as: rbs_backend_available?

Check if the RBS gem is available and functional

The RBS gem only works on MRI Ruby (C extension).

Returns:

  • (Boolean)

    true if rbs gem is available and can parse RBS



675
676
677
678
679
680
681
682
683
684
685
686
687
688
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 675

def rbs_gem_available?
  return @rbs_gem_available if defined?(@rbs_gem_available)
  @rbs_gem_available = begin
    require "rbs"
    # Verify it can actually parse - just requiring isn't enough
    buffer = ::RBS::Buffer.new(name: "test.rbs", content: "class Foo end")
    ::RBS::Parser.parse_signature(buffer)
    true
  rescue LoadError
    false
  rescue StandardError
    false
  end
end

.reset!void

This method returns an undefined value.

Reset all memoized availability checks

Useful in tests that need to re-check availability after mocking.
Note: This does NOT undo backend usage recording.



941
942
943
944
945
946
947
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 941

def reset!
  instance_variables.each do |ivar|
    # Don't reset ENV-based values
    next if %i[@selected_backend @allowed_native_backends @allowed_ruby_backends].include?(ivar)
    remove_instance_variable(ivar) if ivar.to_s.end_with?("_available")
  end
end

.reset_selected_backend!void

This method returns an undefined value.

Reset selected backend caches (useful for testing with different ENV values)

Also resets TreeHaver’s backend caches.



954
955
956
957
958
959
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 954

def reset_selected_backend!
  remove_instance_variable(:@selected_backend) if defined?(@selected_backend)
  remove_instance_variable(:@allowed_native_backends) if defined?(@allowed_native_backends)
  remove_instance_variable(:@allowed_ruby_backends) if defined?(@allowed_ruby_backends)
  TreeHaver.reset_backend!
end

.rust_backend_available?Boolean

Check if tree_stump gem is available (Rust backend)

The Rust backend only works on MRI Ruby (magnus uses MRI’s C API).

Returns:

  • (Boolean)

    true if tree_stump gem is available



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 422

def rust_backend_available?
  return @rust_backend_available if defined?(@rust_backend_available)

  # If TREE_HAVER_BACKEND explicitly selects a different native backend,
  # Rust is not available for testing
  return @rust_backend_available = false unless backend_allowed?(:rust)

  # tree_stump uses magnus which requires MRI's C API
  return @rust_backend_available = false unless mri?

  @rust_backend_available = begin
    require "tree_stump"
    true
  rescue LoadError
    false
  end
end

.selected_backendSymbol

Get the selected backend from TREE_HAVER_BACKEND

Returns:

  • (Symbol)

    the selected backend (:auto if not set)



248
249
250
251
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 248

def selected_backend
  return @selected_backend if defined?(@selected_backend)
  @selected_backend = TreeHaver.backend
end

.summaryHash{Symbol => Boolean}

Get a summary of available dependencies (for debugging)

This method respects blocked_backends to avoid loading backends
that would conflict with isolated test modes (e.g., FFI-only tests).

Returns:

  • (Hash{Symbol => Boolean})

    map of dependency name to availability



845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 845

def summary
  # Use stored blocked_backends if available, otherwise compute dynamically
  blocked = @blocked_backends || compute_blocked_backends

  result = {
    # Backend selection from environment variables
    selected_backend: selected_backend,
    allowed_native_backends: allowed_native_backends,
    allowed_ruby_backends: allowed_ruby_backends,
  }

  # Built-in TreeHaver backends (*_backend) - skip blocked backends to avoid loading them
  builtin_backends = {
    ffi: :ffi_available?,
    mri: :mri_backend_available?,
    rust: :rust_backend_available?,
    java: :java_backend_available?,
    prism: :prism_available?,
    psych: :psych_available?,
    citrus: :citrus_available?,
    parslet: :parslet_available?,
    rbs: :rbs_backend_available?,
  }

  builtin_backends.each do |backend, method|
    tag = :"#{backend}_backend"
    result[tag] = blocked.include?(backend) ? :blocked : public_send(method)
  end

  # Dynamically registered backends from BackendRegistry
  TreeHaver::BackendRegistry.registered_tags.each do |tag_name|
    next if result.key?(tag_name) # Don't override built-ins

    meta = TreeHaver::BackendRegistry.(tag_name)
    next unless meta && meta[:category] == :backend

    backend = meta[:backend_name]
    result[tag_name] = blocked.include?(backend) ? :blocked : TreeHaver::BackendRegistry.tag_available?(tag_name)
  end

  # Ruby engines (*_engine)
  result[:ruby_engine] = RUBY_ENGINE
  result[:mri_engine] = mri?
  result[:jruby_engine] = jruby?
  result[:truffleruby_engine] = truffleruby?

  # Tree-sitter grammars (*_grammar) - also respect blocked backends
  # since grammar checks may load backends
  result[:libtree_sitter] = libtree_sitter_available?
  result[:bash_grammar] = blocked.include?(:mri) ? :blocked : tree_sitter_bash_available?
  result[:toml_grammar] = blocked.include?(:mri) ? :blocked : tree_sitter_toml_available?
  result[:json_grammar] = blocked.include?(:mri) ? :blocked : tree_sitter_json_available?
  result[:jsonc_grammar] = blocked.include?(:mri) ? :blocked : tree_sitter_jsonc_available?
  result[:rbs_grammar] = blocked.include?(:mri) ? :blocked : tree_sitter_rbs_available?
  result[:any_native_grammar] = blocked.include?(:mri) ? :blocked : any_native_grammar_available?

  # Language parsing capabilities (*_parsing)
  result[:toml_parsing] = any_toml_backend_available?
  result[:markdown_parsing] = any_markdown_backend_available?
  result[:json_parsing] = any_json_backend_available?
  result[:jsonc_parsing] = any_jsonc_backend_available?
  result[:rbs_parsing] = any_rbs_backend_available?

  # Specific libraries (*_gem)
  result[:toml_rb_gem] = toml_rb_gem_available?
  result[:toml_gem] = toml_gem_available?
  result[:rbs_gem] = rbs_gem_available?

  result
end

.toml_gem_available?Boolean

Check if toml gem is available and functional (Parslet backend for TOML)

Returns:

  • (Boolean)

    true if toml gem is available and can parse TOML



723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 723

def toml_gem_available?
  return @toml_gem_available if defined?(@toml_gem_available)
  @toml_gem_available = begin
    require "toml"
    # Verify it can actually parse - just requiring isn't enough
    source_toml = <<~TOML
      # My Information
      [machine]
      host = "localhost"
    TOML
    TOML.load(source_toml)
    true
  rescue LoadError
    false
  rescue StandardError
    false
  end
end

.toml_grammar_available?Boolean

Check if a TOML grammar library is available via environment variable

Returns:

  • (Boolean)

    true if TREE_SITTER_TOML_PATH points to an existing file



518
519
520
521
522
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 518

def toml_grammar_available?
  return @toml_grammar_available if defined?(@toml_grammar_available)
  path = find_toml_grammar_path
  @toml_grammar_available = path && File.exist?(path)
end

.toml_rb_gem_available?Boolean

Check if toml-rb gem is available and functional (Citrus backend for TOML)

Returns:

  • (Boolean)

    true if toml-rb gem is available and can parse TOML



706
707
708
709
710
711
712
713
714
715
716
717
718
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 706

def toml_rb_gem_available?
  return @toml_rb_gem_available if defined?(@toml_rb_gem_available)
  @toml_rb_gem_available = begin
    require "toml-rb"
    # Verify it can actually parse - just requiring isn't enough
    TomlRB.parse('key = "value"')
    true
  rescue LoadError
    false
  rescue StandardError
    false
  end
end

.tree_sitter_bash_available?Boolean

Check if tree-sitter-bash grammar is available and working

Returns:

  • (Boolean)

    true if bash grammar works



633
634
635
636
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 633

def tree_sitter_bash_available?
  return @tree_sitter_bash_available if defined?(@tree_sitter_bash_available)
  @tree_sitter_bash_available = grammar_works?(:bash, "echo hello")
end

.tree_sitter_json_available?Boolean

Check if tree-sitter-json grammar is available and working

Returns:

  • (Boolean)

    true if json grammar works



649
650
651
652
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 649

def tree_sitter_json_available?
  return @tree_sitter_json_available if defined?(@tree_sitter_json_available)
  @tree_sitter_json_available = grammar_works?(:json, '{"key": "value"}')
end

.tree_sitter_jsonc_available?Boolean

Check if tree-sitter-jsonc grammar is available and working

Returns:

  • (Boolean)

    true if jsonc grammar works



657
658
659
660
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 657

def tree_sitter_jsonc_available?
  return @tree_sitter_jsonc_available if defined?(@tree_sitter_jsonc_available)
  @tree_sitter_jsonc_available = grammar_works?(:jsonc, '{"key": "value" /* comment */}')
end

.tree_sitter_rbs_available?Boolean

Check if tree-sitter-rbs grammar is available and working

Returns:

  • (Boolean)

    true if rbs grammar works



665
666
667
668
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 665

def tree_sitter_rbs_available?
  return @tree_sitter_rbs_available if defined?(@tree_sitter_rbs_available)
  @tree_sitter_rbs_available = grammar_works?(:rbs, "class Foo end")
end

.tree_sitter_toml_available?Boolean

Check if tree-sitter-toml grammar is available and working via TreeHaver

Returns:

  • (Boolean)

    true if toml grammar works



641
642
643
644
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 641

def tree_sitter_toml_available?
  return @tree_sitter_toml_available if defined?(@tree_sitter_toml_available)
  @tree_sitter_toml_available = grammar_works?(:toml, 'key = "value"')
end

.truffleruby?Boolean

Check if running on TruffleRuby

Returns:

  • (Boolean)

    true if running on TruffleRuby



614
615
616
# File 'lib/tree_haver/rspec/dependency_tags.rb', line 614

def truffleruby?
  defined?(RUBY_ENGINE) && RUBY_ENGINE == "truffleruby"
end