Давеча наткнулся на
весьма интересную реализацию псевдо-ООП на баше. Идея вельми остроумна, но чуть-чуть погоняв ее, возникла мысль - а почему бы не посовершенствовать ее (Подразумевается, что вышеуказанная статья уже прочитанна, и понята). Итак:
Для начала совершенно непонятно на кой ляд автору понадобились отдельные файлы obj.h и obj.class (для большего уподобления разве что?). Тайна сия велика есть, посему попробуем обойтись без них:
########################################################################
#/bin/bash
obj() {
. <(sed "s/obj/$1/g" <<< '
obj_properties=()
# properties IDs
fileName=0
fileSize=1
obj.method1(){
echo obj method1 called
}
obj.property(){
if [ "$2" == "=" ]
then
obj_properties[$1]=$3
else
echo ${obj_properties[$1]}
fi
}
obj.fileName(){
if [ "$1" == "=" ]
then
obj.property fileName = $2
else
obj.property fileName
fi
}
')
}
obj myobj1
obj myobj2
########################################################################
Проверяем в дебаггере
########################################################################
[13:04] bash -x oop.sh
+ obj myobj1
+ . /dev/fd/63
++ sed s/obj/myobj1/g
++ myobj1_properties=()
++ fileName=0
++ fileSize=1
+ obj myobj2
+ . /dev/fd/63
++ sed s/obj/myobj2/g
++ myobj2_properties=()
++ fileName=0
++ fileSize=1
########################################################################
Вуаля, работает. Только вспомним строки из исходной статьи: "Тут есть один момент: для разных классов нельзя использовать разные значения индексов со свойствами, имеющими одинаковые названия, поскольку это может привести к некорректной работе скрипта.". Так почему бы нам не сделать уникальные "properties IDs" для каждого псевдо-класса, тем паче все равно перед инклюдом мы sedом меняем "obj" на имя псевдо-класса. Да и обьявлять их заново при создании каждого обьекта нужды особой нет.
Итак версия 2, дополненная:
########################################################################
#/bin/bash
our_class_name() {
. <(sed "s/obj/$1/g" <<< '
obj_properties=()
# properties IDs
if [[ ! "$our_class_name_IDs" ]]; then
our_class_name_IDs=1
our_class_name_fileName=0
our_class_name_fileSize=1
fi
obj.method1(){
echo obj method1 called
}
obj.property(){
if [ "$2" == "=" ]
then
obj_properties[$1]=$3
else
echo ${obj_properties[$1]}
fi
}
obj.fileName(){
if [ "$1" == "=" ]
then
obj.property our_class_name_fileName = $2
else
obj.property our_class_name_fileName
fi
}
')
}
our_class_name myobj1
our_class_name myobj2
########################################################################
Выхлоп:
########################################################################
[13:14] bash -x oop.sh
+ our_class_name myobj1
+ . /dev/fd/63
++ sed s/obj/myobj1/g
++ myobj1_properties=()
++ [[ ! -n '' ]]
++ our_class_name_IDs=1
++ our_class_name_fileName=0
++ our_class_name_fileSize=1
+ our_class_name myobj2
+ . /dev/fd/63
++ sed s/obj/myobj2/g
++ myobj2_properties=()
++ [[ ! -n 1 ]]
########################################################################
Вуаля. Переменные обьявляются один раз и можно не беспокоиться на тему одинаковых названий свойств.
А теперь попробуем методы:
########################################################################
# добавим в конец скрипта
myobj1.fileName = "FirstName"
myobj2.fileName = "Long name of 2nd object"
myobj1.fileName
myobj2.fileName
########################################################################
Выхлоп:
########################################################################
[13:22] bash oop.sh
FirstName
Long
########################################################################
О-па! За кулисами что-то пошло не так. А если использовать не "", а ''?
########################################################################
[13:22] bash oop.sh
FirstName
Long
########################################################################
Безрезультатно. А вампир то зарыт в незакавыченных $1, $2 и так далее.
Версия третья исправленная:
########################################################################
#/bin/bash
our_class_name() {
. <(sed "s/obj/$1/g" <<< '
obj_properties=()
# properties IDs
if [[ ! "$our_class_name_IDs" ]]; then
our_class_name_IDs=1
our_class_name_fileName=0
our_class_name_fileSize=1
fi
obj.method1(){
echo "obj method1 called"
}
obj.property(){
if [ "$2" == "=" ]
then
obj_properties["$1"]="$3"
else
echo "${obj_properties["$1"]}"
fi
}
obj.fileName(){
if [ "$1" == "=" ]
then
obj.property our_class_name_fileName = "$2"
else
obj.property our_class_name_fileName
fi
}
')
}
our_class_name myobj1
our_class_name myobj2
our_class_name myobj3
myobj1.fileName = 'FirstName'
myobj2.fileName = 'Long name of 2nd object'
myobj3.fileName = "Long name of 3rd object"
myobj1.fileName
myobj2.fileName
myobj3.fileName
########################################################################
Выхлоп:
########################################################################
[13:31] bash oop.sh
FirstName
Long name of 2nd object
Long name of 3rd object
########################################################################
[13:31] bash -x oop.sh
+ our_class_name myobj1
+ . /dev/fd/63
++ sed s/obj/myobj1/g
++ myobj1_properties=()
++ [[ ! -n '' ]]
++ our_class_name_IDs=1
++ our_class_name_fileName=0
++ our_class_name_fileSize=1
+ our_class_name myobj2
+ . /dev/fd/63
++ sed s/obj/myobj2/g
++ myobj2_properties=()
++ [[ ! -n 1 ]]
+ our_class_name myobj3
+ . /dev/fd/63
++ sed s/obj/myobj3/g
++ myobj3_properties=()
++ [[ ! -n 1 ]]
+ myobj1.fileName = FirstName
+ '[' = == = ']'
+ myobj1.property our_class_name_fileName = FirstName
+ '[' = == = ']'
+ myobj1_properties["$1"]=FirstName
+ myobj2.fileName = 'Long name of 2nd object'
+ '[' = == = ']'
+ myobj2.property our_class_name_fileName = 'Long name of 2nd object'
+ '[' = == = ']'
+ myobj2_properties["$1"]='Long name of 2nd object'
+ myobj3.fileName = 'Long name of 3rd object'
+ '[' = == = ']'
+ myobj3.property our_class_name_fileName = 'Long name of 3rd object'
+ '[' = == = ']'
+ myobj3_properties["$1"]='Long name of 3rd object'
+ myobj1.fileName
+ '[' '' == = ']'
+ myobj1.property our_class_name_fileName
+ '[' '' == = ']'
+ echo FirstName
FirstName
+ myobj2.fileName
+ '[' '' == = ']'
+ myobj2.property our_class_name_fileName
+ '[' '' == = ']'
+ echo 'Long name of 2nd object'
Long name of 2nd object
+ myobj3.fileName
+ '[' '' == = ']'
+ myobj3.property our_class_name_fileName
+ '[' '' == = ']'
+ echo 'Long name of 3rd object'
Long name of 3rd object
########################################################################
Вот это уже на что-то похоже. И работает с обоими типами кавычек.
С sedом кстати тоже есть некая подлянка - не приведи Кришна в тексте псевдо-класса будет что-то типа 'obj' (например переменная $objective) - sed переименует ее в имя обьекта, и в результате н-ное количество веселья с переменной $myobj1ective гарантировано. Посему лучше все-таки длинное имя с претензией на уникальность:
########################################################################
#/bin/bash
our_class_name() {
. <(sed "s/our_object_name/$1/g" <<< '
our_object_name_properties=()
# properties IDs
if [[ ! "$our_class_name_IDs" ]]; then
our_class_name_IDs=1
our_class_name_fileName=0
our_class_name_fileSize=1
fi
our_object_name.method1(){
echo "our_object_name method1 called"
}
our_object_name.property(){
if [ "$2" == "=" ]
then
our_object_name_properties["$1"]="$3"
else
echo "${our_object_name_properties["$1"]}"
fi
}
our_object_name.fileName(){
if [ "$1" == "=" ]
then
our_object_name.property our_class_name_fileName = "$2"
else
our_object_name.property our_class_name_fileName
fi
}
')
}
our_class_name myobj1
our_class_name myobj2
our_class_name myobj3
myobj1.fileName = 'FirstName'
myobj2.fileName = 'Long name of 2nd object'
myobj3.fileName = "Long name of 3rd object"
myobj1.fileName
myobj2.fileName
myobj3.fileName
########################################################################
Тоже, конечно, не панацея, но встретить переменную в имени которой есть 'our_object_name' сильно сложнее чем с 'obj'.
На всякий пожарный уточним - то что перед практическим использованием "our_class_name" меняется на имя класса, подразумевается.
Продолжение тут