A kód kiírása
A listákon kívül szükségünk lehet a kód ellenőrzésére is. A változókat létrehozó parancs rekonstruálása másféle eredmémyt ad a bash parancsértelmezőben, ha egyszerű változóról vagy tömbről van szó. Így e feladat megoldására egy segédfüggvényt írunk.
Változó lekérdezése
A változó lekérdezését megoldhatjuk a declare -p paranccsal és a válasz darabolásával, csakhogy akkor alhéjat kell indítsunk. Ezért e helyett ismét a bash saját változókezeléséhez nyúlunk. A ${változónév[@]@A} értéke azonos azzal, amit a declare -p parancs ír ki, kivéve, ha olyan egyszerű változót kérdezünk le, amelynek még semmilyen értéket sem adtunk. Így szükségünk lesz még a ${változónév@a} változóra is, amelyik a változó típusát adja vissza. A segédfüggvényt a basic.oob fájlba (verzió: 0.0.5) írjuk:
oob_getDeclare() { # input variable name # result: code (declare string for variable as global)
local t decl; eval t=\${$1@a} decl="\${$1[@]@A}" # get type and value of the variable
[[ $decl == *=* ]] && decl="=${decl#*=}" || decl="" # detect if variable was only declared but not used
code="declare -g$t $1$decl" # create and save definition command
} # oob_getDeclare()Az oob_getDeclare segédfüggvény az argumentumában megadott névhez tartozó változó típusát elhelyezi a t, a lekérdezett parancsot a decl helyi változóba. Mivel itt is egymásba ágyazott indirekt változónevekről van szó, a lekérdezést az eval parancson belül hajtjuk végre. Alhéj indítása helyett így két értékadó utasítással kérdeztük le az információkat. Ezután megvizsgáljuk, hogy a decl helyi változó tartalmaz-e egyenlőségjelet. Ha nem, akkor a lekérdezett változó csak deklarálva volt, de értéket még nem kapott. Az információk birtokában ezután összeállítjuk annak a parancsnak a kódját, amellyel létre lehet hozni a változót az aktuális értékkel, de globális változóként. Az így megkonstruált parancsot szövegként elmentjük a code változóba.
A kódot kiíró parancs
Ez a parancs két részből áll a basic.oob fájlban (verzió: 0.0.6). Először az érdemi részt írjuk meg:
oob_getObjectsAndClassesCode() { # environment: mode=[-odmc] # input: object names # displays code of objects, data or methods
local i dobj; local -A classes
for i; do # one object
dobj=d$i; local -n dc_d=dc_${!dobj}_d dc_m=dc_${!dobj}_m; classes+=( [${!dobj}]=${!dobj} ) # get class descriptors
case $mode in *o*) echo "$dobj=${!dobj}";; esac # show descriptor of object
case $mode in *d*) for t in ${!dc_d[@]}; do oob_getDeclare ${dobj#d}_$t; echo "$code"; done;; esac
case $mode in *m*) for t in ${!dc_m[@]}; do code="$(type ${dobj#d}_$t)"; echo "${code#*$'\n'}"; done;; esac
echo "" # empty line between objects
done # one object
case $mode in *c*) # display classes
echo "# classes"; for i in ${classes[@]}; do # one class
echo "" # empty line between classes
eval code="\${dc_${i}_d[@]@A}"; echo "${code/-/-g}" # display data descriptor of the class
eval code="\${dc_${i}_m[@]@A}"; echo "${code/-/-g}" # display method descriptor of the class
done # one class
;; esac # display classes
} # oob_getObjectsAndClassesCode()A parancs egyesével feldolgozza az argumentumokat, azaz a classes asszociatív tömbbe elmenti az objektumleírókban tárolt számot (az osztályok azonosító számát) és kiírja az opciókban meghatározott kódokat. Az adattagok kódjának kiírása az oob_getDeclare segédfüggvény által kitöltött code váltózó kiírása. A metódusok kiírásához a type belső parancsot használjuk úgy, hogy a kapott szövegből eltávolítjuk az első sort, az ugyanis nem a kódot tartalmazza, hanem magyarázó sor.
Ha be van kapcsolva a c opció, ezután a classes tömb elemeinek feldolgozása következik egyesével. Mivel a classes tömb associatív, így minden osztályazonosító csak egyszer szerepel benne. A parancs az oob_getDeclare segédfüggvényben megismert módszerrel előállítja az osztály leírókat létrehozó parancsot és kiírja. Nincs szükség a segédfüggvény alkalmazására, mert ismerjük a leírók típusát és biztosak lehetünk benne, hogy van értékük is. (Ez alól a gyökérobjektum lenne kivétel, azonban azt az oob_filter segédfüggvény soha nem listázza.)
Most megírjuk a felhasználói interfészt:
oob_code() { # input: [-odmc] object-patterns # displays code of objects, data or methods
local i dobj t mode="-odmc" all code; local -A classes; local -a oob_LSS
[[ $1 == -?* ]] && mode=$1 && shift; [[ -z $* ]] && all="o_@"; oob_lss $all $@ # list all objects and roles
oob_getObjectsAndClassesCode ${oob_LSS[@]} # get code of objects and classes
} # oob_code()Ha a parancs első argumentuma kötőjellel kezdődik, akkor az opció. Ha az opció tartalmazza az o betűt, akkor kiírja az objektumleírókat, ha a d betűt, akkor az adattagokat, ha az m betűt, akkor a metódusokat, ha a c betűt, akkor az osztályleírókat. Ha nem adunk meg opciót, akkor az egyenértékű az -odmc opcióval. Ha nem adunk meg mintát, akkor az összes objektumot megkeresi. Az objektumnevek megkereséséhez és a duplikátuok kiszűréséhez oob_lss parancsot használjuk és a visszaadott oob_LSS tömböt használjuk az oob_getObjectsAndClasses segédfüggvény argumentumaiként.
A teszteléshez átírjuk a develop.sh fájl ## run szakaszát:
## run
main() { oob_code $@; o_star_planet4_moon1_sayHello; }
: set -x; main "$@"; set +xA kód exportálása
Az oob_code parancsot arra is felhasználhatjuk, hogy az objektumokat, a tagokat és az osztályokat kiírjuk egy fájlba. Ezt a fájlt később egy szkriptbe betöltve tovább alakíthatjuk az objektumokat és szerepeket. Irassuk ki a komponenseket egy fájlba. Módosítsuk a develop.sh fájl ## run szakaszát:
## run
main() { oob_code > $HOME/user-objects; }
: set -x; main "$@"; set +xHajtsuk végre a develop.sh szkriptet! A képernyőre nem ír ki semmit. Most írjunk a saját könyvtárunkba egy futtatható fájlt run.sh néven a teszteléshez:
#!/usr/bin/env bash ## load objects source $HOME/user-objects ## run main() { o_star_planet4_moon1_sayHello; } : set -x; main "$@"; set +x
Ha most ezt lefuttatjuk, láthatjuk, hogy jól működnek a metódusok. Figyeljük meg a run.sh shebang-ját: a bash parancsértelmezőt hívja, nem az oob értelmezőt. A teszteléshez mostantól ehhez hasonló parancssort is használhatunk:
~/develop.sh; ~/run.sh
A metódusok futtatásához és az adattagok kezeléséhez nem szükséges az objektumok kiírása, így tovább egyszerűsíthetjük az exportálást. Módosítsuk a develop.sh fájl ## run szakaszát úgy, hogy csak a szükséges objektum adattagját és metódusait írjuk ki:
## run
main() { oob_code -dm o_star_planet4_moon1 > $HOME/user-objects; }
: set -x; main "$@"; set +xE módszerrel a program futását könnyen gyorsíthatjuk: Előre megírjuk az objektumokat, kiválogatjuk közülük a program futásához szükségeseket és a tagjaikat exportáljuk egy fájlba. A program használatakor csak ezt a fájlt töltjük be és máris munkára foghatóak a metódusok és adattagok.
Az oob_code parancs másik hasznos felhasználása a beállítófájlok készítése és használata, valamint a program állapotának elmentése és egy későbbi időpontban történő folytatása. Ezt az teszi lehetővé, hogy a kód exportálása az objektumok állapotát (az adattagjaiknak értékét) is menti. E felhasználási mód és a hatékony hibakeresés érdekében választottuk azt a megoldást, hogy az adattagok és a metódusok futó kódját kérdezzük le, ahelyett, hogy a valamivel gyorsabb eljárást, a leírókból való előállítást alkalmaznánk.