staging.inyokaproject.org

Objektorientierte Bash-Skripte

Status: Ungelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

domachine

Anmeldungsdatum:
16. Mai 2007

Beiträge: 562

Hallo Ubuntuusers,

mir ist heute in der Uni eine irrwitzige Idee gekommen und sie hat mich schlicht nicht mehr losgelassen 😀. Und zwar dacht ich mir, dass es doch möglich sein muss (mit eval), der Bash (zumindest pseudo-mäßige) Objektorientierung beizubringen. Ob das ganze nun sinnvoll ist oder nicht, war mir erst einmal egal. Es ging mir rein ums Prinzip 😀. Naja ich hab mich dann auch gleich zu Hause hingesetz und angefangen. Ich will euch hier einfach mal gern das Resultat servieren.

Der Header, der das ganze implementiert sieht so aus:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/bash

# Oobash is a module which makes it possible to write
# pseudo-object-oriented bash-scripts.

# Copyright (C) 2010 Dominik Burgdörfer <dominik.burgdoerfer@googlemail.com>

# Oobash is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Oobash is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with oobash.  If not, see <http://www.gnu.org/licenses/>.



declare -A __OOB_OBJ_TABLE
declare -A __OOB_ADDR_TABLE


# Create new object without registering it in the object table.

# Arguments:
#    * unique objectname
#    * variable name to export object name to
#    * member declarations ...
new_metaobject()
{
    local OBJ_NAME=$1
    shift

    local VARNAME=$1
    shift

    while ! [[ -z $1 ]]; do
        if [[ $1 == "function" ]]; then
            eval "$OBJ_NAME.$2() { $3 $OBJ_NAME \"\$@\"; }"
        elif [[ $1 == "var" ]]; then
            eval ${OBJ_NAME}_$2=$3
            eval "$OBJ_NAME.$2() { echo \"\$${OBJ_NAME}_$2\"; }"
            eval "$OBJ_NAME.set_$2() { ${OBJ_NAME}_$2=\$1; }"
        fi
        shift 3
    done

    eval $VARNAME=$OBJ_NAME
}


# Create new object and register it in the object table

# Arguments:
#    * Variable name of the class array
#    * Variable name to export object name to
#    + (optional) arguments to constructor.
new()
{
    local CLASS=$1
    shift

    local VARNAME=$1
    shift

    local i

    # Increment class id number.
    if [[ -z ${__OOB_OBJ_TABLE[$CLASS]} ]]; then
        __OOB_OBJ_TABLE[$CLASS]=1
    else
        ((__OOB_OBJ_TABLE[$CLASS] += 1))
    fi


    # Generate unique object-name.
    local OBJ_NAME="${CLASS}_Object_id_${__OOB_OBJ_TABLE[$CLASS]}"

    # Register object-name.
    __OOB_ADDR_TABLE[$CLASS]="${__OOB_ADDR_TABLE[$CLASS]}:$OBJ_NAME:"


    # Create new object.
    eval new_metaobject $OBJ_NAME $VARNAME \"\${$CLASS[@]}\"

    # Call constructor.
    [[ $(type -t $OBJ_NAME.__new__) == function ]] && $OBJ_NAME.__new__ "$@"
}


# Deletes All references to the object
# and calls the destructor if it exists.

# Arguments:
#    * A reference to an object
delete()
{
    local CLASSNAME=$(echo $1|sed -r 's/_Object_id_[0-9]+$//')

    __OOB_ADDR_TABLE[$CLASSNAME]=$(echo "${__OOB_ADDR_TABLE[$CLASSNAME]}"|sed -r "s/:$1://")

    if [[ -z ${__OOB_ADDR_TABLE[$CLASSNAME]} ]]; then
        unset __OOB_ADDR_TABLE[$CLASSNAME]
    fi

    # Check for destructor and call it if one is existent.
    [[ $(type -t $1.__delete__) == function ]] && $1.__delete__
}


# Deletes all references to the objects of all or
# specific classes.

# Arguments:
#    + (optional) Classnames ...
delete_all()
{
    local i
    local j

    if [[ -z $1 ]]; then
        # Loop through all registered objects and delete them
        for i in "${__OOB_ADDR_TABLE[@]}"; do
            local a=$(echo "$i"| \
                awk 'BEGIN { RS = ":+" } /^.+$/ {print $1" "}')

            for j in $a; do
                delete $j
            done
        done
    else
        for i; do
            local str=${__OOB_ADDR_TABLE[$i]}
            local a=$(echo "$str"| \
                awk 'BEGIN { RS = ":+" } /^.+$/ {print $1" "}')

            for j in $a; do
                delete $j
            done
        done
    fi
}

Um mal die Benutzung zu demonstrieren, hier ein Code-Schnippsel, der so eine Bash-Klasse implementiert:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
source oobash.sh

## class Person
# Definition der Methoden funktionen, die in der Metatable
# dann in Methoden umgewandelt werden.
Person_new()
{
    local self=$1
    shift

    $self.set_name "$1"
}


Person_delete()
{
    echo "Destructor for $($1.name) called"
}


Person_say_hello()
{
    # Get self reference.
    local self=$1

    shift
    
    echo "$self: Hello my name is $($self.name)"
}


# Class metatable
Person=(
    # Constructor
    function __new__ Person_new

    function __delete__ Person_delete

    # Methoden-deklaration: say_hello
    function say_hello Person_say_hello

    # member variable: name
    # Die inneren Hochkommata sind wichtig!
    # Für jede member-variable wird je ein getter
    # und ein setter generiert.
    var name "'Default value'"
)

## end of class Person


# "Instantiierung" zweier Objekte der "Klasse" Person
# Hierdurch wird die Methode __new__ des Objektes (also die Funktion Person_new)
# mit
# einer "Referenz" des Objektes und den mitgegebenen Argumenten aufgerufen.
new Person person "Dominik"
new Person person2 "Max Mustermann"

# Hier wird jeweils die verknüpfte Funktion aufgerufen,
# mit einer "Referenz" auf das Objekt als erstes Argument.
# Alle restlichen Argumente werden hinten angestellt.
$person.say_hello
$person2.say_hello

# Neuen Namen setzen
$person.set_name "Fritz Nochwas"

$person.say_hello

echo "Der Name von \$person ist: $($person.name)"
# Alle angelegten Objekte werden "zerstört".
# Sprich alle Destruktoren werden aufgerufen (__delete__-methoden)
delete_all

Ich hoffe die Code-Kommentierung reicht fürs erste aus. Bash-erfahrung ist natürlich nötig.

Wollte einfach nur mal hören, was ihr dazu meint, Gruß Domi

JuergenF

Anmeldungsdatum:
22. Oktober 2004

Beiträge: 2009

Ich mag 'irrwitzige' Ideen, v.A. wenn dann noch eine Beispiel-Implementation kommt ☺

Aber ich denke dennoch, wenn Bash-Scripts so kompliziert werden, dass sie OOP-Überlegungen anregen, sollte man sie gleich lieber in einer der vorhandenen OO-Sprachen schreiben (Python wird ja z.B. auch gerne in Ubuntu-Scripts (und nicht nur bei Ubuntu) benutzt).

domachine

(Themenstarter)

Anmeldungsdatum:
16. Mai 2007

Beiträge: 562

JuergenF schrieb:

Ich mag 'irrwitzige' Ideen, v.A. wenn dann noch eine Beispiel-Implementation kommt ☺

Aber ich denke dennoch, wenn Bash-Scripts so kompliziert werden, dass sie OOP-Überlegungen anregen, sollte man sie gleich lieber in einer der vorhandenen OO-Sprachen schreiben (Python wird ja z.B. auch gerne in Ubuntu-Scripts (und nicht nur bei Ubuntu) benutzt).

Da hast du auf jeden Fall recht. Trotzdem ist das Einsatzgebiet von Bash-Skripten groß (Bei Arch-Linux zum Beispiel, wird sehr sehr viel damit gelöst, sogar netzwerktechnische Dinge).

Außerdem ist mir gestern Nacht eine echte Einsatzmöglichkeit für das OOP eingefallen. Schau dir mal folgende Wrapper-klasse für mktemp an:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
source oobash.sh


Tempfile_new()
{
    local self=$1
    shift

    $self.set_name "$(mktemp)"
}


Tempfile_delete()
{
    local self=$1
    shift

    echo "Delete temporary file: $($self.name)"
    rm -f "$($self.name)"
}

## class Tempfile
Tempfile=(
    # Constructor.
    function __new__ Tempfile_new

    # Destructor.
    function __delete__ Tempfile_delete

    # member: name
    var name '(null)'
)

# Make sure to delete all objects at end of program
trap 'delete_all' TERM EXIT INT

new Tempfile tmp
echo "\$tmp.name: $($tmp.name)"

# Do something with your temporary file ...

Ich finde sowas irgendwie schon cool und praktisch. Klar, ma könnte das auch über einen normalen Signal-Handler lösen, aber das mit dem delete_all, macht das ganze irgendwie aufgeräumt, finde ich. Vorallem, wenn man zum Beispiel mehrere temporäre Dateien verwendet und sichergehen will, dass die alle am Ende wieder gelöscht werden. Solche Dateischiebereien sind für Bash-Skripte nicht unüblich. Ich glaube da liegt potential für OOP. Naja so oder so, ich fands einfach nur cool 😀.

Gruß Domi

philluder

Anmeldungsdatum:
12. Januar 2011

Beiträge: Zähle...

Hallo,

kannst Dir ja auch mal folgendes Konstrukt ansehen: http://sourceforge.net/projects/oobash/files/

Grüsse Andreas

domachine

(Themenstarter)

Anmeldungsdatum:
16. Mai 2007

Beiträge: 562

philluder schrieb:

Hallo,

kannst Dir ja auch mal folgendes Konstrukt ansehen: http://sourceforge.net/projects/oobash/files/

Grüsse Andreas

Das find ich jetzt erstens fast schon wieder übertrieben und zweitens kann man da ja gar keine eigenen Klassen schreiben, sondern nur vorhandene nutzen.

BTW, hab meins noch etwas verfeinert.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#!/bin/bash

# Oobash is a module which makes it possible to write
# pseudo-object-oriented bash-scripts.

# Copyright (C) 2010 Dominik Burgdörfer <dominik.burgdoerfer@googlemail.com>

# Oobash is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Oobash is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with oobash.  If not, see <http://www.gnu.org/licenses/>.



declare -A __OOB_OBJ_TABLE
declare -A __OOB_ADDR_TABLE


# Create new object without registering it in the object table.

# Arguments:
#    * unique objectname
#    * variable name to export object name to
#    * member declarations ...
new_metaobject()
{
    echo "new_metaobject: This function is deprecated. Use new_metaobject2" >&2

    local OBJ_NAME=$1
    shift

    local VARNAME=$1
    shift

    while ! [[ -z $1 ]]; do
        if [[ $1 == "function" ]]; then
            eval "$OBJ_NAME.$2() { $3 $OBJ_NAME \"\$@\"; }"
        elif [[ $1 == "var" ]]; then
            eval ${OBJ_NAME}_$2=$3
            eval "$OBJ_NAME.$2() { echo \"\$${OBJ_NAME}_$2\"; }"
            eval "$OBJ_NAME.set_$2() { ${OBJ_NAME}_$2=\$1; }"
        fi
        shift 3
    done

    eval $VARNAME=$OBJ_NAME
}


# Create new object without registering it in the object table.

# Arguments:
#    * unique objectname
#    * variable name to export object name to
#    * member declarations ...
new_metaobject2()
{
    local OBJ_NAME=$1
    shift

    local CLASS=$1
    shift

    local VARNAME=$1
    shift

    local SHIFT
    local VALUE_FIELD
    local CLASS_FIELDS=1

    while ! [[ -z $1 ]]; do
        if [[ $3 == "=" ]]; then
            SHIFT=4
            VALUE_FIELD=$4
        else
            SHIFT=2
            VALUE_FIELD=  # empty
        fi

        if [[ $1 == "function" ]]; then
            [[ -z $VALUE_FIELD ]] && VALUE_FIELD=${CLASS}::$2
            eval "$OBJ_NAME.$2() { $VALUE_FIELD $OBJ_NAME \"\$@\"; }"
        elif [[ $1 == "declare" ]]; then
            eval ${OBJ_NAME}_$2=$VALUE_FIELD
            eval "$OBJ_NAME.$2() { echo \"\$${OBJ_NAME}_$2\"; }"
            eval "$OBJ_NAME.set_$2() { ${OBJ_NAME}_$2=\$1; }"
        else
            echo -e "oobash: Syntax error in class-field $CLASS_FIELDS in class $CLASS,
\texpected function or declare keyword" >&2
            return 1
        fi

        (( ++CLASS_FIELDS ))
        shift $SHIFT
    done

    eval $VARNAME=$OBJ_NAME
    return 0
}


# Create new object and register it in the object table

# Arguments:
#    * Variable name of the class array
#    * Variable name to export object name to
#    + (optional) arguments to constructor.
new()
{
    local CLASS=$1
    shift

    local VARNAME=$1
    shift

    local i

    # Increment class id number.
    if [[ -z ${__OOB_OBJ_TABLE[$CLASS]} ]]; then
        __OOB_OBJ_TABLE[$CLASS]=1
    else
        ((__OOB_OBJ_TABLE[$CLASS] += 1))
    fi


    # Generate unique object-name.
    local OBJ_NAME="${CLASS}_Object_id_${__OOB_OBJ_TABLE[$CLASS]}"

    # Register object-name.
    __OOB_ADDR_TABLE[$CLASS]="${__OOB_ADDR_TABLE[$CLASS]}:$OBJ_NAME:"


    # Create new object.
    eval new_metaobject2 $OBJ_NAME $CLASS $VARNAME \"\${$CLASS[@]}\"

    # Call constructor.
    [[ $(type -t $OBJ_NAME.__new__) == function ]] && $OBJ_NAME.__new__ "$@"
}


# Deletes All references to the object
# and calls the destructor if it exists.

# Arguments:
#    * A reference to an object
delete()
{
    local CLASSNAME=$(echo $1|sed -r 's/_Object_id_[0-9]+$//')

    __OOB_ADDR_TABLE[$CLASSNAME]=$(echo "${__OOB_ADDR_TABLE[$CLASSNAME]}"|sed -r "s/:$1://")

    if [[ -z ${__OOB_ADDR_TABLE[$CLASSNAME]} ]]; then
        unset __OOB_ADDR_TABLE[$CLASSNAME]
    fi

    # Check for destructor and call it if one is existent.
    [[ $(type -t $1.__delete__) == function ]] && $1.__delete__
}


# Deletes all references to the objects of all or
# specific classes.

# Arguments:
#    + (optional) Classnames ...
delete_all()
{
    local i
    local j

    if [[ -z $1 ]]; then
        # Loop through all registered objects and delete them
        for i in "${__OOB_ADDR_TABLE[@]}"; do
            local a=$(echo "$i"| \
                awk 'BEGIN { RS = ":+" } /^.+$/ {print $1" "}')

            for j in $a; do
                delete $j
            done
        done
    else
        for i; do
            local str=${__OOB_ADDR_TABLE[$i]}
            local a=$(echo "$str"| \
                awk 'BEGIN { RS = ":+" } /^.+$/ {print $1" "}')

            for j in $a; do
                delete $j
            done
        done
    fi
}

Damit ist der Methodenstil etwas an Perl und C++ angeglichen. Außerdem aussagekräftigere Syntax (ersetzung des Schlüsselwortes var mit declare). Defaultwerte für Variablen sind nun optional und werden mit = eingeleitet (Dasselbe gilt für Methoden). Außerdem ist begrenzte Vererbung möglich.

Der folgende Snippet verdeutlicht das alles wieder mit der Klasse Tempfile, die von der Klasse File abgeleitet wird:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/bin/bash

source oobash.sh


## class File

File=(
    function write = File::write  # Explicit to make inheritance possible.

    # No default value
    declare name
)

## File implementation

File::write()
{
    local self=$1
    shift

    echo "$1" >>"$($self.name)"
}


## class Tempfile

Tempfile=("${File[@]}"  # Inherits File
    # Constructor.
    # No explicit definition so Tempfile::__new__() is used.
    function __new__

    # Destructor.
    function __delete__

    # Specifies whether the file should be deleted after
    # the destruction of the object.
    # Take notice about the default value set with =
    declare delete = 1
)

## Tempfile implementation

Tempfile::__new__()
{
    local self=$1
    shift

    $self.set_name "$(mktemp)"

    [[ -z $1 ]] || $self.set_delete "$1"
}


Tempfile::__delete__()
{
    local self=$1
    shift

    [[ $($self.delete) == 1 ]] && rm -f "$($self.name)"
}


# Make sure to delete all objects at end of program
trap 'delete_all' TERM EXIT INT

new Tempfile tmp

$tmp.write "'Hey dudes'"

cat $($tmp.name)

$tmp.delete
echo "\$tmp.name: $($tmp.name)"

Happy bashing 😀

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7529

Nette Idee.

Benutzen würde ich es allerdings nicht. Irgendwann ist Bash einfach der falsche Schuh.

Raybuntu

Avatar von Raybuntu

Anmeldungsdatum:
18. August 2007

Beiträge: 795

Hallo Domi,

Geile Idee! Für OOP sollte man aber doch dann lieber was anderes nehmen ☺

domachine

(Themenstarter)

Anmeldungsdatum:
16. Mai 2007

Beiträge: 562

Raybuntu schrieb:

Hallo Domi,

Geile Idee! Für OOP sollte man aber doch dann lieber was anderes nehmen ☺

Wie gesagt, war nur ne Schnapsidee, die ich eher aus Interesse als aus praktischen Nutzgedanken heraus, umgesetzt hab. Wollte nur mal sehen ob das möglich ist und ich in der Lage bin es umzusetzen.

Nur der Vollständigkeit halber, noch die letzte Version:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/bin/bash

# Oobash is a module which makes it possible to write
# pseudo-object-oriented bash-scripts.

# Copyright (C) 2010 Dominik Burgdörfer <dominik.burgdoerfer@googlemail.com>

# Oobash is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Oobash is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with oobash.  If not, see <http://www.gnu.org/licenses/>.



declare -A __OOB_OBJ_TABLE
declare -A __OOB_ADDR_TABLE


# Create new object without registering it in the object table.

# Arguments:
#    * unique objectname
#    * class name
#    * variable name to export object name to
#    * member declarations ...
new_metaobject()
{
    local OBJ_NAME=$1
    shift

    local CLASS=$1
    shift

    local VARNAME=$1
    shift

    local SHIFT
    local VALUE_FIELD
    local CLASS_FIELDS=1

    while ! [[ -z $1 ]]; do
        if [[ $3 == "=" ]]; then
            SHIFT=4
            VALUE_FIELD=$4
        else
            SHIFT=2
            VALUE_FIELD=  # empty
        fi

        if [[ $1 == "function" ]]; then
            [[ -z $VALUE_FIELD ]] && VALUE_FIELD=${CLASS}::$2
            eval "$OBJ_NAME.$2() { $VALUE_FIELD $OBJ_NAME \"\$@\"; }"
        elif [[ $1 == "declare" ]]; then
            eval ${OBJ_NAME}_$2=$VALUE_FIELD
            eval "$OBJ_NAME.$2() { echo \"\$${OBJ_NAME}_$2\"; }"
            eval "$OBJ_NAME.set_$2() { ${OBJ_NAME}_$2=\$1; }"
        else
            echo -e "oobash: Syntax error in class-field $CLASS_FIELDS in class $CLASS,
\texpected function or declare keyword" >&2
            return 1
        fi

        (( ++CLASS_FIELDS ))
        shift $SHIFT
    done

    eval $VARNAME=$OBJ_NAME
    return 0
}


# Create new object and register it in the object table

# Arguments:
#    * Variable name of the class array
#    * Variable name to export object name to
#    + (optional) arguments to constructor.
new()
{
    local CLASS=$1
    shift

    local VARNAME=$1
    shift

    local i

    # Increment class id number.
    if [[ -z ${__OOB_OBJ_TABLE[$CLASS]} ]]; then
        __OOB_OBJ_TABLE[$CLASS]=1
    else
        ((__OOB_OBJ_TABLE[$CLASS] += 1))
    fi


    # Generate unique object-name.
    local OBJ_NAME="${CLASS}_Object_id_${__OOB_OBJ_TABLE[$CLASS]}"

    # Register object-name.
    __OOB_ADDR_TABLE[$CLASS]="${__OOB_ADDR_TABLE[$CLASS]}:$OBJ_NAME:"


    # Create new object.
    eval new_metaobject $OBJ_NAME $CLASS $VARNAME \"\${$CLASS[@]}\"

    # Call constructor.
    [[ $(type -t $OBJ_NAME.__new__) == function ]] && $OBJ_NAME.__new__ "$@"
}


# Deletes All references to the object
# and calls the destructor if it exists.

# Arguments:
#    * A reference to an object
delete()
{
    local CLASSNAME=$(echo $1|sed -r 's/_Object_id_[0-9]+$//')

    __OOB_ADDR_TABLE[$CLASSNAME]=$(echo "${__OOB_ADDR_TABLE[$CLASSNAME]}"|sed -r "s/:$1://")

    if [[ -z ${__OOB_ADDR_TABLE[$CLASSNAME]} ]]; then
        unset __OOB_ADDR_TABLE[$CLASSNAME]
    fi

    # Check for destructor and call it if one is existent.
    [[ $(type -t $1.__delete__) == function ]] && $1.__delete__
}


# Deletes all references to the objects of all or
# specific classes.

# Arguments:
#    + (optional) Classnames ...
delete_all()
{
    local i
    local j

    if [[ -z $1 ]]; then
        # Loop through all registered objects and delete them
        for i in "${__OOB_ADDR_TABLE[@]}"; do
            local a=$(echo "$i"| \
                awk 'BEGIN { RS = ":+" } /^.+$/ {print $1" "}')

            for j in $a; do
                delete $j
            done
        done
    else
        for i; do
            local str=${__OOB_ADDR_TABLE[$i]}
            local a=$(echo "$str"| \
                awk 'BEGIN { RS = ":+" } /^.+$/ {print $1" "}')

            for j in $a; do
                delete $j
            done
        done
    fi
}

philluder

Anmeldungsdatum:
12. Januar 2011

Beiträge: 3

Hallo,

"Das find ich jetzt erstens fast schon wieder übertrieben und zweitens kann man da ja gar keine eigenen Klassen schreiben, sondern nur vorhandene nutzen."

–> Übertrieben ist es auf alle Fälle, sonst wäre es ja auch nicht lustig 😉 –> Und eigene Klassen kann man natürlich schreiben, es hält Dich ja keiner auf, das File anzupassen.

Trotzdem danke für die Anregung, die nächste Version wird einen Class-Template-Generator beinhalten.

Grüsse Andreas

domachine

(Themenstarter)

Anmeldungsdatum:
16. Mai 2007

Beiträge: 562

philluder schrieb:

Hallo,

"Das find ich jetzt erstens fast schon wieder übertrieben und zweitens kann man da ja gar keine eigenen Klassen schreiben, sondern nur vorhandene nutzen."

–> Übertrieben ist es auf alle Fälle, sonst wäre es ja auch nicht lustig 😉

Stimmt ☺

–> Und eigene Klassen kann man natürlich schreiben, es hält Dich ja keiner auf, das File anzupassen.

Module sind aber in der Regel nicht zum herumdoktern sondern zur Verwendung da.

Trotzdem danke für die Anregung, die nächste Version wird einen Class-Template-Generator beinhalten.

Ja erfinde mein Rad neu 😀. Nein Spaß. Viel Erfolg

philluder

Anmeldungsdatum:
12. Januar 2011

Beiträge: 3

Hallo nochmal neu Version ist oben...( mit Class.generate )

Wenn jemand Lust hat brauchbare/lustige neue Klassen zu generieren...gerne mir zukommen lassen. Ich werde das ganze dann auf sourceforge als Extension publizieren.

Viel Spass

Antworten |