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;
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/
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:
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.