1 <!DOCTYPE HTML
PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
4 <title
>PsN
:: Developer
's Guide</title>
5 <!--Adobe(R) LiveMotion(TM) 1.0 Generated JavaScript. Please do not edit. -->
10 function newImage(arg) {
12 if (document.images) {
24 ImageArray = new Array;
26 var preloadFlag = false;
28 function preloadImages() {
30 if (document.images) {
32 ImageArray[ImageArray.length++] = newImage(/* OWNER('object', 'dflt
') *//*URL*/'images
/indexhome
.jpg
');
33 ImageArray[ImageArray.length++] = newImage(/* OWNER('object', 'movr
') *//*URL*/'images
/indexhomeov
.jpg
');
34 ImageArray[ImageArray.length++] = newImage(/* OWNER('object1
', 'dflt
') *//*URL*/'images
/indexdocumentation
.jpg
');
35 ImageArray[ImageArray.length++] = newImage(/* OWNER('object1
', 'movr
') *//*URL*/'images
/indexdocumentationov
.jpg
');
36 ImageArray[ImageArray.length++] = newImage(/* OWNER('object2
', 'dflt
') *//*URL*/'images
/indexdownload
.jpg
');
37 ImageArray[ImageArray.length++] = newImage(/* OWNER('object2
', 'movr
') *//*URL*/'images
/indexdownloadov
.jpg
');
38 ImageArray[ImageArray.length++] = newImage(/* OWNER('object3
', 'dflt
') *//*URL*/'images
/indexbuglist
.jpg
');
39 ImageArray[ImageArray.length++] = newImage(/* OWNER('object3
', 'movr
') *//*URL*/'images
/indexbuglistov
.jpg
');
40 ImageArray[ImageArray.length++] = newImage(/* OWNER('object4
', 'dflt
') *//*URL*/'images
/indexmailing_list
.jpg
');
41 ImageArray[ImageArray.length++] = newImage(/* OWNER('object4
', 'movr
') *//*URL*/'images
/indexmailing_listov
.jpg
');
45 function changeImages() {
46 if (document.images && (preloadFlag == true)) {
47 for (var i=0; i<changeImages.arguments.length; i+=2) {
48 document[changeImages.arguments[i]].src = changeImages.arguments[i+1];
53 </script><!-- End generated JavaScript. -->
54 <meta http-equiv="Content-Type"
55 content="text/html; charset=ISO-8859-1">
56 <style type="text/css">
59 font-family: Helvetica, Arial, serif;
68 background-image: url(gfx/bg.jpg);
82 text-decoration: none;
86 text-decoration: none;
90 text-decoration: none;
94 text-decoration: none;
98 <script language="JavaScript" type="text/JavaScript">
100 function MM_reloadPage(init) { //reloads the window if Nav4 resized
101 if (init==true) with (navigator) {if ((appName=="Netscape")&&(parseInt(appVersion)==4)) {
102 document.MM_pgW=innerWidth; document.MM_pgH=innerHeight; onresize=MM_reloadPage; }}
103 else if (innerWidth!=document.MM_pgW || innerHeight!=document.MM_pgH) location.reload();
108 <meta content="Pontus Pihlgren" name="author">
110 <body onload="preloadImages();"
111 style="background-color: rgb(255, 255, 255);">
112 <!-- The table is not formatted nicely because some browsers cannot join images in table cells if there are any hard carriage returns in a TD. -->
114 style="position: absolute; left: 335px; top: 42px; width: 388px; height: 43px; z-index: 1; font-size: x-small;">
115 <div class="style1" align="right">Developer's
120 style
="position: absolute; z-index: 2; width: 497px; left: 226px; top: 188px; height: 2972px;">
121 <h3 style
="margin-left: 40px;" class="heading1">Introduction
</h3
>
122 <div style
="text-align: justify;">
123 So you want to dig into the PsN code
. Maybe you want to write a
new
124 tool
for the toolkit
or just learn more about PsN
. Either way
, here you
125 will find what you need to learn how to
use PsN
as well
as writing nice
126 maintainable
and readable code in the spirit of PsN
. <br
>
128 <p style
="text-align: justify;">To
129 fully apprecieate this document
130 you should have some coding
131 experience
and should have worked with
object oriented programming
. If
132 you know about UML
and XML that is a bonus
. If you don
't know about
133 these fancy things, don't sweat it
, We
'll try to keep it as simple as
135 <h3 style="margin-left: 40px;" class="heading1">Dia
137 <p style="text-align: justify;">
138 PsN is written in <a target="_blank" href="http://www.perl.org/">Perl</a>.
139 Perl is powerful, good at text manipulation and system interaction and
141 very flexible. A little too flexible for a piece of software the size
143 PsN. When we took the first steps to making PsN object oriented we felt
144 that defining the object structure in Perl was a bit cumbersome. Also,
145 Perl lacks type-checking, which very much eases debugging. Adding that
146 manually for accessors and methods in all of PsN's classes would be
147 time
-consuming
and probably wouldn
't be done homogenous and be
149 to maintain. Our answer to the hurdles is <a target="_blank"
150 href="http://www.gnome.org/projects/dia/">Dia</a>.
151 Dia is a GTK+ based diagram creation program released under the GPL
153 <p style="text-align: justify;">With
154 Dia, we have created UML
155 diagrams for all classes in PsN. Dia saves
156 its diagrams in XML format. This allows us to generate code through <a
157 target="_blank" href="http://dia2code.sourceforge.net/">Dia2Code</a>.
158 Dia2Code is a small utility used to generate code from a Dia diagram.
159 Dia2Code didn't support Perl
, so we added a plugin to it that generates
160 appropriate code
. It gave us freedom in how we
do type checking
, and
162 and methods are created
. </p
>
163 <p
> In order to produce
164 usable PsN code from the diagrams it takes three steps
. </p
>
167 <div style
="text-align: justify;">
169 create a Dia UML diagram that defines classes complete with typed
170 members
, methods
and inheritance between classes
.</p
>
172 <p style
="text-align: justify;">Read
173 our
<a href
="dia_index.php">Dia
174 UML guide
</a
> for details
. You can
175 also have a look at the Dia authors
' <a target="_blank"
176 href="http://www.gnome.org/projects/dia/diatut/all/all.html">tutorial</a>
177 on how to use Dia. </p>
181 <p style="text-align: justify;">The
183 add code that goes into the class structure skeleton generated by
184 Dia2Code. As described in step three.</p>
185 <p style="text-align: justify;">Dia2Code
187 each class, generate a constructor(a method named "new"), a skeleton
188 for each class method and accessors for each class member. Each members
189 accessor can take one argument, that argument will then be set as the
190 new value for the member. If no argument is given, the accessor will
191 return the current value of the accessor. </p>
192 <p style="text-align: justify;">Both
194 constructor are in fact perl methods, but since
195 Dia2Code writes slightly different skeletons for them, we give them
196 different names to ease discussion. </p>
197 <p style="text-align: justify;">
199 method you can add your own code (Otherwise it would be rather
200 pointless, wouldn't it
). You can also add code to the constructur
, and
201 to
accessors (something we don
't do much, but there are cases where it
202 might be useful). </p>
203 <p style="text-align: justify;">To
204 add your own code you
205 must create a file parallel to the file
206 generated by Dia2Code. So, for example, we can look the class <tt>"problem"</tt>
207 defined in <tt>"model.dia"</tt>.
208 Dia2Code would generate the file: </p>
210 <p class="style2"><tt>[
211 Path to PsN Diagrams ]lib/model/problem.pm</tt><br>
214 Then you should create the file:
216 <p class="style2"><tt>[
217 Path to PsN Diagrams ]lib/model/problem_subs.pm</tt><br>
220 <p style="text-align: justify;">The
221 extension <tt>_subs</tt>
222 and the <tt>"lib"</tt>
223 directory is just a convention, you
224 can call it whatever you like, but if you want to use our makefile
225 script described in step three, you should add <tt>_subs</tt>
227 and put it in the <tt>"lib"</tt>
228 directory. It will make life easier. </p>
229 <p>Note that you should keep
232 <p style="text-align: justify;">
233 In the <tt>_subs</tt>
235 you add a block of code for each method you need to add. Each block
236 must start with <tt>"start
237 method_name"</tt> and end with <tt>"end
239 Everything in between must be valid Perl code. A typical block might
245 # returns the number of thetas in the model for the given<br>
246 # problem number.<br>
247 $nthetas = $self -> _parameter_count( 'record
' =>
249 'problem_number
' => $problem_number );<br>
253 <p style="text-align: justify;">What
255 example is that you have accecss to any
256 argument that was defined for the method in the Dia diagram. And the <tt>$self</tt>
257 variable which is a reference to the class instance from which
259 method was called (comparable to the <tt>"this"</tt>
260 variable in C++).</p>
261 <p style="text-align: justify;">In
264 you have access to the variable <tt>$parm</tt>
265 which is the given argument, if any. And in the constructor block(the
266 special method named <tt>"new"</tt>),
268 is called <tt>$this</tt>
270 reason, this might change.</p>
274 <div style="text-align: justify;"></div>
275 <p style="text-align: justify;">The
277 compile the diagrams and <tt>_subs</tt>
278 files into a functional PsN library. If
279 you have everything installed in place and have not added any new Perl
280 files or diagrams you only need to run make from the diagrams
281 directory. If you have added new files or new classes(which implicitly
282 means Dia2Code will generate files for them) you must add those files
284 <p style="text-align: justify;">
286 to run Dia2Code manually. Assuming that you have Dia2Code installed and
287 working you should start your shell and go to the directory where you
288 created the Dia file and type the following: </p>
290 <p class="style2"><tt>dia2code
291 -t perl file.dia</tt></p>
293 <p style="text-align: justify;">Dia2Code
295 file called <tt>"class.pm"</tt>
296 for each defined class.
297 In each it has defined a Perl package, a constructor (called <tt>new</tt>),
299 method and an accessor.</p>
300 <p style="text-align: justify;">
302 this file and add your own code to the skeleton. Notice though, that
303 the file will be overwritten each time you run Dia2Code. We have solved
304 this with a script called fill_diacode.pl that takes code from <tt>file_subs.pm</tt>
305 and puts it into the <tt>file.pm</tt>
306 file generated by Dia. To use <tt>fill_diacode.pl</tt>
309 <p class="style2"><tt>fill_diacode.pl
310 file_subs file.pm</tt></p>
312 <p style="text-align: justify;">Now
314 code and should be ready to run. I suggest you
315 also have perl check it for syntax errors (and enable warnings):</p>
317 <p class="style2"><tt>perl
318 -c -W -t -T file.pm</tt></p>
322 <p style="text-align: justify;">Now
323 you should at least have an
324 overview of how the system is thought
325 out to work. If you find any inconsistencies or even errors (I'm sure
326 there are
), please don
't be afraid to contact us with questions.</p>
327 <p style="text-align: justify;"></p>
328 <h3 style="margin-left: 40px;" class="heading1">Coding
329 Style and Conventions</h3>
330 <p style="text-align: justify;">
331 Since there are several
332 developers working on PsN, we have tried to conform to a coding
334 100% enforced throughout PsN and it is not expected that you follow our
335 recommendations to the extreme. Consider our recommendations as
336 friendly guidelines to something we think is readable code. </p>
339 <div style="text-align: justify;"><span style="font-weight: bold;">Variables</span>
341 long variables
, several words are more than OK
. But
try to limit
342 yourself to four
or five words
. And for the love of God
, don
't write
343 them together and capitalize letters, like so: <tt>$thisIsALongAndHardToReadVariableName</tt>.
344 Instead separate word with and
345 underscore and keep them lowercase, like this: <tt>$nice_readable_variable</tt>.
348 only needed when the use of the varible is not entirely clear and is
349 used in a long scope (such as an entire function). In other cases
350 shorter names are allowed (and encouraged) such as <tt>$i</tt>,
352 or even <tt>$string</tt>.</p>
356 <p>when it is obvious how the
357 variable is intended to be used. </p>
360 <div style="text-align: justify;"><span style="font-weight: bold;">Loops</span>
362 to write loops with the powerful <tt>foreach</tt>
363 construct. Try to use them as
364 much as you can. In cases where you need an index in the loop, use <tt>$i</tt>
365 as loop variable and keep initial values and loop conditions simple.
369 <p><span style="font-weight: bold;">Conditions</span>
371 cond ? this : that"</tt> constructs,
372 they are hard to read!</p>
374 <li style="text-align: justify;">
375 <p><span style="font-weight: bold;">Methods</span>
377 should be similar to variable names, and should start with double
378 underscores if they are private.</p>
381 <h3 style="margin-left: 40px;" class="heading1">Error
383 <p style="text-align: justify;"> To simplify debugging a bit we
384 have created a wrapper around Perl's Carp module
. Every Perl file
385 genereted with our perl plugin
for Dia2Code uses it
. </p
>
386 <p style
="text-align: justify;"> It is a common Perl module
388 you
include it with
<tt
>use debug
;</tt
>.
389 Then you have a few methods to
print warning messages
and die with a
390 bit more detailed error message than is produced by perl
<tt
>die</tt
>
392 <p style
="text-align: justify;"> The Debug
class is a little
393 bit special in that it should never be instantiated
. An instance is
394 kept globally which can be accessed by the members of the debug
class
395 if they are called statically
. Calling a member statically means that
396 you adress them using the Perl module name
, for example
:</p
>
397 <p style
="text-align: justify;"> <tt
>debug
398 ->
; level( );</tt
></p
>
399 <p style
="text-align: justify;"> Notice that there is no $ in
400 front of
'debug'. Here level is called
"statically". In other words
, it
401 means
"call a member without an instance".</p
>
402 <p style
="text-align: justify;"> The reason
for this is that
403 debug keeps a
"level" variable globaly
, which indicates how verbose PsN
404 should be
, the higher the level
, the more messages you will see
. The
405 level variable is numerical
, but each level has a name in order to make
406 its
use a bit more intuitive
. The levels are
, starting with the lowest
:</p
>
407 <p style
="text-align: justify;"></p
>
408 <dl style
="text-align: justify;">
409 <dt style
="font-weight: bold;">"fatal"</dt
>
410 <dd
>only when an error so grave
411 that PsN has to
exit, a fatal message may be printed
. This is the least
412 amount of messages you can see
.</dd
>
413 <dt style
="font-weight: bold;">"warning"</dt
>
414 <dd
>When something critical
415 happens
, somethings that probably should be examined closer
, though not
416 serious enough to
exit PsN a warning message may be printed
.</dd
>
417 <dt style
="font-weight: bold;">"information"</dt
>
418 <dd
>When something out of the
419 ordinary happens
and we think the user should be informed
, an
420 informational message may be printed
.</dd
>
421 <dt style
="font-weight: bold;">"call_trace"</dt
>
422 <dd
>This level is mostly used by
423 developers when debugging PsN
. If this level is set a message will be
424 printed
for each method which is called inside PsN
. Needless to say
,
425 this will
print a lot of text
. The only time a user should turn this is
426 when filing a bug report
, and only then
if a developer thinks it is
429 <div style
="text-align: justify;">Setting a higher level than
"fatal"
430 also means that message of all
431 lower levels will be printed
.
433 <p style
="text-align: justify;"> No PsN
class may change the
435 <p style
="text-align: justify;"> The methods available debug
437 <p style
="text-align: justify;"> </p
>
439 <dt style
="text-align: justify;"><b
>level(
441 <dd style
="text-align: justify;">If you give a value to level
442 as a single argument
, you will set the
global level of debug messages
.
444 ->
; level( debug
::warning
)</tt
></p
>
445 <p
> If you don
't give any
446 argument the current level is returned. </p>
448 $current_level = debug -> level</tt></p>
451 <dt style="text-align: justify;"><b>package(
453 <dd style="text-align: justify;">If you give a value to
454 package as a single argument, you will set the global package of debug
455 messages. If you don't give any argument the current package is
458 $current_package = debug
->
; package
</tt
></p
>
461 <dt style
="text-align: justify;"><b
>subroutine(
463 <dd style
="text-align: justify;">If you give a value to
464 subroutine
as a single argument
, you will set the
global subroutine of
467 ->
; subroutine( 'output' )</tt
></p
>
468 <p
> If you don
't give any
469 argument the current subroutine is returned. <tt>my
470 $current_subroutine = debug -> subroutine</tt></p>
473 <dt style="text-align: justify;"><b>level_name(
475 <dd style="text-align: justify;"><span style="font-family: monospace;">level_name</span>
477 integer in the interval 0 to 3 to a string. The string is the name of
478 the level with that number in the order of levels. ( <span
479 style="font-family: monospace;">"fatal"</span>
481 and <span style="font-family: monospace;">"call_trace"</span>
484 $level_name = debug -> level_name( level => 1 )</tt></p>
485 <p> By default it returns the
486 name of the current set level.</p>
488 $current_level_name = debug -> level_name;</tt>
491 <dt style="text-align: justify;"><b>warn_with_trace(
493 <dd style="text-align: justify;">By default, a trace of
494 function calls is printed when PsN dies. If you like you can set a
495 level for which you like traces to be printed. Notice that all lower
496 level messages will also have a trace printed after them.
498 -> warn_with_trace( debug::warning )</tt>
501 <dt style="text-align: justify;"><b>warn(
503 <dd style="text-align: justify;"><span style="font-family: monospace;">debug::warn</span>
505 warning, informational or call_trace messages corresponding to the
506 level specified as argument. <tt>debug::warn</tt>
507 will look at the level given
508 and the global level to see whether anything should be printed.
510 -> warn( level => debug::warning, message => "This
511 is a warning" );</tt></p>
512 <p> NOTICE the lack of <tt>"\n"</tt>
514 the end of the message, <tt>debug::warn</tt>
515 will append one <tt>"\n"</tt>.
516 In case there ever is a GUI for PsN <tt>debug::warn</tt>
517 could be used to create a message in the GUI. And in that
518 case, an extra <tt>"\n"</tt>
519 might be annoying. </p>
521 <dt style="text-align: justify;"><b>die(
524 <div style="text-align: justify;"><span
525 style="font-family: monospace;">debug::die</span>
527 instead of <span style="font-family: monospace;">"die"</span>
528 in order to get a call trace. The given message is
531 <p style="text-align: justify;"> <tt>debug
532 -> die( message => "This message will print, and then PsN
533 will die" );</tt></p>
534 <p style="text-align: justify;"> NOTICE the lack of <span
535 style="font-family: monospace;">"\n"</span>
537 the end of the message, <span style="font-family: monospace;">debug::warn</span>
538 will append one <span style="font-family: monospace;">"\n"</span>.
540 ever is a GUI for PsN debug::doe could be used to create a message in
541 the GUI. And in that case, an extra <span
542 style="font-family: monospace;">"\n"</span> might be annoying. </p>
547 <table border="0" cellpadding="0" cellspacing="0" width="780">
550 <td height="600" width="780">
551 <table border="0" cellpadding="0" cellspacing="0" width="780">
554 <td colspan="7" height="201" width="780"><img
555 src="images/indexpane1_1_.jpg" name="" alt="" border="0" height="201"
559 <td height="46" width="26"><img
560 src="images/indexpane1_2_.jpg" name="" alt="" border="0" height="46"
562 <td height="46" width="73"><a href="index.php"
563 onmouseover="changeImages(/*CMP*/ 'object', /*URL*/ 'images
/indexhomeov
.jpg
'); return true;"
564 onmouseout="changeImages(/*CMP*/ 'object', /*URL*/ 'images
/indexhome
.jpg
'); return true;"><img
565 src="images/indexhome.jpg" name="object" alt="Home" border="0"
566 height="46" width="73"></a></td>
567 <td height="46" width="11"><img
568 src="images/indexpane3_2_.jpg" name="" alt="" border="0" height="46"
570 <td height="46" width="25"><img
571 src="images/indexpane4_2_.jpg" name="" alt="" border="0" height="46"
573 <td height="46" width="15"><img
574 src="images/indexpane5_2_.jpg" name="" alt="" border="0" height="46"
576 <td height="46" width="40"><img
577 src="images/indexpane6_2_.jpg" name="" alt="" border="0" height="46"
579 <td height="46" width="590"><img
580 src="images/indexpane7_2_.jpg" name="" alt="" border="0" height="46"
584 <td colspan="7" height="7" width="780"><img
585 src="images/indexpane1_3_.jpg" name="" alt="" border="0" height="7"
589 <td height="46" width="26"><img
590 src="images/indexpane1_4_.jpg" name="" alt="" border="0" height="46"
592 <td colspan="5" height="46" width="164"><a href="docs.php"
593 onmouseover="changeImages(/*CMP*/ 'object1
', /*URL*/ 'images
/indexdocumentationov
.jpg
'); return true;"
594 onmouseout="changeImages(/*CMP*/ 'object1
', /*URL*/ 'images
/indexdocumentation
.jpg
'); return true;"><img
595 src="images/indexdocumentation.jpg" name="object1" alt="Documentation"
596 border="0" height="46" width="164"></a></td>
597 <td height="46" width="590"><img
598 src="images/indexpane7_4_.jpg" name="" alt="" border="0" height="46"
602 <td colspan="7" height="7" width="780"><img
603 src="images/indexpane1_5_.jpg" name="" alt="" border="0" height="7"
607 <td height="46" width="26"><img
608 src="images/indexpane1_6_.jpg" name="" alt="" border="0" height="46"
610 <td colspan="3" height="46" width="109"><a
612 onmouseover="changeImages(/*CMP*/ 'object2
', /*URL*/ 'images
/indexdownloadov
.jpg
'); return true;"
613 onmouseout="changeImages(/*CMP*/ 'object2
', /*URL*/ 'images
/indexdownload
.jpg
'); return true;"><img
614 src="images/indexdownload.jpg" name="object2" alt="Download" border="0"
615 height="46" width="109"></a></td>
616 <td colspan="3" height="46" width="645"><img
617 src="images/indexpane5_6_.jpg" name="" alt="" border="0" height="46"
621 <td colspan="7" height="7" width="780"><img
622 src="images/indexpane1_7_.jpg" name="" alt="" border="0" height="7"
626 <td height="46" width="26"><img
627 src="images/indexpane1_8_.jpg" name="" alt="" border="0" height="46"
629 <td colspan="2" height="46" width="84"><a href="buglist.php"
630 onmouseover="changeImages(/*CMP*/ 'object3
', /*URL*/ 'images
/indexbuglistov
.jpg
'); return true;"
631 onmouseout="changeImages(/*CMP*/ 'object3
', /*URL*/ 'images
/indexbuglist
.jpg
'); return true;"><img
632 src="images/indexbuglist.jpg" name="object3" alt="Buglist" border="0"
633 height="46" width="84"></a></td>
634 <td colspan="4" height="46" width="670"><img
635 src="images/indexpane4_8_.jpg" name="" alt="" border="0" height="46"
639 <td colspan="7" height="7" width="780"><img
640 src="images/indexpane1_9_.jpg" name="" alt="" border="0" height="7"
644 <td height="46" width="26"><img
645 src="images/indexpane1_10_.jpg" name="" alt="" border="0" height="46"
647 <td colspan="4" height="46" width="124"><a href="list.php"
648 onmouseover="changeImages(/*CMP*/ 'object4
', /*URL*/ 'images
/indexmailing_listov
.jpg
'); return true;"
649 onmouseout="changeImages(/*CMP*/ 'object4
', /*URL*/ 'images
/indexmailing_list
.jpg
'); return true;"><img
650 src="images/indexmailing_list.jpg" name="object4" alt="Mailing List"
651 border="0" height="46" width="124"></a></td>
652 <td colspan="2" height="46" width="630"><img
653 src="images/indexpane6_10_.jpg" name="" alt="" border="0" height="46"
657 <td colspan="7" height="141" width="780"><img
658 src="images/indexpane1_11_.jpg" name="" alt="" border="0" height="141"
666 <td><img src="images/is_single_pixel_gif.gif" alt="" height="1"
671 <!--Adobe(R) LiveMotion(TM) DataMap1.0 DO NOT EDIT