tree_haver 5.0.4 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/tree_haver/backend_context.rb +28 -0
  4. data/lib/tree_haver/backend_registry.rb +19 -432
  5. data/lib/tree_haver/contracts.rb +460 -0
  6. data/lib/tree_haver/kaitai_backend.rb +30 -0
  7. data/lib/tree_haver/language_pack.rb +190 -0
  8. data/lib/tree_haver/peg_backends.rb +76 -0
  9. data/lib/tree_haver/version.rb +1 -12
  10. data/lib/tree_haver.rb +7 -1316
  11. data.tar.gz.sig +0 -0
  12. metadata +34 -245
  13. metadata.gz.sig +0 -0
  14. data/CHANGELOG.md +0 -1366
  15. data/CITATION.cff +0 -20
  16. data/CODE_OF_CONDUCT.md +0 -134
  17. data/CONTRIBUTING.md +0 -359
  18. data/FUNDING.md +0 -74
  19. data/LICENSE.txt +0 -21
  20. data/README.md +0 -2347
  21. data/REEK +0 -0
  22. data/RUBOCOP.md +0 -71
  23. data/SECURITY.md +0 -21
  24. data/lib/tree_haver/backend_api.rb +0 -349
  25. data/lib/tree_haver/backends/citrus.rb +0 -487
  26. data/lib/tree_haver/backends/ffi.rb +0 -1009
  27. data/lib/tree_haver/backends/java.rb +0 -893
  28. data/lib/tree_haver/backends/mri.rb +0 -362
  29. data/lib/tree_haver/backends/parslet.rb +0 -560
  30. data/lib/tree_haver/backends/prism.rb +0 -471
  31. data/lib/tree_haver/backends/psych.rb +0 -375
  32. data/lib/tree_haver/backends/rust.rb +0 -239
  33. data/lib/tree_haver/base/language.rb +0 -98
  34. data/lib/tree_haver/base/node.rb +0 -322
  35. data/lib/tree_haver/base/parser.rb +0 -24
  36. data/lib/tree_haver/base/point.rb +0 -48
  37. data/lib/tree_haver/base/tree.rb +0 -128
  38. data/lib/tree_haver/base.rb +0 -12
  39. data/lib/tree_haver/citrus_grammar_finder.rb +0 -218
  40. data/lib/tree_haver/compat.rb +0 -43
  41. data/lib/tree_haver/grammar_finder.rb +0 -374
  42. data/lib/tree_haver/language.rb +0 -295
  43. data/lib/tree_haver/language_registry.rb +0 -190
  44. data/lib/tree_haver/library_path_utils.rb +0 -80
  45. data/lib/tree_haver/node.rb +0 -579
  46. data/lib/tree_haver/parser.rb +0 -438
  47. data/lib/tree_haver/parslet_grammar_finder.rb +0 -224
  48. data/lib/tree_haver/path_validator.rb +0 -353
  49. data/lib/tree_haver/point.rb +0 -27
  50. data/lib/tree_haver/rspec/dependency_tags.rb +0 -1392
  51. data/lib/tree_haver/rspec/testable_node.rb +0 -217
  52. data/lib/tree_haver/rspec.rb +0 -33
  53. data/lib/tree_haver/tree.rb +0 -258
  54. data/sig/tree_haver/backends.rbs +0 -352
  55. data/sig/tree_haver/grammar_finder.rbs +0 -29
  56. data/sig/tree_haver/path_validator.rbs +0 -32
  57. data/sig/tree_haver.rbs +0 -234
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ca322ee7eaf08af41dba8cd7f11eb577d4e2491f382c9842689d46bca615031
4
- data.tar.gz: bfa7434b7e837a8cc6e73ae47c002d92136cf8ad8db6b54a7c283df0a72350dc
3
+ metadata.gz: 9252beb2837645a278018f2cc625f06e941ab68a7058f424963c37bfa7fab2fc
4
+ data.tar.gz: 140b2cfadb89f3f6d09d838053a667a2d10f278345e4d695dc15b439fff170eb
5
5
  SHA512:
6
- metadata.gz: e9ab1b591d247befd732b2bb0eec47c9c32aecdf9a0a462875cc3408314e65434699f7a9ea33d5616f0d03fb0833807cc9b8d0693ea5640badc4ffba1a6491c0
7
- data.tar.gz: 7e1805c2137d517158f3211dabede8a4846e0b575f95943e60d81baad71379582909356ec5311f950658fee39e4848ebcf3fbe2fbc3b138ae09364dbbb556ff0
6
+ metadata.gz: d1bc2f9f44b55dba4d026b0b27ee4c6f1e076dc42cd3759a2a43d2f1e745f4e3efd8a0d8c94d71c3cfc94a4df46770ab2be0315904cb3da3d6759468b530993f
7
+ data.tar.gz: 468d12010d1b8120e80744c8ef6fff01297c4085c9b359c411a3201dc94325e64661b00c6171c8e3436323f4b8d16450a83d40c07d17ec13cc6f182938f2402b
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreeHaver
4
+ BACKEND_CONTEXT_KEY = :structured_merge_tree_haver_backend
5
+
6
+ module_function
7
+
8
+ def current_backend_id
9
+ Thread.current[BACKEND_CONTEXT_KEY]
10
+ end
11
+
12
+ def with_backend(backend_id)
13
+ validate_backend_id!(backend_id)
14
+
15
+ previous_backend = Thread.current[BACKEND_CONTEXT_KEY]
16
+ Thread.current[BACKEND_CONTEXT_KEY] = backend_id.to_s
17
+ yield
18
+ ensure
19
+ Thread.current[BACKEND_CONTEXT_KEY] = previous_backend
20
+ end
21
+
22
+ def validate_backend_id!(backend_id)
23
+ return if BackendRegistry.fetch(backend_id.to_s)
24
+
25
+ raise ArgumentError, "Unknown tree_haver backend #{backend_id}."
26
+ end
27
+ private_class_method :validate_backend_id!
28
+ end
@@ -1,457 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TreeHaver
4
- # Registry for backend dependency tag availability checkers
5
- #
6
- # This module allows external gems (like commonmarker-merge, markly-merge, rbs-merge)
7
- # to register their availability checker for RSpec dependency tags without
8
- # TreeHaver needing to know about them directly.
9
- #
10
- # == Purpose
11
- #
12
- # When running RSpec tests with dependency tags (e.g., `:commonmarker_backend`),
13
- # TreeHaver needs to know if each backend is available. Rather than hardcoding
14
- # checks like `TreeHaver::Backends::Commonmarker.available?` (which would fail
15
- # if the backend module doesn't exist), the BackendRegistry provides a dynamic
16
- # way for backends to register their availability checkers.
17
- #
18
- # == Built-in vs External Backends
19
- #
20
- # - **Built-in backends** (MRI, Rust, FFI, Java, Prism, Psych, Citrus) register
21
- # their checkers automatically when loaded from `tree_haver/backends/*.rb`
22
- # - **External backends** (commonmarker-merge, markly-merge, rbs-merge) register
23
- # their checkers when their backend module is loaded
24
- #
25
- # == Full Tag Registration
26
- #
27
- # External gems can register complete tag support using {register_tag}:
28
- # - Tag name (e.g., :commonmarker_backend)
29
- # - Category (:backend, :gem, :parsing, :grammar)
30
- # - Availability checker
31
- # - Optional require path for lazy loading
32
- #
33
- # This enables tree_haver/rspec/dependency_tags to automatically configure
34
- # RSpec exclusion filters for any registered tag without hardcoded knowledge.
35
- #
36
- # == Thread Safety
37
- #
38
- # All operations are thread-safe using a Mutex for synchronization.
39
- # Results are cached after first check for performance.
40
- #
41
- # @example Registering a backend availability checker (simple form)
42
- # # In commonmarker-merge/lib/commonmarker/merge/backend.rb
43
- # TreeHaver::BackendRegistry.register_availability_checker(:commonmarker) do
44
- # available?
45
- # end
46
- #
47
- # @example Registering a full tag with require path (preferred for external gems)
48
- # TreeHaver::BackendRegistry.register_tag(
49
- # :commonmarker_backend,
50
- # category: :backend,
51
- # backend_name: :commonmarker,
52
- # require_path: "commonmarker/merge"
53
- # ) { Commonmarker::Merge::Backend.available? }
54
- #
55
- # @example Checking backend availability
56
- # TreeHaver::BackendRegistry.available?(:commonmarker) # => true/false
57
- # TreeHaver::BackendRegistry.available?(:markly) # => true/false
58
- # TreeHaver::BackendRegistry.available?(:rbs) # => true/false
59
- #
60
- # @example Getting all registered tags
61
- # TreeHaver::BackendRegistry.registered_tags # => [:commonmarker_backend, :markly_backend, ...]
62
- # TreeHaver::BackendRegistry.tags_by_category(:backend) # => [...]
63
- #
64
- # @see TreeHaver::RSpec::DependencyTags Uses BackendRegistry for dynamic backend detection
65
- # @api public
66
4
  module BackendRegistry
67
- @mutex = Mutex.new
68
- @availability_checkers = {} # rubocop:disable ThreadSafety/MutableClassInstanceVariable
69
- @availability_cache = {} # rubocop:disable ThreadSafety/MutableClassInstanceVariable
70
- @tag_registry = {} # rubocop:disable ThreadSafety/MutableClassInstanceVariable
71
-
72
- # Tag categories for organizing dependency tags
73
- # @api private
74
- CATEGORIES = %i[backend gem parsing grammar engine other].freeze
75
-
76
5
  module_function
77
6
 
78
- # Register a full dependency tag with all metadata
79
- #
80
- # This is the preferred method for external gems to register their availability
81
- # with complete tag support. It registers both the availability checker and
82
- # the tag metadata needed for RSpec configuration.
83
- #
84
- # When a tag is registered, this also dynamically defines a `*_available?` method
85
- # on `TreeHaver::RSpec::DependencyTags` if it doesn't already exist.
86
- #
87
- # @param tag_name [Symbol] the RSpec tag name (e.g., :commonmarker_backend)
88
- # @param category [Symbol] one of :backend, :gem, :parsing, :grammar, :engine, :other
89
- # @param backend_name [Symbol, nil] the backend name for availability checks (defaults to tag without suffix)
90
- # @param require_path [String, nil] optional require path to load before checking availability
91
- # @param checker [#call, nil] a callable that returns true if available
92
- # @yield Block form of checker (alternative to passing a callable)
93
- # @yieldreturn [Boolean] true if the tag's dependency is available
94
- # @return [void]
95
- #
96
- # @example Register a backend tag with require path
97
- # TreeHaver::BackendRegistry.register_tag(
98
- # :commonmarker_backend,
99
- # category: :backend,
100
- # require_path: "commonmarker/merge"
101
- # ) { Commonmarker::Merge::Backend.available? }
102
- #
103
- # @example Register a gem tag
104
- # TreeHaver::BackendRegistry.register_tag(
105
- # :toml_gem,
106
- # category: :gem,
107
- # require_path: "toml"
108
- # ) { defined?(TOML) }
109
- def register_tag(tag_name, category:, backend_name: nil, require_path: nil, checker: nil, &block)
110
- callable = checker || block
111
- raise ArgumentError, "Must provide a checker callable or block" unless callable
112
- raise ArgumentError, "Checker must respond to #call" unless callable.respond_to?(:call)
113
- raise ArgumentError, "Invalid category: #{category}" unless CATEGORIES.include?(category)
114
-
115
- tag_sym = tag_name.to_sym
116
- # Derive backend_name from tag_name if not provided (e.g., :commonmarker_backend -> :commonmarker)
117
- derived_backend = backend_name || tag_sym.to_s.sub(/_backend$/, "").to_sym
118
-
119
- @mutex.synchronize do
120
- @tag_registry[tag_sym] = {
121
- category: category,
122
- backend_name: derived_backend,
123
- require_path: require_path,
124
- checker: callable,
125
- }
126
- # Also register as availability checker for the backend name
127
- @availability_checkers[derived_backend] = callable
128
- # Clear caches
129
- @availability_cache.delete(derived_backend)
130
- end
131
-
132
- # Dynamically define the availability method on DependencyTags
133
- # This happens outside the mutex to avoid potential deadlock
134
- define_availability_method(derived_backend, tag_sym)
135
-
136
- nil
137
- end
138
-
139
- # Register an availability checker for a backend (simple form)
140
- #
141
- # The checker should be a callable (lambda/proc/block) that returns true if
142
- # the backend is available and can be used. The checker is called lazily
143
- # (only when {available?} is first called for this backend).
144
- #
145
- # For full tag support including require paths, use {register_tag} instead.
146
- #
147
- # @param backend_name [Symbol, String] the backend name (e.g., :commonmarker, :markly)
148
- # @param checker [#call, nil] a callable that returns true if the backend is available
149
- # @yield Block form of checker (alternative to passing a callable)
150
- # @yieldreturn [Boolean] true if the backend is available
151
- # @return [void]
152
- # @raise [ArgumentError] if no checker callable or block is provided
153
- # @raise [ArgumentError] if checker doesn't respond to #call
154
- #
155
- # @example Register with a block
156
- # TreeHaver::BackendRegistry.register_availability_checker(:commonmarker) do
157
- # require "commonmarker"
158
- # true
159
- # rescue LoadError
160
- # false
161
- # end
162
- #
163
- # @example Register with a lambda
164
- # checker = -> { Commonmarker::Merge::Backend.available? }
165
- # TreeHaver::BackendRegistry.register_availability_checker(:commonmarker, checker)
166
- #
167
- # @example Register referencing the module's available? method
168
- # TreeHaver::BackendRegistry.register_availability_checker(:my_backend) do
169
- # available? # Calls the enclosing module's available? method
170
- # end
171
- def register_availability_checker(backend_name, checker = nil, &block)
172
- callable = checker || block
173
- raise ArgumentError, "Must provide a checker callable or block" unless callable
174
- raise ArgumentError, "Checker must respond to #call" unless callable.respond_to?(:call)
175
-
176
- @mutex.synchronize do
177
- @availability_checkers[backend_name.to_sym] = callable
178
- # Clear cache for this backend when re-registering
179
- @availability_cache.delete(backend_name.to_sym)
7
+ def register(backend)
8
+ mutex.synchronize do
9
+ backends[backend.id] = deep_dup(backend.to_h)
180
10
  end
181
11
  nil
182
12
  end
183
13
 
184
- # Check if a backend is available
185
- #
186
- # If a checker was registered via {register_availability_checker}, it is called
187
- # (and the result cached). If no checker is registered, falls back to checking
188
- # `TreeHaver::Backends::<Name>.available?` for built-in backends.
189
- #
190
- # Results are cached to avoid repeated expensive checks (e.g., requiring gems).
191
- # Use {clear_cache!} to reset the cache if backend availability may have changed.
192
- #
193
- # @param backend_name [Symbol, String] the backend name to check
194
- # @return [Boolean] true if the backend is available, false otherwise
195
- #
196
- # @example
197
- # TreeHaver::BackendRegistry.available?(:commonmarker) # => true
198
- # TreeHaver::BackendRegistry.available?(:nonexistent) # => false
199
- def available?(backend_name)
200
- key = backend_name.to_sym
201
-
202
- # First, check cache and get checker without holding mutex for long
203
- checker = nil
204
- @mutex.synchronize do
205
- # Return cached result if available
206
- return @availability_cache[key] if @availability_cache.key?(key)
207
-
208
- # Get registered checker (if any)
209
- checker = @availability_checkers[key]
210
- end
211
-
212
- # Compute result OUTSIDE the mutex to avoid deadlock when loading backends
213
- # (loading a backend module triggers register_availability_checker which needs the mutex)
214
- result = if checker
215
- # Use the registered checker
216
- begin
217
- checker.call
218
- rescue StandardError
219
- false
220
- end
221
- else
222
- # Fall back to checking TreeHaver::Backends::<Name>
223
- # This may load the backend module, which will register its checker
224
- check_builtin_backend(key)
225
- end
226
-
227
- # Cache the result
228
- @mutex.synchronize do
229
- # Double-check cache in case another thread computed it
230
- return @availability_cache[key] if @availability_cache.key?(key)
231
- @availability_cache[key] = result
232
- end
233
-
234
- result
235
- end
236
-
237
- # Check if an availability checker is registered for a backend
238
- #
239
- # @param backend_name [Symbol, String] the backend name
240
- # @return [Boolean] true if a checker is registered
241
- #
242
- # @example
243
- # TreeHaver::BackendRegistry.registered?(:commonmarker) # => true (if loaded)
244
- # TreeHaver::BackendRegistry.registered?(:nonexistent) # => false
245
- def registered?(backend_name)
246
- @mutex.synchronize do
247
- @availability_checkers.key?(backend_name.to_sym)
248
- end
14
+ def fetch(id)
15
+ data = mutex.synchronize { backends[id] }
16
+ data && BackendReference.new(**deep_dup(data))
249
17
  end
250
18
 
251
- # Get all registered backend names
252
- #
253
- # @return [Array<Symbol>] list of registered backend names
254
- #
255
- # @example
256
- # TreeHaver::BackendRegistry.registered_backends
257
- # # => [:mri, :rust, :ffi, :java, :prism, :psych, :citrus, :commonmarker, :markly]
258
- def registered_backends
259
- @mutex.synchronize do
260
- @availability_checkers.keys.dup
19
+ def all
20
+ mutex.synchronize do
21
+ backends.values.map { |backend| BackendReference.new(**deep_dup(backend)) }
261
22
  end
262
23
  end
263
24
 
264
- # Clear the availability cache
265
- #
266
- # Useful for testing or when backend availability may have changed
267
- # (e.g., after installing a gem mid-process).
268
- #
269
- # @return [void]
270
- #
271
- # @example
272
- # TreeHaver::BackendRegistry.clear_cache!
273
- # # Next call to available? will re-check
274
- def clear_cache!
275
- @mutex.synchronize do
276
- @availability_cache.clear
277
- end
278
- nil
279
- end
280
-
281
- # Clear all registrations and cache
282
- #
283
- # Removes all registered checkers and cached results.
284
- # Primarily useful for testing to reset state between test cases.
285
- #
286
- # @return [void]
287
- #
288
- # @example
289
- # TreeHaver::BackendRegistry.clear!
290
25
  def clear!
291
- @mutex.synchronize do
292
- @availability_checkers.clear
293
- @availability_cache.clear
294
- @tag_registry.clear
295
- end
296
- nil
26
+ mutex.synchronize { backends.clear }
297
27
  end
298
28
 
299
- # ============================================================
300
- # Tag Registry Methods
301
- # ============================================================
302
-
303
- # Get all registered tag names
304
- #
305
- # @return [Array<Symbol>] list of registered tag names
306
- #
307
- # @example
308
- # TreeHaver::BackendRegistry.registered_tags
309
- # # => [:commonmarker_backend, :markly_backend, :toml_gem, ...]
310
- def registered_tags
311
- @mutex.synchronize do
312
- @tag_registry.keys.dup
313
- end
314
- end
315
-
316
- # Get tags filtered by category
317
- #
318
- # @param category [Symbol] one of :backend, :gem, :parsing, :grammar, :engine, :other
319
- # @return [Array<Symbol>] list of tag names in that category
320
- #
321
- # @example
322
- # TreeHaver::BackendRegistry.tags_by_category(:backend)
323
- # # => [:commonmarker_backend, :markly_backend, :mri_backend, ...]
324
- def tags_by_category(category)
325
- @mutex.synchronize do
326
- @tag_registry.select { |_, meta| meta[:category] == category }.keys
327
- end
328
- end
329
-
330
- # Get tag metadata
331
- #
332
- # @param tag_name [Symbol] the tag name
333
- # @return [Hash, nil] tag metadata or nil if not registered
334
- #
335
- # @example
336
- # TreeHaver::BackendRegistry.tag_metadata(:commonmarker_backend)
337
- # # => { category: :backend, backend_name: :commonmarker, require_path: "commonmarker/merge", checker: #<Proc> }
338
- def tag_metadata(tag_name)
339
- @mutex.synchronize do
340
- @tag_registry[tag_name.to_sym]&.dup
341
- end
29
+ def deep_dup(value)
30
+ Marshal.load(Marshal.dump(value))
342
31
  end
32
+ private_class_method :deep_dup
343
33
 
344
- # Check if a tag is registered
345
- #
346
- # @param tag_name [Symbol] the tag name
347
- # @return [Boolean] true if the tag is registered
348
- def tag_registered?(tag_name)
349
- @mutex.synchronize do
350
- @tag_registry.key?(tag_name.to_sym)
351
- end
34
+ def backends
35
+ @backends ||= {} # rubocop:disable ThreadSafety/MutableClassInstanceVariable
352
36
  end
37
+ private_class_method :backends
353
38
 
354
- # Check if a tag's dependency is available
355
- #
356
- # This method handles require paths: if the tag has a require_path, it will
357
- # attempt to load the gem before checking availability. This enables lazy
358
- # loading of external gems.
359
- #
360
- # @param tag_name [Symbol] the tag name to check
361
- # @return [Boolean] true if the tag's dependency is available
362
- #
363
- # @example
364
- # TreeHaver::BackendRegistry.tag_available?(:commonmarker_backend) # => true/false
365
- def tag_available?(tag_name)
366
- tag_sym = tag_name.to_sym
367
-
368
- # Get tag metadata
369
- meta = @mutex.synchronize { @tag_registry[tag_sym] }
370
-
371
- # If tag not registered, check if it's a backend name with _backend suffix
372
- unless meta
373
- # Try to derive backend name (e.g., :commonmarker_backend -> :commonmarker)
374
- backend_name = tag_sym.to_s.sub(/_backend$/, "").to_sym
375
- return available?(backend_name) if backend_name != tag_sym
376
- return false
377
- end
378
-
379
- # Try to load the gem if require_path is specified
380
- if meta[:require_path]
381
- begin
382
- require meta[:require_path]
383
- rescue LoadError
384
- # Gem not available
385
- return false
386
- end
387
- end
388
-
389
- # Check availability using the backend name
390
- available?(meta[:backend_name])
391
- end
392
-
393
- # Get a summary of all registered tags and their availability
394
- #
395
- # @return [Hash{Symbol => Boolean}] map of tag name to availability
396
- #
397
- # @example
398
- # TreeHaver::BackendRegistry.tag_summary
399
- # # => { commonmarker_backend: true, markly_backend: false, ... }
400
- def tag_summary
401
- @mutex.synchronize { @tag_registry.keys.dup }.each_with_object({}) do |tag, result|
402
- result[tag] = tag_available?(tag)
403
- end
404
- end
405
-
406
- # Check a built-in TreeHaver backend
407
- #
408
- # Attempts to find the backend module at `TreeHaver::Backends::<Name>` and
409
- # call its `available?` method. This is the fallback when no explicit
410
- # checker has been registered.
411
- #
412
- # @param backend_name [Symbol] the backend name (e.g., :mri, :rust, :ffi)
413
- # @return [Boolean] true if the backend module exists and reports available
414
- # @api private
415
- def check_builtin_backend(backend_name)
416
- # Convert backend_name to PascalCase constant name
417
- # e.g., :mri -> "MRI", :ffi -> "FFI", :commonmarker -> "Commonmarker"
418
- const_name = backend_name.to_s.split("_").map(&:capitalize).join
419
- backend_mod = TreeHaver::Backends.const_get(const_name)
420
- backend_mod.respond_to?(:available?) && backend_mod.available?
421
- rescue NameError
422
- # Backend module doesn't exist
423
- false
424
- end
425
- private_class_method :check_builtin_backend
426
-
427
- # Dynamically define an availability method on DependencyTags
428
- #
429
- # This creates a `*_available?` method that checks tag_available? with
430
- # memoization. The method is only defined if DependencyTags is loaded
431
- # and doesn't already have a method with that name.
432
- #
433
- # @param backend_name [Symbol] the backend name (e.g., :commonmarker)
434
- # @param tag_name [Symbol] the tag name (e.g., :commonmarker_backend)
435
- # @return [void]
436
- # @api private
437
- def define_availability_method(backend_name, tag_name)
438
- method_name = :"#{backend_name}_available?"
439
-
440
- # Only define if DependencyTags is loaded
441
- return unless defined?(TreeHaver::RSpec::DependencyTags)
442
-
443
- deps = TreeHaver::RSpec::DependencyTags
444
-
445
- # Don't override existing methods (built-in backends have explicit methods)
446
- return if deps.respond_to?(method_name)
447
-
448
- # Define the method dynamically
449
- ivar = :"@#{backend_name}_available"
450
- deps.define_singleton_method(method_name) do
451
- return instance_variable_get(ivar) if instance_variable_defined?(ivar)
452
- instance_variable_set(ivar, TreeHaver::BackendRegistry.tag_available?(tag_name))
453
- end
39
+ def mutex
40
+ @mutex ||= Mutex.new # rubocop:disable ThreadSafety/MutableClassInstanceVariable
454
41
  end
455
- private_class_method :define_availability_method
42
+ private_class_method :mutex
456
43
  end
457
44
  end