From 0549b1e5a8a3132005e275d6026db8003cb067d2 Mon Sep 17 00:00:00 2001 From: chai Date: Tue, 26 Oct 2021 11:32:46 +0800 Subject: *rename folder --- Data/DefaultContent/Libraries/GameLab/Class.lua | 38 + .../GameLab/Engine/Animation/Animation.lua | 0 .../Libraries/GameLab/Engine/Animation/init.lua | 6 + .../Libraries/GameLab/Engine/Core/Camera.lua | 5 + .../Libraries/GameLab/Engine/Core/Component.lua | 11 + .../Libraries/GameLab/Engine/Core/Game.lua | 14 + .../Libraries/GameLab/Engine/Core/GameObject.lua | 7 + .../Libraries/GameLab/Engine/Core/Sprite.lua | 21 + .../Libraries/GameLab/Engine/GL/init.lua | 20 + .../Libraries/GameLab/Engine/Math/Math.lua | 21 + .../Libraries/GameLab/Engine/Math/Matrix33.lua | 7 + .../Libraries/GameLab/Engine/Math/Matrix44.lua | 73 ++ .../Libraries/GameLab/Engine/Math/Quaternion.lua | 14 + .../Libraries/GameLab/Engine/Math/Vector2.lua | 5 + .../Libraries/GameLab/Engine/Math/Vector3.lua | 5 + .../Libraries/GameLab/Engine/Math/Vector4.lua | 45 + .../Libraries/GameLab/Engine/Math/init.lua | 16 + .../Libraries/GameLab/Engine/Rendering/Color.lua | 36 + .../Libraries/GameLab/Engine/Rendering/Color32.lua | 36 + .../Libraries/GameLab/Engine/Rendering/init.lua | 13 + .../Libraries/GameLab/Engine/Utils/EventCenter.lua | 23 + .../GameLab/Engine/Utils/StateMachine.lua | 0 .../Libraries/GameLab/Engine/Utils/Util.lua | 0 .../Libraries/GameLab/Engine/init.lua | 5 + Data/DefaultContent/Libraries/GameLab/Enum.lua | 9 + .../Libraries/GameLab/InternalClass.lua | 12 + Data/DefaultContent/Libraries/GameLab/init.lua | 41 + Data/DefaultContent/Libraries/LiteJson/LICENSE | 20 + Data/DefaultContent/Libraries/LiteJson/README.md | 46 + .../Libraries/LiteJson/bench/bench_all.lua | 6 + .../Libraries/LiteJson/bench/bench_decode.lua | 75 ++ .../Libraries/LiteJson/bench/bench_encode.lua | 63 ++ .../Libraries/LiteJson/bench/get_json_libs.sh | 15 + .../Libraries/LiteJson/bench/util/bench.lua | 62 ++ Data/DefaultContent/Libraries/LiteJson/json.lua | 388 +++++++ .../Libraries/LiteJson/test/test.lua | 245 +++++ Data/DefaultContent/Libraries/containers/README.md | 202 ++++ Data/DefaultContent/Libraries/containers/list.lua | 199 ++++ Data/DefaultContent/Libraries/containers/queue.lua | 111 ++ Data/DefaultContent/Libraries/containers/stack.lua | 67 ++ Data/DefaultContent/Libraries/containers/tuple.lua | 60 ++ .../DefaultContent/Libraries/containers/vector.lua | 122 +++ Data/DefaultContent/Libraries/inspect/.travis.yml | 36 + Data/DefaultContent/Libraries/inspect/CHANGELOG.md | 39 + .../Libraries/inspect/MIT-LICENSE.txt | 20 + Data/DefaultContent/Libraries/inspect/README.md | 253 +++++ Data/DefaultContent/Libraries/inspect/inspect.lua | 334 ++++++ .../inspect/rockspecs/inspect-1.2-2.rockspec | 23 + .../inspect/rockspecs/inspect-2.0-1.rockspec | 23 + .../inspect/rockspecs/inspect-3.0-1.rockspec | 23 + .../inspect/rockspecs/inspect-3.0-2.rockspec | 23 + .../inspect/rockspecs/inspect-3.0-3.rockspec | 23 + .../inspect/rockspecs/inspect-3.0-4.rockspec | 23 + .../inspect/rockspecs/inspect-3.1.1-0.rockspec | 23 + .../Libraries/inspect/spec/inspect_spec.lua | 460 +++++++++ .../Libraries/inspect/spec/unindent.lua | 39 + Data/DefaultContent/Libraries/json4lua/README.md | 52 + .../Libraries/json4lua/doc/INSTALL.txt | 4 + .../Libraries/json4lua/doc/LICENCE.txt | 21 + .../Libraries/json4lua/doc/README.txt | 5 + .../Libraries/json4lua/doc/VERSION.txt | 4 + .../Libraries/json4lua/doc/cgilua_patch.html | 187 ++++ .../Libraries/json4lua/doc/index.html | 394 ++++++++ .../Libraries/json4lua/doc/pics/json4lua.gif | Bin 0 -> 5023 bytes .../Libraries/json4lua/doc/pics/lunartone.gif | Bin 0 -> 312 bytes .../Libraries/json4lua/examples/example.lua | 23 + .../Libraries/json4lua/examples/jsonrpc.lua | 21 + .../Libraries/json4lua/examples/tests.lua | 223 +++++ .../Libraries/json4lua/examples/timetrials.lua | 46 + .../Libraries/json4lua/json/json.lua | 427 ++++++++ .../DefaultContent/Libraries/json4lua/json/rpc.lua | 107 ++ .../Libraries/json4lua/json/rpcserver.lua | 78 ++ .../Libraries/json4lua/json4lua-1.0.0-1.rockspec | 32 + Data/DefaultContent/Libraries/lbase64/.gitignore | 3 + Data/DefaultContent/Libraries/lbase64/.travis.yml | 25 + Data/DefaultContent/Libraries/lbase64/README.md | 48 + Data/DefaultContent/Libraries/lbase64/base64.lua | 201 ++++ Data/DefaultContent/Libraries/lbase64/bench.lua | 76 ++ .../lbase64/rockspec/base64-1.5-1.rockspec | 20 + .../lbase64/rockspec/base64-1.5-2.rockspec | 20 + .../lbase64/rockspec/base64-1.5-3.rockspec | 20 + Data/DefaultContent/Libraries/lbase64/test.lua | 47 + Data/DefaultContent/Libraries/lua-csv/.gitignore | 2 + Data/DefaultContent/Libraries/lua-csv/AUTHORS | 2 + Data/DefaultContent/Libraries/lua-csv/LICENSE | 22 + Data/DefaultContent/Libraries/lua-csv/README.md | 93 ++ .../DefaultContent/Libraries/lua-csv/lua/config.ld | 4 + Data/DefaultContent/Libraries/lua-csv/lua/csv.lua | 557 +++++++++++ Data/DefaultContent/Libraries/lua-csv/lua/test.lua | 102 ++ Data/DefaultContent/Libraries/lua-csv/makefile | 14 + .../Libraries/lua-csv/rockspecs/csv-1-1.rockspec | 24 + .../Libraries/lua-csv/rockspecs/csv-scm-1.rockspec | 23 + .../Libraries/lua-csv/test-data/BOM.csv | 3 + .../Libraries/lua-csv/test-data/bars.txt | 7 + .../Libraries/lua-csv/test-data/blank-line.csv | 2 + .../lua-csv/test-data/embedded-newlines.csv | 8 + .../lua-csv/test-data/embedded-quotes.csv | 2 + .../Libraries/lua-csv/test-data/header.csv | 3 + Data/DefaultContent/Libraries/luafun/.gitignore | 4 + Data/DefaultContent/Libraries/luafun/.travis.yml | 74 ++ .../Libraries/luafun/CONTRIBUTING.md | 20 + Data/DefaultContent/Libraries/luafun/COPYING.md | 27 + Data/DefaultContent/Libraries/luafun/README.md | 107 ++ .../Libraries/luafun/debian/.gitignore | 8 + .../Libraries/luafun/debian/changelog | 5 + Data/DefaultContent/Libraries/luafun/debian/compat | 1 + .../DefaultContent/Libraries/luafun/debian/control | 20 + .../Libraries/luafun/debian/copyright | 31 + .../Libraries/luafun/debian/lua-fun.docs | 1 + .../Libraries/luafun/debian/lua5.1.dh-lua.conf | 4 + .../Libraries/luafun/debian/lua5.2.dh-lua.conf | 1 + .../Libraries/luafun/debian/lua5.3.dh-lua.conf | 1 + .../Libraries/luafun/debian/patches/series | 0 Data/DefaultContent/Libraries/luafun/debian/rules | 12 + .../Libraries/luafun/debian/source/format | 1 + Data/DefaultContent/Libraries/luafun/debian/watch | 6 + .../DefaultContent/Libraries/luafun/doc/.gitignore | 1 + Data/DefaultContent/Libraries/luafun/doc/Makefile | 153 +++ .../Libraries/luafun/doc/_static/.keep | 0 .../Libraries/luafun/doc/_templates/layout.html | 14 + Data/DefaultContent/Libraries/luafun/doc/about.rst | 42 + Data/DefaultContent/Libraries/luafun/doc/basic.rst | 141 +++ .../Libraries/luafun/doc/compositions.rst | 140 +++ Data/DefaultContent/Libraries/luafun/doc/conf.py | 247 +++++ .../Libraries/luafun/doc/filtering.rst | 121 +++ .../Libraries/luafun/doc/generators.rst | 233 +++++ .../Libraries/luafun/doc/getting_started.rst | 254 +++++ Data/DefaultContent/Libraries/luafun/doc/index.rst | 29 + .../Libraries/luafun/doc/indexing.rst | 74 ++ Data/DefaultContent/Libraries/luafun/doc/intro.rst | 69 ++ Data/DefaultContent/Libraries/luafun/doc/logo.png | Bin 0 -> 14370 bytes Data/DefaultContent/Libraries/luafun/doc/logo.svg | 758 ++++++++++++++ Data/DefaultContent/Libraries/luafun/doc/make.bat | 190 ++++ .../Libraries/luafun/doc/operators.rst | 203 ++++ .../Libraries/luafun/doc/reducing.rst | 323 ++++++ .../Libraries/luafun/doc/reference.rst | 14 + .../Libraries/luafun/doc/slicing.rst | 246 +++++ .../Libraries/luafun/doc/transformations.rst | 87 ++ .../Libraries/luafun/doc/under_the_hood.rst | 154 +++ .../Libraries/luafun/fun-scm-1.rockspec | 34 + Data/DefaultContent/Libraries/luafun/fun.lua | 1058 ++++++++++++++++++++ .../Libraries/luafun/rpm/lua-fun.spec | 76 ++ .../Libraries/luafun/tests/.gitignore | 1 + .../Libraries/luafun/tests/basic.lua | 332 ++++++ .../Libraries/luafun/tests/compositions.lua | 170 ++++ .../Libraries/luafun/tests/filtering.lua | 102 ++ .../Libraries/luafun/tests/generators.lua | 287 ++++++ .../Libraries/luafun/tests/indexing.lua | 83 ++ .../Libraries/luafun/tests/operators.lua | 322 ++++++ .../Libraries/luafun/tests/reducing.lua | 289 ++++++ Data/DefaultContent/Libraries/luafun/tests/runtest | 114 +++ .../Libraries/luafun/tests/slicing.lua | 339 +++++++ .../Libraries/luafun/tests/transformations.lua | 107 ++ Data/DefaultContent/Libraries/md5.lua/.travis.yml | 34 + Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md | 5 + .../Libraries/md5.lua/MIT-LICENSE.txt | 20 + Data/DefaultContent/Libraries/md5.lua/README.md | 62 ++ Data/DefaultContent/Libraries/md5.lua/md5.lua | 396 ++++++++ .../Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec | 21 + .../Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec | 21 + .../Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec | 21 + .../Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec | 21 + .../Libraries/md5.lua/spec/md5_spec.lua | 40 + .../Libraries/middleclass/.travis.yml | 36 + .../Libraries/middleclass/CHANGELOG.md | 55 + .../Libraries/middleclass/MIT-LICENSE.txt | 20 + .../DefaultContent/Libraries/middleclass/README.md | 80 ++ .../Libraries/middleclass/UPDATING.md | 69 ++ .../Libraries/middleclass/middleclass.lua | 183 ++++ .../Libraries/middleclass/performance/run.lua | 43 + .../Libraries/middleclass/performance/time.lua | 13 + .../rockspecs/middleclass-3.0-0.rockspec | 21 + .../rockspecs/middleclass-3.1-0.rockspec | 21 + .../rockspecs/middleclass-3.2-0.rockspec | 21 + .../rockspecs/middleclass-4.0-0.rockspec | 21 + .../rockspecs/middleclass-4.1-0.rockspec | 21 + .../rockspecs/middleclass-4.1.1-0.rockspec | 21 + .../Libraries/middleclass/spec/class_spec.lua | 28 + .../Libraries/middleclass/spec/classes_spec.lua | 138 +++ .../middleclass/spec/default_methods_spec.lua | 236 +++++ .../Libraries/middleclass/spec/instances_spec.lua | 65 ++ .../middleclass/spec/metamethods_lua_5_2.lua | 85 ++ .../middleclass/spec/metamethods_lua_5_3.lua | 106 ++ .../middleclass/spec/metamethods_spec.lua | 317 ++++++ .../Libraries/middleclass/spec/mixins_spec.lua | 53 + Data/DefaultContent/Libraries/socket/README.txt | 1 + Data/DefaultContent/Libraries/socket/core.dll | Bin 0 -> 104448 bytes 187 files changed, 15883 insertions(+) create mode 100644 Data/DefaultContent/Libraries/GameLab/Class.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Animation/Animation.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Animation/init.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Core/Camera.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Core/Component.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Core/Game.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Core/GameObject.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Core/Sprite.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/GL/init.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix33.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix44.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector2.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector3.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector4.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Math/init.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color32.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Rendering/init.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Utils/EventCenter.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Utils/StateMachine.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/Utils/Util.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Engine/init.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/Enum.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/InternalClass.lua create mode 100644 Data/DefaultContent/Libraries/GameLab/init.lua create mode 100644 Data/DefaultContent/Libraries/LiteJson/LICENSE create mode 100644 Data/DefaultContent/Libraries/LiteJson/README.md create mode 100644 Data/DefaultContent/Libraries/LiteJson/bench/bench_all.lua create mode 100644 Data/DefaultContent/Libraries/LiteJson/bench/bench_decode.lua create mode 100644 Data/DefaultContent/Libraries/LiteJson/bench/bench_encode.lua create mode 100644 Data/DefaultContent/Libraries/LiteJson/bench/get_json_libs.sh create mode 100644 Data/DefaultContent/Libraries/LiteJson/bench/util/bench.lua create mode 100644 Data/DefaultContent/Libraries/LiteJson/json.lua create mode 100644 Data/DefaultContent/Libraries/LiteJson/test/test.lua create mode 100644 Data/DefaultContent/Libraries/containers/README.md create mode 100644 Data/DefaultContent/Libraries/containers/list.lua create mode 100644 Data/DefaultContent/Libraries/containers/queue.lua create mode 100644 Data/DefaultContent/Libraries/containers/stack.lua create mode 100644 Data/DefaultContent/Libraries/containers/tuple.lua create mode 100644 Data/DefaultContent/Libraries/containers/vector.lua create mode 100644 Data/DefaultContent/Libraries/inspect/.travis.yml create mode 100644 Data/DefaultContent/Libraries/inspect/CHANGELOG.md create mode 100644 Data/DefaultContent/Libraries/inspect/MIT-LICENSE.txt create mode 100644 Data/DefaultContent/Libraries/inspect/README.md create mode 100644 Data/DefaultContent/Libraries/inspect/inspect.lua create mode 100644 Data/DefaultContent/Libraries/inspect/rockspecs/inspect-1.2-2.rockspec create mode 100644 Data/DefaultContent/Libraries/inspect/rockspecs/inspect-2.0-1.rockspec create mode 100644 Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-1.rockspec create mode 100644 Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-2.rockspec create mode 100644 Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-3.rockspec create mode 100644 Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-4.rockspec create mode 100644 Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.1.1-0.rockspec create mode 100644 Data/DefaultContent/Libraries/inspect/spec/inspect_spec.lua create mode 100644 Data/DefaultContent/Libraries/inspect/spec/unindent.lua create mode 100644 Data/DefaultContent/Libraries/json4lua/README.md create mode 100644 Data/DefaultContent/Libraries/json4lua/doc/INSTALL.txt create mode 100644 Data/DefaultContent/Libraries/json4lua/doc/LICENCE.txt create mode 100644 Data/DefaultContent/Libraries/json4lua/doc/README.txt create mode 100644 Data/DefaultContent/Libraries/json4lua/doc/VERSION.txt create mode 100644 Data/DefaultContent/Libraries/json4lua/doc/cgilua_patch.html create mode 100644 Data/DefaultContent/Libraries/json4lua/doc/index.html create mode 100644 Data/DefaultContent/Libraries/json4lua/doc/pics/json4lua.gif create mode 100644 Data/DefaultContent/Libraries/json4lua/doc/pics/lunartone.gif create mode 100644 Data/DefaultContent/Libraries/json4lua/examples/example.lua create mode 100644 Data/DefaultContent/Libraries/json4lua/examples/jsonrpc.lua create mode 100644 Data/DefaultContent/Libraries/json4lua/examples/tests.lua create mode 100644 Data/DefaultContent/Libraries/json4lua/examples/timetrials.lua create mode 100644 Data/DefaultContent/Libraries/json4lua/json/json.lua create mode 100644 Data/DefaultContent/Libraries/json4lua/json/rpc.lua create mode 100644 Data/DefaultContent/Libraries/json4lua/json/rpcserver.lua create mode 100644 Data/DefaultContent/Libraries/json4lua/json4lua-1.0.0-1.rockspec create mode 100644 Data/DefaultContent/Libraries/lbase64/.gitignore create mode 100644 Data/DefaultContent/Libraries/lbase64/.travis.yml create mode 100644 Data/DefaultContent/Libraries/lbase64/README.md create mode 100644 Data/DefaultContent/Libraries/lbase64/base64.lua create mode 100644 Data/DefaultContent/Libraries/lbase64/bench.lua create mode 100644 Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-1.rockspec create mode 100644 Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-2.rockspec create mode 100644 Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-3.rockspec create mode 100644 Data/DefaultContent/Libraries/lbase64/test.lua create mode 100644 Data/DefaultContent/Libraries/lua-csv/.gitignore create mode 100644 Data/DefaultContent/Libraries/lua-csv/AUTHORS create mode 100644 Data/DefaultContent/Libraries/lua-csv/LICENSE create mode 100644 Data/DefaultContent/Libraries/lua-csv/README.md create mode 100644 Data/DefaultContent/Libraries/lua-csv/lua/config.ld create mode 100644 Data/DefaultContent/Libraries/lua-csv/lua/csv.lua create mode 100644 Data/DefaultContent/Libraries/lua-csv/lua/test.lua create mode 100644 Data/DefaultContent/Libraries/lua-csv/makefile create mode 100644 Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-1-1.rockspec create mode 100644 Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-scm-1.rockspec create mode 100644 Data/DefaultContent/Libraries/lua-csv/test-data/BOM.csv create mode 100644 Data/DefaultContent/Libraries/lua-csv/test-data/bars.txt create mode 100644 Data/DefaultContent/Libraries/lua-csv/test-data/blank-line.csv create mode 100644 Data/DefaultContent/Libraries/lua-csv/test-data/embedded-newlines.csv create mode 100644 Data/DefaultContent/Libraries/lua-csv/test-data/embedded-quotes.csv create mode 100644 Data/DefaultContent/Libraries/lua-csv/test-data/header.csv create mode 100644 Data/DefaultContent/Libraries/luafun/.gitignore create mode 100644 Data/DefaultContent/Libraries/luafun/.travis.yml create mode 100644 Data/DefaultContent/Libraries/luafun/CONTRIBUTING.md create mode 100644 Data/DefaultContent/Libraries/luafun/COPYING.md create mode 100644 Data/DefaultContent/Libraries/luafun/README.md create mode 100644 Data/DefaultContent/Libraries/luafun/debian/.gitignore create mode 100644 Data/DefaultContent/Libraries/luafun/debian/changelog create mode 100644 Data/DefaultContent/Libraries/luafun/debian/compat create mode 100644 Data/DefaultContent/Libraries/luafun/debian/control create mode 100644 Data/DefaultContent/Libraries/luafun/debian/copyright create mode 100644 Data/DefaultContent/Libraries/luafun/debian/lua-fun.docs create mode 100644 Data/DefaultContent/Libraries/luafun/debian/lua5.1.dh-lua.conf create mode 100644 Data/DefaultContent/Libraries/luafun/debian/lua5.2.dh-lua.conf create mode 100644 Data/DefaultContent/Libraries/luafun/debian/lua5.3.dh-lua.conf create mode 100644 Data/DefaultContent/Libraries/luafun/debian/patches/series create mode 100644 Data/DefaultContent/Libraries/luafun/debian/rules create mode 100644 Data/DefaultContent/Libraries/luafun/debian/source/format create mode 100644 Data/DefaultContent/Libraries/luafun/debian/watch create mode 100644 Data/DefaultContent/Libraries/luafun/doc/.gitignore create mode 100644 Data/DefaultContent/Libraries/luafun/doc/Makefile create mode 100644 Data/DefaultContent/Libraries/luafun/doc/_static/.keep create mode 100644 Data/DefaultContent/Libraries/luafun/doc/_templates/layout.html create mode 100644 Data/DefaultContent/Libraries/luafun/doc/about.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/basic.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/compositions.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/conf.py create mode 100644 Data/DefaultContent/Libraries/luafun/doc/filtering.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/generators.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/getting_started.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/index.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/indexing.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/intro.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/logo.png create mode 100644 Data/DefaultContent/Libraries/luafun/doc/logo.svg create mode 100644 Data/DefaultContent/Libraries/luafun/doc/make.bat create mode 100644 Data/DefaultContent/Libraries/luafun/doc/operators.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/reducing.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/reference.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/slicing.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/transformations.rst create mode 100644 Data/DefaultContent/Libraries/luafun/doc/under_the_hood.rst create mode 100644 Data/DefaultContent/Libraries/luafun/fun-scm-1.rockspec create mode 100644 Data/DefaultContent/Libraries/luafun/fun.lua create mode 100644 Data/DefaultContent/Libraries/luafun/rpm/lua-fun.spec create mode 100644 Data/DefaultContent/Libraries/luafun/tests/.gitignore create mode 100644 Data/DefaultContent/Libraries/luafun/tests/basic.lua create mode 100644 Data/DefaultContent/Libraries/luafun/tests/compositions.lua create mode 100644 Data/DefaultContent/Libraries/luafun/tests/filtering.lua create mode 100644 Data/DefaultContent/Libraries/luafun/tests/generators.lua create mode 100644 Data/DefaultContent/Libraries/luafun/tests/indexing.lua create mode 100644 Data/DefaultContent/Libraries/luafun/tests/operators.lua create mode 100644 Data/DefaultContent/Libraries/luafun/tests/reducing.lua create mode 100644 Data/DefaultContent/Libraries/luafun/tests/runtest create mode 100644 Data/DefaultContent/Libraries/luafun/tests/slicing.lua create mode 100644 Data/DefaultContent/Libraries/luafun/tests/transformations.lua create mode 100644 Data/DefaultContent/Libraries/md5.lua/.travis.yml create mode 100644 Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md create mode 100644 Data/DefaultContent/Libraries/md5.lua/MIT-LICENSE.txt create mode 100644 Data/DefaultContent/Libraries/md5.lua/README.md create mode 100644 Data/DefaultContent/Libraries/md5.lua/md5.lua create mode 100644 Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec create mode 100644 Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec create mode 100644 Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec create mode 100644 Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec create mode 100644 Data/DefaultContent/Libraries/md5.lua/spec/md5_spec.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/.travis.yml create mode 100644 Data/DefaultContent/Libraries/middleclass/CHANGELOG.md create mode 100644 Data/DefaultContent/Libraries/middleclass/MIT-LICENSE.txt create mode 100644 Data/DefaultContent/Libraries/middleclass/README.md create mode 100644 Data/DefaultContent/Libraries/middleclass/UPDATING.md create mode 100644 Data/DefaultContent/Libraries/middleclass/middleclass.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/performance/run.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/performance/time.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.0-0.rockspec create mode 100644 Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.1-0.rockspec create mode 100644 Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.2-0.rockspec create mode 100644 Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.0-0.rockspec create mode 100644 Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1-0.rockspec create mode 100644 Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1.1-0.rockspec create mode 100644 Data/DefaultContent/Libraries/middleclass/spec/class_spec.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/spec/classes_spec.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/spec/default_methods_spec.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/spec/instances_spec.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_2.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_3.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/spec/metamethods_spec.lua create mode 100644 Data/DefaultContent/Libraries/middleclass/spec/mixins_spec.lua create mode 100644 Data/DefaultContent/Libraries/socket/README.txt create mode 100644 Data/DefaultContent/Libraries/socket/core.dll (limited to 'Data/DefaultContent/Libraries') diff --git a/Data/DefaultContent/Libraries/GameLab/Class.lua b/Data/DefaultContent/Libraries/GameLab/Class.lua new file mode 100644 index 0000000..62369e1 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Class.lua @@ -0,0 +1,38 @@ +-- Declare class + +local _class = function (className) + local class = {} + local pkgName = (type(className) == "string") and string.match(className, "^(.+)%.%w+$") or "" + local shortName = (type(className) == "string") and string.match(className, "%.*(%w+)$") or "" + class._type = { -- 类型元数据,GameLab的类型都会包含这些 + mode = "lua", + name = shortName or "", + package = pkgName or "", + fullName = className + } + class.__index = class + class.New = function(...) + local instance = {} + setmetatable(instance, class) + instance:Ctor(...) + return instance + end + return class +end + +-- 提供ClassName和PkgName作为类型的元数据,可以留空,但是最好提供,会作为类型判断的依据 +local Class = function(className) + local cls = _class(className) + cls.Extend = function(childName) + local child = _class(childName) + if cls then + setmetatable(child, cls) + child.base = cls + end + return child + end + return cls +end + +GameLab.Class = Class +return Class \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Animation/Animation.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Animation/Animation.lua new file mode 100644 index 0000000..e69de29 diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Animation/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Animation/init.lua new file mode 100644 index 0000000..032f42d --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Animation/init.lua @@ -0,0 +1,6 @@ +GameLab.Animation = GameLab.Animation or {} +local m = GameLab.Animation + + + +return m \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/Camera.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Camera.lua new file mode 100644 index 0000000..5fcfbe7 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Camera.lua @@ -0,0 +1,5 @@ +local Camera = {} + + + +return Camera \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/Component.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Component.lua new file mode 100644 index 0000000..00bf2ca --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Component.lua @@ -0,0 +1,11 @@ +local Component = {} + +Component.New = function() + +end + +Component.GetGameObject = function() + +end + +Jin.Component = Component \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/Game.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Game.lua new file mode 100644 index 0000000..51ce25f --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Game.lua @@ -0,0 +1,14 @@ + +-- Game entry + +local Game = {} + +Game.OnEvent = function(e) + +end + +Game.MainLoop = function() + +end + +return Game \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/GameObject.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/GameObject.lua new file mode 100644 index 0000000..ee0d143 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/GameObject.lua @@ -0,0 +1,7 @@ +local GameObject = {} + +GameObject.AddComponent = function(self, comp) + +end + +Jin.GameObject = GameObject diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/Sprite.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Sprite.lua new file mode 100644 index 0000000..47cb50d --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Sprite.lua @@ -0,0 +1,21 @@ +-- Quadķװʺ2DϷ +local Sprite = {} + +Sprite.New = function(quad) + local spr = {} + spr.quad = Jin.Quad.New(quad) + spr.pivot = Jin.Vector2.New(0.5, 0) + spr.transform = Jin.Transform.New() + spr.depth = 0 + return spr +end + +Sprite.SetDepth = function(self, depth) + spr.depth = depth +end + +Sprite.SetTexture = function(self, tex, reset_quad) + +end + +Jin.Sprite = Sprite \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/GL/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/GL/init.lua new file mode 100644 index 0000000..f69d1f6 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/GL/init.lua @@ -0,0 +1,20 @@ +local GL = GameLab.Engine.GL or {} +GameLab.Engine.GL = GL + +local Matrix44 = GameLab.find("GameLab.Engine.Math.Matrix44") + +GL.LoadPixelMatrix = function(l, r, b, t) + local ortho = Matrix44.New() + ortho:SetOrtho(l, r, b, t, 0.1, 10) + GL.MatrixMode(GL.EMatrixMode.Projection) + GL.LoadIdentity() + GL.LoadMatrix(ortho) + GL.MatrixMode(GL.EMatrixMode.ModelView) + GL.LoadIdentity() +end + +GL.LoadPixelMatrixTL = function (l, r, b, t) + +end + +return GL \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua new file mode 100644 index 0000000..0bbe7f0 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua @@ -0,0 +1,21 @@ +-- 数学函数 +local m = GameLab.Engine.Math or {} +GameLab.Engine.Math = m + +m.Abs = function(n) + +end + +m.Lerp = function (a, b, t) + +end + +m.Round = function (n) + +end + +m.Sign = function(n) + +end + +return m \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix33.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix33.lua new file mode 100644 index 0000000..8cb7e72 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix33.lua @@ -0,0 +1,7 @@ +local Matrix33 = GameLab.Class("GameLab.Engine.Math.Matrix33") + +Matrix33.Ctor = function(self) + +end + +return Matrix33 \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix44.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix44.lua new file mode 100644 index 0000000..2347207 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix44.lua @@ -0,0 +1,73 @@ +local Matrix44 = GameLab.Class("GameLab.Engine.Math.Matrix44") + +Matrix44.Ctor = function(self) + for r = 0, 3 do + for c = 0, 3 do + self["m"..r..c] = 0 + end + end +end + +Matrix44.Clear = function(self) + for r = 0, 3 do + for c = 0, 3 do + self["m"..r..c] = 0 + end + end +end + +Matrix44.SetRow = function(self, row, value) + +end + +Matrix44.SetColum = function(self, colum, value) + +end + +Matrix44.Set = function(self, row, colum ,value) + +end + +Matrix44.GetColum = function(self, colum) + +end + +Matrix44.GetRow = function(self, row) + +end + +-- note: n>0, f>0 +Matrix44.SetOrtho = function(self, l, r, b, t, n, f) + self:Clear() + self.m00 = 2 / (r - l) + self.m03 = (r + l) / (l - r) + self.m11 = 2 / (t - b) + self.m13 = (t + b) / (b - t) + self.m22 = 2 / (n - f) + self.m23 = (f + n) / (n - f) + self.m33 = 1 +end + +-- note: n>0, f>0 +Matrix44.SetFrustum = function(self, l, r, b, t, n, f) + self:Clear() + self.m00 = 2 * n / (r - l) + self.m02 = (r + l) / (r - l) + self.m11 = 2 * n / (t - b) + self.m12 = (t + b) / (t - b) + self.m22 = (f + n) / (n - f) + self.m23 = 2 * f * n / (n - f) + self.m32 = -1 +end + +-- note: n>0, f>0 +Matrix44.SetPerspective = function(self, fov, aspect, near, far) + self:Clear() + self.m00 = 1 / (aspect * math.tan(fov/2)) + self.m11 = 1 / math.tan(fov/2) + self.m22 = (far + near) / (near - far) + self.m23 = 2 * far * near / (near - far) + self.m32 = -1 +end + +return Matrix44 \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua new file mode 100644 index 0000000..4d690e3 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua @@ -0,0 +1,14 @@ +local Quaternion = {} + +Quaternion.Ctor = function(self) + self.x = 0 + self.y = 0 + self.z = 0 + self.w = 0 +end + +Quaternion.Euler = function(euler) + +end + +return Quaternion \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector2.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector2.lua new file mode 100644 index 0000000..5697797 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector2.lua @@ -0,0 +1,5 @@ +local Vector2 = GameLab.Class("GameLab.Engine.Math.Vector2") + + + +return Vector2 \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector3.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector3.lua new file mode 100644 index 0000000..caa28a4 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector3.lua @@ -0,0 +1,5 @@ +local Vector3 = GameLab.Class("GameLab.Engine.Math.Vector3") + + + +return Vector3 \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector4.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector4.lua new file mode 100644 index 0000000..e232c93 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector4.lua @@ -0,0 +1,45 @@ +local Vector4 = GameLab.Class("GameLab.Engine.Math.Vector4") + +Vector4.Ctor = function (self, x, y, z, w) + self.x = x or 0 + self.y = y or 0 + self.z = z or 0 + self.w = w or 0 +end + +Vector4.Magnitude = function (self) + +end + +Vector4.Normalized = function (self) + +end + +Vector4.SqrMagnitude = function (self) + +end + +Vector4.Distance = function (self, to) + +end + +Vector4.Dot = function(self, v) + +end + +Vector4.Lerp = function(self, v, t) + +end + +Vector4.Project = function (self, v) + +end + +Vector4.Scale = function(self, scale) + +end + +Vector4.one = Vector4.New(1,1,1,1) +Vector4.zero = Vector4.New(0,0,0,0) + +return Vector4 \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/init.lua new file mode 100644 index 0000000..eb75db7 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/init.lua @@ -0,0 +1,16 @@ +local m = GameLab.Engine.Math or {} +GameLab.Engine.Math = m + +local import = GameLab.import(...) + +import("Math") +m.Vector2 = import("Vector2") +m.Vector3 = import("Vector3") +m.Vector4 = import("Vector4") +m.Matrix44 = import("Matrix44") +m.Matrix33 = import("Matrix33") +m.Quaternion = import("Quaternion") + +GameLab.Debug.Log("GameLab.Engine.Math loaded") + +return m \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color.lua new file mode 100644 index 0000000..bf908a4 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color.lua @@ -0,0 +1,36 @@ +local Color = GameLab.Class("GameLab.Engine.Rendering.Color") + +Color.Ctor = function(self, r, g, b, a) + self.r = r + self.g = g + self.b = b + self.a = a +end + +Color.ToColor32 = function(self) + local Color32 = GameLab.find("GameLab.Engine.Rendering.Color32") + local c32 = Color32.New() + c32.r = self.r * 255 + c32.g = self.g * 255 + c32.b = self.b * 255 + c32.a = self.a * 255 + return c32 +end + +Color.Clear = function(self) + self.r = 0 + self.g = 0 + self.b = 0 + self.a = 0 +end + +Color.red = Color.New(1,0,0,1) +Color.green = Color.New(0,1,0,1) +Color.blue = Color.New(0,0,1,1) +Color.magenta = Color.New(1,0,1,1) +Color.red = Color.New(1,0,0,1) +Color.yellow = Color.New(1,1,0,1) +Color.black = Color.New(0,0,0,1) +Color.white = Color.New(1,1,1,1) + +return Color \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color32.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color32.lua new file mode 100644 index 0000000..d108dfb --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color32.lua @@ -0,0 +1,36 @@ +local Color32 = GameLab.Class("GameLab.Engine.Rendering.Color32") + +Color32.Ctor = function(self, r, g, b, a) + self.r = r + self.g = g + self.b = b + self.a = a +end + +Color32.ToColor = function(self) + local Color = GameLab.find("GameLab.Engine.Rendering.Color") + local c = Color.New() + c.r = self.r / 255 + c.g = self.g / 255 + c.b = self.b / 255 + c.a = self.a / 255 + return c +end + +Color32.Clear = function(self) + self.r = 0 + self.g = 0 + self.b = 0 + self.a = 0 +end + +Color32.red = Color32.New(255,0,0,255) +Color32.green = Color32.New(0,255,0,255) +Color32.blue = Color32.New(0,0,255,255) +Color32.magenta = Color32.New(255,0,255,255) +Color32.red = Color32.New(255,0,0,255) +Color32.yellow = Color32.New(255,255,0,255) +Color32.black = Color32.New(0,0,0,255) +Color32.white = Color32.New(255,255,255,255) + +return Color32 \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/init.lua new file mode 100644 index 0000000..d9b4e3e --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/init.lua @@ -0,0 +1,13 @@ +local m = GameLab.Engine.Rendering or {} +GameLab.Engine.Rendering = m + +local import = GameLab.import(...) + +m.Color = import("Color") +m.Color32 = import("Color32") + +m.LoadTexture = function(path) + +end + +return m \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Utils/EventCenter.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/EventCenter.lua new file mode 100644 index 0000000..664ecba --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/EventCenter.lua @@ -0,0 +1,23 @@ +local EventCenter = {} + +EventCenter.Subscribe = function(event, callback) + +end + +EventCenter.Unsubscribe = function(event, callback) + +end + +EventCenter.UnsubscribeAll = function(event) + +end + +EventCenter.Publish = function(event, ...) + +end + +EventCenter.Clear = function() + +end + +Jin.EventCenter = EventCenter \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Utils/StateMachine.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/StateMachine.lua new file mode 100644 index 0000000..e69de29 diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Utils/Util.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/Util.lua new file mode 100644 index 0000000..e69de29 diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/init.lua new file mode 100644 index 0000000..f6f46a4 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Engine/init.lua @@ -0,0 +1,5 @@ +GameLab.Engine = GameLab.Engine or {} + +local import = GameLab.import(...) + +return GameLab.Engine \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/Enum.lua b/Data/DefaultContent/Libraries/GameLab/Enum.lua new file mode 100644 index 0000000..d1a1ae0 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/Enum.lua @@ -0,0 +1,9 @@ +-- Declare enum + + +local Enum = function() + +end + + +GameLab.Enum = Enum \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/InternalClass.lua b/Data/DefaultContent/Libraries/GameLab/InternalClass.lua new file mode 100644 index 0000000..36ad568 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/InternalClass.lua @@ -0,0 +1,12 @@ +local Class = GameLab.Class or require("GameLab.Class") + +-- 声明类的同时添加到G表 +local InternalClass = function(className) + local cls = Class(className) + _G[className] = className + return cls +end + +GameLab.InternalClass = InternalClass + +return InternalClass \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/GameLab/init.lua b/Data/DefaultContent/Libraries/GameLab/init.lua new file mode 100644 index 0000000..c87ace3 --- /dev/null +++ b/Data/DefaultContent/Libraries/GameLab/init.lua @@ -0,0 +1,41 @@ +GameLab = GameLab or {} + +-- methods +-- 用于模块的init.lua中加载模块内的脚本 +GameLab.import = function(packageName) + local _import = function(path) + local name = packageName .. "." .. path + local m = require(name) + --package.loaded[name] = m + return m + end + return _import +end + +-- 用于相对路径包含 +-- GameLab.require = function(className) +-- local packageName = (type(className) == "string") and string.match(className, "^(.+)%.%w+$") or "" +-- local _require = function(path) +-- local name = packageName .. "." .. path +-- local m = require(name) +-- return m +-- end +-- return _require +-- end + +GameLab.find = function(fullName) + if _G[fullName] ~= nil then + return _G[fullName] + end + if package.loaded[fullName] ~= nil then + return package.loaded[fullName] + end + return require(fullName) +end + +-- classes +GameLab.Class = require("GameLab.Class") + +GameLab.InternalClass = require("GameLab.InternalClass") + +return GameLab \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/LiteJson/LICENSE b/Data/DefaultContent/Libraries/LiteJson/LICENSE new file mode 100644 index 0000000..9eb37b1 --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2020 rxi + + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Data/DefaultContent/Libraries/LiteJson/README.md b/Data/DefaultContent/Libraries/LiteJson/README.md new file mode 100644 index 0000000..96b9b66 --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/README.md @@ -0,0 +1,46 @@ +# ![json.lua](https://cloud.githubusercontent.com/assets/3920290/9281532/99e5e0cc-42bd-11e5-8fce-eaff2f7fc681.png) +A lightweight JSON library for Lua + + +## Features +* Implemented in pure Lua: works with 5.1, 5.2, 5.3 and JIT +* Fast: generally outperforms other pure Lua JSON implementations + ([benchmark scripts](bench/)) +* Tiny: around 280sloc, 9kb +* Proper error messages, *eg:* `expected '}' or ',' at line 203 col 30` + + +## Usage +The [json.lua](json.lua?raw=1) file should be dropped into an existing project +and required by it: +```lua +json = require "json" +``` +The library provides the following functions: + +#### json.encode(value) +Returns a string representing `value` encoded in JSON. +```lua +json.encode({ 1, 2, 3, { x = 10 } }) -- Returns '[1,2,3,{"x":10}]' +``` + +#### json.decode(str) +Returns a value representing the decoded JSON string. +```lua +json.decode('[1,2,3,{"x":10}]') -- Returns { 1, 2, 3, { x = 10 } } +``` + +## Notes +* Trying to encode values which are unrepresentable in JSON will never result + in type conversion or other magic: sparse arrays, tables with mixed key types + or invalid numbers (NaN, -inf, inf) will raise an error +* `null` values contained within an array or object are converted to `nil` and + are therefore lost upon decoding +* *Pretty* encoding is not supported, `json.encode()` only encodes to a compact + format + + +## License +This library is free software; you can redistribute it and/or modify it under +the terms of the MIT license. See [LICENSE](LICENSE) for details. + diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/bench_all.lua b/Data/DefaultContent/Libraries/LiteJson/bench/bench_all.lua new file mode 100644 index 0000000..3f99e99 --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/bench/bench_all.lua @@ -0,0 +1,6 @@ + +print("[decode]") +loadfile("bench_decode.lua")() +print() +print("[encode]") +loadfile("bench_encode.lua")() diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/bench_decode.lua b/Data/DefaultContent/Libraries/LiteJson/bench/bench_decode.lua new file mode 100644 index 0000000..6c2e93a --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/bench/bench_decode.lua @@ -0,0 +1,75 @@ +local bench = require "util.bench" + + +local libs = { + "../json.lua", -- https://github.com/rxi/json.lua + "dkjson.lua", -- https://github.com/LuaDist/dkjson + "jfjson.lua", -- http://regex.info/blog/lua/json + --"json4lua.lua", -- https://github.com/craigmj/json4lua +} + + +-- JSON string: wikipedia example stored 1000 times in an array +local text = "[" .. string.rep([[{ + "firstName": "John", + "lastName": "Smith", + "isAlive": true, + "age": 25, + "address": { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": "10021-3100" + }, + "phoneNumbers": [ + { + "type": "home", + "number": "212 555-1234" + }, + { + "type": "office", + "number": "646 555-4567" + } + ], + "children": [], + "spouse": null +}, ]], 1000):sub(1, -3) .. "]" + + +-- As this is meant to be a pure Lua benchmark, we remove the ability to +-- require 'lpeg' so dkjson doesn't use it for parsing. (Incidentally json.lua +-- seems to outperform libraries which use lpeg when both are using LuaJIT) +local _require = require +require = function(modname) + if modname == "lpeg" then error() end + return _require(modname) +end + +-- Run benchmarks, store results +local results = {} + +for i, name in ipairs(libs) do + local f = loadfile(name) + if not f then + error( "failed to load '" .. name .. "'; run './get_json_libs.sh'" ) + end + local json = f() + + -- Remap functions to work for jfjson.lua + if name == "jfjson.lua" then + local _encode, _decode = json.encode, json.decode + json.encode = function(...) return _encode(json, ...) end + json.decode = function(...) return _decode(json, ...) end + end + + -- Warmup (for LuaJIT) + bench.run(name, 1, function() json.decode(text) end) + + -- Run and push results + local res = bench.run(name, 10, function() json.decode(text) end) + table.insert(results, res) +end + + +bench.print_system_info() +bench.print_results(results) diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/bench_encode.lua b/Data/DefaultContent/Libraries/LiteJson/bench/bench_encode.lua new file mode 100644 index 0000000..426f7c8 --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/bench/bench_encode.lua @@ -0,0 +1,63 @@ +local bench = require "util.bench" + + +local libs = { + "../json.lua", -- https://github.com/rxi/json.lua + "dkjson.lua", -- https://github.com/LuaDist/dkjson + "jfjson.lua", -- http://regex.info/blog/lua/json + "json4lua.lua", -- https://github.com/craigmj/json4lua +} + + +-- Build table which will be encoded: wikipedia example stored 1000 times +local data = {} +for i = 1, 1000 do + table.insert(data, { + firstName = "John", + lastName = "Smith", + isAlive = true, + age = 25, + address = { + streetAddress = "21 2nd Street", + city = "New York", + state = "NY", + postalCode = "10021-3100" + }, + phoneNumbers = { + { type = "home", number = "212 555-1234" }, + { type = "office", number = "646 555-4567" } + }, + children = {}, + spouse = nil + }) +end + + +-- Run benchmarks +local results = {} + +for i, name in ipairs(libs) do + local f = loadfile(name) + if not f then + error( "failed to load '" .. name .. "'; run './get_json_libs.sh'" ) + end + local json = f() + + -- Handle special cases + if name == "jfjson.lua" then + local _encode, _decode = json.encode, json.decode + json.encode = function(...) return _encode(json, ...) end + json.decode = function(...) return _decode(json, ...) end + end + + -- Warmup (for LuaJIT) + bench.run(name, 1, function() json.encode(data) end) + + -- Run and push results + local res = bench.run(name, 10, function() json.encode(data) end) + table.insert(results, res) +end + + +bench.print_system_info() +bench.print_results(results) diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/get_json_libs.sh b/Data/DefaultContent/Libraries/LiteJson/bench/get_json_libs.sh new file mode 100644 index 0000000..ecb4525 --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/bench/get_json_libs.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Downloads other JSON libraries for use in the benchmark scripts + +# Remove libraries +rm dkjson.lua 2>/dev/null +rm jfjson.lua 2>/dev/null +rm json4lua.lua 2>/dev/null + +# Get libraries +echo "Downloading json libs..." +curl -sS -o dkjson.lua "https://raw.githubusercontent.com/LuaDist/dkjson/master/dkjson.lua" +curl -sS -o json4lua.lua "https://raw.githubusercontent.com/craigmj/json4lua/master/json/json.lua" +curl -sS -o jfjson.lua "http://regex.info/code/JSON.lua" + +echo "Done" diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/util/bench.lua b/Data/DefaultContent/Libraries/LiteJson/bench/util/bench.lua new file mode 100644 index 0000000..9f02738 --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/bench/util/bench.lua @@ -0,0 +1,62 @@ +local bench = {} + +local unpack = unpack or table.unpack +local fmt = string.format + + +function bench.run(name, count, func) + -- Run bench + local res = {} + for i = 1, count do + local start_time = os.clock() + func() + table.insert(res, (os.clock() - start_time)) + end + -- Calculate average + local avg = 0 + for i, v in ipairs(res) do + avg = avg + v + end + avg = avg / #res + -- Build and return result table + return { + name = name, + avg = avg, + min = math.min(unpack(res)), + max = math.max(unpack(res)), + all = res, + } +end + + +function bench.get_cpu_name() + local fp = io.open("/proc/cpuinfo", "rb") + if not fp then + return "unknown" + end + local text = fp:read("*a") + return text:match("model name%s*:%s*(.-)\n") +end + + +function bench.print_system_info() + print( fmt("Lua version : %s", jit and jit.version or _VERSION) ) + print( fmt("CPU name : %s", bench.get_cpu_name()) ) +end + + +function bench.print_results(results) + -- Find best average + local best = math.huge + for i, v in ipairs(results) do + best = math.min(best, v.avg) + end + -- Print results + for i, v in ipairs(results) do + print( fmt("%-13s : %.03gs [x%1.3g] (min: %.03gs, max %.03gs)", + v.name, v.avg, v.avg / best, v.min, v.max) ) + end +end + + +return bench diff --git a/Data/DefaultContent/Libraries/LiteJson/json.lua b/Data/DefaultContent/Libraries/LiteJson/json.lua new file mode 100644 index 0000000..711ef78 --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/json.lua @@ -0,0 +1,388 @@ +-- +-- json.lua +-- +-- Copyright (c) 2020 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local json = { _version = "0.1.2" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\", + [ "\"" ] = "\"", + [ "\b" ] = "b", + [ "\f" ] = "f", + [ "\n" ] = "n", + [ "\r" ] = "r", + [ "\t" ] = "t", +} + +local escape_char_map_inv = { [ "/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(1, 4), 16 ) + local n2 = tonumber( s:sub(7, 10), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local res = "" + local j = i + 1 + local k = j + + while j <= #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + + elseif x == 92 then -- `\`: Escape + res = res .. str:sub(k, j - 1) + j = j + 1 + local c = str:sub(j, j) + if c == "u" then + local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) + or str:match("^%x%x%x%x", j + 1) + or decode_error(str, j - 1, "invalid unicode escape in string") + res = res .. parse_unicode_escape(hex) + j = j + #hex + else + if not escape_chars[c] then + decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") + end + res = res .. escape_char_map_inv[c] + end + k = j + 1 + + elseif x == 34 then -- `"`: End of string + res = res .. str:sub(k, j - 1) + return res, j + 1 + end + + j = j + 1 + end + + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end + + +return json diff --git a/Data/DefaultContent/Libraries/LiteJson/test/test.lua b/Data/DefaultContent/Libraries/LiteJson/test/test.lua new file mode 100644 index 0000000..74470b2 --- /dev/null +++ b/Data/DefaultContent/Libraries/LiteJson/test/test.lua @@ -0,0 +1,245 @@ + +local json = loadfile("../json.lua")() + + +local fmt = string.format + +local function test(name, func) + xpcall(function() + func() + print( fmt("[pass] %s", name) ) + end, function(err) + print( fmt("[fail] %s : %s", name, err) ) + end) +end + + +local function equal(a, b) + -- Handle table + if type(a) == "table" and type(b) == "table" then + for k in pairs(a) do + if not equal(a[k], b[k]) then + return false + end + end + for k in pairs(b) do + if not equal(b[k], a[k]) then + return false + end + end + return true + end + -- Handle scalar + return a == b +end + + +test("numbers", function() + local t = { + [ "123.456" ] = 123.456, + [ "-123" ] = -123, + [ "-567.765" ] = -567.765, + [ "12.3" ] = 12.3, + [ "0" ] = 0, + [ "0.10000000012" ] = 0.10000000012, + } + for k, v in pairs(t) do + local res = json.decode(k) + assert( res == v, fmt("expected '%s', got '%s'", k, res) ) + local res = json.encode(v) + assert( res == k, fmt("expected '%s', got '%s'", v, res) ) + end + assert( json.decode("13e2") == 13e2 ) + assert( json.decode("13E+2") == 13e2 ) + assert( json.decode("13e-2") == 13e-2 ) +end) + + +test("literals", function() + assert( json.decode("true") == true ) + assert( json.encode(true) == "true" ) + assert( json.decode("false") == false ) + assert( json.encode(false) == "false" ) + assert( json.decode("null") == nil ) + assert( json.encode(nil) == "null") +end) + + +test("strings", function() + local s = "" + assert( s == json.decode( json.encode(s) ) ) + local s = "\\" + assert( s == json.decode( json.encode(s) ) ) + local s = "Hello world" + assert( s == json.decode( json.encode(s) ) ) + local s = "\0 \13 \27" + assert( s == json.decode( json.encode(s) ) ) + local s = "\0\r\n\8" + assert( s == json.decode( json.encode(s) ) ) +end) + + +test("unicode", function() + local s = "こんにちは世界" + assert( s == json.decode( json.encode(s) ) ) +end) + + +test("arrays", function() + local t = { "cat", "dog", "owl" } + assert( equal( t, json.decode( json.encode(t) ) ) ) +end) + + +test("objects", function() + local t = { x = 10, y = 20, z = 30 } + assert( equal( t, json.decode( json.encode(t) ) ) ) +end) + + +--test("strict decode", function() +-- local t = { +-- '{x : 1}', +-- '{x : hello}', +-- "{'x' : 1}", +-- '{"x" : nil}', +-- '{"x" : 0x10}', +-- '{"x" : 001}', +-- '{"x" : .1}', +-- '{"x" : 1, }', +-- '[1, 2, 3, ]', +-- } +-- for i, v in ipairs(t) do +-- local status = pcall(json.decode, v) +-- assert( not status, fmt("'%s' was parsed without error", v) ) +-- end +--end) + + +test("decode invalid", function() + local t = { + '', + ' ', + '{', + '[', + '{"x" : ', + '{"x" : 1', + '{"x" : z }', + '{"x" : 123z }', + '{x : 123 }', + '{10 : 123 }', + '{]', + '[}', + '"a', + '10 xx', + '{}123' + } + for i, v in ipairs(t) do + local status = pcall(json.decode, v) + assert( not status, fmt("'%s' was parsed without error", v) ) + end +end) + + +test("decode invalid string", function() + local t = { + [["\z"]], + [["\1"]], + [["\u000z"]], + [["\ud83d\ude0q"]], + '"x\ny"', + '"x\0y"', + } + for i, v in ipairs(t) do + local status, err = pcall(json.decode, v) + assert( not status, fmt("'%s' was parsed without error", v) ) + end +end) + + +test("decode escape", function() + local t = { + [ [["\u263a"]] ] = '☺', + [ [["\ud83d\ude02"]] ] = '😂', + [ [["\r\n\t\\\""]] ] = '\r\n\t\\"', + [ [["\\"]] ] = '\\', + [ [["\\\\"]] ] = '\\\\', + [ [["\/"]] ] = '/', + [ [["\\u \u263a"]] ] = [[\u ☺]], + } + for k, v in pairs(t) do + local res = json.decode(k) + assert( res == v, fmt("expected '%s', got '%s'", v, res) ) + end +end) + + +test("decode empty", function() + local t = { + [ '[]' ] = {}, + [ '{}' ] = {}, + [ '""' ] = "", + } + for k, v in pairs(t) do + local res = json.decode(k) + assert( equal(res, v), fmt("'%s' did not equal expected", k) ) + end +end) + + +test("decode collection", function() + local t = { + [ '[1, 2, 3, 4, 5, 6]' ] = {1, 2, 3, 4, 5, 6}, + [ '[1, 2, 3, "hello"]' ] = {1, 2, 3, "hello"}, + [ '{ "name": "test", "id": 231 }' ] = {name = "test", id = 231}, + [ '{"x":1,"y":2,"z":[1,2,3]}' ] = {x = 1, y = 2, z = {1, 2, 3}}, + } + for k, v in pairs(t) do + local res = json.decode(k) + assert( equal(res, v), fmt("'%s' did not equal expected", k) ) + end +end) + + +test("encode invalid", function() + local t = { + { [1000] = "b" }, + { [ function() end ] = 12 }, + { nil, 2, 3, 4 }, + { x = 10, [1] = 2 }, + { [1] = "a", [3] = "b" }, + { x = 10, [4] = 5 }, + } + for i, v in ipairs(t) do + local status, res = pcall(json.encode, v) + assert( not status, fmt("encoding idx %d did not result in an error", i) ) + end +end) + + +test("encode invalid number", function() + local t = { + math.huge, -- inf + -math.huge, -- -inf + math.huge * 0, -- NaN + } + for i, v in ipairs(t) do + local status, res = pcall(json.encode, v) + assert( not status, fmt("encoding '%s' did not result in an error", v) ) + end +end) + + +test("encode escape", function() + local t = { + [ '"x"' ] = [["\"x\""]], + [ 'x\ny' ] = [["x\ny"]], + [ 'x\0y' ] = [["x\u0000y"]], + [ 'x\27y' ] = [["x\u001by"]], + [ '\r\n\t\\"' ] = [["\r\n\t\\\""]], + } + for k, v in pairs(t) do + local res = json.encode(k) + assert( res == v, fmt("'%s' was not escaped properly", k) ) + end +end) diff --git a/Data/DefaultContent/Libraries/containers/README.md b/Data/DefaultContent/Libraries/containers/README.md new file mode 100644 index 0000000..cba8776 --- /dev/null +++ b/Data/DefaultContent/Libraries/containers/README.md @@ -0,0 +1,202 @@ +# Lua-ADT(5.1分支和5.2分支) +封装的lua数据结构, 元组(tuple)、动态数组(vector)、双向链表(list)、队列(queue)、栈(stack)。 +纯lua方法封装,没有使用oop,延续lua的简洁的风格。封装的数据结构能安全使用,在语言层面过滤掉非法操作,使其使用更加简单高效。 + +所有的类型都支持#获取长度. +> eg. +```lua + local tuple = require("tuple") + local v = tuple.create({2,3,6}) + print(#v) + ---3 +``` + +### 元组(tuple) +需要用table的动态数组初始化(不支持hashtable),只对外公开遍历,修改关闭。 + +遍历: +```lua + local tuple = require("tuple") + local v = tuple.create({2,3,6}) + + for i,v in ipairs(v) do --只支持ipairs遍历,抛弃了pairs(因为原则上我们是数组,不存在key) + print(i,v) + end + ---1 2 + ---2 3 + ---3 6 + + print(v) --重写了__tostring,方便快速浏览数据 + ---2,3,6 + + v[2] = 9 --因为对修改关闭了所以这地方修改会抛出错误 + ---lua: .\tuple.lua:33: >> Dee: Limited access + ---stack traceback: + ---[C]: in function 'error' +``` + +### 动态数组(vector) +实现高效的遍历和修改,但是新增和删除都不是线性时间复杂度。基本上就是lua table的数组,但是lua的table我们会一不小心就搞成不连续的。比如: +```lua + local t = {2,4} + t[4] = 9 + + print(#t) -- 2 +``` +#### 方法: + * add --尾添加(高效的操作) + * insert --插入(会有内存整理) + * addRange --尾添加一个表, + * removeAt + * remove + * contains + * indexOf + * sort + * find + +#### eg. +```lua + local vector = require("vector") + local v = vector.create() + + v:add(4) + v:add(5) + v:add(6) + v:add(7) + + for i,v in ipairs(v) do + print(i,v) + end + ---1 4 + ---2 5 + ---3 6 + ---4 7 + + print(v) + ---4,5,6,7 + + v[4] = 9 --修改值 + + print(v) + ---4,5,6,9 + + v[7] = 9 + ---lua: .\vector.lua:101: outrange of vector + ---stack traceback: + --- [C]: in function 'assert' +``` + +### 双向链表(list) +弥补动态数组增删的不足,提供增删效率,但是遍历和修改效率比较低 + +#### 方法: + * addFirst --头添加 + * addLast --尾添加 + * addBefore --node前添加 + * addAfter --node后添加 + * removeNode --删除node + * remove --根据值移除 + * find --查找node +#### eg. +```lua + local vector = require("list") + local v = list.create() + + v.addFirst(1) + v.addLast(2) + print(v) + ---1,2 + + local node = v.find(1) + node.value = 9 + print(v) + ---9,2 + + v.removeNode(node) + print(v) + ---2 + + v.addLast(10) + v.addLast(20) + v.addLast(30) + print(v) + ---2,10,20,30 + + for _,i,v in ipairs(v) do --第一个参数是node, i: index, v: value + print(i,v) + end + ---1 2 + ---2 10 + ---3 20 + ---4 30 +``` +### 栈(stack) +FILO先进后出, 对修改关闭,关闭遍历,只能通过方法修改数据 +#### 方法: + * push --添加 + * pop --移除 + * peek --返回栈顶数据 + * clear --清空 +#### eg. +```lua + local stack = require("stack") + local v = stack.create() + + v.push(1) + v.push(2) + v.push(5) + + print(v) + ---5,2,1 + print(v.len) + ---3 + v.pop() + print(v) + ---2,1 + v.clear() + print(v.len) + ---0 +``` +### 队列(queue) +FIFO,先进先出,因为是队首删除所以不能使用table.remove +#### 方法: + * enqueue --添加 + * dequeue --移除 + * peek --返回栈顶数据 + * clear --清空 + * #queue --获取长度 +#### eg. +```lua +local queue = require("queue") +-- lua table +local cnt = 10000 * 1 + +local t = {} +for i=1,cnt do +t[i] = i +end + +local time = os.clock() +while #t > 0 do +-- table.remove(t) + table.remove(t, 1) +end +print(os.clock() - time) +---1.037s + +local v = queue.create() + +for i=1,cnt do + v.enqueue(i) +end + + +local time1 = os.clock() +while v.len > 10 do + v.dequeue() +end +print(os.clock() - time1) +---0.005s +``` +1w条数据,lua table直接删除表头的耗时1.037s,queue耗时0.005s,而且queue整理内存的步长可以调整,耗时可以进步一提高. + diff --git a/Data/DefaultContent/Libraries/containers/list.lua b/Data/DefaultContent/Libraries/containers/list.lua new file mode 100644 index 0000000..59233b9 --- /dev/null +++ b/Data/DefaultContent/Libraries/containers/list.lua @@ -0,0 +1,199 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by Dee. +--- DateTime: 2019/3/7 14:00 +--- 高效增删有序表,低效遍历 +--- + +--[[ +遍历: + for _,idx, value in ipairs(l) do .. end + for _, value in pairs(l) do ... end +]] + +list = list or {} + +function list.create() + local lenght = 0 + -- 类似stl的方式,头尾只是作为指针使用 + local first = {front = nil, next = nil, value = nil} + local last = {front = nil, next = nil, value = nil} + first.next = last + last.front = first + + + ---查找值 + ---@param value + ---@return node + local find = function(value) + local ret = nil + local nextNode = first + while nextNode do + nextNode = nextNode.next + if nextNode.value == value then + ret = nextNode + break + end + end + + return ret + end + + ---查找(根据下标查找) + ---@param idx 下标 + ---@return node + local findByIdx = function(idx) + local i = 0 + local ret + local nextNode = first + while nextNode and i < lenght do + i = i+1 + nextNode = nextNode.next + if i == idx then + ret = nextNode + break + end + end + + return ret + end + + ---在node前添加 + ---@param node + ---@param v + local addBefore = function(node, v) + assert(node) + + local frontNode = node.front + local newNode = {} + newNode.front = frontNode + newNode.next = node + newNode.value = v + node.front = newNode + frontNode.next = newNode + + lenght = lenght+1 + end + + ---在node后添加 + ---@param node + ---@param v + local addAfter = function(node, v) + assert(node) + local nextNode = node.next + local newNode = {} + newNode.front = node + newNode.next = nextNode + newNode.value = v + node.next = newNode + nextNode.front = newNode + + lenght = lenght+1 + end + + ---在队首添加 + ---@param v + local addFirst = function(v) + addAfter(first, v) + end + + ---在队尾添加 + ---@param v + local addLast = function(v) + addBefore(last, v) + end + + ---删除节点 + ---@param node + local removeNode = function(node) + assert(node) + + local frontNode = node.front + local nextNode = node.next + + if frontNode == nil then + first = nextNode + else + frontNode.next = nextNode + end + + if nextNode ~= nil then + nextNode.front = frontNode + end + lenght = lenght - 1 + end + + ---删除节点 + ---@param v + local remove = function(v) + local node = find(v) + if node then + removeNode(node) + end + end + + local t = { + addFirst = addFirst, + addLast = addLast, + addBefore = addBefore, + addAfter = addAfter, + removeNode = removeNode, + remove = remove, + find = find, + findByIdx = findByIdx + } + + local mt = { + __index = function(i_t, key) + return findByIdx(key) + end, + __newindex = function(i_t,k,v) + local node = findByIdx(k) + if not node then + error("out range: "..k) + else + node.value = v + end + end, + __tostring = function() + local ret = {} + local next = first.next + while next and next ~= last do + ret[#ret+1] = next.value + next = next.next + end + + return table.concat(ret, ',') + end, + __len = function(v) + return lenght + end, + --迭代器返回node-value + __ipairs = function(i_t) + local idx = 0 + local function iter(i_t, node) + idx = idx + 1 + if node and node.next ~= last then + return node.next, idx, node.next.value + end + end + + return iter, t, first + end, + __pairs = function(i_t) + local function iter(i_t, node) + if node and node.next ~= last then + return node.next, node.next.value + end + end + + return iter, t, first + end + } + + setmetatable(t, mt) + + return t +end + +return list \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/containers/queue.lua b/Data/DefaultContent/Libraries/containers/queue.lua new file mode 100644 index 0000000..126daa8 --- /dev/null +++ b/Data/DefaultContent/Libraries/containers/queue.lua @@ -0,0 +1,111 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by Dee. +--- DateTime: 2019/3/7 11:27 +--- FIFO +--- + +queue = queue or {} + +---@return Queue +function queue.create() + ---数据容器 + local data = {} + ---数据长度 + local lenght = 0 + ---队首索引 + local first = 1 + + ---获取队首值 + local peek = function() + return data[first] + end + + ---压入数据 + local enqueue = function(v) + assert(v ~= nil, "nil value") + first = lenght == 0 and 1 or first + lenght = lenght + 1 + table.insert(data, first+lenght-1, v) + end + + ---弹出数据 + local dequeue = function() + assert(lenght > 0, "nill queue") + + local ret = peek() + data[first] = nil + first = first+1 + lenght = lenght - 1 + first = lenght == 0 and 1 or first + + if math.fmod(first, 4) == 0 then + local tmp = {} + table.move(data, first, first + lenght, 1, tmp) + + first = 1 + data = nil + data = tmp + end + + return ret + end + + local clear = function() + data = {} + first = 1 + lenght = 0 + end + + local __tostring = function() + local tmp = {} + for i=1,lenght do + tmp[i] = data[i + first - 1] + end + return table.concat(tmp, ",") + end + + local __len = function() + return lenght + end + + local __index = function(i_t, key) + error(">> Dee: Limited access") + end + + local __newindex = function(i_t, key, v) + error(">> Dee: Limited access") + end + + local __ipairs = function(i_t) + local idx = 0 + local function iter(i_t) + idx = idx + 1 + if idx <= lenght then + return idx, data[first + idx - 1] + end + end + + return iter + end + + local __pairs = function(i_t) + error(">> Dee: Limited access") + end + + local mt = {__tostring = __tostring, __index = __index, __newindex = __newindex, __ipairs = __ipairs, __pairs = __pairs, __len = __len} + + ---@class Queue + local t = { + enqueue = enqueue, + dequeue = dequeue, + peek = peek, + clear = clear + } + + setmetatable(t, mt) + + return t +end + +return queue diff --git a/Data/DefaultContent/Libraries/containers/stack.lua b/Data/DefaultContent/Libraries/containers/stack.lua new file mode 100644 index 0000000..d828c81 --- /dev/null +++ b/Data/DefaultContent/Libraries/containers/stack.lua @@ -0,0 +1,67 @@ +--堆栈实现 +stack = stack or {} + +function stack.create() + local data = {} + + local function push(v) + assert(v) + table.insert(data, v) + end + + local function pop() + assert(#data > 0) + table.remove(data) + end + + local function peek() + return #data > 0 and data[#data] or nil + end + + local function clear() + for i=1,#data do + data[i] = nil + end + end + + + + local __tostring = function() + local tmp = {} + for i,v in ipairs(data) do + tmp[#data+1 - i] = v + end + return table.concat(tmp, ",") + end + + local __index = function(i_t, key) + error(">> Dee: Limited access") + end + + local __len = function() + return #data + end + + local __newindex = function(i_t, key, v) + error(">> Dee: Limited access") + end + + local __ipairs = function() + error(">> Dee: Limited access") + end + + local mt = {__tostring = __tostring, __index = __index, __newindex = __newindex, __ipairs = __ipairs, __pairs = __ipairs, __len = __len} + + local t = { + push = push, + pop = pop, + peek = peek, + clear = clear + } + + setmetatable(t, mt) + + return t +end + +return stack \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/containers/tuple.lua b/Data/DefaultContent/Libraries/containers/tuple.lua new file mode 100644 index 0000000..0646d5a --- /dev/null +++ b/Data/DefaultContent/Libraries/containers/tuple.lua @@ -0,0 +1,60 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by Dee. +--- DateTime: 2019/3/7 14:00 +--- 元組,對修改關閉 +--- + +tuple = tuple or {} + +function tuple.create(i_data) + assert(type(i_data) == "table", ">> Dee: shoudle create with table") + + local data = {} + for k,v in pairs(i_data) do + data[#data+1] = v + end + + local t = {} + + local __tostring = function() + return table.concat(data, ",") + end + + local __index = function(i_t, key) + return data[key] + end + + local __newindex = function(i_t, key, v) + error(">> Dee: Limited access") + end + + local __pairs = function() + error(">> Dee: Limited access") + end + + local __ipairs = function(i_t) + local idx = 0 + local function iter(i_t) + idx = idx + 1 + if idx <= #data then + return idx, data[idx] + end + end + + return iter + end + + local __len = function(v) + return #data + end + + local mt = {__tostring = __tostring, __index = __index, __newindex = __newindex, __pairs =__pairs, __ipairs = __ipairs, __len = __len} + + setmetatable(t, mt) + + return t + end + + +return tuple \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/containers/vector.lua b/Data/DefaultContent/Libraries/containers/vector.lua new file mode 100644 index 0000000..0b349ce --- /dev/null +++ b/Data/DefaultContent/Libraries/containers/vector.lua @@ -0,0 +1,122 @@ +--- +--- Generated by EmmyLua(https://github.com/EmmyLua) +--- Created by Dee. +--- DateTime: 2019/3/7 14:00 +--- 快速遍历修改,低效的增删 +--- + +vector = vector or {} + +function vector.create() + local t = {} + + + ---尾添加元素(高效) + function t:add(v) + rawset(self, #self + 1, v) + end + + ---插入(低效) + ---@param k 位置 + ---@param v 值 + function t:insert(k, v) + assert(k > 0 and k <= #self, "outrange of vector") + + local cnt = #self + for i = cnt, k, -1 do + rawset(self, i+1, self[i]) + end + + rawset(self, k, v) + end + + ---值的索引 + ---@return -1不存在 + function t:indexOf(i_v) + assert(type(self) == 'table') + + local ret = -1 + local cnt = #self + for i = 1, #self do + if self[i] == i_v then + ret = i + end + end + + return ret + end + + ---是否存在某元素 + function t:contains(v) + assert(type(self) == 'table') + return self:indexOf(v) ~= -1 + end + + ---根据下标索引移除元素(低效) + function t:removeAt(idx) + assert(idx <= #self) + table.remove(self, idx) + end + + ---删除值(非贪婪) + ---@return 删除位置 -1未删除 + function t:remove(v) + local ret = self:indexOf(v) + if ret ~= -1 then + self:removeAt(ret) + end + + return ret + end + + ---删除所有值 + function t:removeAll(v) + assert(type(self) == 'table') + error(">>Dee: wait ...") + end + + ---排序 + function t:sort(comparer) + assert(type(self) == 'table') + table.sort(self, comparer) + end + + ---匹配 + ---@param 匹配函数 + ---@return idx,value + function t:find(matcher) + assert(type(self) == 'table') + + local _idx, _value = -1, nil + local cnt = #self + for i = 1, cnt do + if matcher(i, self[i]) then + _value = self[i] + _idx = i + break + end + end + + return _idx, _value + end + + --------------------------------metatable--------------------------------------- + t.__newindex = function(i_t,k,v) + error(">> Dee: [], replace with add()") + end + + t.__tostring = function(i_t) + return table.concat(i_t, ',') + end + + t.__pairs = function(...) + error(">> Dee: Limited access") + end + + setmetatable(t, t) + ----------------------------------------------------------------------- + + return t +end + +return vector \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/inspect/.travis.yml b/Data/DefaultContent/Libraries/inspect/.travis.yml new file mode 100644 index 0000000..91f7f93 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/.travis.yml @@ -0,0 +1,36 @@ +language: python +sudo: false + +env: + - LUA="lua=5.1" + - LUA="lua=5.2" + - LUA="lua=5.3" + - LUA="luajit=2.0" + - LUA="luajit=2.1" + +before_install: + - pip install hererocks + - hererocks lua_install -r^ --$LUA + - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH + +install: + - luarocks install luacheck + - luarocks install busted + - luarocks install luacov + - luarocks install luacov-coveralls + +script: + - luacheck --std max+busted *.lua spec + - busted --verbose --coverage + +after_success: + - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install + +branches: + except: + - gh-pages + +notifications: + email: + on_success: change + on_failure: always diff --git a/Data/DefaultContent/Libraries/inspect/CHANGELOG.md b/Data/DefaultContent/Libraries/inspect/CHANGELOG.md new file mode 100644 index 0000000..bc2311b --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/CHANGELOG.md @@ -0,0 +1,39 @@ +## v3.1.1 + +* Better handling of LuaJIT's `ctype` and `cdata` values (#34, thanks @akopytov) + +## v3.1.0 + +* Fixes bug: all control codes are escaped correctly (instead of only the named ones such as \n). + Example: \1 becomes \\1 (or \\001 when followed by a digit) +* Fixes bug when using the `process` option in recursive tables +* Overriding global `tostring` with inspect no longer results in an error. +* Simplifies id generation, using less tables and metatables. + +## v3.0.3 +* Fixes a bug which sometimes displayed struct-like parts of tables as sequence-like due + to the way rawlen/the # operator are implemented. + +## v3.0.2 +* Fixes a bug when a table was garbage-collected while inspect was trying to render it + +## v3.0.1 +* Fixes a bug when dealing with tables which have a __len metamethod in Lua >= 5.2 + +## v3.0.0 + +The basic functionality remains as before, but there's one backwards-incompatible change if you used `options.filter`. + +* **Removed** `options.filter` +* **Added** `options.process`, which can be used to do the same as `options.filter`, and more. +* **Added** two new constants, `inspect.METATABLE` and `inspect.KEY` +* **Added** `options.indent` & `options.newline`. + + +## v2.0.0 + +* Ability to deal with LuaJit's custom types +* License change from BSD to MIT +* Moved second parameter (depth) to options (options.depth) +* Added a new parameter, options.filter. +* Reimplemented some parts of the system without object orientation diff --git a/Data/DefaultContent/Libraries/inspect/MIT-LICENSE.txt b/Data/DefaultContent/Libraries/inspect/MIT-LICENSE.txt new file mode 100644 index 0000000..555835c --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/MIT-LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2013 Enrique García Cota + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Data/DefaultContent/Libraries/inspect/README.md b/Data/DefaultContent/Libraries/inspect/README.md new file mode 100644 index 0000000..e9c6f86 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/README.md @@ -0,0 +1,253 @@ +inspect.lua +=========== + +[![Build Status](https://travis-ci.org/kikito/inspect.lua.png?branch=master)](https://travis-ci.org/kikito/inspect.lua) +[![Coverage Status](https://coveralls.io/repos/github/kikito/inspect.lua/badge.svg?branch=master)](https://coveralls.io/github/kikito/inspect.lua?branch=master) + + +This library transforms any Lua value into a human-readable representation. It is especially useful for debugging errors in tables. + +The objective here is human understanding (i.e. for debugging), not serialization or compactness. + +Examples of use +=============== + +`inspect` has the following declaration: `local str = inspect(value, )`. + +`value` can be any Lua value. + +`inspect` transforms simple types (like strings or numbers) into strings. + +```lua +assert(inspect(1) == "1") +assert(inspect("Hello") == '"Hello"') +``` + +Tables, on the other hand, are rendered in a way a human can read easily. + +"Array-like" tables are rendered horizontally: + +```lua +assert(inspect({1,2,3,4}) == "{ 1, 2, 3, 4 }") +``` + +"Dictionary-like" tables are rendered with one element per line: + +```lua +assert(inspect({a=1,b=2}) == [[{ + a = 1, + b = 2 +}]]) +``` + +The keys will be sorted alphanumerically when possible. + +"Hybrid" tables will have the array part on the first line, and the dictionary part just below them: + +```lua +assert(inspect({1,2,3,b=2,a=1}) == [[{ 1, 2, 3, + a = 1, + b = 2 +}]]) +``` + +Subtables are indented with two spaces per level. + +```lua +assert(inspect({a={b=2}}) == [[{ + a = { + b = 2 + } +}]]) +``` + +Functions, userdata and any other custom types from Luajit are simply as ``, ``, etc.: + +```lua +assert(inspect({ f = print, ud = some_user_data, thread = a_thread} ) == [[{ + f = , + u = , + thread = +}]]) +``` + +If the table has a metatable, inspect will include it at the end, in a special field called ``: + +```lua +assert(inspect(setmetatable({a=1}, {b=2}) == [[{ + a = 1 + = { + b = 2 + } +}]])) +``` + +`inspect` can handle tables with loops inside them. It will print `` right before the table is printed out the first time, and replace the whole table with `` from then on, preventing infinite loops. + +```lua +local a = {1, 2} +local b = {3, 4, a} +a[3] = b -- a references b, and b references a +assert(inspect(a) == "<1>{ 1, 2, { 3, 4,
} }") +``` + +Notice that since both `a` appears more than once in the expression, it is prefixed by `<1>` and replaced by `
` every time it appears later on. + +### options + +`inspect` has a second parameter, called `options`. It is not mandatory, but when it is provided, it must be a table. + +#### options.depth + +`options.depth` sets the maximum depth that will be printed out. +When the max depth is reached, `inspect` will stop parsing tables and just return `{...}`: + +```lua + +local t5 = {a = {b = {c = {d = {e = 5}}}}} + +assert(inspect(t5, {depth = 4}) == [[{ + a = { + b = { + c = { + d = {...} + } + } + } +}]]) + +assert(inspect(t5, {depth = 2}) == [[{ + a = { + b = {...} + } +}]]) + +``` + +`options.depth` defaults to infinite (`math.huge`). + +#### options.newline & options.indent + +These are the strings used by `inspect` to respectively add a newline and indent each level of a table. + +By default, `options.newline` is `"\n"` and `options.indent` is `" "` (two spaces). + +``` lua +local t = {a={b=1}} + +assert(inspect(t) == [[{ + a = { + b = 1 + } +}]]) + +assert(inspect(t, {newline='@', indent="++"}), "{@++a = {@++++b = 1@++}@}" +``` + +#### options.process + +`options.process` is a function which allow altering the passed object before transforming it into a string. +A typical way to use it would be to remove certain values so that they don't appear at all. + +`options.process` has the following signature: + +``` lua +local processed_item = function(item, path) +``` + +* `item` is either a key or a value on the table, or any of its subtables +* `path` is an array-like table built with all the keys that have been used to reach `item`, from the root. + * For values, it is just a regular list of keys. For example, to reach the 1 in `{a = {b = 1}}`, the `path` + will be `{'a', 'b'}` + * For keys, the special value `inspect.KEY` is inserted. For example, to reach the `c` in `{a = {b = {c = 1}}}`, + the path will be `{'a', 'b', 'c', inspect.KEY }` + * For metatables, the special value `inspect.METATABLE` is inserted. For `{a = {b = 1}}}`, the path + `{'a', {b = 1}, inspect.METATABLE}` means "the metatable of the table `{b = 1}`". +* `processed_item` is the value returned by `options.process`. If it is equal to `item`, then the inspected + table will look unchanged. If it is different, then the table will look different; most notably, if it's `nil`, + the item will dissapear on the inspected table. + +#### Examples + +Remove a particular metatable from the result: + +``` lua +local t = {1,2,3} +local mt = {b = 2} +setmetatable(t, mt) + +local remove_mt = function(item) + if item ~= mt then return item end +end + +-- mt does not appear +assert(inspect(t, {process = remove_mt}) == "{ 1, 2, 3 }") +``` + +The previous exaple only works for a particular metatable. If you want to make *all* metatables, you can use the `path` parameter to check +wether the last element is `inspect.METATABLE`, and return `nil` instead of the item: + +``` lua +local t, mt = ... -- (defined as before) + +local remove_all_metatables = function(item, path) + if path[#path] ~= inspect.METATABLE then return item end +end + +assert(inspect(t, {process = remove_all_metatables}) == "{ 1, 2, 3 }") +``` + +Filter a value: + +```lua +local anonymize_password = function(item, path) + if path[#path] == 'password' then return "XXXX" end + return item +end + +local info = {user = 'peter', password = 'secret'} + +assert(inspect(info, {process = anonymize_password}) == [[{ + password = "XXXX", + user = "peter" +}]]) +``` + +Gotchas / Warnings +================== + +This method is *not* appropriate for saving/restoring tables. It is meant to be used by the programmer mainly while debugging a program. + +Installation +============ + +If you are using luarocks, just run + + luarocks install inspect + +Otherwise, you can just copy the inspect.lua file somewhere in your projects (maybe inside a /lib/ folder) and require it accordingly. + +Remember to store the value returned by require somewhere! (I suggest a local variable named inspect, although others might like table.inspect) + + local inspect = require 'inspect' + -- or -- + local inspect = require 'lib.inspect' + +Also, make sure to read the license; the text of that license file must appear somewhere in your projects' files. For your convenience, it's included at the begining of inspect.lua. + +Specs +===== + +This project uses [busted](http://olivinelabs.com/busted/) for its specs. If you want to run the specs, you will have to install busted first. Then just execute the following from the root inspect folder: + + busted + +Change log +========== + +Read it on the CHANGELOG.md file + + + + + diff --git a/Data/DefaultContent/Libraries/inspect/inspect.lua b/Data/DefaultContent/Libraries/inspect/inspect.lua new file mode 100644 index 0000000..e2e3806 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/inspect.lua @@ -0,0 +1,334 @@ +local inspect ={ + _VERSION = 'inspect.lua 3.1.0', + _URL = 'http://github.com/kikito/inspect.lua', + _DESCRIPTION = 'human-readable representations of tables', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2013 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +local tostring = tostring + +inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end}) +inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end}) + +local function rawpairs(t) + return next, t, nil +end + +-- Apostrophizes the string if it has quotes, but not aphostrophes +-- Otherwise, it returns a regular quoted string +local function smartQuote(str) + if str:match('"') and not str:match("'") then + return "'" .. str .. "'" + end + return '"' .. str:gsub('"', '\\"') .. '"' +end + +-- \a => '\\a', \0 => '\\0', 31 => '\31' +local shortControlCharEscapes = { + ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", + ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" +} +local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031 +for i=0, 31 do + local ch = string.char(i) + if not shortControlCharEscapes[ch] then + shortControlCharEscapes[ch] = "\\"..i + longControlCharEscapes[ch] = string.format("\\%03d", i) + end +end + +local function escape(str) + return (str:gsub("\\", "\\\\") + :gsub("(%c)%f[0-9]", longControlCharEscapes) + :gsub("%c", shortControlCharEscapes)) +end + +local function isIdentifier(str) + return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) +end + +local function isSequenceKey(k, sequenceLength) + return type(k) == 'number' + and 1 <= k + and k <= sequenceLength + and math.floor(k) == k +end + +local defaultTypeOrders = { + ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, + ['function'] = 5, ['userdata'] = 6, ['thread'] = 7 +} + +local function sortKeys(a, b) + local ta, tb = type(a), type(b) + + -- strings and numbers are sorted numerically/alphabetically + if ta == tb and (ta == 'string' or ta == 'number') then return a < b end + + local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] + -- Two default types are compared according to the defaultTypeOrders table + if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] + elseif dta then return true -- default types before custom ones + elseif dtb then return false -- custom types after default ones + end + + -- custom types are sorted out alphabetically + return ta < tb +end + +-- For implementation reasons, the behavior of rawlen & # is "undefined" when +-- tables aren't pure sequences. So we implement our own # operator. +local function getSequenceLength(t) + local len = 1 + local v = rawget(t,len) + while v ~= nil do + len = len + 1 + v = rawget(t,len) + end + return len - 1 +end + +local function getNonSequentialKeys(t) + local keys, keysLength = {}, 0 + local sequenceLength = getSequenceLength(t) + for k,_ in rawpairs(t) do + if not isSequenceKey(k, sequenceLength) then + keysLength = keysLength + 1 + keys[keysLength] = k + end + end + table.sort(keys, sortKeys) + return keys, keysLength, sequenceLength +end + +local function countTableAppearances(t, tableAppearances) + tableAppearances = tableAppearances or {} + + if type(t) == 'table' then + if not tableAppearances[t] then + tableAppearances[t] = 1 + for k,v in rawpairs(t) do + countTableAppearances(k, tableAppearances) + countTableAppearances(v, tableAppearances) + end + countTableAppearances(getmetatable(t), tableAppearances) + else + tableAppearances[t] = tableAppearances[t] + 1 + end + end + + return tableAppearances +end + +local copySequence = function(s) + local copy, len = {}, #s + for i=1, len do copy[i] = s[i] end + return copy, len +end + +local function makePath(path, ...) + local keys = {...} + local newPath, len = copySequence(path) + for i=1, #keys do + newPath[len + i] = keys[i] + end + return newPath +end + +local function processRecursive(process, item, path, visited) + if item == nil then return nil end + if visited[item] then return visited[item] end + + local processed = process(item, path) + if type(processed) == 'table' then + local processedCopy = {} + visited[item] = processedCopy + local processedKey + + for k,v in rawpairs(processed) do + processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) + if processedKey ~= nil then + processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) + end + end + + local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) + if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field + setmetatable(processedCopy, mt) + processed = processedCopy + end + return processed +end + + + +------------------------------------------------------------------- + +local Inspector = {} +local Inspector_mt = {__index = Inspector} + +function Inspector:puts(...) + local args = {...} + local buffer = self.buffer + local len = #buffer + for i=1, #args do + len = len + 1 + buffer[len] = args[i] + end +end + +function Inspector:down(f) + self.level = self.level + 1 + f() + self.level = self.level - 1 +end + +function Inspector:tabify() + self:puts(self.newline, string.rep(self.indent, self.level)) +end + +function Inspector:alreadyVisited(v) + return self.ids[v] ~= nil +end + +function Inspector:getId(v) + local id = self.ids[v] + if not id then + local tv = type(v) + id = (self.maxIds[tv] or 0) + 1 + self.maxIds[tv] = id + self.ids[v] = id + end + return tostring(id) +end + +function Inspector:putKey(k) + if isIdentifier(k) then return self:puts(k) end + self:puts("[") + self:putValue(k) + self:puts("]") +end + +function Inspector:putTable(t) + if t == inspect.KEY or t == inspect.METATABLE then + self:puts(tostring(t)) + elseif self:alreadyVisited(t) then + self:puts('
') + elseif self.level >= self.depth then + self:puts('{...}') + else + if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end + + local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t) + local mt = getmetatable(t) + + self:puts('{') + self:down(function() + local count = 0 + for i=1, sequenceLength do + if count > 0 then self:puts(',') end + self:puts(' ') + self:putValue(t[i]) + count = count + 1 + end + + for i=1, nonSequentialKeysLength do + local k = nonSequentialKeys[i] + if count > 0 then self:puts(',') end + self:tabify() + self:putKey(k) + self:puts(' = ') + self:putValue(t[k]) + count = count + 1 + end + + if type(mt) == 'table' then + if count > 0 then self:puts(',') end + self:tabify() + self:puts(' = ') + self:putValue(mt) + end + end) + + if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing } + self:tabify() + elseif sequenceLength > 0 then -- array tables have one extra space before closing } + self:puts(' ') + end + + self:puts('}') + end +end + +function Inspector:putValue(v) + local tv = type(v) + + if tv == 'string' then + self:puts(smartQuote(escape(v))) + elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or + tv == 'cdata' or tv == 'ctype' then + self:puts(tostring(v)) + elseif tv == 'table' then + self:putTable(v) + else + self:puts('<', tv, ' ', self:getId(v), '>') + end +end + +------------------------------------------------------------------- + +function inspect.inspect(root, options) + options = options or {} + + local depth = options.depth or math.huge + local newline = options.newline or '\n' + local indent = options.indent or ' ' + local process = options.process + + if process then + root = processRecursive(process, root, {}, {}) + end + + local inspector = setmetatable({ + depth = depth, + level = 0, + buffer = {}, + ids = {}, + maxIds = {}, + newline = newline, + indent = indent, + tableAppearances = countTableAppearances(root) + }, Inspector_mt) + + inspector:putValue(root) + + return table.concat(inspector.buffer) +end + +setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) + +return inspect + diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-1.2-2.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-1.2-2.rockspec new file mode 100644 index 0000000..b683143 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-1.2-2.rockspec @@ -0,0 +1,23 @@ +package = "inspect" +version = "1.2-2" +source = { + url = "https://github.com/kikito/inspect.lua/archive/v1.2.0.tar.gz", + dir = "inspect.lua-1.2.0" +} +description = { + summary = "Lua table visualizer, ideal for debugging", + detailed = [[ + inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name, handles data recursion + ]], + homepage = "https://github.com/kikito/inspect.lua", + license = "MIT " +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + inspect = "inspect.lua" + } +} diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-2.0-1.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-2.0-1.rockspec new file mode 100644 index 0000000..286bbd5 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-2.0-1.rockspec @@ -0,0 +1,23 @@ +package = "inspect" +version = "2.0-1" +source = { + url = "https://github.com/kikito/inspect.lua/archive/v2.0.0.tar.gz", + dir = "inspect.lua-2.0.0" +} +description = { + summary = "Lua table visualizer, ideal for debugging", + detailed = [[ + inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name, handles data recursion + ]], + homepage = "https://github.com/kikito/inspect.lua", + license = "MIT " +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + inspect = "inspect.lua" + } +} diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-1.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-1.rockspec new file mode 100644 index 0000000..387d450 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-1.rockspec @@ -0,0 +1,23 @@ +package = "inspect" +version = "3.0-1" +source = { + url = "https://github.com/kikito/inspect.lua/archive/v3.0.0.tar.gz", + dir = "inspect.lua-3.0.0" +} +description = { + summary = "Lua table visualizer, ideal for debugging", + detailed = [[ + inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly. + ]], + homepage = "https://github.com/kikito/inspect.lua", + license = "MIT " +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + inspect = "inspect.lua" + } +} diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-2.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-2.rockspec new file mode 100644 index 0000000..b22ec9c --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-2.rockspec @@ -0,0 +1,23 @@ +package = "inspect" +version = "3.0-2" +source = { + url = "https://github.com/kikito/inspect.lua/archive/v3.0.1.tar.gz", + dir = "inspect.lua-3.0.1" +} +description = { + summary = "Lua table visualizer, ideal for debugging", + detailed = [[ + inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly. + ]], + homepage = "https://github.com/kikito/inspect.lua", + license = "MIT " +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + inspect = "inspect.lua" + } +} diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-3.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-3.rockspec new file mode 100644 index 0000000..9e07b01 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-3.rockspec @@ -0,0 +1,23 @@ +package = "inspect" +version = "3.0-3" +source = { + url = "https://github.com/kikito/inspect.lua/archive/v3.0.2.tar.gz", + dir = "inspect.lua-3.0.2" +} +description = { + summary = "Lua table visualizer, ideal for debugging", + detailed = [[ + inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly. + ]], + homepage = "https://github.com/kikito/inspect.lua", + license = "MIT " +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + inspect = "inspect.lua" + } +} diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-4.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-4.rockspec new file mode 100644 index 0000000..56f3d48 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-4.rockspec @@ -0,0 +1,23 @@ +package = "inspect" +version = "3.0-4" +source = { + url = "https://github.com/kikito/inspect.lua/archive/v3.0.3.tar.gz", + dir = "inspect.lua-3.0.3" +} +description = { + summary = "Lua table visualizer, ideal for debugging", + detailed = [[ + inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly. + ]], + homepage = "https://github.com/kikito/inspect.lua", + license = "MIT " +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + inspect = "inspect.lua" + } +} diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.1.1-0.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.1.1-0.rockspec new file mode 100644 index 0000000..740b644 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.1.1-0.rockspec @@ -0,0 +1,23 @@ +package = "inspect" +version = "3.1.1-0" +source = { + url = "https://github.com/kikito/inspect.lua/archive/v3.1.1.tar.gz", + dir = "inspect.lua-3.1.1" +} +description = { + summary = "Lua table visualizer, ideal for debugging", + detailed = [[ + inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly. + ]], + homepage = "https://github.com/kikito/inspect.lua", + license = "MIT " +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + inspect = "inspect.lua" + } +} diff --git a/Data/DefaultContent/Libraries/inspect/spec/inspect_spec.lua b/Data/DefaultContent/Libraries/inspect/spec/inspect_spec.lua new file mode 100644 index 0000000..edea720 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/spec/inspect_spec.lua @@ -0,0 +1,460 @@ +local inspect = require 'inspect' +local unindent = require 'spec.unindent' +local is_luajit, ffi = pcall(require, 'ffi') +local has_rawlen = type(_G.rawlen) == 'function' + +describe( 'inspect', function() + + describe('numbers', function() + it('works', function() + assert.equals("1", inspect(1)) + assert.equals("1.5", inspect(1.5)) + assert.equals("-3.14", inspect(-3.14)) + end) + end) + + describe('strings', function() + it('puts quotes around regular strings', function() + assert.equals('"hello"', inspect("hello")) + end) + + it('puts apostrophes around strings with quotes', function() + assert.equals("'I have \"quotes\"'", inspect('I have "quotes"')) + end) + + it('uses regular quotes if the string has both quotes and apostrophes', function() + assert.equals('"I have \\"quotes\\" and \'apostrophes\'"', inspect("I have \"quotes\" and 'apostrophes'")) + end) + + it('escapes newlines properly', function() + assert.equals('"I have \\n new \\n lines"', inspect('I have \n new \n lines')) + end) + + it('escapes tabs properly', function() + assert.equals('"I have \\t a tab character"', inspect('I have \t a tab character')) + end) + + it('escapes backspaces properly', function() + assert.equals('"I have \\b a back space"', inspect('I have \b a back space')) + end) + + it('escapes unnamed control characters with 1 or 2 digits', function() + assert.equals('"Here are some control characters: \\0 \\1 \\6 \\17 \\27 \\31"', + inspect('Here are some control characters: \0 \1 \6 \17 \27 \31')) + end) + + it('escapes unnamed control characters with 3 digits when they are followed by numbers', function() + assert.equals('"Control chars followed by digits \\0001 \\0011 \\0061 \\0171 \\0271 \\0311"', + inspect('Control chars followed by digits \0001 \0011 \0061 \0171 \0271 \0311')) + end) + + it('backslashes its backslashes', function() + assert.equals('"I have \\\\ a backslash"', inspect('I have \\ a backslash')) + assert.equals('"I have \\\\\\\\ two backslashes"', inspect('I have \\\\ two backslashes')) + assert.equals('"I have \\\\\\n a backslash followed by a newline"', + inspect('I have \\\n a backslash followed by a newline')) + end) + + end) + + it('works with nil', function() + assert.equals('nil', inspect(nil)) + end) + + it('works with functions', function() + assert.equals('{ , , }', inspect({ print, type, print })) + end) + + it('works with booleans', function() + assert.equals('true', inspect(true)) + assert.equals('false', inspect(false)) + end) + + if is_luajit then + it('works with luajit cdata', function() + assert.equals('{ cdata: PTR, ctype, cdata: PTR }', + inspect({ ffi.new("int", 1), ffi.typeof("int"), ffi.typeof("int")(1) }):gsub('(0x%x+)','PTR')) + end) + end + + describe('tables', function() + + it('works with simple array-like tables', function() + assert.equals("{ 1, 2, 3 }", inspect({1,2,3})) + end) + + it('works with nested arrays', function() + assert.equals('{ "a", "b", "c", { "d", "e" }, "f" }', inspect({'a','b','c', {'d','e'}, 'f'})) + end) + + if has_rawlen then + it('handles arrays with a __len metatable correctly (ignoring the __len metatable and using rawlen)', function() + local arr = setmetatable({1,2,3}, {__len = function() return nil end}) + assert.equals("{ 1, 2, 3,\n = {\n __len = \n }\n}", inspect(arr)) + end) + + it('handles tables with a __pairs metamethod (ignoring the __pairs metamethod and using next)', function() + local t = setmetatable({ {}, name = "yeah" }, { __pairs = function() end }) + assert.equals( + unindent([[{ {}, + name = "yeah", + = { + __pairs = + } + }]]), + inspect(t)) + end) + end + + it('works with simple dictionary tables', function() + assert.equals("{\n a = 1,\n b = 2\n}", inspect({a = 1, b = 2})) + end) + + it('identifies tables with no number 1 as struct-like', function() + assert.equals(unindent([[{ + [2] = 1, + [25] = 1, + id = 1 + } + ]]), inspect({[2]=1,[25]=1,id=1})) + end) + + it('identifies numeric non-array keys as dictionary keys', function() + assert.equals("{ 1, 2,\n [-1] = true\n}", inspect({1, 2, [-1] = true})) + assert.equals("{ 1, 2,\n [1.5] = true\n}", inspect({1, 2, [1.5] = true})) + end) + + it('sorts keys in dictionary tables', function() + local t = { 1,2,3, + [print] = 1, ["buy more"] = 1, a = 1, + [coroutine.create(function() end)] = 1, + [14] = 1, [{c=2}] = 1, [true]= 1 + } + assert.equals(unindent([[ + { 1, 2, 3, + [14] = 1, + [true] = 1, + a = 1, + ["buy more"] = 1, + [{ + c = 2 + }] = 1, + [] = 1, + [] = 1 + } + ]]), inspect(t)) + end) + + it('works with nested dictionary tables', function() + assert.equals(unindent([[{ + a = 1, + b = { + c = 2 + }, + d = 3 + }]]), inspect( {d=3, b={c=2}, a=1} )) + end) + + it('works with hybrid tables', function() + assert.equals(unindent([[ + { "a", { + b = 1 + }, 2, + ["ahoy you"] = 4, + c = 3 + } + ]]), inspect({ 'a', {b = 1}, 2, c = 3, ['ahoy you'] = 4 })) + + + end) + + it('displays
instead of repeating an already existing table', function() + local a = { 1, 2, 3 } + local b = { 'a', 'b', 'c', a } + a[4] = b + a[5] = a + a[6] = b + assert.equals('<1>{ 1, 2, 3, <2>{ "a", "b", "c",
},
,
}', inspect(a)) + end) + + describe('The depth parameter', function() + local level5 = { 1,2,3, a = { b = { c = { d = { e = 5 } } } } } + local keys = { [level5] = true } + + it('has infinite depth by default', function() + assert.equals(unindent([[ + { 1, 2, 3, + a = { + b = { + c = { + d = { + e = 5 + } + } + } + } + } + ]]), inspect(level5)) + end) + it('is modifiable by the user', function() + assert.equals(unindent([[ + { 1, 2, 3, + a = { + b = {...} + } + } + ]]), inspect(level5, {depth = 2})) + + assert.equals(unindent([[ + { 1, 2, 3, + a = {...} + } + ]]), inspect(level5, {depth = 1})) + + assert.equals(unindent([[ + { 1, 2, 3, + a = { + b = { + c = { + d = {...} + } + } + } + } + ]]), inspect(level5, {depth = 4})) + + assert.equals("{...}", inspect(level5, {depth = 0})) + end) + + it('respects depth on keys', function() + assert.equals(unindent([[ + { + [{ 1, 2, 3, + a = { + b = { + c = {...} + } + } + }] = true + } + ]]), inspect(keys, {depth = 4})) + end) + end) + + describe('the newline option', function() + it('changes the substring used for newlines', function() + local t = {a={b=1}} + + assert.equal("{@ a = {@ b = 1@ }@}", inspect(t, {newline='@'})) + end) + end) + + describe('the indent option', function() + it('changes the substring used for indenting', function() + local t = {a={b=1}} + + assert.equal("{\n>>>a = {\n>>>>>>b = 1\n>>>}\n}", inspect(t, {indent='>>>'})) + end) + end) + + describe('the process option', function() + + it('removes one element', function() + local names = {'Andrew', 'Peter', 'Ann' } + local removeAnn = function(item) if item ~= 'Ann' then return item end end + assert.equals('{ "Andrew", "Peter" }', inspect(names, {process = removeAnn})) + end) + + it('uses the path', function() + local names = {'Andrew', 'Peter', 'Ann' } + local removeThird = function(item, path) if path[1] ~= 3 then return item end end + assert.equals('{ "Andrew", "Peter" }', inspect(names, {process = removeThird})) + end) + + it('replaces items', function() + local names = {'Andrew', 'Peter', 'Ann' } + local filterAnn = function(item) return item == 'Ann' and '' or item end + assert.equals('{ "Andrew", "Peter", "" }', inspect(names, {process = filterAnn})) + end) + + it('nullifies metatables', function() + local mt = {'world'} + local t = setmetatable({'hello'}, mt) + local removeMt = function(item) if item ~= mt then return item end end + assert.equals('{ "hello" }', inspect(t, {process = removeMt})) + end) + + it('nullifies metatables using their paths', function() + local mt = {'world'} + local t = setmetatable({'hello'}, mt) + local removeMt = function(item, path) if path[#path] ~= inspect.METATABLE then return item end end + assert.equals('{ "hello" }', inspect(t, {process = removeMt})) + end) + + it('nullifies the root object', function() + local names = {'Andrew', 'Peter', 'Ann' } + local removeNames = function(item) if item ~= names then return item end end + assert.equals('nil', inspect(names, {process = removeNames})) + end) + + it('changes keys', function() + local dict = {a = 1} + local changeKey = function(item) return item == 'a' and 'x' or item end + assert.equals('{\n x = 1\n}', inspect(dict, {process = changeKey})) + end) + + it('nullifies keys', function() + local dict = {a = 1, b = 2} + local removeA = function(item) return item ~= 'a' and item or nil end + assert.equals('{\n b = 2\n}', inspect(dict, {process = removeA})) + end) + + it('prints inspect.KEY & inspect.METATABLE', function() + local t = {inspect.KEY, inspect.METATABLE} + assert.equals("{ inspect.KEY, inspect.METATABLE }", inspect(t)) + end) + + it('marks key paths with inspect.KEY and metatables with inspect.METATABLE', function() + local t = { [{a=1}] = setmetatable({b=2}, {c=3}) } + + local items = {} + local addItem = function(item, path) + items[#items + 1] = {item = item, path = path} + return item + end + + inspect(t, {process = addItem}) + + assert.same({ + {item = t, path = {}}, + {item = {a=1}, path = {{a=1}, inspect.KEY}}, + {item = 'a', path = {{a=1}, inspect.KEY, 'a', inspect.KEY}}, + {item = 1, path = {{a=1}, inspect.KEY, 'a'}}, + {item = setmetatable({b=2}, {c=3}), path = {{a=1}}}, + {item = 'b', path = {{a=1}, 'b', inspect.KEY}}, + {item = 2, path = {{a=1}, 'b'}}, + {item = {c=3}, path = {{a=1}, inspect.METATABLE}}, + {item = 'c', path = {{a=1}, inspect.METATABLE, 'c', inspect.KEY}}, + {item = 3, path = {{a=1}, inspect.METATABLE, 'c'}} + }, items) + + end) + + it('handles recursive tables correctly', function() + local tbl = { 1,2,3} + tbl.loop = tbl + inspect(tbl, { process=function(x) return x end}) + end) + end) + + describe('metatables', function() + + it('includes the metatable as an extra hash attribute', function() + local foo = { foo = 1, __mode = 'v' } + local bar = setmetatable({a = 1}, foo) + assert.equals(unindent([[ + { + a = 1, + = { + __mode = "v", + foo = 1 + } + } + ]]), inspect(bar)) + end) + + it('can be used on the __tostring metamethod of a table without errors', function() + local f = function(x) return inspect(x) end + local tbl = setmetatable({ x = 1 }, { __tostring = f }) + assert.equals(unindent([[ + { + x = 1, + = { + __tostring = + } + } + ]]), tostring(tbl)) + end) + + it('does not allow collecting weak tables while they are being inspected', function() + collectgarbage('stop') + finally(function() collectgarbage('restart') end) + local shimMetatable = { + __mode = 'v', + __index = function() return {} end, + } + local function shim() return setmetatable({}, shimMetatable) end + local t = shim() + t.key = shim() + assert.equals(unindent([[ + { + key = { + = <1>{ + __index = , + __mode = "v" + } + }, + =
+ } + ]]), inspect(t)) + end) + + it('ignores metatables with __metatable field set to non-nil and non-table type', function() + local function process(item) return item end + local function inspector(data) return inspect(data, {process=process}) end + + local foo = setmetatable({}, {__metatable=false}) + local bar = setmetatable({}, {__metatable=true}) + local baz = setmetatable({}, {__metatable=10}) + local spam = setmetatable({}, {__metatable=nil}) + local eggs = setmetatable({}, {__metatable={}}) + assert.equals(unindent('{}'), inspector(foo)) + assert.equals(unindent('{}'), inspector(bar)) + assert.equals(unindent('{}'), inspector(baz)) + assert.equals(unindent([[ + { + = {} + } + ]]), inspector(spam)) + assert.equals(unindent([[ + { + = {} + } + ]]), inspector(eggs)) + end) + + describe('When a table is its own metatable', function() + it('accepts a table that is its own metatable without stack overflowing', function() + local x = {} + setmetatable(x,x) + assert.equals(unindent([[ + <1>{ + =
+ } + ]]), inspect(x)) + end) + + it('can invoke the __tostring method without stack overflowing', function() + local t = {} + t.__index = t + setmetatable(t,t) + assert.equals(unindent([[ + <1>{ + __index =
, + =
+ } + ]]), inspect(t)) + end) + end) + end) + end) + + it('allows changing the global tostring', function() + local save = _G.tostring + _G.tostring = inspect + local s = tostring({1, 2, 3}) + _G.tostring = save + assert.equals("{ 1, 2, 3 }", s) + end) + +end) diff --git a/Data/DefaultContent/Libraries/inspect/spec/unindent.lua b/Data/DefaultContent/Libraries/inspect/spec/unindent.lua new file mode 100644 index 0000000..02324a1 --- /dev/null +++ b/Data/DefaultContent/Libraries/inspect/spec/unindent.lua @@ -0,0 +1,39 @@ +-- Unindenting transforms a string like this: +-- [[ +-- { +-- foo = 1, +-- bar = 2 +-- } +-- ]] +-- +-- Into the same one without indentation, nor start/end newlines +-- +-- [[{ +-- foo = 1, +-- bar = 2 +-- }]] +-- +-- This makes the strings look and read better in the tests +-- + +local getIndentPreffix = function(str) + local level = math.huge + local minPreffix = "" + local len + for preffix in str:gmatch("\n( +)") do + len = #preffix + if len < level then + level = len + minPreffix = preffix + end + end + return minPreffix +end + +local unindent = function(str) + str = str:gsub(" +$", ""):gsub("^ +", "") -- remove spaces at start and end + local preffix = getIndentPreffix(str) + return (str:gsub("\n" .. preffix, "\n"):gsub("\n$", "")) +end + +return unindent diff --git a/Data/DefaultContent/Libraries/json4lua/README.md b/Data/DefaultContent/Libraries/json4lua/README.md new file mode 100644 index 0000000..b4f8015 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/README.md @@ -0,0 +1,52 @@ +# json4lua +JSON and JSONRPC for Lua + +# Installation # +``` +luarocks install --server=http://rocks.moonscript.org/manifests/amrhassan --local json4Lua +``` + +# JSON Usage # + +## Encoding ## + +```lua +json = require('json') +print(json.encode({ 1, 2, 'fred', {first='mars',second='venus',third='earth'} })) +``` +```json +[1,2,"fred", {"first":"mars","second":"venus","third":"earth"}] +``` + +## Decoding ## + +```lua +json = require("json") +testString = [[ { "one":1 , "two":2, "primes":[2,3,5,7] } ]] +decoded = json.decode(testString) +table.foreach(decoded, print) +print ("Primes are:") +table.foreach(decoded.primes,print) +``` +``` +one 1 +two 2 +primes table: 0032B928 +Primes are: +1 2 +2 3 +3 5 +4 7 +``` + +# JSONRPC Usage # +```lua +json = require('json') +require("json.rpc") +server = json.rpc.proxy("http://jsolait.net/testj.py") +result, error = server.echo('Test echo!') +print(result) +``` +``` +Test echo! +``` diff --git a/Data/DefaultContent/Libraries/json4lua/doc/INSTALL.txt b/Data/DefaultContent/Libraries/json4lua/doc/INSTALL.txt new file mode 100644 index 0000000..3e7cad3 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/doc/INSTALL.txt @@ -0,0 +1,4 @@ +INSTALLATION +============ + +See INSTALLATION section in doc/index.html \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/json4lua/doc/LICENCE.txt b/Data/DefaultContent/Libraries/json4lua/doc/LICENCE.txt new file mode 100644 index 0000000..48f61e7 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/doc/LICENCE.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2009 Craig Mason-Jones + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/json4lua/doc/README.txt b/Data/DefaultContent/Libraries/json4lua/doc/README.txt new file mode 100644 index 0000000..59e5b7b --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/doc/README.txt @@ -0,0 +1,5 @@ +=================================================================================================================== +== README.txt +=================================================================================================================== + +Please see doc/index.html diff --git a/Data/DefaultContent/Libraries/json4lua/doc/VERSION.txt b/Data/DefaultContent/Libraries/json4lua/doc/VERSION.txt new file mode 100644 index 0000000..deae881 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/doc/VERSION.txt @@ -0,0 +1,4 @@ +JSON4Lua and JSONRPC4Lua +Version 1.0.0 +4 March 2015 +http://github.com/craigmj/json4lua/ \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/json4lua/doc/cgilua_patch.html b/Data/DefaultContent/Libraries/json4lua/doc/cgilua_patch.html new file mode 100644 index 0000000..1b4d6b3 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/doc/cgilua_patch.html @@ -0,0 +1,187 @@ + + +JSON4Lua and JSONRPC4Lua + + +
+ + + + + + + + +
+

+ + +

+ + + + + + + +
+
Patching CGILua to handle text/plain
+ + +JSON RPC (both the JSONRPC4Lua implementation and the jsolait Javascript implementation) send the http request with a Content-Type of text/plain.

+ +CGILua 5.0 does not accept text/plain content, and will generate an error of 'Unsupported Media Type: text/plain'.

+ +This is easily patched in CGILua 5.0 by making the following change to cgilua/post.lua, line 286:

+Change:

+	elseif strfind (contenttype, "text/xml") then
+
+to +
+	elseif strfind (contenttype, "text/xml") or strfind (contenttype, "text/plain") then
+
+This makes CGILua handle text/plain as it does text/xml, without parsing the incoming POST data.

+ +Please note: I have requested the maintainers of CGILua to make this change to CGILua, whereafter this patch will no longer be required. + + +

+ + \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/json4lua/doc/index.html b/Data/DefaultContent/Libraries/json4lua/doc/index.html new file mode 100644 index 0000000..12ec6c7 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/doc/index.html @@ -0,0 +1,394 @@ + + +JSON4Lua and JSONRPC4Lua + + + + + + + + + + + +
+

+ + +

+ + + + + + + +
+
JSON4Lua and JSONRPC4Lua
+ +

Latest News

+

(2009-08-06) We've changed the JSON4Lua and JSONRPC4Lua licence from the GPL to the MIT licence, like Lua itself.

+

+ The 0.9.20 release fixes a bug in Lua 5.1 operation, introduces a json.null value to force null values in JSON encodings, improves performance (over 50% faster on some tests), and permits /* comments */ in the JSON string being decoded. +

+ + +

Introduction

+ JSON4Lua and JSONRPC4Lua implement JSON (JavaScript Object Notation) encoding and decoding and a JSON-RPC-over-http client for Lua.

+ +JSON is JavaScript Object Notation, a simple encoding of Javascript-like objects that is ideal for lightweight transmission of relatively weakly-typed data. +A sub-package of JSON4Lua is JSONRPC4Lua, which provides a simple JSON-RPC-over-http client and server (in a CGILua environment) for Lua. Please seen the documentation below for JSONRPC4Lua. + + +

Licence

+ JSON4Lua is licensed under the MIT Consortium licence like Lua itself. Please see LICENCE.txt for details.

+ + +

Requirements

+ JSON4Lua is a pure-Lua module that is Lua 5.0 compatible (if you have compat-5.1 for Lua 5.0). JSON4Lua also works (perfectly, I hope) under Lua 5.1, which is where I largely use it nowadays. Since Lua is platform independent, so is JSON4Lua.

+ + The JSON4RPC sub-module requires Lua Socket 2.0. It uses socket.http for for the RPC over http connection. Socket 2.0 includes ltn12, which is also used by JSON4RPC.

+ + To use json.rpcserver you need a CGILua enabled webserver. However, a quick patch is required in CGILua 5.0 to support JSON-RPC. + + +

Download

+ JSON4Lua is hosted on LuaForge. + + + + + + + + + + + + + + + +
VersionDateNotes
0.9.306 August 2009 + Changed to MIT Licence. +
0.9.204 January 2006 + Introduction of local Lua functions for private functions (removed _ function prefix).
+ Fixed Lua 5.1 compatibility issues.
+ Introduced json.null to have null values in associative arrays.
+ Performance improvement (more than 50% on some tests) through table.concat rather than .. operator.
+ json.decode now ignores /* */ comments in the JSON string.
+
0.9.1020 December 2005 + Fixes bug with array representation when nil / null values occur in the array.
+ Adds content-type header of text/plain to JSON RPC http requests.
+ Introduces json.rpcserver module with simple JSON RPC enablement for Lua objects.
+ Moved the json.lua file into the json directory. Ensure, therefore, that your LUA_PATH contains a module-finding form like LUA_PATH = c:\proj\lua\?\?.lua;?.lua.
+
0.9.0119 December 2005Minor corrections to documentation.
0.9.0019 December 2005First release
+ + + +

Installation

+ As of version 0.9.10, all the JSON4Lua files are contained in the json subdirectory in the distribution zip.

+ Simply copy the json subdirectory so that it is in your Lua path.

+ Ensure that your LUA_PATH variable permits module resolution of the form ?/?.lua.

+ Example +

+
+

Using Windows

+ Under Windows, set your Lua path as (my Lua installation is in c:\proj\lua\):

+ + set LUA_PATH=c:\proj\lua\?.lua;c:\proj\lua\?\?.lua;?.lua +

+ For compat-5.1.lua to start when Lua starts (if you're using Lua 5.0), you also need:

+ + set LUA_INIT=@c:\proj\lua\compat-5.1.lua +

+ You probably also want to set your library path:

+ set LUA_CPATH=c:\proj\lua\lib\?.dll;?.dll + + +

Usage & Reference

+ The following functions in JSON4Lua and JSONRPC4Lua are of interest:

+

+
string json.encode( lua_object )
+
Returns the Lua object JSON encoded into a string.

+ Example +

+ + json = require("json")
+ print (json.encode( { 1, 2, 'fred', {first='mars',second='venus',third='earth'} } )) +

+ prints

[1,2,"fred", {"first":"mars","second":"venus","third","earth"}] +

+ +
+
lua_object json.decode( json_string )
+
Decodes the JSON encoded data structure, and returns a Lua object with the appropriate data.

+ Example + +

+ + json = require("json")
+ + testString = [[ { "one":1 , "two":2, "primes":[2,3,5,7] } ]]
+ o = json.decode(testString)
+ table.foreach(o,print)
+ print ("Primes are:")
+ table.foreach(o.primes,print) +

+ prints:

+

+one		1
+two		2
+primes		table: 0032B928
+Primes are:
+1		2
+2		3
+3		5
+4		7
+
+ +
json.null
+
Returns a unique value that will be encoded as a null in a JSON encoding. +

This is necessary in one situation. In Lua, if a key in a table has a nil value, the key is simply discarded (since any non-existent key has a nil value). The encoding of arrays has been built to manage this nil-values in arrays, but associative arrays provide a problem. Consider: +

t = { user="test", password=nil }
+ Since Lua simply discards the password key, JSON4Lua encodes this as the JSON string +
{"user":"test"}
+ If, for some reason, your JSON RPC Server requires a defined null value, use the following code: +
t = { user="test", password=json.null }
+ This will now correctly encode to: +
{"user":"test","password":null}
+ Incidentally, json.null is simply a function that returns itself, so that you can use either json.null or json.null() as you fancy. +
+ + +
result, error json.rpc.call ( url, method, ...)
+
Calls the named method on the given url with the arg parameters. Returns the result and the error. If error is nil, no error occurred.

+ Example +

+
require ("json.rpc")
+result, error = json.rpc.call("http://jsolait.net/testj.py","echo","Test echo!")
+print(result)
+

prints

+

Test echo!
+
+
+
proxyServer = json.rpc.proxy (url)
+
Creates a proxy server object on which JSON-RPC calls can be made. Each call will return the result, error. If error is nil, no error occurred.

+ Example +

+
+require ("json.rpc")
+server = json.rpc.proxy("http://jsolait.net/testj.py")
+result, error  = server.echo('Test echo!')
+print(result)
+

prints

+

Test echo!
+
+
+ +
json.rpcserver.serve(object[, packReturn])
+
+ Handles an incoming CGILua request as a JSON RPC request and serves the request from + the given object. +

The optional packReturn parameter, if set true, will, if the requested + method returns more than one value, pack these returned values into an array. If only a single value + is returned, it is not packed into an array. If packReturn is false (or not set), only the first + return value from the requested method will be returned. This is necessitated since the JSON protocol does not permit a method call to return more than a single value. +

+ + serve returns nothing.

+ + Example +

+
+--
+-- jsonrpc.lua
+-- Installed in a CGILua webserver environment (with necessary CGI Lua 5.0 patch)
+--
+require ('json.rpcserver')
+
+-- The Lua class that is to serve JSON RPC requests
+local myServer = {
+  echo = function (msg) return msg end,
+  average = function(...)
+    local total=0
+    local count=0
+    for i=1, table.getn(arg) do
+      total = total + arg[i]
+      count = count + 1
+    end
+    return { average= total/count, sum = total, n=count }
+  end
+}
+
+json.rpcserver.serve(myServer)
+
+An example of using this JSON RPC server from a Lua file: +
+require ('json.rpc')
+local server = json.rpc.proxy('http://www.myserver.com/jsonrpc.lua')
+table.foreach(server.average(10,15,23), print)
+
+Prints: +
+average	16
+sum	48
+n	3
+
+
+ +
+
+ + +

History & Roadmap

+ The downloads sections details the versions and their related histories. I will wait for Lua 5.1 to be final (expected late January) before making the JSON4Lua module beta. If no serious bugs or objections are encountered, I will make the module 1.0 on 1 April 2006 (to coincide with April Fool's day!) +
+ + \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/json4lua/doc/pics/json4lua.gif b/Data/DefaultContent/Libraries/json4lua/doc/pics/json4lua.gif new file mode 100644 index 0000000..938bcb9 Binary files /dev/null and b/Data/DefaultContent/Libraries/json4lua/doc/pics/json4lua.gif differ diff --git a/Data/DefaultContent/Libraries/json4lua/doc/pics/lunartone.gif b/Data/DefaultContent/Libraries/json4lua/doc/pics/lunartone.gif new file mode 100644 index 0000000..e914a8f Binary files /dev/null and b/Data/DefaultContent/Libraries/json4lua/doc/pics/lunartone.gif differ diff --git a/Data/DefaultContent/Libraries/json4lua/examples/example.lua b/Data/DefaultContent/Libraries/json4lua/examples/example.lua new file mode 100644 index 0000000..36497da --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/examples/example.lua @@ -0,0 +1,23 @@ +--[[ +JSON4Lua example script. +Demonstrates the simple functionality of the json module. +]]-- +json = require('json') + + +-- Object to JSON encode +test = { + one='first',two='second',three={2,3,5} +} + +jsonTest = json.encode(test) + +print('JSON encoded test is: ' .. jsonTest) + +-- Now JSON decode the json string +result = json.decode(jsonTest) + +print ("The decoded table result:") +table.foreach(result,print) +print ("The decoded table result.three") +table.foreach(result.three, print) diff --git a/Data/DefaultContent/Libraries/json4lua/examples/jsonrpc.lua b/Data/DefaultContent/Libraries/json4lua/examples/jsonrpc.lua new file mode 100644 index 0000000..f265b8a --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/examples/jsonrpc.lua @@ -0,0 +1,21 @@ +-- +-- jsonrpc.lua +-- Installed in a CGILua webserver environment (with necessary CGI Lua 5.0 patch) +-- +require ('json.rpcserver') + +-- The Lua class that is to serve JSON RPC requests +local myServer = { + echo = function (msg) return msg end, + average = function(...) + local total=0 + local count=0 + for i=1, table.getn(arg) do + total = total + arg[i] + count = count + 1 + end + return { average= total/count, sum = total, n=count } + end +} + +json.rpcserver.serve(myServer) \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/json4lua/examples/tests.lua b/Data/DefaultContent/Libraries/json4lua/examples/tests.lua new file mode 100644 index 0000000..2e58b6e --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/examples/tests.lua @@ -0,0 +1,223 @@ +--[[ +Some basic tests for JSON4Lua. +]]-- + +--- Compares two tables for being data-identical. +function compareData(a,b) + if (type(a)=='string' or type(a)=='number' or type(a)=='boolean' or type(a)=='nil') then return a==b end + -- After basic data types, we're only interested in tables + if (type(a)~='table') then return true end + -- Check that a has everything b has + for k,v in pairs(b) do + if (not compareData( a[k], v ) ) then return false end + end + for k,v in pairs(a) do + if (not compareData( v, b[k] ) ) then return false end + end + return true +end + +--- +-- Checks that our compareData function works properly +function testCompareData() + s = "name" + r = "name" + assert(compareData(s,r)) + assert(not compareData('fred',s)) + assert(not compareData(nil, s)) + assert(not compareData("123",123)) + assert(not compareData(false, nil)) + assert(compareData(true, true)) + assert(compareData({1,2,3},{1,2,3})) + assert(compareData({'one',2,'three'},{'one',2,'three'})) + assert(not compareData({'one',2,4},{4,2,'one'})) + assert(compareData({one='ichi',two='nichi',three='san'}, {three='san',two='nichi',one='ichi'})) + s = { one={1,2,3}, two={one='hitotsu',two='futatsu',three='mitsu'} } + assert(compareData(s,s)) + t = { one={1,2,3}, two={one='een',two='twee',three='drie'} } + assert(not compareData(s,t)) +end + +testCompareData() + +-- +-- +-- Performs some perfunctory tests on JSON module +function testJSON4Lua() + json = require('json') + + if nil then + -- Test encodeString + s = [["\" +]] + r = json._encodeString(s) + assert(r=='\\"\\\\\\"\\n') + s = [["""\\\"]] + r = json._encodeString(s) + assert(r==[[\"\"\"\\\\\\\"]]) + + end + + -- Test encode for basic strings (complicated strings) + s = [[Hello, Lua!]] + r = json.encode(s) + assert(r=='"Hello, Lua!"') + s = [["\" +]] + r = json.encode(s) + assert(r=='\"\\"\\\\\\"\\n\"') + s = [["""\\\"]] + r = json.encode(s) + assert(r==[["\"\"\"\\\\\\\""]]) + + -- Test encode for numeric values + s = 23 + r = json.encode(s) + assert(r=='23') + s=48.123 + r = json.encode(s) + assert(r=='48.123') + + -- Test encode for boolean values + assert(json.encode(true)=='true') + assert(json.encode(false)=='false') + assert(json.encode(nil)=='null') + + -- Test encode for arrays + s = {1,2,3} + r = json.encode(s) + assert(r=="[1,2,3]") + s = {9,9,9} + r = json.encode(s) + assert(r=="[9,9,9]") + + -- Complex array test + s = { 2, 'joe', false, nil, 'hi' } + r = json.encode(s) + assert(r=='[2,"joe",false,null,"hi"]') + + -- Test encode for tables + s = {Name='Craig',email='craig@lateral.co.za',age=35} + r = json.encode(s) + -- NB: This test can fail because of order: need to test further once + -- decoding is supported. + -- assert(r==[[{"age":35,"Name":"Craig","email":"craig@lateral.co.za"}]]) + + -- Test encoding tables with numeric (string) indexes + s = {} + s['1']='One' + r = json.encode(s) + -- print("r = ", r) + assert(r=='{"1":"One"}') + + s['2']= {One='Uno'} + r = json.encode(s) + assert(compareData(json.decode(r), s)) + + -- Test decode_scanWhitespace + if nil then + s = " \n \r \t " + e = json._decode_scanWhitespace(s,1) + assert(e==string.len(s)+1) + s = " \n\r\t4" + assert(json._decode_scanWhitespace(s,1)==5) + + -- Test decode_scanString + s = [["Test"]] + r,e = json._decode_scanString(s,1) + assert(r=='Test' and e==7) + s = [["This\nis a \"test"]] + r = json._decode_scanString(s,1) + assert(r=="This\nis a \"test") + + s = [["Test\u00A7\\"]] + r,e = json._decode_scanString(s,1) + assert(r=="Test\xC2\xA7\\" and e==9) + + -- Test decode_scanNumber + s = [[354]] + r,e = json._decode_scanNumber(s,1) + assert(r==354 and e==4) + s = [[ 4565.23 AND OTHER THINGS ]] + r,e = json._decode_scanNumber(s,2) + assert(r==4565.23 and e==9) + s = [[ -23.22 and ]] + r,e = json._decode_scanNumber(s,2) + assert(r==-23.22 and e==8) + + -- Test decode_scanConstant + s = "true" + r,e = json._decode_scanConstant(s,1) + assert(r==true and e==5) + s = " false " + r,e = json._decode_scanConstant(s,3) + assert(r==false and e==8) + s = "1null6" + r,e = json._decode_scanConstant(s,2) + assert(r==nil and e==6) + + -- Test decode_scanArray + s = "[1,2,3]" + r,e = json._decode_scanArray(s,1) + assert(compareData(r,{1,2,3})) + s = [[[ 1 , 3 ,5 , "Fred" , true, false, null, -23 ] ]] + r,e = json._decode_scanArray(s,1) + assert(compareData(r, {1,3,5,'Fred',true,false,nil,-23} ) ) + s = "[3,5,null,7,9]" + r,e = json._decode_scanArray(s,1) + assert(compareData(r, {3,5,nil,7,9})) + s = "[3,5,null,7,9,null,null]" + r,e = json._decode_scanArray(s,1) + assert(compareData(r, {3,5,nil,7,9,nil,nil})) + + end + + s = [["Test\u00A7\\\""]] + r,e = json.decode(s) + assert(r=="Test\xC2\xA7\\\"", r) + + -- Test decode_scanObject + s = [[ {"one":1, "two":2, "three":"three", "four":true} ]] + r,e = json.decode(s) + -- for x,y in pairs(r) do + -- print(x,y) + -- end + assert(compareData(r,{one=1,two=2,three='three',four=true})) + s = [[ { "one" : { "first":1,"second":2,"third":3}, "two":2, "three":false } ]] + r,e = json.decode(s) + assert(compareData(r, {one={first=1,second=2,third=3},two=2,three=false})) + s = [[ { "primes" : [2,3,5,7,9], "user":{"name":"craig","age":35,"programs_lua":true}, + "lua_is_great":true } ]] + r,e = json.decode(s) + assert(compareData(r, {primes={2,3,5,7,9},user={name='craig',age=35,programs_lua=true},lua_is_great=true})) + + -- Test json.null management + t = { 1,2,json.null,4 } + assert( json.encode(t)=="[1,2,null,4]" ) + t = {x=json.null } + r = json.encode(t) + assert( json.encode(t) == '{"x":null}' ) + + -- Test comment decoding + s = [[ /* A comment + that spans + a few lines + */ + "test" + ]] + r,e = json.decode(s) + assert(r=='test',"Comment decoding failed") + + -- Per error reported by M.Hund, with incorrect decoding of string-numbered tables + s = {} + subt = {a="a",b="b",c="c"} + s['1'] = subt + s['2'] = subt + s['3'] = subt + r = json.decode('{"1":{"a":"a","b":"b","c":"c"},"2":{"a":"a","b":"b","c":"c"},"3":{"a":"a","b":"b","c":"c"}}') + assert(compareData(s, r)) +end + +testJSON4Lua() + +print("JSON4Lua tests completed successfully") diff --git a/Data/DefaultContent/Libraries/json4lua/examples/timetrials.lua b/Data/DefaultContent/Libraries/json4lua/examples/timetrials.lua new file mode 100644 index 0000000..cbda514 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/examples/timetrials.lua @@ -0,0 +1,46 @@ +--[[ + Some Time Trails for the JSON4Lua package +]]-- + + +require('json') +require('os') +require('table') + +local t1 = os.clock() +local jstr +local v +for i=1,100 do + local t = {} + for j=1,500 do + table.insert(t,j) + end + for j=1,500 do + table.insert(t,"VALUE") + end + jstr = json.encode(t) + v = json.decode(jstr) + --print(json.encode(t)) +end + +for i = 1,100 do + local t = {} + for j=1,500 do + local m= math.mod(j,3) + if (m==0) then + t['a'..j] = true + elseif m==1 then + t['a'..j] = json.null + else + t['a'..j] = j + end + end + jstr = json.encode(t) + v = json.decode(jstr) +end + +print (jstr) +--print(type(t1)) +local t2 = os.clock() + +print ("Elapsed time=" .. os.difftime(t2,t1) .. "s") \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/json4lua/json/json.lua b/Data/DefaultContent/Libraries/json4lua/json/json.lua new file mode 100644 index 0000000..79761b6 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/json/json.lua @@ -0,0 +1,427 @@ +----------------------------------------------------------------------------- +-- JSON4Lua: JSON encoding / decoding support for the Lua language. +-- json Module. +-- Author: Craig Mason-Jones +-- Homepage: http://github.com/craigmj/json4lua/ +-- Version: 1.0.0 +-- This module is released under the MIT License (MIT). +-- Please see LICENCE.txt for details. +-- +-- USAGE: +-- This module exposes two functions: +-- json.encode(o) +-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string. +-- json.decode(json_string) +-- Returns a Lua object populated with the data encoded in the JSON string json_string. +-- +-- REQUIREMENTS: +-- compat-5.1 if using Lua 5.0 +-- +-- CHANGELOG +-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix). +-- Fixed Lua 5.1 compatibility issues. +-- Introduced json.null to have null values in associative arrays. +-- json.encode() performance improvement (more than 50%) through table.concat rather than .. +-- Introduced decode ability to ignore /**/ comments in the JSON string. +-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays. +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Imports and dependencies +----------------------------------------------------------------------------- +local math = require('math') +local string = require("string") +local table = require("table") + +----------------------------------------------------------------------------- +-- Module declaration +----------------------------------------------------------------------------- +local json = {} -- Public namespace +local json_private = {} -- Private namespace + +-- Public constants +json.EMPTY_ARRAY={} +json.EMPTY_OBJECT={} + +-- Public functions + +-- Private functions +local decode_scanArray +local decode_scanComment +local decode_scanConstant +local decode_scanNumber +local decode_scanObject +local decode_scanString +local decode_scanWhitespace +local encodeString +local isArray +local isEncodable + +----------------------------------------------------------------------------- +-- PUBLIC FUNCTIONS +----------------------------------------------------------------------------- +--- Encodes an arbitrary Lua object / variable. +-- @param v The Lua object / variable to be JSON encoded. +-- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode) +function json.encode (v) + -- Handle nil values + if v==nil then + return "null" + end + + local vtype = type(v) + + -- Handle strings + if vtype=='string' then + return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string + end + + -- Handle booleans + if vtype=='number' or vtype=='boolean' then + return tostring(v) + end + + -- Handle tables + if vtype=='table' then + local rval = {} + -- Consider arrays separately + local bArray, maxCount = isArray(v) + if bArray then + for i = 1,maxCount do + table.insert(rval, json.encode(v[i])) + end + else -- An object, not an array + for i,j in pairs(v) do + if isEncodable(i) and isEncodable(j) then + table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j)) + end + end + end + if bArray then + return '[' .. table.concat(rval,',') ..']' + else + return '{' .. table.concat(rval,',') .. '}' + end + end + + -- Handle null values + if vtype=='function' and v==json.null then + return 'null' + end + + assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v)) +end + + +--- Decodes a JSON string and returns the decoded value as a Lua data structure / value. +-- @param s The string to scan. +-- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1. +-- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil, +-- and the position of the first character after +-- the scanned JSON object. +function json.decode(s, startPos) + startPos = startPos and startPos or 1 + startPos = decode_scanWhitespace(s,startPos) + assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']') + local curChar = string.sub(s,startPos,startPos) + -- Object + if curChar=='{' then + return decode_scanObject(s,startPos) + end + -- Array + if curChar=='[' then + return decode_scanArray(s,startPos) + end + -- Number + if string.find("+-0123456789.e", curChar, 1, true) then + return decode_scanNumber(s,startPos) + end + -- String + if curChar==[["]] or curChar==[[']] then + return decode_scanString(s,startPos) + end + if string.sub(s,startPos,startPos+1)=='/*' then + return json.decode(s, decode_scanComment(s,startPos)) + end + -- Otherwise, it must be a constant + return decode_scanConstant(s,startPos) +end + +--- The null function allows one to specify a null value in an associative array (which is otherwise +-- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null } +function json.null() + return json.null -- so json.null() will also return null ;-) +end +----------------------------------------------------------------------------- +-- Internal, PRIVATE functions. +-- Following a Python-like convention, I have prefixed all these 'PRIVATE' +-- functions with an underscore. +----------------------------------------------------------------------------- + +--- Scans an array from JSON into a Lua object +-- startPos begins at the start of the array. +-- Returns the array and the next starting position +-- @param s The string being scanned. +-- @param startPos The starting position for the scan. +-- @return table, int The scanned array as a table, and the position of the next character to scan. +function decode_scanArray(s,startPos) + local array = {} -- The return value + local stringLen = string.len(s) + assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s ) + startPos = startPos + 1 + -- Infinite loop for array elements + local index = 1 + repeat + startPos = decode_scanWhitespace(s,startPos) + assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.') + local curChar = string.sub(s,startPos,startPos) + if (curChar==']') then + return array, startPos+1 + end + if (curChar==',') then + startPos = decode_scanWhitespace(s,startPos+1) + end + assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.') + object, startPos = json.decode(s,startPos) + array[index] = object + index = index + 1 + until false +end + +--- Scans a comment and discards the comment. +-- Returns the position of the next character following the comment. +-- @param string s The JSON string to scan. +-- @param int startPos The starting position of the comment +function decode_scanComment(s, startPos) + assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos) + local endPos = string.find(s,'*/',startPos+2) + assert(endPos~=nil, "Unterminated comment in string at " .. startPos) + return endPos+2 +end + +--- Scans for given constants: true, false or null +-- Returns the appropriate Lua type, and the position of the next character to read. +-- @param s The string being scanned. +-- @param startPos The position in the string at which to start scanning. +-- @return object, int The object (true, false or nil) and the position at which the next character should be +-- scanned. +function decode_scanConstant(s, startPos) + local consts = { ["true"] = true, ["false"] = false, ["null"] = nil } + local constNames = {"true","false","null"} + + for i,k in pairs(constNames) do + if string.sub(s,startPos, startPos + string.len(k) -1 )==k then + return consts[k], startPos + string.len(k) + end + end + assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos) +end + +--- Scans a number from the JSON encoded string. +-- (in fact, also is able to scan numeric +- eqns, which is not +-- in the JSON spec.) +-- Returns the number, and the position of the next character +-- after the number. +-- @param s The string being scanned. +-- @param startPos The position at which to start scanning. +-- @return number, int The extracted number and the position of the next character to scan. +function decode_scanNumber(s,startPos) + local endPos = startPos+1 + local stringLen = string.len(s) + local acceptableChars = "+-0123456789.e" + while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true) + and endPos<=stringLen + ) do + endPos = endPos + 1 + end + local stringValue = 'return ' .. string.sub(s,startPos, endPos-1) + local stringEval = load(stringValue) + assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos) + return stringEval(), endPos +end + +--- Scans a JSON object into a Lua object. +-- startPos begins at the start of the object. +-- Returns the object and the next starting position. +-- @param s The string being scanned. +-- @param startPos The starting position of the scan. +-- @return table, int The scanned object as a table and the position of the next character to scan. +function decode_scanObject(s,startPos) + local object = {} + local stringLen = string.len(s) + local key, value + assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s) + startPos = startPos + 1 + repeat + startPos = decode_scanWhitespace(s,startPos) + assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.') + local curChar = string.sub(s,startPos,startPos) + if (curChar=='}') then + return object,startPos+1 + end + if (curChar==',') then + startPos = decode_scanWhitespace(s,startPos+1) + end + assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.') + -- Scan the key + key, startPos = json.decode(s,startPos) + assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + startPos = decode_scanWhitespace(s,startPos) + assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos) + startPos = decode_scanWhitespace(s,startPos+1) + assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + value, startPos = json.decode(s,startPos) + object[key]=value + until false -- infinite loop while key-value pairs are found +end + +-- START SoniEx2 +-- Initialize some things used by decode_scanString +-- You know, for efficiency +local escapeSequences = { + ["\\t"] = "\t", + ["\\f"] = "\f", + ["\\r"] = "\r", + ["\\n"] = "\n", + ["\\b"] = "\b" +} +setmetatable(escapeSequences, {__index = function(t,k) + -- skip "\" aka strip escape + return string.sub(k,2) +end}) +-- END SoniEx2 + +--- Scans a JSON string from the opening inverted comma or single quote to the +-- end of the string. +-- Returns the string extracted as a Lua string, +-- and the position of the next non-string character +-- (after the closing inverted comma or single quote). +-- @param s The string being scanned. +-- @param startPos The starting position of the scan. +-- @return string, int The extracted string as a Lua string, and the next character to parse. +function decode_scanString(s,startPos) + assert(startPos, 'decode_scanString(..) called without start position') + local startChar = string.sub(s,startPos,startPos) + -- START SoniEx2 + -- PS: I don't think single quotes are valid JSON + assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string') + --assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart) + local t = {} + local i,j = startPos,startPos + while string.find(s, startChar, j+1) ~= j+1 do + local oldj = j + i,j = string.find(s, "\\.", j+1) + local x,y = string.find(s, startChar, oldj+1) + if not i or x < i then + i,j = x,y-1 + end + table.insert(t, string.sub(s, oldj+1, i-1)) + if string.sub(s, i, j) == "\\u" then + local a = string.sub(s,j+1,j+4) + j = j + 4 + local n = tonumber(a, 16) + assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j) + -- math.floor(x/2^y) == lazy right shift + -- a % 2^b == bitwise_and(a, (2^b)-1) + -- 64 = 2^6 + -- 4096 = 2^12 (or 2^6 * 2^6) + local x + if n < 0x80 then + x = string.char(n % 0x80) + elseif n < 0x800 then + -- [110x xxxx] [10xx xxxx] + x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40)) + else + -- [1110 xxxx] [10xx xxxx] [10xx xxxx] + x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40)) + end + table.insert(t, x) + else + table.insert(t, escapeSequences[string.sub(s, i, j)]) + end + end + table.insert(t,string.sub(j, j+1)) + assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")") + return table.concat(t,""), j+2 + -- END SoniEx2 +end + +--- Scans a JSON string skipping all whitespace from the current start position. +-- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached. +-- @param s The string being scanned +-- @param startPos The starting position where we should begin removing whitespace. +-- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string +-- was reached. +function decode_scanWhitespace(s,startPos) + local whitespace=" \n\r\t" + local stringLen = string.len(s) + while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do + startPos = startPos + 1 + end + return startPos +end + +--- Encodes a string to be JSON-compatible. +-- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-) +-- @param s The string to return as a JSON encoded (i.e. backquoted string) +-- @return The string appropriately escaped. + +local escapeList = { + ['"'] = '\\"', + ['\\'] = '\\\\', + ['/'] = '\\/', + ['\b'] = '\\b', + ['\f'] = '\\f', + ['\n'] = '\\n', + ['\r'] = '\\r', + ['\t'] = '\\t' +} + +function json_private.encodeString(s) + local s = tostring(s) + return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat +end + +-- Determines whether the given Lua type is an array or a table / dictionary. +-- We consider any table an array if it has indexes 1..n for its n items, and no +-- other data in the table. +-- I think this method is currently a little 'flaky', but can't think of a good way around it yet... +-- @param t The table to evaluate as an array +-- @return boolean, number True if the table can be represented as an array, false otherwise. If true, +-- the second returned value is the maximum +-- number of indexed elements in the array. +function isArray(t) + -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable + -- (with the possible exception of 'n') + if (t == json.EMPTY_ARRAY) then return true, 0 end + if (t == json.EMPTY_OBJECT) then return false end + + local maxIndex = 0 + for k,v in pairs(t) do + if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair + if (not isEncodable(v)) then return false end -- All array elements must be encodable + maxIndex = math.max(maxIndex,k) + else + if (k=='n') then + if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements + else -- Else of (k=='n') + if isEncodable(v) then return false end + end -- End of (k~='n') + end -- End of k,v not an indexed pair + end -- End of loop across all pairs + return true, maxIndex +end + +--- Determines whether the given Lua object / table / variable can be JSON encoded. The only +-- types that are JSON encodable are: string, boolean, number, nil, table and json.null. +-- In this implementation, all other types are ignored. +-- @param o The object to examine. +-- @return boolean True if the object should be JSON encoded, false if it should be ignored. +function isEncodable(o) + local t = type(o) + return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or + (t=='function' and o==json.null) +end + +return json diff --git a/Data/DefaultContent/Libraries/json4lua/json/rpc.lua b/Data/DefaultContent/Libraries/json4lua/json/rpc.lua new file mode 100644 index 0000000..952c5b5 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/json/rpc.lua @@ -0,0 +1,107 @@ +----------------------------------------------------------------------------- +-- JSONRPC4Lua: JSON RPC client calls over http for the Lua language. +-- json.rpc Module. +-- Author: Craig Mason-Jones +-- Homepage: http://github.com/craigmj/json4lua/ +-- Version: 1.0.0 +-- This module is released under the MIT License (MIT). +-- Please see LICENCE.txt for details. +-- +-- USAGE: +-- This module exposes two functions: +-- proxy( 'url') +-- Returns a proxy object for calling the JSON RPC Service at the given url. +-- call ( 'url', 'method', ...) +-- Calls the JSON RPC server at the given url, invokes the appropriate method, and +-- passes the remaining parameters. Returns the result and the error. If the result is nil, an error +-- should be there (or the system returned a null). If an error is there, the result should be nil. +-- +-- REQUIREMENTS: +-- Lua socket 2.0 (http://www.cs.princeton.edu/~diego/professional/luasocket/) +-- json (The JSON4Lua package with which it is bundled) +-- compat-5.1 if using Lua 5.0. +----------------------------------------------------------------------------- + +local json = require('json') +json.rpc = {} -- Module public namespace + +----------------------------------------------------------------------------- +-- Imports and dependencies +----------------------------------------------------------------------------- +local json = require('json') +local http = require("socket.http") + +----------------------------------------------------------------------------- +-- PUBLIC functions +----------------------------------------------------------------------------- + +--- Creates an RPC Proxy object for the given Url of a JSON-RPC server. +-- @param url The URL for the JSON RPC Server. +-- @return Object on which JSON-RPC remote methods can be called. +-- EXAMPLE Usage: +-- local jsolait = json.rpc.proxy('http://jsolait.net/testj.py') +-- print(jsolait.echo('This is a test of the echo method!')) +-- print(jsolait.args2String('first','second','third')) +-- table.foreachi( jsolait.args2Array(5,4,3,2,1), print) +function json.rpc.proxy(url) + local serverProxy = {} + local proxyMeta = { + __index = function(self, key) + return function(...) + return json.rpc.call(url, key, ...) + end + end + } + setmetatable(serverProxy, proxyMeta) + return serverProxy +end + +--- Calls a JSON RPC method on a remote server. +-- Returns a boolean true if the call succeeded, false otherwise. +-- On success, the second returned parameter is the decoded +-- JSON object from the server. +-- On http failure, returns nil and an error message. +-- On success, returns the result and nil. +-- @param url The url of the JSON RPC server. +-- @param method The method being called. +-- @param ... Parameters to pass to the method. +-- @return result, error The JSON RPC result and error. One or the other should be nil. If both +-- are nil, this means that the result of the RPC call was nil. +-- EXAMPLE Usage: +-- print(json.rpc.call('http://jsolait.net/testj.py','echo','This string will be returned')) +function json.rpc.call(url, method, ...) + local JSONRequestArray = { + id=tostring(math.random()), + ["method"]=method, + ["jsonrpc"]="2.0", + params = ... + } + local httpResponse, result , code + local jsonRequest = json.encode(JSONRequestArray) + -- We use the sophisticated http.request form (with ltn12 sources and sinks) so that + -- we can set the content-type to text/plain. While this shouldn't strictly-speaking be true, + -- it seems a good idea (Xavante won't work w/out a content-type header, although a patch + -- is needed to Xavante to make it work with text/plain) + local ltn12 = require('ltn12') + local resultChunks = {} + httpResponse, code = http.request( + { ['url'] = url, + sink = ltn12.sink.table(resultChunks), + method = 'POST', + headers = { ['content-type']='application/json-rpc', ['content-length']=string.len(jsonRequest) }, + source = ltn12.source.string(jsonRequest) + } + ) + httpResponse = table.concat(resultChunks) + -- Check the http response code + if (code~=200) then + return nil, "HTTP ERROR: " .. code + end + -- And decode the httpResponse and check the JSON RPC result code + result = json.decode( httpResponse ) + if result.result then + return result.result, nil + else + return nil, result.error + end +end diff --git a/Data/DefaultContent/Libraries/json4lua/json/rpcserver.lua b/Data/DefaultContent/Libraries/json4lua/json/rpcserver.lua new file mode 100644 index 0000000..e01f1f8 --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/json/rpcserver.lua @@ -0,0 +1,78 @@ +----------------------------------------------------------------------------- +-- JSONRPC4Lua: JSON RPC server for exposing Lua objects as JSON RPC callable +-- objects via http. +-- json.rpcserver Module. +-- Author: Craig Mason-Jones +-- Homepage: http://github.com/craigmj/json4lua/ +-- Version: 1.0.0 +-- This module is released under the MIT License (MIT). +-- Please see LICENCE.txt for details. +-- +-- USAGE: +-- This module exposes one function: +-- server(luaClass, packReturn) +-- Manages incoming JSON RPC request forwarding the method call to the given +-- object. If packReturn is true, multiple return values are packed into an +-- array on return. +-- +-- IMPORTANT NOTES: +-- 1. This version ought really not be 0.9.10, since this particular part of the +-- JSONRPC4Lua package is very first-draft. However, the JSON4Lua package with which +-- it comes is quite solid, so there you have it :-) +-- 2. This has only been tested with Xavante webserver, with which it works +-- if you patch CGILua to accept 'text/plain' content type. See doc\cgilua_patch.html +-- for details. +---------------------------------------------------------------------------- + +module ('json.rpcserver') + +--- +-- Implements a JSON RPC Server wrapping for luaClass, exposing each of luaClass's +-- methods as JSON RPC callable methods. +-- @param luaClass The JSON RPC class to expose. +-- @param packReturn If true, the server will automatically wrap any +-- multiple-value returns into an array. Single returns remain single returns. If +-- false, when a function returns multiple values, only the first of these values will +-- be returned. +-- +function serve(luaClass, packReturn) + cgilua.contentheader('text','plain') + require('cgilua') + require ('json') + local postData = "" + + if not cgilua.servervariable('CONTENT_LENGTH') then + cgilua.put("Please access JSON Request using HTTP POST Request") + return 0 + else + postData = cgi[1] -- SAPI.Request.getpostdata() --[[{ "id":1, "method":"echo","params":["Hi there"]}]] -- + end + -- @TODO Catch an error condition on decoding the data + local jsonRequest = json.decode(postData) + local jsonResponse = {} + jsonResponse.id = jsonRequest.id + local method = luaClass[ jsonRequest.method ] + + if not method then + jsonResponse.error = 'Method ' .. jsonRequest.method .. ' does not exist at this server.' + else + local callResult = { pcall( method, unpack( jsonRequest.params ) ) } + if callResult[1] then -- Function call successfull + table.remove(callResult,1) + if packReturn and table.getn(callResult)>1 then + jsonResponse.result = callResult + else + jsonResponse.result = unpack(callResult) -- NB: Does not support multiple argument returns + end + else + jsonResponse.error = callResult[2] + end + end + + -- Output the result + -- TODO: How to be sure that the result and error tags are there even when they are nil in Lua? + -- Can force them by hand... ? + cgilua.contentheader('text','plain') + cgilua.put( json.encode( jsonResponse ) ) +end + diff --git a/Data/DefaultContent/Libraries/json4lua/json4lua-1.0.0-1.rockspec b/Data/DefaultContent/Libraries/json4lua/json4lua-1.0.0-1.rockspec new file mode 100644 index 0000000..b3b737a --- /dev/null +++ b/Data/DefaultContent/Libraries/json4lua/json4lua-1.0.0-1.rockspec @@ -0,0 +1,32 @@ +package="JSON4Lua" +version="1.0.0" +source = { + url = "git://github.com/craigmj/json4lua.git", + tag = "1.0.0" +} +description = { + summary = "JSON4Lua and JSONRPC4Lua implement JSON (JavaScript Object Notation) encoding and decoding and a JSON-RPC-over-http client for Lua.", + detailed = [[ + JSON4Lua and JSONRPC4Lua implement JSON (JavaScript Object Notation) + encoding and decoding and a JSON-RPC-over-http client for Lua. + JSON is JavaScript Object Notation, a simple encoding of + Javascript-like objects that is ideal for lightweight transmission + of relatively weakly-typed data. A sub-package of JSON4Lua is + JSONRPC4Lua, which provides a simple JSON-RPC-over-http client and server + (in a CGILua environment) for Lua. + ]], + homepage = "http://github.com/craigmj/json4lua/", + license = "GPL" +} +dependencies = { + "lua >= 5.2", + "luasocket", +} + +build = { + type = "builtin", + modules = { + ["json"] = "json/json.lua", + ["json.rpc"] = "json/rpc.lua" + } +} diff --git a/Data/DefaultContent/Libraries/lbase64/.gitignore b/Data/DefaultContent/Libraries/lbase64/.gitignore new file mode 100644 index 0000000..a70719a --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/.gitignore @@ -0,0 +1,3 @@ +*.out +*.swp +*.swo diff --git a/Data/DefaultContent/Libraries/lbase64/.travis.yml b/Data/DefaultContent/Libraries/lbase64/.travis.yml new file mode 100644 index 0000000..7bca356 --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/.travis.yml @@ -0,0 +1,25 @@ +language: python +sudo: false + +env: + - LUA="lua 5.1" + - LUA="lua 5.2" + - LUA="lua 5.3" + - LUA="lua 5.4" + - LUA="luajit 2.0" + - LUA="luajit 2.1" + +before_install: + - pip install hererocks + - hererocks env --$LUA -rlatest # Use latest LuaRocks, install into 'env' directory. + - source env/bin/activate # Add directory with all installed binaries to PATH.notifications: + +notifications: + email: false + +install: + - luarocks install luacheck + +script: + - luacheck --no-unused-args *.lua + - lua test.lua diff --git a/Data/DefaultContent/Libraries/lbase64/README.md b/Data/DefaultContent/Libraries/lbase64/README.md new file mode 100644 index 0000000..1b5b0ee --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/README.md @@ -0,0 +1,48 @@ +[![Build Status](https://travis-ci.org/iskolbin/lbase64.svg?branch=master)](https://travis-ci.org/iskolbin/lbase64) +[![license](https://img.shields.io/badge/license-public%20domain-blue.svg)]() +[![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php) + +Lua base64 encoder/decoder +========================== + +Pure Lua [base64](https://en.wikipedia.org/wiki/Base64) encoder/decoder. Works with +Lua 5.1+ and LuaJIT. Fallbacks to pure Lua bit operations if bit/bit32/native bit +operators are not available. + +```lua +local base64 = require'base64' +local str = 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.' +local b64str = 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=' +local encoded = base64.encode( str ) +local decoded = base64.decode( b64str ) +assert( str == decoded ) +assert( b64str == encoded ) +``` + +base64.encode( str, encoder = DEFAULT, usecache = false ) +--------------------------------------------------------- +Encodes `str` string using `encoder` table. By default uses table with `+` as +char for 62, `/` as char for 63 and `=` as padding char. You can specify custom +encoder. For this you could use `base64.makeencoder`. If you are encoding large +chunks of text (or another highly redundant data) it's possible to highly +increase performace (for text approx. x2 gain) by using `usecache = true`. For +binary data like images using cache decreasing performance. + +base64.decode( str, decoder = DEFAULT, usecache = false ) +--------------------------------------------------------- +Decodes `str` string using `decoder` table. Default decoder uses same chars as +default encoder. + +base64.makeencoder( s62 = '+', s63 = '/', spad = '=' ) +------------------------------------------------------ +Make custom encoding table + +base64.makedecoder( s62 = '+', s63 = '/', spad = '=' ) +------------------------------------------------------ +Make custom decoding table + +Install +------- +```bash +luarocks install base64 +``` diff --git a/Data/DefaultContent/Libraries/lbase64/base64.lua b/Data/DefaultContent/Libraries/lbase64/base64.lua new file mode 100644 index 0000000..32de332 --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/base64.lua @@ -0,0 +1,201 @@ +--[[ + + base64 -- v1.5.3 public domain Lua base64 encoder/decoder + no warranty implied; use at your own risk + + Needs bit32.extract function. If not present it's implemented using BitOp + or Lua 5.3 native bit operators. For Lua 5.1 fallbacks to pure Lua + implementation inspired by Rici Lake's post: + http://ricilake.blogspot.co.uk/2007/10/iterating-bits-in-lua.html + + author: Ilya Kolbin (iskolbin@gmail.com) + url: github.com/iskolbin/lbase64 + + COMPATIBILITY + + Lua 5.1+, LuaJIT + + LICENSE + + See end of file for license information. + +--]] + + +local base64 = {} + +local extract = _G.bit32 and _G.bit32.extract -- Lua 5.2/Lua 5.3 in compatibility mode +if not extract then + if _G.bit then -- LuaJIT + local shl, shr, band = _G.bit.lshift, _G.bit.rshift, _G.bit.band + extract = function( v, from, width ) + return band( shr( v, from ), shl( 1, width ) - 1 ) + end + elseif _G._VERSION == "Lua 5.1" then + extract = function( v, from, width ) + local w = 0 + local flag = 2^from + for i = 0, width-1 do + local flag2 = flag + flag + if v % flag2 >= flag then + w = w + 2^i + end + flag = flag2 + end + return w + end + else -- Lua 5.3+ + extract = load[[return function( v, from, width ) + return ( v >> from ) & ((1 << width) - 1) + end]]() + end +end + + +function base64.makeencoder( s62, s63, spad ) + local encoder = {} + for b64code, char in pairs{[0]='A','B','C','D','E','F','G','H','I','J', + 'K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y', + 'Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n', + 'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2', + '3','4','5','6','7','8','9',s62 or '+',s63 or'/',spad or'='} do + encoder[b64code] = char:byte() + end + return encoder +end + +function base64.makedecoder( s62, s63, spad ) + local decoder = {} + for b64code, charcode in pairs( base64.makeencoder( s62, s63, spad )) do + decoder[charcode] = b64code + end + return decoder +end + +local DEFAULT_ENCODER = base64.makeencoder() +local DEFAULT_DECODER = base64.makedecoder() + +local char, concat = string.char, table.concat + +function base64.encode( str, encoder, usecaching ) + encoder = encoder or DEFAULT_ENCODER + local t, k, n = {}, 1, #str + local lastn = n % 3 + local cache = {} + for i = 1, n-lastn, 3 do + local a, b, c = str:byte( i, i+2 ) + local v = a*0x10000 + b*0x100 + c + local s + if usecaching then + s = cache[v] + if not s then + s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)]) + cache[v] = s + end + else + s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)]) + end + t[k] = s + k = k + 1 + end + if lastn == 2 then + local a, b = str:byte( n-1, n ) + local v = a*0x10000 + b*0x100 + t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[64]) + elseif lastn == 1 then + local v = str:byte( n )*0x10000 + t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[64], encoder[64]) + end + return concat( t ) +end + +function base64.decode( b64, decoder, usecaching ) + decoder = decoder or DEFAULT_DECODER + local pattern = '[^%w%+%/%=]' + if decoder then + local s62, s63 + for charcode, b64code in pairs( decoder ) do + if b64code == 62 then s62 = charcode + elseif b64code == 63 then s63 = charcode + end + end + pattern = ('[^%%w%%%s%%%s%%=]'):format( char(s62), char(s63) ) + end + b64 = b64:gsub( pattern, '' ) + local cache = usecaching and {} + local t, k = {}, 1 + local n = #b64 + local padding = b64:sub(-2) == '==' and 2 or b64:sub(-1) == '=' and 1 or 0 + for i = 1, padding > 0 and n-4 or n, 4 do + local a, b, c, d = b64:byte( i, i+3 ) + local s + if usecaching then + local v0 = a*0x1000000 + b*0x10000 + c*0x100 + d + s = cache[v0] + if not s then + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d] + s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8)) + cache[v0] = s + end + else + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d] + s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8)) + end + t[k] = s + k = k + 1 + end + if padding == 1 then + local a, b, c = b64:byte( n-3, n-1 ) + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + t[k] = char( extract(v,16,8), extract(v,8,8)) + elseif padding == 2 then + local a, b = b64:byte( n-3, n-2 ) + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + t[k] = char( extract(v,16,8)) + end + return concat( t ) +end + +return base64 + +--[[ +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2018 Ilya Kolbin +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +--]] diff --git a/Data/DefaultContent/Libraries/lbase64/bench.lua b/Data/DefaultContent/Libraries/lbase64/bench.lua new file mode 100644 index 0000000..d24c1bf --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/bench.lua @@ -0,0 +1,76 @@ +local base64 = require'base64' +local N = 10000000 +local st = {} +local letters = ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' + .. 'абвгдеёжзийклмнопрстуфхцшщчъыьэюя' + .. 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦШЩЧЪЫЬЭЮЯ' +local nletters = #letters +for i = 1, N do + local j = math.random( nletters ) + st[i] = letters:sub( j, j ) +end +local s = table.concat( st ) +local t = os.clock() +local encoded = base64.encode( s ) +local encodetime = os.clock() - t + +t = os.clock() +local decoded = base64.decode( encoded ) +local decodetime = os.clock() - t + +assert( s == decoded ) +print('Common text') +print(('Encoding: %d bytes/sec'):format( math.floor(N/encodetime))) +print(('Decoding: %d bytes/sec'):format( math.floor(N/decodetime))) +collectgarbage() + +t = os.clock() +encoded = base64.encode( s, nil, true ) +encodetime = os.clock() - t + +t = os.clock() +decoded = base64.decode( encoded, nil, true ) +assert( s == decoded ) +decodetime = os.clock() - t +print('Common text (cache)') +print(('Encoding: %d bytes/sec'):format( math.floor(N/encodetime))) +print(('Decoding: %d bytes/sec'):format( math.floor(N/decodetime))) +collectgarbage() + +local lt = {} +for i = 0, 255 do + lt[i] = string.char(i) +end +nletters = #lt +for i = 1, N do + local j = math.random( nletters ) + st[i] = lt[j] +end +s = table.concat( st ) + +t = os.clock() +encoded = base64.encode( s, nil ) +encodetime = os.clock() - t + +t = os.clock() +decoded = base64.decode( encoded ) +decodetime = os.clock() - t + +assert( s == decoded ) +print('Binary') +print(('Encoding: %d bytes/sec'):format( math.floor(N/encodetime))) +print(('Decoding: %d bytes/sec'):format( math.floor(N/decodetime))) +collectgarbage() + +t = os.clock() +encoded = base64.encode( s, nil, true ) +encodetime = os.clock() - t + +t = os.clock() +decoded = base64.decode( encoded, nil, true ) +assert( s == decoded ) +decodetime = os.clock() - t +print('Binary (cache)') +print(('Encoding: %d bytes/sec'):format( math.floor(N/encodetime))) +print(('Decoding: %d bytes/sec'):format( math.floor(N/decodetime))) +collectgarbage() diff --git a/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-1.rockspec b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-1.rockspec new file mode 100644 index 0000000..f25c7b4 --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-1.rockspec @@ -0,0 +1,20 @@ +package = "base64" +version = "1.5-1" +source = { + url = "git+https://github.com/iskolbin/lbase64", + tag = "v1.5.1", +} +description = { + summary = "Pure Lua base64 encoder/decoder", + detailed = [[ +Pure Lua [base64](https://en.wikipedia.org/wiki/Base64) encoder/decoder. Works with Lua 5.1+ and LuaJIT. Fallbacks to pure Lua bit operations if bit/bit32/native bit operators are not available.]], + homepage = "https://github.com/iskolbin/lbase64", + license = "MIT/Public Domain" +} +dependencies = {} +build = { + type = "builtin", + modules = { + base64 = "base64.lua", + } +} diff --git a/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-2.rockspec b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-2.rockspec new file mode 100644 index 0000000..7d0addd --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-2.rockspec @@ -0,0 +1,20 @@ +package = "base64" +version = "1.5-2" +source = { + url = "git://github.com/iskolbin/lbase64", + tag = "v1.5.2", +} +description = { + summary = "Pure Lua base64 encoder/decoder", + detailed = [[ +Pure Lua [base64](https://en.wikipedia.org/wiki/Base64) encoder/decoder. Works with Lua 5.1+ and LuaJIT. Fallbacks to pure Lua bit operations if bit/bit32/native bit operators are not available.]], + homepage = "https://github.com/iskolbin/lbase64", + license = "MIT/Public Domain" +} +dependencies = {} +build = { + type = "builtin", + modules = { + base64 = "base64.lua", + } +} diff --git a/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-3.rockspec b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-3.rockspec new file mode 100644 index 0000000..60706d3 --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-3.rockspec @@ -0,0 +1,20 @@ +package = "base64" +version = "1.5-3" +source = { + url = "git://github.com/iskolbin/lbase64", + tag = "v1.5.3", +} +description = { + summary = "Pure Lua base64 encoder/decoder", + detailed = [[ +Pure Lua base64 encoder/decoder. Works with Lua 5.1+ and LuaJIT. Fallbacks to pure Lua bit operations if bit/bit32/native bit operators are not available.]], + homepage = "https://github.com/iskolbin/lbase64", + license = "MIT/Public Domain" +} +dependencies = {} +build = { + type = "builtin", + modules = { + base64 = "base64.lua", + } +} diff --git a/Data/DefaultContent/Libraries/lbase64/test.lua b/Data/DefaultContent/Libraries/lbase64/test.lua new file mode 100644 index 0000000..d8efebf --- /dev/null +++ b/Data/DefaultContent/Libraries/lbase64/test.lua @@ -0,0 +1,47 @@ +local base64 = require('base64') + +local function test( s, b64 ) + assert( base64.encode( s ) == b64 ) + assert( base64.decode( b64 ) == s ) + assert( base64.decode( base64.encode( s )) == s ) + assert( base64.encode( s, nil, true ) == b64 ) + assert( base64.decode( b64, nil, true ) == s ) + assert( base64.decode( base64.encode( s, nil, true ), nil, true ) == s ) +end + +test( 'any carnal pleasure.', 'YW55IGNhcm5hbCBwbGVhc3VyZS4=' ) +test( 'any carnal pleasure', 'YW55IGNhcm5hbCBwbGVhc3VyZQ==' ) +test( 'any carnal pleasur', 'YW55IGNhcm5hbCBwbGVhc3Vy' ) +test( 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a ' .. + 'lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, ' .. + 'exceeds the short vehemence of any carnal pleasure.', 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb' .. + '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoY' .. + 'XQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd' .. + '2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=' ) +test( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et ' .. + 'dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea ' .. + 'commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat ' .. + 'nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit ' .. + 'anim id est laborum.', 'TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVp' .. + 'dXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBx' .. + 'dWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1' .. + 'aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0' .. + 'IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBv' .. + 'ZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==') +test( '«В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!»', + 'wqvQkiDRh9Cw0YnQsNGFINGO0LPQsCDQttC40Lsg0LHRiyDR' .. + 'htC40YLRgNGD0YE/INCU0LAsINC90L4g0YTQsNC70YzRiNC40LLRi9C5INGN0LrQt9C10LzQv9C70Y/RgCHCuw==') +test( '«В чащах юга жил бы цитрус? Да, фальшивый экземпляр!»', + 'wqvQkiDRh9Cw0YnQsNGFINGO0LPQsCDQttC40Lsg0LHRiyDRhtC' .. + '40YLRgNGD0YE/INCU0LAsINGE0LDQu9GM0YjQuNCy0YvQuSDRjdC60LfQtdC80L/Qu9GP0YAhwrs=') +test( '\137\080\078\071\013\010\026\010\000\000\000\013\073\072\068\082\000\000\000\032\000\000\000\032\001\003\000' .. + '\000\000\073\180\232\183\000\000\000\006\080\076\084\069\255\255\255\000\000\000\085\194\211\126\000\000\000\018' .. + '\073\068\065\084\008\215\099\248\015\004\196\016\084\006\196\218\011\000\237\189\063\193\243\000\141\059\000\000' .. + '\000\000\073\069\078\068\174\066\096\130', 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQMAAABJtOi3AAAABlBMVEX///8AAABVwtN+' .. + 'AAAAEklEQVQI12P4DwTEEFQGxNoLAO29P8HzAI07AAAAAElFTkSuQmCC' ) + +assert( base64.decode('YW55IGNhcm5hbCBwbGVhc3VyZS4=\n\r\\' ) == 'any carnal pleasure.' ) + +assert( base64.decode('wйqеvнQсуkкiеDнRгhш9щCзwх0ъфYыnвQаsпNрGоFллIдNжGэOё0яLчPQsCDQttC40Lsg0LHRiyDRhtC' .. + '40YLRgNGD0YE/INсCмUи0тLьAбsюIЙКNЕG\n\n\n\n\r\rE0LDQu9GM0YjQuNCy0YvQuSDRjdC60LfQtdC80L/Qu9GP0YAhwrs=') == + '«В чащах юга жил бы цитрус? Да, фальшивый экземпляр!»' ) diff --git a/Data/DefaultContent/Libraries/lua-csv/.gitignore b/Data/DefaultContent/Libraries/lua-csv/.gitignore new file mode 100644 index 0000000..131f9b6 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +lua/docs \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/lua-csv/AUTHORS b/Data/DefaultContent/Libraries/lua-csv/AUTHORS new file mode 100644 index 0000000..84961bd --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/AUTHORS @@ -0,0 +1,2 @@ +Leyland, Geoff +Martin, Kevin diff --git a/Data/DefaultContent/Libraries/lua-csv/LICENSE b/Data/DefaultContent/Libraries/lua-csv/LICENSE new file mode 100644 index 0000000..d8472a0 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013-2014 Incremental IP Limited +Copyright (c) 2014 Kevin Martin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + diff --git a/Data/DefaultContent/Libraries/lua-csv/README.md b/Data/DefaultContent/Libraries/lua-csv/README.md new file mode 100644 index 0000000..d10314a --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/README.md @@ -0,0 +1,93 @@ +# Lua-CSV - delimited file reading + +## 1. What? + +Lua-CSV is a Lua module for reading delimited text files (popularly CSV and +tab-separated files, but you can specify the separator). + +Lua-CSV tries to auto-detect whether a file is delimited with commas or tabs, +copes with non-native newlines, survives newlines and quotes inside quoted +fields and offers an iterator interface so it can handle large files. + + +## 2. How? + + local csv = require("csv") + local f = csv.open("file.csv") + for fields in f:lines() do + for i, v in ipairs(fields) do print(i, v) end + end + +`csv.open` takes a second argument `parameters`, a table of parameters +controlling how the file is read: + ++ `separator` sets the separator. It'll probably guess the separator + correctly if it's a comma or a tab (unless, say, the first field in a + tab-delimited file contains a comma), but if you want something else you'll + have to set this. It could be more than one character, but it's used as + part of a set: `"["..sep.."\n\r]"` + ++ Set `header` to true if the file contains a header and each set of fields + will be keyed by the names in the header rather than by integer index. + ++ `columns` provides a mechanism for column remapping. + Suppose you have a csv file as follows: + + Word,Number + ONE,10 + + And columns is: + + + `{ word = true }` then the only field in the file would be + `{ word = "ONE" }` + + `{ first = { name = "word"} }` then it would be `{ first = "ONE" }` + + `{ word = { transform = string.lower }}` would give `{ word = "one" }` + + finally, + + { word = true + number = { transform = function(x) return tonumber(x) / 10 end }} + + would give `{ word = "ONE", number = 1 }` + + A column can have more than one name: + `{ first = { names = {"word", "worm"}}}` to help cope with badly specified + file formats and spelling mistakes. + ++ `buffer_size` controls the size of the blocks the file is read in. The + default is 1MB. It used to be 4096 bytes which is what `pagesize` says on + my system, but that seems kind of small. + +`csv.openstring` works exactly like `csv.open` except the first argument +is the contents of the csv file. In this case `buffer_size` is set to +the length of the string. + +## 3. Requirements + +Lua 5.1, 5.2 or LuaJIT. + + +## 4. Issues + ++ Some whitespace-delimited files might use more than one space between + fields, for example if the columns are "manually" aligned: + + street nr city + "Oneway Street" 1 Toontown + + It won't cope with this - you'll get lots of extra empty fields. + +## 5. Wishlist + ++ Tests would be nice. ++ So would better LDoc documentation. + + +## 6. Alternatives + ++ [Penlight](http://github.com/stevedonovan/penlight) contains delimited + file reading. It reads the whole file in one go. ++ The Lua Wiki contains two pages on CSV + [here](http://lua-users.org/wiki/LuaCsv) and + [here](http://lua-users.org/wiki/CsvUtils). ++ There's an example using [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/) + to parse CSV [here](http://www.inf.puc-rio.br/~roberto/lpeg/#CSV) diff --git a/Data/DefaultContent/Libraries/lua-csv/lua/config.ld b/Data/DefaultContent/Libraries/lua-csv/lua/config.ld new file mode 100644 index 0000000..af51949 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/lua/config.ld @@ -0,0 +1,4 @@ +project = "Lua-CSV" +title = "Lua-CSV Source Documentation" +description = "Lua-CSV reads delimited text files" +format = "markdown" diff --git a/Data/DefaultContent/Libraries/lua-csv/lua/csv.lua b/Data/DefaultContent/Libraries/lua-csv/lua/csv.lua new file mode 100644 index 0000000..64196c0 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/lua/csv.lua @@ -0,0 +1,557 @@ +--- Read a comma or tab (or other delimiter) separated file. +-- This version of a CSV reader differs from others I've seen in that it +-- +-- + handles embedded newlines in fields (if they're delimited with double +-- quotes) +-- + is line-ending agnostic +-- + reads the file line-by-line, so it can potientially handle large +-- files. +-- +-- Of course, for such a simple format, CSV is horribly complicated, so it +-- likely gets something wrong. + +-- (c) Copyright 2013-2014 Incremental IP Limited. +-- (c) Copyright 2014 Kevin Martin +-- Available under the MIT licence. See LICENSE for more information. + +local DEFAULT_BUFFER_BLOCK_SIZE = 1024 * 1024 + + +------------------------------------------------------------------------------ + +local function trim_space(s) + return s:match("^%s*(.-)%s*$") +end + + +local function fix_quotes(s) + -- the sub(..., -2) is to strip the trailing quote + return string.sub(s:gsub('""', '"'), 1, -2) +end + + +------------------------------------------------------------------------------ + +local column_map = {} +column_map.__index = column_map + + +local function normalise_string(s) + return (s:lower():gsub("[^%w%d]+", " "):gsub("^ *(.-) *$", "%1")) +end + + +--- Parse a list of columns. +-- The main job here is normalising column names and dealing with columns +-- for which we have more than one possible name in the header. +function column_map:new(columns) + local name_map = {} + for n, v in pairs(columns) do + local names + local t + if type(v) == "table" then + t = { transform = v.transform, default = v.default } + if v.name then + names = { normalise_string(v.name) } + elseif v.names then + names = v.names + for i, n in ipairs(names) do names[i] = normalise_string(n) end + end + else + if type(v) == "function" then + t = { transform = v } + else + t = {} + if type(v) == "string" then + names = { normalise_string(v) } + end + end + end + + if not names then + names = { (n:lower():gsub("[^%w%d]+", " ")) } + end + + t.name = n + for _, n in ipairs(names) do + name_map[n:lower()] = t + end + end + + return setmetatable({ name_map = name_map }, column_map) +end + + +--- Map "virtual" columns to file columns. +-- Once we've read the header, work out which columns we're interested in and +-- what to do with them. Mostly this is about checking we've got the columns +-- we need and writing a nice complaint if we haven't. +function column_map:read_header(header) + local index_map = {} + + -- Match the columns in the file to the columns in the name map + local found = {} + local found_any + for i, word in ipairs(header) do + word = normalise_string(word) + local r = self.name_map[word] + if r then + index_map[i] = r + found[r.name] = true + found_any = true + end + end + + if not found_any then return end + + -- check we found all the columns we need + local not_found = {} + for name, r in pairs(self.name_map) do + if not found[r.name] then + local nf = not_found[r.name] + if nf then + nf[#nf+1] = name + else + not_found[r.name] = { name } + end + end + end + -- If any columns are missing, assemble an error message + if next(not_found) then + local problems = {} + for k, v in pairs(not_found) do + local missing + if #v == 1 then + missing = "'"..v[1].."'" + else + missing = v[1] + for i = 2, #v - 1 do + missing = missing..", '"..v[i].."'" + end + missing = missing.." or '"..v[#v].."'" + end + problems[#problems+1] = "Couldn't find a column named "..missing + end + error(table.concat(problems, "\n"), 0) + end + + self.index_map = index_map + return true +end + + +function column_map:transform(value, index) + local field = self.index_map[index] + if field then + if field.transform then + local ok + ok, value = pcall(field.transform, value) + if not ok then + error(("Error reading field '%s': %s"):format(field.name, value), 0) + end + end + return value or field.default, field.name + end +end + + +------------------------------------------------------------------------------ + +local file_buffer = {} +file_buffer.__index = file_buffer + +function file_buffer:new(file, buffer_block_size) + return setmetatable({ + file = file, + buffer_block_size = buffer_block_size or DEFAULT_BUFFER_BLOCK_SIZE, + buffer_start = 0, + buffer = "", + }, file_buffer) +end + + +--- Cut the front off the buffer if we've already read it +function file_buffer:truncate(p) + p = p - self.buffer_start + if p > self.buffer_block_size then + local remove = self.buffer_block_size * + math.floor((p-1) / self.buffer_block_size) + self.buffer = self.buffer:sub(remove + 1) + self.buffer_start = self.buffer_start + remove + end +end + + +--- Find something in the buffer, extending it if necessary +function file_buffer:find(pattern, init) + while true do + local first, last, capture = + self.buffer:find(pattern, init - self.buffer_start) + -- if we found nothing, or the last character is at the end of the + -- buffer (and the match could potentially be longer) then read some + -- more. + if not first or last == #self.buffer then + local s = self.file:read(self.buffer_block_size) + if not s then + if not first then + return + else + return first + self.buffer_start, last + self.buffer_start, capture + end + end + self.buffer = self.buffer..s + else + return first + self.buffer_start, last + self.buffer_start, capture + end + end +end + + +--- Extend the buffer so we can see more +function file_buffer:extend(offset) + local extra = offset - #self.buffer - self.buffer_start + if extra > 0 then + local size = self.buffer_block_size * + math.ceil(extra / self.buffer_block_size) + local s = self.file:read(size) + if not s then return end + self.buffer = self.buffer..s + end +end + + +--- Get a substring from the buffer, extending it if necessary +function file_buffer:sub(a, b) + self:extend(b) + b = b == -1 and b or b - self.buffer_start + return self.buffer:sub(a - self.buffer_start, b) +end + + +--- Close a file buffer +function file_buffer:close() + self.file:close() + self.file = nil +end + + +------------------------------------------------------------------------------ + +local separator_candidates = { ",", "\t", "|" } +local guess_separator_params = { record_limit = 8; } + + +local function try_separator(buffer, sep, f) + guess_separator_params.separator = sep + local min, max = math.huge, 0 + local lines, split_lines = 0, 0 + local iterator = coroutine.wrap(function() f(buffer, guess_separator_params) end) + for t in iterator do + min = math.min(min, #t) + max = math.max(max, #t) + split_lines = split_lines + (t[2] and 1 or 0) + lines = lines + 1 + end + if split_lines / lines > 0.75 then + return max - min + else + return math.huge + end +end + + +--- If the user hasn't specified a separator, try to work out what it is. +function guess_separator(buffer, f) + local best_separator, lowest_diff = "", math.huge + for _, s in ipairs(separator_candidates) do + local ok, diff = pcall(function() return try_separator(buffer, s, f) end) + if ok and diff < lowest_diff then + best_separator = s + lowest_diff = diff + end + end + + return best_separator +end + + +local unicode_BOMS = +{ + { + length = 2, + BOMS = + { + ["\254\255"] = true, -- UTF-16 big-endian + ["\255\254"] = true, -- UTF-16 little-endian + } + }, + { + length = 3, + BOMS = + { + ["\239\187\191"] = true, -- UTF-8 + } + } +} + + +local function find_unicode_BOM(sub) + for _, x in ipairs(unicode_BOMS) do + local code = sub(1, x.length) + if x.BOMS[code] then + return x.length + end + end + return 0 +end + + +--- Iterate through the records in a file +-- Since records might be more than one line (if there's a newline in quotes) +-- and line-endings might not be native, we read the file in chunks of +-- we read the file in chunks using a file_buffer, rather than line-by-line +-- using io.lines. +local function separated_values_iterator(buffer, parameters) + local field_start = 1 + + local advance + if buffer.truncate then + advance = function(n) + field_start = field_start + n + buffer:truncate(field_start) + end + else + advance = function(n) + field_start = field_start + n + end + end + + + local function field_sub(a, b) + b = b == -1 and b or b + field_start - 1 + return buffer:sub(a + field_start - 1, b) + end + + + local function field_find(pattern, init) + init = init or 1 + local f, l, c = buffer:find(pattern, init + field_start - 1) + if not f then return end + return f - field_start + 1, l - field_start + 1, c + end + + + -- Is there some kind of Unicode BOM here? + advance(find_unicode_BOM(field_sub)) + + + -- Start reading the file + local sep = "(["..(parameters.separator or + guess_separator(buffer, separated_values_iterator)).."\n\r])" + local line_start = 1 + local line = 1 + local field_count, fields, starts, nonblanks = 0, {}, {} + local header, header_read + local field_start_line, field_start_column + local record_count = 0 + + + local function problem(message) + error(("%s:%d:%d: %s"): + format(parameters.filename, field_start_line, field_start_column, + message), 0) + end + + + while true do + local field_end, sep_end, this_sep + local tidy + field_start_line = line + field_start_column = field_start - line_start + 1 + + -- If the field is quoted, go find the other quote + if field_sub(1, 1) == '"' then + advance(1) + local current_pos = 0 + repeat + local a, b, c = field_find('"("?)', current_pos + 1) + current_pos = b + until c ~= '"' + if not current_pos then problem("unmatched quote") end + tidy = fix_quotes + field_end, sep_end, this_sep = field_find(" *([^ ])", current_pos+1) + if this_sep and not this_sep:match(sep) then problem("unmatched quote") end + else + field_end, sep_end, this_sep = field_find(sep, 1) + tidy = trim_space + end + + -- Look for the separator or a newline or the end of the file + field_end = (field_end or 0) - 1 + + -- Read the field, then convert all the line endings to \n, and + -- count any embedded line endings + local value = field_sub(1, field_end) + value = value:gsub("\r\n", "\n"):gsub("\r", "\n") + for nl in value:gmatch("\n()") do + line = line + 1 + line_start = nl + field_start + end + + value = tidy(value) + if #value > 0 then nonblanks = true end + field_count = field_count + 1 + + -- Insert the value into the table for this "line" + local key + if parameters.column_map and header_read then + local ok + ok, value, key = pcall(parameters.column_map.transform, + parameters.column_map, value, field_count) + if not ok then problem(value) end + elseif header then + key = header[field_count] + else + key = field_count + end + if key then + fields[key] = value + starts[key] = { line=field_start_line, column=field_start_column } + end + + -- if we ended on a newline then yield the fields on this line. + if not this_sep or this_sep == "\r" or this_sep == "\n" then + if parameters.column_map and not header_read then + header_read = parameters.column_map:read_header(fields) + elseif parameters.header and not header_read then + if nonblanks or field_count > 1 then -- ignore blank lines + header = fields + header_read = true + end + else + if nonblanks or field_count > 1 then -- ignore blank lines + coroutine.yield(fields, starts) + record_count = record_count + 1 + if parameters.record_limit and + record_count >= parameters.record_limit then + break + end + end + end + field_count, fields, starts, nonblanks = 0, {}, {} + end + + -- If we *really* didn't find a separator then we're done. + if not sep_end then break end + + -- If we ended on a newline then count it. + if this_sep == "\r" or this_sep == "\n" then + if this_sep == "\r" and field_sub(sep_end+1, sep_end+1) == "\n" then + sep_end = sep_end + 1 + end + line = line + 1 + line_start = field_start + sep_end + end + + advance(sep_end) + end +end + + +------------------------------------------------------------------------------ + +local buffer_mt = +{ + lines = function(t) + return coroutine.wrap(function() + separated_values_iterator(t.buffer, t.parameters) + end) + end, + close = function(t) + if t.buffer.close then t.buffer:close() end + end, + name = function(t) + return t.parameters.filename + end, +} +buffer_mt.__index = buffer_mt + + +--- Use an existing file or buffer as a stream to read csv from. +-- (A buffer is just something that looks like a string in that we can do +-- `buffer:sub()` and `buffer:find()`) +-- @return a file object +local function use( + buffer, -- ?string|file|buffer: the buffer to read from. If it's: + -- - a string, read from that; + -- - a file, turn it into a file_buffer; + -- - nil, read from stdin + -- otherwise assume it's already a a buffer. + parameters) -- ?table: parameters controlling reading the file. + -- See README.md + parameters = parameters or {} + parameters.filename = parameters.filename or "" + parameters.column_map = parameters.columns and + column_map:new(parameters.columns) + + if not buffer then + buffer = file_buffer:new(io.stdin) + elseif io.type(buffer) == "file" then + buffer = file_buffer:new(buffer) + end + + local f = { buffer = buffer, parameters = parameters } + return setmetatable(f, buffer_mt) +end + + +------------------------------------------------------------------------------ + +--- Open a file for reading as a delimited file +-- @return a file object +local function open( + filename, -- string: name of the file to open + parameters) -- ?table: parameters controlling reading the file. + -- See README.md + local file, message = io.open(filename, "r") + if not file then return nil, message end + + parameters = parameters or {} + parameters.filename = filename + return use(file_buffer:new(file), parameters) +end + + +------------------------------------------------------------------------------ + +local function makename(s) + local t = {} + t[#t+1] = "<(String) " + t[#t+1] = (s:gmatch("[^\n]+")() or ""):sub(1,15) + if #t[#t] > 14 then t[#t+1] = "..." end + t[#t+1] = " >" + return table.concat(t) +end + + +--- Open a string for reading as a delimited file +-- @return a file object +local function openstring( + filecontents, -- string: The contents of the delimited file + parameters) -- ?table: parameters controlling reading the file. + -- See README.md + + parameters = parameters or {} + + + parameters.filename = parameters.filename or makename(filecontents) + parameters.buffer_size = parameters.buffer_size or #filecontents + return use(filecontents, parameters) +end + + +------------------------------------------------------------------------------ + +return { open = open, openstring = openstring, use = use } + +------------------------------------------------------------------------------ diff --git a/Data/DefaultContent/Libraries/lua-csv/lua/test.lua b/Data/DefaultContent/Libraries/lua-csv/lua/test.lua new file mode 100644 index 0000000..f418cf6 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/lua/test.lua @@ -0,0 +1,102 @@ +pcall(require, "strict") +local csv = require"csv" + +local errors = 0 + +local function testhandle(handle, correct_result) + local result = {} + for r in handle:lines() do + if not r[1] then + local r2 = {} + for k, v in pairs(r) do r2[#r2+1] = k..":"..tostring(v) end + table.sort(r2) + r = r2 + end + result[#result+1] = table.concat(r, ",") + end + + handle:close() + + result = table.concat(result, "!\n").."!" + if result ~= correct_result then + io.stderr:write( + ("Error reading '%s':\nExpected output:\n%s\n\nActual output:\n%s\n\n"): + format(handle:name(), correct_result, result)) + errors = errors + 1 + return false + end + return true +end + +local function test(filename, correct_result, parameters) + parameters = parameters or {} + for i = 1, 16 do + parameters.buffer_size = i + local f = csv.open(filename, parameters) + local fileok = testhandle(f, correct_result) + + if fileok then + f = io.open(filename, "r") + local data = f:read("*a") + f:close() + + f = csv.openstring(data, parameters) + testhandle(f, correct_result) + end + end +end + +test("../test-data/embedded-newlines.csv", [[ +embedded +newline,embedded +newline,embedded +newline! +embedded +newline,embedded +newline,embedded +newline!]]) + +test("../test-data/embedded-quotes.csv", [[ +embedded "quotes",embedded "quotes",embedded "quotes"! +embedded "quotes",embedded "quotes",embedded "quotes"!]]) + +test("../test-data/header.csv", [[ +alpha:ONE,bravo:two,charlie:3! +alpha:four,bravo:five,charlie:6!]], {header=true}) + +test("../test-data/header.csv", [[ +apple:one,charlie:30! +apple:four,charlie:60!]], +{ columns = { + apple = { name = "ALPHA", transform = string.lower }, + charlie = { transform = function(x) return tonumber(x) * 10 end }}}) + +test("../test-data/blank-line.csv", [[ +this,file,ends,with,a,blank,line!]]) + +test("../test-data/BOM.csv", [[ +apple:one,charlie:30! +apple:four,charlie:60!]], +{ columns = { + apple = { name = "ALPHA", transform = string.lower }, + charlie = { transform = function(x) return tonumber(x) * 10 end }}}) + +test("../test-data/bars.txt", [[ +there's a comma in this field, but no newline,embedded +newline,embedded +newline! +embedded +newline,embedded +newline,embedded +newline!]]) + + +if errors == 0 then + io.stdout:write("Passed\n") +elseif errors == 1 then + io.stdout:write("1 error\n") +else + io.stdout:write(("%d errors\n"):format(errors)) +end + +os.exit(errors) diff --git a/Data/DefaultContent/Libraries/lua-csv/makefile b/Data/DefaultContent/Libraries/lua-csv/makefile new file mode 100644 index 0000000..dfa7596 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/makefile @@ -0,0 +1,14 @@ +LUA= $(shell echo `which lua`) +LUA_BINDIR= $(shell echo `dirname $(LUA)`) +LUA_PREFIX= $(shell echo `dirname $(LUA_BINDIR)`) +LUA_VERSION = $(shell echo `lua -v 2>&1 | cut -d " " -f 2 | cut -b 1-3`) +LUA_SHAREDIR=$(LUA_PREFIX)/share/lua/$(LUA_VERSION) + +default: + @echo "Nothing to build. Try 'make install' or 'make test'." + +install: + cp lua/csv.lua $(LUA_SHAREDIR) + +test: + cd lua && $(LUA) test.lua diff --git a/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-1-1.rockspec b/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-1-1.rockspec new file mode 100644 index 0000000..6f280aa --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-1-1.rockspec @@ -0,0 +1,24 @@ +package = "csv" +version = "1-1" +source = +{ + url = "git://github.com/geoffleyland/lua-csv.git", + branch = "master", + tag = "v1", +} +description = +{ + summary = "CSV and other delimited file reading", + homepage = "http://github.com/geoffleyland/lua-csv", + license = "MIT/X11", + maintainer = "Geoff Leyland " +} +dependencies = { "lua >= 5.1" } +build = +{ + type = "builtin", + modules = + { + csv = "lua/csv.lua", + }, +} diff --git a/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-scm-1.rockspec b/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-scm-1.rockspec new file mode 100644 index 0000000..29629da --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-scm-1.rockspec @@ -0,0 +1,23 @@ +package = "csv" +version = "scm-1" +source = +{ + url = "git://github.com/geoffleyland/lua-csv.git", + branch = "master", +} +description = +{ + summary = "CSV and other delimited file reading", + homepage = "http://github.com/geoffleyland/lua-csv", + license = "MIT/X11", + maintainer = "Geoff Leyland " +} +dependencies = { "lua >= 5.1" } +build = +{ + type = "builtin", + modules = + { + csv = "lua/csv.lua", + }, +} diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/BOM.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/BOM.csv new file mode 100644 index 0000000..9787c0d --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/test-data/BOM.csv @@ -0,0 +1,3 @@ +alpha,bravo,charlie +ONE,two,3 +four,five,6 \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/bars.txt b/Data/DefaultContent/Libraries/lua-csv/test-data/bars.txt new file mode 100644 index 0000000..9decabc --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/test-data/bars.txt @@ -0,0 +1,7 @@ +there's a comma in this field, but no newline|"embedded +newline"|"embedded +newline" +"embedded +newline"|"embedded +newline"|"embedded +newline" \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/blank-line.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/blank-line.csv new file mode 100644 index 0000000..63fc515 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/test-data/blank-line.csv @@ -0,0 +1,2 @@ +this,file,ends,with,a,blank,line + diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-newlines.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-newlines.csv new file mode 100644 index 0000000..67987d1 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-newlines.csv @@ -0,0 +1,8 @@ +"embedded +newline","embedded +newline","embedded +newline" +"embedded +newline","embedded +newline","embedded +newline" \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-quotes.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-quotes.csv new file mode 100644 index 0000000..e0c5c73 --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-quotes.csv @@ -0,0 +1,2 @@ +"embedded ""quotes""","embedded ""quotes""","embedded ""quotes""" +"embedded ""quotes""","embedded ""quotes""","embedded ""quotes""" \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/header.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/header.csv new file mode 100644 index 0000000..89f702e --- /dev/null +++ b/Data/DefaultContent/Libraries/lua-csv/test-data/header.csv @@ -0,0 +1,3 @@ +alpha,bravo,charlie +ONE,two,3 +four,five,6 \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/luafun/.gitignore b/Data/DefaultContent/Libraries/luafun/.gitignore new file mode 100644 index 0000000..0ebe4e1 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/.gitignore @@ -0,0 +1,4 @@ +*~ +temp/ +fun.lua.c +5.?-fun/ diff --git a/Data/DefaultContent/Libraries/luafun/.travis.yml b/Data/DefaultContent/Libraries/luafun/.travis.yml new file mode 100644 index 0000000..2c3f4d8 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/.travis.yml @@ -0,0 +1,74 @@ +sudo: false +language: C +services: + - docker + +env: + global: + - PRODUCT=lua-fun + matrix: + - OS=el DIST=7 + - OS=fedora DIST=24 + - OS=fedora DIST=25 + - OS=ubuntu DIST=xenial + - OS=ubuntu DIST=yakkety + - OS=debian DIST=stretch + +before_deploy: + - git clone https://github.com/packpack/packpack.git packpack + - ./packpack/packpack + +deploy: + provider: packagecloud + username: ${PACKAGECLOUD_USER} + repository: ${PACKAGECLOUD_REPO} + token: ${PACKAGECLOUD_TOKEN} + dist: ${OS}/${DIST} + package_glob: build/*.{deb,rpm} + skip_cleanup: true + on: + branch: master + condition: -n "${OS}" && -n "${DIST}" && -n "${PACKAGECLOUD_TOKEN}" + +after_deploy: + # Prune old packages from PackageCloud, keep only the last two + - pip install -r ./packpack/tools/requirements.txt + - python ./packpack/tools/packagecloud prune ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO} deb ${OS} ${DIST} --keep 2 + - python ./packpack/tools/packagecloud prune ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO} rpm ${OS} ${DIST} --keep 2 + +cache: + directories: + - $HOME/lua-5.3.2 + +addons: + apt: + packages: + - lua5.1 + - lua5.2 + - luajit + +# Ubuntu Precise on Travis doesn't have lua5.3 package +install: + - | + [ -e ${HOME}/lua-5.3.2/src/lua ] || (\ + wget http://www.lua.org/ftp/lua-5.3.2.tar.gz -c && \ + tar xzf lua-5.3.2.tar.gz -C ${HOME} && \ + make -j -C ${HOME}/lua-5.3.2 linux \ + ) + +script: + - cd tests + - LUAJIT=`echo /usr/bin/luajit* | cut -f 1 -d ' '` + - ${LUAJIT} -v + - ${LUAJIT} runtest *.lua + - lua5.1 -v + - lua5.1 runtest *.lua + - lua5.2 -v + - lua5.2 runtest *.lua + - LUA53=${HOME}/lua-5.3.2/src/lua + - ${LUA53} -v + - ${LUA53} runtest *.lua + - cd .. + +notifications: + email: true diff --git a/Data/DefaultContent/Libraries/luafun/CONTRIBUTING.md b/Data/DefaultContent/Libraries/luafun/CONTRIBUTING.md new file mode 100644 index 0000000..660ec53 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/CONTRIBUTING.md @@ -0,0 +1,20 @@ +Contributing +============ + +We'd love for you to contribute to the project and make **Lua Fun** even better +than it is today! + +Filling Issues +--------------- + +Please file bugs reports and feature requests using [GitHub Issues]. + +[GitHub Issues]: https://github.com/luafun/luafun/issues + +Making Changes +-------------- + +If you want to contribute code, please fork the project on [GitHub], make +changes in branch and send a pull request. + +[GitHub]: https://github.com/luafun/luafun diff --git a/Data/DefaultContent/Libraries/luafun/COPYING.md b/Data/DefaultContent/Libraries/luafun/COPYING.md new file mode 100644 index 0000000..c945d62 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/COPYING.md @@ -0,0 +1,27 @@ +Copying +======= + +**Lua Fun** source codes, logo and documentation are distributed under the +**[MIT/X11 License]** - same as Lua and LuaJIT. + +Copyright (c) 2013-2017 Roman Tsisyk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +[MIT/X11 License]: http://www.opensource.org/licenses/mit-license.php diff --git a/Data/DefaultContent/Libraries/luafun/README.md b/Data/DefaultContent/Libraries/luafun/README.md new file mode 100644 index 0000000..c7a2d61 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/README.md @@ -0,0 +1,107 @@ +Lua Functional +============== + + + +**Lua Fun** is a high-performance functional programming library for [Lua] +designed with [LuaJIT's trace compiler][LuaJIT] in mind. + +Lua Fun provides a set of more than 50 programming primitives typically +found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and +even Lisp. High-order functions such as ``map``, ``filter``, ``reduce``, +``zip``, etc., make it easy to **write simple and efficient functional code**. + +Let's see an example: + + > -- Functional style + > require "fun" () + > -- calculate sum(x for x^2 in 1..n) + > n = 100 + > print(reduce(operator.add, 0, map(function(x) return x^2 end, range(n)))) + 328350 + + > -- Object-oriented style + > local fun = require "fun" + > -- calculate sum(x for x^2 in 1..n) + > print(fun.range(n):map(function(x) return x^2 end):reduce(operator.add, 0)) + 328350 + +**Lua Fun** takes full advantage of the innovative **tracing JIT compiler** +to achieve transcendental performance on nested functional expressions. +Functional compositions and high-order functions can be translated into +**efficient machine code**. Can you believe it? Just try to run the example +above with ``luajit -jdump`` and see what happens: + + -- skip some initilization code -- + ->LOOP: + 0bcaffd0 movaps xmm5, xmm7 + 0bcaffd3 movaps xmm7, xmm1 + 0bcaffd6 addsd xmm7, xmm5 + 0bcaffda ucomisd xmm7, xmm0 + 0bcaffde jnb 0x0bca0024 ->5 + 0bcaffe4 movaps xmm5, xmm7 + 0bcaffe7 mulsd xmm5, xmm5 + 0bcaffeb addsd xmm6, xmm5 + 0bcaffef jmp 0x0bcaffd0 ->LOOP + ---- TRACE 1 stop -> loop + +The functional chain above was translated by LuaJIT to (!) **one machine loop** +containing just 10 CPU assembly instructions without CALL. Unbelievable! + +Readable? Efficient? Can your Python/Ruby/V8 do better? + +Status +------ + +**Lua Fun** is in an early alpha stage. The library fully [documented] +[Documentation] and covered with unit tests. + +[![Build Status](https://travis-ci.org/luafun/luafun.png)] +(https://travis-ci.org/luafun/luafun) + +LuaJIT 2.1 alpha is recommended. The library designed in mind of fact that +[LuaJIT traces tail-, up- and down-recursion][LuaJIT-Recursion] and has a lot of +[byte code optimizations][LuaJIT-Optimizations]. Lua 5.1-5.3 are also +supported. + +This is **master** (development) branch. API may be changed without any special +notice. Please use **stable** branch for your production deployments. +If you still want to use **master**, please don't forget to grep `git log` +for *Incompatible API changes* message. Thanks! + +Please check out [documentation][Documentation] for more information. + +Misc +---- + +**Lua Fun** is distributed under the [MIT/X11 License] - +(same as Lua and LuaJIT). + +The library was written to use with [Tarantool] - an efficient in-memory +store and an asynchronous Lua application server. + +See Also +-------- + +* [Documentation] +* [RockSpec] +* [RPM/DEB packages](https://packagecloud.io/rtsisyk/master) +* lua-l@lists.lua.org +* luajit@freelists.org +* roman@tsisyk.com + + [Lua]: http://www.lua.org/ + [LuaJIT]: http://luajit.org/luajit.html + [LuaJIT-Recursion]: http://lambda-the-ultimate.org/node/3851#comment-57679 + [LuaJIT-Optimizations]: http://wiki.luajit.org/Optimizations + [MIT/X11 License]: http://opensource.org/licenses/MIT + [Tarantool]: http://github.com/tarantool/tarantool + [Getting Started]: https://luafun.github.io/getting_started.html + [Documentation]: http://luafun.github.io/ + [RockSpec]: https://raw.github.com/luafun/luafun/master/fun-scm-1.rockspec + +Please **"Star"** the project on GitHub to help it to survive! Thanks! + +***** + +**Lua Fun**. Simple, Efficient and Functional. In Lua. With JIT. diff --git a/Data/DefaultContent/Libraries/luafun/debian/.gitignore b/Data/DefaultContent/Libraries/luafun/debian/.gitignore new file mode 100644 index 0000000..aa3e6bf --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/.gitignore @@ -0,0 +1,8 @@ +lua-fun/ +tmp/ +trash +files +lua_versions +*.install +*.substvars +*.log diff --git a/Data/DefaultContent/Libraries/luafun/debian/changelog b/Data/DefaultContent/Libraries/luafun/debian/changelog new file mode 100644 index 0000000..262c02d --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/changelog @@ -0,0 +1,5 @@ +lua-fun (0.1.3-1) unstable; urgency=medium + + * Initial release. (Closes: #811482) + + -- Roman Tsisyk Mon, 18 Jan 2016 10:00:00 +0300 diff --git a/Data/DefaultContent/Libraries/luafun/debian/compat b/Data/DefaultContent/Libraries/luafun/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/compat @@ -0,0 +1 @@ +9 diff --git a/Data/DefaultContent/Libraries/luafun/debian/control b/Data/DefaultContent/Libraries/luafun/debian/control new file mode 100644 index 0000000..f93b318 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/control @@ -0,0 +1,20 @@ +Source: lua-fun +Section: interpreters +Priority: optional +Maintainer: Roman Tsisyk +Build-Depends: debhelper (>= 9), dh-lua (>= 19) +Standards-Version: 3.9.6 +Homepage: https://github.com/luafun/luafun +Vcs-Git: git://github.com/luafun/luafun.git +Vcs-Browser: https://github.com/luafun/luafun + +Package: lua-fun +Architecture: all +Depends: ${misc:Depends} +Provides: ${lua:Provides} +XB-Lua-Versions: ${lua:Versions} +Description: High-performance functional programming library for Lua + Lua Fun provides a set of more than 50 programming primitives typically + found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and + even Lisp. High-order functions such as map, filter, reduce, zip, etc., + make it easy to write simple and efficient functional code. diff --git a/Data/DefaultContent/Libraries/luafun/debian/copyright b/Data/DefaultContent/Libraries/luafun/debian/copyright new file mode 100644 index 0000000..34f24ad --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/copyright @@ -0,0 +1,31 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: luafun +Upstream-Contact: Roman Tsisyk +Source: https://github.com/luafun/luafun + +Files: * +Copyright: 2013-2017 Roman Tsisyk +Comment: In the Lua community this license is better known as "MIT". + Unfortunately other variants of this license are also known as "MIT". + To obtain a machine intepretable copyright file Debian prefers to name this + version of the MIT license using the non ambiguous term "Expat". +License: Expat + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + “Software”), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + . + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/Data/DefaultContent/Libraries/luafun/debian/lua-fun.docs b/Data/DefaultContent/Libraries/luafun/debian/lua-fun.docs new file mode 100644 index 0000000..b43bf86 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/lua-fun.docs @@ -0,0 +1 @@ +README.md diff --git a/Data/DefaultContent/Libraries/luafun/debian/lua5.1.dh-lua.conf b/Data/DefaultContent/Libraries/luafun/debian/lua5.1.dh-lua.conf new file mode 100644 index 0000000..fa57bb6 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/lua5.1.dh-lua.conf @@ -0,0 +1,4 @@ +PKG_NAME=fun +LUA_MODNAME=fun +LUA_SOURCES=fun.lua +LUA_TEST=tests/runtest tests/*.lua diff --git a/Data/DefaultContent/Libraries/luafun/debian/lua5.2.dh-lua.conf b/Data/DefaultContent/Libraries/luafun/debian/lua5.2.dh-lua.conf new file mode 100644 index 0000000..ba875b6 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/lua5.2.dh-lua.conf @@ -0,0 +1 @@ +lua5.1.dh-lua.conf \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/luafun/debian/lua5.3.dh-lua.conf b/Data/DefaultContent/Libraries/luafun/debian/lua5.3.dh-lua.conf new file mode 100644 index 0000000..ba875b6 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/lua5.3.dh-lua.conf @@ -0,0 +1 @@ +lua5.1.dh-lua.conf \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/luafun/debian/patches/series b/Data/DefaultContent/Libraries/luafun/debian/patches/series new file mode 100644 index 0000000..e69de29 diff --git a/Data/DefaultContent/Libraries/luafun/debian/rules b/Data/DefaultContent/Libraries/luafun/debian/rules new file mode 100644 index 0000000..9e473ed --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/rules @@ -0,0 +1,12 @@ +#!/usr/bin/make -f + +VERSION := $(shell dpkg-parsechangelog|grep ^Version|awk '{print $$2}') +UVERSION := $(shell echo $(VERSION)|sed 's/-[[:digit:]]\+$$//') + +%: + dh $@ --buildsystem=lua --with lua + +tarball: clean + tar --exclude=.git --exclude=debian --exclude rpm \ + --transform='s,^\.,luafun-$(UVERSION),S' \ + -czf ../luafun-$(UVERSION).orig.tar.gz . diff --git a/Data/DefaultContent/Libraries/luafun/debian/source/format b/Data/DefaultContent/Libraries/luafun/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/Data/DefaultContent/Libraries/luafun/debian/watch b/Data/DefaultContent/Libraries/luafun/debian/watch new file mode 100644 index 0000000..40bc2ca --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/debian/watch @@ -0,0 +1,6 @@ +# test this watch file using: +# uscan --watchfile debian/watch --upstream-version 0.0.1 --package lua-fun +# https://wiki.debian.org/debian/watch#GitHub +version=3 +opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/luafun-$1\.tar\.gz/ \ + https://github.com/luafun/luafun/tags .*/v?(\d\S*)\.tar\.gz diff --git a/Data/DefaultContent/Libraries/luafun/doc/.gitignore b/Data/DefaultContent/Libraries/luafun/doc/.gitignore new file mode 100644 index 0000000..e35d885 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/.gitignore @@ -0,0 +1 @@ +_build diff --git a/Data/DefaultContent/Libraries/luafun/doc/Makefile b/Data/DefaultContent/Libraries/luafun/doc/Makefile new file mode 100644 index 0000000..1e1b049 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/LuaFunctional.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/LuaFunctional.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/LuaFunctional" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/LuaFunctional" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/Data/DefaultContent/Libraries/luafun/doc/_static/.keep b/Data/DefaultContent/Libraries/luafun/doc/_static/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Data/DefaultContent/Libraries/luafun/doc/_templates/layout.html b/Data/DefaultContent/Libraries/luafun/doc/_templates/layout.html new file mode 100644 index 0000000..ee1fa29 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/_templates/layout.html @@ -0,0 +1,14 @@ +{% extends "!layout.html" %} + +{% block footer %} +{{ super() }} + +{% endblock %} diff --git a/Data/DefaultContent/Libraries/luafun/doc/about.rst b/Data/DefaultContent/Libraries/luafun/doc/about.rst new file mode 100644 index 0000000..97da8dc --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/about.rst @@ -0,0 +1,42 @@ +About +===== + +Credits +------- + +An initial prototype was designed and enginered in one evening by Roman Tsisyk. +After that the library was completely rewritten, tested and documented +(which took a while). + +The project exists only thanks to the excellent tracing just-in-time compiler +in `LuaJIT `_. + +The library works best with `Tarantool `_ -- +an efficient in-memory database and Lua application server. + +Copying +------- + +Lua Fun source codes, logo and documentation are distributed under the +`MIT License (MIT) `_ -- +same as LuaJIT. + +Copyright (c) 2013-2017 Roman Tsisyk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Data/DefaultContent/Libraries/luafun/doc/basic.rst b/Data/DefaultContent/Libraries/luafun/doc/basic.rst new file mode 100644 index 0000000..346dd78 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/basic.rst @@ -0,0 +1,141 @@ +Basic Functions +=============== + +.. module:: fun + +The section contains functions to create iterators from Lua objects. + +.. function:: iter(array) + iter(map) + iter(string) + iter(gen, param, state) + + :returns: ``gen, param, state`` -- :ref:`iterator triplet ` + + Make ``gen, param, state`` iterator from the iterable object. + The function is a generalized version of :func:`pairs` and :func:`ipairs`. + + The function distinguish between arrays and maps using ``#arg == 0`` + check to detect maps. For arrays ``ipairs`` is used. For maps a modified + version of ``pairs`` is used that also returns keys. Userdata objects + are handled in the same way as tables. + + If ``LUAJIT_ENABLE_LUA52COMPAT`` [#luajit_lua52compat]_ mode is enabled and + argument has metamethods ``__pairs`` (for maps) or ``__ipairs`` for (arrays), + call it with the table or userdata as argument and return the first three + results from the call [#lua52_ipairs]_. + + All library iterator are suitable to use with Lua's ``for .. in`` loop. + + .. code-block:: lua + + > for _it, a in iter({1, 2, 3}) do print(a) end + 1 + 2 + 3 + + > for _it, k, v in iter({ a = 1, b = 2, c = 3}) do print(k, v) end + b 2 + a 1 + c 3 + + > for _it, a in iter("abcde") do print(a) end + a + b + c + d + e + + The first cycle variable *_it* is needed to store an internal state of + the iterator. The value must be always ignored in loops: + + .. code-block:: lua + + for _it, a, b in iter({ a = 1, b = 2, c = 3}) do print(a, b) end + -- _it is some internal iterator state - always ignore it + -- a, b are values return from the iterator + + Simple iterators like ``iter({1, 2, 3})`` have simple states, whereas + other iterators like :func:`zip` or :func:`chain` have complicated + internal states which values senseless for the end user. + + Check out :doc:`under_the_hood` section for more details. + + There is also the possibility to supply custom iterators to the + function: + + .. code-block:: lua + + > local function mypairs_gen(max, state) + if (state >= max) then + return nil + end + return state + 1, state + 1 + end + + > local function mypairs(max) + return mypairs_gen, max, 0 + end + + > for _it, a in iter(mypairs(10)) do print(a) end + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + + Iterators can return multiple values. + + Check out :doc:`under_the_hood` section for more details. + + .. [#luajit_lua52compat] http://luajit.org/extensions.html + .. [#lua52_ipairs] http://www.lua.org/manual/5.2/manual.html#pdf-ipairs + +.. function:: each(fun, gen, param, state) + iterator:each(fun) + + :returns: none + + Execute the *fun* for each iteration value. The function is equivalent to + the code below: + + .. code-block:: lua + + for _it, ... in iter(gen, param, state) do + fun(...) + end + + Examples: + + .. code-block:: lua + + > each(print, { a = 1, b = 2, c = 3}) + b 2 + a 1 + c 3 + + > each(print, {1, 2, 3}) + 1 + 2 + 3 + + The function is used for its side effects. Implementation directly applies + *fun* to all iteration values without returning a new iterator, in contrast + to functions like :func:`map`. + + .. seealso:: :func:`map`, :func:`reduce` + +.. function:: for_each(fun, gen, param, state) + iterator:for_each(fun) + + An alias for :func:`each`. + +.. function:: foreach(fun, gen, param, state) + iterator:foreach(fun) + + An alias for :func:`each`. diff --git a/Data/DefaultContent/Libraries/luafun/doc/compositions.rst b/Data/DefaultContent/Libraries/luafun/doc/compositions.rst new file mode 100644 index 0000000..4c789b3 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/compositions.rst @@ -0,0 +1,140 @@ +Compositions +============ + +.. module:: fun + +.. function:: zip(...) + iterator1:zip(iterator2, iterator3, ...) + + :param ...: iterators to "zip" + :type ...: iterator + + :returns: an iterator + + Return a new iterator where i-th return value contains the i-th element + from each of the iterators. The returned iterator is truncated in length + to the length of the shortest iterator. For multi-return iterators only the + first variable is used. + + Examples: + + .. code-block:: lua + + > dump(zip({"a", "b", "c", "d"}, {"one", "two", "three"})) + a one + b two + c three + + > each(print, zip()) + + > each(print, zip(range(5), {'a', 'b', 'c'}, rands())) + 1 a 0.57514179487402 + 2 b 0.79693061238668 + 3 c 0.45174307459403 + + > each(print, zip(partition(function(x) return x > 7 end, range(1, 15, 1)))) + 8 1 + 9 2 + 10 3 + 11 4 + 12 5 + 13 6 + 14 7 + +.. function:: cycle(gen, param, state) + iterator:cycle() + + :returns: a cycled version of ``{gen, param, state}`` iterator + + Make a new iterator that returns elements from ``{gen, param, state}`` + iterator until the end and then "restart" iteration using a saved clone of + ``{gen, param, state}``. The returned iterator is constant space and no + return values are buffered. Instead of that the function make a clone of the + source ``{gen, param, state}`` iterator. Therefore, the source iterator + must be pure functional to make an indentical clone. Infinity iterators + are supported, but are not recommended. + + .. note:: ``{gen, param, state}`` must be pure functional to work properly + with the function. + + Examples: + + .. code-block:: lua + + > each(print, take(15, cycle(range(5)))) + 1 + 2 + 3 + 4 + 5 + 1 + 2 + 3 + 4 + 5 + 1 + 2 + 3 + 4 + 5 + + > each(print, take(15, cycle(zip(range(5), {"a", "b", "c", "d", "e"})))) + 1 a + 2 b + 3 c + 4 d + 5 e + 1 a + 2 b + 3 c + 4 d + 5 e + 1 a + 2 b + 3 c + 4 d + 5 e + +.. function:: chain(...) + iterator1:chain(iterator2, iterator3, ...) + + :param ...: iterators to chain + :type ...: iterator + :returns: a consecutive iterator from sources (left from right) + + Make an iterator that returns elements from the first iterator until it is + exhausted, then proceeds to the next iterator, until all of the iterators + are exhausted. Used for treating consecutive iterators as a single iterator. + Infinity iterators are supported, but are not recommended. + + Examples: + + .. code-block:: lua + + > each(print, chain(range(2), {"a", "b", "c"}, {"one", "two", "three"})) + 1 + 2 + a + b + c + one + two + three + + > each(print, take(15, cycle(chain(enumerate({"a", "b", "c"}), + {"one", "two", "three"})))) + 1 a + 2 b + 3 c + one + two + three + 1 a + 2 b + 3 c + one + two + three + 1 a + 2 b + 3 c diff --git a/Data/DefaultContent/Libraries/luafun/doc/conf.py b/Data/DefaultContent/Libraries/luafun/doc/conf.py new file mode 100644 index 0000000..ce36bbf --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/conf.py @@ -0,0 +1,247 @@ +# -*- coding: utf-8 -*- +# +# Lua Functional documentation build configuration file, created by +# sphinx-quickstart on Sat Nov 9 14:21:28 2013. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +#extensions = [ "redjack.sphinx.lua" ] + +# The documentation primary domain is lua +#primary_domain = "lua" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Lua Functional' +copyright = u'2013-2017, Roman Tsisyk' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1' +# The full version, including alpha/beta/rc tags. +release = '0.1.3' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'haiku' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = { + #"full_logo": False, +#} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = "logo.png" + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +#htmlhelp_basename = 'LuaFunctionaldoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +#latex_documents = [ + #('index', 'LuaFunctional.tex', u'Lua Functional Documentation', + #u'Roman Tsisyk', 'manual'), +#] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'luafun', u'Lua Functional Documentation', + [u'Roman Tsisyk'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +#texinfo_documents = [ + #('index', 'LuaFunctional', u'Lua Functional Documentation', + #u'Roman Tsisyk', 'LuaFunctional', 'One line description of project.', + #'Miscellaneous'), +#] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff --git a/Data/DefaultContent/Libraries/luafun/doc/filtering.rst b/Data/DefaultContent/Libraries/luafun/doc/filtering.rst new file mode 100644 index 0000000..2852f6c --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/filtering.rst @@ -0,0 +1,121 @@ +Filtering +========= + +.. module:: fun + +This section contains functions to filter values during iteration. + +.. function:: filter(predicate, gen, param, state) + iterator:filter(predicate) + + :param param: an predicate to filter the iterator + :type param: (function(...) -> bool) + + Return a new iterator of those elements that satisfy the **predicate**. + + Examples: + + .. code-block:: lua + + > each(print, filter(function(x) return x % 3 == 0 end, range(10))) + 3 + 6 + 9 + + > each(print, take(5, filter(function(i, x) return i % 3 == 0 end, + enumerate(duplicate('x'))))) + 3 x + 6 x + 9 x + 12 x + 15 x + + .. note:: Multireturn iterators are supported but can cause performance + regressions. + + .. seealso:: :func:`take_while` and :func:`drop_while`. + +.. function:: remove_if(predicate, gen, param, state) + iterator:remove_if(predicate) + + An alias for :func:`filter`. + +.. function:: grep(regexp_or_predicate, gen, param, state) + iterator:grep(regexp_or_predicate) + + If **regexp_or_predicate** is string then the parameter is used as a regular + expression to build filtering predicate. Otherwise the function is just an + alias for :func:`filter`. + + Equivalent to: + + .. code-block:: lua + + local fun = regexp_or_predicate + if type(regexp_or_predicate) == "string" then + fun = function(x) return string.find(x, regexp_or_predicate) ~= nil end + end + return filter(fun, gen, param, state) + + Examples: + + .. code-block:: lua + + lines_to_grep = { + [[Emily]], + [[Chloe]], + [[Megan]], + [[Jessica]], + [[Emma]], + [[Sarah]], + [[Elizabeth]], + [[Sophie]], + [[Olivia]], + [[Lauren]] + } + + each(print, grep("^Em", lines_to_grep)) + --[[test + Emily + Emma + --test]] + + each(print, grep("^P", lines_to_grep)) + --[[test + --test]] + + > each(print, grep(function(x) return x % 3 == 0 end, range(10))) + 3 + 6 + 9 + +.. function:: partition(predicate, gen, param, state) + iterator:partition(predicate) + + :param x: a value to find + :returns: {gen1, param1, state1}, {gen2, param2, state2} + + The function returns two iterators where elements do and do not satisfy the + prediucate. Equivalent to: + + .. code-block:: lua + + return filter(predicate, gen', param', state'), + filter(function(...) return not predicate(...) end, gen, param, state); + + The function make a clone of the source iterator. Iterators especially + returned in tables to work with :func:`zip` and other functions. + + Examples: + + .. code-block:: lua + + > each(print, zip(partition(function(i, x) return i % 3 == 0 end, range(10)))) + 3 1 + 6 2 + 9 4 + + .. note:: ``gen, param, state`` must be pure functional to work properly + with the function. + + .. seealso:: :func:`span` diff --git a/Data/DefaultContent/Libraries/luafun/doc/generators.rst b/Data/DefaultContent/Libraries/luafun/doc/generators.rst new file mode 100644 index 0000000..7132d47 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/generators.rst @@ -0,0 +1,233 @@ +Generators +========== + +.. module:: fun + +This section contains a number of useful generators modeled after Standard ML, +Haskell, Python, Ruby, JavaScript and other languages. + +Finite Generators +----------------- + +.. function:: range([start,] stop[, step]) + + :param start: an endpoint of the interval (see below) + :type start: number + :param stop: an endpoint of the interval (see below) + :type stop: number + :param step: a step + :type step: number + + :returns: an iterator + + The iterator to create arithmetic progressions. Iteration values are generated + within closed interval ``[start, stop]`` (i.e. *stop* is included). + If the *start* argument is omitted, it defaults to ``1`` (*stop* > 0) or + to ``-1`` (*stop* < 0). If the *step* argument is omitted, it defaults to + ``1`` (*start* <= *stop*) or to ``-1`` (*start* > *stop*). If *step* is + positive, the last element is the largest ``start + i * step`` less than or + equal to *stop*; if *step* is negative, the last element is the smallest + ``start + i * step`` greater than or equal to *stop*. + *step* must not be zero (or else an error is raised). + ``range(0)`` returns empty iterator. + + Examples: + + .. code-block:: lua + + > for _it, v in range(5) do print(v) end + 1 + 2 + 3 + 4 + 5 + > for _it, v in range(-5) do print(v) end + -1 + -2 + -3 + -4 + -5 + > for _it, v in range(1, 6) do print(v) end + 1 + 2 + 3 + 4 + 5 + 6 + > for _it, v in range(0, 20, 5) do print(v) end + 0 + 5 + 10 + 15 + 20 + > for _it, v in range(0, 10, 3) do print(v) end + 0 + 3 + 6 + 9 + > for _it, v in range(0, 1.5, 0.2) do print(v) end + 0 + 0.2 + 0.4 + 0.6 + 0.8 + 1 + 1.2 + 1.4 + > for _it, v in range(0) do print(v) end + > for _it, v in range(1) do print(v) end + 1 + > for _it, v in range(1, 0) do print(v) end + 1 + 0 + > for _it, v in range(0, 10, 0) do print(v) end + error: step must not be zero + +Infinity Generators +------------------- + +.. function:: duplicate(...) + + :param ...: objects to duplicate + :type ...: non nil + :returns: an iterator + + The iterator returns values over and over again indefinitely. All values + that passed to the iterator are returned as-is during the iteration. + + Examples: + + .. code-block:: lua + + > each(print, take(3, duplicate('a', 'b', 'c'))) + a b c + a b c + > each(print, take(3, duplicate('x'))) + x + x + x + > for _it, a, b, c, d, e in take(3, duplicate(1, 2, 'a', 3, 'b')) do + print(a, b, c, d, e) + >> end + 1 2 a 3 b + 1 2 a 3 b + 1 2 a 3 b + +.. function:: xrepeat(...) + + An alias for :func:`duplicate`. + +.. function:: replicate(...) + + An alias for :func:`duplicate`. + +.. function:: tabulate(fun) + + :param fun: an unary generating function + :type fun: function(n: uint) -> ... + :returns: an iterator + + The iterator that returns ``fun(0)``, ``fun(1)``, ``fun(2)``, ``...`` values + indefinitely. + + Examples: + + .. code-block:: lua + + > each(print, take(5, tabulate(function(x) return 'a', 'b', 2*x end))) + a b 0 + a b 2 + a b 4 + a b 6 + a b 8 + > each(print, take(5, tabulate(function(x) return x^2 end))) + 0 + 1 + 4 + 9 + 16 + +.. function:: zeros() + + :returns: an iterator + + The iterator returns ``0`` indefinitely. + + Examples: + + .. code-block:: lua + + > each(print, take(5, zeros())) + 0 + 0 + 0 + 0 + 0 + +.. function:: ones() + + :returns: an iterator + + The iterator that returns ``1`` indefinitely. + + Example:: + + > each(print, take(5, ones())) + 1 + 1 + 1 + 1 + 1 + +Random sampling +--------------- + +.. function:: rands([n[, m]]) + + :param n: an endpoint of the interval (see below) + :type n: uint + :param m: an endpoint of the interval (see below) + :type m: uint + :returns: an iterator + + The iterator returns random values using :func:`math.random`. + If the **n** and **m** are set then the iterator returns pseudo-random + integers in the ``[n, m)`` interval (i.e. **m** is not included). + If the **m** is not set then the iterator generates pseudo-random integers + in the ``[0, n)`` interval. When called without arguments returns + pseudo-random real numbers with uniform distribution in the + interval ``[0, 1)``. + + .. warning:: This iterator is not pure-functional and may not work as + expected with some library functions. + + Examples: + + .. code-block:: lua + + > each(print, take(10, rands(10, 20))) + 19 + 17 + 11 + 19 + 12 + 13 + 14 + 16 + 10 + 11 + + > each(print, take(5, rands(10))) + 7 + 6 + 5 + 9 + 0 + + > each(print, take(5, rands())) + 0.79420629243124 + 0.69885246563716 + 0.5901037417281 + 0.7532286166836 + 0.080971251199854 + diff --git a/Data/DefaultContent/Libraries/luafun/doc/getting_started.rst b/Data/DefaultContent/Libraries/luafun/doc/getting_started.rst new file mode 100644 index 0000000..9a9e3de --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/getting_started.rst @@ -0,0 +1,254 @@ +Getting Started +=============== + +Please jump to `Using the Library`_ section if you are familiar with Lua and +LuaJIT. + +.. contents:: + +Prerequisites +------------- + +The library is designed for LuaJIT_. **LuaJIT 2.1 alpha** is high^W **Highly** +recommended for performance reasons. Lua 5.1--5.3 are also supported. + +The library is platform-independent and expected to work on all platforms that +supported by Lua(JIT). It can be also used in any Lua(JIT) based applications, +e.g. Tarantool_ or OpenResty_. + +You might need diff_ tool to run test system and sphinx_ to regenerate the +documentation from source files. + +.. _LuaJIT: http://luajit.org/ +.. _Tarantool: http://tarantool.org/ +.. _OpenResty: http://openresty.org/ +.. _diff: http://en.wikipedia.org/wiki/Diff +.. _sphinx: http://sphinx-doc.org/ + +Installing LuaJIT +----------------- + +You can build LuaJIT from sources or install it from a binary archive. + +From Sources +```````````` + +1. Clone LuaJIT git repository. Please note that **v2.1** branch is needed. +You can always select this branch using ``git checkout v2.1``. + +.. code-block:: bash + + $ git clone http://luajit.org/git/luajit-2.0.git -b v2.1 luajit-2.1 + Cloning into 'luajit-2.1'... + +2. Compile LuaJIT + +.. code-block:: bash + + $ cd luajit-2.1/ + luajit-2.1 $ make -j8 + +3. Install LuaJIT + +.. code-block:: bash + + luajit-2.1 $ make install + luajit-2.1 $ ln -s /usr/local/bin/luajit-2.1.0-alpha /usr/local/bin/luajit + +Install operation might require root permissions. However, you can install +LuaJIT into your home directory. + +From a Binary Archive +````````````````````` + +If operations above look too complicated for you, you always can download a +binary archive from http://luajit.org/download.html page. +Your favorite package manager may also have LuaJIT packages. + +Running LuaJIT +`````````````` + +Ensure that freshly installed LuaJIT works: + +.. code-block:: bash + + $ luajit + LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/ + JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse + > = 2 + 2 + 4 + +It is good idea to use LuaJIT CLI under ``rlwrap`` (on nix platforms): + +.. code-block:: bash + + alias luajit="rlwrap luajit" + $ luajit + LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/ + JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse + > = 2 + 2 + 4 + > = 2 + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Data/DefaultContent/Libraries/luafun/doc/make.bat b/Data/DefaultContent/Libraries/luafun/doc/make.bat new file mode 100644 index 0000000..0f68e89 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/make.bat @@ -0,0 +1,190 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\LuaFunctional.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\LuaFunctional.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/Data/DefaultContent/Libraries/luafun/doc/operators.rst b/Data/DefaultContent/Libraries/luafun/doc/operators.rst new file mode 100644 index 0000000..2f3edd4 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/operators.rst @@ -0,0 +1,203 @@ +Operators +========= + +.. module:: fun.operator + +This auxiliary module exports a set of Lua operators as intrinsic functions +to use with the library high-order primitives. + +.. contents:: + +.. note:: **op** can be used as a shortcut to **operator**. + +Comparison operators +-------------------- + +.. seealso:: `Lua Relational Operators + `_ + +.. function:: le(a, b) + + :returns: **a** <= **b** + +.. function:: lt(a, b) + + :returns: **a** < **b** + +.. function:: eq(a, b) + + :returns: **a** == **b** + +.. function:: ne(a, b) + + :returns: **a** ~= **b** + +.. function:: ge(a, b) + + :returns: **a** >= **b** + +.. function:: gt(a, b) + + :returns: **a** > **b** + +Arithmetic operators +-------------------- + +.. seealso:: `Lua Arithmetic Operators + `_ + +.. function:: add(a, b) + + :returns: **a** + **b** + +.. function:: div(a, b) + + An alias for :func:`truediv`. + +.. function:: truediv(a, b) + + :returns: **a** / **b** + + Performs "true" float division. + Examples: + + .. code-block:: lua + + > print(operator.div(10, 3)) + 3.3333333333333 + > print(operator.div(-10, 3)) + -3.3333333333333 + +.. function:: floordiv(a, b) + + :returns: math.floor(**a** / **b**) + + Performs division where a result is rounded down. Examples: + + .. code-block:: lua + + > print(operator.floordiv(10, 3)) + 3 + > print(operator.floordiv(12, 3)) + 4 + > print(operator.floordiv(-10, 3)) + -4 + > print(operator.floordiv(-12, 3)) + -4 + +.. function:: intdiv(a, b) + + Performs C-like integer division. + + Equvalent to: + + .. code-block:: lua + + function(a, b) + local q = a / b + if a >= 0 then return math.floor(q) else return math.ceil(q) end + end + + Examples: + + .. code-block:: lua + + > print(operator.floordiv(10, 3)) + 3 + > print(operator.floordiv(12, 3)) + 4 + > print(operator.floordiv(-10, 3)) + -3 + > print(operator.floordiv(-12, 3)) + -4 + +.. function:: mod(a, b) + + :returns: **a** % **b** + + .. note:: Result has same sign as **divisor**. Modulo in Lua is defined as + ``a % b == a - math.floor(a/b)*b``. + + Examples: + + .. code-block:: lua + :emphasize-lines: 5-6 + + > print(operator.mod(10, 2)) + 0 + > print(operator.mod(10, 3)) + 2 + print(operator.mod(-10, 3)) + 2 -- == -1 in C, Java, JavaScript and but not in Lua, Python, Haskell! + +.. function:: neq(a) + + :returns: -**a** + +.. function:: unm(a) + + Unary minus. An alias for :func:`neq`. + +.. function:: pow(a, b) + + :returns: math.pow(**a**, **b**) + +.. function:: sub(a, b) + + :returns: **a** - **b** + +String operators +---------------- + +.. seealso:: `Lua Concatenation Operator + `_ + +.. function:: concat(a, b) + + :returns: **a** .. **b** + +.. function:: len(a) + + :returns: # **a** + +.. function:: length(a) + + An alias for :func:`len`. + +Logical operators +----------------- + +.. seealso:: `Lua Logical Operators + `_ + +.. function:: land(a, b) + + :returns: **a** and **b** + +.. function:: lor(a, b) + + :returns: **a** or **b** + +.. function:: lnot(a) + + :returns: not **a** + +.. function:: truth(a) + + :returns: not not **a** + + Return ``true`` if **a** is true, and ``false`` otherwise. Examples: + + .. code-block:: lua + + > print(operator.truth(1)) + true + > print(operator.truth(0)) + true -- It is Lua, baby! + > print(operator.truth(nil)) + false + > print(operator.truth("")) + true + > print(operator.truth({})) + true + diff --git a/Data/DefaultContent/Libraries/luafun/doc/reducing.rst b/Data/DefaultContent/Libraries/luafun/doc/reducing.rst new file mode 100644 index 0000000..f7b89da --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/reducing.rst @@ -0,0 +1,323 @@ +Reducing +======== + +.. module:: fun + +The section contains functions to analyze iteration values and recombine +through use of a given combining operation the results of recursively processing +its constituent parts, building up a return value + +.. contents:: + +.. note:: An attempt to use infinity iterators with the most function from + the module causes an infinite loop. + +Folds +----- + +.. function:: foldl(accfun, initval, gen, param, state) + iterator:reduce(accfun, initval) + + :param accfun: an accumulating function + :type param: (function(prevval, ...) -> val) + :param initval: an initial value that passed to **accfun** on the first + iteration + + The function reduces the iterator from left to right using the binary + operator **accfun** and the initial value **initval**. + Equivalent to:: + + local val = initval + for _k, ... in gen, param, state do + val = accfun(val, ...) + end + return val + + Examples: + + .. code-block:: lua + + > print(foldl(function(acc, x) return acc + x end, 0, range(5))) + 15 + + > print(foldl(operator.add, 0, range(5))) + 15 + + > print(foldl(function(acc, x, y) return acc + x * y; end, 0, + zip(range(1, 5), {4, 3, 2, 1}))) + 20 + +.. function:: reduce(accfun, initval, gen, param, state) + iterator:reduce(accfun, initval) + + An alias to :func:`foldl`. + +.. function:: length(gen, param, state) + iterator:length() + + :returns: a number of elements in ``gen, param, state`` iterator. + + Return a number of elements in ``gen, param, state`` iterator. + This function is equivalent to ``#obj`` for basic array and string iterators. + + Examples: + + .. code-block:: lua + + > print(length({"a", "b", "c", "d", "e"})) + 5 + + > print(length({})) + 0 + + > print(length(range(0))) + 0 + + .. warning:: An attempt to call this function on an infinite iterator will + result an infinite loop. + + .. note:: This function has ``O(n)`` complexity for all iterators except + basic array and string iterators. + +.. function:: totable(gen, param, state) + + :returns: a new table (array) from iterated values. + + The function reduces the iterator from left to right using ``table.insert``. + + Examples: + + .. code-block:: lua + + > local tab = totable("abcdef") + > print(type(tab), #tab) + table 6 + > each(print, tab) + a + b + c + d + e + f + +.. function:: tomap(gen, param, state) + + :returns: a new table (map) from iterated values. + + The function reduces the iterator from left to right using + ``tab[val1] = val2`` expression. + + Examples: + + .. code-block:: lua + + > local tab = tomap(zip(range(1, 7), 'abcdef')) + > print(type(tab), #tab) + table 6 + > each(print, iter(tab)) + a + b + c + d + e + f + +Predicates +---------- + +.. function:: is_prefix_of(iterator1, iterator2) + iterator1:is_prefix_of(iterator2) + + The function takes two iterators and returns ``true`` if the first iterator + is a prefix of the second. + + Examples: + + .. code-block:: lua + + > print(is_prefix_of({"a"}, {"a", "b", "c"})) + true + + > print(is_prefix_of(range(6), range(5))) + false + +.. function:: is_null(gen, param, state) + iterator:is_null() + + :returns: true when `gen, param, state`` iterator is empty or finished. + :returns: false otherwise. + + Example:: + + > print(is_null({"a", "b", "c", "d", "e"})) + false + + > print(is_null({})) + true + + > print(is_null(range(0))) + true + +.. function:: all(predicate, gen, param, state) + iterator:all(predicate) + + :param predicate: a predicate + + Returns true if all return values of iterator satisfy the **predicate**. + + Examples: + + .. code-block:: lua + + > print(all(function(x) return x end, {true, true, true, true})) + true + + > print(all(function(x) return x end, {true, true, true, false})) + false + +.. function:: every(predicate, gen, param, state) + + An alias for :func:`all`. + +.. function:: any(predicate, gen, param, state) + iterator:any(predicate) + + :param predicate: a predicate + + Returns ``true`` if at least one return values of iterator satisfy the + **predicate**. The iteration stops on the first such value. Therefore, + infinity iterators that have at least one satisfying value might work. + + Examples: + + .. code-block:: lua + + > print(any(function(x) return x end, {false, false, false, false})) + false + + > print(any(function(x) return x end, {false, false, false, true})) + true + +.. function:: some(predicate, gen, param, state) + + An alias for :func:`any`. + +Special folds +------------- + +.. function:: sum(gen, param, state) + iterator:sum() + + Sum up all iteration values. An optimized alias for:: + + foldl(operator.add, 0, gen, param, state) + + For an empty iterator ``0`` is returned. + + Examples: + + .. code-block:: lua + + > print(sum(range(5))) + 15 + +.. function:: product(gen, param, state) + iterator:product() + + Multiply all iteration values. An optimized alias for:: + + foldl(operator.mul, 1, gen, param, state) + + For an empty iterator ``1`` is returned. + + Examples: + + .. code-block:: lua + + > print(product(range(1, 5))) + 120 + +.. function:: min(gen, param, state) + iterator:min() + + Return a minimum value from the iterator using :func:`operator.min` or ``<`` + for numbers and other types respectivly. The iterator must be + non-null, otherwise an error is raised. + + Examples: + + .. code-block:: lua + + > print(min(range(1, 10, 1))) + 1 + + > print(min({"f", "d", "c", "d", "e"})) + c + + > print(min({})) + error: min: iterator is empty + +.. function:: minimum(gen, param, state) + + An alias for :func:`min`. + +.. function:: min_by(cmp, gen, param, state) + iterator:min_by(cmp) + + Return a minimum value from the iterator using the **cmp** as a ``<`` + operator. The iterator must be non-null, otherwise an error is raised. + + Examples: + + .. code-block:: lua + + > function min_cmp(a, b) if -a < -b then return a else return b end end + > print(min_by(min_cmp, range(1, 10, 1))) + 9 + +.. function:: minimum_by(cmp, gen, param, state) + + An alias for :func:`min_by`. + +.. function:: max(gen, param, state) + iterator:max() + + Return a maximum value from the iterator using :func:`operator.max` or ``>`` + for numbers and other types respectivly. + + The iterator must be non-null, otherwise an error is raised. + + Examples: + + .. code-block:: lua + + > print(max(range(1, 10, 1))) + 9 + + > print(max({"f", "d", "c", "d", "e"})) + f + + > print(max({})) + error: max: iterator is empty + +.. function:: maximum(gen, param, state) + + An alias for :func:`max`. + +.. function:: max_by(cmp, gen, param, state) + iterator:max_by(cmp) + + Return a maximum value from the iterator using the **cmp** as a `>` + operator. The iterator must be non-null, otherwise an error is raised. + + Examples: + + .. code-block:: lua + + > function max_cmp(a, b) if -a > -b then return a else return b end end + > print(max_by(max_cmp, range(1, 10, 1))) + 1 + +.. function:: maximum_by(cmp, gen, param, state) + + An alias for :func:`max_by`. diff --git a/Data/DefaultContent/Libraries/luafun/doc/reference.rst b/Data/DefaultContent/Libraries/luafun/doc/reference.rst new file mode 100644 index 0000000..f1f9cfc --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/reference.rst @@ -0,0 +1,14 @@ +API Reference +============= + +.. toctree:: + + basic.rst + generators.rst + slicing.rst + indexing.rst + filtering.rst + reducing.rst + transformations.rst + compositions.rst + operators.rst \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/luafun/doc/slicing.rst b/Data/DefaultContent/Libraries/luafun/doc/slicing.rst new file mode 100644 index 0000000..1af642f --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/slicing.rst @@ -0,0 +1,246 @@ +Slicing +======= + +.. module:: fun + +This section contains functions to make subsequences from iterators. + +Basic +----- + +.. function:: nth(n, gen, param, state) + iterator:nth(n) + + :param uint n: a sequential number (indexed starting from ``1``, + like Lua tables) + :returns: **n**-th element of ``gen, param, state`` iterator + + This function returns the **n**-th element of ``gen, param, state`` + iterator. If the iterator does not have **n** items then ``nil`` is returned. + + Examples: + + .. code-block:: lua + + > print(nth(2, range(5))) + 2 + + > print(nth(10, range(5))) + nil + + > print(nth(2, {"a", "b", "c", "d", "e"})) + b + + > print(nth(2, enumerate({"a", "b", "c", "d", "e"}))) + 2 b + + This function is optimized for basic array and string iterators and has + ``O(1)`` complexity for these cases. + +.. function:: head(gen, param, state) + iterator:head() + + :returns: a first element of ``gen, param, state`` iterator + + Extract the first element of ``gen, param, state`` iterator. + If the iterator is empty then an error is raised. + + Examples: + + .. code-block:: lua + + > print(head({"a", "b", "c", "d", "e"})) + a + > print(head({})) + error: head: iterator is empty + > print(head(range(0))) + error: head: iterator is empty + > print(head(enumerate({"a", "b"}))) + 1 a + +.. function:: car(gen, param, state) + + An alias for :func:`head`. + +.. function:: tail(gen, param, state) + iterator:tail() + + :returns: ``gen, param, state`` iterator without a first element + + Return a copy of ``gen, param, state`` iterator without its first element. + If the iterator is empty then an empty iterator is returned. + + Examples: + + .. code-block:: lua + + > each(print, tail({"a", "b", "c", "d", "e"})) + b + c + d + e + > each(print, tail({})) + > each(print, tail(range(0))) + > each(print, tail(enumerate({"a", "b", "c"}))) + 2 b + 3 c + +.. function:: cdr(gen, param, state) + + An alias for :func:`tail`. + +Subsequences +------------ + +.. function:: take_n(n, gen, param, state) + iterator:take_n(n) + + :param n: a number of elements to take + :type n: uint + :returns: an iterator on the subsequence of first **n** elements + + Examples: + + .. code-block:: lua + + > each(print, take_n(5, range(10))) + 1 + 2 + 3 + 4 + 5 + + > each(print, take_n(5, enumerate(duplicate('x')))) + 1 x + 2 x + 3 x + 4 x + 5 x + +.. function:: take_while(predicate, gen, param, state) + iterator:take_while(predicate) + + :type predicate: function(...) -> bool + :returns: an iterator on the longest prefix of ``gen, param, state`` + elements that satisfy **predicate**. + + Examples: + + .. code-block:: lua + + > each(print, take_while(function(x) return x < 5 end, range(10))) + 1 + 2 + 3 + 4 + + > each(print, take_while(function(i, a) return i ~=a end, + enumerate({5, 3, 4, 4, 2}))) + 1 5 + 2 3 + 3 4 + + .. seealso:: :func:`filter` + +.. function:: take(n_or_predicate, gen, param, state) + iterator:take(n_or_predicate) + + An alias for :func:`take_n` and :func:`take_while` that autodetects + required function based on **n_or_predicate** type. + +.. function:: drop_n(n, gen, param, state) + iterator:drop_n(n) + + :param n: the number of elements to drop + :type n: uint + :returns: ``gen, param, state`` iterator after skipping first **n** + elements + + Examples: + + .. code-block:: lua + + > each(print, drop_n(2, range(5))) + 3 + 4 + 5 + + > each(print, drop_n(2, enumerate({'a', 'b', 'c', 'd', 'e'}))) + 3 c + 4 d + 5 e + +.. function:: drop_while(predicate, gen, param, state) + iterator:drop_while(predicate) + + :type predicate: function(...) -> bool + :returns: ``gen, param, state`` after skipping the longest prefix + of elements that satisfy **predicate**. + + Examples: + + .. code-block:: lua + + > each(print, drop_while(function(x) return x < 5 end, range(10))) + 5 + 6 + 7 + 8 + 9 + 10 + + .. seealso:: :func:`filter` + +.. function:: drop(n_or_predicate, gen, param, state) + iterator:drop(n_or_predicate) + + An alias for :func:`drop_n` and :func:`drop_while` that autodetects + required function based on **n_or_predicate** type. + + +.. function:: span(n_or_predicate, gen, param, state) + iterator:span(n_or_predicate) + + :type n_or_predicate: function(...) -> bool or uint + :returns: iterator, iterator + + Return an iterator pair where the first operates on the longest prefix + (possibly empty) of ``gen, param, state`` iterator of elements that + satisfy **predicate** and second operates the remainder of + ``gen, param, state`` iterator. + Equivalent to: + + .. code-block:: lua + + return take(n_or_predicate, gen, param, state), + drop(n_or_predicate, gen, param, state); + + Examples: + + .. code-block:: lua + + > each(print, zip(span(function(x) return x < 5 end, range(10)))) + 1 5 + 2 6 + 3 7 + 4 8 + + > each(print, zip(span(5, range(10)))) + 1 6 + 2 7 + 3 8 + 4 9 + 5 10 + + .. note:: ``gen, param, state`` must be pure functional to work properly + with the function. + + .. seealso:: :func:`partition` + +.. function:: split(n_or_predicate, gen, param, state) + + An alias for :func:`span`. + +.. function:: split_at(n, gen, param, state) + + An alias for :func:`span`. diff --git a/Data/DefaultContent/Libraries/luafun/doc/transformations.rst b/Data/DefaultContent/Libraries/luafun/doc/transformations.rst new file mode 100644 index 0000000..e446d2f --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/transformations.rst @@ -0,0 +1,87 @@ +Transformations +=============== + +.. module:: fun + +.. function:: map(fun, gen, param, state) + iterator:map(fun) + + :param fun: a function to apply + :type fun: (function(...) -> ...) + :returns: a new iterator + + Return a new iterator by applying the **fun** to each element of + ``gen, param, state`` iterator. The mapping is performed on the fly + and no values are buffered. + + Examples: + + .. code-block:: lua + + > each(print, map(function(x) return 2 * x end, range(4))) + 2 + 4 + 6 + 8 + + fun = function(...) return 'map', ... end + > each(print, map(fun, range(4))) + map 1 + map 2 + map 3 + map 4 + +.. function:: enumerate(gen, param, state) + iterator:enumerate() + + :returns: a new iterator + + Return a new iterator by enumerating all elements of the + ``gen, param, state`` iterator starting from ``1``. The mapping is performed + on the fly and no values are buffered. + + Examples: + + .. code-block:: lua + + > each(print, enumerate({"a", "b", "c", "d", "e"})) + 1 a + 2 b + 3 c + 4 d + 5 e + + > each(print, enumerate(zip({"one", "two", "three", "four", "five"}, + {"a", "b", "c", "d", "e"}))) + 1 one a + 2 two b + 3 three c + 4 four d + 5 five e + +.. function:: intersperse(x, gen, param, state) + iterator:intersperse(x) + + :type x: any + :returns: a new iterator + + Return a new iterator where the **x** value is interspersed between the + elements of the source iterator. The **x** value can also be added as a + last element of returning iterator if the source iterator contains the odd + number of elements. + + Examples: + + .. code-block:: lua + + > each(print, intersperse("x", {"a", "b", "c", "d", "e"})) + a + x + b + x + c + x + d + x + e + x diff --git a/Data/DefaultContent/Libraries/luafun/doc/under_the_hood.rst b/Data/DefaultContent/Libraries/luafun/doc/under_the_hood.rst new file mode 100644 index 0000000..802659e --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/doc/under_the_hood.rst @@ -0,0 +1,154 @@ +Under the Hood +============== + +.. module:: fun + +The section shed some light on the internal library structure and working +principles. + +Iterators +--------- + +A basic primitive of the library after functions is an iterator. Most functions +takes an iterator and returns a new iteraror(s). Iterators all the way down! +[#iterators]_. + +The simplest iterator is (surprise!) :func:`pairs` and :func:`ipairs` +Lua functions. Have you ever tried to call, say, :func:`ipairs` function +without using it inside a ``for`` loop? Try to do that on any Lua +implementation: + +.. _iterator_triplet: +.. code-block:: bash + + > =ipairs({'a', 'b', 'c'}) + function: builtin#6 table: 0x40f80e38 0 + +The function returned three strange values which look useless without a ``for`` +loop. We call these values **iterator triplet**. +Let's see how each value is used for: + +``gen`` -- first value + A generating function that can produce a next value on each iteration. + Usually returns a new ``state`` and iteration values (multireturn). + +``param`` -- second value + A permanent (constant) parameter of a generating function is used to create + specific instance of the generating function. For example, a table itself + for ``ipairs`` case. + +``state`` -- third value + A some transient state of an iterator that is changed after each iteration. + For example, an array index for ``ipairs`` case. + +Try to call ``gen`` function manually: + + .. code-block:: lua + + > gen, param, state = ipairs({'a', 'b', 'c'}) + > =gen(param, state) + 1 a + +The ``gen`` function returned a new state ``1`` and the next iteration +value ``a``. The second call to ``gen`` with the new state will return the next +state and the next iteration value. When the iterator finishes to the end +the ``nil`` value is returned instead of the next state. + +**Please do not panic!** You do not have to use these values directly. +It is just a nice trick to get ``for .. in`` loop working in Lua. + +Iterations +---------- + +What happens when you type the following code into a Lua console:: + + for _it, x in ipairs({'a', 'b', 'c'}) do print(x) end + +According to Lua reference manual [#lua_for]_ the code above is equivalent to:: + + do + -- Initialize the iterator + local gen, param, state = ipairs({'a', 'b', 'c'}) + while true do + -- Next iteration + local state, var_1, ···, var_n = gen(param, state) + if state == nil then break end + -- Assign values to our variables + _it = state + x = var_1 + -- Execute the code block + print(x) + end + end + +What does it mean for us? + +* An iterator can be used together with ``for .. in`` to generate a loop +* An iterator is fully defined using ``gen``, ``param`` and ``state`` iterator + triplet +* The ``nil`` state marks the end of an iteration +* An iterator can return an arbitrary number of values (multireturn) +* It is possible to make some wrapping functions to take an iterator and + + return a new modified iterator + +**The library provides a set of iterators** that can be used like ``pairs`` +and ``ipairs``. + +Iterator Types +-------------- + +Pure functional iterators +````````````````````````` + +Iterators can be either pure functional or have some side effects and returns +different values for some initial conditions [#pure_function]_. An **iterator is +pure functional** if it meets the following criteria: + +- ``gen`` function always returns the same values for the same ``param`` and + ``state`` values (idempotence property) +- ``param`` and ``state`` values are not modified during ``gen`` call and + a new ``state`` object is returned instead (referential transparency + property). + +Pure functional iterators are very important for us. Pure functional iterator +can be safety cloned or reapplied without creating side effects. Many library +function use these properties. + +Finite iterators +```````````````` + +Iterators can be **finite** (sooner or later end up) or **infinite** +(never end). +Since there is no way to determine automatically if an iterator is finite or +not [#turing]_ the library function can not automatically resolve infinite +loops. It is your obligation to do not pass infinite iterator to reducing +functions. + +Tracing JIT +----------- + +Tracing just-in-time compilation is a technique used by virtual machines to +optimize the execution of a program at runtime. This is done by recording a +linear sequence of frequently executed operations, compiling them to native +machine code and executing them. + +First profiling information for loops is collected. After a hot loop has been +identified, a special tracing mode is entered which records all executed +operations of that loop. This sequence of operations is called a **trace**. +The trace is then optimized and compiled to machine code (trace). When this +loop is executed again the compiled trace is called instead of the program +counterpart [#tracing_jit]_. + +Why the tracing JIT is important for us? The LuaJIT tracing compiler can detect +tail-, up- and down-recursion [#luajit-recursion]_, unroll compositions of +functions and inline high-order functions [#luajit-optimizations]_. +All of these concepts make the foundation for functional programming. + +.. [#iterators] http://en.wikipedia.org/wiki/Turtles_all_the_way_down +.. [#lua_for] http://www.lua.org/manual/5.2/manual.html#3.3.5 +.. [#pure_function] http://en.wikipedia.org/wiki/Pure_function +.. [#turing] `Proved by Turing `_ +.. [#tracing_jit] http://en.wikipedia.org/wiki/Tracing_just-in-time_compilation +.. [#luajit-recursion] http://lambda-the-ultimate.org/node/3851#comment-57679 +.. [#luajit-optimizations] http://wiki.luajit.org/Optimizations diff --git a/Data/DefaultContent/Libraries/luafun/fun-scm-1.rockspec b/Data/DefaultContent/Libraries/luafun/fun-scm-1.rockspec new file mode 100644 index 0000000..8f22022 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/fun-scm-1.rockspec @@ -0,0 +1,34 @@ +package = "fun" +version = "scm-1" + +source = { + url = "git://github.com/luafun/luafun.git", +} + +description = { + summary = "High-performance functional programming library for Lua", + homepage = "https://luafun.github.io/", + license = "MIT/X11", + maintainer = "Roman Tsisyk ", + detailed = [[ +Lua Fun is a high-performance functional programming library for Lua +designed with LuaJIT's trace compiler in mind. + +Lua Fun provides a set of more than 50 programming primitives typically +found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and +even Lisp. High-order functions such as map, filter, reduce, zip, etc., +make it easy to write simple and efficient functional code. +]] +} + +dependencies = { + "lua" +} + +build = { + type = "builtin", + modules = { + fun = "fun.lua", + }, + copy_directories = { "tests" }, +} diff --git a/Data/DefaultContent/Libraries/luafun/fun.lua b/Data/DefaultContent/Libraries/luafun/fun.lua new file mode 100644 index 0000000..2427bb2 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/fun.lua @@ -0,0 +1,1058 @@ +--- +--- Lua Fun - a high-performance functional programming library for LuaJIT +--- +--- Copyright (c) 2013-2017 Roman Tsisyk +--- +--- Distributed under the MIT/X11 License. See COPYING.md for more details. +--- + +local exports = {} +local methods = {} + +-- compatibility with Lua 5.1/5.2 +local unpack = rawget(table, "unpack") or unpack + +-------------------------------------------------------------------------------- +-- Tools +-------------------------------------------------------------------------------- + +local return_if_not_empty = function(state_x, ...) + if state_x == nil then + return nil + end + return ... +end + +local call_if_not_empty = function(fun, state_x, ...) + if state_x == nil then + return nil + end + return state_x, fun(...) +end + +local function deepcopy(orig) -- used by cycle() + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key)] = deepcopy(orig_value) + end + else + copy = orig + end + return copy +end + +local iterator_mt = { + -- usually called by for-in loop + __call = function(self, param, state) + return self.gen(param, state) + end; + __tostring = function(self) + return '' + end; + -- add all exported methods + __index = methods; +} + +local wrap = function(gen, param, state) + return setmetatable({ + gen = gen, + param = param, + state = state + }, iterator_mt), param, state +end +exports.wrap = wrap + +local unwrap = function(self) + return self.gen, self.param, self.state +end +methods.unwrap = unwrap + +-------------------------------------------------------------------------------- +-- Basic Functions +-------------------------------------------------------------------------------- + +local nil_gen = function(_param, _state) + return nil +end + +local string_gen = function(param, state) + local state = state + 1 + if state > #param then + return nil + end + local r = string.sub(param, state, state) + return state, r +end + +local ipairs_gen = ipairs({}) -- get the generating function from ipairs + +local pairs_gen = pairs({ a = 0 }) -- get the generating function from pairs +local map_gen = function(tab, key) + local value + local key, value = pairs_gen(tab, key) + return key, key, value +end + +local rawiter = function(obj, param, state) + assert(obj ~= nil, "invalid iterator") + if type(obj) == "table" then + local mt = getmetatable(obj); + if mt ~= nil then + if mt == iterator_mt then + return obj.gen, obj.param, obj.state + elseif mt.__ipairs ~= nil then + return mt.__ipairs(obj) + elseif mt.__pairs ~= nil then + return mt.__pairs(obj) + end + end + if #obj > 0 then + -- array + return ipairs(obj) + else + -- hash + return map_gen, obj, nil + end + elseif (type(obj) == "function") then + return obj, param, state + elseif (type(obj) == "string") then + if #obj == 0 then + return nil_gen, nil, nil + end + return string_gen, obj, 0 + end + error(string.format('object %s of type "%s" is not iterable', + obj, type(obj))) +end + +local iter = function(obj, param, state) + return wrap(rawiter(obj, param, state)) +end +exports.iter = iter + +local method0 = function(fun) + return function(self) + return fun(self.gen, self.param, self.state) + end +end + +local method1 = function(fun) + return function(self, arg1) + return fun(arg1, self.gen, self.param, self.state) + end +end + +local method2 = function(fun) + return function(self, arg1, arg2) + return fun(arg1, arg2, self.gen, self.param, self.state) + end +end + +local export0 = function(fun) + return function(gen, param, state) + return fun(rawiter(gen, param, state)) + end +end + +local export1 = function(fun) + return function(arg1, gen, param, state) + return fun(arg1, rawiter(gen, param, state)) + end +end + +local export2 = function(fun) + return function(arg1, arg2, gen, param, state) + return fun(arg1, arg2, rawiter(gen, param, state)) + end +end + +local each = function(fun, gen, param, state) + repeat + state = call_if_not_empty(fun, gen(param, state)) + until state == nil +end +methods.each = method1(each) +exports.each = export1(each) +methods.for_each = methods.each +exports.for_each = exports.each +methods.foreach = methods.each +exports.foreach = exports.each + +-------------------------------------------------------------------------------- +-- Generators +-------------------------------------------------------------------------------- + +local range_gen = function(param, state) + local stop, step = param[1], param[2] + local state = state + step + if state > stop then + return nil + end + return state, state +end + +local range_rev_gen = function(param, state) + local stop, step = param[1], param[2] + local state = state + step + if state < stop then + return nil + end + return state, state +end + +local range = function(start, stop, step) + if step == nil then + if stop == nil then + if start == 0 then + return nil_gen, nil, nil + end + stop = start + start = stop > 0 and 1 or -1 + end + step = start <= stop and 1 or -1 + end + + assert(type(start) == "number", "start must be a number") + assert(type(stop) == "number", "stop must be a number") + assert(type(step) == "number", "step must be a number") + assert(step ~= 0, "step must not be zero") + + if (step > 0) then + return wrap(range_gen, {stop, step}, start - step) + elseif (step < 0) then + return wrap(range_rev_gen, {stop, step}, start - step) + end +end +exports.range = range + +local duplicate_table_gen = function(param_x, state_x) + return state_x + 1, unpack(param_x) +end + +local duplicate_fun_gen = function(param_x, state_x) + return state_x + 1, param_x(state_x) +end + +local duplicate_gen = function(param_x, state_x) + return state_x + 1, param_x +end + +local duplicate = function(...) + if select('#', ...) <= 1 then + return wrap(duplicate_gen, select(1, ...), 0) + else + return wrap(duplicate_table_gen, {...}, 0) + end +end +exports.duplicate = duplicate +exports.replicate = duplicate +exports.xrepeat = duplicate + +local tabulate = function(fun) + assert(type(fun) == "function") + return wrap(duplicate_fun_gen, fun, 0) +end +exports.tabulate = tabulate + +local zeros = function() + return wrap(duplicate_gen, 0, 0) +end +exports.zeros = zeros + +local ones = function() + return wrap(duplicate_gen, 1, 0) +end +exports.ones = ones + +local rands_gen = function(param_x, _state_x) + return 0, math.random(param_x[1], param_x[2]) +end + +local rands_nil_gen = function(_param_x, _state_x) + return 0, math.random() +end + +local rands = function(n, m) + if n == nil and m == nil then + return wrap(rands_nil_gen, 0, 0) + end + assert(type(n) == "number", "invalid first arg to rands") + if m == nil then + m = n + n = 0 + else + assert(type(m) == "number", "invalid second arg to rands") + end + assert(n < m, "empty interval") + return wrap(rands_gen, {n, m - 1}, 0) +end +exports.rands = rands + +-------------------------------------------------------------------------------- +-- Slicing +-------------------------------------------------------------------------------- + +local nth = function(n, gen_x, param_x, state_x) + assert(n > 0, "invalid first argument to nth") + -- An optimization for arrays and strings + if gen_x == ipairs_gen then + return param_x[n] + elseif gen_x == string_gen then + if n <= #param_x then + return string.sub(param_x, n, n) + else + return nil + end + end + for i=1,n-1,1 do + state_x = gen_x(param_x, state_x) + if state_x == nil then + return nil + end + end + return return_if_not_empty(gen_x(param_x, state_x)) +end +methods.nth = method1(nth) +exports.nth = export1(nth) + +local head_call = function(state, ...) + if state == nil then + error("head: iterator is empty") + end + return ... +end + +local head = function(gen, param, state) + return head_call(gen(param, state)) +end +methods.head = method0(head) +exports.head = export0(head) +exports.car = exports.head +methods.car = methods.head + +local tail = function(gen, param, state) + state = gen(param, state) + if state == nil then + return wrap(nil_gen, nil, nil) + end + return wrap(gen, param, state) +end +methods.tail = method0(tail) +exports.tail = export0(tail) +exports.cdr = exports.tail +methods.cdr = methods.tail + +local take_n_gen_x = function(i, state_x, ...) + if state_x == nil then + return nil + end + return {i, state_x}, ... +end + +local take_n_gen = function(param, state) + local n, gen_x, param_x = param[1], param[2], param[3] + local i, state_x = state[1], state[2] + if i >= n then + return nil + end + return take_n_gen_x(i + 1, gen_x(param_x, state_x)) +end + +local take_n = function(n, gen, param, state) + assert(n >= 0, "invalid first argument to take_n") + return wrap(take_n_gen, {n, gen, param}, {0, state}) +end +methods.take_n = method1(take_n) +exports.take_n = export1(take_n) + +local take_while_gen_x = function(fun, state_x, ...) + if state_x == nil or not fun(...) then + return nil + end + return state_x, ... +end + +local take_while_gen = function(param, state_x) + local fun, gen_x, param_x = param[1], param[2], param[3] + return take_while_gen_x(fun, gen_x(param_x, state_x)) +end + +local take_while = function(fun, gen, param, state) + assert(type(fun) == "function", "invalid first argument to take_while") + return wrap(take_while_gen, {fun, gen, param}, state) +end +methods.take_while = method1(take_while) +exports.take_while = export1(take_while) + +local take = function(n_or_fun, gen, param, state) + if type(n_or_fun) == "number" then + return take_n(n_or_fun, gen, param, state) + else + return take_while(n_or_fun, gen, param, state) + end +end +methods.take = method1(take) +exports.take = export1(take) + +local drop_n = function(n, gen, param, state) + assert(n >= 0, "invalid first argument to drop_n") + local i + for i=1,n,1 do + state = gen(param, state) + if state == nil then + return wrap(nil_gen, nil, nil) + end + end + return wrap(gen, param, state) +end +methods.drop_n = method1(drop_n) +exports.drop_n = export1(drop_n) + +local drop_while_x = function(fun, state_x, ...) + if state_x == nil or not fun(...) then + return state_x, false + end + return state_x, true, ... +end + +local drop_while = function(fun, gen_x, param_x, state_x) + assert(type(fun) == "function", "invalid first argument to drop_while") + local cont, state_x_prev + repeat + state_x_prev = deepcopy(state_x) + state_x, cont = drop_while_x(fun, gen_x(param_x, state_x)) + until not cont + if state_x == nil then + return wrap(nil_gen, nil, nil) + end + return wrap(gen_x, param_x, state_x_prev) +end +methods.drop_while = method1(drop_while) +exports.drop_while = export1(drop_while) + +local drop = function(n_or_fun, gen_x, param_x, state_x) + if type(n_or_fun) == "number" then + return drop_n(n_or_fun, gen_x, param_x, state_x) + else + return drop_while(n_or_fun, gen_x, param_x, state_x) + end +end +methods.drop = method1(drop) +exports.drop = export1(drop) + +local split = function(n_or_fun, gen_x, param_x, state_x) + return take(n_or_fun, gen_x, param_x, state_x), + drop(n_or_fun, gen_x, param_x, state_x) +end +methods.split = method1(split) +exports.split = export1(split) +methods.split_at = methods.split +exports.split_at = exports.split +methods.span = methods.split +exports.span = exports.split + +-------------------------------------------------------------------------------- +-- Indexing +-------------------------------------------------------------------------------- + +local index = function(x, gen, param, state) + local i = 1 + for _k, r in gen, param, state do + if r == x then + return i + end + i = i + 1 + end + return nil +end +methods.index = method1(index) +exports.index = export1(index) +methods.index_of = methods.index +exports.index_of = exports.index +methods.elem_index = methods.index +exports.elem_index = exports.index + +local indexes_gen = function(param, state) + local x, gen_x, param_x = param[1], param[2], param[3] + local i, state_x = state[1], state[2] + local r + while true do + state_x, r = gen_x(param_x, state_x) + if state_x == nil then + return nil + end + i = i + 1 + if r == x then + return {i, state_x}, i + end + end +end + +local indexes = function(x, gen, param, state) + return wrap(indexes_gen, {x, gen, param}, {0, state}) +end +methods.indexes = method1(indexes) +exports.indexes = export1(indexes) +methods.elem_indexes = methods.indexes +exports.elem_indexes = exports.indexes +methods.indices = methods.indexes +exports.indices = exports.indexes +methods.elem_indices = methods.indexes +exports.elem_indices = exports.indexes + +-------------------------------------------------------------------------------- +-- Filtering +-------------------------------------------------------------------------------- + +local filter1_gen = function(fun, gen_x, param_x, state_x, a) + while true do + if state_x == nil or fun(a) then break; end + state_x, a = gen_x(param_x, state_x) + end + return state_x, a +end + +-- call each other +local filterm_gen +local filterm_gen_shrink = function(fun, gen_x, param_x, state_x) + return filterm_gen(fun, gen_x, param_x, gen_x(param_x, state_x)) +end + +filterm_gen = function(fun, gen_x, param_x, state_x, ...) + if state_x == nil then + return nil + end + if fun(...) then + return state_x, ... + end + return filterm_gen_shrink(fun, gen_x, param_x, state_x) +end + +local filter_detect = function(fun, gen_x, param_x, state_x, ...) + if select('#', ...) < 2 then + return filter1_gen(fun, gen_x, param_x, state_x, ...) + else + return filterm_gen(fun, gen_x, param_x, state_x, ...) + end +end + +local filter_gen = function(param, state_x) + local fun, gen_x, param_x = param[1], param[2], param[3] + return filter_detect(fun, gen_x, param_x, gen_x(param_x, state_x)) +end + +local filter = function(fun, gen, param, state) + return wrap(filter_gen, {fun, gen, param}, state) +end +methods.filter = method1(filter) +exports.filter = export1(filter) +methods.remove_if = methods.filter +exports.remove_if = exports.filter + +local grep = function(fun_or_regexp, gen, param, state) + local fun = fun_or_regexp + if type(fun_or_regexp) == "string" then + fun = function(x) return string.find(x, fun_or_regexp) ~= nil end + end + return filter(fun, gen, param, state) +end +methods.grep = method1(grep) +exports.grep = export1(grep) + +local partition = function(fun, gen, param, state) + local neg_fun = function(...) + return not fun(...) + end + return filter(fun, gen, param, state), + filter(neg_fun, gen, param, state) +end +methods.partition = method1(partition) +exports.partition = export1(partition) + +-------------------------------------------------------------------------------- +-- Reducing +-------------------------------------------------------------------------------- + +local foldl_call = function(fun, start, state, ...) + if state == nil then + return nil, start + end + return state, fun(start, ...) +end + +local foldl = function(fun, start, gen_x, param_x, state_x) + while true do + state_x, start = foldl_call(fun, start, gen_x(param_x, state_x)) + if state_x == nil then + break; + end + end + return start +end +methods.foldl = method2(foldl) +exports.foldl = export2(foldl) +methods.reduce = methods.foldl +exports.reduce = exports.foldl + +local length = function(gen, param, state) + if gen == ipairs_gen or gen == string_gen then + return #param + end + local len = 0 + repeat + state = gen(param, state) + len = len + 1 + until state == nil + return len - 1 +end +methods.length = method0(length) +exports.length = export0(length) + +local is_null = function(gen, param, state) + return gen(param, deepcopy(state)) == nil +end +methods.is_null = method0(is_null) +exports.is_null = export0(is_null) + +local is_prefix_of = function(iter_x, iter_y) + local gen_x, param_x, state_x = iter(iter_x) + local gen_y, param_y, state_y = iter(iter_y) + + local r_x, r_y + for i=1,10,1 do + state_x, r_x = gen_x(param_x, state_x) + state_y, r_y = gen_y(param_y, state_y) + if state_x == nil then + return true + end + if state_y == nil or r_x ~= r_y then + return false + end + end +end +methods.is_prefix_of = is_prefix_of +exports.is_prefix_of = is_prefix_of + +local all = function(fun, gen_x, param_x, state_x) + local r + repeat + state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x)) + until state_x == nil or not r + return state_x == nil +end +methods.all = method1(all) +exports.all = export1(all) +methods.every = methods.all +exports.every = exports.all + +local any = function(fun, gen_x, param_x, state_x) + local r + repeat + state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x)) + until state_x == nil or r + return not not r +end +methods.any = method1(any) +exports.any = export1(any) +methods.some = methods.any +exports.some = exports.any + +local sum = function(gen, param, state) + local s = 0 + local r = 0 + repeat + s = s + r + state, r = gen(param, state) + until state == nil + return s +end +methods.sum = method0(sum) +exports.sum = export0(sum) + +local product = function(gen, param, state) + local p = 1 + local r = 1 + repeat + p = p * r + state, r = gen(param, state) + until state == nil + return p +end +methods.product = method0(product) +exports.product = export0(product) + +local min_cmp = function(m, n) + if n < m then return n else return m end +end + +local max_cmp = function(m, n) + if n > m then return n else return m end +end + +local min = function(gen, param, state) + local state, m = gen(param, state) + if state == nil then + error("min: iterator is empty") + end + + local cmp + if type(m) == "number" then + -- An optimization: use math.min for numbers + cmp = math.min + else + cmp = min_cmp + end + + for _, r in gen, param, state do + m = cmp(m, r) + end + return m +end +methods.min = method0(min) +exports.min = export0(min) +methods.minimum = methods.min +exports.minimum = exports.min + +local min_by = function(cmp, gen_x, param_x, state_x) + local state_x, m = gen_x(param_x, state_x) + if state_x == nil then + error("min: iterator is empty") + end + + for _, r in gen_x, param_x, state_x do + m = cmp(m, r) + end + return m +end +methods.min_by = method1(min_by) +exports.min_by = export1(min_by) +methods.minimum_by = methods.min_by +exports.minimum_by = exports.min_by + +local max = function(gen_x, param_x, state_x) + local state_x, m = gen_x(param_x, state_x) + if state_x == nil then + error("max: iterator is empty") + end + + local cmp + if type(m) == "number" then + -- An optimization: use math.max for numbers + cmp = math.max + else + cmp = max_cmp + end + + for _, r in gen_x, param_x, state_x do + m = cmp(m, r) + end + return m +end +methods.max = method0(max) +exports.max = export0(max) +methods.maximum = methods.max +exports.maximum = exports.max + +local max_by = function(cmp, gen_x, param_x, state_x) + local state_x, m = gen_x(param_x, state_x) + if state_x == nil then + error("max: iterator is empty") + end + + for _, r in gen_x, param_x, state_x do + m = cmp(m, r) + end + return m +end +methods.max_by = method1(max_by) +exports.max_by = export1(max_by) +methods.maximum_by = methods.maximum_by +exports.maximum_by = exports.maximum_by + +local totable = function(gen_x, param_x, state_x) + local tab, key, val = {} + while true do + state_x, val = gen_x(param_x, state_x) + if state_x == nil then + break + end + table.insert(tab, val) + end + return tab +end +methods.totable = method0(totable) +exports.totable = export0(totable) + +local tomap = function(gen_x, param_x, state_x) + local tab, key, val = {} + while true do + state_x, key, val = gen_x(param_x, state_x) + if state_x == nil then + break + end + tab[key] = val + end + return tab +end +methods.tomap = method0(tomap) +exports.tomap = export0(tomap) + +-------------------------------------------------------------------------------- +-- Transformations +-------------------------------------------------------------------------------- + +local map_gen = function(param, state) + local gen_x, param_x, fun = param[1], param[2], param[3] + return call_if_not_empty(fun, gen_x(param_x, state)) +end + +local map = function(fun, gen, param, state) + return wrap(map_gen, {gen, param, fun}, state) +end +methods.map = method1(map) +exports.map = export1(map) + +local enumerate_gen_call = function(state, i, state_x, ...) + if state_x == nil then + return nil + end + return {i + 1, state_x}, i, ... +end + +local enumerate_gen = function(param, state) + local gen_x, param_x = param[1], param[2] + local i, state_x = state[1], state[2] + return enumerate_gen_call(state, i, gen_x(param_x, state_x)) +end + +local enumerate = function(gen, param, state) + return wrap(enumerate_gen, {gen, param}, {1, state}) +end +methods.enumerate = method0(enumerate) +exports.enumerate = export0(enumerate) + +local intersperse_call = function(i, state_x, ...) + if state_x == nil then + return nil + end + return {i + 1, state_x}, ... +end + +local intersperse_gen = function(param, state) + local x, gen_x, param_x = param[1], param[2], param[3] + local i, state_x = state[1], state[2] + if i % 2 == 1 then + return {i + 1, state_x}, x + else + return intersperse_call(i, gen_x(param_x, state_x)) + end +end + +-- TODO: interperse must not add x to the tail +local intersperse = function(x, gen, param, state) + return wrap(intersperse_gen, {x, gen, param}, {0, state}) +end +methods.intersperse = method1(intersperse) +exports.intersperse = export1(intersperse) + +-------------------------------------------------------------------------------- +-- Compositions +-------------------------------------------------------------------------------- + +local function zip_gen_r(param, state, state_new, ...) + if #state_new == #param / 2 then + return state_new, ... + end + + local i = #state_new + 1 + local gen_x, param_x = param[2 * i - 1], param[2 * i] + local state_x, r = gen_x(param_x, state[i]) + if state_x == nil then + return nil + end + table.insert(state_new, state_x) + return zip_gen_r(param, state, state_new, r, ...) +end + +local zip_gen = function(param, state) + return zip_gen_r(param, state, {}) +end + +-- A special hack for zip/chain to skip last two state, if a wrapped iterator +-- has been passed +local numargs = function(...) + local n = select('#', ...) + if n >= 3 then + -- Fix last argument + local it = select(n - 2, ...) + if type(it) == 'table' and getmetatable(it) == iterator_mt and + it.param == select(n - 1, ...) and it.state == select(n, ...) then + return n - 2 + end + end + return n +end + +local zip = function(...) + local n = numargs(...) + if n == 0 then + return wrap(nil_gen, nil, nil) + end + local param = { [2 * n] = 0 } + local state = { [n] = 0 } + + local i, gen_x, param_x, state_x + for i=1,n,1 do + local it = select(n - i + 1, ...) + gen_x, param_x, state_x = rawiter(it) + param[2 * i - 1] = gen_x + param[2 * i] = param_x + state[i] = state_x + end + + return wrap(zip_gen, param, state) +end +methods.zip = zip +exports.zip = zip + +local cycle_gen_call = function(param, state_x, ...) + if state_x == nil then + local gen_x, param_x, state_x0 = param[1], param[2], param[3] + return gen_x(param_x, deepcopy(state_x0)) + end + return state_x, ... +end + +local cycle_gen = function(param, state_x) + local gen_x, param_x, state_x0 = param[1], param[2], param[3] + return cycle_gen_call(param, gen_x(param_x, state_x)) +end + +local cycle = function(gen, param, state) + return wrap(cycle_gen, {gen, param, state}, deepcopy(state)) +end +methods.cycle = method0(cycle) +exports.cycle = export0(cycle) + +-- call each other +local chain_gen_r1 +local chain_gen_r2 = function(param, state, state_x, ...) + if state_x == nil then + local i = state[1] + i = i + 1 + if param[3 * i - 1] == nil then + return nil + end + local state_x = param[3 * i] + return chain_gen_r1(param, {i, state_x}) + end + return {state[1], state_x}, ... +end + +chain_gen_r1 = function(param, state) + local i, state_x = state[1], state[2] + local gen_x, param_x = param[3 * i - 2], param[3 * i - 1] + return chain_gen_r2(param, state, gen_x(param_x, state[2])) +end + +local chain = function(...) + local n = numargs(...) + if n == 0 then + return wrap(nil_gen, nil, nil) + end + + local param = { [3 * n] = 0 } + local i, gen_x, param_x, state_x + for i=1,n,1 do + local elem = select(i, ...) + gen_x, param_x, state_x = iter(elem) + param[3 * i - 2] = gen_x + param[3 * i - 1] = param_x + param[3 * i] = state_x + end + + return wrap(chain_gen_r1, param, {1, param[3]}) +end +methods.chain = chain +exports.chain = chain + +-------------------------------------------------------------------------------- +-- Operators +-------------------------------------------------------------------------------- + +local operator = { + ---------------------------------------------------------------------------- + -- Comparison operators + ---------------------------------------------------------------------------- + lt = function(a, b) return a < b end, + le = function(a, b) return a <= b end, + eq = function(a, b) return a == b end, + ne = function(a, b) return a ~= b end, + ge = function(a, b) return a >= b end, + gt = function(a, b) return a > b end, + + ---------------------------------------------------------------------------- + -- Arithmetic operators + ---------------------------------------------------------------------------- + add = function(a, b) return a + b end, + div = function(a, b) return a / b end, + floordiv = function(a, b) return math.floor(a/b) end, + intdiv = function(a, b) + local q = a / b + if a >= 0 then return math.floor(q) else return math.ceil(q) end + end, + mod = function(a, b) return a % b end, + mul = function(a, b) return a * b end, + neq = function(a) return -a end, + unm = function(a) return -a end, -- an alias + pow = function(a, b) return a ^ b end, + sub = function(a, b) return a - b end, + truediv = function(a, b) return a / b end, + + ---------------------------------------------------------------------------- + -- String operators + ---------------------------------------------------------------------------- + concat = function(a, b) return a..b end, + len = function(a) return #a end, + length = function(a) return #a end, -- an alias + + ---------------------------------------------------------------------------- + -- Logical operators + ---------------------------------------------------------------------------- + land = function(a, b) return a and b end, + lor = function(a, b) return a or b end, + lnot = function(a) return not a end, + truth = function(a) return not not a end, +} +exports.operator = operator +methods.operator = operator +exports.op = operator +methods.op = operator + +-------------------------------------------------------------------------------- +-- module definitions +-------------------------------------------------------------------------------- + +-- a special syntax sugar to export all functions to the global table +setmetatable(exports, { + __call = function(t, override) + for k, v in pairs(t) do + if rawget(_G, k) ~= nil then + local msg = 'function ' .. k .. ' already exists in global scope.' + if override then + rawset(_G, k, v) + print('WARNING: ' .. msg .. ' Overwritten.') + else + print('NOTICE: ' .. msg .. ' Skipped.') + end + else + rawset(_G, k, v) + end + end + end, +}) + +return exports diff --git a/Data/DefaultContent/Libraries/luafun/rpm/lua-fun.spec b/Data/DefaultContent/Libraries/luafun/rpm/lua-fun.spec new file mode 100644 index 0000000..b200c76 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/rpm/lua-fun.spec @@ -0,0 +1,76 @@ +%define luaver 5.3 +%define luapkgdir %{_datadir}/lua/%{luaver} +# LuaJIT is compatible with Lua 5.1 and uses the same directory for modules +%global ljpkgdir %{_datadir}/lua/5.1 + +Name: lua-fun +Version: 0.1.3 +Release: 1%{?dist} +Summary: Functional programming library for Lua +Group: Development/Libraries +License: MIT +URL: https://github.com/luafun/luafun +Source0: https://github.com/luafun/luafun/archive/%{version}/luafun-%{version}.tar.gz +BuildArch: noarch +BuildRequires: luajit >= 2.0 +BuildRequires: lua >= 5.1 +Requires: lua >= 5.1 + +%package -n luajit-fun +Summary: Functional programming library for LuaJIT +Requires: luajit >= 2.0 + +%description -n lua-fun +Lua Fun is a high-performance functional programming library for Lua +designed with LuaJIT's trace compiler in mind. + +Lua Fun provides a set of more than 50 programming primitives typically +found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and +even Lisp. High-order functions such as map, filter, reduce, zip, etc., +make it easy to write simple and efficient functional code. + +This package provides a module for Lua %{luaver}. + +%description -n luajit-fun +Lua Fun is a high-performance functional programming library for Lua +designed with LuaJIT's trace compiler in mind. + +Lua Fun provides a set of more than 50 programming primitives typically +found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and +even Lisp. High-order functions such as map, filter, reduce, zip, etc., +make it easy to write simple and efficient functional code. + +This package provides a module for LuaJIT. + +%prep +%setup -q -n luafun-%{version} + +%build +# nothing to do + +%install +# Install for Lua +mkdir -p %{buildroot}%{luapkgdir} +cp -av fun.lua %{buildroot}%{luapkgdir}/fun.lua +# Install for LuaJIT +mkdir -p %{buildroot}%{ljpkgdir} +cp -av fun.lua %{buildroot}%{ljpkgdir}/fun.lua + +%check +cd tests +luajit ./runtest *.lua +lua ./runtest *.lua + +%files -n lua-fun +%{luapkgdir}/fun.lua +%doc README.md CONTRIBUTING.md +%license COPYING.md + +%files -n luajit-fun +%{ljpkgdir}/fun.lua +%doc README.md CONTRIBUTING.md +%license COPYING.md + +%changelog +* Mon Jan 18 2016 Roman Tsisyk - 0.1.3-1 +- Initial version. diff --git a/Data/DefaultContent/Libraries/luafun/tests/.gitignore b/Data/DefaultContent/Libraries/luafun/tests/.gitignore new file mode 100644 index 0000000..ce0a7f3 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/.gitignore @@ -0,0 +1 @@ +*.new diff --git a/Data/DefaultContent/Libraries/luafun/tests/basic.lua b/Data/DefaultContent/Libraries/luafun/tests/basic.lua new file mode 100644 index 0000000..97e7aae --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/basic.lua @@ -0,0 +1,332 @@ +-------------------------------------------------------------------------------- +-- iter +-------------------------------------------------------------------------------- + +-- +-- Arrays +-- + +for _it, a in iter({1, 2, 3}) do print(a) end +--[[test +1 +2 +3 +--test]] + +for _it, a in iter(iter(iter({1, 2, 3}))) do print(a) end +--[[test +1 +2 +3 +--test]] + +for _it, a in wrap(wrap(iter({1, 2, 3}))) do print(a) end +--[[test +1 +2 +3 +--test]] + +for _it, a in wrap(wrap(ipairs({1, 2, 3}))) do print(a) end +--[[test +1 +2 +3 +--test]] + +for _it, a in iter({}) do print(a) end +--[[test +--test]] + +for _it, a in iter(iter(iter({}))) do print(a) end +--[[test +--test]] + +for _it, a in wrap(wrap(iter({}))) do print(a) end +--[[test +--test]] + +for _it, a in wrap(wrap(ipairs({}))) do print(a) end +--[[test +--test]] + +-- Check that ``iter`` for arrays is equivalent to ``ipairs`` +local t = {1, 2, 3} +gen1, param1, state1 = iter(t):unwrap() +gen2, param2, state2 = ipairs(t) +print(gen1 == gen2, param1 == param2, state1 == state2) +--[[test +true true true +--test]] + +-- Test that ``wrap`` do nothing for wrapped iterators +gen1, param1, state1 = iter({1, 2, 3}) +gen2, param2, state2 = wrap(gen1, param1, state1):unwrap() +print(gen1 == gen2, param1 == param2, state1 == state2) +--[[test +true true true +--test]] + +-- +-- Maps +-- + +local t = {} +for _it, k, v in iter({ a = 1, b = 2, c = 3}) do t[#t + 1] = k end +table.sort(t) +for _it, v in iter(t) do print(v) end +--[[test +a +b +c +--test]] + +local t = {} +for _it, k, v in iter(iter(iter({ a = 1, b = 2, c = 3}))) do t[#t + 1] = k end +table.sort(t) +for _it, v in iter(t) do print(v) end +--[[test +a +b +c +--test]] + +for _it, k, v in iter({}) do print(k, v) end +--[[test +--test]] + +for _it, k, v in iter(iter(iter({}))) do print(k, v) end +--[[test +--test]] + +-- +-- String +-- + +for _it, a in iter("abcde") do print(a) end +--[[test +a +b +c +d +e +--test]] + +for _it, a in iter(iter(iter("abcde"))) do print(a) end +--[[test +a +b +c +d +e +--test]] + +for _it, a in iter("") do print(a) end +--[[test +--test]] + +for _it, a in iter(iter(iter(""))) do print(a) end +--[[test +--test]] + +-- +-- Custom generators +-- + +local function mypairs_gen(max, state) + if (state >= max) then + return nil + end + return state + 1, state + 1 +end + +local function mypairs(max) + return mypairs_gen, max, 0 +end + +for _it, a in iter(mypairs(10)) do print(a) end +--[[test +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +--test]] + +-- +-- Invalid values +-- + +for _it, a in iter(1) do print(a) end +--[[test +error: object 1 of type "number" is not iterable +--test]] + +for _it, a in iter(1, 2, 3, 4, 5, 6, 7) do print(a) end +--[[test +error: object 1 of type "number" is not iterable +--test]] + +-------------------------------------------------------------------------------- +-- each +-------------------------------------------------------------------------------- + +each(print, {1, 2, 3}) +--[[test +1 +2 +3 +--test]] + +each(print, iter({1, 2, 3})) +--[[test +1 +2 +3 +--test]] + +each(print, {}) +--[[test +--test]] + + +each(print, iter({})) +--[[test +--test]] + +local keys, vals = {}, {} +each(function(k, v) + keys[#keys + 1] = k + vals[#vals + 1] = v +end, { a = 1, b = 2, c = 3}) +table.sort(keys) +table.sort(vals) +each(print, keys) +each(print, vals) +--[[test +a +b +c +1 +2 +3 +--test]] + +each(print, "abc") +--[[test +a +b +c +--test]] + +each(print, iter("abc")) +--[[test +a +b +c +--test]] + +print(for_each == each) -- an alias +--[[test +true +--test]] + +print(foreach == each) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- totable +-------------------------------------------------------------------------------- + +local tab = totable(range(5)) +print(type(tab), #tab) +each(print, tab) +--[[test +table 5 +1 +2 +3 +4 +5 +--test]] + +local tab = totable(range(0)) +print(type(tab), #tab) +--[[test +table 0 +--test]] + +local tab = totable("abcdef") +print(type(tab), #tab) +each(print, tab) +--[[test +table 6 +a +b +c +d +e +f +--test]] + +local unpack = rawget(table, "unpack") or unpack +local tab = totable({ 'a', {'b', 'c'}, {'d', 'e', 'f'}}) +print(type(tab), #tab) +each(print, tab[1]) +each(print, map(unpack, drop(1, tab))) +--[[test +table 3 +a +b c +d e f +--test]] + +-------------------------------------------------------------------------------- +-- tomap +-------------------------------------------------------------------------------- + +local tab = tomap(zip(range(1, 7), 'abcdef')) +print(type(tab), #tab) +each(print, iter(tab)) +--[[test +table 6 +a +b +c +d +e +f +--test]] + +local tab = tomap({a = 1, b = 2, c = 3}) +print(type(tab), #tab) +local t = {} +for _it, k, v in iter(tab) do t[v] = k end +table.sort(t) +for k, v in ipairs(t) do print(k, v) end +--[[test +table 0 +1 a +2 b +3 c +--test]] + +local tab = tomap(enumerate("abcdef")) +print(type(tab), #tab) +each(print, tab) +--[[test +table 6 +a +b +c +d +e +f +--test]] diff --git a/Data/DefaultContent/Libraries/luafun/tests/compositions.lua b/Data/DefaultContent/Libraries/luafun/tests/compositions.lua new file mode 100644 index 0000000..7b81d88 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/compositions.lua @@ -0,0 +1,170 @@ +-------------------------------------------------------------------------------- +-- zip +-------------------------------------------------------------------------------- + +dump(zip({"a", "b", "c", "d"}, {"one", "two", "three"})) +--[[test +a one +b two +c three +--test]] + +dump(zip()) +--[[test +--test]] + +dump(zip(range(0))) +--[[test +error: invalid iterator +--test]] + +dump(zip(range(0), range(0))) +--[[test +error: invalid iterator +--test]] + +print(nth(10, zip(range(1, 100, 3), range(1, 100, 5), range(1, 100, 7)))) +--[[test +28 46 64 +--test]] + +dump(zip(partition(function(x) return x > 7 end, range(1, 15, 1)))) +--[[test +8 1 +9 2 +10 3 +11 4 +12 5 +13 6 +14 7 +--test]] + +-------------------------------------------------------------------------------- +-- cycle +-------------------------------------------------------------------------------- + +dump(take(15, cycle({"a", "b", "c", "d", "e"}))) +--[[test +a +b +c +d +e +a +b +c +d +e +a +b +c +d +e +--test]] + + +dump(take(15, cycle(range(5)))) +--[[test +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +--test]] + +dump(take(15, cycle(zip(range(5), {"a", "b", "c", "d", "e"})))) +--[[test +1 a +2 b +3 c +4 d +5 e +1 a +2 b +3 c +4 d +5 e +1 a +2 b +3 c +4 d +5 e +--test]] + +-------------------------------------------------------------------------------- +-- chain +-------------------------------------------------------------------------------- + +dump(chain(range(2))) +--[[test +1 +2 +--test]] + +dump(chain(range(2), {"a", "b", "c"}, {"one", "two", "three"})) +--[[test +1 +2 +a +b +c +one +two +three +--test]] + +dump(take(15, cycle(chain(enumerate({"a", "b", "c"}), + {"one", "two", "three"})))) +--[[test +1 a +2 b +3 c +one +two +three +1 a +2 b +3 c +one +two +three +1 a +2 b +3 c +--test]] + +local tab = {} +local keys = {} +for _it, k, v in chain({ a = 11, b = 12, c = 13}, { d = 21, e = 22 }) do + tab[k] = v + table.insert(keys, k) +end +table.sort(keys) +for _, key in ipairs(keys) do print(key, tab[key]) end +--[[test +a 11 +b 12 +c 13 +d 21 +e 22 +--test]] + +dump(chain(range(0), range(0), range(0))) +--[[test +error: invalid iterator +--test]] + +dump(chain(range(0), range(1), range(0))) +--[[test +error: invalid iterator +--test]] diff --git a/Data/DefaultContent/Libraries/luafun/tests/filtering.lua b/Data/DefaultContent/Libraries/luafun/tests/filtering.lua new file mode 100644 index 0000000..a5fdfe2 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/filtering.lua @@ -0,0 +1,102 @@ +-------------------------------------------------------------------------------- +-- filter +-------------------------------------------------------------------------------- + +dump(filter(function(x) return x % 3 == 0 end, range(10))) +--[[test +3 +6 +9 +--test]] + +dump(filter(function(x) return x % 3 == 0 end, range(0))) +--[[test +--test]] + + +dump(take(5, filter(function(i, x) return i % 3 == 0 end, + enumerate(duplicate('x'))))) +--[[test +3 x +6 x +9 x +12 x +15 x +--test]] + +function filter_fun(a, b, c) + if a % 16 == 0 then + return true + else + return false + end +end + +function test3(a, b, c) + return a, c, b +end + +n = 50 +dump(filter(filter_fun, map(test3, zip(range(0, n, 1), + range(0, n, 2), range(0, n, 3))))) +--[[test +0 0 0 +16 48 32 +--test]] + +print(remove_if == filter) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- grep +-------------------------------------------------------------------------------- + +lines_to_grep = { + [[Lorem ipsum dolor sit amet, consectetur adipisicing elit, ]], + [[sed do eiusmod tempor incididunt ut labore et dolore magna ]], + [[aliqua. Ut enim ad minim veniam, quis nostrud exercitation ]], + [[ullamco laboris nisi ut aliquip ex ea commodo consequat.]], + [[Duis aute irure dolor in reprehenderit in voluptate velit ]], + [[esse cillum dolore eu fugiat nulla pariatur. Excepteur sint ]], + [[occaecat cupidatat non proident, sunt in culpa qui officia ]], + [[deserunt mollit anim id est laborum.]] +} + +dump(grep("lab", lines_to_grep)) +--[[test +sed do eiusmod tempor incididunt ut labore et dolore magna +ullamco laboris nisi ut aliquip ex ea commodo consequat. +deserunt mollit anim id est laborum. +--test]] + +lines_to_grep = { + [[Emily]], + [[Chloe]], + [[Megan]], + [[Jessica]], + [[Emma]], + [[Sarah]], + [[Elizabeth]], + [[Sophie]], + [[Olivia]], + [[Lauren]] +} + +dump(grep("^Em", lines_to_grep)) +--[[test +Emily +Emma +--test]] + +-------------------------------------------------------------------------------- +-- partition +-------------------------------------------------------------------------------- + +dump(zip(partition(function(i, x) return i % 3 == 0 end, range(10)))) +--[[test +3 1 +6 2 +9 4 +--test]] diff --git a/Data/DefaultContent/Libraries/luafun/tests/generators.lua b/Data/DefaultContent/Libraries/luafun/tests/generators.lua new file mode 100644 index 0000000..7a89ebf --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/generators.lua @@ -0,0 +1,287 @@ +-------------------------------------------------------------------------------- +-- range +-------------------------------------------------------------------------------- + +dump(range(0)) +print('--') +for i=1,0 do print(i) end +--[[test +-- +--test]] + +dump(range(0, 0)) +print('--') +for i=0,0 do print(i) end +--[[test +0 +-- +0 +--test]] + +dump(range(5)) +print('--') +for i=1,5 do print(i) end +--[[test +1 +2 +3 +4 +5 +-- +1 +2 +3 +4 +5 +--test]] + +dump(range(0, 5)) +print('--') +for i=0,5 do print(i) end +--[[test +0 +1 +2 +3 +4 +5 +-- +0 +1 +2 +3 +4 +5 +--test]] + +dump(range(0, 5, 1)) +print('--') +for i=0,5,1 do print(i) end +--[[test +0 +1 +2 +3 +4 +5 +-- +0 +1 +2 +3 +4 +5 +--test]] + +dump(range(0, 10, 2)) +print('--') +for i=0,10,2 do print(i) end +--[[test +0 +2 +4 +6 +8 +10 +-- +0 +2 +4 +6 +8 +10 +--test]] + +dump(range(-5)) +print('--') +for i=-1,-5,-1 do print(i) end +--[[test +-1 +-2 +-3 +-4 +-5 +-- +-1 +-2 +-3 +-4 +-5 +--test]] + +dump(range(0, -5, 1)) +print('--') +for i=0,-5,1 do print(i) end +--[[test +-- +--test]] + +dump(range(0, -5, -1)) +print('--') +for i=0,-5,-1 do print(i) end +--[[test +0 +-1 +-2 +-3 +-4 +-5 +-- +0 +-1 +-2 +-3 +-4 +-5 +--test]] + +dump(range(0, -10, -2)) +print('--') +for i=0,-10,-2 do print(i) end +--[[test +0 +-2 +-4 +-6 +-8 +-10 +-- +0 +-2 +-4 +-6 +-8 +-10 +--test]] + +dump(range(1.2, 1.6, 0.1)) +--[[test +1.2 +1.3 +1.4 +1.5 +--test]] + +-- Invalid step +dump(range(0, 5, 0)) +--[[test +error: step must not be zero +--test]] + +-------------------------------------------------------------------------------- +-- duplicate +-------------------------------------------------------------------------------- + +dump(take(5, duplicate(48))) +--[[test +48 +48 +48 +48 +48 +--test]] + +dump(take(5, duplicate(1,2,3,4,5))) +--[[test +1 2 3 4 5 +1 2 3 4 5 +1 2 3 4 5 +1 2 3 4 5 +1 2 3 4 5 +--test]] + +print(xrepeat == duplicate) -- an alias +--[[test +true +--test]] + +print(replicate == duplicate) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- tabulate +-------------------------------------------------------------------------------- + +dump(take(5, tabulate(function(x) return 2 * x end))) +--[[test +0 +2 +4 +6 +8 +--test]] + +-------------------------------------------------------------------------------- +-- zeros +-------------------------------------------------------------------------------- + +dump(take(5, zeros())) +--[[test +0 +0 +0 +0 +0 +--test]] + +-------------------------------------------------------------------------------- +-- ones +-------------------------------------------------------------------------------- + +dump(take(5, ones())) +--[[test +1 +1 +1 +1 +1 +--test]] + +-------------------------------------------------------------------------------- +-- rands +-------------------------------------------------------------------------------- + +print(all(function(x) return x >= 0 and x < 1 end, take(5, rands()))) +--[[test +true +--test]] + +dump(take(5, rands(0))) +--[[test +error: empty interval +--test]] + +print(all(function(x) return math.floor(x) == x end, take(5, rands(10)))) +--[[test +true +--test]] + +print(all(function(x) return math.floor(x) == x end, take(5, rands(1024)))) +--[[test +true +--test]] + +dump(take(5, rands(0, 1))) +--[[test +0 +0 +0 +0 +0 +--test]] + +dump(take(5, rands(5, 6))) +--[[test +5 +5 +5 +5 +5 +--test]] + +print(all(function(x) return x >= 10 and x < 20 end, take(20, rands(10, 20)))) +--[[test +true +--test]] diff --git a/Data/DefaultContent/Libraries/luafun/tests/indexing.lua b/Data/DefaultContent/Libraries/luafun/tests/indexing.lua new file mode 100644 index 0000000..febc1ae --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/indexing.lua @@ -0,0 +1,83 @@ +-------------------------------------------------------------------------------- +-- index +-------------------------------------------------------------------------------- + +print(index(2, range(5))) +--[[test +2 +--test]] + +print(index(10, range(5))) +--[[test +nil +--test]] + +print(index(2, range(0))) +--[[test +nil +--test]] + +print(index("b", {"a", "b", "c", "d", "e"})) +--[[test +2 +--test]] + +print(index(1, enumerate({"a", "b", "c", "d", "e"}))) +--[[test +1 +--test]] + +print(index("b", "abcdef")) +--[[test +2 +--test]] + +print(index_of == index) -- an alias +--[[test +true +--test]] + +print(elem_index == index) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- indexes +-------------------------------------------------------------------------------- + +dump(indexes("a", {"a", "b", "c", "d", "e", "a", "b", "c", "d", "a", "a"})) +--[[test +1 +6 +10 +11 +--test]] + +dump(indexes("f", {"a", "b", "c", "d", "e", "a", "b", "c", "d", "a", "a"})) +--[[test +--test]] + +dump(indexes("f", {})) +--[[test +--test]] + +dump(indexes(1, enumerate({"a", "b", "c", "d", "e"}))) +--[[test +1 +--test]] + +print(indices == indexes) -- an alias +--[[test +true +--test]] + +print(elem_indexes == indexes) -- an alias +--[[test +true +--test]] + +print(elem_indices == indexes) -- an alias +--[[test +true +--test]] diff --git a/Data/DefaultContent/Libraries/luafun/tests/operators.lua b/Data/DefaultContent/Libraries/luafun/tests/operators.lua new file mode 100644 index 0000000..98ab7bb --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/operators.lua @@ -0,0 +1,322 @@ +-- +-- All these functions are fully covered by Lua tests. +-- This test just checks that all functions were defined correctly. +-- + +print(op == operator) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- Comparison operators +-------------------------------------------------------------------------------- + +local comparators = { 'le', 'lt', 'eq', 'ne', 'ge', 'gt' } +for _k, op in iter(comparators) do + print('op', op) + print('==') + print('num:') + print(operator[op](0, 1)) + print(operator[op](1, 0)) + print(operator[op](0, 0)) + print('str:') + print(operator[op]("abc", "cde")) + print(operator[op]("cde", "abc")) + print(operator[op]("abc", "abc")) + print('') +end +--[[test +op le +== +num: +true +false +true +str: +true +false +true + +op lt +== +num: +true +false +false +str: +true +false +false + +op eq +== +num: +false +false +true +str: +false +false +true + +op ne +== +num: +true +true +false +str: +true +true +false + +op ge +== +num: +false +true +true +str: +false +true +true + +op gt +== +num: +false +true +false +str: +false +true +false + +--test]] + +-------------------------------------------------------------------------------- +-- Arithmetic operators +-------------------------------------------------------------------------------- + +print(operator.add(-1.0, 1.0)) +print(operator.add(0, 0)) +print(operator.add(12, 2)) +--[[test +0 +0 +14 +--test]] + +print(operator.div(10, 2)) +print(operator.div(10, 3)) +print(operator.div(-10, 3)) +--[[test +5 +3.3333333333333 +-3.3333333333333 +--test]] + +print(operator.floordiv(10, 3)) +print(operator.floordiv(11, 3)) +print(operator.floordiv(12, 3)) +print(operator.floordiv(-10, 3)) +print(operator.floordiv(-11, 3)) +print(operator.floordiv(-12, 3)) +--[[test +3 +3 +4 +-4 +-4 +-4 +--test]] + +print(operator.intdiv(10, 3)) +print(operator.intdiv(11, 3)) +print(operator.intdiv(12, 3)) +print(operator.intdiv(-10, 3)) +print(operator.intdiv(-11, 3)) +print(operator.intdiv(-12, 3)) +--[[test +3 +3 +4 +-3 +-3 +-4 +--test]] + +print(operator.truediv(10, 3)) +print(operator.truediv(11, 3)) +print(operator.truediv(12, 3)) +print(operator.truediv(-10, 3)) +print(operator.truediv(-11, 3)) +print(operator.truediv(-12, 3)) +--[[test +3.3333333333333 +3.6666666666667 +4 +-3.3333333333333 +-3.6666666666667 +-4 +--test]] + +print(operator.mod(10, 2)) +print(operator.mod(10, 3)) +print(operator.mod(-10, 3)) +--[[test +0 +1 +2 +--test]] + +print(operator.mul(10, 0.1)) +print(operator.mul(0, 0)) +print(operator.mul(-1, -1)) +--[[test +1 +0 +1 +--test]] + +print(operator.neq(1)) +print(operator.neq(0) == 0) +print(operator.neq(-0) == 0) +print(operator.neq(-1)) +--[[test +-1 +true +true +1 +--test]] + +print(operator.unm(1)) +print(operator.unm(0) == 0) +print(operator.unm(-0) == 0) +print(operator.unm(-1)) +--[[test +-1 +true +true +1 +--test]] + +print(operator.pow(2, 3)) +print(operator.pow(0, 10)) +print(operator.pow(2, 0)) +--[[test +8 +0 +1 +--test]] + +print(operator.sub(2, 3)) +print(operator.sub(0, 10)) +print(operator.sub(2, 2)) +--[[test +-1 +-10 +0 +--test]] + +-------------------------------------------------------------------------------- +-- String operators +-------------------------------------------------------------------------------- + +print(operator.concat("aa", "bb")) +print(operator.concat("aa", "")) +print(operator.concat("", "bb")) +--[[test +aabb +aa +bb +--test]] + +print(operator.len("")) +print(operator.len("ab")) +print(operator.len("abcd")) +--[[test +0 +2 +4 +--test]] + +print(operator.length("")) +print(operator.length("ab")) +print(operator.length("abcd")) +--[[test +0 +2 +4 +--test]] + +---------------------------------------------------------------------------- +-- Logical operators +---------------------------------------------------------------------------- + +print(operator.land(true, true)) +print(operator.land(true, false)) +print(operator.land(false, true)) +print(operator.land(false, false)) +print(operator.land(1, 0)) +print(operator.land(0, 1)) +print(operator.land(1, 1)) +print(operator.land(0, 0)) +--[[test +true +false +false +false +0 +1 +1 +0 +--test]] + +print(operator.lor(true, true)) +print(operator.lor(true, false)) +print(operator.lor(false, true)) +print(operator.lor(false, false)) +print(operator.lor(1, 0)) +print(operator.lor(0, 1)) +print(operator.lor(1, 1)) +print(operator.lor(0, 0)) +--[[test +true +true +true +false +1 +0 +1 +0 +--test]] + +print(operator.lnot(true)) +print(operator.lnot(false)) +print(operator.lor(1)) +print(operator.lor(0)) +--[[test +false +true +1 +0 +--test]] + +print(operator.truth(true)) +print(operator.truth(false)) +print(operator.truth(1)) +print(operator.truth(0)) +print(operator.truth(nil)) +print(operator.truth("")) +print(operator.truth({})) +--[[test +true +false +true +true +false +true +true +--test]] diff --git a/Data/DefaultContent/Libraries/luafun/tests/reducing.lua b/Data/DefaultContent/Libraries/luafun/tests/reducing.lua new file mode 100644 index 0000000..8e4aaeb --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/reducing.lua @@ -0,0 +1,289 @@ +-------------------------------------------------------------------------------- +-- foldl +-------------------------------------------------------------------------------- + +print(foldl(function(acc, x) return acc + x end, 0, range(5))) +--[[test +15 +--test]] + +print(foldl(operator.add, 0, range(5))) +--[[test +15 +--test]] + +print(foldl(function(acc, x, y) return acc + x * y; end, 0, + zip(range(1, 5), {4, 3, 2, 1}))) +--[[test +20 +--test]] + +print(reduce == foldl) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- length +-------------------------------------------------------------------------------- + +print(length({"a", "b", "c", "d", "e"})) +--[[test +5 +--test]] + +print(length({})) +--[[test +0 +--test]] + +print(length(range(0))) +--[[test +0 +--test]] + +-------------------------------------------------------------------------------- +-- is_null +-------------------------------------------------------------------------------- + +print(is_null({"a", "b", "c", "d", "e"})) +--[[test +false +--test]] + +print(is_null({})) +--[[test +true +--test]] + +print(is_null(range(0))) +--[[test +true +--test]] + +local gen, init, state = range(5) +print(is_null(gen, init, state)) +dump(gen, init, state) +--[[test +false +1 +2 +3 +4 +5 +--test]] + +-------------------------------------------------------------------------------- +-- is_prefix_of +-------------------------------------------------------------------------------- + +print(is_prefix_of({"a"}, {"a", "b", "c"})) +--[[test +true +--test]] + +print(is_prefix_of({}, {"a", "b", "c"})) +--[[test +true +--test]] + +print(is_prefix_of({}, {})) +--[[test +true +--test]] + +print(is_prefix_of({"a"}, {})) +--[[test +false +--test]] + +print(is_prefix_of(range(5), range(6))) +--[[test +true +--test]] + +print(is_prefix_of(range(6), range(5))) +--[[test +false +--test]] + +-------------------------------------------------------------------------------- +-- all +-------------------------------------------------------------------------------- + +print(all(function(x) return x end, {true, true, true, true})) +--[[test +true +--test]] + +print(all(function(x) return x end, {true, true, true, false})) +--[[test +false +--test]] + +print(all(function(x) return x end, {})) +--[[test +true +--test]] + +print(every == all) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- any +-------------------------------------------------------------------------------- + +print(any(function(x) return x end, {false, false, false, false})) +--[[test +false +--test]] + +print(any(function(x) return x end, {false, false, false, true})) +--[[test +true +--test]] + +print(any(function(x) return x end, {})) +--[[test +false +--test]] + +print(some == any) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- sum +-------------------------------------------------------------------------------- + +print(sum(range(1, 5))) +--[[test +15 +--test]] + +print(sum(range(1, 5, 0.5))) +--[[test +27 +--test]] + +print(sum(range(0))) +--[[test +0 +--test]] + +-------------------------------------------------------------------------------- +-- product +-------------------------------------------------------------------------------- + +print(product(range(1, 5))) +--[[test +120 +--test]] + +print(product(range(1, 5, 0.5))) +--[[test +7087.5 +--test]] + +print(product(range(0))) +--[[test +1 +--test]] + + +-------------------------------------------------------------------------------- +-- min +-------------------------------------------------------------------------------- + +print(min(range(1, 10, 1))) +--[[test +1 +--test]] + +print(min({"f", "d", "c", "d", "e"})) +--[[test +c +--test]] + +print(min({})) +--[[test +error: min: iterator is empty +--test]] + +print(minimum == min) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- min_by +-------------------------------------------------------------------------------- + +function min_cmp(a, b) if -a < -b then return a else return b end end +--[[test +--test]] + +print(min_by(min_cmp, range(1, 10, 1))) +--[[test +10 +--test]] + +print(min_by(min_cmp, {})) +--[[test +error: min: iterator is empty +--test]] + +print(minimum_by == min_by) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- max +-------------------------------------------------------------------------------- + +print(max(range(1, 10, 1))) +--[[test +10 +--test]] + +print(max({"f", "d", "c", "d", "e"})) +--[[test +f +--test]] + +print(max({})) +--[[test +error: max: iterator is empty +--test]] + +print(maximum == max) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- max_by +-------------------------------------------------------------------------------- + +function max_cmp(a, b) if -a > -b then return a else return b end end +--[[test +--test]] + +print(max_by(max_cmp, range(1, 10, 1))) +--[[test +1 +--test]] + +print(max_by(max_cmp, {})) +--[[test +error: max: iterator is empty +--test]] + +print(maximum_by == maximum_by) -- an alias +--[[test +true +--test]] diff --git a/Data/DefaultContent/Libraries/luafun/tests/runtest b/Data/DefaultContent/Libraries/luafun/tests/runtest new file mode 100644 index 0000000..f6774f6 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/runtest @@ -0,0 +1,114 @@ +#!/usr/bin/env lua + +package.path = "../?.lua;"..package.path +require "fun" () +function dump(gen, init, state) each(print, gen, init, state) end + +local unpack = rawget(table, "unpack") or unpack +local loadstring = rawget(_G, "loadstring") or load + +function file_print(file, ...) + local n, i = select("#",...) + for i=1,n do + local x = select(i, ...) + if type(x) == "number" and math.floor(x) == math.ceil(x) then + -- A special hack for Lua 5.3: remove .0 for integer + x = string.match(select(i,...), '^-?%d+') + end + file:write(tostring(x)) + if i~=n then + file:write(' ') + end + end + file:write('\n') +end + +local globals = {} +setmetatable(_G, { + __newindex = function(t,k,v) + local info = debug.getinfo(2, "S") + if info.short_src:sub(1,7) ~= '[string' then + local file = info.short_src + local func = debug.getinfo(2, "n").name or "" + local line = info.linedefined + globals[file..':'..line..':'..k] = {file, line, func, k} + end + rawset(t, k, v) + end +}) + +local function process(test_name) + io.write("Testing ", test_name, "\n") + local new_name = test_name..".new" + local test_file = io.open(test_name, 'r') + local content = test_file:read("*a"); + test_file:close() + + local new_file = io.open(new_name, 'w') + + local prev_print = print + print = function(...) file_print(new_file, ...) end + + io.flush() + local expr + for expr in content:gmatch("(.-)%s*--%[%[test.-test%]%]") do + new_file:write(expr) + new_file:write("\n--[[test\n") + local res, err = loadstring(expr) + if res then + res, err = pcall(res, expr) + end + if not res then + new_file:write('error: ', err:match(".-:%d+:%s*(.*)"), "\n") + end + new_file:write("--test]]") + end + new_file:write("\n") + new_file:close() + + print = prev_print + + local r = os.execute(string.format('diff -U4 "%s" "%s" 2>&1', + test_name, new_name)) + if r then + os.remove(new_name) + return true + else + return false + end +end + +if #arg <= 0 then + io.write("Usage: runtest *.lua", "\n") + os.exit(1) +end + +local failed, i = {} +for i=1,#arg,1 do + local test_name = arg[i] + if not process(test_name) then + table.insert(failed, test_name) + end +end + +if #failed > 0 then + io.write("\n") + io.write("Failed tests:", "\n") + for _k,test_name in ipairs(failed) do + io.write(" ", test_name, "\n") + end + io.write("\n", "Please review *.new files and update tests", "\n") +end + +if next(globals) then + io.write("\n") + io.write("Some global variables have been declared by mistake:", "\n") + for k, pollution in pairs(globals) do + local file, line, func, var = unpack(pollution) + io.write(file..":"..line.." function "..func.."() = var '"..var.."'", "\n") + end + io.write("\n", "Please declare them with the local statement", "\n") +elseif #failed == 0 then + io.write("All tests have passed!", "\n") + os.exit(0) +end diff --git a/Data/DefaultContent/Libraries/luafun/tests/slicing.lua b/Data/DefaultContent/Libraries/luafun/tests/slicing.lua new file mode 100644 index 0000000..c4678c4 --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/slicing.lua @@ -0,0 +1,339 @@ +-------------------------------------------------------------------------------- +-- nth +-------------------------------------------------------------------------------- + +print(nth(2, range(5))) +--[[test +2 +--test]] + +print(nth(10, range(5))) +--[[test +nil +--test]] + +print(nth(2, range(0))) +--[[test +nil +--test]] + +print(nth(2, {"a", "b", "c", "d", "e"})) +--[[test +b +--test]] + +print(nth(2, enumerate({"a", "b", "c", "d", "e"}))) +--[[test +2 b +--test]] + +print(nth(1, "abcdef")) +--[[test +a +--test]] + +print(nth(2, "abcdef")) +--[[test +b +--test]] + +print(nth(6, "abcdef")) +--[[test +f +--test]] + +print(nth(0, "abcdef")) +--[[test +error: invalid first argument to nth +--test]] + +print(nth(7, "abcdef")) +--[[test +nil +--test]] + +-------------------------------------------------------------------------------- +-- head +-------------------------------------------------------------------------------- + +print(head({"a", "b", "c", "d", "e"})) +--[[test +a +--test]] + +print(head({})) +--[[test +error: head: iterator is empty +--test]] + +print(head(range(0))) +--[[test +error: head: iterator is empty +--test]] + +print(head(enumerate({"a", "b"}))) +--[[test +1 a +--test]] + +print(car == head) -- an alias +--[[test +true +--test]] + +-------------------------------------------------------------------------------- +-- tail +-------------------------------------------------------------------------------- + +dump(tail({"a", "b", "c", "d", "e"})) +--[[test +b +c +d +e +--test]] + +dump(tail({})) +--[[test +--test]] + +dump(tail(range(0))) +--[[test +--test]] + +dump(tail(enumerate({"a", "b"}))) +--[[test +2 b +--test]] + +print(cdr == tail) -- an alias +--[[test +true +--test]] + + +-------------------------------------------------------------------------------- +-- take_n +-------------------------------------------------------------------------------- + +dump(take_n(0, duplicate(48))) +--[[test +--test]] + +dump(take_n(5, range(0))) +--[[test +--test]] + +dump(take_n(1, duplicate(48))) +--[[test +48 +--test]] + +dump(take_n(5, duplicate(48))) +--[[test +48 +48 +48 +48 +48 +--test]] + +dump(take_n(5, enumerate(duplicate('x')))) +--[[test +1 x +2 x +3 x +4 x +5 x +--test]] + +-------------------------------------------------------------------------------- +-- take_while +-------------------------------------------------------------------------------- + +dump(take_while(function(x) return x < 5 end, range(10))) +--[[test +1 +2 +3 +4 +--test]] + +dump(take_while(function(x) return x < 5 end, range(0))) +--[[test +--test]] + +dump(take_while(function(x) return x > 100 end, range(10))) +--[[test +--test]] + +dump(take_while(function(i, a) return i ~=a end, enumerate({5, 2, 1, 3, 4}))) +--[[test +1 5 +--test]] + +-------------------------------------------------------------------------------- +-- take +-------------------------------------------------------------------------------- + +dump(take(function(x) return x < 5 end, range(10))) +--[[test +1 +2 +3 +4 +--test]] + +dump(take(5, duplicate(48))) +--[[test +48 +48 +48 +48 +48 +--test]] + +-------------------------------------------------------------------------------- +-- drop_n +-------------------------------------------------------------------------------- + +dump(drop_n(5, range(10))) +--[[test +6 +7 +8 +9 +10 +--test]] + +dump(drop_n(0, range(5))) +--[[test +1 +2 +3 +4 +5 +--test]] + +dump(drop_n(5, range(0))) +--[[test +--test]] + +dump(drop_n(2, enumerate({'a', 'b', 'c', 'd', 'e'}))) +--[[test +3 c +4 d +5 e +--test]] + +-------------------------------------------------------------------------------- +-- drop_while +-------------------------------------------------------------------------------- + +dump(drop_while(function(x) return x < 5 end, range(10))) +--[[test +5 +6 +7 +8 +9 +10 +--test]] + +dump(drop_while(function(x) return x < 5 end, range(0))) +--[[test +--test]] + +dump(drop_while(function(x) return x > 100 end, range(10))) +--[[test +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +--test]] + +dump(drop_while(function(i, a) return i ~=a end, enumerate({5, 2, 1, 3, 4}))) +--[[test +2 2 +3 1 +4 3 +5 4 +--test]] + +dump(drop_while(function(i, a) return i ~=a end, + zip({1, 2, 3, 4, 5}, {5, 4, 3, 2, 1}))) +--[[test +3 3 +4 2 +5 1 +--test]] + +-------------------------------------------------------------------------------- +-- drop +-------------------------------------------------------------------------------- + +dump(drop(5, range(10))) +--[[test +6 +7 +8 +9 +10 +--test]] + +dump(drop(function(x) return x < 5 end, range(10))) +--[[test +5 +6 +7 +8 +9 +10 +--test]] + + +-------------------------------------------------------------------------------- +-- span +-------------------------------------------------------------------------------- + +dump(zip(span(function(x) return x < 5 end, range(10)))) +--[[test +1 5 +2 6 +3 7 +4 8 +--test]] + +dump(zip(span(5, range(10)))) +--[[test +1 6 +2 7 +3 8 +4 9 +5 10 +--test]] + +dump(zip(span(function(x) return x < 5 end, range(0)))) +--[[test +--test]] + +dump(zip(span(function(x) return x < 5 end, range(5)))) +--[[test +1 5 +--test]] + +print(split == span) -- an alias +--[[test +true +--test]] + +print(split_at == span) -- an alias +--[[test +true +--test]] diff --git a/Data/DefaultContent/Libraries/luafun/tests/transformations.lua b/Data/DefaultContent/Libraries/luafun/tests/transformations.lua new file mode 100644 index 0000000..b4fddab --- /dev/null +++ b/Data/DefaultContent/Libraries/luafun/tests/transformations.lua @@ -0,0 +1,107 @@ +-------------------------------------------------------------------------------- +-- map +-------------------------------------------------------------------------------- + +fun = function(...) return 'map', ... end + +dump(map(fun, range(0))) +--[[test +--test]] + + +dump(map(fun, range(4))) +--[[test +map 1 +map 2 +map 3 +map 4 +--test]] + +dump(map(fun, enumerate({"a", "b", "c", "d", "e"}))) +--[[test +map 1 a +map 2 b +map 3 c +map 4 d +map 5 e +--test]] + +dump(map(function(x) return 2 * x end, range(4))) +--[[test +2 +4 +6 +8 +--test]] + +fun = nil +--[[test +--test]] + +-------------------------------------------------------------------------------- +-- enumerate +-------------------------------------------------------------------------------- + +dump(enumerate({"a", "b", "c", "d", "e"})) +--[[test +1 a +2 b +3 c +4 d +5 e +--test]] + +dump(enumerate(enumerate(enumerate({"a", "b", "c", "d", "e"})))) +--[[test +1 1 1 a +2 2 2 b +3 3 3 c +4 4 4 d +5 5 5 e +--test]] + +dump(enumerate(zip({"one", "two", "three", "four", "five"}, + {"a", "b", "c", "d", "e"}))) +--[[test +1 one a +2 two b +3 three c +4 four d +5 five e +--test]] + +-------------------------------------------------------------------------------- +-- intersperse +-------------------------------------------------------------------------------- + +dump(intersperse("x", {})) + +dump(intersperse("x", {"a", "b", "c", "d", "e"})) +--[[test +a +x +b +x +c +x +d +x +e +x +--test]] + +dump(intersperse("x", {"a", "b", "c", "d", "e", "f"})) +--[[test +a +x +b +x +c +x +d +x +e +x +f +x +--test]] diff --git a/Data/DefaultContent/Libraries/md5.lua/.travis.yml b/Data/DefaultContent/Libraries/md5.lua/.travis.yml new file mode 100644 index 0000000..90bd434 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/.travis.yml @@ -0,0 +1,34 @@ +language: python +sudo: false + +env: + - LUA="lua=5.1" + - LUA="lua=5.2" + - LUA="lua=5.3" + - LUA="luajit=2.0" + - LUA="luajit=2.1" + +before_install: + - pip install hererocks + - hererocks lua_install -r^ --$LUA + - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH + +install: + - luarocks install busted + - luarocks install luacov + - luarocks install luacov-coveralls + +script: + - busted --verbose --coverage + +after_success: + - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install + +branches: + except: + - gh-pages + +notifications: + email: + on_success: change + on_failure: always diff --git a/Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md b/Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md new file mode 100644 index 0000000..a48c47a --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md @@ -0,0 +1,5 @@ + +# 1.1.0 + +* Fixes error with long strings in Lua 5.1 (@pgimeno) +* Adds incremental mode (@pgimeno) diff --git a/Data/DefaultContent/Libraries/md5.lua/MIT-LICENSE.txt b/Data/DefaultContent/Libraries/md5.lua/MIT-LICENSE.txt new file mode 100644 index 0000000..1630e47 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/MIT-LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Data/DefaultContent/Libraries/md5.lua/README.md b/Data/DefaultContent/Libraries/md5.lua/README.md new file mode 100644 index 0000000..ee7bbd8 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/README.md @@ -0,0 +1,62 @@ +md5.lua [![Build Status](https://travis-ci.org/kikito/md5.lua.svg)](https://travis-ci.org/kikito/md5.lua) +========================================================================================================= + +This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1. + +It implements md5.sum and md5.sumhex like the [kernel project md5 package](http://www.keplerproject.org/md5/), but it's done completely in Lua, with no dependencies on other libs or C files. + +Usage +===== + +Simple example: + + local md5 = require 'md5' + + local md5_as_data = md5.sum(message) -- returns raw bytes + local md5_as_hex = md5.sumhexa(message) -- returns a hex string + local md5_as_hex2 = md5.tohex(md5_as_data) -- returns the same string as md5_as_hex + +Incremental example (for computing md5 of streams, or big files which have to be loaded in chunks - new since 1.1.0): + + local m = md5.new() + m:update('some bytes') + m:update('some more bytes') + m:update('etc') + return md5.tohex(m:finish()) + +Credits +======= + +This is a cleanup of an implementation by Adam Baldwin - https://gist.github.com/evilpacket/3647908 + +Which in turn was a mix of the bitwise lib, http://luaforge.net/projects/bit/ by hanzhao (`abrash_han - at - hotmail.com`), +and http://equi4.com/md5/md5calc.lua, by Equi 4 Software. + +Lua 5.2 and LuaJIT compatibility by [Positive07](https://github.com/kikito/md5.lua/pull/2) + +A very important fix and the incremental variant by [pgimeno](https://github.com/kikito/md5.lua/pull/10) + + +License +======= + +This library, as well as all the previous ones in which is based, is released under the MIT license (See license file for details). + +Specs +===== + +The specs for this library are implemented with [busted](http://ovinelabs.com/busted/). In order to run them, install busted and then: + + cd path/to/where/the/spec/folder/is + busted + +Install +======= + +Either copy the file or using luarocks: + + luarocks install --server=http://luarocks.org/manifests/kikito md5 + + + + diff --git a/Data/DefaultContent/Libraries/md5.lua/md5.lua b/Data/DefaultContent/Libraries/md5.lua/md5.lua new file mode 100644 index 0000000..5e73ba6 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/md5.lua @@ -0,0 +1,396 @@ +local md5 = { + _VERSION = "md5.lua 1.1.0", + _DESCRIPTION = "MD5 computation in Lua (5.1-3, LuaJIT)", + _URL = "https://github.com/kikito/md5.lua", + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +-- bit lib implementions + +local char, byte, format, rep, sub = + string.char, string.byte, string.format, string.rep, string.sub +local bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift + +local ok, bit = pcall(require, 'bit') +if ok then + bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift = bit.bor, bit.band, bit.bnot, bit.bxor, bit.rshift, bit.lshift +else + ok, bit = pcall(require, 'bit32') + + if ok then + + bit_not = bit.bnot + + local tobit = function(n) + return n <= 0x7fffffff and n or -(bit_not(n) + 1) + end + + local normalize = function(f) + return function(a,b) return tobit(f(tobit(a), tobit(b))) end + end + + bit_or, bit_and, bit_xor = normalize(bit.bor), normalize(bit.band), normalize(bit.bxor) + bit_rshift, bit_lshift = normalize(bit.rshift), normalize(bit.lshift) + + else + + local function tbl2number(tbl) + local result = 0 + local power = 1 + for i = 1, #tbl do + result = result + tbl[i] * power + power = power * 2 + end + return result + end + + local function expand(t1, t2) + local big, small = t1, t2 + if(#big < #small) then + big, small = small, big + end + -- expand small + for i = #small + 1, #big do + small[i] = 0 + end + end + + local to_bits -- needs to be declared before bit_not + + bit_not = function(n) + local tbl = to_bits(n) + local size = math.max(#tbl, 32) + for i = 1, size do + if(tbl[i] == 1) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + return tbl2number(tbl) + end + + -- defined as local above + to_bits = function (n) + if(n < 0) then + -- negative + return to_bits(bit_not(math.abs(n)) + 1) + end + -- to bits table + local tbl = {} + local cnt = 1 + local last + while n > 0 do + last = n % 2 + tbl[cnt] = last + n = (n-last)/2 + cnt = cnt + 1 + end + + return tbl + end + + bit_or = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i]== 0 and tbl_n[i] == 0) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + + return tbl2number(tbl) + end + + bit_and = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i]== 0 or tbl_n[i] == 0) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + + return tbl2number(tbl) + end + + bit_xor = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i] ~= tbl_n[i]) then + tbl[i] = 1 + else + tbl[i] = 0 + end + end + + return tbl2number(tbl) + end + + bit_rshift = function(n, bits) + local high_bit = 0 + if(n < 0) then + -- negative + n = bit_not(math.abs(n)) + 1 + high_bit = 0x80000000 + end + + local floor = math.floor + + for i=1, bits do + n = n/2 + n = bit_or(floor(n), high_bit) + end + return floor(n) + end + + bit_lshift = function(n, bits) + if(n < 0) then + -- negative + n = bit_not(math.abs(n)) + 1 + end + + for i=1, bits do + n = n*2 + end + return bit_and(n, 0xFFFFFFFF) + end + end +end + +-- convert little-endian 32-bit int to a 4-char string +local function lei2str(i) + local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end + return f(0)..f(8)..f(16)..f(24) +end + +-- convert raw string to big-endian int +local function str2bei(s) + local v=0 + for i=1, #s do + v = v * 256 + byte(s, i) + end + return v +end + +-- convert raw string to little-endian int +local function str2lei(s) + local v=0 + for i = #s,1,-1 do + v = v*256 + byte(s, i) + end + return v +end + +-- cut up a string in little-endian ints of given size +local function cut_le_str(s,...) + local o, r = 1, {} + local args = {...} + for i=1, #args do + table.insert(r, str2lei(sub(s, o, o + args[i] - 1))) + o = o + args[i] + end + return r +end + +local swap = function (w) return str2bei(lei2str(w)) end + +-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) +-- 10/02/2001 jcw@equi4.com + +local CONSTS = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 +} + +local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end +local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end +local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end +local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end +local z=function (ff,a,b,c,d,x,s,ac) + a=bit_and(a+ff(b,c,d)+x+ac,0xFFFFFFFF) + -- be *very* careful that left shift does not cause rounding! + return bit_or(bit_lshift(bit_and(a,bit_rshift(0xFFFFFFFF,s)),s),bit_rshift(a,32-s))+b +end + +local function transform(A,B,C,D,X) + local a,b,c,d=A,B,C,D + local t=CONSTS + + a=z(f,a,b,c,d,X[ 0], 7,t[ 1]) + d=z(f,d,a,b,c,X[ 1],12,t[ 2]) + c=z(f,c,d,a,b,X[ 2],17,t[ 3]) + b=z(f,b,c,d,a,X[ 3],22,t[ 4]) + a=z(f,a,b,c,d,X[ 4], 7,t[ 5]) + d=z(f,d,a,b,c,X[ 5],12,t[ 6]) + c=z(f,c,d,a,b,X[ 6],17,t[ 7]) + b=z(f,b,c,d,a,X[ 7],22,t[ 8]) + a=z(f,a,b,c,d,X[ 8], 7,t[ 9]) + d=z(f,d,a,b,c,X[ 9],12,t[10]) + c=z(f,c,d,a,b,X[10],17,t[11]) + b=z(f,b,c,d,a,X[11],22,t[12]) + a=z(f,a,b,c,d,X[12], 7,t[13]) + d=z(f,d,a,b,c,X[13],12,t[14]) + c=z(f,c,d,a,b,X[14],17,t[15]) + b=z(f,b,c,d,a,X[15],22,t[16]) + + a=z(g,a,b,c,d,X[ 1], 5,t[17]) + d=z(g,d,a,b,c,X[ 6], 9,t[18]) + c=z(g,c,d,a,b,X[11],14,t[19]) + b=z(g,b,c,d,a,X[ 0],20,t[20]) + a=z(g,a,b,c,d,X[ 5], 5,t[21]) + d=z(g,d,a,b,c,X[10], 9,t[22]) + c=z(g,c,d,a,b,X[15],14,t[23]) + b=z(g,b,c,d,a,X[ 4],20,t[24]) + a=z(g,a,b,c,d,X[ 9], 5,t[25]) + d=z(g,d,a,b,c,X[14], 9,t[26]) + c=z(g,c,d,a,b,X[ 3],14,t[27]) + b=z(g,b,c,d,a,X[ 8],20,t[28]) + a=z(g,a,b,c,d,X[13], 5,t[29]) + d=z(g,d,a,b,c,X[ 2], 9,t[30]) + c=z(g,c,d,a,b,X[ 7],14,t[31]) + b=z(g,b,c,d,a,X[12],20,t[32]) + + a=z(h,a,b,c,d,X[ 5], 4,t[33]) + d=z(h,d,a,b,c,X[ 8],11,t[34]) + c=z(h,c,d,a,b,X[11],16,t[35]) + b=z(h,b,c,d,a,X[14],23,t[36]) + a=z(h,a,b,c,d,X[ 1], 4,t[37]) + d=z(h,d,a,b,c,X[ 4],11,t[38]) + c=z(h,c,d,a,b,X[ 7],16,t[39]) + b=z(h,b,c,d,a,X[10],23,t[40]) + a=z(h,a,b,c,d,X[13], 4,t[41]) + d=z(h,d,a,b,c,X[ 0],11,t[42]) + c=z(h,c,d,a,b,X[ 3],16,t[43]) + b=z(h,b,c,d,a,X[ 6],23,t[44]) + a=z(h,a,b,c,d,X[ 9], 4,t[45]) + d=z(h,d,a,b,c,X[12],11,t[46]) + c=z(h,c,d,a,b,X[15],16,t[47]) + b=z(h,b,c,d,a,X[ 2],23,t[48]) + + a=z(i,a,b,c,d,X[ 0], 6,t[49]) + d=z(i,d,a,b,c,X[ 7],10,t[50]) + c=z(i,c,d,a,b,X[14],15,t[51]) + b=z(i,b,c,d,a,X[ 5],21,t[52]) + a=z(i,a,b,c,d,X[12], 6,t[53]) + d=z(i,d,a,b,c,X[ 3],10,t[54]) + c=z(i,c,d,a,b,X[10],15,t[55]) + b=z(i,b,c,d,a,X[ 1],21,t[56]) + a=z(i,a,b,c,d,X[ 8], 6,t[57]) + d=z(i,d,a,b,c,X[15],10,t[58]) + c=z(i,c,d,a,b,X[ 6],15,t[59]) + b=z(i,b,c,d,a,X[13],21,t[60]) + a=z(i,a,b,c,d,X[ 4], 6,t[61]) + d=z(i,d,a,b,c,X[11],10,t[62]) + c=z(i,c,d,a,b,X[ 2],15,t[63]) + b=z(i,b,c,d,a,X[ 9],21,t[64]) + + return bit_and(A+a,0xFFFFFFFF),bit_and(B+b,0xFFFFFFFF), + bit_and(C+c,0xFFFFFFFF),bit_and(D+d,0xFFFFFFFF) +end + +---------------------------------------------------------------- + +local function md5_update(self, s) + self.pos = self.pos + #s + s = self.buf .. s + for ii = 1, #s - 63, 64 do + local X = cut_le_str(sub(s,ii,ii+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) + assert(#X == 16) + X[0] = table.remove(X,1) -- zero based! + self.a,self.b,self.c,self.d = transform(self.a,self.b,self.c,self.d,X) + end + self.buf = sub(s, math.floor(#s/64)*64 + 1, #s) + return self +end + +local function md5_finish(self) + local msgLen = self.pos + local padLen = 56 - msgLen % 64 + + if msgLen % 64 > 56 then padLen = padLen + 64 end + + if padLen == 0 then padLen = 64 end + + local s = char(128) .. rep(char(0),padLen-1) .. lei2str(bit_and(8*msgLen, 0xFFFFFFFF)) .. lei2str(math.floor(msgLen/0x20000000)) + md5_update(self, s) + + assert(self.pos % 64 == 0) + return lei2str(self.a) .. lei2str(self.b) .. lei2str(self.c) .. lei2str(self.d) +end + +---------------------------------------------------------------- + +function md5.new() + return { a = CONSTS[65], b = CONSTS[66], c = CONSTS[67], d = CONSTS[68], + pos = 0, + buf = '', + update = md5_update, + finish = md5_finish } +end + +function md5.tohex(s) + return format("%08x%08x%08x%08x", str2bei(sub(s, 1, 4)), str2bei(sub(s, 5, 8)), str2bei(sub(s, 9, 12)), str2bei(sub(s, 13, 16))) +end + +function md5.sum(s) + return md5.new():update(s):finish() +end + +function md5.sumhexa(s) + return md5.tohex(md5.sum(s)) +end + +return md5 diff --git a/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec new file mode 100644 index 0000000..4103148 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec @@ -0,0 +1,21 @@ +package = "md5" +version = "1.0-0" +source = { + url = "https://github.com/kikito/md5.lua/archive/v1.0.0.tar.gz", + dir = "md5.lua-1.0.0" +} +description = { + summary = "MD5 sum in pure Lua, with no C and no external dependencies", + detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1", + homepage = "https://github.com/kikito/md5.lua", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + md5 = "md5.lua" + } +} diff --git a/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec new file mode 100644 index 0000000..f9f5203 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec @@ -0,0 +1,21 @@ +package = "md5" +version = "1.0-1" +source = { + url = "https://github.com/kikito/md5.lua/archive/v1.0.1.tar.gz", + dir = "md5.lua-1.0.1" +} +description = { + summary = "MD5 sum in pure Lua, with no C and no external dependencies", + detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1", + homepage = "https://github.com/kikito/md5.lua", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + md5 = "md5.lua" + } +} diff --git a/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec new file mode 100644 index 0000000..c8034f9 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec @@ -0,0 +1,21 @@ +package = "md5" +version = "1.0-2" +source = { + url = "https://github.com/kikito/md5.lua/archive/v1.0.2.tar.gz", + dir = "md5.lua-1.0.2" +} +description = { + summary = "MD5 sum in pure Lua, with no C and no external dependencies", + detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1", + homepage = "https://github.com/kikito/md5.lua", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + md5 = "md5.lua" + } +} diff --git a/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec new file mode 100644 index 0000000..ef1b392 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec @@ -0,0 +1,21 @@ +package = "md5" +version = "1.1-0" +source = { + url = "https://github.com/kikito/md5.lua/archive/v1.1.0.tar.gz", + dir = "md5.lua-1.1.0" +} +description = { + summary = "MD5 sum in pure Lua, with no C and no external dependencies", + detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1", + homepage = "https://github.com/kikito/md5.lua", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + md5 = "md5.lua" + } +} diff --git a/Data/DefaultContent/Libraries/md5.lua/spec/md5_spec.lua b/Data/DefaultContent/Libraries/md5.lua/spec/md5_spec.lua new file mode 100644 index 0000000..69dde39 --- /dev/null +++ b/Data/DefaultContent/Libraries/md5.lua/spec/md5_spec.lua @@ -0,0 +1,40 @@ +local md5 = require('md5') + +local function hex2bin(hex) + local result, _ = hex:gsub('..', function(hexval) + return string.char(tonumber(hexval, 16)) + end) + return result +end + +describe('md5', function() + describe('md5.sumhexa', function() + it('works', function() + assert.equal(md5.sumhexa("asdf"), '912ec803b2ce49e4a541068d495ab570') + assert.equal(md5.sumhexa('The quick brown fox jumps over the lazy dog'), '9e107d9d372bb6826bd81d3542a419d6') + assert.equal(md5.sumhexa('The quick brown fox jumps over the lazy dog.'), 'e4d909c290d0fb1ca068ffaddf22cbd0') + assert.equal(md5.sumhexa(''), 'd41d8cd98f00b204e9800998ecf8427e') + assert.equal(md5.sumhexa(('1'):rep(824)), 'a126fd3611ab8d9b7e8a3384e2fa78a0') + assert.equal(md5.sumhexa(('1'):rep(1528)), '3750b6a29d923b633e05d6ae76895664') + local state = md5.new() + state:update('Hello') + state:update(', World!') + assert.equal(md5.tohex(state:finish()), '65a8e27d8879283831b664bd8b7f0ad4') + end) + end) + + describe('md5.sum', function() + it('works', function() + assert.equal(md5.sum("asdf"), hex2bin '912ec803b2ce49e4a541068d495ab570') + assert.equal(md5.sum('The quick brown fox jumps over the lazy dog'), hex2bin '9e107d9d372bb6826bd81d3542a419d6') + assert.equal(md5.sum('The quick brown fox jumps over the lazy dog.'), hex2bin 'e4d909c290d0fb1ca068ffaddf22cbd0') + assert.equal(md5.sum(''), hex2bin 'd41d8cd98f00b204e9800998ecf8427e') + assert.equal(md5.sum(('1'):rep(824)), hex2bin 'a126fd3611ab8d9b7e8a3384e2fa78a0') + assert.equal(md5.sum(('1'):rep(1528)), hex2bin '3750b6a29d923b633e05d6ae76895664') + local state = md5.new() + state:update('Hello') + state:update(', World!') + assert.equal(state:finish(), hex2bin '65a8e27d8879283831b664bd8b7f0ad4') + end) + end) +end) diff --git a/Data/DefaultContent/Libraries/middleclass/.travis.yml b/Data/DefaultContent/Libraries/middleclass/.travis.yml new file mode 100644 index 0000000..53998d6 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/.travis.yml @@ -0,0 +1,36 @@ +language: python +sudo: false + +env: + - LUA="lua=5.1" + - LUA="lua=5.2" + - LUA="lua=5.3" + - LUA="luajit=2.0" + - LUA="luajit=2.1" + +before_install: + - pip install hererocks + - hererocks lua_install -r^ --$LUA + - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH + +install: + - luarocks install luacheck + - luarocks install busted + - luarocks install luacov + - luarocks install luacov-coveralls + +script: + - luacheck --no-unused-args --std max+busted *.lua spec + - busted --verbose --coverage + +after_success: + - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install + +branches: + except: + - gh-pages + +notifications: + email: + on_success: change + on_failure: always diff --git a/Data/DefaultContent/Libraries/middleclass/CHANGELOG.md b/Data/DefaultContent/Libraries/middleclass/CHANGELOG.md new file mode 100644 index 0000000..5f8b93a --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/CHANGELOG.md @@ -0,0 +1,55 @@ +middleclass changelog +==================== + +# Version 4.1.1 + +* Fixed a bug in which `static` values which evaluated to `false` were not available + in subclasses (#51, thanks @qaisjp for the patch!) +* `isInstanceOf` does not throw an error any more when its first parameter is a + primitive (#55) (This effectively undoes the change introduced in 4.1.0) + + +# Version 4.1.0 + +* Simplifies implementation of `isInstanceOf` and `isSubclassOf`. They will now raise an error if their first + parameter (the `self`) isn't an instance or a class respectively. + +# Version 4.0.0 + +* Unified the method and metamethod lookup into a single algorithm +* Added the capacity of setting up the `__index` metamethod in classes +* Removed global `Object` (classes created with `class()` have no superclass now) +* Removed default method `Class:implements()` +* Renamed several internal functions + +# Version 3.2.0 + +* Changed the way metamethods were handled to fix certain bugs (un-stubbed metamethods could not be inherited) + +# Version 3.1.0 + +* Added Lua 5.3 metamethod support (`__band`, `__bor`, `__bxor`, `__shl`, `__bnot`) + +# Version 3.0.1 + +* Added `__len`, `__ipairs` and `__pairs` metamethods for Lua 5.2 + +# Version 3.0 + +* Anything that behaves reasonably like a class can be a class (no internal list of classes) +* The `class` global function is now just the return value of `require +'middleclass'`. It is a callable table, but works exactly as before. +* The global variable `Object` becomes `class.Object` +* The global function `instanceOf` becomes `class.Object.isInstanceOf`. Parameter order is reversed. +* The global function `subclassOf` becomes `class.Object.static.isSubclassOf`. Parameter order is reversed. +* The global function `implements` becomes `class.Object.static.implements`. Parameter order is reversed. +* Specs have been translated from telescope to busted + +# Version 2.0 + +* Static methods are now separated from instance methods +* class.superclass has now become class.super +* It's now possible to do class.subclasses +* middleclass is now a single file; init.lua has dissapeared +* license is changed from BSD to MIT. License included in source FTW + diff --git a/Data/DefaultContent/Libraries/middleclass/MIT-LICENSE.txt b/Data/DefaultContent/Libraries/middleclass/MIT-LICENSE.txt new file mode 100644 index 0000000..525287a --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/MIT-LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2011 Enrique García Cota + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Data/DefaultContent/Libraries/middleclass/README.md b/Data/DefaultContent/Libraries/middleclass/README.md new file mode 100644 index 0000000..fc1153b --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/README.md @@ -0,0 +1,80 @@ +middleclass +=========== + +[![Build Status](https://travis-ci.org/kikito/middleclass.png?branch=master)](https://travis-ci.org/kikito/middleclass) +[![Coverage Status](https://coveralls.io/repos/kikito/middleclass/badge.svg?branch=master&service=github)](https://coveralls.io/github/kikito/middleclass?branch=master) + +A simple OOP library for Lua. It has inheritance, metamethods (operators), class variables and weak mixin support. + +Quick Look +========== + +```lua +local class = require 'middleclass' + +local Fruit = class('Fruit') -- 'Fruit' is the class' name + +function Fruit:initialize(sweetness) + self.sweetness = sweetness +end + +Fruit.static.sweetness_threshold = 5 -- class variable (also admits methods) + +function Fruit:isSweet() + return self.sweetness > Fruit.sweetness_threshold +end + +local Lemon = class('Lemon', Fruit) -- subclassing + +function Lemon:initialize() + Fruit.initialize(self, 1) -- invoking the superclass' initializer +end + +local lemon = Lemon:new() + +print(lemon:isSweet()) -- false +``` + +Documentation +============= + +See the [github wiki page](https://github.com/kikito/middleclass/wiki) for examples & documentation. + +You can read the `CHANGELOG.md` file to see what has changed on each version of this library. + +If you need help updating to a new middleclass version, read `UPDATING.md`. + +Installation +============ + +Just copy the middleclass.lua file wherever you want it (for example on a lib/ folder). Then write this in any Lua file where you want to use it: + +```lua +local class = require 'middleclass' +``` + +Specs +===== + +This project uses [busted](http://olivinelabs.com/busted/) for its specs. If you want to run the specs, you will have to install it first. Then just execute the following: + +```bash +cd /folder/where/the/spec/folder/is +busted +``` + +Performance tests +================= + +Middleclass also comes with a small performance test suite. Just run the following command: + +```bash +lua performance/run.lua +``` + +License +======= + +Middleclass is distributed under the MIT license. + + diff --git a/Data/DefaultContent/Libraries/middleclass/UPDATING.md b/Data/DefaultContent/Libraries/middleclass/UPDATING.md new file mode 100644 index 0000000..83855c9 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/UPDATING.md @@ -0,0 +1,69 @@ +Updating from 3.x to 4.x +======================== + +In middleclass 4.0 there is no global `Object` class any more. Classes created with `class()` don't have a superclass any more. +If you need a global `Object` class, you must create it explicitly and then use it when creating new classes: + +```lua +local Object = class('Object') + +... + +local MyClass = class('MyClass', Object) +``` + +If you are using a library which depends on the internal implementation of middleclass they might not work with middleclass 4.0. You might need to update those other libraries. + +Middleclass 4.0 comes with support for `__index` metamethod support. If your library manipulated the classes' `__instanceDict` internal attribute, you might do the same thing now using `__index` instead. + +Also note that the class method `:implements` has been removed. + +Updating from 2.x to 3.x +======================== + +Middleclass used to expose several global variables on the main scope. It does not do that anymore. + +`class` is now returned by `require 'middleclass'`, and it is not set globally. So you can do this: + +```lua +local class = require 'middleclass' +local MyClass = class('MyClass') -- works as before +``` + +`Object` is not a global variable any more. But you can get it from `class.Object` + +```lua +local class = require 'middleclass' +local Object = class.Object + +print(Object) -- prints 'class Object' +``` + +The public functions `instanceOf`, `subclassOf` and `includes` have been replaced by `Object.isInstanceOf`, `Object.static.isSubclassOf` and `Object.static.includes`. + +Prior to 3.x: + +```lua +instanceOf(MyClass, obj) +subclassOf(Object, aClass) +includes(aMixin, aClass) +``` + +Since 3.x: + +```lua +obj:isInstanceOf(MyClass) +aClass:isSubclassOf(Object) +aClass:includes(aMixin) +``` + +The 3.x code snippet will throw an error if `obj` is not an object, or if `aClass` is not a class (since they will not implement `isInstanceOf`, `isSubclassOf` or `includes`). +If you are unsure of whether `obj` and `aClass` are an object or a class, you can use the methods in `Object`. They are prepared to work with random types, not just classes and instances: + +```lua +Object.isInstanceOf(obj, MyClass) +Object.isSubclassOf(aClass, Object) +Object.includes(aClass, aMixin) +``` + +Notice that the parameter order is not the same now as it was in 2.x. Also note the change in naming: `isInstanceOf` instead of `instanceOf`, and `isSubclassOf` instead of `subclassOf`. diff --git a/Data/DefaultContent/Libraries/middleclass/middleclass.lua b/Data/DefaultContent/Libraries/middleclass/middleclass.lua new file mode 100644 index 0000000..7e36bcd --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/middleclass.lua @@ -0,0 +1,183 @@ +local middleclass = { + _VERSION = 'middleclass v4.1.1', + _DESCRIPTION = 'Object Orientation for Lua', + _URL = 'https://github.com/kikito/middleclass', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2011 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +local function _createIndexWrapper(aClass, f) + if f == nil then + return aClass.__instanceDict + else + return function(self, name) + local value = aClass.__instanceDict[name] + + if value ~= nil then + return value + elseif type(f) == "function" then + return (f(self, name)) + else + return f[name] + end + end + end +end + +local function _propagateInstanceMethod(aClass, name, f) + f = name == "__index" and _createIndexWrapper(aClass, f) or f + aClass.__instanceDict[name] = f + + for subclass in pairs(aClass.subclasses) do + if rawget(subclass.__declaredMethods, name) == nil then + _propagateInstanceMethod(subclass, name, f) + end + end +end + +local function _declareInstanceMethod(aClass, name, f) + aClass.__declaredMethods[name] = f + + if f == nil and aClass.super then + f = aClass.super.__instanceDict[name] + end + + _propagateInstanceMethod(aClass, name, f) +end + +local function _tostring(self) return "class " .. self.name end +local function _call(self, ...) return self:new(...) end + +local function _createClass(name, super) + local dict = {} + dict.__index = dict + + local aClass = { name = name, super = super, static = {}, + __instanceDict = dict, __declaredMethods = {}, + subclasses = setmetatable({}, {__mode='k'}) } + + if super then + setmetatable(aClass.static, { + __index = function(_,k) + local result = rawget(dict,k) + if result == nil then + return super.static[k] + end + return result + end + }) + else + setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end }) + end + + setmetatable(aClass, { __index = aClass.static, __tostring = _tostring, + __call = _call, __newindex = _declareInstanceMethod }) + + return aClass +end + +local function _includeMixin(aClass, mixin) + assert(type(mixin) == 'table', "mixin must be a table") + + for name,method in pairs(mixin) do + if name ~= "included" and name ~= "static" then aClass[name] = method end + end + + for name,method in pairs(mixin.static or {}) do + aClass.static[name] = method + end + + if type(mixin.included)=="function" then mixin:included(aClass) end + return aClass +end + +local DefaultMixin = { + __tostring = function(self) return "instance of " .. tostring(self.class) end, + + initialize = function(self, ...) end, + + isInstanceOf = function(self, aClass) + return type(aClass) == 'table' + and type(self) == 'table' + and (self.class == aClass + or type(self.class) == 'table' + and type(self.class.isSubclassOf) == 'function' + and self.class:isSubclassOf(aClass)) + end, + + static = { + allocate = function(self) + assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'") + return setmetatable({ class = self }, self.__instanceDict) + end, + + new = function(self, ...) + assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'") + local instance = self:allocate() + instance:initialize(...) + return instance + end, + + subclass = function(self, name) + assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'") + assert(type(name) == "string", "You must provide a name(string) for your class") + + local subclass = _createClass(name, self) + + for methodName, f in pairs(self.__instanceDict) do + _propagateInstanceMethod(subclass, methodName, f) + end + subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end + + self.subclasses[subclass] = true + self:subclassed(subclass) + + return subclass + end, + + subclassed = function(self, other) end, + + isSubclassOf = function(self, other) + return type(other) == 'table' and + type(self.super) == 'table' and + ( self.super == other or self.super:isSubclassOf(other) ) + end, + + include = function(self, ...) + assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'") + for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end + return self + end + } +} + +function middleclass.class(name, super) + assert(type(name) == 'string', "A name (string) is needed for the new class") + return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin) +end + +setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end }) + +return middleclass diff --git a/Data/DefaultContent/Libraries/middleclass/performance/run.lua b/Data/DefaultContent/Libraries/middleclass/performance/run.lua new file mode 100644 index 0000000..8d8ba47 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/performance/run.lua @@ -0,0 +1,43 @@ +local class = require 'middleclass' + +time = require 'performance/time' + +time('class creation', function() + local A = class('A') +end) + +local A = class('A') + +time('instance creation', function() + local a = A:new() +end) + +function A:foo() + return 1 +end + +local a = A:new() + +time('instance method invocation', function() + a:foo() +end) + +local B = class('B', A) + +local b = B:new() + +time('inherited method invocation', function() + b:foo() +end) + +function A.static:bar() + return 2 +end + +time('class method invocation', function() + A:bar() +end) + +time('inherited class method invocation', function() + B:bar() +end) diff --git a/Data/DefaultContent/Libraries/middleclass/performance/time.lua b/Data/DefaultContent/Libraries/middleclass/performance/time.lua new file mode 100644 index 0000000..dd02455 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/performance/time.lua @@ -0,0 +1,13 @@ +return function(title, f) + + collectgarbage() + + local startTime = os.clock() + + for i=0,10000 do f() end + + local endTime = os.clock() + + print( title, endTime - startTime ) + +end diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.0-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.0-0.rockspec new file mode 100644 index 0000000..f9ec58c --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.0-0.rockspec @@ -0,0 +1,21 @@ +package = "middleclass" +version = "3.0-0" +source = { + url = "https://github.com/kikito/middleclass/archive/v3.0.0.tar.gz", + dir = "middleclass-3.0.0" +} +description = { + summary = "A simple OOP library for Lua", + detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support", + homepage = "https://github.com/kikito/middleclass", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + middleclass = "middleclass.lua" + } +} diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.1-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.1-0.rockspec new file mode 100644 index 0000000..24a233e --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.1-0.rockspec @@ -0,0 +1,21 @@ +package = "middleclass" +version = "3.1-0" +source = { + url = "https://github.com/kikito/middleclass/archive/v3.1.0.tar.gz", + dir = "middleclass-3.1.0" +} +description = { + summary = "A simple OOP library for Lua", + detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support", + homepage = "https://github.com/kikito/middleclass", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + middleclass = "middleclass.lua" + } +} diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.2-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.2-0.rockspec new file mode 100644 index 0000000..03e3b30 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.2-0.rockspec @@ -0,0 +1,21 @@ +package = "middleclass" +version = "3.2-0" +source = { + url = "https://github.com/kikito/middleclass/archive/v3.2.0.tar.gz", + dir = "middleclass-3.2.0" +} +description = { + summary = "A simple OOP library for Lua", + detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support", + homepage = "https://github.com/kikito/middleclass", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + middleclass = "middleclass.lua" + } +} diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.0-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.0-0.rockspec new file mode 100644 index 0000000..517984e --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.0-0.rockspec @@ -0,0 +1,21 @@ +package = "middleclass" +version = "4.0-0" +source = { + url = "https://github.com/kikito/middleclass/archive/v4.0.0.tar.gz", + dir = "middleclass-4.0.0" +} +description = { + summary = "A simple OOP library for Lua", + detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support", + homepage = "https://github.com/kikito/middleclass", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + middleclass = "middleclass.lua" + } +} diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1-0.rockspec new file mode 100644 index 0000000..dc710e9 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1-0.rockspec @@ -0,0 +1,21 @@ +package = "middleclass" +version = "4.1-0" +source = { + url = "https://github.com/kikito/middleclass/archive/v4.1.0.tar.gz", + dir = "middleclass-4.1.0" +} +description = { + summary = "A simple OOP library for Lua", + detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support", + homepage = "https://github.com/kikito/middleclass", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + middleclass = "middleclass.lua" + } +} diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1.1-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1.1-0.rockspec new file mode 100644 index 0000000..ddaacd9 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1.1-0.rockspec @@ -0,0 +1,21 @@ +package = "middleclass" +version = "4.1.1-0" +source = { + url = "https://github.com/kikito/middleclass/archive/v4.1.1.tar.gz", + dir = "middleclass-4.1.1" +} +description = { + summary = "A simple OOP library for Lua", + detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support", + homepage = "https://github.com/kikito/middleclass", + license = "MIT" +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + middleclass = "middleclass.lua" + } +} diff --git a/Data/DefaultContent/Libraries/middleclass/spec/class_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/class_spec.lua new file mode 100644 index 0000000..144cb9f --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/spec/class_spec.lua @@ -0,0 +1,28 @@ +local class = require 'middleclass' + +describe('class()', function() + + describe('when given no params', function() + it('it throws an error', function() + assert.error(class) + end) + end) + + describe('when given a name', function() + it('the resulting class has the correct name and Object as its superclass', function() + local TheClass = class('TheClass') + assert.equal(TheClass.name, 'TheClass') + assert.is_nil(TheClass.super) + end) + end) + + describe('when given a name and a superclass', function() + it('the resulting class has the correct name and superclass', function() + local TheSuperClass = class('TheSuperClass') + local TheSubClass = class('TheSubClass', TheSuperClass) + assert.equal(TheSubClass.name, 'TheSubClass') + assert.equal(TheSubClass.super, TheSuperClass) + end) + end) + +end) diff --git a/Data/DefaultContent/Libraries/middleclass/spec/classes_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/classes_spec.lua new file mode 100644 index 0000000..7942f18 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/spec/classes_spec.lua @@ -0,0 +1,138 @@ +local class = require 'middleclass' + +describe('A Class', function() + + describe('Default stuff', function() + + local AClass + + before_each(function() + AClass = class('AClass') + end) + + describe('name', function() + it('is correctly set', function() + assert.equal(AClass.name, 'AClass') + end) + end) + + describe('tostring', function() + it('returns "class *name*"', function() + assert.equal(tostring(AClass), 'class AClass') + end) + end) + + describe('()', function() + it('returns an object, like Class:new()', function() + local obj = AClass() + assert.equal(obj.class, AClass) + end) + end) + + describe('include', function() + it('throws an error when used without the :', function() + assert.error(function() AClass.include() end) + end) + it('throws an error when passed a non-table:', function() + assert.error(function() AClass:include(1) end) + end) + end) + + describe('subclass', function() + + it('throws an error when used without the :', function() + assert.error(function() AClass.subclass() end) + end) + + it('throws an error when no name is given', function() + assert.error( function() AClass:subclass() end) + end) + + describe('when given a subclass name', function() + + local SubClass + + before_each(function() + function AClass.static:subclassed(other) self.static.child = other end + SubClass = AClass:subclass('SubClass') + end) + + it('it returns a class with the correct name', function() + assert.equal(SubClass.name, 'SubClass') + end) + + it('it returns a class with the correct superclass', function() + assert.equal(SubClass.super, AClass) + end) + + it('it invokes the subclassed hook method', function() + assert.equal(SubClass, AClass.child) + end) + + it('it includes the subclass in the list of subclasses', function() + assert.is_true(AClass.subclasses[SubClass]) + end) + + end) + + end) + + end) + + + + describe('attributes', function() + + local A, B + + before_each(function() + A = class('A') + A.static.foo = 'foo' + + B = class('B', A) + end) + + it('are available after being initialized', function() + assert.equal(A.foo, 'foo') + end) + + it('are available for subclasses', function() + assert.equal(B.foo, 'foo') + end) + + it('are overridable by subclasses, without affecting the superclasses', function() + B.static.foo = 'chunky bacon' + assert.equal(B.foo, 'chunky bacon') + assert.equal(A.foo, 'foo') + end) + + end) + + describe('methods', function() + + local A, B + + before_each(function() + A = class('A') + function A.static:foo() return 'foo' end + + B = class('B', A) + end) + + it('are available after being initialized', function() + assert.equal(A:foo(), 'foo') + end) + + it('are available for subclasses', function() + assert.equal(B:foo(), 'foo') + end) + + it('are overridable by subclasses, without affecting the superclasses', function() + function B.static:foo() return 'chunky bacon' end + assert.equal(B:foo(), 'chunky bacon') + assert.equal(A:foo(), 'foo') + end) + + end) + +end) diff --git a/Data/DefaultContent/Libraries/middleclass/spec/default_methods_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/default_methods_spec.lua new file mode 100644 index 0000000..91fd9b8 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/spec/default_methods_spec.lua @@ -0,0 +1,236 @@ +local class = require 'middleclass' + +describe('Default methods', function() + local Object + before_each(function() + Object = class('Object') + end) + + describe('name', function() + it('is correctly set', function() + assert.equal(Object.name, 'Object') + end) + end) + + describe('tostring', function() + it('returns "class Object"', function() + assert.equal(tostring(Object), 'class Object') + end) + end) + + describe('()', function() + it('returns an object, like Object:new()', function() + local obj = Object() + assert.is_true(obj:isInstanceOf(Object)) + end) + end) + + describe('subclass', function() + + it('throws an error when used without the :', function() + assert.error(function() Object.subclass() end) + end) + + it('throws an error when no name is given', function() + assert.error( function() Object:subclass() end) + end) + + describe('when given a class name', function() + + local SubClass + + before_each(function() + SubClass = Object:subclass('SubClass') + end) + + it('it returns a class with the correct name', function() + assert.equal(SubClass.name, 'SubClass') + end) + + it('it returns a class with the correct superclass', function() + assert.equal(SubClass.super, Object) + end) + + it('it includes the subclass in the list of subclasses', function() + assert.is_true(Object.subclasses[SubClass]) + end) + + end) + + end) + + describe('instance creation', function() + + local SubClass + + before_each(function() + SubClass = class('SubClass') + function SubClass:initialize() self.mark=true end + end) + + describe('allocate', function() + + it('allocates instances properly', function() + local instance = SubClass:allocate() + assert.equal(instance.class, SubClass) + assert.equal(tostring(instance), "instance of " .. tostring(SubClass)) + end) + + it('throws an error when used without the :', function() + assert.error(Object.allocate) + end) + + it('does not call the initializer', function() + local allocated = SubClass:allocate() + assert.is_nil(allocated.mark) + end) + + it('can be overriden', function() + + local previousAllocate = SubClass.static.allocate + + function SubClass.static:allocate() + local instance = previousAllocate(SubClass) + instance.mark = true + return instance + end + + local allocated = SubClass:allocate() + assert.is_true(allocated.mark) + end) + + end) + + describe('new', function() + + it('initializes instances properly', function() + local instance = SubClass:new() + assert.equal(instance.class, SubClass) + end) + + it('throws an error when used without the :', function() + assert.error(SubClass.new) + end) + + it('calls the initializer', function() + local initialized = SubClass:new() + assert.is_true(initialized.mark) + end) + + end) + + describe('isInstanceOf', function() + + describe('primitives', function() + local o = Object:new() + local primitives = {nil, 1, 'hello', {}, function() end, Object:new()} + + describe('used as classes', function() + for _,primitive in pairs(primitives) do + local theType = type(primitive) + it('object:isInstanceOf(, '.. theType ..') returns false', function() + assert.is_falsy(o:isInstanceOf(primitive)) + end) + end + end) + + describe('used as instances', function() + for _,primitive in pairs(primitives) do + local theType = type(primitive) + it('Object.isInstanceOf('.. theType ..', Object) returns false without error', function() + assert.is_falsy(Object.isInstanceOf(primitive, Object)) + end) + end + end) + + + end) + + describe('An instance', function() + local Class1 = class('Class1') + local Class2 = class('Class2', Class1) + local Class3 = class('Class3', Class2) + local UnrelatedClass = class('Unrelated') + + local o1, o2, o3 = Class1:new(), Class2:new(), Class3:new() + + it('isInstanceOf its class', function() + assert.is_true(o1:isInstanceOf(Class1)) + assert.is_true(o2:isInstanceOf(Class2)) + assert.is_true(o3:isInstanceOf(Class3)) + end) + + it('is instanceOf its class\' superclasses', function() + assert.is_true(o2:isInstanceOf(Class1)) + assert.is_true(o3:isInstanceOf(Class1)) + assert.is_true(o3:isInstanceOf(Class2)) + end) + + it('is not instanceOf its class\' subclasses', function() + assert.is_false(o1:isInstanceOf(Class2)) + assert.is_false(o1:isInstanceOf(Class3)) + assert.is_false(o2:isInstanceOf(Class3)) + end) + + it('is not instanceOf an unrelated class', function() + assert.is_false(o1:isInstanceOf(UnrelatedClass)) + assert.is_false(o2:isInstanceOf(UnrelatedClass)) + assert.is_false(o3:isInstanceOf(UnrelatedClass)) + end) + + end) + + end) + + end) + + describe('isSubclassOf', function() + + it('returns false for instances', function() + assert.is_false(Object:isSubclassOf(Object:new())) + end) + + describe('on primitives', function() + local primitives = {nil, 1, 'hello', {}, function() end} + + for _,primitive in pairs(primitives) do + local theType = type(primitive) + it('returns false for ' .. theType, function() + assert.is_false(Object:isSubclassOf(primitive)) + end) + end + + end) + + describe('Any class (except Object)', function() + local Class1 = class('Class1') + local Class2 = class('Class2', Class1) + local Class3 = class('Class3', Class2) + local UnrelatedClass = class('Unrelated') + + it('is subclassOf its direct superclass', function() + assert.is_true(Class2:isSubclassOf(Class1)) + assert.is_true(Class3:isSubclassOf(Class2)) + end) + + it('is subclassOf its ancestors', function() + assert.is_true(Class3:isSubclassOf(Class1)) + end) + + it('is a subclassOf its class\' subclasses', function() + assert.is_true(Class2:isSubclassOf(Class1)) + assert.is_true(Class3:isSubclassOf(Class1)) + assert.is_true(Class3:isSubclassOf(Class2)) + end) + + it('is not a subclassOf an unrelated class', function() + assert.is_false(Class1:isSubclassOf(UnrelatedClass)) + assert.is_false(Class2:isSubclassOf(UnrelatedClass)) + assert.is_false(Class3:isSubclassOf(UnrelatedClass)) + end) + + end) + end) +end) + + diff --git a/Data/DefaultContent/Libraries/middleclass/spec/instances_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/instances_spec.lua new file mode 100644 index 0000000..d9ac52c --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/spec/instances_spec.lua @@ -0,0 +1,65 @@ +local class = require 'middleclass' + +describe('An instance', function() + + describe('attributes', function() + + local Person + + before_each(function() + Person = class('Person') + function Person:initialize(name) + self.name = name + end + end) + + it('are available in the instance after being initialized', function() + local bob = Person:new('bob') + assert.equal(bob.name, 'bob') + end) + + it('are available in the instance after being initialized by a superclass', function() + local AgedPerson = class('AgedPerson', Person) + function AgedPerson:initialize(name, age) + Person.initialize(self, name) + self.age = age + end + + local pete = AgedPerson:new('pete', 31) + assert.equal(pete.name, 'pete') + assert.equal(pete.age, 31) + end) + + end) + + describe('methods', function() + + local A, B, a, b + + before_each(function() + A = class('A') + function A:overridden() return 'foo' end + function A:regular() return 'regular' end + + B = class('B', A) + function B:overridden() return 'bar' end + + a = A:new() + b = B:new() + end) + + it('are available for any instance', function() + assert.equal(a:overridden(), 'foo') + end) + + it('are inheritable', function() + assert.equal(b:regular(), 'regular') + end) + + it('are overridable', function() + assert.equal(b:overridden(), 'bar') + end) + + end) + +end) diff --git a/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_2.lua b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_2.lua new file mode 100644 index 0000000..2ea6c9b --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_2.lua @@ -0,0 +1,85 @@ +local class = require 'middleclass' + +local it = require('busted').it +local describe = require('busted').describe +local before_each = require('busted').before_each +local assert = require('busted').assert + +describe('Lua 5.2 Metamethods', function() + local Vector, v + before_each(function() + Vector= class('Vector') + function Vector.initialize(a,x,y,z) a.x, a.y, a.z = x,y,z end + function Vector.__eq(a,b) return a.x==b.x and a.y==b.y and a.z==b.z end + + function Vector.__len(a) return 3 end + function Vector.__pairs(a) + local t = {x=a.x,y=a.y,z=a.z} + return coroutine.wrap(function() + for k,val in pairs(t) do + coroutine.yield(k,val) + end + end) + end + function Vector.__ipairs(a) + local t = {a.x,a.y,a.z} + return coroutine.wrap(function() + for k,val in ipairs(t) do + coroutine.yield(k,val) + end + end) + end + + v = Vector:new(1,2,3) + end) + + it('implements __len', function() + assert.equal(#v, 3) + end) + + it('implements __pairs',function() + local output = {} + for k,val in pairs(v) do + output[k] = val + end + assert.are.same(output,{x=1,y=2,z=3}) + end) + + it('implements __ipairs',function() + local output = {} + for _,i in ipairs(v) do + output[#output+1] = i + end + assert.are.same(output,{1,2,3}) + end) + + describe('Inherited Metamethods', function() + local Vector2, v2 + before_each(function() + Vector2= class('Vector2', Vector) + function Vector2:initialize(x,y,z) Vector.initialize(self,x,y,z) end + + v2 = Vector2:new(1,2,3) + end) + + it('implements __len', function() + assert.equal(#v2, 3) + end) + + it('implements __pairs',function() + local output = {} + for k,val in pairs(v2) do + output[k] = val + end + assert.are.same(output,{x=1,y=2,z=3}) + end) + + it('implements __ipairs',function() + local output = {} + for _,i in ipairs(v2) do + output[#output+1] = i + end + assert.are.same(output,{1,2,3}) + end) + end) +end) diff --git a/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_3.lua b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_3.lua new file mode 100644 index 0000000..e74f6d7 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_3.lua @@ -0,0 +1,106 @@ +local class = require 'middleclass' + +local it = require('busted').it +local describe = require('busted').describe +local before_each = require('busted').before_each +local assert = require('busted').assert + +describe('Lua 5.3 Metamethods', function() + local Vector, v, last_gc + before_each(function() + Vector= class('Vector') + function Vector.initialize(a,x,y,z) a.x, a.y, a.z = x,y,z end + function Vector.__eq(a,b) return a.x==b.x and a.y==b.y and a.z==b.z end + function Vector.__pairs(a) + local t = {x=a.x,y=a.y,z=a.z} + return coroutine.wrap(function() + for k,val in pairs(t) do + coroutine.yield(k,val) + end + end) + end + function Vector.__len(a) return 3 end + + function Vector.__gc(a) last_gc = {a.class.name, a.x, a.y, a.z} end + function Vector.__band(a,n) return a.class:new(a.x & n, a.y & n, a.z & n) end + function Vector.__bor(a,n) return a.class:new(a.x | n, a.y | n, a.z | n) end + function Vector.__bxor(a,n) return a.class:new(a.x ~ n, a.y ~ n, a.z ~ n) end + function Vector.__shl(a,n) return a.class:new(a.x << n, a.y << n, a.z << n) end + function Vector.__shr(a,n) return a.class:new(a.x >> n, a.y >> n, a.z >> n) end + function Vector.__bnot(a) return a.class:new(~a.x, ~a.y, ~a.z) end + + v = Vector:new(1,2,3) + end) + + it('implements __gc', function() + collectgarbage() + v = nil + collectgarbage() + assert.are.same(last_gc, {"Vector",1,2,3}) + end) + + it('implements __band', function() + assert.equal(v & 1, Vector(1,0,1)) + end) + + it('implements __bor', function() + assert.equal(v | 0, Vector(1,2,3)) + end) + + it('implements __bxor', function() + assert.equal(v | 1, Vector(1,3,3)) + end) + + it('implements __shl', function() + assert.equal(v << 1, Vector(2,4,6)) + end) + + it('implements __shr', function() + assert.equal(v >> 1, Vector(0,1,1)) + end) + + it('implements __bnot', function() + assert.equal(~v, Vector(-2,-3,-4)) + end) + + describe('Inherited Metamethods', function() + local Vector2, v2 + before_each(function() + Vector2= class('Vector2', Vector) + function Vector2:initialize(x,y,z) Vector.initialize(self,x,y,z) end + + v2 = Vector2:new(1,2,3) + end) + + it('implements __gc', function() + collectgarbage() + v2 = nil + collectgarbage() + assert.are.same(last_gc, {"Vector2",1,2,3}) + end) + + it('implements __band', function() + assert.equal(v2 & 1, Vector2(1,0,1)) + end) + + it('implements __bor', function() + assert.equal(v2 | 0, Vector2(1,2,3)) + end) + + it('implements __bxor', function() + assert.equal(v2 | 1, Vector2(1,3,3)) + end) + + it('implements __shl', function() + assert.equal(v2 << 1, Vector2(2,4,6)) + end) + + it('implements __shr', function() + assert.equal(v2 >> 1, Vector2(0,1,1)) + end) + + it('implements __bnot', function() + assert.equal(~v2, Vector2(-2,-3,-4)) + end) + end) +end) diff --git a/Data/DefaultContent/Libraries/middleclass/spec/metamethods_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_spec.lua new file mode 100644 index 0000000..73bf883 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_spec.lua @@ -0,0 +1,317 @@ +local class = require 'middleclass' + +local function is_lua_5_2_compatible() + return type(rawlen) == 'function' +end + +local function is_lua_5_3_compatible() + return type(string.unpack) == 'function' +end + +if is_lua_5_2_compatible() then + require 'spec/metamethods_lua_5_2' +end + +if is_lua_5_3_compatible() then + require 'spec.metamethods_lua_5_3' +end + +describe('Metamethods', function() + describe('Custom Metamethods', function() + local Vector, v, w + before_each(function() + Vector= class('Vector') + function Vector.initialize(a,x,y,z) a.x, a.y, a.z = x,y,z end + function Vector.__tostring(a) return a.class.name .. '[' .. a.x .. ',' .. a.y .. ',' .. a.z .. ']' end + function Vector.__eq(a,b) return a.x==b.x and a.y==b.y and a.z==b.z end + function Vector.__lt(a,b) return a() < b() end + function Vector.__le(a,b) return a() <= b() end + function Vector.__add(a,b) return a.class:new(a.x+b.x, a.y+b.y ,a.z+b.z) end + function Vector.__sub(a,b) return a.class:new(a.x-b.x, a.y-b.y, a.z-b.z) end + function Vector.__div(a,s) return a.class:new(a.x/s, a.y/s, a.z/s) end + function Vector.__unm(a) return a.class:new(-a.x, -a.y, -a.z) end + function Vector.__concat(a,b) return a.x*b.x+a.y*b.y+a.z*b.z end + function Vector.__call(a) return math.sqrt(a.x*a.x+a.y*a.y+a.z*a.z) end + function Vector.__pow(a,b) + return a.class:new(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x) + end + function Vector.__mul(a,b) + if type(b)=="number" then return a.class:new(a.x*b, a.y*b, a.z*b) end + if type(a)=="number" then return b.class:new(a*b.x, a*b.y, a*b.z) end + end + Vector.__metatable = "metatable of a vector" + Vector.__mode = "k" + + v = Vector:new(1,2,3) + w = Vector:new(2,4,6) + end) + + it('implements __tostring', function() + assert.equal(tostring(v), "Vector[1,2,3]") + end) + + it('implements __eq', function() + assert.equal(v, v) + end) + + it('implements __lt', function() + assert.is_true(v < w) + end) + + it('implements __le', function() + assert.is_true(v <= w) + end) + + it('implements __add', function() + assert.equal(v+w, Vector(3,6,9)) + end) + + it('implements __sub', function() + assert.equal(w-v, Vector(1,2,3)) + end) + + it('implements __div', function() + assert.equal(w/2, Vector(1,2,3)) + end) + + it('implements __concat', function() + assert.equal(v..w, 28) + end) + + it('implements __call', function() + assert.equal(v(), math.sqrt(14)) + end) + + it('implements __pow', function() + assert.equal(v^w, Vector(0,0,0)) + end) + + it('implements __mul', function() + assert.equal(4*v, Vector(4,8,12)) + end) + + it('implements __metatable', function() + assert.equal("metatable of a vector", getmetatable(v)) + end) + + it('implements __mode', function() + v[{}] = true + collectgarbage() + for k in pairs(v) do assert.not_table(k) end + end) + + --[[ + it('implements __index', function() + assert.equal(b[1], 3) + end) + --]] + + describe('Inherited Metamethods', function() + local Vector2, v2, w2 + before_each(function() + Vector2= class('Vector2', Vector) + function Vector2:initialize(x,y,z) Vector.initialize(self,x,y,z) end + + v2 = Vector2:new(1,2,3) + w2 = Vector2:new(2,4,6) + end) + + it('implements __tostring', function() + assert.equal(tostring(v2), "Vector2[1,2,3]") + end) + + it('implements __eq', function() + assert.equal(v2, v2) + end) + + it('implements __lt', function() + assert.is_true(v2 < w2) + end) + + it('implements __le', function() + assert.is_true(v2 <= w2) + end) + + it('implements __add', function() + assert.equal(v2+w2, Vector2(3,6,9)) + end) + + it('implements __sub', function() + assert.equal(w2-v2, Vector2(1,2,3)) + end) + + it('implements __div', function() + assert.equal(w2/2, Vector2(1,2,3)) + end) + + it('implements __concat', function() + assert.equal(v2..w2, 28) + end) + + it('implements __call', function() + assert.equal(v2(), math.sqrt(14)) + end) + + it('implements __pow', function() + assert.equal(v2^w2, Vector2(0,0,0)) + end) + + it('implements __mul', function() + assert.equal(4*v2, Vector2(4,8,12)) + end) + + it('implements __metatable', function() + assert.equal("metatable of a vector", getmetatable(v2)) + end) + + it('implements __mode', function() + v2[{}] = true + collectgarbage() + for k in pairs(v2) do assert.not_table(k) end + end) + + it('allows inheriting further', function() + local Vector3 = class('Vector3', Vector2) + local v3 = Vector3(1,2,3) + local w3 = Vector3(3,4,5) + assert.equal(v3+w3, Vector3(4,6,8)) + end) + + describe('Updates', function() + it('overrides __add', function() + Vector2.__add = function(a, b) return Vector.__add(a, b)/2 end + assert.equal(v2+w2, Vector2(1.5,3,4.5)) + end) + + it('updates __add', function() + Vector.__add = Vector.__sub + assert.equal(v2+w2, Vector2(-1,-2,-3)) + end) + + it('does not update __add after overriding', function() + Vector2.__add = function(a, b) return Vector.__add(a, b)/2 end + Vector.__add = Vector.__sub + assert.equal(v2+w2, Vector2(-0.5,-1,-1.5)) + end) + + it('reverts __add override', function() + Vector2.__add = function(a, b) return Vector.__add(a, b)/2 end + Vector2.__add = nil + assert.equal(v2+w2, Vector2(3,6,9)) + end) + end) + end) + end) + + describe('Custom __index and __newindex', function() + describe('Tables', function() + local Proxy, fallback, p + before_each(function() + Proxy = class('Proxy') + fallback = {foo = 'bar', common = 'fallback'} + Proxy.__index = fallback + Proxy.__newindex = fallback + Proxy.common = 'class' + p = Proxy() + end) + + it('uses __index', function() + assert.equal(p.foo, 'bar') + end) + + it('does not use __index when field exists in class', function() + assert.equal(p.common, 'class') + end) + + it('uses __newindex', function() + p.key = 'value' + assert.equal(fallback.key, 'value') + end) + + it('uses __newindex when field exists in class', function() + p.common = 'value' + assert.equal(p.common, 'class') + assert.equal(Proxy.common, 'class') + assert.equal(fallback.common, 'value') + end) + end) + + describe('Functions', function() + local Namespace, Rectangle, r + before_each(function() + Namespace = class('Namespace') + function Namespace:__index(name) + local getter = self.class[name.."Getter"] + if getter then return getter(self) end + end + function Namespace:__newindex(name, value) + local setter = self.class[name.."Setter"] + if setter then setter(self, value) else rawset(self, name, value) end + end + Rectangle = class('Rectangle', Namespace) + function Rectangle:initialize(x, y, scale) + self._scale, self.x, self.y = 1, x, y + self.scale = scale + end + function Rectangle:scaleGetter() return self._scale end + function Rectangle:scaleSetter(v) + self.x = self.x*v/self._scale + self.y = self.y*v/self._scale + self._scale = v + end + function Rectangle:areaGetter() return self.x * self.y end + r = Rectangle(3, 4, 2) + end) + + it('uses setter', function() + assert.equal(r.x, 6) + assert.equal(r.y, 8) + r.scale = 3 + assert.equal(r.x, 9) + assert.equal(r.y, 12) + end) + + it('uses getters', function() + assert.equal(r.scale, 2) + assert.equal(r.area, 48) + end) + + it('updates inherited __index', function() + function Namespace.__index() return 42 end + assert.equal(r.area, 42) + function Rectangle.__index() return 24 end + assert.equal(r.area, 24) + function Namespace.__index() return 96 end + assert.equal(r.area, 24) + Rectangle.__index = nil + assert.equal(r.area, 96) + end) + end) + end) + + describe('Default Metamethods', function() + + local Peter, peter + + before_each(function() + Peter = class('Peter') + peter = Peter() + end) + + describe('A Class', function() + it('has a call metamethod properly set', function() + assert.is_true(peter:isInstanceOf(Peter)) + end) + it('has a tostring metamethod properly set', function() + assert.equal(tostring(Peter), 'class Peter') + end) + end) + + describe('An instance', function() + it('has a tostring metamethod, returning a different result from Object.__tostring', function() + assert.equal(tostring(peter), 'instance of class Peter') + end) + end) + end) + +end) diff --git a/Data/DefaultContent/Libraries/middleclass/spec/mixins_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/mixins_spec.lua new file mode 100644 index 0000000..ef592a1 --- /dev/null +++ b/Data/DefaultContent/Libraries/middleclass/spec/mixins_spec.lua @@ -0,0 +1,53 @@ +local class = require 'middleclass' + +describe('A Mixin', function() + + local Mixin1, Mixin2, Class1, Class2 + + before_each(function() + Mixin1, Mixin2 = {},{} + + function Mixin1:included(theClass) theClass.includesMixin1 = true end + function Mixin1:foo() return 'foo' end + function Mixin1:bar() return 'bar' end + Mixin1.static = {} + Mixin1.static.bazzz = function() return 'bazzz' end + + + function Mixin2:baz() return 'baz' end + + Class1 = class('Class1'):include(Mixin1, Mixin2) + function Class1:foo() return 'foo1' end + + Class2 = class('Class2', Class1) + function Class2:bar2() return 'bar2' end + end) + + it('invokes the "included" method when included', function() + assert.is_true(Class1.includesMixin1) + end) + + it('has all its functions (except "included") copied to its target class', function() + assert.equal(Class1:bar(), 'bar') + assert.is_nil(Class1.included) + end) + + it('makes its functions available to subclasses', function() + assert.equal(Class2:baz(), 'baz') + end) + + it('allows overriding of methods in the same class', function() + assert.equal(Class2:foo(), 'foo1') + end) + + it('allows overriding of methods on subclasses', function() + assert.equal(Class2:bar2(), 'bar2') + end) + + it('makes new static methods available in classes', function() + assert.equal(Class1:bazzz(), 'bazzz') + assert.equal(Class2:bazzz(), 'bazzz') + end) + +end) + diff --git a/Data/DefaultContent/Libraries/socket/README.txt b/Data/DefaultContent/Libraries/socket/README.txt new file mode 100644 index 0000000..7f61184 --- /dev/null +++ b/Data/DefaultContent/Libraries/socket/README.txt @@ -0,0 +1 @@ +https://github.com/diegonehab/luasocket \ No newline at end of file diff --git a/Data/DefaultContent/Libraries/socket/core.dll b/Data/DefaultContent/Libraries/socket/core.dll new file mode 100644 index 0000000..9febf20 Binary files /dev/null and b/Data/DefaultContent/Libraries/socket/core.dll differ -- cgit v1.1-26-g67d0