Lab 3 - moduły + PasDoc — IPP 2011/12

Spis treści

Poprzedni temat

Lab 2 - Valgrind + styl kodowania

Następny temat

Lab 4 - Object Pascal, testy i GDB

Lab 3 - moduły + PasDoc

Moduły

Większe programy czy biblioteki zwykle składają się z modułów, których kod przechowywany jest w osobnych plikach. Takie podejście ma wiele zalet:

  • Struktura projektu jest bardziej przejrzysta.
  • Funkcje, typy czy stałe wykorzystywane tylko w jednym module mogą zostać ukryte przed pozostałymi modułami.
  • Po wprowadzeniu zmian w kodzie ponownej kompilacji wymagają tylko zmodyfikwane moduły.
  • Ułatwia pracę z systemem kontroli wersji.
  • ...

W Pascalu moduł to plik źródłowy, którego struktura została przedstawiona na poniższym przykładzie.

{ Na początku zamiast 'program' trzeba napisać 'unit'. }
unit SampleUnit;

{ Używamy nowoczesnego dialektu Pascala (objfpc)
  oraz nowocześniejszej implementacji mtypu String (H+). )
{$mode objfpc}{$H+}

{ Po słowie kluczowym 'interface' następuje interfejs modułu,
  czyli spis deklaracji, które mają być widoczne dla jego
  użytkowników. }
interface

{ Mogą to być np. stałe. }
const
    SAMPLE_CONST : Integer = 42;

{ Ale też typy. }
type
    TSampleRange = 1 .. 100;
    TSampleRecord = record
        SampleField : Integer;
        AnotherField : String;
    end;
    TSampleEnum = ( ENUM_VALUE1, ENUM_VALUE2 );

{ Oraz, oczywiście, procedury czy funkcje.
  Zauważmy, że w sekcji 'interface' umieszczamy jedynie
  sygnatury funkcji, a nie ich implementację.
}
procedure SampleProcedure(Param1 : Integer; Param2 : Integer);
function SampleFunction(Param1 : Integer; Param2 : Integer) : Integer;

{ Następna sekcja zaczyna się od słowa 'implementation'.
  Zawiera kod procedur zadeklarowanych w interfejsie oraz
  wszystkie elementy niewidoczne na zewnątrz modułu. }
implementation

{ Możemy tu deklarować typy wykorzystywane wewnątrz modułu. }
type
    PrivateEnum = ( YES, NO );

{ Funkcja prywatna (nie ma jej w interfejsie). }
function PrivateFunction(Param1 : Integer) : Integer;
begin
    Result := Param1 + 1;
end;

{ Implementacja funkcji z interfejsu. }

procedure SampleProcedure(Param1 : Integer; Param2 : Integer);
begin
    WriteLn('Param1 = ', Param1);
    WriteLn('Param2 = ', Param2);
end;

function SampleFunction(Param1 : Integer; Param2 : Integer) : Integer;
begin
    Result := PrivateFunction(Param1 + Param2);
end;

{ Sekcja 'initialization' zawiera instrukcje wykonywane
  przy ładowaniu modułu (tz. przy uruchomieniu programu,
  który z owego modułu korzysta). }
initialization
   WriteLn('SampleUnit loaded');

end.

Moduł kompilujemy tym samym poleceniem, co zwykły program:

$ ppcx64 sampleunit.pas
Free Pascal Compiler version 2.4.0 [2010/01/15] for x86_64
Copyright (c) 1993-2009 by Florian Klaempfl
Target OS: Linux for x86-64
Compiling sampleunit.pas
48 lines compiled, 0.0 sec

Spowoduje to wygenerowanie dwóch plików. Jeden z nich będzie miał rozszerzenie .ppu i będzie zawierał skompilowany opis interfejsu modułu. Skompilowany kod umieszczony zostanie w drugim pliku, o rozszerzeniu .o.

Aby wykorzystać moduł w programie (lub innym module) należy umieścić jego nazwę w klauzuli uses, jak w poniższym przykładzie:

program SampleProgram;

uses SampleUnit;

begin
    SampleProcedure(42, 44);
end;

PasDoc

Komentarze w kodzie opisujące strukturę typów, działanie procedur czy znaczenie ich poszczególnych parametrów są istotnym (zwłaszcza dla osób zainteresowanych zaliczeniem IPP) składnikiem każdego modułu. Jednak lektura komentarzy w pliku źródłowym nie zawsze jest wygodna. Czasami możemy w ogóle nie mieć do takiego pliku dostępu. Dobrze więc byłoby mieć narzędzie, które potrafi przeczytać komentarze w interfejsie modułu i wygenerować z nich np. stroną podobną do tej:

http://pasdoc.sourceforge.net/autodoc/html/index.html

Jednym z takich narzędzi jest PasDoc:

Todo

Przykład pliku z komentarzami.

http://pasdoc.sipsolutions.net/

C++

Dużą popularnością cieszy się narzędzie Doxygen:

http://www.stack.nl/~dimitri/doxygen/index.html

Jeśli program korzysta z biblioteki Qt, można też rozważyć QDoc:

http://doc.qt.nokia.com/qdoc/

FPDoc

Dokumentację można również przechowywać w osobnych plikach. Przykładem narzędzia stosującego to podejście jest fpdoc. Wszelkie opisy umieszczane są w osobnym pliku .xml, wyglądającym podobnie do poniższego przykładu.

<?xml version="1.0" encoding="ISO-8859-1"?>
<fpdoc-descriptions>
<package name="SamplePackage">

<!--
  ====================================================================
    SampleUnit
  ====================================================================
-->

<module name="SampleUnit">
<short></short>
<descr>
This is a sample unit, used to demonstrate the unit mechanism used by Pascal.
</descr>

<!-- constant Visibility: default -->
<element name="SAMPLE_CONST">
<short>Sample constant.</short>
<descr>
Longer description of the sample constant.
</descr>
<seealso>
</seealso>
</element>

...

</module> <!-- SampleUnit -->

</package>
</fpdoc-descriptions>

Ręczne tworzenie większej ilości XMLa jest raczej nieprzyjemne. Na szczęście środowisko Lazarus zawiera wbudowany edytor dokumentacji w formacie fpdoc. Wystarczy w edytorze wskazać kursorem jakiś element i wpisać jego opis w stosownym okienku.