Class: TreeHaver::ParsletGrammarFinder
- Inherits:
-
Object
- Object
- TreeHaver::ParsletGrammarFinder
- Defined in:
- lib/tree_haver/parslet_grammar_finder.rb
Overview
Utility for finding and registering Parslet grammar gems.
ParsletGrammarFinder provides language-agnostic discovery of Parslet grammar
gems. Given a language name and gem information, it attempts to load the
grammar and register it with tree_haver.
Unlike tree-sitter grammars (which are .so files), Parslet grammars are
Ruby classes that inherit from Parslet::Parser. This class handles the
discovery and registration of these grammars.
Instance Attribute Summary collapse
-
#gem_name ⇒ String
readonly
The gem name to require.
-
#grammar_const ⇒ String
readonly
The constant path to the grammar class (e.g., “TOML::Parslet”).
-
#language_name ⇒ Symbol
readonly
The language identifier.
-
#require_path ⇒ String?
readonly
Custom require path (defaults to gem_name).
Instance Method Summary collapse
-
#available? ⇒ Boolean
Check if the Parslet grammar is available.
-
#grammar_class ⇒ Class?
Get the resolved grammar class.
-
#initialize(language:, gem_name:, grammar_const:, require_path: nil) ⇒ ParsletGrammarFinder
constructor
Initialize a Parslet grammar finder.
-
#not_found_message ⇒ String
Get a human-readable error message when grammar is not found.
-
#register!(raise_on_missing: false) ⇒ Boolean
Register this Parslet grammar with TreeHaver.
-
#search_info ⇒ Hash
Get debug information about the search.
Constructor Details
#initialize(language:, gem_name:, grammar_const:, require_path: nil) ⇒ ParsletGrammarFinder
Initialize a Parslet grammar finder
51 52 53 54 55 56 57 58 59 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 51 def initialize(language:, gem_name:, grammar_const:, require_path: nil) @language_name = language.to_sym @gem_name = gem_name @grammar_const = grammar_const @require_path = require_path || gem_name @load_attempted = false @available = false @grammar_class = nil end |
Instance Attribute Details
#gem_name ⇒ String (readonly)
Returns the gem name to require.
37 38 39 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 37 def gem_name @gem_name end |
#grammar_const ⇒ String (readonly)
Returns the constant path to the grammar class (e.g., “TOML::Parslet”).
40 41 42 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 40 def grammar_const @grammar_const end |
#language_name ⇒ Symbol (readonly)
Returns the language identifier.
34 35 36 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 34 def language_name @language_name end |
#require_path ⇒ String? (readonly)
Returns custom require path (defaults to gem_name).
43 44 45 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 43 def require_path @require_path end |
Instance Method Details
#available? ⇒ Boolean
Check if the Parslet grammar is available
Attempts to require the gem and resolve the grammar constant.
Result is cached after first call.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 67 def available? return @available if @load_attempted @load_attempted = true debug = ENV["TREE_HAVER_DEBUG"] # Guard against nil require_path (can happen if gem_name was nil) if @require_path.nil? || @require_path.empty? warn("ParsletGrammarFinder: require_path is nil or empty for #{@language_name}") if debug @available = false return false end begin # Try to require the gem require @require_path # Try to resolve the constant @grammar_class = resolve_constant(@grammar_const) # Verify it can create a parser instance with a parse method unless valid_grammar_class?(@grammar_class) if debug warn("ParsletGrammarFinder: #{@grammar_const} is not a valid Parslet grammar class") warn("ParsletGrammarFinder: #{@grammar_const}.class = #{@grammar_class.class}") end @available = false return false end @available = true rescue LoadError => e # :nocov: defensive - requires gem to not be installed if debug warn("ParsletGrammarFinder: Failed to load '#{@require_path}': #{e.class}: #{e.}") warn("ParsletGrammarFinder: LoadError backtrace:\n #{e.backtrace&.first(10)&.join("\n ")}") end @available = false # :nocov: rescue NameError => e # :nocov: defensive - requires gem with missing constant if debug warn("ParsletGrammarFinder: Failed to resolve '#{@grammar_const}': #{e.class}: #{e.}") warn("ParsletGrammarFinder: NameError backtrace:\n #{e.backtrace&.first(10)&.join("\n ")}") end @available = false # :nocov: rescue TypeError => e # :nocov: defensive - TruffleRuby-specific edge case warn("ParsletGrammarFinder: TypeError during load of '#{@require_path}': #{e.class}: #{e.}") warn("ParsletGrammarFinder: This may be a TruffleRuby bundled_gems.rb issue") if debug warn("ParsletGrammarFinder: TypeError backtrace:\n #{e.backtrace&.first(10)&.join("\n ")}") end @available = false # :nocov: rescue => e # :nocov: defensive - catch-all for unexpected errors warn("ParsletGrammarFinder: Unexpected error: #{e.class}: #{e.}") if debug warn("ParsletGrammarFinder: backtrace:\n #{e.backtrace&.first(10)&.join("\n ")}") end @available = false # :nocov: end @available end |
#grammar_class ⇒ Class?
Get the resolved grammar class
139 140 141 142 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 139 def grammar_class available? # Ensure we've tried to load @grammar_class end |
#not_found_message ⇒ String
Get a human-readable error message when grammar is not found
185 186 187 188 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 185 def "Parslet grammar for #{@language_name} not found. " \ "Install #{@gem_name} gem: gem install #{@gem_name}" end |
#register!(raise_on_missing: false) ⇒ Boolean
Register this Parslet grammar with TreeHaver
After registration, the language can be used via:
TreeHaver::Language.#language_name
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 152 def register!(raise_on_missing: false) unless available? if raise_on_missing raise NotAvailable, end return false end TreeHaver.register_language( @language_name, grammar_class: @grammar_class, gem_name: @gem_name, ) true end |
#search_info ⇒ Hash
Get debug information about the search
171 172 173 174 175 176 177 178 179 180 |
# File 'lib/tree_haver/parslet_grammar_finder.rb', line 171 def search_info { language: @language_name, gem_name: @gem_name, grammar_const: @grammar_const, require_path: @require_path, available: available?, grammar_class: @grammar_class&.name, } end |