diff --git a/.gitignore b/.gitignore index 6040af99..c287260e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ docs/_site *.ignore +test-ignore-* vendor builds/* !builds/.gitkeep diff --git a/docs/_includes/toc.md b/docs/_includes/toc.md index d42d1d29..89a31e83 100644 --- a/docs/_includes/toc.md +++ b/docs/_includes/toc.md @@ -28,6 +28,7 @@ ## Miscellaneous +* [Installing 3rd party libraries](/misc/3pl) * [Errors](/misc/error) * [Configuring the REPL](/misc/configuring-the-repl) * [Runtime](/misc/runtime) diff --git a/docs/misc/3pl.md b/docs/misc/3pl.md new file mode 100644 index 00000000..278edb61 --- /dev/null +++ b/docs/misc/3pl.md @@ -0,0 +1,92 @@ +# Installing 3rd party libraries + +The ABS interpreter comes with a built-in installer for 3rd party libraries, +very similar to `npm install`, `pip install` or `go get`. + +The installer, budled since the `1.8.0` release, is currently **experimental** +and a few things might change. + +In order to install a package, you simply need to run `abs get`: + +``` bash +$ abs get github.com/abs-lang/abs-sample-module +🌘 - Downloading archive +Unpacking... +Creating alias... +Install Success. You can use the module with `require("abs-sample-module")` +``` + +Modules will be saved under the `vendor/$MODULE-master` directory. Each module +also gets an alias to facilitate requiring them in your code, meaning that +both of these forms are supported: + +``` +⧐ require("abs-sample-module/sample.abs") +{"another": f() {return hello world;}} + +⧐ require("vendor/github.com/abs-lang/abs-sample-module-master/sample.abs") +{"another": f() {return hello world;}} +``` + +Note that the `-master` prefix [will be removed](https://github.com/abs-lang/abs/issues/286) in future versions of ABS. + +Module aliases are saved in the `packages.abs.json` file +which is created in the same directory where you run the +`abs get ...` command: + +``` +$ abs get github.com/abs-lang/abs-sample-module +🌗 - Downloading archive +Unpacking... +Creating alias... +Install Success. You can use the module with `require("abs-sample-module")` + +$ cat packages.abs.json +{ + "abs-sample-module": "./vendor/github.com/abs-lang/abs-sample-module-master" +} +``` + +If an alias is already taken, the installer will let you know that you +will need to use the full path when requiring the module: + +``` +$ echo '{"abs-sample-module": "xyz"}' > packages.abs.json + +$ abs get github.com/abs-lang/abs-sample-module +🌘 - Downloading archive +Unpacking... +Creating alias...This module could not be aliased because module of same name exists + +Install Success. You can use the module with `require("./vendor/github.com/abs-lang/abs-sample-module-master")` +``` + +When requiring a module, ABS will try to load the `index.abs` file unless +another file is specified: + +``` +$ ~/projects/abs/builds/abs +Hello alex, welcome to the ABS (1.8.0) programming language! +Type 'quit' when you're done, 'help' if you get lost! + +⧐ require("abs-sample-module") +{"another": f() {return hello world;}} + +⧐ require("abs-sample-module/index.abs") +{"another": f() {return hello world;}} + +⧐ require("abs-sample-module/another.abs") +f() {return hello world;} +``` + +## Supported hosting platforms + +Currently, the installer supports modules hosted on: + +* GitHub + +## Next + +That's about it for this section! + +You can now head over to read a little bit about [errors](/misc/error). \ No newline at end of file diff --git a/docs/types/builtin-function.md b/docs/types/builtin-function.md index 6610caaa..7a5aafaf 100644 --- a/docs/types/builtin-function.md +++ b/docs/types/builtin-function.md @@ -339,4 +339,4 @@ statements until changed. That's about it for this section! -You can now head over to read a little bit about [errors](/misc/error). \ No newline at end of file +You can now head over to read a little bit about [how to install 3rd party libraries](/misc/3pl). \ No newline at end of file diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index cc0d760c..a4a20240 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -945,10 +945,10 @@ c")`, []string{"a", "b", "c"}}, {`sleep(0.01)`, nil}, {`$()`, ""}, {`a = 1; eval("a")`, 1}, - {`"a = 2; return 10" >> "test-source-vs-require.abs.ignore"; a = 1; x = source("test-source-vs-require.abs.ignore"); a`, 2}, - {`"a = 2; return 10" >> "test-source-vs-require.abs.ignore"; a = 1; x = require("test-source-vs-require.abs.ignore"); a`, 1}, - {`"a = 2; return 10" >> "test-source-vs-require.abs.ignore"; a = 1; x = source("test-source-vs-require.abs.ignore"); x`, 10}, - {`"a = 2; return 10" >> "test-source-vs-require.abs.ignore"; a = 1; x = require("test-source-vs-require.abs.ignore"); x`, 10}, + {`"a = 2; return 10" >> "test-ignore-source-vs-require.abs"; a = 1; x = source("test-ignore-source-vs-require.abs"); a`, 2}, + {`"a = 2; return 10" >> "test-ignore-source-vs-require.abs"; a = 1; x = require("test-ignore-source-vs-require.abs"); a`, 1}, + {`"a = 2; return 10" >> "test-ignore-source-vs-require.abs"; a = 1; x = source("test-ignore-source-vs-require.abs"); x`, 10}, + {`"a = 2; return 10" >> "test-ignore-source-vs-require.abs"; a = 1; x = require("test-ignore-source-vs-require.abs"); x`, 10}, {`[[1,2,3], [2,3,4]].tsv()`, "1\t2\t3\n2\t3\t4"}, {`[1].tsv()`, "tsv() must be called on an array of arrays or objects, such as [[1, 2, 3], [4, 5, 6]], '[1]' given"}, {`[{"c": 3, "b": "hello"}, {"b": 20, "c": 0}].tsv()`, "b\tc\nhello\t3\n20\t0"}, diff --git a/util/util.go b/util/util.go index 03f6d66d..e5a06c43 100644 --- a/util/util.go +++ b/util/util.go @@ -122,15 +122,18 @@ func UnaliasPath(path string, packageAlias map[string]string) string { // paths p := []string{packageAlias[parts[0]]} p = append(p, parts[1:]...) + path = filepath.Join(p...) + } + return appendIndexFile(path) +} - // If our path didn't end with an ABS file, - // let's assume it's a directory and we will - // auto-include the index.abs file from it - if filepath.Ext(path) != ".abs" { - p = append(p, "index.abs") - } - - return filepath.Join(p...) +// If our path didn't end with an ABS file (.abs), +// let's assume it's a directory and we will +// auto-include the index.abs file from it +func appendIndexFile(path string) string { + if filepath.Ext(path) != ".abs" { + return filepath.Join(path, "index.abs") } + return path } diff --git a/util/util_test.go b/util/util_test.go index 0f98addc..2f62bb53 100644 --- a/util/util_test.go +++ b/util/util_test.go @@ -11,11 +11,11 @@ func TestUnaliasPath(t *testing.T) { aliases map[string]string expected string }{ - {"test", map[string]string{}, "test"}, + {"test", map[string]string{}, "test" + string(os.PathSeparator) + "index.abs"}, {"test" + string(os.PathSeparator) + "sample.abs", map[string]string{}, "test" + string(os.PathSeparator) + "sample.abs"}, {"test" + string(os.PathSeparator) + "sample.abs", map[string]string{"test": "path"}, "path" + string(os.PathSeparator) + "sample.abs"}, {"test", map[string]string{"test": "path"}, "path" + string(os.PathSeparator) + "index.abs"}, - {"." + string(os.PathSeparator) + "test", map[string]string{"test": "path"}, "." + string(os.PathSeparator) + "test"}, + {"." + string(os.PathSeparator) + "test", map[string]string{"test": "path"}, "test" + string(os.PathSeparator) + "index.abs"}, } for _, tt := range tests {