<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>samples/animals/c++/Makefile</filename>
    </added>
    <added>
      <filename>samples/animals/c++/animal.h</filename>
    </added>
    <added>
      <filename>samples/animals/c++/cat.cc</filename>
    </added>
    <added>
      <filename>samples/animals/c++/cat.h</filename>
    </added>
    <added>
      <filename>samples/animals/c++/dog.cc</filename>
    </added>
    <added>
      <filename>samples/animals/c++/dog.h</filename>
    </added>
    <added>
      <filename>samples/animals/c++/main.cc</filename>
    </added>
    <added>
      <filename>samples/animals/c++/mammal.h</filename>
    </added>
    <added>
      <filename>samples/animals/java/Animal.java</filename>
    </added>
    <added>
      <filename>samples/animals/java/Cat.java</filename>
    </added>
    <added>
      <filename>samples/animals/java/Dog.java</filename>
    </added>
    <added>
      <filename>samples/animals/java/Main.java</filename>
    </added>
    <added>
      <filename>samples/animals/java/Makefile</filename>
    </added>
    <added>
      <filename>samples/animals/java/Mammal.java</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -9,7 +9,6 @@ use Egypt::Model;
 
 our $QUIET = undef;
 
-__PACKAGE__-&gt;mk_accessors(qw(model));
 __PACKAGE__-&gt;mk_ro_accessors(qw(current_member));
 
 sub alias {
@@ -35,6 +34,14 @@ sub load {
   return $extractor;
 }
 
+sub model {
+  my $self = shift;
+  if (!exists($self-&gt;{model})) {
+    $self-&gt;{model} = new Egypt::Model;
+  }
+  return $self-&gt;{model};
+}
+
 sub current_module {
   my $self = shift;
 
@@ -44,6 +51,9 @@ sub current_module {
 
     # read variable declarations
     $self-&gt;_read_variable_declarations();
+
+    #declare
+    $self-&gt;model-&gt;declare_module($self-&gt;{current_module});
   }
 
   return $self-&gt;{current_module};</diff>
      <filename>Egypt/Extractor.pm</filename>
    </modified>
    <modified>
      <diff>@@ -9,10 +9,7 @@ use File::Basename;
 
 sub new {
   my $package = shift;
-  my @defaults = (
-    model =&gt; Egypt::Model-&gt;new, # temporary (?)
-  );
-  return bless { @defaults, @_ }, $package;
+  return bless { @_ }, $package;
 }
 
 sub feed {
@@ -31,21 +28,29 @@ sub feed {
     $self-&gt;{current_member} = $variable;
   }
 
+  # inheritance
+  if ($line =~ m/^\s{3}inherits from (.+)$/) {
+    $self-&gt;model-&gt;add_inheritance($self-&gt;current_module, $1);
+  }
+
   # function calls/uses
   if ($line =~ m/^\s{6}uses function (\S+) defined in (\S+)$/) {
     my $function = _qualified_name($2, $1);
     $self-&gt;model-&gt;add_call($self-&gt;current_member, $function, 'direct');
   }
+
   # variable references
   elsif ($line =~ m/^\s{6}uses variable (\S+) defined in (\S+)$/) {
     my $variable = _qualified_name($2, $1);
     $self-&gt;model-&gt;add_variable_use($self-&gt;current_member, $variable);
   }
 
+  # public members
   if ($line =~ m/^\s{6}protection public$/) {
     $self-&gt;model-&gt;add_protection($self-&gt;current_member, 'public');
   }
 
+  # method LOC
   if($line =~ m/^\s{6}(\d+) lines of code$/){
       $self-&gt;model-&gt;add_loc($self-&gt;current_member, $1);
   }</diff>
      <filename>Egypt/Extractor/Doxyparse.pm</filename>
    </modified>
    <modified>
      <diff>@@ -66,10 +66,7 @@ use File::Find;
 
 sub new {
   my $package = shift;
-  my @defaults = (
-    model =&gt; Egypt::Model-&gt;new, # temporary (?)
-  );
-  return bless { @defaults, @_ }, $package;
+  return bless { @_ }, $package;
 }
 
 sub feed {</diff>
      <filename>Egypt/Extractor/GCC.pm</filename>
    </modified>
    <modified>
      <diff>@@ -130,6 +130,18 @@ sub amz_size {
   return ($count &gt; 0) ? ($lines / $count) : 0;
 }
 
+sub dit {
+  my ($self, $module) = @_;
+  my @parents = $self-&gt;model-&gt;inheritance($module);
+  if (@parents) {
+    my @parent_dits = map { $self-&gt;dit($_) } @parents;
+    my @sorted = reverse(sort(@parent_dits));
+    return 1 + $sorted[0];
+  } else {
+    return 0;
+  }
+}
+
 sub report {
   my $self = shift;
   my $result = '';
@@ -144,7 +156,7 @@ sub report {
     loc =&gt; 0
   );
 
-  for my $module (keys(%{$self-&gt;model-&gt;modules})) {
+  for my $module ($self-&gt;model-&gt;module_names) {
     my $coupling = $self-&gt;coupling($module);
     my $number_of_functions = $self-&gt;number_of_functions($module);
     my $lcom1 = $self-&gt;lcom1($module);
@@ -153,6 +165,7 @@ sub report {
     my $public_functions = $self-&gt;public_functions($module);
     my $amz_size = amz_size($lines, $number_of_functions);
     my $public_variables = $self-&gt;public_variables($module);
+    my $dit = $self-&gt;dit($module);
 
     my %data = (
       _module =&gt; $module,
@@ -166,7 +179,8 @@ sub report {
       loc =&gt; $lines,
       max_mloc =&gt; $max_mloc,
       public_functions =&gt; $public_functions,
-      public_variables =&gt; $public_variables
+      public_variables =&gt; $public_variables,
+      dit =&gt; $dit,
     );
     $result .= Dump(\%data);
 </diff>
      <filename>Egypt/Metrics.pm</filename>
    </modified>
    <modified>
      <diff>@@ -9,7 +9,9 @@ sub new {
     demangle =&gt; {},
     calls =&gt; {},
     lines =&gt; {},
-    protection =&gt; {}
+    protection =&gt; {},
+    inheritance =&gt; {},
+    module_names =&gt; [],
   );
   return bless { @defaults }, __PACKAGE__;
 }
@@ -19,6 +21,30 @@ sub modules {
   return $self-&gt;{modules};
 }
 
+sub module_names {
+  my $self = shift;
+  return @{$self-&gt;{module_names}};
+}
+
+sub declare_module {
+  my ($self, $module) = @_;
+  if (! grep { $_ eq $module} @{$self-&gt;{module_names}}) {
+    push @{$self-&gt;{module_names}}, $module;
+  }
+}
+
+sub inheritance {
+  my ($self, $module) = @_;
+  my $list = $self-&gt;{inheritance}-&gt;{$module};
+  return $list ? @$list : ();
+}
+
+sub add_inheritance {
+  my ($self, $child, $parent) = @_;
+  $self-&gt;{inheritance}-&gt;{$child} = [] if !exists($self-&gt;{inheritance}-&gt;{$child});
+  push @{$self-&gt;{inheritance}-&gt;{$child}}, $parent;
+}
+
 sub members {
   my $self = shift;
   return $self-&gt;{members};</diff>
      <filename>Egypt/Model.pm</filename>
    </modified>
    <modified>
      <diff>@@ -22,6 +22,16 @@ sub new {
   return bless $self, $package;
 }
 
+sub _add_dependency {
+  my ($dependencies, $from, $to) = @_;
+  $dependencies-&gt;{$from} = { } if !exists($dependencies-&gt;{$from});
+  if (exists $dependencies-&gt;{$from}-&gt;{$to}) {
+    $dependencies-&gt;{$from}-&gt;{$to} += 1;
+  } else {
+    $dependencies-&gt;{$from}-&gt;{$to} = 1;
+  }
+}
+
 sub string {
   my $self = shift;
   my $result = &quot;digraph callgraph {\n&quot;;
@@ -38,14 +48,15 @@ sub string {
         my $calling_module = $self-&gt;_function_to_module($caller);
         my $called_module = $self-&gt;_function_to_module($callee);
         next unless (defined($calling_module) &amp;&amp; defined($called_module) &amp;&amp; ($calling_module ne $called_module));
-        $modules_dependencies-&gt;{$calling_module} = { } if !exists($modules_dependencies-&gt;{$calling_module});
-        if (exists $modules_dependencies-&gt;{$calling_module}-&gt;{$called_module}) {
-          $modules_dependencies-&gt;{$calling_module}-&gt;{$called_module} += 1;
-        } else {
-          $modules_dependencies-&gt;{$calling_module}-&gt;{$called_module} = 1;
-        }
+        _add_dependency($modules_dependencies, $calling_module, $called_module);
       }
     }
+    foreach my $subclass (keys(%{$self-&gt;model-&gt;{inheritance}})) {
+      foreach my $superclass ($self-&gt;model-&gt;inheritance($subclass)) {
+        _add_dependency($modules_dependencies, $subclass, $superclass);
+      }
+    }
+
     foreach my $calling_module (sort(keys %{$modules_dependencies})) {
       foreach my $called_module (sort(keys %{$modules_dependencies-&gt;{$calling_module}})) {
         my $strength = $modules_dependencies-&gt;{$calling_module}-&gt;{$called_module};</diff>
      <filename>Egypt/Output/DOT.pm</filename>
    </modified>
    <modified>
      <diff>@@ -15,7 +15,8 @@ sub list_metrics()
       public_methods =&gt; &quot;Number of public methods&quot;,
       amz_size =&gt; &quot;Average number of lines per method&quot;,
       max_mloc =&gt; &quot;Max number of method lines&quot;,
-      public_variables =&gt; &quot;Number of public variaveis&quot;
+      public_variables =&gt; &quot;Number of public variaveis&quot;,
+      dit =&gt; &quot;Depth of Inheritance Tree&quot;,
     );
 
     foreach my $key (sort keys %metrics){</diff>
      <filename>egypt-metrics</filename>
    </modified>
    <modified>
      <diff>@@ -49,3 +49,18 @@ Feature: multi-language support
     | c++      | 2                 | main        | HelloWorld         | 4               |
     | java     | 2                 | Main        | HelloWorld         | 4               |
 
+  Scenario Outline: inheritance data
+    Given I am in samples/animals/&lt;language&gt;
+    When I run &quot;egypt graph --modules .&quot;
+    Then egypt must report that &quot;Cat&quot; depends on &quot;Mammal&quot;
+    Then egypt must report that &quot;Dog&quot; depends on &quot;Mammal&quot;
+    Then egypt must report that &quot;Mammal&quot; depends on &quot;Animal&quot;
+    When I run &quot;egypt metrics .&quot;
+    And egypt must report that module Cat has dit = 2
+    And egypt must report that module Dog has dit = 2
+    And egypt must report that module Mammal has dit = 1
+    And egypt must report that module Animal has dit = 0
+  Examples:
+    | language |
+    | c++      |
+    | java     |</diff>
      <filename>features/language_support.feature</filename>
    </modified>
    <modified>
      <diff>@@ -16,10 +16,6 @@ sub constructor : Tests {
   isa_ok(new Egypt::Extractor, 'Egypt::Extractor');
 }
 
-sub has_a_model : Tests {
-  can_ok('Egypt::Extractor', 'model');
-}
-
 sub has_a_current_member : Tests {
   can_ok('Egypt::Extractor', 'current_member');
 }
@@ -28,7 +24,7 @@ sub has_a_current_member : Tests {
 # BEGIN test of indicating current module
 ##############################################################################
 sub current_module : Tests {
-  my $extractor = Egypt::Extractor-&gt;new;
+  my $extractor = new Egypt::Extractor;
   $extractor-&gt;current_module('module1.c');
   is($extractor-&gt;current_module, 'module1.c', 'must be able to set the current module');
   $extractor-&gt;current_module('module2.c');</diff>
      <filename>t/02_extractor.t</filename>
    </modified>
    <modified>
      <diff>@@ -15,6 +15,26 @@ sub empty_object : Tests {
   isa_ok($model-&gt;members, 'HASH', 'must have members');
 }
 
+sub declaring_modules : Tests {
+  my $model = new Egypt::Model;
+  $model-&gt;declare_module('Module1');
+  $model-&gt;declare_module('Module2');
+  my @modules = $model-&gt;module_names;
+  is($modules[0], 'Module1');
+  is($modules[1], 'Module2');
+}
+
+sub declaring_inheritance : Tests {
+  my $model = new Egypt::Model;
+  $model-&gt;add_inheritance('Child', 'Parent');
+  my @parents = $model-&gt;inheritance('Child');
+  is($parents[0], 'Parent', 'class with one superclass');
+
+  $model-&gt;add_inheritance('Child', 'AnotherParent');
+  @parents = $model-&gt;inheritance(&quot;Child&quot;);
+  is($parents[1], 'AnotherParent', 'class with two superclasses');
+}
+
 sub declaring_function : Tests {
   my $model = new Egypt::Model;
   $model-&gt;declare_function('mymodule', 'myfunction');</diff>
      <filename>t/03_model.t</filename>
    </modified>
    <modified>
      <diff>@@ -142,29 +142,52 @@ sub public_variables : Tests {
 }
 
 sub loc : Tests {
-  is($metrics-&gt;loc('mod1'), (0, 0), 'empty module has 0 LOC');
+  my @result = $metrics-&gt;loc('mod1');
+  is($result[0], 0, 'empty module has 0 LOC');
+  is($result[1], 0, 'empty module has max LOC 0');
 
   $model-&gt;declare_function('mod1', 'mod1::f1');
   $model-&gt;add_loc('mod1::f1', 10);
-  eq_array($metrics-&gt;loc('mod1'), [10, 10], 'one module, with 10 LOC');
+  @result = $metrics-&gt;loc('mod1');
+  is($result[0], 10, 'one module, with 10 LOC');
+  is($result[1], 10, 'one module, with 10 LOC, makes max LOC = 10');
 
-  $model-&gt;declare_function('mod1', 'mod1::f1');
-  $model-&gt;add_loc('mod1::f1', 20);
-  eq_array($metrics-&gt;loc('mod1'), [30, 20], 'other module, with 20 LOC');
+  $model-&gt;declare_function('mod1', 'mod1::f2');
+  $model-&gt;add_loc('mod1::f2', 20);
+  @result = $metrics-&gt;loc('mod1');
+  is($result[0], 30, 'adding another module with 20 LOC makes the total equal 30');
+  is($result[1], 20, 'adding another module with 20 LOC makes the max LOC equal 20');
 }
 
 sub amz_size_with_no_functions_at_all : Tests {
   is($metrics-&gt;amz_size(0, 0), 0);
 }
 
+sub dit : Tests {
+  $model-&gt;add_inheritance('Level1', 'Level2');
+  $model-&gt;add_inheritance('Level2', 'Level3');
+  is($metrics-&gt;dit('Level1'), 2, 'DIT = 2');
+  is($metrics-&gt;dit('Level2'), 1, 'DIT = 1');
+  is($metrics-&gt;dit('Level3'), 0, 'DIT = 0');
+}
+
+sub dit_with_multiple_inheritance : Tests {
+  $model-&gt;add_inheritance('Level1', 'Level2A');
+  $model-&gt;add_inheritance('Level1', 'Level2B');
+  $model-&gt;add_inheritance('Level2B', 'Level3B');
+  is($metrics-&gt;dit('Level1'), 2, 'with multiple inheritance take the larger DIT between the parents');
+}
+
 sub report : Tests {
   # first module
+  $model-&gt;declare_module('mod1');
   $model-&gt;declare_function('mod1' , 'f1a');
   $model-&gt;declare_function('mod1' , 'f1b');
   $model-&gt;declare_variable('mod1' , 'v1');
   $model-&gt;add_variable_use($_, 'v1') for qw(f1a f1b);
 
   # second module
+  $model-&gt;declare_module('mod2');
   $model-&gt;declare_function('mod2', 'f2');
   $model-&gt;add_call('f2', 'f1a');
   $model-&gt;add_call('f2', 'f1b');
@@ -174,34 +197,6 @@ sub report : Tests {
   ok($output =~ /number_of_modules: 2/, 'reporting number of modules in YAML stream');
   ok($output =~ /_module: mod1/, 'reporting module 1');
   ok($output =~ /_module: mod2/, 'reporting module 2');
-
-  #s(
-#'---
-#average_coupling: 0.5
-#average_coupling_times_lcom1: 0
-#average_coupling_times_lcom4: 0.5
-#average_lcom1: 0
-#average_lcom4: 1
-#number_of_functions: 3
-#number_of_modules: 2
-#---
-#_module: mod1
-#coupling: 0
-#coupling_times_lcom1: 0
-#coupling_times_lcom4: 0
-#interface_size: 2
-#lcom1: 0
-#lcom4: 1
-#---
-#_module: mod2
-#coupling: 1
-#coupling_times_lcom1: 0
-#coupling_times_lcom4: 1
-#interface_size: 1
-#lcom1: 0
-#lcom4: 1
-#',
-    #'must report metrics as a YAML stream');
 }
 
 sub discard_external_symbols_for_coupling : Tests {</diff>
      <filename>t/04_metrics.t</filename>
    </modified>
    <modified>
      <diff>@@ -29,6 +29,14 @@ sub current_module : Tests {
   is($extractor-&gt;current_module, 'module2.c', 'must be able to change the current module');
 }
 
+sub inheritance : Tests {
+  my $extractor = Egypt::Extractor-&gt;load('Doxyparse');
+  $extractor-&gt;current_module('Child');
+  $extractor-&gt;feed('   inherits from Parent');
+  my @result = $extractor-&gt;model-&gt;inheritance('Child');
+  is($result[0], 'Parent', 'extractor detects inheritance');
+}
+
 sub detect_function_declaration : Tests {
   my $extractor = Egypt::Extractor-&gt;load('Doxyparse', current_module =&gt; 'module1.c');
   $extractor-&gt;feed('   function myfunction in line 5');</diff>
      <filename>t/06_extractor_doxyparse.t</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>1ebd9453591046adbf1f969acf65f70e05938846</id>
    </parent>
  </parents>
  <author>
    <name>Antonio Terceiro</name>
    <email>terceiro@softwarelivre.org</email>
  </author>
  <url>http://github.com/terceiro/egypt/commit/fb4d6eb39bd9f8e4e44f52b4c0aed9160ef5ff07</url>
  <id>fb4d6eb39bd9f8e4e44f52b4c0aed9160ef5ff07</id>
  <committed-date>2009-10-12T18:04:42-07:00</committed-date>
  <authored-date>2009-10-12T18:04:42-07:00</authored-date>
  <message>Implementing inheritance support

Added:

  * sample Animals program in C++ and Java
  * new metric DIT
  * noticing dependency by inheritance

Changed:

  * now there is an explicit list of modules in Egypt::Model. This way
    empty modules will be listed in metrics report.
  * refactored the module dependency calculation by extracting a method to
    populate the dependencies hashes.</message>
  <tree>ac881702f5e87ac579758f7ed6b9913c16d9b49a</tree>
  <committer>
    <name>Antonio Terceiro</name>
    <email>terceiro@softwarelivre.org</email>
  </committer>
</commit>
