Module: Bulldogger::Probe::TargetResolver
- Defined in:
- lib/bulldogger/probe/target_resolver.rb
Overview
Turns "Klass#method" / "Klass.method" strings into Targets, failing before any TracePoint is enabled. Resolving every target up front (not lazily, on first call) is the contract's own requirement: a probe session must not let bad instrumentation surface only after the caller's code has already started running.
Constant Summary collapse
- INSTANCE_PATTERN =
/\A(.+)#(.+)\z/- SINGLETON_PATTERN =
/\A(.+)\.(.+)\z/
Class Method Summary collapse
-
.assert_targetable!(unbound_method, target_string) ⇒ Object
The only way to learn that a method is C-implemented is to actually try targeting it: UnboundMethod itself resolves fine for a C method (Array.instance_method(:push) succeeds); it is TracePoint#enable(target:) that raises ArgumentError (measured: "specified target is not supported", Array#push).
- .resolve!(target_strings) ⇒ Object
-
.resolve_constant!(owner_name, target_string) ⇒ Object
const_get(name, false) at each nesting level (not a single Object.const_get("A::B")) so a wrong nested name fails with the segment that is actually missing, and so this never accidentally resolves a same-named top-level constant that const_get's own inherit-search could reach from a deeper module (the
falseargument). - .resolve_one!(target_string) ⇒ Object
- .resolve_unbound_method!(owner, method_name, kind, target_string) ⇒ Object
- .split(target_string) ⇒ Object
Class Method Details
.assert_targetable!(unbound_method, target_string) ⇒ Object
The only way to learn that a method is C-implemented is to actually try targeting it: UnboundMethod itself resolves fine for a C method (Array.instance_method(:push) succeeds); it is TracePoint#enable(target:) that raises ArgumentError (measured: "specified target is not supported", Array#push). The probe TracePoint built here is disabled again immediately -- its only purpose is to surface that error before any of the caller's targets go live.
76 77 78 79 80 81 82 83 |
# File 'lib/bulldogger/probe/target_resolver.rb', line 76 def assert_targetable!(unbound_method, target_string) probe_tp = TracePoint.new(:call) {} probe_tp.enable(target: unbound_method) probe_tp.disable rescue ArgumentError raise ArgumentError, "bulldogger: probe target #{target_string.inspect} is a C-implemented method and can't be traced" end |
.resolve!(target_strings) ⇒ Object
19 20 21 |
# File 'lib/bulldogger/probe/target_resolver.rb', line 19 def resolve!(target_strings) target_strings.map { |s| resolve_one!(s) } end |
.resolve_constant!(owner_name, target_string) ⇒ Object
const_get(name, false) at each nesting level (not a single
Object.const_get("A::B")) so a wrong nested name fails with
the segment that is actually missing, and so this never
accidentally resolves a same-named top-level constant that
const_get's own inherit-search could reach from a deeper
module (the false argument).
49 50 51 52 53 54 55 56 |
# File 'lib/bulldogger/probe/target_resolver.rb', line 49 def resolve_constant!(owner_name, target_string) owner_name.split("::").reject(&:empty?).reduce(Object) do |mod, name| mod.const_get(name, false) end rescue NameError raise NameError, "bulldogger: no constant #{owner_name.inspect} for probe target #{target_string.inspect}" end |
.resolve_one!(target_string) ⇒ Object
23 24 25 26 27 28 29 |
# File 'lib/bulldogger/probe/target_resolver.rb', line 23 def resolve_one!(target_string) owner_name, method_name, kind = split(target_string) owner = resolve_constant!(owner_name, target_string) unbound_method = resolve_unbound_method!(owner, method_name, kind, target_string) assert_targetable!(unbound_method, target_string) Target.new(target_string, unbound_method) end |
.resolve_unbound_method!(owner, method_name, kind, target_string) ⇒ Object
58 59 60 61 62 63 64 65 66 |
# File 'lib/bulldogger/probe/target_resolver.rb', line 58 def resolve_unbound_method!(owner, method_name, kind, target_string) if kind == :instance owner.instance_method(method_name.to_sym) else owner.method(method_name.to_sym).unbind end rescue NameError raise NameError, "bulldogger: no method for probe target #{target_string.inspect}" end |
.split(target_string) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/bulldogger/probe/target_resolver.rb', line 31 def split(target_string) if (m = INSTANCE_PATTERN.match(target_string)) [m[1], m[2], :instance] elsif (m = SINGLETON_PATTERN.match(target_string)) [m[1], m[2], :singleton] else raise ArgumentError, "bulldogger: invalid probe target #{target_string.inspect} " \ '(expected "Klass#method" or "Klass.method")' end end |