{"id":15700006,"url":"https://github.com/binaryphile/source-as-module","last_synced_at":"2025-05-12T13:03:44.459Z","repository":{"id":143324981,"uuid":"156932481","full_name":"binaryphile/source-as-module","owner":"binaryphile","description":"basic module system for bash","archived":false,"fork":false,"pushed_at":"2018-11-20T00:57:20.000Z","size":19,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-31T22:11:35.080Z","etag":null,"topics":["bash"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/binaryphile.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"publiccode":null,"codemeta":null}},"created_at":"2018-11-10T00:22:04.000Z","updated_at":"2025-02-25T01:12:45.000Z","dependencies_parsed_at":"2023-05-14T21:15:15.644Z","dependency_job_id":null,"html_url":"https://github.com/binaryphile/source-as-module","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsource-as-module","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsource-as-module/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsource-as-module/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsource-as-module/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/binaryphile","download_url":"https://codeload.github.com/binaryphile/source-as-module/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253745054,"owners_count":21957317,"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"],"created_at":"2024-10-03T19:43:52.609Z","updated_at":"2025-05-12T13:03:44.424Z","avatar_url":"https://github.com/binaryphile.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"Source As Module\n================\n\nAny bash library sourced with the help of *source as module*\nautomatically has the library name prepended to the names of its\nfunctions. The sourced library does not need any knowledge of *source as\nmodule*, only your code does.\n\nThis is a way to namespace functions so that they do not conflict with\nyour own. The effect is to emulate how other languages import functions\nfrom modules into their namespaces, languages such as Python and Ruby.\n\nFor the background on how *source as module* works, you can read my\n[blog post].\n\nRequirements\n------------\n\nThe sourced code must use the *name() {}* form of function declaration,\nnot the *function name {}* form.\n\nInstallation\n------------\n\nClone this repository or download *lib/as* and put it somewhere in front\nof */usr/bin* on your PATH.\n\nSourcing Regular Libraries with Source As Module\n------------------------------------------------\n\nFrom your code:\n\n``` bash\nsource as module /path/to/foo.sh\n```\n\nor for multiple libraries:\n\n``` bash\nsource as module /path/to/foo.sh /path/to/bar.sh\n```\n\n*/path/to* is optional if *foo.sh* is on your PATH.  That's a feature of\n*source*'s normal behavior.\n\nLet's say *foo.sh* defines the function *foo*. That function is now\navailable to your code as *foo.foo*.\n\n*source as module* drops the path and file extension from the filename\nto determine what name to use for the import. If you want to use a\ndifferent name, use the following:\n\n``` bash\nsource as module bar=/path/to/foo.sh\n```\n\nThis will import function *foo* as *bar.foo*. The same syntax works if\nyou are sourcing multiple files.\n\n*foo* (the unnamespaced version) is never instantiated, so your own\n*foo* definition won't be overwritten even if it exists before *foo.sh*\nis sourced.\n\nMaking Modules of Your Code\n---------------------------\n\nTo make it so that your own library becomes a module when sourced by\nother files using the regular *source* command, add this at the top of\nyour file:\n\n``` bash\nsource \"$(dirname \"$(readlink -f $BASH_SOURCE)\")\"/as module\nmodule.already_loaded \u0026\u0026 return\n```\n\nNote that MacOS requires GNU readlink, called as *greadlink*, from\nhomebrew.\n\nIn the shown use case, you'll want to distribute the *as* file with your\nscript. However if *as* is on the PATH of the system already, you don't\nneed the dirname and readlink calls, in which case the line is just\n*source as module*.\n\nIf your module is named *bar.sh* and defines a function named *bar*,\nthat function will be available to any code which sources your module as\n*bar.bar*. The sourcing code doesn't need to know about *source as\nmodule*, it just sources your module with *source /path/to/bar.sh*.\n\nThis allows you to write and call your functions without namespacing\nthem, but any file which sources your code will only see the namespaced\nversions. Calls to your functions from within your code will\nautomatically be converted to use the namespaced versions as well.\n\n*source as module* also defines a function called\n*module.already\\_loaded* which is used in the example above. It's only\nnecessary when you are using *source as module* to make your own library\nbe a module, but it is essential. You don't need it when you are loading\nregular (non-modular) libraries using *source as module\n/path/to/foo.sh*.\n\nOther Notes\n===========\n\nIf your code creates any global variables then you may want to namespace\nthose yourself manually by prefixing them with your module's name, e.g.\n*foo_myvar*.  Global variables may otherwise conflict with the caller's.\nUnfortunately *source as module* can't help with namespacing of\nvariables.\n\nNote that *source as module* does leave some private functions and\nvariables defined, but they are pre- and postfixed with an underscore so\nthey aren't likely to cause conflict with yours.\n\nWhy Source As Module?\n---------------------\n\nWhy not just *source module* instead of *source as module*?\nUnfortunately, bash is a little weird when it comes to passing\npositional arguments to sourced files.  You can pass arguments in the\n*source* call, but if you don't, then the caller's positional arguments\nare available instead.  This gets confusing for *source as module*,\nsince it uses the positional arguments to tell what it should do in the\ncontext of a particular invocation.\n\nTo always clear the caller's positional arguments, the alternatives are\nto either force you to call *set \\-\\-* before *source as module* or to\nrequire you to always feed the library a dummy argument.  I've chosen\nthe latter.  To the reader's eye, I feel that *source as module* reads\nthe most cleanly, so I've made the library's name *as* and require an\nargument of *module*.\n\nUsing Source As Module as a Library\n-----------------------------------\n\nTo source just the functions defined by *source as module*'s and not use\nits functionality, call *source as library*.\n\n  [blog post]: http://www.binaryphile.com/bash/2018/10/16/approach-bash-like-a-developer-part-33-modules.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinaryphile%2Fsource-as-module","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinaryphile%2Fsource-as-module","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinaryphile%2Fsource-as-module/lists"}