A CallSiteAnalyzer can be used to obtain information about:
where a method is defined (“defsite“)
where a method was called from (“callsite“)
example.rb:
class X def f1; f2 end def f2; 1 + 1 end def f3; f1 end end analyzer = Rcov::CallSiteAnalyzer.new x = X.new analyzer.run_hooked do x.f1 end # .... analyzer.run_hooked do x.f3 # the information generated in this run is aggregated # to the previously recorded one end analyzer.analyzed_classes # => ["X", ... ] analyzer.methods_for_class("X") # => ["f1", "f2", "f3"] analyzer.defsite("X#f1") # => DefSite object analyzer.callsites("X#f2") # => hash with CallSite => count # associations defsite = analyzer.defsite("X#f1") defsite.file # => "example.rb" defsite.line # => 2
You can have several CallSiteAnalyzer objects at a time, and it is possible to nest the # / #/# blocks: each analyzer will manage its data separately. Note however that no special provision is taken to ignore code executed “inside” the CallSiteAnalyzer class.
defsite information is only available for methods that were called under the inspection of the CallSiteAnalyzer, i.o.w. you will only have defsite information for those methods for which callsite information is available.
Classes whose methods have been called. Returns an array of strings describing the classes (just klass.to_s for each of them). Singleton classes are rendered as:
#<Class:MyNamespace::MyClass>
# File lib/rcov/call_site_analyzer.rb, line 110 110: def analyzed_classes 111: raw_data_relative.first.keys.map{|klass, meth| klass}.uniq.sort 112: end
Returns a hash with CallSite => call count associations or nil Can be called in two ways:
analyzer.callsites("Foo#f1") # instance method analyzer.callsites("Foo.g1") # singleton method of the class
or
analyzer.callsites("Foo", "f1") analyzer.callsites("#<class:Foo>", "g1")
# File lib/rcov/call_site_analyzer.rb, line 130 130: def callsites(classname_or_fullname, methodname = nil) 131: rawsites = raw_data_relative.first[expand_name(classname_or_fullname, methodname)] 132: return nil unless rawsites 133: ret = {} 134: # could be a job for inject but it's slow and I don't mind the extra loc 135: rawsites.each_pair do |backtrace, count| 136: ret[CallSite.new(backtrace)] = count 137: end 138: ret 139: end
Returns a DefSite object corresponding to the given method Can be called in two ways:
analyzer.defsite("Foo#f1") # instance method analyzer.defsite("Foo.g1") # singleton method of the class
or
analyzer.defsite("Foo", "f1") analyzer.defsite("#<class:Foo>", "g1")
# File lib/rcov/call_site_analyzer.rb, line 148 148: def defsite(classname_or_fullname, methodname = nil) 149: file, line = raw_data_relative[1][expand_name(classname_or_fullname, methodname)] 150: return nil unless file && line 151: DefSite.new(file, line) 152: end
Methods that were called for the given class. See # for the notation used for singleton classes. Returns an array of strings or nil
# File lib/rcov/call_site_analyzer.rb, line 117 117: def methods_for_class(classname) 118: a = raw_data_relative.first.keys.select{|kl,_| kl == classname}.map{|_,meth| meth}.sort 119: a.empty? ? nil : a 120: end
# File lib/rcov/call_site_analyzer.rb, line 189 189: def aggregate_data(aggregated_data, delta) 190: callsites1, defsites1 = aggregated_data 191: callsites2, defsites2 = delta 192: 193: callsites2.each_pair do |(klass, method), hash| 194: dest_hash = (callsites1[[klass, method]] ||= {}) 195: hash.each_pair do |callsite, count| 196: dest_hash[callsite] ||= 0 197: dest_hash[callsite] += count 198: end 199: end 200: 201: defsites1.update(defsites2) 202: end
# File lib/rcov/call_site_analyzer.rb, line 204 204: def compute_raw_data_difference(first, last) 205: difference = {} 206: default = Hash.new(0) 207: 208: callsites1, defsites1 = *first 209: callsites2, defsites2 = *last 210: 211: callsites2.each_pair do |(klass, method), hash| 212: old_hash = callsites1[[klass, method]] || default 213: hash.each_pair do |callsite, count| 214: diff = hash[callsite] - (old_hash[callsite] || 0) 215: if diff > 0 216: difference[[klass, method]] ||= {} 217: difference[[klass, method]][callsite] = diff 218: end 219: end 220: end 221: 222: [difference, defsites1.update(defsites2)] 223: end
# File lib/rcov/call_site_analyzer.rb, line 171 171: def data_default; [{}, {}] end
# File lib/rcov/call_site_analyzer.rb, line 156 156: def expand_name(classname_or_fullname, methodname = nil) 157: if methodname.nil? 158: case classname_or_fullname 159: when /(.*)#(.*)/ then classname, methodname = $1, $2 160: when /(.*)\.(.*)/ then classname, methodname = "#<Class:#{$1}>", $2 161: else 162: raise ArgumentError, "Incorrect method name" 163: end 164: 165: return [classname, methodname] 166: end 167: 168: [classname_or_fullname, methodname] 169: end
# File lib/rcov/call_site_analyzer.rb, line 173 173: def raw_data_absolute 174: raw, method_def_site = RCOV__.generate_callsite_info 175: ret1 = {} 176: ret2 = {} 177: raw.each_pair do |(klass, method), hash| 178: begin 179: key = [klass.to_s, method.to_s] 180: ret1[key] = hash.clone #Marshal.load(Marshal.dump(hash)) 181: ret2[key] = method_def_site[[klass, method]] 182: #rescue Exception 183: end 184: end 185: 186: [ret1, ret2] 187: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.