2021-12-29 12:33:51 +00:00
#
# BashOOP - Simple OOP implementation for bash.
2022-01-07 14:24:54 +00:00
# Copyright (C) 2022 Ad5001 <mail@ad5001.eu>
2021-12-29 12:33:51 +00:00
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#
2021-12-27 23:44:16 +00:00
# This file contains all functions required to create a namespace.
# Internal variables are marked with a beginning underscore, like in most other languages.
# Signatures are a list of arguments.. Those within <> are mandatory, the ones within [] are optional.
2021-12-28 20:00:45 +00:00
# Namespace related variables.
2021-12-27 23:44:16 +00:00
_namespace = ""
2021-12-27 23:57:55 +00:00
_namespacePath = $( realpath $( dirname ${ BASH_SOURCE [0] } ) )
2021-12-27 23:44:16 +00:00
2022-01-07 14:24:54 +00:00
# Allows the creation of temporary, unique names for variables so that
# when declaring a new object with the same variable name, the previous one wouldn't be overwritten with
# the new object.
# However, this disallows the syntax that doesn't use $ at first, which makes the documentation clearer.
_counter = 0
2021-12-28 20:00:45 +00:00
# This dictionnary saves all classes for each namespace so they can be retreived and aliased.
declare -Ag _namespacesClasses
# This dictionnary links all files for static namespaces.
declare -Ag _namespacesStaticClasses
2022-01-01 15:39:35 +00:00
# Declares the current namespace.
# Signature: ([string namespaceName]) -> void
2021-12-27 23:44:16 +00:00
namespace( ) {
_namespace = $1 ;
}
# Imports a namespace into the current shell.
2021-12-28 20:00:45 +00:00
# It saves the path of the file so that relative paths can be
# properly resolved.
# For example, if the object Object exists within namespace Example, it
# will be accessible with "Example.Object".
2022-01-01 15:39:35 +00:00
# Signature: (<string namespaceFile>) -> void
2021-12-27 23:44:16 +00:00
importNamespace( ) {
namespaceFile = $1
# Save the path in order to get the absolute path of the file.
_namespacePath = $( realpath $( dirname $namespaceFile ) )
. $namespaceFile
}
2021-12-28 20:00:45 +00:00
# Aliases the classes in global namespace.
# For example, if the object Object exists within namespace Example, it
# will be accessible with "Example.Object" and "Object".
2022-01-01 15:39:35 +00:00
# Signature: (<string namespaceName>) -> void
2021-12-28 20:00:45 +00:00
using( ) {
namespaceName = $1
# Import static classes
if [ " ${ _namespacesStaticClasses [ $namespaceName ] } " != "" ] ; then
oldNamespace = _namespace
namespace # Reset namespace
# Split all
staticClasses = $( echo " ${ _namespacesStaticClasses [ $namespaceName ] } " | tr ";" "\n" )
for cl in $staticClasses ; do
parts = $( echo " $cl " | tr ":" "\n" )
static_class ${ parts [0] } ${ parts [1] }
done
namespace $oldNamespace
fi
# Import static classes
if [ " ${ _namespacesClasses [ $namespaceName ] } " != "" ] ; then
classes = $( echo " ${ _namespacesClasses [ $namespaceName ] } " | tr ";" "\n" )
for type in $classes ; do
eval " $type () { $namespaceName . $type \$@; } "
done
fi
}
2021-12-29 12:33:51 +00:00
# Creates a "property holder" based on a name.
# A "property holder" is a dictionnary maintaining the values of properties for a specific variable.
# One is created each time an object is declared, but this function can also be used for namespaces to have global
# properties.
2022-01-01 15:39:35 +00:00
# Signature: (<string name>) -> void
2021-12-29 12:33:51 +00:00
createPropertyHolder( ) {
name = $1
eval " declare -Ag _ ${ name } _properties "
}
2022-01-01 15:39:35 +00:00
# Creates an object instance of `type` in variable `variableName`.
# Signature: (<string type>, <string associatedFile>, <string variableName>, [string[] constructorArguments]) -> void
2021-12-27 23:44:16 +00:00
_createObject( ) {
type = $1
associatedFile = $2
varName = $3
2022-01-01 23:25:14 +00:00
constructorArguments = " ${ @ : 4 } "
2021-12-27 23:44:16 +00:00
2022-01-07 14:24:54 +00:00
# Get a temporary variable. It's equivalent to the memory space in bash of the object.
varTmpName = " _obj ${ _counter } "
_counter = $(( _counter + 1 ))
2021-12-27 23:44:16 +00:00
# Declare dummy constructor.
2022-01-07 14:24:54 +00:00
eval " $varTmpName .constructor() { :; } "
2021-12-29 12:12:31 +00:00
# Declare base properties.
2022-01-07 14:24:54 +00:00
eval " $varTmpName .type() { echo $type ; } "
eval " $varTmpName .source() { echo $associatedFile ; } "
2021-12-27 23:44:16 +00:00
# Create property array.
2022-01-07 14:24:54 +00:00
createPropertyHolder $varTmpName
# alias the "varTmpName" variable to itself, so that it can be used and transmitted in other variables (e.g: $varName.name would alias to varTmpName.name)
eval " $varName =' $varTmpName ' "
2021-12-27 23:44:16 +00:00
# Imports the file and replace all "<Type>." with the variable name.
2022-01-07 14:24:54 +00:00
. <( sed s/this\\ ./$varTmpName ./g <( sed s/$type \\ ./$varTmpName ./g $associatedFile ) )
2021-12-27 23:44:16 +00:00
# Call the constructor
2021-12-29 12:12:31 +00:00
$varName .constructor $constructorArguments
2021-12-27 23:44:16 +00:00
}
2022-01-01 15:39:35 +00:00
# Declares a new class named `type` in the current namespace being defined in `associatedFile`.
# Signature: (<string type>, <string associatedFile>) -> void
2021-12-27 23:44:16 +00:00
class( ) {
type = $1 # Type of the object as declared within the file.
associatedFile = $2
objFullName = $type # Type of the object referenced elsewhere
if [ " $_namespace " != "" ] ; then
objFullName = " ${ _namespace } . $type "
fi
if [ ${ associatedFile : : 1 } != "/" ] ; then # Relative path, we save only the absolute path
associatedFile = " $_namespacePath / $associatedFile "
fi
# Declares a new function for object initialisation.
2021-12-28 20:00:45 +00:00
eval " $objFullName () { _createObject $type $associatedFile \$@; } "
# Save the class in the dictionnary for reference.
if [ " $_namespace " != "" ] ; then
if [ " ${ _namespacesClasses [ $_namespace ] } " = = "" ] ; then
_namespacesClasses[ $_namespace ] = $type
else
_namespacesClasses[ $_namespace ] = " ${ _namespacesClasses [ $_namespace ] } ; $type "
fi
fi
}
2022-01-01 15:39:35 +00:00
# Declares a new static class named `type` in the current namespace being defined in `associatedFile`.
# Signature: (<string type>, <string associatedFile>) -> void
2021-12-28 20:00:45 +00:00
static_class( ) {
type = $1 # Type of the object as declared within the file.
associatedFile = $2
objFullName = $type # Type of the object referenced elsewhere
if [ " $_namespace " != "" ] ; then
objFullName = " ${ _namespace } . $type "
fi
if [ ${ associatedFile : : 1 } != "/" ] ; then # Relative path, we save only the absolute path
associatedFile = " $_namespacePath / $associatedFile "
fi
# Imports the file and replace all "<Type>." with the variable name.
. <( sed s/this\\ ./$objFullName ./g <( sed s/$type \\ ./$objFullName ./g $associatedFile ) )
# Save the class in the dictionnary for reference.
if [ " $_namespace " != "" ] ; then
if [ " ${ _namespacesStaticClasses [ $_namespace ] } " = = "" ] ; then
_namespacesStaticClasses[ $_namespace ] = " $type : $associatedFile "
else
_namespacesStaticClasses[ $_namespace ] = " ${ _namespacesStaticClasses [ $_namespace ] } ; $type : $associatedFile "
fi
fi
2021-12-27 23:44:16 +00:00
}
2022-01-01 15:39:35 +00:00
# Gets or sets the value of the property `propertyName` of an object set to variable `variableName`.
# Signature: (<string variableName>, <string propertyName>, [string operator, string value]) -> string|void
2021-12-27 23:44:16 +00:00
_accessProperty( ) {
varName = $1
prop = $2
2021-12-29 19:11:17 +00:00
val = " ${ @ : 4 } "
2021-12-27 23:44:16 +00:00
if [ " $3 " = = "=" ] ; then
2021-12-29 19:11:17 +00:00
eval " _ ${ varName } _properties[ $prop ]=\"\$val\" "
2021-12-27 23:44:16 +00:00
else
2021-12-29 19:14:35 +00:00
eval " echo \"\${_ ${ varName } _properties[ $prop ]}\" "
2021-12-27 23:44:16 +00:00
fi
}
2022-01-01 15:39:35 +00:00
# Declares a property `propertyFullName` with an optional default value `propertyValue`.
# Signature: (<string propertyFullName>, [string propertyValue]) -> void
2021-12-27 23:44:16 +00:00
property( ) {
propertyFullName = $1
2021-12-29 12:39:39 +00:00
propertyValue = $2
2021-12-27 23:44:16 +00:00
# Split the name by ".". First element is variable name,
# second is property name.
propertyNames = ( $( echo $propertyFullName | tr "." "\n" ) )
varName = ${ propertyNames [0] }
prop = ${ propertyNames [1] }
# Default value
2021-12-29 12:39:39 +00:00
eval " _ ${ varName } _properties[ $prop ]=' $propertyValue ' "
2021-12-27 23:44:16 +00:00
# Property alias
2021-12-29 19:45:34 +00:00
eval " $propertyFullName () { _accessProperty $varName $prop \$1 \"\${@:2}\"; } "
2021-12-27 23:44:16 +00:00
}