class Rcov::DifferentialAnalyzer
def self.hook_level
def self.hook_level raise "must be implemented by the subclass" end
def aggregate_data(aggregated_data, delta)
def aggregate_data(aggregated_data, delta) raise "must be implemented by the subclass" end
def compute_raw_data_difference(first, last)
def compute_raw_data_difference(first, last) raise "must be implemented by the subclass" end
def data_default
def data_default raise "must be implemented by the subclass" end
def initialize(install_hook_meth, remove_hook_meth, reset_meth)
def initialize(install_hook_meth, remove_hook_meth, reset_meth) @cache_state = :wait @start_raw_data = data_default @end_raw_data = data_default @aggregated_data = data_default @install_hook_meth = install_hook_meth @remove_hook_meth= remove_hook_meth @reset_meth= reset_meth end
def install_hook
collected until #remove_hook is called.
Start monitoring execution to gather information. Such data will be
def install_hook @start_raw_data = raw_data_absolute Rcov::RCOV__.send(@install_hook_meth) @cache_state = :hooked @@mutex.synchronize{ self.class.hook_level += 1 } end
def raw_data_absolute
def raw_data_absolute raise "must be implemented by the subclass" end
def raw_data_relative
def raw_data_relative case @cache_state when :wait return @aggregated_data when :hooked new_start = raw_data_absolute new_diff = compute_raw_data_difference(@start_raw_data, new_start) @start_raw_data = new_start when :done @cache_state = :wait new_diff = compute_raw_data_difference(@start_raw_data, @end_raw_data) end aggregate_data(@aggregated_data, new_diff) @aggregated_data end
def remove_hook
#remove_hook will also stop collecting info if it is run inside a
Stop collecting information.
def remove_hook @@mutex.synchronize do self.class.hook_level -= 1 Rcov::RCOV__.send(@remove_hook_meth) if self.class.hook_level == 0 end @end_raw_data = raw_data_absolute @cache_state = :done # force computation of the stats for the traced code in this run; # we cannot simply let it be if self.class.hook_level == 0 because # some other analyzer could install a hook, causing the raw_data_absolute # to change again. # TODO: lazy computation of raw_data_relative, only when the hook gets # activated again. raw_data_relative end
def reset
Remove the data collected so far. Further collection will start from
def reset @@mutex.synchronize do if self.class.hook_level == 0 # Unfortunately there's no way to report this as covered with rcov: # if we run the tests under rcov self.class.hook_level will be >= 1 ! # It is however executed when we run the tests normally. Rcov::RCOV__.send(@reset_meth) @start_raw_data = data_default @end_raw_data = data_default else @start_raw_data = @end_raw_data = raw_data_absolute end @raw_data_relative = data_default @aggregated_data = data_default end end
def run_hooked
Execute the code in the given block, monitoring it in order to gather
def run_hooked install_hook yield ensure remove_hook end