florath/rmtoo

View on GitHub
rmtoo/lib/analytics/DescWords.py

Summary

Maintainability
A
0 mins
Test Coverage
# -*- coding: utf-8 -*-
'''
 rmtoo
   Free and Open Source Requirements Management Tool

  The Description is the critical part of the requirement. This
  module checks for some good and bad words and tries a heuristic to
  get an idea about bad requirement descriptions.

 (c) 2010-2012,2017 by flonatel GmbH & Co. KG

 For licensing details see COPYING
'''
from __future__ import unicode_literals

import re

from rmtoo.lib.Markup import Markup
from rmtoo.lib.analytics.Result import Result
from rmtoo.lib.analytics.Base import Base
from rmtoo.lib.logging import tracer


class DescWords(Base):
    """This is the assessment of each word (better regular expression).
    If the regular expression matches, the value is added.
    If the resulting number is lower than a given limit, an error is
    assumed.
    The numbers are provided on a level between [-100, 100] where
    -100 is a very very bad word and 100 is a very very good.
    Do not add the single word 'not': only do this in pairs,
    e.g. 'must not'.
    """
    words_en_GB = [
        [re.compile(r"\. "), -15,
         "Additional fullstop (not only at the end of the desctiption)"],
        [re.compile(" about "), -15, "Usage of the word 'about'"],
        [re.compile(" and "), -10, "Usage of the word 'and'"],
        [re.compile(" approximately "), -100,
         "Usage of the word 'approximately'"],
        [re.compile(r" etc\.? "), -40, "Usage of the word 'etc'"],
        [re.compile(r" e\.g\. "), -40, "Usage of the word 'e.g.'"],
        [re.compile(" has to "), 20, "Usage of the word 'has to'"],
        [re.compile(" have to "), 20, "Usage of the word 'have to'"],
        [re.compile(r" i\.e\. "), -40, "Usage of the word 'i.e.'"],
        [re.compile(" many "), -20, "Usage of the word 'many'"],
        [re.compile(" may "), 10, "Usage of the word 'may'"],
        [re.compile(" maybe "), -50, "Usage of the word 'maybe'"],
        [re.compile(" might "), 10, "Usage of the word 'might'"],
        [re.compile(" must "), 25, "Usage of the word 'must'"],
        [re.compile(" or "), -15, "Usage of the word 'or'"],
        [re.compile(" perhaps "), -100, "Usage of the word 'perhaps'"],
        [re.compile(" should "), 15, "Usage of the word 'should'"],
        [re.compile(" shall "), 15, "Usage of the word 'shall'"],
        [re.compile(" some "), -25, "Usage of the word 'some'"],
        [re.compile(" vaguely "), -25, "Usage of the word 'vaguely'"],
    ]

    words_de_DE = [
        [re.compile(r"\. "), -15,
         "Additional fullstop (not only at the end of the desctiption)"],
        [re.compile(r" ca\. "), -75, "Usage of the word 'ca.'"],
        [re.compile(" möglicherweise "), -100,
         "Usage of the word 'möglicherweise'"],
        [re.compile(" muss "), 25, "Usage of the word 'muss'"],
        [re.compile(" oder "), -15, "Usage of the word 'oder'"],
        [re.compile(" und "), -10, "Usage of the word 'und'"],
        [re.compile(" usw."), -40, "Usage of the word 'usw'"],
        [re.compile(" vielleicht "), -25, "Usage of the word 'vielleicht'"],
        [re.compile(r" z\.B\. "), -40, "Usage of the word 'z.B.'"],
    ]

    words = {"en_GB": words_en_GB,
             "de_DE": words_de_DE}

    def __init__(self, config):
        '''Sets up the DescWord object for use.'''
        Base.__init__(self)
        self.lwords = DescWords.get_lang(config)
        self.markup = Markup("txt")

    @staticmethod
    def get_lang(config):
        """Get the language from the config.

        If not present, return en_GB as default.
        """
        def_lang = config.get_value_default(
            'requirements.input.default_language', 'en_GB')

        if def_lang in DescWords.words:
            return DescWords.words[def_lang]
        tracer.warning("Language [%s] not supported, using en_GB", def_lang)
        return DescWords.words["en_GB"]

    def analyse(self, lname, text):
        """Analyse the text.

        Must be at least some positive things to get this
        positive. (An empty description is a bad one.)
        """
        level = -10
        log = []
        for wre, wlvl, wdsc in self.lwords:
            plain_txt = self.markup.replace(text).strip()
            fal = len(wre.findall(plain_txt))
            if fal > 0:
                level += fal * wlvl
                log.append("%+4d:%d*%d: %s" % (fal * wlvl, fal, wlvl, wdsc))
                # Note the result of this test in the requirement itself.
        return Result('DescWords', lname, level, log)

    def topic_continuum_set_sort(self, list_to_sort):
        '''Can only handle from the last version.'''
        return [list(list_to_sort)[-1]]

    def topic_continuum_sort(self, vcs_commit_ids, topic_sets):
        '''Because graph2 can only one topic continuum,
           the latest (newest) is used.'''
        return [topic_sets[vcs_commit_ids[-1].get_commit()]]

    def requirement_set_sort(self, list_to_sort):
        '''Sort by id.'''
        return sorted(list_to_sort, key=lambda r: r.get_id())

    def requirement(self, requirement):
        '''Checks all the requirements.
           If the result is positive, it is good.'''
        result = self.analyse(
            requirement.get_id(),
            requirement.get_value("Description").get_content())
        if result.get_value() < 0:
            self.set_failed()
        self.add_result(result)