3. Руководство по программированию

В данном разделе обсуждаются руководящие указания по написанию кода, которым необходимо следовать во всех исходных кодах пакета Planner. Пожалуйста, проследите, что указания выполнены, прежде чем отправлять патчи.

3.1. Соглашения об именах

Схемы именования, применяемые в libplanner и planner немного отличаются; это сделано для облегчения понимания из названия функции, к какому из пакетов она относится. Цель предлагаемых схем именования состоит в том, чтобы обеспечить легкое нахождение определения и реализации function/enum/class/... просто посмотрев на название.

3.1.1. Имена классов

  • Имя класса должно начинаться с префикса Mrp для классов в libplanner и Planner для классов в planner.
  • Используйте заглавные буквы в качестве разделителей слов, и строчные буквы для остальной части слова.
  • Не используйте в именах символы подчеркивания («_»).

Имена классов

class MrpTaskManager
class PlannerResourceModel

3.1.2. Имена файлов

Имена файлов должны быть сформированы следующим образом:

  • Не используйте заглавные буквы.
  • Для разделения слов используйте дефис («-»).
  • Для пакета libplanner используйте в именах файлов префикс mrp-, а для пакета planner – префикс planner-.

Имена файлов

mrp-task-manager.c
mrp-task-manager.h
planner-resource-model.c
planner-resource-model.h

3.1.3. Имена внешних функций

Имена внешних функций должны присваиваться так же, как имена файлов, с заменой дефисов («-») на символ подчеркивания («_»).

Имена внешних функций

mrp_task_manager_get_root (...)
planner_resource_model_get_type_string (...)

3.1.4. Имена статических функций

Для статических функций используется та же схема, что и для внешних функций, но не добавляется префикс. Так, например:

Имена статических функций

Внешняя функция

mrp_resource_get_name (...)

становится

resource_get_name (...)

если это статическая функция в файле mrp−resource.c.

Заметим, что данная схема в настоящее время в Planner не используется, но схема будет заменена на описанную по мере редактирования файлов, так что просим использовать указанную схему при написании всего нового кода.

3.1.5. Имена Enum/Struct

Соглашение об именах для enum и structs такое же, как и для классов (classes).

Имена Enum/Struct

в файле mrp−resource.h

typedef enum {
        MRP_RESOURCE_TYPE_NONE,
        MRP_RESOURCE_TYPE_WORK,
        MRP_RESOURCE_TYPE_MATERIAL
} MrpResourceType;

Сходным образом следует применять схему именования для структур.

3.1.6. Имена #define и macro

#define и macro должны быть названы таким же образом, как и функции, но с прописными буквами вместо строчных.

Имена #define и macro

В файле mrp−resource.h

#define MRP_TYPE_RESOURCE         (mrp_resource_get_type ())

В файле planner−resource−model.h

#define PLANNER_IS_RESOURCE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
                                    PLANNER_TYPE_RESOURCE_MODEL))

3.2. Форматирование кода

Чтобы сделать код более читабельным, здесь определен ряд правил форматирования, которые должны соблюдаться. Если каждый, кто программирует для Planner, будет использовать такое же форматирование кода, читать чужой код будет гораздо проще.

3.2.1. Отступ

Отступ надо оформлять при помощи символа табуляции, и одна табуляция должна быть шириной в восемь пробелов.

Отступ

static void
mrp_resource_new (void)
{
        MrpResource *resource;

        resource = g_object_new (MRP_TYPE_RESOURCE, NULL);

        return resource;
}

Такой же стиль используется в ядре Linux и в проекте GNOME.

3.2.2. Политика фигурных скобок

  • Во всех выражениях if-, while-, do-, for должны использоваться фигурные скобки, даже в однострочных. Это делается для того, чтобы было видно, где выражение начинается/заканчивается. Кроме того, это полезно, потому что, когда требуется добавить еще одну строку в выражение, вам не нужно беспокоиться, требуется ли добавление фигурных скобок.

    Использование фигурных скобок в выражениях

    if (i >= 0) {
            /* do something */
    }
    
  • Для данных типов выражений открывающая фигурная скобка должна быть помещена на той же строке, что и выражение, с одиночным пробелом между выражением и открывающей скобкой.

    Однострочные выражения

    for (i = 0; i < len; ++i) {
            /* my one−liner */
    
    }
    
  • Для функций открывающая фигурная скобка должна быть размещена на строке ниже функции

    Фигурные скобки вокруг выражений функции

    void static
    my_function (void)
    {
            /* do something */
    }
    
  • В выражениях if-elseif-else нужно использовать следующее форматирование.

    if−elseif−else statement

    if (...) {
            /* do something */
    }
    else if (...) {
            /* do something else */
    } else {
           /* do yet another thing */
    }
    

3.2.3. Политика круглых скобок

???

3.2.4. Декларация и реализация функции

Несколько рекомендаций по описанию функции.

  • В декларации всегда размещайте один аргумент на строку и выровняйте функции, типы и аргументы для легкого чтения.

    Декларация функции

    void      mrp_resource_assign             (MrpResource     *resource,
                                               MrpTask         *task,
                                               gint             units);
    GList *   mrp_resource_get_assignments    (MrpResource     *resource);
    
  • При реализации функции попробуйте расположить все аргументы в одной строке; если это не получается в 80 символов, расположите по одному аргументу на строку. Поместите один пробел между самым длинным типом и аргументами.

    Реализация функции

    void
    mrp_resource_assign (MrpResource *resource, MrpTask *task, gint units)
    {
            /* ... */
    }
    
    gboolean
    mrp_project_save_as (MrpProject   *project,
                         const gchar  *uri,
                         gboolean      force,
                         GError      **error)
    {
            /* ... */
    }
    
  • Если у вас есть аргументы типа «указатель» с * или **, символы «*» должны быть размещены вместе с аргументом, а не с типом. Они должны быть выровнены, как показано в примере ниже.

    Выравнивание аргументов типа «указатель»

    gboolean
    mrp_project_save_as (MrpProject   *project,
                         const gchar  *uri,
                         gboolean      force,
                         GError      **error)
    {
            /* ... */
    }
    

3.2.5. Определение переменных

Переменные должны быть выровнены таким же образом, как аргументы функции. Поместите один пробел между самым длинным типом и аргументами и выровняйте с символами указателя * и ** так же, как и для аргументов функций.

3.3. Структура исходных файлов

Все исходные файлы должны начинаться с используемого в Planner заголовка.

/* −*− Mode: C; tab−width: 8; indent−tabs−mode: t; c−basic−offset: 8 −*− */
/*
 * Copyright (C) 2002 Your name <your@email>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * Free Software Foundation, Inc., 59 Temple Place − Suite 330,
 * Boston, MA 02111−1307, USA.
 */

3.3.1. Заголовочные файлы

Заголовочные файлы создаются следующим образом.

Заголовочный файл с комментариями

/* Header as described above */
/* −*− Mode: C; tab−width: 8; indent−tabs−mode: t; c−basic−offset: 8 −*− */
/*
* Copyright (C) 2001−2002 CodeFactory AB
* Copyright (C) 2001−2002 Richard Hult <rhult@codefactory.se>
* Copyright (C) 2001−2002 Mikael Hallendal <micke@codefactory.se>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place − Suite 330,
* Boston, MA 02111−1307, USA.
*/

/*
* include guards, these are to make sure that the same header only
* gets included once.
*/

#ifndef __MRP_ASSIGNMENT_H__
#define __MRP_ASSIGNMENT_H__

/*
* Includes needed by this header, put as much includes as possible in
* the C−file rather than the header file.
*/

#include <planner/mrp−object.h>
#include <planner/mrp−time.h>

/*
* If it is a class you are defining you need this convenience macros,
* they should come directly after the includes.
*/

#define MRP_TYPE_ASSIGNMENT         (mrp_assignment_get_type ())
#define MRP_ASSIGNMENT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o),
                                   MRP_TYPE_ASSIGNMENT, MrpAssignment))
#define MRP_ASSIGNMENT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k),
                                   MRP_TYPE_ASSIGNMENT, MrpAssignmentClass))
#define MRP_IS_ASSIGNMENT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o),
                                   MRP_TYPE_ASSIGNMENT))
#define MRP_IS_ASSIGNMENT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k),
                                   MRP_TYPE_ASSIGNMENT))
#define MRP_ASSIGNMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
                                   MRP_TYPE_ASSIGNMENT, MrpAssignmentClass))

/*
* Defining the class structures
*/

typedef struct _MrpAssignmentClass MrpAssignmentClass;
typedef struct _MrpAssignmentPriv  MrpAssignmentPriv;
struct _MrpAssignment {
      MrpObject          parent;
      MrpAssignmentPriv *priv;
};

struct _MrpAssignmentClass {
      MrpObjectClass parent_class;
};

/* Function declarations */
GType              mrp_assignment_get_type     (void) G_GNUC_CONST;
MrpAssignment     *mrp_assignment_new          (void);
MrpTimeInterval   *mrp_assignment_get_interval (MrpAssignment *assignment);
MrpTask           *mrp_assignment_get_task     (MrpAssignment *assignment);
MrpResource       *mrp_assignment_get_resource (MrpAssignment *assignment);
gint               mrp_assignment_get_units    (MrpAssignment *assignemnt);

/* End of the include guard */

#endif /* __MRP_ASSIGNMENT_H__ */

3.3.2. Файлы на C

Файл на C с комментариями

/* Same header as in the header file */
/* −*− Mode: C; tab−width: 8; indent−tabs−mode: t; c−basic−offset: 8 −*− */
/*
* Copyright (C) 2001−2002 CodeFactory AB
* Copyright (C) 2001−2002 Richard Hult <rhult@codefactory.se>
* Copyright (C) 2001−2002 Mikael Hallendal <micke@codefactory.se>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place − Suite 330,
* Boston, MA 02111−1307, USA.
*/

/*
* Declarations of private structures and enums, the should come
* before the internal functions since some of the internal functions
* might need these structures/enums.
*/

struct _MrpAssignmentPriv {
      MrpTask     *task;
      MrpResource *resource;
      gint         units;
};

/* Properties */
enum {
      PROP_0,
      PROP_TASK,
      PROP_RESOURCE,
      PROP_UNITS
};

/* Declaration of internal functions */
static void mpa_class_init        (MrpAssignmentClass *klass);
static void mpa_init              (MrpAssignment      *assignment);
static void mpa_finalize          (GObject            *object);
static void mpa_set_property      (GObject            *object,
                                 guint               prop_id,
                                 const GValue       *value,
                                 GParamSpec         *pspec);
static void mpa_get_property      (GObject            *object,
                                 guint               prop_id,
                                 GValue             *value,
                                 GParamSpec         *pspec);

/*
* Declaration of internal file global variables
* NOTE! Try to not use file global variables and instead put them in
*       a privat structure as in this example
*/
static MrpObjectClass *parent_class;

/*
* Put the get_type function as the first function implementation.
*/
GType
mrp_assignment_get_type (void)
{
      /* ... */
}

/*
* It should be directly followed by the static variables
* (in the same order as they were defined).
*/
static void
mpa_class_init (MrpAssignmentClass *klass)
{
    /* <snip> */
}

/* After the internal functions you put the implementations of the
* external functions.
* (These too in the same order as they were declared).
*/

3.3.3. Использование приватных структур

Мы настоятельно рекомендуем использовать приватные структуры, как показано в приведенном выше примере кода. Это делает код более объектно-ориентированным и гарантирует, что вы не используете внутренние переменные напрямую.