Műveletek objektumokkal
Szerepek törlése
Ha ki tudjuk listázni az objektumokat, akkor törölni is tudjuk azokat. Megírjuk az objektumok törlése parancsot a basic.oob fájlba (verzió: 0.0.7):
oob_rm() { # input: name of objects # deletes objects and roles of objects
local i dobj t; local -a oob_list rmData rmMethods
for i; do # one pattern
[[ $i == *@(+|@|-)* ]] && { oob_trap "Not an object name:" "$i"; continue; }
oob_filter $i@; # get descriptors of object and its roles
for dobj in ${oob_list[@]}; do # one object
local -n dc_d=dc_${!dobj}_d dc_m=dc_${!dobj}_m # get class descriptors
for t in ${!dc_d[@]}; do rmData+=( ${d#d}_$t ); done
for t in ${!dc_m[@]}; do rmMethods+=( ${d#d}_$t ); done
done # one object
unset -v ${oob_list[@]} ${rmData[@]}; unset -f ${rmMethods[@]} # remove objects
done # one pattern
} # oob_rm()Az oob_rm parancs csak objektumneveket fogad el, egyéb mintákat nem, így a kiegészítő jelek előfordulása esetén meghívja a hibakezelőt. Az objektumnevekhez hozzáfűzi a @ jelet, így biztosítja azt, hogy az oob_filter az objektum és az összes szerepének a leíróit visszaadja. A leírókból elkészíti az adattagok és a metódusok listáját, végül az osztályok kivételével törli az argumentumhoz tartozó összes elemet.
A teszthez átírjuk a develop.sh fájl főmenü szakaszát:
## run
main() { oob_rm o_star_planet4; oob_code > $HOME/user-objects; }
: set -x; main "$@"; set +xObjektumok másolása
Egy objektum másolása
Egy objektum másolása azt jelenti, hogy a másolandó objektumot prototípusként használva az új objektumban létrehozzuk annak metódusait és az adattagokat érték nélkül. Ezt úgy hajtjuk végre, hogy a prototípushoz tartozó osztály leíróiból hozzuk létre a tagokat. Az ezt végrehajtó utasítást a basic.oob fájlba (verzió: 0.0.8) írjuk meg:
oob_cpOneObject() { # input: new proto # copy one object or role
[[ $1 == $2 ]] && return; local i dnew=d$1 downer=d${1%_*} dproto=d$2
[[ -v $dnew ]] && { oob_trap "New object already exists:" "$1"; return 1; }
[[ -v $downer ]] || { oob_trap "Owner object not exists:" "${downer#d}"; return 1; }
local -n dc_d=dc_${!dproto}_d dc_m=dc_${!dproto}_m # get class descriptors
for i in ${!dc_d[@]}; do declare ${dc_d[$i]} ${1}_$i; done # create data for new object
for i in ${!dc_m[@]}; do eval ${1}_$i '()' "${dc_m[$i]}"; done # create methods for new object
declare -g $dnew=${!dproto} # set descriptor for new object
} # oob_cpOneObject()A parancs két argumentuma az új és a prototípus objektum neve. Ha ez a kettő azonos, akkor nyilván nincs teendő, a parancs azonnal visszatér. Ha az új objektum már létezik, akkor a parancs hibaágra fut. Akkor is hibaágra fut, ha az új objektum szerepgazdája nem létezik. Így kerüljük el az "árva" szerepek létrejöttét. A felső szintű objektumok szerepgazdája a gyökérobjektum, azt a basic.oob fájl első programsorában már definiáltuk. A parancs utolsó három sorában rendre létrehozzuk az adattagokat, a metódusokat, végül az objektumleírót.
Az utasítás nem ellenőrzi az objektumnevek megfelelőségét, de erre nincs is szükség, ha az utasítást egy olyan parancsból hívjuk meg, amely az ellenőrzést elvégzi. Másik parancsot meg írunk, ugyanis kényelmes, ha egész objektumstruktúrákat is tudunk másolni.
Objektumok és szerepeik másolása
Ennek a parancsnak minden argumentuma <létező objektum>_=<minta> vagy <új objektum>=<minta> alakú. Az első esetben a másolandó objektumok a létező objektum szerepei lesznek és a minta az oob_filter bármelyik mintája lehet. A második esetben az új objektum a másolás során jön létre és ezért az csak azokkal a mintákkal használható, amelyek definíció szerint egy objektumot vagy egy objektumot és annak szerepeit adják viszza.
A parancsot a basic.oob fájlba (verzió: 0.0.9) írjuk meg:
oob_cp() { # input: new=proto... # copy objects (and roles of objects)
local i dobj o new proto ref; local -a oob_list
for i; do # one copy from proto
[[ ${i%=*} =~ ^o_[0-9a-zA-Z_]+$ ]] || { oob_trap "New object syntax error:" "$i"; continue; }
new=${i%=*} new=${new%_} proto=${i#*=}
case $i in # select type of copy
*_=*_-|*_=*_+|*_=*_@) ref=${proto%_*};; # copy roles under object
*_=*) ref=${proto%_*};; # copy object (and roles) under object
*=*-|*=*_-|*=*_+|*=*_@) oob_trap "Multiple prototype objects definition:" "$proto"; continue;;
*) ref=${proto%+} ref=${ref%@};; # copy object (and roles) to object
esac # select type of copy
oob_filter $proto && for dobj in ${oob_list[@]}; do o=${dobj#d}; oob_cpOneObject ${o/$ref/$new} $o; done
done # one copy from proto
} # oob_cp()A parancs sorban végrehajtja az argumentumaiban előírt másolást. Először szintaktikailag ellenőrzi a célt, majd az argumentum alakja alapján meghatározza a másolás típusát (és hibára fut ellentmondásos típus esetén), valamint a referenciát. Ezután az oob_filter által visszaadott objektumnév listából a referencia kicserélésével darabonként meghívja az oob_cpOneObject utasítást.
Az ellenőrzéshez lecseréljük a develop.sh fájl teljes tartalmát:
#!/usr/bin/env oob ## objects do_star=1 # attributes declare -gA o_star_info=([name]=Sun ) # methods o_star_getName() { local self=${FUNCNAME%_*}; local -n self_info=${self}_info; :; echo "${self_info[name]}"; } o_star_sayHello() { local self=${FUNCNAME%_*}; local -n self_info=${self}_info; :; echo "Hello $(${self}_getName)!"; } ## classes declare -gA dc_1_d=( [info]="-gA" ) declare -gA dc_1_m=( [sayHello]='{ local self=${FUNCNAME%_*}; local -n self_info=${self}_info; :; echo "Hello $(${self}_getName)"; }' [getName]='{ local self=${FUNCNAME%_*}; local -n self_info=${self}_info; :; echo "${self_info[name]}"; }' ) ## run main() { oob_cp o_star_moon1=o_star o_star_moon2=o_star o_star_planet4=o_star@ o_star_planet4_moon1_=o_star_moon- oob_lss o_star_moon-; oob_rm ${oob_LSS[@]} o_star_planet4_moon1_info=( [name]=Phobos ) oob_code o_star_planet4_moon1@ oob_code -dm o_star_planet4_moon1 > $HOME/user-objects } : set -x; main "$@"; set +x
A másolást végző utasítássor szándékosan bonyolult, hogy többféle másolási módban is tesztelhessük a parancsot. A Phobos holdhoz két névtelen műholdat adtunk.
Félidő
Létrehoztunk egy objektum és szereporientált kiegészítést a bash parancsértelmezőhöz. Az osztályra épülő prototípusból új objektumokat és szerepsruktúrákat készíthetünk és ezeket a struktúrákat egyetlen utasítással tudjuk másolni is. A struktúrák átnevezése is megoldható az oob_cp és az oob_rm utasításokkal. Mivel az alapvető objektumkezelő parancsokat megírtuk, a basic.oob fájl verziószámában a köztes értéket megemeljük:
#
# OOB internal
# basic.oob, version 0.1.0
# https://oob.xport.hu
# basic commands for Object Oriented BashAzonban még mindig sok adminisztrációs adatot kell beírjunk egy prototípus és osztály létrehozásakor. A következő fejezetekben minimalizáljuk az adminisztrációs adatok kézi beírását.