class Rcov::CallSiteAnalyzer

available.
information for those methods for which callsite information is
the inspection of the CallSiteAnalyzer, i.o.w. you will only have defsite
defsite information is only available for methods that were called under
class.
provision is taken to ignore code executed “inside” the CallSiteAnalyzer
analyzer will manage its data separately. Note however that no special
possible to nest the #run_hooked / #install_hook/#remove_hook blocks: each
You can have several CallSiteAnalyzer objects at a time, and it is
defsite.line # => 2
defsite.file # => “example.rb”
defsite = analyzer.defsite(“X#f1”)
# associations
analyzer.callsites(“X#f2”) # => hash with CallSite => count
analyzer.defsite(“X#f1”) # => DefSite object
analyzer.methods_for_class(“X”) # => [“f1”, “f2”, “f3”]
analyzer.analyzed_classes # => [“X”, … ]
end
# to the previously recorded one
# the information generated in this run is aggregated
x.f3
analyzer.run_hooked do
# .…
end
x.f1
analyzer.run_hooked do
x = X.new
analyzer = Rcov::CallSiteAnalyzer.new
end
def f3; f1 end
def f2; 1 + 1 end
def f1; f2 end
class X
example.rb:
== Example
* where a method was called from (“callsite”)
* where a method is defined (“defsite”)
A CallSiteAnalyzer can be used to obtain information about:

def self.hook_level # :nodoc:

:nodoc:
defined this way instead of attr_accessor so that it's covered
def self.hook_level      # :nodoc:
  @hook_level
end

def self.hook_level=(x) # :nodoc:

:nodoc:
def self.hook_level=(x)  # :nodoc:
  @hook_level = x
end

def aggregate_data(aggregated_data, delta)

def aggregate_data(aggregated_data, delta)
  callsites1, defsites1 = aggregated_data
  callsites2, defsites2 = delta

  callsites2.each_pair do |(klass, method), hash|
    dest_hash = (callsites1[[klass, method]] ||= {})
    hash.each_pair do |callsite, count|
      dest_hash[callsite] ||= 0
      dest_hash[callsite] += count
    end
  end
  defsites1.update(defsites2)
end

def analyzed_classes

#
each of them). Singleton classes are rendered as:
Returns an array of strings describing the classes (just klass.to_s for
Classes whose methods have been called.
def analyzed_classes
  raw_data_relative.first.keys.map{|klass, meth| klass}.uniq.sort
end

def callsites(classname_or_fullname, methodname = nil)

analyzer.callsites("#", "g1")
analyzer.callsites("Foo", "f1")
or
analyzer.callsites("Foo.g1") # singleton method of the class
analyzer.callsites("Foo#f1") # instance method
Can be called in two ways:
Returns a hash with CallSite => call count associations or +nil+
def callsites(classname_or_fullname, methodname = nil)
  rawsites = raw_data_relative.first[expand_name(classname_or_fullname, methodname)]
  return nil unless rawsites
  ret = {}
  # could be a job for inject but it's slow and I don't mind the extra loc
  rawsites.each_pair do |backtrace, count|
    ret[CallSite.new(backtrace)] = count
  end
  ret
end

def compute_raw_data_difference(first, last)

def compute_raw_data_difference(first, last)
  difference = {}
  default = Hash.new(0)
  callsites1, defsites1 = *first
  callsites2, defsites2 = *last
  callsites2.each_pair do |(klass, method), hash|
    old_hash = callsites1[[klass, method]] || default
    hash.each_pair do |callsite, count|
      diff = hash[callsite] - (old_hash[callsite] || 0)
      if diff > 0
        difference[[klass, method]] ||= {}
        difference[[klass, method]][callsite] = diff
      end
    end
  end
  [difference, defsites1.update(defsites2)]
end

def data_default; [{}, {}] end

def data_default; [{}, {}] end

def defsite(classname_or_fullname, methodname = nil)

analyzer.defsite("#", "g1")
analyzer.defsite("Foo", "f1")
or
analyzer.defsite("Foo.g1") # singleton method of the class
analyzer.defsite("Foo#f1") # instance method
Can be called in two ways:
Returns a DefSite object corresponding to the given method
def defsite(classname_or_fullname, methodname = nil)
  file, line = raw_data_relative[1][expand_name(classname_or_fullname, methodname)]
  return nil unless file && line
  DefSite.new(file, line)
end

def expand_name(classname_or_fullname, methodname = nil)

def expand_name(classname_or_fullname, methodname = nil)
  if methodname.nil?
    case classname_or_fullname
    when /(.*)#(.*)/ then classname, methodname = $1, $2
    when /(.*)\.(.*)/ then classname, methodname = "#<Class:#{$1}>", $2
    else
      raise ArgumentError, "Incorrect method name"
    end
    return [classname, methodname]
  end
  [classname_or_fullname, methodname]
end

def initialize

def initialize
  super(:install_callsite_hook, :remove_callsite_hook,
        :reset_callsite)
end

def methods_for_class(classname)

Returns an array of strings or +nil+
the notation used for singleton classes.
Methods that were called for the given class. See #analyzed_classes for
def methods_for_class(classname)
  a = raw_data_relative.first.keys.select{|kl,_| kl == classname}.map{|_,meth| meth}.sort
  a.empty? ? nil : a
end

def raw_data_absolute

def raw_data_absolute
  raw, method_def_site = RCOV__.generate_callsite_info
  ret1 = {}
  ret2 = {}
  raw.each_pair do |(klass, method), hash|
    begin  
      key = [klass.to_s, method.to_s]
      ret1[key] = hash.clone #Marshal.load(Marshal.dump(hash))
      ret2[key] = method_def_site[[klass, method]]
    #rescue Exception
    end
  end
  [ret1, ret2]
end