-redef class Model
-
- # List of modules in std lib
- # FIXME this is quite ugly, find a dynamic way...
- fun std_modules: Set[String] do
- if self.std_modules_cache == null then
- self.std_modules_cache = new HashSet[String]
- self.std_modules_cache.add("collection")
- self.std_modules_cache.add("abstract_collection")
- self.std_modules_cache.add("array")
- self.std_modules_cache.add("hash_collection")
- self.std_modules_cache.add("list")
- self.std_modules_cache.add("range")
- self.std_modules_cache.add("sorter")
- self.std_modules_cache.add("environ")
- self.std_modules_cache.add("exec")
- self.std_modules_cache.add("file")
- self.std_modules_cache.add("gc")
- self.std_modules_cache.add("hash")
- self.std_modules_cache.add("kernel")
- self.std_modules_cache.add("math")
- self.std_modules_cache.add("standard")
- self.std_modules_cache.add("stream")
- self.std_modules_cache.add("string")
- self.std_modules_cache.add("string_search")
- self.std_modules_cache.add("time")
+# A Metric is used to collect data about things
+#
+# The concept is reified here for a better organization and documentation
+interface Metric
+
+ # Type of elements measured by this metric.
+ type ELM: Object
+
+ # Type of values used to measure elements.
+ type VAL: Object
+
+ # Type of data representation used to associate elements and values.
+ type RES: Map[ELM, VAL]
+
+ # The name of this metric (generally an acronym about the metric).
+ fun name: String is abstract
+
+ # A long and understandable description about what is measured by this metric.
+ fun desc: String is abstract
+
+ # Clear all results for this metric
+ fun clear is abstract
+
+ # Values for each element
+ fun values: RES is abstract
+
+ # Collect metric values on elements
+ fun collect(elements: Collection[ELM]) is abstract
+
+ # The value calculated for the element
+ fun [](element: ELM): VAL do return values[element]
+
+ # Does the element have a value for this metric?
+ fun has_element(element: ELM): Bool do return values.has_key(element)
+
+ # The values average
+ fun avg: Float is abstract
+
+ # Pretty print the metric results in console
+ fun to_console(indent: Int, colors: Bool) do
+ if values.is_empty then
+ if colors then
+ print "{"\t" * indent}{name}: {desc} -- nothing".green
+ else
+ print "{"\t" * indent}{name}: {desc} -- nothing"
+ end
+ return
+ end
+
+ var max = self.max
+ var min = self.min
+ if colors then
+ print "{"\t" * indent}{name}: {desc}".green
+ print "{"\t" * indent} avg: {avg}".light_gray
+ print "{"\t" * indent} max: {max} ({self[max]})".light_gray
+ print "{"\t" * indent} min: {min} ({self[min]})".light_gray
+ print "{"\t" * indent} std: {std_dev}".light_gray
+ else
+ print "{"\t" * indent}{name}: {desc}"
+ print "{"\t" * indent} avg: {avg}"
+ print "{"\t" * indent} max: {max} ({self[max]})"
+ print "{"\t" * indent} min: {min} ({self[min]})"
+ print "{"\t" * indent} std: {std_dev}"
+ end
+ end
+
+ # The sum of all the values.
+ fun sum: VAL is abstract
+
+ # The values standard derivation
+ fun std_dev: Float is abstract
+
+ # The element with the highest value
+ fun max: ELM is abstract
+
+ # The element with the lowest value
+ fun min: ELM is abstract
+
+ # The value threshold above what elements are considered as 'interesting'
+ fun threshold: Float do return avg + std_dev
+
+ # The set of element above the threshold
+ fun above_threshold: Set[ELM] is abstract
+
+ # Sort the metric keys by values
+ fun sort: Array[ELM] do
+ return values.keys_sorted_by_values(default_reverse_comparator)
+ end
+end
+
+# A Metric that collects integer data
+#
+# Used to count things
+class IntMetric
+ super Metric
+
+ redef type VAL: Int is fixed
+ redef type RES: Counter[ELM]
+
+ # `IntMetric` uses a Counter to store values in intern.
+ protected var values_cache = new Counter[ELM]
+
+ redef fun values do return values_cache
+
+ redef fun clear do values_cache.clear
+
+ redef fun sum do return values_cache.sum
+
+ redef fun max do
+ assert not values_cache.is_empty
+ return values_cache.max.as(not null)
+ end
+
+ redef fun min do
+ assert not values_cache.is_empty
+ return values_cache.min.as(not null)
+ end
+
+ # Values average
+ redef fun avg do return values_cache.avg
+
+ redef fun std_dev do return values_cache.std_dev
+
+ redef fun above_threshold do
+ var above = new HashSet[ELM]
+ var threshold = threshold
+ for element, value in values do
+ if value.to_f > threshold then above.add(element)
+ end
+ return above
+ end
+
+ redef fun to_console(indent, colors) do
+ super
+ if colors then
+ print "{"\t" * indent} sum: {sum}".light_gray
+ else
+ print "{"\t" * indent} sum: {sum}"