OOB: Objektumok bash parancsértelmezőben

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 +x

Objektumok 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 Bash

Azonban 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.

1 2 3 4 5 6 7 8 9