├── .gitignore ├── README.md ├── emitter.bash ├── test ├── once.sh ├── test1.bash ├── test1.txt └── test2.bash └── todo.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.~ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Emitter 2 | Emitter is a bash library that helps you to be able to create custom event listeners and assign a function to be executed whenever the listener is been emitted 3 | 4 | **Usage** 5 | `event` takes three subcommands which are `attach` `emit` and `detach` 6 | 7 | **event attach** 8 | `event attach` takes two argument which is the name of the event you want to listen for and the function to execute when the event is emitted 9 | 10 | ```bash 11 | 1 #!/usr/bin/env bash 12 | 2 source ../evt.sh 13 | 3 CreateFile() { 14 | 4 local ftocreate=$1 15 | 5 echo -e "Love is a name \nSex is a game\nPlay the Game\nForget the name " > "$ftocreate" 16 | 6 printf "%s\n" "$ftocreate have been created" 17 | 7 } 18 | 8 event attach createfile CreateFile ;# createfile is the event to listen for, CreateFile is the callback function to execute when the event is emitted 19 | 9 event attach showfile ReadFile ;# showfile is the event to listen for, ReadFile is the callback function to execute when the event is emitted 20 | ``` 21 | 22 | 23 | **event emit** 24 | `event emit` the first argument to `event emit` must be the the event you want to listen for and it must have already been added to the stack with `event attach` , the second argument must be the list of all the argument which will be passed to the callback function (behind the hood) assigned to the event you want to listen for 25 | 26 | Note:- You must not pass the arguments to the callback function directly when createing the event listener with `event attach` 27 | 28 | Note:- When assigning the arguments to the event listener using `event emit` you must wrap the arguments with double quotes , each argument must be separated with a single space, if a single argument have spaces or tabs , wrap that specific argument with single quotes. 29 | 30 | Note:- Under the hood, 2 other argument are passed to the callback function which is the name of the event listend for and the function that will be fired if the event is emitted 31 | 32 | for example: 33 | 34 | ```bash 35 | event attach talk SayShell # talk is the event to listen for, SayShell is the callback function to execute when the event talk is been emitted 36 | 37 | event emit talk "bash ksh zsh sh" # talk is the event to listen for, "bash ksh zsh sh" is the argument passed to SayShell 38 | 39 | loveWhat="These are the shells i love" 40 | event emit talk "'$loveWhat' bash ksh zsh sh" # loveWhat variable contains space, and it's wrapped in single quotes so that it will be parsed as a single argument 41 | 42 | ``` 43 | 44 | 45 | see line 7 and line 27 46 | 47 | ```bash 48 | 1 #!/usr/bin/env bash 49 | 2 source ../evt.sh 50 | 3 CreateFile() { 51 | 4 local text=$1 ftocreate=$2 52 | 5 echo -e "Love is a name \nSex is a game\nPlay the Game\nForget the name " > "$ftocreate" 53 | 6 printf "%s\n" "$ftocreate $text" 54 | 7 event emit showfile "$ftocreate" 55 | 8 } 56 | 9 event attach createfile CreateFile ; #createfile is the event to listen for, CreateFile is the callback function to execute when the event is emitted 57 | 10 event attach showfile ReadFile ; #showfile is the event to listen for, ReadFile is the callback function execute when the event is emitted 58 | 11 ReadFile() { 59 | 12 local file=$1 60 | 13 echo "------------------------- READING $file -----------------------" 61 | 14 while read log;do 62 | 15 printf "%s\n" "$log" 63 | 16 done < "$file" 64 | 17 echo "------------------------- DONE READING $file ------------------" 65 | 18 } 66 | 19 67 | 20 File() { 68 | 21 69 | 22 if [[ ! -f "log.txt" ]];then 70 | 23 event emit createfile "'has been created' log.txt" ;# 'has been created' and log.txt will be passed to CreateFile 71 | 24 return 1; 72 | 25 fi 73 | 26 74 | 27 event emit showfile "log.txt" ; #log.txt will be passed to ReadFile 75 | 28} 76 | 77 | ``` 78 | **once** 79 | `event once` works like `event emit`. The only difference is that once an event is emitted in `event once` that event is removed as an event listener i.e it is only executed ones 80 | 81 | 82 | ```bash 83 | # check test/once.sh 84 | 85 | source ../emitter.bash; 86 | 87 | s() { 88 | echo "${1}"; 89 | } 90 | event attach sayHoss s 91 | 92 | event emit sayHoss 'victory' 93 | event emit sayHoss 'victory' 94 | event emit sayHoss 'victory' 95 | 96 | 97 | ff() { 98 | local _num1=${1}; 99 | local _num2=${2}; 100 | 101 | printf "%d\n" "$(( _num1 + _num2 ))"; 102 | } 103 | 104 | event attach addNumber ff 105 | 106 | event once addNumber 2 2 107 | 108 | ``` 109 | 110 | **NOTE:** once the event `addNumber` is emitted trying to emit again will cause an error 111 | 112 | 113 | **removeall listener** 114 | `event removeAll` This subcommands removes all listener by unsetting the Stack array 115 | 116 | **List Event** 117 | `event list` takes no argument. It lists the total number of event listener in the Stack 118 | 119 | example 120 | `event list` 121 | 122 | 123 | **setmaxlistener** 124 | `event setMaxlistener` takes one argument which must be an integer. It resets the default maximum listener by the specified ones 125 | 126 | 127 | **Detach Event** 128 | `event detach` takes a single argument, it detaches/removes the event you don't want to listen for again from the Stack. 129 | 130 | `event detach eventName` 131 | 132 | 133 | **maxlisteners** 134 | The total number of listeners allowed is 1000, and it's readonly, you cannot modify it in your script, except you want to modify it directly from the emitter library 135 | 136 | ***License*** 137 | GNU General Public License 138 | -------------------------------------------------------------------------------- /emitter.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | declare -A Stack 4 | declare -i _MAXLISTENER_=11 5 | event() { 6 | 7 | local subcomm=$1 8 | 9 | 10 | case $subcomm in 11 | attach) 12 | 13 | # total number of arguement must be exactly 3 14 | [[ ! ${#@} -eq 3 ]] && { 15 | throw error "Invalid Number of Arguments to $subcomm" 16 | } 17 | 18 | # if subcomm is attach assign the second variable as the type of the event 19 | # assign the third variable as the callback to fire 20 | local typeofEvent=$2 21 | 22 | local messageCallback=$3 23 | 24 | 25 | # checking if truy messageCallback is a function 26 | declare -F ${messageCallback} >/dev/null 27 | # if messageCallback is not a function return from this function 28 | [[ $? -gt 0 ]] && { 29 | throw error "${messageCallback} is not defined" 30 | return 1; 31 | } 32 | 33 | { 34 | [[ ${#Stack[@]} -eq ${_MAXLISTENER_} ]] || [[ ${#Stack[@]} -gt ${_MAXLISTENER_} ]] 35 | 36 | } && { 37 | throw error "Number of listeners exceeded, use setMaxlisteners subcommand to increment the amount of listeners" 38 | } 39 | 40 | # assigining the event type as a key to the global Array Stack and messageCallback as it's value 41 | Stack[$typeofEvent]=${messageCallback} 42 | ;; 43 | emit) 44 | # total number of argument must not be less than 2 45 | 46 | [[ ${#@} -lt 2 ]] && { 47 | throw error "Invalid Number of Arguments to $subcomm" 48 | } 49 | 50 | # assign the second variable as the type of event 51 | # argsToCallback contains args to be passed to the function messageCallback inside the attach case 52 | # the args should be passed like this 53 | # "firstarg secondarg 'third arg'" <<< use ' ' if the argument contains space or tabs 54 | # the last two argument to the messageCallback function is the typeofEvent fired and the messageCallback function itself 55 | local typeofEvent=$2 56 | local argsToCallback=$3 57 | read -a argsToCallback <<<${argsToCallback} 58 | argsToCallback[$(( ${#argsToCallback[@]} + 1 ))]=${typeofEvent} 59 | 60 | shift 2 61 | 62 | # if there is not listener in the stack, throw an error 63 | [[ ${#Stack[@]} -eq 0 ]] && { 64 | throw error "There is no listener in the stack to emit" 65 | } 66 | 67 | 68 | for stacks in "${!Stack[@]}";do 69 | [[ "$stacks" == "$typeofEvent" ]] && { 70 | argsToCallback[$(( ${#argsToCallback[@]} + 1 ))]=${Stack[$stacks]} 71 | eval ${Stack[$stacks]} "${argsToCallback[*]}" 72 | break 73 | } 74 | done 75 | 76 | [[ $? -gt 0 ]] && { 77 | throw error "cannot emit ${typeofEvent} because it has not been registerd as a listener" 78 | } 79 | 80 | ;; 81 | detach) 82 | # Deatch ( remove ) the event type from the Stack 83 | local typeofEvent=$2 84 | [[ ! ${#@} -eq 2 ]] && { 85 | throw error "Invalid Number of Arguments to $subcomm" 86 | } 87 | 88 | for stacks in "${!Stack[@]}";do 89 | 90 | [[ "$stacks" == "$typeofEvent" ]] && { 91 | unset Stack[$stacks] 92 | break 93 | } 94 | 95 | done 96 | 97 | [[ $? -gt 0 ]] && { 98 | throw error "cannot detach ${typeofEvent} because it has not been registerd as a listener" 99 | } 100 | 101 | ;; 102 | once) 103 | # total number of argument must not be less than 2 104 | 105 | [[ ${#@} -lt 2 ]] && { 106 | throw error "Invalid Number of Arguments to $subcomm" 107 | } 108 | 109 | local typeofEvent=$2 110 | local argsToCallback=$3 111 | read -a argsToCallback <<<${argsToCallback} 112 | argsToCallback[$(( ${#argsToCallback[@]} + 1 ))]=${typeofEvent} 113 | 114 | shift 2 115 | 116 | # if there is not listener in the stack, throw an error 117 | [[ ${#Stack[@]} -eq 0 ]] && { 118 | throw error "There is no listener in the stack to emit" 119 | } 120 | 121 | 122 | for stacks in "${!Stack[@]}";do 123 | [[ "$stacks" == "$typeofEvent" ]] && { 124 | argsToCallback[$(( ${#argsToCallback[@]} + 1 ))]=${Stack[$stacks]} 125 | eval ${Stack[$stacks]} "${argsToCallback[*]}" 126 | unset Stack[$stacks]; 127 | break 128 | } 129 | done 130 | 131 | [[ $? -gt 0 ]] && { 132 | throw error "cannot emit ${typeofEvent} because it has not been registerd as a listener" 133 | } 134 | 135 | ;; 136 | list) 137 | [[ ${#Stack[@]} -eq 0 ]] && { 138 | throw error "There is no listener in the stack" 139 | } 140 | for stacks in "${!Stack[@]}";do 141 | printf "%s\n" "${stacks}" 142 | done 143 | ;; 144 | removeAll) 145 | unset Stack 146 | ;; 147 | setMaxListener) 148 | 149 | [[ ! ${#@} -eq 2 ]] && { 150 | throw error "$subcomm requires only one argument" 151 | } 152 | 153 | local num=${2} 154 | 155 | [[ ! ${num} =~ ^[[:digit:]]{1,}$ ]] && { 156 | throw error "the argument to $subcomm must be an integer" 157 | } 158 | 159 | _MAXLISTENER_=${num} 160 | 161 | ;; 162 | *) 163 | throw error "\" $subcomm \" is not a valid subcommand" 164 | ;; 165 | esac 166 | } 167 | 168 | 169 | throw() { 170 | local subComm="${1}" 171 | local message="${2}" 172 | local open="\e[" 173 | local close="\e[0m" 174 | local bold="1;" 175 | local light="0;" 176 | local red="31m" 177 | local yellow="33m" 178 | 179 | case $subComm in 180 | error) 181 | 182 | 183 | [[ -z ${message} ]] && { 184 | #${FUNCNAME[$(( ${#FUNCNAME[@]} - $(( ${#FUNCNAME[@]} - 2 )) ))]} , 185 | # to get the calling function, when you do a - 1 it gives 186 | # the source builtin command as the calling function, 187 | # so we have to minus by 2 188 | message="An Error has occured in ${FUNCNAME[$(( ${#FUNCNAME[@]} - 2))]}" 189 | } 190 | printf "${open}${bold}${red}%s${close}\n" "${message}" 191 | 192 | ;; 193 | warning) 194 | [[ -z ${message} ]] && { 195 | message="An Error has occured in ${FUNCNAME[$(( ${#FUNCNAME[@]} - 2))]}" 196 | } 197 | printf "${open}${bold}${yellow}%s${close}\n" "${message}" 198 | ;; 199 | *) 200 | ${FUNCNAME} error "Invalid Arugment was passed to ${FUNCNAME}" 201 | ;; 202 | esac 203 | exit 1; 204 | } 205 | 206 | -------------------------------------------------------------------------------- /test/once.sh: -------------------------------------------------------------------------------- 1 | source ../emitter.bash; 2 | 3 | s() { 4 | echo "${1}"; 5 | } 6 | event attach sayHoss s 7 | 8 | event emit sayHoss 'victory' 9 | event emit sayHoss 'victory' 10 | event emit sayHoss 'victory' 11 | 12 | 13 | ff() { 14 | local _num1=${1}; 15 | local _num2=${2}; 16 | 17 | printf "%d\n" "$(( _num1 + _num2 ))"; 18 | } 19 | 20 | event attach addNumber ff 21 | 22 | event once addNumber 2 2 23 | -------------------------------------------------------------------------------- /test/test1.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source ../emitter.bash 4 | 5 | 6 | readFile() { 7 | local text=$1 8 | local num=$2 9 | 10 | printf "%s\n" "${text} ${num}" 11 | } 12 | 13 | 14 | # Attaching event to the stack 15 | event attach fileRead readFile 16 | i=1; 17 | while read line;do 18 | # emiting the event 19 | event emit fileRead "'$line' $i" 20 | : $((i++)) 21 | done < "test1.txt" 22 | 23 | # detaching the event from the stack 24 | event detach fileRead 25 | 26 | 27 | while read line;do 28 | # event is not emmited since fileRead is not among the stack anymore 29 | event emit fileRead "'$line' $i" 30 | : $((i++)) 31 | done < "test1.txt" 32 | -------------------------------------------------------------------------------- /test/test1.txt: -------------------------------------------------------------------------------- 1 | my name is victory osikwemhe 2 | my default shell is bash 3 | i love bash 4 | -------------------------------------------------------------------------------- /test/test2.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source ../emitter.bash 4 | 5 | 6 | CreateFile() { 7 | local ftocreate=$1 8 | 9 | echo -e "Love is a name \nSex is a game\n Play the Game\n Forget the name " > "$ftocreate" 10 | 11 | printf "%s\n" "$ftocreate have been created" 12 | event emit showfile "$ftocreate" 13 | } 14 | 15 | ReadFile() { 16 | local file=$1 17 | echo "------------------------- READING $file -----------------------" 18 | while read log;do 19 | printf "%s\n" "$log" 20 | done < "$file" 21 | echo "------------------------- DONE READING $file ------------------" 22 | } 23 | 24 | event attach createfile CreateFile 25 | event attach showfile ReadFile 26 | 27 | File() { 28 | 29 | if [[ ! -f "log.txt" ]];then 30 | event emit createfile "log.txt" 31 | return 1; 32 | fi 33 | 34 | event emit showfile "log.txt" 35 | } 36 | 37 | File 38 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | add newListener support, this will be emitted anytime a listener is added 2 | --------------------------------------------------------------------------------