Бу: ООП в bash
ООП к «башу» приделать и до меня пытались, ничего в этом смысле нового, но мне ни одна реализация не нравится, из того, что я видел, всё примитивное и синтаксис кривой, всё время хотелось свою сделать. Вчера вечером заморочился, думал на выходных что-то дописывать буду, не хотел никуда выкладывать, но чуть случайно не стёр основной файл и решил, что пора выложить на «Гитхаб» от вреда подальше.
Долго мучался с названием, решил, что пусть пока называется «Бу» (b-oo.sh), выложил туда же пример на котором вчера тестировал:
#!/bin/bash
# Evgeny.Stepanischev Jan 2013 /
. b-oo.sh
@Class Base
@Dim cnt
@Dim
__construct() {
This[cnt]=0
}
@Dim
IncCnt() {
let 'This[cnt]++'
}
@Dim
GetCnt() {
[ "$This[cnt]" -gt 1 ] && s=s
echo $Self said $This[cnt] time$s
}
@End
@Class Dog Base
@Dim
say() {
$This.IncCnt
echo 'Bow-wow!'
}
@End
@Class Car Base
@Dim
say() {
$This.IncCnt
echo 'Beep'
}
@End
@Class Proxy
@Dim obj
@Dim Static
getInstance() {
$1.New Self[obj]
@Ret $2 $Self[obj]
}
@End
Proxy.getInstance Car car # создание через «фабрику», через статический метод
Proxy.getInstance Dog dog # создание через «фабрику», через статический метод
$car.say
$car.say
$car.GetCnt # 2, вызывается из родительского класса
$dog.say
$dog.GetCnt # 1, вызывается из родительского класса
Dog.New anothedog # создание через конструктор
$anothedog.say
$anothedog.say
$anothedog.GetCnt # 2, вызывается из родительского класса
Я не стал заморачиваться с модификаторами доступа (хотя может ещё и сделаю), из реализованного: создание объектов, наследование (есть множественное), статические и динамические методы и свойства, конструктор, есть переменная This (текущий объект), Self (текущий класс) и Parent (чтобы вызывать родительские методы).
Всё делается при помощи вызовов, начинающихся с собачки. Вряд ли синтаксис кого-то поставит в тупик, но есть несколько важных замечаний.
Во-первых, «@Dim», определящий свойства должен находиться на той же строке, что и имя свойства, а в случае метода имя метода должно быть записано на следующей строке (смотрите пример).
Во-вторых, в шеле всё уныло с передачей значения в переменную, обычные способы чаще всего создают так называемый «сабшел», поэтому передать значение в переменную следующим образом не получится:
# !неправильно
obj=$(Dog.New)
obj=`Dog.New`
Чтобы выполнить Dog.New интерпретатор создаёт отдельный процесс, где всё и выполняется, после выхода из этого процесса всё моё колдунство исчезает и от переданного значения толку нет (если у вас не «баш 4», тогда есть способы).
Поэтому конструктор у меня принимает первым параметром имя переменной, куда нужно положить экземпляр класса, а облегчения жизни программисту сделана специальная команда «@Ret», посмотрите как она используется в методе getInstance.
Естественно, в глобальном пространстве создаётся куча всякой магии, но у всего этого есть свои префиксы.
Господи, боже мой.
А что нельзя сделать на баше?
Комментарий для http://malfer.mu:
Легко и приятно программировать без напряга нельзя :) Язык с миллионом особенностей :)