Module: RSpecTracer::RSpec::Installation Private
- Defined in:
- lib/rspec_tracer/rspec/installation.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Prepends RunnerHook + ReporterHook onto RSpec’s runner/reporter classes. Called once from ‘RSpecTracer.start`.
1.x used ‘ObjectSpace.each_object(::RSpec::Core::Runner)` to find the already-instantiated runner and prepend onto its singleton class - forcing start-time ordering (RSpec had to be mid-boot). 2.0 prepends onto the class itself at require time, so the hooks apply to every subsequent Runner / Reporter instance.
Consequence: ‘RSpecTracer.start` no longer requires RSpec to be running. As long as `RSpec::Core::Runner` and `RSpec::Core::Reporter` are loaded (the standard `require ’rspec’‘ in spec_helper covers both), install! succeeds. Side effect: the JRuby FULL_TRACE_ENABLED / object_space_enabled guard that 1.x needed is no longer load- bearing - prepend doesn’t touch ObjectSpace.
Idempotence: ‘Module#prepend` is a no-op when the module is already in the ancestors chain. Double-calling install! is safe.
Class Method Summary collapse
-
._count_accumulated_files ⇒ Object
private
Internal helper for the tracer pipeline.
-
.install!(runner_class: ::RSpec::Core::Runner, reporter_class: ::RSpec::Core::Reporter) ⇒ Object
private
‘install!` is named for its side effect (prepend the hooks), not as a predicate - rubocop’s Naming/PredicateMethod defaults to flagging anything that doesn’t return a boolean, but the trailing ‘true` is the Ruby idiom for “side-effect method ran fine”.
-
.prepend_hook(target_class, hook_module) ⇒ Object
private
rubocop:enable Naming/PredicateMethod.
-
.warn_if_coverage_already_accumulated ⇒ Object
private
Emit a single warn-level line when the user’s spec_helper triggered substantial application-code loads before calling ‘RSpecTracer.start`.
Class Method Details
._count_accumulated_files ⇒ Object
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.
Internal helper for the tracer pipeline.
89 90 91 92 93 94 |
# File 'lib/rspec_tracer/rspec/installation.rb', line 89 def self._count_accumulated_files ::Coverage.peek_result.count do |_, cov| lines = cov.is_a?(::Hash) ? cov[:lines] : cov lines.is_a?(::Array) && lines.any? { |strength| strength.is_a?(::Integer) && strength.positive? } end end |
.install!(runner_class: ::RSpec::Core::Runner, reporter_class: ::RSpec::Core::Reporter) ⇒ Object
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.
‘install!` is named for its side effect (prepend the hooks), not as a predicate - rubocop’s Naming/PredicateMethod defaults to flagging anything that doesn’t return a boolean, but the trailing ‘true` is the Ruby idiom for “side-effect method ran fine”.
Target classes are parameterized so unit specs can pass anonymous fresh classes instead of stubbing the real RSpec constants - the latter collides with RSpec’s own reporter finalization at at_exit time (RSpec::Core::Time vanishes while the outer suite is still finalizing). rubocop:disable Naming/PredicateMethod
42 43 44 45 46 47 48 49 |
# File 'lib/rspec_tracer/rspec/installation.rb', line 42 def self.install!(runner_class: ::RSpec::Core::Runner, reporter_class: ::RSpec::Core::Reporter) warn_if_coverage_already_accumulated prepend_hook(runner_class, RSpecTracer::RSpec::RunnerHook) prepend_hook(reporter_class, RSpecTracer::RSpec::ReporterHook) true end |
.prepend_hook(target_class, hook_module) ⇒ Object
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.
rubocop:enable Naming/PredicateMethod
52 53 54 55 56 |
# File 'lib/rspec_tracer/rspec/installation.rb', line 52 def self.prepend_hook(target_class, hook_module) return if target_class.ancestors.include?(hook_module) target_class.prepend(hook_module) end |
.warn_if_coverage_already_accumulated ⇒ Object
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.
Emit a single warn-level line when the user’s spec_helper triggered substantial application-code loads before calling ‘RSpecTracer.start`. The Coverage peek_result is per-file; we count files that already have at least one executed line. A non-SimpleCov fresh boot with >10 tracked files is the signal that app code loaded before the tracer started, which means boot-set capture misses those files as transitive dependencies.
Conservative by design: skip the warning when SimpleCov is running (SimpleCov-first is the documented load order), and when Coverage hasn’t started (defended-library edge case).
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/rspec_tracer/rspec/installation.rb', line 69 def self.warn_if_coverage_already_accumulated return unless defined?(::Coverage) return unless ::Coverage.respond_to?(:running?) && ::Coverage.running? return if defined?(::SimpleCov) && ::SimpleCov.running accumulated = _count_accumulated_files return if accumulated < 10 RSpecTracer.logger.warn( "RSpec tracer: coverage has already accumulated for #{accumulated} file(s) " \ 'before RSpecTracer.start. Expected load order: RSpecTracer.start runs before ' \ 'any application code (or after SimpleCov.start if using SimpleCov). Dependency ' \ 'attribution may miss boot-time loads.' ) rescue StandardError nil end |