{"id":13448434,"url":"https://github.com/niieani/bash-oo-framework","last_synced_at":"2025-05-14T12:13:08.281Z","repository":{"id":25141940,"uuid":"28564207","full_name":"niieani/bash-oo-framework","owner":"niieani","description":"Bash Infinity is a modern standard library / framework / boilerplate for Bash","archived":false,"fork":false,"pushed_at":"2023-12-15T14:25:19.000Z","size":676,"stargazers_count":5599,"open_issues_count":36,"forks_count":245,"subscribers_count":138,"default_branch":"master","last_synced_at":"2025-05-08T18:53:23.969Z","etag":null,"topics":["bash","boilerplate","error-handling","framework","functional-programming","logging","oop","shell","standard-library","testing"],"latest_commit_sha":null,"homepage":"https://github.com/niieani/bash-oo-framework/discussions","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niieani.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2014-12-28T14:53:27.000Z","updated_at":"2025-05-02T13:48:37.000Z","dependencies_parsed_at":"2023-12-15T15:42:36.293Z","dependency_job_id":null,"html_url":"https://github.com/niieani/bash-oo-framework","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niieani%2Fbash-oo-framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niieani%2Fbash-oo-framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niieani%2Fbash-oo-framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niieani%2Fbash-oo-framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niieani","download_url":"https://codeload.github.com/niieani/bash-oo-framework/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254140769,"owners_count":22021220,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","boilerplate","error-handling","framework","functional-programming","logging","oop","shell","standard-library","testing"],"created_at":"2024-07-31T05:01:45.479Z","updated_at":"2025-05-14T12:13:03.269Z","avatar_url":"https://github.com/niieani.png","language":"Shell","funding_links":[],"categories":["Shell","\u003ca name=\"scripting\"\u003e\u003c/a\u003escripting","bash","boilerplate","Shell Script Development","Productivity tools","Libraries"],"sub_categories":["PCAP","Chess :chess_pawn:","Reusable Things"],"readme":"Bash Infinity\n=============\n[![Build Status](https://travis-ci.com/niieani/bash-oo-framework.svg?branch=master)](https://travis-ci.com/niieani/bash-oo-framework)\n[![Build Status](https://api.cirrus-ci.com/github/niieani/bash-oo-framework.svg)](https://cirrus-ci.com/github/niieani/bash-oo-framework)\n[![Join the chat at https://gitter.im/niieani/bash-oo-framework](https://badges.gitter.im/niieani/bash-oo-framework.svg)](https://gitter.im/niieani/bash-oo-framework?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nBash Infinity is a standard library and a boilerplate framework for writing tools using **bash**.\nIt's modular and lightweight, while managing to implement some concepts from C#, Java or JavaScript into bash.\nThe Infinity Framework is also plug \u0026 play: include it at the beginning of your existing script to import any of the individual features such as error handling, and start using other features gradually.\n\nThe aim of Bash Infinity is to maximize readability of bash scripts, minimize the amount of code repeat and create a central repository for well-written, and a well-tested standard library for bash.\n\nBash Infinity transforms the often obfuscated \"bash syntax\" to a cleaner, more modern syntax.\n\nDisclaimer\n==========\n\nSome components are more sturdy than others, and as-it-stands the framework lacks good test coverage (we need your help!).\n\nDue to the above and relatively high code-complexity, we have decided that it will make the most sense to do a rewrite for the next major version 3.0 (see discussion in #45), taking the best parts of the framework, while re-using established tools from bash community.\n\nAt this point, I would **not recommend starting major projects** based on the whole framework. Instead, copy and paste parts you need, ideally those you understand, if you found a particular feature useful.\n\nCompatibility\n=============\n\nNot all of the modules work with earlier versions of bash, as I test with **bash 4**. However, it should be possible (and relatively easy) to [port non-working parts](#porting-to-bash-3) to earlier versions.\n\nQuick-start\n===========\n\nSingle-file release and dynamic loading is not available for v2.0 yet. To load the framework locally, [read on](#how-to-use).\n\nMain modules\n============\n\n* automatic error handling with exceptions and visual stack traces (`util/exception`)\n* named parameters in functions (instead of $1, $2...) (`util/namedParameters`)\n* passing arrays and maps as parameters (`util/variable`)\n* **try-catch** implementation (`util/tryCatch`)\n* throwing custom **exceptions** (`util/exception`)\n* **import** keyword for clever sourcing of scripts à la *require-js* (`oo-bootstrap`)\n* handy aliases for **colors** and **powerline** characters to increase readability in the output of your scripts (`UI/Color`)\n* well-formatted, colorful **logging** to *stderr* or custom delegate functions (`util/log`)\n* **unit test** library (`util/test`)\n* standard library for the type system with plenty of useful functions (`util/type`)\n* operational chains for **functional programming** in bash (`util/type`)\n* **type system** for object-oriented scripting (`util/class`)\n\nAll of the features are modular and it's easy to only import the ones you'd like to use, without importing the rest of the framework. For example, the named parameters or the try-catch modules are self-contained in individual files.\n\nError handling with exceptions and `throw`\n==============================================\n\n```\nimport util/exception\n```\n\nOne of the highlight features is error handling that should work out of the box. If the script generates an error it will break and display a call stack:\n\n![example call stack](https://raw.githubusercontent.com/niieani/bash-oo-framework/master/docs/exception.png \"Example Call Stack\")\n\nYou may also force an error by `throw`ing your own Exception:\n\n```bash\ne=\"The hard disk is not connected properly!\" throw\n```\n\nIt's useful for debugging, as you'll also get the call stack if you're not sure where the call is coming from.\n\n**Exceptions** combined with *try \u0026 catch* give you safety without having to run with **-o errexit**.\n\nIf you do something wrong, you'll get a detailed exception backtrace, highlighting the command where it went wrong in the line from the source. The script execution will be halted with the option to continue or break.\nOn the other hand if you expect a part of block to fail, you can wrap it in a `try` block, and handle the error inside a `catch` block.\n\nNamed parameters in functions\n=============================\n\n```\nimport util/namedParameters\n```\n\nIn any programing language, it makes sense to use meaningful names for variables for greater readability.\nIn case of Bash, that means avoiding using positional arguments in functions.\nInstead of using the unhelpful `$1`, `$2` and so on within functions to access the passed in values, you may write:\n\n```bash\ntestPassingParams() {\n\n    [string] hello\n    [string[4]] anArrayWithFourElements\n    l=2 [string[]] anotherArrayWithTwo\n    [string] anotherSingle\n    [reference] table   # references only work in bash \u003e=4.3\n    [...rest] anArrayOfVariedSize\n\n    test \"$hello\" = \"$1\" \u0026\u0026 echo correct\n    #\n    test \"${anArrayWithFourElements[0]}\" = \"$2\" \u0026\u0026 echo correct\n    test \"${anArrayWithFourElements[1]}\" = \"$3\" \u0026\u0026 echo correct\n    test \"${anArrayWithFourElements[2]}\" = \"$4\" \u0026\u0026 echo correct\n    # etc...\n    #\n    test \"${anotherArrayWithTwo[0]}\" = \"$6\" \u0026\u0026 echo correct\n    test \"${anotherArrayWithTwo[1]}\" = \"$7\" \u0026\u0026 echo correct\n    #\n    test \"$anotherSingle\" = \"$8\" \u0026\u0026 echo correct\n    #\n    test \"${table[test]}\" = \"works\"\n    table[inside]=\"adding a new value\"\n    #\n    # I'm using * just in this example:\n    test \"${anArrayOfVariedSize[*]}\" = \"${*:10}\" \u0026\u0026 echo correct\n}\n\nfourElements=( a1 a2 \"a3 with spaces\" a4 )\ntwoElements=( b1 b2 )\n\ndeclare -A assocArray\nassocArray[test]=\"works\"\n\ntestPassingParams \"first\" \"${fourElements[@]}\" \"${twoElements[@]}\" \"single with spaces\" assocArray \"and more... \" \"even more...\"\n\ntest \"${assocArray[inside]}\" = \"adding a new value\"\n```\n\nThe system will automatically assign:\n * **$1** to **$hello**\n * **$anArrayWithFourElements** will be an array of params with values from $2 till $5\n * **$anotherArrayWithTwo** will be an array of params with values from $6 till $7\n * **$8** to **$anotherSingle**\n * **$table** will be a reference to the variable whose name was passed in as the 9th parameter\n * **$anArrayOfVariedSize** will be a bash array containing all the following params (from $10 on)\n\nIn other words, not only you can call your parameters by their names (which makes up for a more readable core), you can actually pass arrays easily (and references to variables - this feature needs bash \u003e=4.3 though)! Plus, the mapped variables are all in the local scope.\nThis module is pretty light and works in bash 3 and bash 4 (except for references - bash \u003e=4.3) and if you only want to use it separately from this project, get the file /lib/system/02_named_parameters.sh.\n\nNote: For lengths between 2-10 there are aliases for arrays, such as ```[string[4]]```, if you need anything more, you need to use the syntax ```l=LENGTH [string[]]```, like shown in the above example. Or, make your own aliases :).\n\nUsing ```import```\n==================\n\nAfter bootstrapping, you may use `import` to load either the library files or your own files.\nThe command will ensure they're only loaded once. You may either use a relative path from the file you're importing, a path relative to the file that first included the framework, or an absolute path. `.sh` suffix is optional.\nYou can also load all the files inside of a directory by simply including the path to that directory instead of the file.\n\nUsing `try \u0026 catch`\n=======================\n\n```bash\nimport util/tryCatch\nimport util/exception # needed only for Exception::PrintException\n```\n\nSample usage:\n\n```bash\ntry {\n    # something...\n    cp ~/test ~/test2\n    # something more...\n} catch {\n    echo \"The hard disk is not connected properly!\"\n    echo \"Caught Exception:$(UI.Color.Red) $__BACKTRACE_COMMAND__ $(UI.Color.Default)\"\n    echo \"File: $__BACKTRACE_SOURCE__, Line: $__BACKTRACE_LINE__\"\n\n    ## printing a caught exception couldn't be simpler, as it's stored in \"${__EXCEPTION__[@]}\"\n    Exception::PrintException \"${__EXCEPTION__[@]}\"\n}\n```\n\nIf any command fails (i.e. returns anything else than 0) in the ```try``` block, the system will automatically start executing the ```catch``` block.\nBraces are optional for the ```try``` block, but required for ```catch``` if it's multiline.\n\nNote: `try` is executed in a subshell, therefore you cannot assign any variables inside of it.\n\nUsing Basic Logging, Colors and Powerline Emoji\n===============================================\n\n```\nimport util/log\n```\n\n```bash\n# using colors:\necho \"$(UI.Color.Blue)I'm blue...$(UI.Color.Default)\"\n\n# enable basic logging for this file by declaring a namespace\nnamespace myApp\n# make the Log method direct everything in the namespace 'myApp' to the log handler called DEBUG\nLog::AddOutput myApp DEBUG\n\n# now we can write with the DEBUG output set\nLog \"Play me some Jazz, will ya? $(UI.Powerline.Saxophone)\"\n\n# redirect error messages to STDERR\nLog::AddOutput error STDERR\nsubject=error Log \"Something bad happened.\"\n\n# reset outputs\nLog::ResetAllOutputsAndFilters\n\n# You may also hardcode the use for the StdErr output directly:\nConsole::WriteStdErr \"This will be printed to STDERR, no matter what.\"\n```\n\nBoth the colors and the Powerline characters fallback gracefully on systems that don't support them.\nTo see Powerline icons, you'll need to use a powerline-patched font.\n\nFor the list of available colors and emoji's take a look into [lib/UI/Color.sh](https://github.com/niieani/bash-oo-framework/blob/master/lib/UI/Color.sh).\nFork and contribute more!\n\nSee [Advanced Logging](#advanced-logging) below to learn more about advanced logging capabilities.\n\nPassing arrays, maps and objects as parameters\n==============================================\n\n```\nimport util/variable\n```\n\nThe Variable utility offers lossless dumping of arrays and associative array (referred here to as `maps`) declarations by the use of the `@get` command.\n\nCombined with the `util/namedParameters` module, you can pass in either as individual parameters.\n\nA more readable way of specifying the will to pass a variable by it's declaration is to simply refer to the variable as `$var:yourVariableName`.\n\nIn bash \u003e=4.3, which supports references, you may pass by reference. This way any changes done to the variable within the function will affect the variable itself. To pass a variable by reference, use the syntax: `$ref:yourVariableName`.\n\n```bash\narray someArray=( 'one' 'two' )\n# the above is an equivalent of: declare -a someArray=( 'one' 'two' )\n# except this one creates a $var:someArray method handler\n\npassingArraysInput() {\n  [array] passedInArray\n\n  # chained usage, see below for more details:\n  $var:passedInArray : \\\n    { map 'echo \"${index} - $(var: item)\"' } \\\n    { forEach 'var: item toUpper' }\n\n  $var:passedInArray push 'will work only for references'\n}\n\necho 'passing by $var:'\n\n## 2 ways of passing a copy of an array (passing by it's definition)\npassingArraysInput \"$(@get someArray)\"\npassingArraysInput $var:someArray\n\n## no changes yet\n$var:someArray toJSON\n\necho\necho 'passing by $ref:'\n\n## in bash \u003e=4.3, which supports references, you may pass by reference\n## this way any changes done to the variable within the function will affect the variable itself\npassingArraysInput $ref:someArray\n\n## should show changes\n$var:someArray toJSON\n```\n\nStandard Library\n================\n\n```\nimport util/type\n```\n\nThe framework offers a standard library for the primitive types, such as string or array manipulations to make common tasks simpler and more readable.\n\nThere are three ways to make use of the standard library.\n\n### 1. Create variables by their handle-creating declaration\n\nIf you create your variables using the oo-framework's handle-creating declarations, you can execute methods of the standard library by referring to your variable as: `$var:yourVariable someMethod someParameter`.\n\nAvailable handle-creating declarations:\n\n* string\n* integer\n* array\n* map\n* boolean\n\nSince bash doesn't support boolean variables natively, the boolean variable is a special case that always needs to be declared and modified using the handle-creating declaration.\n\nExample:\n\n```bash\n# create a string someString\nstring someString=\"My 123 Joe is 99 Mark\"\n\n# saves all matches and their match groups for the said regex:\narray matchGroups=$($var:someString getMatchGroups '([0-9]+) [a-zA-Z]+')\n\n# lists all matches in group 1:\n$var:matchGroups every 2 1\n\n## group 0, match 1\n$var:someString match '([0-9]+) [a-zA-Z]+' 0 1\n\n# calls the getter - here it prints the value\n$var:someString\n```\n\n### 2. Invoke the methods with `var:`\n\nIf you didn't create your variables with their handles, you can also use the method `var:` to access them.\n\nExample:\n\n```bash\n# create a string someString\ndeclare someString=\"My 123 Joe is 99 Mark\"\n\n# saves all matches and their match groups for the said regex:\ndeclare -a matchGroups=$(var: someString getMatchGroups '([0-9]+) [a-zA-Z]+')\n\n# lists all matches in group 1:\nvar: matchGroups every 2 1\n\n## group 0, match 1\nvar: someString match '([0-9]+) [a-zA-Z]+' 0 1\n\n# calls the getter - here it prints the value\nvar: someString\n```\n\n### 3. Pipe the variable declaration directly to the method\n\nFinally, you can also pipe the variable declarations to the methods you wish to invoke.\n\nExample:\n\n```bash\n# create a string someString\ndeclare someString=\"My 123 Joe is 99 Mark\"\n\n# saves all matches and their match groups for the said regex:\ndeclare -a matchGroups=$(@get someString | string.getMatchGroups '([0-9]+) [a-zA-Z]+')\n\n# lists all matches in group 1:\n@get matchGroups | array.every 2 1\n\n## group 0, match 1\n@get someString | string.match '([0-9]+) [a-zA-Z]+' 0 1\n\n# prints the value\necho \"$someString\"\n```\n\n## Adding to the Standard Library\n\nYou can add your own, custom methods to the Standard Library by declaring them like:\n\n```bash\nstring.makeCool() {\n  @resolve:this ## this is required is you want to make use of the pipe passing\n  local outValue=\"cool value: $this\"\n  @return outValue\n}\n\nstring someString=\"nice\"\n$var:someString makeCool\n# prints \"cool value: nice\"\n```\n\nSee more info on writing classes below.\n\nFunctional/operational chains with the Standard Library and custom classes\n==========================================================================\n\n```\nimport util/type\n```\n\nThe type system in Bash Infinity allows you to chain methods together in a similar fashion one might pipe the output from one command to the other, or chain methods in C#, Java or JavaScript (think JQuery's pseudo-monad style).\n\n```bash\ndeclare -a someArray=( 'one' 'two' )\n\nvar: someArray : \\\n  { map 'echo \"${index} - $(var: item)\"' } \\\n  { forEach 'var: item toUpper' }\n\n# above command will result in a definition of an array:\n# ( '0 - ONE' '1 - TWO' )\n```\n\nMethods available in the next chain depend on the return type of the previously executed method.\n\nWriting your own classes\n========================\n\nIt's really simple and straight-forward, like with most modern languages.\n\nKeywords for definition:\n\n* **class:YourName()** - defining a class\n\nKeywords to use inside of the class definition:\n\n* **method ClassName.FunctionName()** - Use for defining methods that have access to *$this*\n* **public SomeType yourProperty** - define public properties (works in all types of classes)\n* **private SomeType _yourProperty** - as above, but accessible only for internal methods\n* **$this** - This variable is available inside the methods, used to refer to the current type\n* **this** - Alias of $var:this, used to invoke methods or get properties of an object\n* NOT YET IMPLEMENTED: **extends SomeClass** - inherit from a base class\n\nAfter a class has been defined, you need to invoke `Type::Initialize NameOfYourType` or `Type::InitializeStatic NameOfYourStaticType` if you want to make your class a singleton.\n\nHere's an example that shows how to define your own classes:\n\n```bash\nimport util/namedParameters util/class\n\nclass:Human() {\n  public string name\n  public integer height\n  public array eaten\n\n  Human.__getter__() {\n    echo \"I'm a human called $(this name), $(this height) cm tall.\"\n  }\n\n  Human.Example() {\n    [array]     someArray\n    [integer]   someNumber\n    [...rest]   arrayOfOtherParams\n\n    echo \"Testing $(var: someArray toString) and $someNumber\"\n    echo \"Stuff: ${arrayOfOtherParams[*]}\"\n\n    # returning the first passed in array\n    @return someArray\n  }\n\n  Human.Eat() {\n    [string] food\n\n    this eaten push \"$food\"\n\n    # will return a string with the value:\n    @return:value \"$(this name) just ate $food, which is the same as $1\"\n  }\n\n  Human.WhatDidHeEat() {\n    this eaten toString\n  }\n\n  # this is a static method, hence the :: in definition\n  Human::PlaySomeJazz() {\n    echo \"$(UI.Powerline.Saxophone)\"\n  }\n}\n\n# required to initialize the class\nType::Initialize Human\n\nclass:SingletonExample() {\n  private integer YoMamaNumber = 150\n\n  SingletonExample.PrintYoMama() {\n    echo \"Number is: $(this YoMamaNumber)!\"\n  }\n}\n\n# required to initialize the static class\nType::InitializeStatic SingletonExample\n```\n\nNow you can use both the `Human` and the `SingletonExample` classes:\n\n```bash\n# create an object called 'Mark' of type Human\nHuman Mark\n\n# call the string.= (setter) method\n$var:Mark name = 'Mark'\n\n# call the integer.= (setter) method\n$var:Mark height = 180\n\n# adds 'corn' to the Mark.eaten array and echoes the output\n$var:Mark Eat 'corn'\n\n# adds 'blueberries' to the Mark.eaten array and echoes the uppercased output\n$var:Mark : { Eat 'blueberries' } { toUpper }\n\n# invoke the getter\n$var:Mark\n\n# invoke the method on the static instance of SingletonExample\nSingletonExample PrintYoMama\n```\n\nWriting Unit Tests\n==================\n\n```\nimport util/test\n```\n\n![unit tests](https://raw.githubusercontent.com/niieani/bash-oo-framework/master/docs/unit.png \"Unit tests for the framework itself\")\n\nSimilarly to [Bats](https://github.com/sstephenson/bats), you can use the unit test module to test Bash scripts or any UNIX program.\nTest cases consist of standard shell commands. Like Bats, Infinity Framework uses Bash's errexit (set -e) option when running test cases. Each test is run in a subshell, and is independent from one another. To quote from Bats:\n\n\u003e If every command in the test case exits with a 0 status code (success), the test passes. In this way, each line is an assertion of truth.\n\nIf you need to do more advanced testing, or need to be able to run your tests on shells other than bash 4, I'd still recommend Bats.\n\nExample usage:\n\n```bash\nit 'should make a number and change its value'\ntry\n    integer aNumber=10\n    aNumber = 12\n    test (($aNumber == 12))\nexpectPass\n\nit \"should make basic operations on two arrays\"\ntry\n    array Letters\n    array Letters2\n\n    $var:Letters push \"Hello Bobby\"\n    $var:Letters push \"Hello Maria\"\n\n    $var:Letters contains \"Hello Bobby\"\n    $var:Letters contains \"Hello Maria\"\n\n    $var:Letters2 push \"Hello Midori,\n                        Best regards!\"\n\n    $var:Letters2 concatAdd $var:Letters\n\n    $var:Letters2 contains \"Hello Bobby\"\nexpectPass\n```\n\nCan you believe this is bash?! ;-)\n\nAdvanced Logging\n================\n\n```\nimport util/log\n```\n\nHere's an example of how to use the power of advanced logging provided by the Infinity Framework.\n\nIn every file you are logging from, you may name the logging scope (namespace).\nIf you won't do it, it'll be the filename, minus the extension.\nIt's better to name though, as filenames can conflict.\nThanks to scopes, you can specify exactly what and how you want to log.\n\n```bash\nnamespace myApp\n\n## ADD OUTPUT OF \"myApp\" TO DELEGATE STDERR\nLog::AddOutput myApp STDERR\n\n## LET'S TRY LOGGING SOMETHING:\nLog \"logging to stderr\"\n```\n\nThe above will simply print \"logging to stderr\" to STDERR.\nAs you saw we used the logger output called \"STDERR\". It is possible to create and register your own loggers:\n\n```bash\n## LET'S MAKE A CUSTOM LOGGER:\nmyLoggingDelegate() {\n    echo \"Hurray: $*\"\n}\n\n## WE NEED TO REGISTER IT:\nLog::RegisterLogger MYLOGGER myLoggingDelegate\n```\n\nNow, we can set it up so that it direct only logs from a specific function to the our custom logger output:\n\n```bash\n## WE WANT TO DIRECT ALL LOGGING WITHIN FUNCTION myFunction OF myApp TO MYLOGGER\nLog::AddOutput myApp/myFunction MYLOGGER\n\n## LET'S DECLARE THAT FUNCTION:\nmyFunction() {\n    echo \"Hey, I am a function!\"\n    Log \"logging from myFunction\"\n}\n\n## AND RUN:\nmyFunction\n```\n\nThe above code should print:\n\n```\nHey, I am a function!\nHurray: logging from myFunction\n```\n\nAs you can see, logging automatically redirected the logger from our function from our previously registered STDERR to our more specifically defined MYLOGGER.\nIf you wish to keep logging to both loggers, you can disable the specificity filter:\n\n```bash\nLog::DisableFilter myApp\n```\n\nNow if we run the function ```myFunction```:\n\nThe output will be:\n\n```\nHey, I am a function!\nHurray: logging from myFunction\nlogging from myFunction\n```\n\nWe can be even more specific and redirect messages with specific *subjects* to other loggers, or mute them altogether:\n\n```bash\n## Assuming we're in the same file, let's reset first\nLog::ResetAllOutputsAndFilters\n\nLog::AddOutput myApp/myFunction MYLOGGER\n\nmyFunction() {\n    echo \"Hey, I am a function!\"\n    Log \"logging from myFunction\"\n    subject=\"unimportant\" Log \"message from myFunction\"\n}\n```\n\nAnd let's change our custom logger a little, to support the subject:\n\n```bash\nmyLoggingDelegate() {\n    echo \"Hurray: $subject $*\"\n}\n```\n\nNow when we run ```myFunction```, we should get:\n\n```\nHey, I am a function!\nHurray:  logging from myFunction\nHurray: unimportant message from myFunction\n```\n\nTo filter (or redirect) messages with subject ```unimportant``` within ```myFunction``` of ```myApp```'s file:\n\n```bash\nLog::AddOutput myApp/myFunction/unimportant VOID\n```\n\nTo filter any messages with subject ```unimportant``` within ```myApp```'s file:\n\n```bash\nLog::AddOutput myApp/unimportant VOID\n```\n\nOr any messages with subject ```unimportant``` anywhere:\n\n```bash\nLog::AddOutput unimportant VOID\n```\n\nNow, running ```myFunction``` will print:\n\n```\nHey, I am a function!\nHurray: logging from myFunction\n```\n\nHow to use?\n===========\n\n1. Clone or download this repository. You'll only need the **/lib/** directory.\n2. Make a new script just outside of that directory and at the top place this:\n\n    ```shell\n    #!/usr/bin/env bash\n    source \"$( cd \"${BASH_SOURCE[0]%/*}\" \u0026\u0026 pwd )/lib/oo-bootstrap.sh\"\n    ```\n\n3. You may of course change the name of the **/lib/** directory to your liking, just change it in the script too.\n4. Out-of-box you only get the import functionality.\n   If you wish to use more features, such as the typing system, you'll need to import those modules as follows:\n\n   ```shell\n   # load the type system\n   import util/log util/exception util/tryCatch util/namedParameters\n\n   # load the standard library for basic types and type the system\n   import util/class\n   ```\n\n5. To import the unit test library you'll need to ```import lib/types/util/test```.\n   The first error inside of the test will make the whole test fail.\n\n6. When using `util/exception` or `util/tryCatch` don't use ```set -o errexit``` or ```set -e``` - it's not necessary, because error handling will be done by the framework itself.\n\nContributing\n============\n\nFeel free to fork, suggest changes or new modules and file a pull request.\nBecause of limitations and unnecessary complexity of the current implementation we're currently brainstorming a 3.0 rewrite in #45.\n\nThe things that I'd love to add are:\n\n* unit tests for all important methods\n* port to bash 3 (preferably a dynamic port that imports the right file for the right version)\n* a web generator for a single file version of the boilerplate (with an option to select modules of your choice)\n* more functions for the standard library for primitive types (arrays, maps, strings, integers)\n* useful standard classes are very welcome too\n\nPorting to Bash 3\n=================\n\nThe main challenge in porting to **bash 3** lays with creating a polyfill for associative arrays (probably by using every other index for the keys in an array), which are used by the type system. The other challenge would be to remove the global declarations (`declare -g`).\n\nAcknowledgments\n===============\n\nIf a function's been adapted or copied from the web or any other libraries out there, I always mention it in a comment within the code.\n\nAdditionally, in the making of the v1 of Bash Infinity I took some inspiration from object-oriented bash libraries:\n\n* https://github.com/tomas/skull/\n* https://github.com/domachine/oobash/\n* https://github.com/metal3d/Baboosh/\n* http://sourceforge.net/p/oobash/\n* http://lab.madscience.nl/oo.sh.txt\n* http://unix.stackexchange.com/questions/4495/object-oriented-shell-for-nix\n* http://hipersayanx.blogspot.sk/2012/12/object-oriented-programming-in-bash.html\n\nMore bash goodness:\n\n* http://wiki.bash-hackers.org\n* http://kvz.io/blog/2013/11/21/bash-best-practices/\n* http://www.davidpashley.com/articles/writing-robust-shell-scripts/\n* http://qntm.org/bash\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniieani%2Fbash-oo-framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniieani%2Fbash-oo-framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniieani%2Fbash-oo-framework/lists"}