写土熊指南

欢迎。本文档介绍了如何为Coala写一只熊的信息。它假设您知道如何使用Coala。如果没有,请阅读我们的 main tutorial

本教程的示例源代码位于我们的Coala-Tutorial库中,请使用以下命令克隆它:

git clone https://github.com/coala/coala-tutorial

这里给出的所有路径和命令都是从Coala-Tutorial存储库的根目录执行的。

备注

如果要包装已有的工具,请参阅 this tutorial instead .

熊是什么?

熊是用来对源代码进行一些分析的。源代码将由Coala提供,这样熊就不必关心它来自哪里或去了哪里。

熊有两种:

  • LocalBears,它只对每个文件本身执行分析

  • GlobalBears,它们是项目范围的,就像GitCommittee Bear

熊可以通过两种方式与用户通信:

  • 通过日志消息

  • VIA结果

日志消息将根据用户设置进行记录,通常在出现问题时使用。但是,您可以使用DEBUG来提供与开发相关的调试信息,因为默认情况下它不会显示给用户。如果使用错误/失败消息,则预计BEAR不会继续分析。

一只你好的世界熊

以下是为每个文件发送调试消息的简单BEAR提供的代码:

import logging

from coalib.bears.LocalBear import LocalBear

class HelloWorldBear(LocalBear):
    def run(self,
            filename,
            file):
        logging.debug("Hello World! Checking file {}.".format(filename))

这只熊存放在 ./bears/HelloWorldBear.py

In order to let coala execute this bear you need to let coala know where to find it. We can do that with the -d (--bear-dirs) argument:

coala -f src/*.c -d bears -b HelloWorldBear -L DEBUG --flush-cache

备注

给定的BEAR目录中不能有任何全局表达式。任何可以解释为全局表达式一部分的字符都将被转义。请使用逗号分隔值给出几个这样的目录。不要忘记刷新缓存(通过添加参数 --flush-cache 在运行Coala时),如果您对先前分析过的文件运行新的Bear(由Coala分析)。

现在,您应该在命令行上看到类似以下内容的输出:

[WARNING][15:07:39] Default coafile '.coafile' not found!
Here's what you can do:
* add `--save` to generate a config file with your current options
* add `-I` to suppress any use of config files
[DEBUG][15:07:39] Platform Linux -- Python 3.5.2, coalib
0.12.0.dev20170626132008
[DEBUG][15:07:39] The file cache was successfully flushed.
[DEBUG][15:07:39] Files that will be checked:
/home/LordVoldemort/programs/coa_dir/coala-tutorial/src/main.c
[DEBUG][15:07:40] coala is run only on changed files, bears' log
messages from previous runs may not appear. You may use the
`--flush-cache` flag to see them.
[DEBUG][15:07:40] Running bear HelloWorldBear...
[DEBUG][15:07:40] Hello World! Checking file /home/LordVoldemort/
programs/coa_dir/coala-tutorial/src/main.c .

Notice that the last ``[DEBUG]`` message is what was coded in
``HelloWorldBear.py``. All the other messages are inherited from the
``LocalBear`` class or run by the code responsible for executing the
bear.

备注

第一 WARNING 消息是因为我们的目录不包含 .coafile 。如果您已按照我们的 main tutorial ,您将拥有一个 .coafile 在您的工作目录中。最好在学习本教程之前删除该文件,否则您还会看到来自其他熊的一大堆其他输出。

有关Python内置的更多详细信息 logging 设施,请参阅https://docs.python.org/3/library/logging.html.

与用户通信

现在我们可以通过队列发送消息了,我们可以做真正的工作了。比方说:

  • 我们需要来自用户的一些信息(例如,如果我们依赖缩进,则制表符宽度)。

  • 我们为用户提供了一些有用的信息,并希望将其展示给他们。他们的代码可能有问题,或者只是行数之类的信息。

因此,让我们将HelloWorldBear扩展一下,我将新熊命名为CommunicationBear,这个名字很有创意:

import logging

from coalib.bears.LocalBear import LocalBear

class CommunicationBear(LocalBear):

    def run(self,
            filename,
            file,
            user_input: str):
        """
        Communicates with the user.

        :param user_input: Arbitrary user input.
        """
        logging.debug("Got '{ui}' as user input of type {type}.".format(
            ui=user_input,
            type=type(user_input)))

        yield self.new_result(message="A hello world result.",
                              file=filename)

尝试执行它:

coala -f=src/\*.c -d=bears -b=CommunicationBear -L=DEBUG --flush-cache

嘿,我们会被要求输入用户信息的!

[WARNING][15:20:18] Default coafile '.coafile' not found!
Here's what you can do:
* add `--save` to generate a config file with your current options
* add `-I` to suppress any use of config files
Please enter a value for the setting "user_input" (No description given.)
needed by CommunicationBear for section "cli":

那不是很容易吗?继续,输入一些内容并观察输出。

Avada Kedavra
[DEBUG][15:22:55] Platform Linux -- Python 3.5.2, coalib
0.12.0.dev20170626132008
[DEBUG][15:22:55] The file cache was successfully flushed.
[DEBUG][15:22:55] Files that will be checked:
/home/LordVoldemort/programs/coa_dir/coala-tutorial/src/main.c
[DEBUG][15:22:55] coala is run only on changed files, bears' log messages
from previous runs may not appear. You may use the `--flush-cache` flag to
see them.
[DEBUG][15:22:55] Running bear CommunicationBear...
[DEBUG][15:22:55] Got 'Avada Kedavra' as user input of type <class 'str'>.

**** CommunicationBear [Section: cli] ****

!    ! [Severity: NORMAL]
!    ! A hello world result.
[    ] Do (N)othing
[    ] (O)pen file
[    ] Add (I)gnore comment
[    ] Enter number (Ctrl-D to exit):

那么,科拉在这里做了什么?

首先,Coala查看了run方法的参数,发现我们需要一些名为user_input的值。然后,它解析我们的文档注释并找到参数的描述,该描述显示给我们以帮助我们选择正确的值。在提供了所需的值之后,Coala将该值转换为字符串,因为我们已经提供了 str 此参数的批注。如果没有给出批注,或者值不能转换为所需的数据类型,您将获得一个 coalib.settings.Setting.Setting .

您的文档字符串还可以用来告诉用户您的熊到底做了什么。

试着执行

coala -d bears -b CommunicationBear --show-bears --show-description

这将向用户显示一系列与熊相关的信息,如:-熊做什么的描述-使用它的部分-它使用的设置(可选和必需)

备注

熊还没有安装好。我们仍然需要使用以下命令指定BEAR目录 -d--bear-dirs 旗帜。

安装本地写入的熊

假设我们编写了一个包含NewBear的文件NewBear.py,并希望在本地运行它。要安装我们的NewBear,请执行以下操作:

  • 移动 NewBear.py 给我们克隆的科拉熊 coala-bear/bears/<some_directory> .

  • 使用以下内容更新来源中的所有熊:

pip3 install -U <path/to/coala-bears>

我们的新熊装好了。

尝试执行以下命令:

coala --show-bears

这显示了所有已安装的熊的列表。我们可以在单子里找到我们的新熊。

支持哪些数据类型?

该设置确实支持一些非常基本的类型:

  • 弦 (str

  • 浮标 (float

  • int (int

  • 布尔 (bool ,将接受如下值 trueyesyeahnonopefalse

  • 字符串列表 (list ,值将用逗号拆分)

  • 字符串词典 (dict ,值将以逗号和冒号分隔)

您可以使用基本类型的快捷方式, str_list 对于字符串, int_list 对于INT, float_list 对于浮点数和 bool_list 用于布尔值。

如果需要其他类型,可以自己编写转换函数并将此函数用作注释(如果不能转换值,请确保抛出 TypeErrorValueError )。我们为您提供了一些高级转换:

  • coalib.settings.Setting.path ,转换为相对于设置了设置的文件/命令的绝对文件路径

  • coalib.settings.Setting.path_list ,转换为相对于设置了设置的文件/命令的绝对文件路径列表

  • coalib.settings.Setting.typed_list(typ) ,转换为列表并应用给定的转换。 (typ )添加到每个元素。

  • coalib.settings.Setting.typed_ordered_dict(key_type, value_type, default) 方法时,转换为词典。 key_type 转换为所有密钥时, value_type 转换为所有值,并使用 default 所有未设置关键点的值。使用 typed_dict 如果订单对你无关紧要。

  • coalib.settings.Setting.language ,转换为Coala Language 对象。

结果

最后,我们得到了一个结果。如果提供了文件,Coala将显示该文件,如果提供了行,Coala还将在受影响的行之前显示几行。Result构造函数有几个参数,因此您可以创建一个向用户建议代码更改的结果。如果用户喜欢,Coala会自动应用它-你不需要在意。

您的函数需要返回一个可迭代的 Result 对象:这意味着您可以返回一个 list 属于 Result 对象,或者简单地将它们返回并将该方法编写为生成器。

备注

我们目前正计划为熊市写手和我们简化熊市。为了使您的Bear将来成为证据,我们建议以生成器样式编写您的方法。

别担心:为了将您的Bears迁移到我们的新API,您可能只需要更改两行代码。有关熊未来的更多信息,请在https://github.com/coala/coala/issues/725上阅读或在https://coala.io/chat.上询问我们

熊依赖于其他熊

所以我们已经有了一个结果,但是如果我们需要我们的Bear依赖于另一个Bear的结果呢?

Coala有一个高效的依赖管理系统,它可以在您的Bear之前运行另一个Bear,并为您获取其结果。你所需要做的就是告诉Coala你想在你的熊之前跑哪只熊。

那么让我们看看你如何告诉Coala在你之前跑哪只熊:

from coalib.bears.LocalBear import LocalBear
from bears.somePathTo.OtherBear import OtherBear

class DependentBear(LocalBear):

    BEAR_DEPS = {OtherBear}

    def run(self, filename, file, dependency_results):
        results = dependency_results[OtherBear.name]

如你所见,我们有一个 coalib.bears.Bear.Bear.BEAR_DEPS 集合,其中包含我们希望依赖的熊的列表。在本例中,它是一个包含1个项目的集合:“OtherBear”。

备注

这个 BEAR_DEPS set必须有Bear本身的类,而不是字符串形式的名称。

科拉得到了 BEAR_DEPS 在执行 DependentBear 先把所有的熊队都放进去。

在运行这些熊之后,Coala给出了熊队在 dependency_results DICTIONARY,它将熊的名字作为关键字,将结果列表作为值。例如,在这种情况下,我们将有 dependency_results == {{'OtherBear' : [list containing results of OtherBear]]}} .

备注

dependency_results 在这里是关键字,不能由任何其他名称调用。

隐藏结果

除了常规结果,Coala还提供HiddenResults,用于在Bears之间共享数据,以及给出没有显示给用户的结果。此功能专门针对作为其他Bears的依赖项的Bears,并且不希望返回在Bear运行时显示的结果。

让我们看看如何在Bear中使用HiddenResults:

from coalib.bears.LocalBear import LocalBear
from coalib.results.HiddenResult import HiddenResult

class OtherBear(LocalBear):

    def run(self, filename, file):
        yield HiddenResult(self, ["Some Content", "Some Other Content"])

在这里我们可以看到,这只熊(与普通熊不同)产生了一个 coalib.results.HiddenResult 而不是 Result 。中的第一个参数 HiddenResult 应该是产生此结果的Bear实例(在本例中 self ),第二个参数应该是我们想要在Bear之间传输的内容。这里我们使用字符串列表作为内容,但它可以是任何对象。

更多配置选项

Coala提供元数据,根据您的需要进一步配置您的熊。以下是您可以提供的所有元数据的列表:

LANGUAGES

要指示您的熊支持哪些语言,您需要给它一个 set 将字符串表示为值:

class SomeBear(Bear):
    LANGUAGES = {'C', 'CPP','C#', 'D'}

备注

  • 对于语言命名,请始终考虑相应Wikipedia页面中使用的格式(例外情况:使用CPP,而不是CPP或C++)。

  • 如果该定义尚不存在,则在编写新的Bear时应添加语言定义。

  • 语言中使用的别名应该是Coala定义中的名称之一。

REQUIREMENTS

若要指示熊的要求,请指定 REQUIREMENTS 具有的子类实例的集合 PackageRequirement 例如:

  • PipRequirement

  • NpmRequirement

  • CondaRequirement

  • DistributionRequirement

  • GemRequirement

  • GoRequirement

  • JuliaRequirement

  • RscriptRequirement

class SomeBear(Bear):
    REQUIREMENTS = {
    PipRequirement('coala_decorators', '0.2.1')}

要指定多个需求,您可以使用Multiple方法。这可以接收两个字符串元组(如果需要特定版本)或简单字符串(如果需要指定最新版本)。

class SomeBear(Bear):
    REQUIREMENTS = PipRequirement.multiple(
        ('colorama', '0.1'),
        'coala_decorators')

INCLUDE_LOCAL_FILES

如果您的熊需要包括本地文件,则通过将包含文件路径的字符串(相对于包含熊的文件)提供给 INCLUDE_LOCAL_FILES .

class SomeBear(Bear):
    INCLUDE_LOCAL_FILES = {'checkstyle.jar',
        'google_checks.xml'}

可检测和可修复(_D)

要轻松跟踪熊可以做什么,可以设置 CAN_FIXCAN_DETECT 成套的。

class SomeBear(Bear):
    CAN_DETECT = {'Unused Code', 'Spelling'}

    CAN_FIX = {'Syntax', 'Formatting'}

要查看可能值的完整列表,请检查此列表:

  • Syntax

  • Formatting

  • Security

  • Complexity

  • Smell

  • Unused Code

  • Redundancy

  • Variable Misuse

  • Spelling

  • Memory Leak

  • Documentation

  • Duplication

  • Commented Code

  • Grammar

  • Missing Import

  • Unreachable Code

  • Undefined Element

  • Code Simplification

指定要执行的操作 CAN_FIX 很明显,它也可以被检测到,因此可以从 CAN_DETECT

BEAR_DEPS

BEAR_DEPS 包含要在执行此Bear之前执行的Bear类。然后,这些Bear的结果将作为字典通过 dependency_results 论点。DICT将以熊的名称作为关键字,并将其结果列表作为值:

class SomeOtherBear(Bear):
    BEAR_DEPS = {SomeBear}

有关更多详细信息,请参见 Bears Depending on Other Bears .

其他元数据

其他元数据,如 AUTHORSAUTHORS_EMAILSMAINTAINERSMAINTAINERS_EMAILSLICENSEASCIINEMA_URLSEE_MORE 可按如下方式使用:

class SomeBear(Bear):
    AUTHORS = {'Jon Snow'}
    AUTHORS_EMAILS = {'jon_snow@gmail.com'}
    MAINTAINERS = {'Catelyn Stark'}
    MAINTAINERS_EMAILS = {'catelyn_stark@gmail.com'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/80761'
    SEE_MORE = 'https://www.pylint.org'

Aspect Bear(方面熊)

Aspect是Coala中的一个特性,它使得在项目中配置Coala变得更加容易,并且与语言无关。有关Aspect的更多详细信息,请参阅https://github.com/coala/cEPs/blob/master/cEP-0005.md.中的CEP-005.

符合方面的BEAR必须:

  1. 声明它可以修复和检测的方面列表。请注意,方面必须是叶方面。您可以在此处查看支持的方面列表https://github.com/coala/aspect-docs.

  2. 声明支持的语言列表。请参阅支持的语言https://github.com/coala/coala/tree/master/coalib/bearlib/languages/definitions.列表

  3. 使用将设置映射到其等效的纵横比或品味 map_setting_to_aspect 装饰者。

  4. 与相关方面的产出结果。

例如,让我们创建一个名为SpellingCheckBear的方面熊。

from coalib.bearlib.aspects import map_setting_to_aspect
from coalib.bearlib.aspects.Spelling import (
    DictionarySpelling,
    OrgSpecificWordSpelling,
)
from coalib.bears.LocalBear import LocalBear


class SpellingCheckBear(
        LocalBear,
        aspect={
            'detect': [
                DictionarySpelling,
                OrgSpecificWordSpelling,
            ],
        },
        languages=['Python']):

    @map_setting_to_aspect(
        use_standard_dictionary=DictionarySpelling,
        additional_dictionary_words=OrgSpecificWordSpelling.specific_word,
    )
    def run(self,
            filename,
            file,
            use_standard_dictionary: bool=True,
            additional_dictionary_words: list=None):
        """
        Detect wrong spelling.

        :param use_standard_dictionary:     Use standard English dictionary.
        :param additional_dictionary_words: Additional list of word.
        """
        if use_standard_dictionary:
            # Imagine this is where we save our standard dictionary.
            dictionary_words = ['lorem', 'ipsum']
        else:
            dictionary_words = []
        if additional_dictionary_words:
            dictionary_words += additional_dictionary_words

        for word in file.split():
            if word not in dictionary_words:
                yield self.new_result(
                    message='Wrong spelling in word `{}`'.format(word),
                    aspect=DictionarySpelling('py'),
                )