Просмотр исходного кода

improved API for advanced counters

avkonst 11 лет назад
Родитель
Сommit
055e98a657

+ 34 - 30
mainline/doc/home.html

@@ -1216,7 +1216,8 @@ class Plugin(mpp.api.Plugin,
             r'''(const\s+([_a-zA-Z][_a-zA-Z0-9]*\s+)+[=]\s*)?[-+]?[0-9]+''')
         self.declare_metric(self.is_active_numbers,
                             self.Field('numbers', int),
-                            pattern_to_search, # and use it here
+                            # give a pair of pattern + custom counter logic class
+                            (pattern_to_search, self.NumbersCounter),
                             marker_type_mask=mpp.api.Marker.T.CODE,
                             region_type_mask=mpp.api.Region.T.ANY)
         
@@ -1228,10 +1229,11 @@ class Plugin(mpp.api.Plugin,
     # implement custom counter behavior:
     # increments counter by 1 only if single number spotted,
     # but not declaration of a constant
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if match.group(0).startswith('const'):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if match.group(0).startswith('const'):
+                return 0
+            return 1
 </pre>
              <li>Initialy counter is initialized by zero, but it is possible to 
              	change it as well by implementing a function with name '_&lt;metric_name&gt;_count_initialize'.
@@ -1275,11 +1277,11 @@ class Plugin(mpp.api.Plugin,
             r'''[0-9]+''')
         self.declare_metric(self.is_active_numbers,
                             self.Field('numbers', int),
-                            # dictionary of patterns instead of a single one
+                            # dictionary of pairs instead of a single pair
                             {
-                             'std.code.java': pattern_to_search_java,
-                             'std.code.cpp': pattern_to_search_cpp_cs,
-                             'std.code.cs': pattern_to_search_cpp_cs,
+                             'std.code.java': (pattern_to_search_java, self.NumbersCounter),
+                             'std.code.cpp': (pattern_to_search_cpp_cs, self.NumbersCounter),
+                             'std.code.cs': (pattern_to_search_cpp_cs, self.NumbersCounter),
                              '*': pattern_to_search
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
@@ -1290,10 +1292,11 @@ class Plugin(mpp.api.Plugin,
         if self.is_active() == True:
             self.subscribe_by_parents_interface(mpp.api.ICode)
 
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if match.group(0).startswith('const'):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if match.group(0).startswith('const'):
+                return 0
+            return 1
 </pre>
              <li>Keys in the dictionary of patterns are names of parent plugins (references to code parsers).
              	The key '*' refers to any parser.</li>
@@ -1337,9 +1340,9 @@ class Plugin(mpp.api.Plugin,
                                 # store only non-zero results
                                 non_zero=True),
                             {
-                             'std.code.java': pattern_to_search_java,
-                             'std.code.cpp': pattern_to_search_cpp_cs,
-                             'std.code.cs': pattern_to_search_cpp_cs,
+                             'std.code.java': (pattern_to_search_java, self.NumbersCounter),
+                             'std.code.cpp': (pattern_to_search_cpp_cs, self.NumbersCounter),
+                             'std.code.cs': (pattern_to_search_cpp_cs, self.NumbersCounter),
                              '*': pattern_to_search
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
@@ -1350,10 +1353,11 @@ class Plugin(mpp.api.Plugin,
         if self.is_active() == True:
             self.subscribe_by_parents_interface(mpp.api.ICode)
 
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if match.group(0).startswith('const'):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if match.group(0).startswith('const'):
+                return 0
+            return 1
 </pre>
             <li>Now run Metrix++ to collect and view the results.</li>
           <pre>&gt; python "/path/to/metrix++.py" collect --myext.magic.numbers</pre>
@@ -1399,9 +1403,9 @@ class Plugin(mpp.api.Plugin,
                             self.Field('numbers', int,
                                 non_zero=True),
                             {
-                             'std.code.java': pattern_to_search_java,
-                             'std.code.cpp': pattern_to_search_cpp_cs,
-                             'std.code.cs': pattern_to_search_cpp_cs,
+                             'std.code.java': (pattern_to_search_java, self.NumbersCounter),
+                             'std.code.cpp': (pattern_to_search_cpp_cs, self.NumbersCounter),
+                             'std.code.cs': (pattern_to_search_cpp_cs, self.NumbersCounter),
                              '*': pattern_to_search
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
@@ -1415,13 +1419,13 @@ class Plugin(mpp.api.Plugin,
         if self.is_active() == True:
             self.subscribe_by_parents_interface(mpp.api.ICode)
 
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if (match.group(0).startswith('const') or
-            # use new option to exclude 0 and 1 numbers
-            (self.is_active_numbers_simplier == True and
-             match.group(0) in ['0', '1', '-1', '+1'])):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if (match.group(0).startswith('const') or
+                (self.plugin.is_active_numbers_simplier == True and
+                 match.group(0) in ['0', '1', '-1', '+1'])):
+                return 0
+            return 1
 </pre>
             <li>Now run Metrix++ to collect and view the results.</li>
           <pre>&gt; python "/path/to/metrix++.py" collect --myext.magic.numbers</pre>

+ 20 - 16
mainline/ext/std/code/complexity.py

@@ -57,9 +57,9 @@ class Plugin(mpp.api.Plugin, mpp.api.MetricPluginMixin, mpp.api.Child, mpp.api.I
         self.declare_metric(self.is_active_maxindent,
                             self.Field('maxindent', int),
                             {
-                                'std.code.cpp': self.pattern_indent,
-                                'std.code.cs': self.pattern_indent,
-                                'std.code.java': self.pattern_indent,
+                                'std.code.cpp': (self.pattern_indent, self.MaxIndentCounter),
+                                'std.code.cs': (self.pattern_indent, self.MaxIndentCounter),
+                                'std.code.java': (self.pattern_indent, self.MaxIndentCounter),
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
                             region_type_mask=mpp.api.Region.T.FUNCTION)
@@ -73,16 +73,20 @@ class Plugin(mpp.api.Plugin, mpp.api.MetricPluginMixin, mpp.api.Child, mpp.api.I
                 'std.code.java'
             ])
 
-    def _maxindent_count_initialize(self, alias, data, region):
-        return (0, {'cur_level': 0})
-    
-    def _maxindent_count(self, alias, data, region, marker, match, count, counter_data):
-        if match.group(0) == '{':
-            counter_data['cur_level'] += 1
-            if counter_data['cur_level'] > count:
-                count = counter_data['cur_level']
-        elif match.group(0) == '}':
-            counter_data['cur_level'] -= 1
-        else:
-            assert False
-        return count
+    class MaxIndentCounter(mpp.api.MetricPluginMixin.IterAssignCounter):
+        
+        def __init__(self, plugin, alias, data, region):
+            super(Plugin.MaxIndentCounter, self).__init__(plugin, alias, data, region)
+            self.current_level = 0
+            
+        def assign(self, match):
+            result = self.result
+            if match.group(0) == '{':
+                self.current_level += 1
+                if self.current_level > self.result:
+                    result = self.current_level
+            elif match.group(0) == '}':
+                self.current_level -= 1
+            else:
+                assert False
+            return result

+ 10 - 9
mainline/ext/std/code/magic.py

@@ -47,9 +47,9 @@ class Plugin(mpp.api.Plugin,
                             self.Field('numbers', int,
                                 non_zero=True),
                             {
-                             'std.code.java': pattern_to_search_java,
-                             'std.code.cpp': pattern_to_search_cpp_cs,
-                             'std.code.cs': pattern_to_search_cpp_cs,
+                             'std.code.java': (pattern_to_search_java, self.NumbersCounter),
+                             'std.code.cpp': (pattern_to_search_cpp_cs, self.NumbersCounter),
+                             'std.code.cs': (pattern_to_search_cpp_cs, self.NumbersCounter),
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
                             region_type_mask=mpp.api.Region.T.ANY)
@@ -60,9 +60,10 @@ class Plugin(mpp.api.Plugin,
         if self.is_active() == True:
             self.subscribe_by_parents_interface(mpp.api.ICode)
 
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if (match.group(0).startswith('const') or
-            (self.is_active_numbers_simplier == True and
-             match.group(0) in ['0', '1', '-1', '+1'])):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if (match.group(0).startswith('const') or
+                (self.plugin.is_active_numbers_simplier == True and
+                 match.group(0) in ['0', '1', '-1', '+1'])):
+                return 0
+            return 1

+ 3 - 2
mainline/ext/std/tools/view.py

@@ -18,6 +18,7 @@
 #
 
 import logging
+import sys
 
 import mpp.api
 import mpp.utils
@@ -433,8 +434,8 @@ def compress_dist(data, columns):
             remaining_count = metric_data['count']
             next_consume = None
             next_bar = None
-            max_count = -(0xFFFFFFFF)
-            min_count = 0xFFFFFFFF
+            max_count = -sys.maxint - 1
+            min_count = sys.maxint
             sum_ratio = 0
             for (ind, bar) in enumerate(distr):
                 if next_bar == None:

+ 64 - 35
mainline/mpp/api.py

@@ -18,6 +18,7 @@
 #
 
 import os.path
+import sys
 
 import mpp.internal.dbwrap
 import mpp.internal.api_impl
@@ -981,8 +982,51 @@ class MetricPluginMixin(object):
 
     class AliasError(Exception):
         def __init__(self, alias):
-            Exception.__init__(self, "Unknown alias: " + str(alias))
-    
+            Exception.__init__(self, "Unknown pattern alias: " + str(alias))
+            
+    class PlainCounter(object):
+        
+        def __init__(self, plugin, alias, data, region):
+            self.plugin = plugin
+            self.alias = alias
+            self.data = data
+            self.region = region
+            self.result = 0
+            
+        def count(self, marker, pattern_to_search):
+            self.result += len(pattern_to_search.findall(self.data.get_content(),
+                                                       marker.get_offset_begin(),
+                                                       marker.get_offset_end()))
+        
+        def get_result(self):
+            return self.result
+
+    class IterIncrementCounter(PlainCounter):
+        
+        def count(self, marker, pattern_to_search):
+            self.marker = marker
+            self.pattern_to_search = pattern_to_search
+            for match in pattern_to_search.finditer(self.data.get_content(),
+                                                    marker.get_offset_begin(),
+                                                    marker.get_offset_end()):
+                self.result += self.increment(match)
+        
+        def increment(self, match):
+            return 1
+
+    class IterAssignCounter(PlainCounter):
+        
+        def count(self, marker, pattern_to_search):
+            self.marker = marker
+            self.pattern_to_search = pattern_to_search
+            for match in pattern_to_search.finditer(self.data.get_content(),
+                                                    marker.get_offset_begin(),
+                                                    marker.get_offset_end()):
+                self.result = self.assign(match)
+        
+        def assign(self, match):
+            return self.result
+
     def declare_metric(self, is_active, field,
                        pattern_to_search_or_map_of_patterns,
                        marker_type_mask=Marker.T.ANY,
@@ -996,6 +1040,12 @@ class MetricPluginMixin(object):
             map_of_patterns = pattern_to_search_or_map_of_patterns
         else:
             map_of_patterns = {'*': pattern_to_search_or_map_of_patterns}
+        # client may suply with pattern or pair of pattern + counter class
+        for key in map_of_patterns.keys():
+            if isinstance(map_of_patterns[key], tuple) == False:
+                # if it is not a pair, create a pair using default counter class
+                map_of_patterns[key] = (map_of_patterns[key],
+                                        MetricPluginMixin.PlainCounter)
 
         if is_active == True:
             self._fields[field.name] = (field,
@@ -1036,48 +1086,27 @@ class MetricPluginMixin(object):
             namespace = self.get_name()
             
         field_data = self._fields[metric_name]
-        text = data.get_content()
-        
         if alias not in field_data[4].keys():
             if '*' not in field_data[4].keys():
                 raise self.AliasError(alias)
             else:
                 alias = '*'
-        pattern_to_search = field_data[4][alias]
+        (pattern_to_search, counter_class) = field_data[4][alias]
         
-        if hasattr(self, '_' + metric_name + '_count'):
-            counter_callback = self.__getattribute__('_' + metric_name + '_count')
-            for region in data.iterate_regions(filter_group=field_data[5]):
-                counter_data = {}
-                count = 0
-                if hasattr(self, '_' + metric_name + '_count_initialize'):
-                    (count, counter_data) = self.__getattribute__('_' + metric_name + '_count_initialize')(alias, data, region)
-                for marker in data.iterate_markers(
-                                filter_group = field_data[1],
-                                region_id = region.get_id(),
-                                exclude_children = field_data[2],
-                                merge=field_data[3]):
-                    begin = marker.get_offset_begin()
-                    end = marker.get_offset_end()
-                    for match in pattern_to_search.finditer(text, begin, end):
-                        count = counter_callback(alias, data, region, marker, match, count, counter_data)
-                if count != 0 or field_data[0].non_zero == False:
-                    region.set_data(namespace, metric_name, count)
-        else:
-            for region in data.iterate_regions(filter_group=field_data[5]):
-                count = 0
-                for marker in data.iterate_markers(
-                                filter_group = field_data[1],
-                                region_id = region.get_id(),
-                                exclude_children = field_data[2],
-                                merge=field_data[3]):
-                    count += len(pattern_to_search.findall(text, marker.get_offset_begin(), marker.get_offset_end()))
-                if count != 0 or field_data[0].non_zero == False:
-                    region.set_data(namespace, metric_name, count)
+        for region in data.iterate_regions(filter_group=field_data[5]):
+            counter = counter_class(self, alias, data, region)
+            for marker in data.iterate_markers(
+                            filter_group = field_data[1],
+                            region_id = region.get_id(),
+                            exclude_children = field_data[2],
+                            merge=field_data[3]):
+                counter.count(marker, pattern_to_search)
+            count = counter.get_result()
+            if count != 0 or field_data[0].non_zero == False:
+                region.set_data(namespace, metric_name, count)
 
 class InterfaceNotImplemented(Exception):
     def __init__(self, obj):
-        import sys
         Exception.__init__(self, "Method '"
                             + sys._getframe(1).f_code.co_name
                             + "' has not been implemented for "

+ 7 - 5
mainline/tests/system/test_api_tutorial/ext/step5/myext/magic.py

@@ -39,7 +39,8 @@ class Plugin(mpp.api.Plugin,
             r'''(const\s+([_a-zA-Z][_a-zA-Z0-9]*\s+)+[=]\s*)?[-+]?[0-9]+''')
         self.declare_metric(self.is_active_numbers,
                             self.Field('numbers', int),
-                            pattern_to_search, # and use it here
+                            # give a pair of pattern + custom counter logic class
+                            (pattern_to_search, self.NumbersCounter),
                             marker_type_mask=mpp.api.Marker.T.CODE,
                             region_type_mask=mpp.api.Region.T.ANY)
         
@@ -51,7 +52,8 @@ class Plugin(mpp.api.Plugin,
     # implement custom counter behavior:
     # increments counter by 1 only if single number spotted,
     # but not declaration of a constant
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if match.group(0).startswith('const'):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if match.group(0).startswith('const'):
+                return 0
+            return 1

+ 9 - 8
mainline/tests/system/test_api_tutorial/ext/step6/myext/magic.py

@@ -45,11 +45,11 @@ class Plugin(mpp.api.Plugin,
             r'''[0-9]+''')
         self.declare_metric(self.is_active_numbers,
                             self.Field('numbers', int),
-                            # dictionary of patterns instead of a single one
+                            # dictionary of pairs instead of a single pair
                             {
-                             'std.code.java': pattern_to_search_java,
-                             'std.code.cpp': pattern_to_search_cpp_cs,
-                             'std.code.cs': pattern_to_search_cpp_cs,
+                             'std.code.java': (pattern_to_search_java, self.NumbersCounter),
+                             'std.code.cpp': (pattern_to_search_cpp_cs, self.NumbersCounter),
+                             'std.code.cs': (pattern_to_search_cpp_cs, self.NumbersCounter),
                              '*': pattern_to_search
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
@@ -60,7 +60,8 @@ class Plugin(mpp.api.Plugin,
         if self.is_active() == True:
             self.subscribe_by_parents_interface(mpp.api.ICode)
 
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if match.group(0).startswith('const'):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if match.group(0).startswith('const'):
+                return 0
+            return 1

+ 8 - 7
mainline/tests/system/test_api_tutorial/ext/step7/myext/magic.py

@@ -46,9 +46,9 @@ class Plugin(mpp.api.Plugin,
                                 # store only non-zero results
                                 non_zero=True),
                             {
-                             'std.code.java': pattern_to_search_java,
-                             'std.code.cpp': pattern_to_search_cpp_cs,
-                             'std.code.cs': pattern_to_search_cpp_cs,
+                             'std.code.java': (pattern_to_search_java, self.NumbersCounter),
+                             'std.code.cpp': (pattern_to_search_cpp_cs, self.NumbersCounter),
+                             'std.code.cs': (pattern_to_search_cpp_cs, self.NumbersCounter),
                              '*': pattern_to_search
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
@@ -59,7 +59,8 @@ class Plugin(mpp.api.Plugin,
         if self.is_active() == True:
             self.subscribe_by_parents_interface(mpp.api.ICode)
 
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if match.group(0).startswith('const'):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if match.group(0).startswith('const'):
+                return 0
+            return 1

+ 10 - 10
mainline/tests/system/test_api_tutorial/ext/step8/myext/magic.py

@@ -50,9 +50,9 @@ class Plugin(mpp.api.Plugin,
                             self.Field('numbers', int,
                                 non_zero=True),
                             {
-                             'std.code.java': pattern_to_search_java,
-                             'std.code.cpp': pattern_to_search_cpp_cs,
-                             'std.code.cs': pattern_to_search_cpp_cs,
+                             'std.code.java': (pattern_to_search_java, self.NumbersCounter),
+                             'std.code.cpp': (pattern_to_search_cpp_cs, self.NumbersCounter),
+                             'std.code.cs': (pattern_to_search_cpp_cs, self.NumbersCounter),
                              '*': pattern_to_search
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
@@ -66,10 +66,10 @@ class Plugin(mpp.api.Plugin,
         if self.is_active() == True:
             self.subscribe_by_parents_interface(mpp.api.ICode)
 
-    def _numbers_count(self, alias, data, region, marker, match, count, counter_data):
-        if (match.group(0).startswith('const') or
-            # use new option to exclude 0 and 1 numbers
-            (self.is_active_numbers_simplier == True and
-             match.group(0) in ['0', '1', '-1', '+1'])):
-            return count
-        return count + 1
+    class NumbersCounter(mpp.api.MetricPluginMixin.IterIncrementCounter):
+        def increment(self, match):
+            if (match.group(0).startswith('const') or
+                (self.plugin.is_active_numbers_simplier == True and
+                 match.group(0) in ['0', '1', '-1', '+1'])):
+                return 0
+            return 1