├── .busted ├── .editorconfig ├── .github └── workflows │ ├── luacheck.yml │ └── unix_build.yml ├── .gitignore ├── .luacheckrc ├── .luacov ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── appveyor.yml ├── config.ld ├── docs ├── classes │ ├── pl.Date.html │ ├── pl.List.html │ ├── pl.Map.html │ ├── pl.MultiMap.html │ ├── pl.OrderedMap.html │ └── pl.Set.html ├── examples │ ├── seesubst.lua.html │ ├── sipscan.lua.html │ ├── symbols.lua.html │ ├── test-cmp.lua.html │ ├── test-data.lua.html │ ├── test-listcallbacks.lua.html │ ├── test-pretty.lua.html │ ├── test-symbols.lua.html │ ├── testapp.lua.html │ ├── testclone.lua.html │ ├── testconfig.lua.html │ ├── testglobal.lua.html │ ├── testinputfields.lua.html │ ├── testinputfields2.lua.html │ ├── testxml.lua.html │ └── which.lua.html ├── index.html ├── ldoc_fixed.css ├── libraries │ ├── pl.Set.html │ ├── pl.app.html │ ├── pl.array2d.html │ ├── pl.class.html │ ├── pl.compat.html │ ├── pl.comprehension.html │ ├── pl.config.html │ ├── pl.data.html │ ├── pl.dir.html │ ├── pl.file.html │ ├── pl.func.html │ ├── pl.html │ ├── pl.import_into.html │ ├── pl.input.html │ ├── pl.lapp.html │ ├── pl.lexer.html │ ├── pl.luabalanced.html │ ├── pl.operator.html │ ├── pl.path.html │ ├── pl.permute.html │ ├── pl.pretty.html │ ├── pl.seq.html │ ├── pl.sip.html │ ├── pl.strict.html │ ├── pl.stringio.html │ ├── pl.stringx.html │ ├── pl.tablex.html │ ├── pl.template.html │ ├── pl.test.html │ ├── pl.text.html │ ├── pl.types.html │ ├── pl.url.html │ ├── pl.utils.html │ └── pl.xml.html └── manual │ ├── 01-introduction.md.html │ ├── 02-arrays.md.html │ ├── 03-strings.md.html │ ├── 04-paths.md.html │ ├── 05-dates.md.html │ ├── 06-data.md.html │ ├── 07-functional.md.html │ ├── 08-additional.md.html │ └── 09-discussion.md.html ├── docs_topics ├── 01-introduction.md ├── 02-arrays.md ├── 03-strings.md ├── 04-paths.md ├── 05-dates.md ├── 06-data.md ├── 07-functional.md ├── 08-additional.md └── 09-discussion.md ├── examples ├── seesubst.lua ├── sipscan.lua ├── symbols.lua ├── test-cmp.lua ├── test-listcallbacks.lua ├── test-pretty.lua ├── test-symbols.lua ├── testclone.lua ├── testconfig.lua ├── testglobal.lua ├── testinputfields.lua ├── testinputfields2.lua ├── testxml.lua └── which.lua ├── ldoc.ltp ├── lua └── pl │ ├── Date.lua │ ├── List.lua │ ├── Map.lua │ ├── MultiMap.lua │ ├── OrderedMap.lua │ ├── Set.lua │ ├── app.lua │ ├── array2d.lua │ ├── class.lua │ ├── compat.lua │ ├── comprehension.lua │ ├── config.lua │ ├── data.lua │ ├── dir.lua │ ├── file.lua │ ├── func.lua │ ├── import_into.lua │ ├── init.lua │ ├── input.lua │ ├── lapp.lua │ ├── lexer.lua │ ├── luabalanced.lua │ ├── operator.lua │ ├── path.lua │ ├── permute.lua │ ├── pretty.lua │ ├── seq.lua │ ├── sip.lua │ ├── strict.lua │ ├── stringio.lua │ ├── stringx.lua │ ├── tablex.lua │ ├── template.lua │ ├── test.lua │ ├── text.lua │ ├── types.lua │ ├── url.lua │ ├── utils.lua │ └── xml.lua ├── penlight-dev-1.rockspec ├── rockspecs ├── penlight-1.10.0-1.rockspec ├── penlight-1.10.0-2.rockspec ├── penlight-1.11.0-1.rockspec ├── penlight-1.11.0-2.rockspec ├── penlight-1.12.0-1.rockspec ├── penlight-1.12.0-2.rockspec ├── penlight-1.13.0-1.rockspec ├── penlight-1.13.1-1.rockspec ├── penlight-1.14.0-1.rockspec ├── penlight-1.14.0-2.rockspec ├── penlight-1.14.0-3.rockspec ├── penlight-1.6.0-1.rockspec ├── penlight-1.6.0-2.rockspec ├── penlight-1.7.0-1.rockspec ├── penlight-1.7.0-2.rockspec ├── penlight-1.8.0-1.rockspec ├── penlight-1.8.0-2.rockspec ├── penlight-1.8.1-1.rockspec ├── penlight-1.8.1-2.rockspec ├── penlight-1.9.1-1.rockspec ├── penlight-1.9.1-2.rockspec ├── penlight-1.9.2-1.rockspec └── penlight-1.9.2-2.rockspec ├── run.lua ├── spec ├── app_spec.lua ├── array2d_spec.lua ├── date_spec.lua ├── func_spec.lua ├── multimap_spec.lua ├── path_spec.lua ├── permute_spec.lua ├── pretty_spec.lua ├── set_spec.lua ├── stringx_spec.lua ├── text_spec.lua ├── utils-choose_spec.lua ├── utils-deprecate_spec.lua ├── utils-enum_spec.lua ├── utils-kpairs_spec.lua ├── utils-npairs_spec.lua └── xml_spec.lua └── tests ├── lua ├── animal.lua ├── bar.lua ├── foo │ └── args.lua ├── mod52.lua └── mymod.lua ├── test-__vector.lua ├── test-app.lua ├── test-app └── require_here-link-target.lua ├── test-class.lua ├── test-class2.lua ├── test-class3.lua ├── test-class4.lua ├── test-compat.lua ├── test-comprehension.lua ├── test-config.lua ├── test-data.lua ├── test-data2.lua ├── test-date.lua ├── test-dir.lua ├── test-func.lua ├── test-import_into.lua ├── test-lapp.lua ├── test-lexer.lua ├── test-list.lua ├── test-list2.lua ├── test-map.lua ├── test-orderedmap.lua ├── test-path.lua ├── test-pretty.lua ├── test-seq.lua ├── test-sip.lua ├── test-strict.lua ├── test-stringio.lua ├── test-tablex.lua ├── test-tablex3.lua ├── test-template.lua ├── test-template2.lua ├── test-types.lua ├── test-url.lua ├── test-utils.lua ├── test-utils2.lua ├── test-utils3.lua └── test-xml.lua /.busted: -------------------------------------------------------------------------------- 1 | return { 2 | default = { 3 | verbose = true, 4 | output = "gtest", 5 | lpath = "./lua/?.lua;./lua/?/init.lua", 6 | } 7 | } 8 | -- vim: ft=lua 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | charset = utf-8 8 | 9 | [*.lua] 10 | indent_style = space 11 | indent_size = 2 12 | 13 | [kong/templates/nginx*] 14 | indent_style = space 15 | indent_size = 4 16 | 17 | [*.template] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | [Makefile] 22 | indent_style = tab 23 | -------------------------------------------------------------------------------- /.github/workflows/luacheck.yml: -------------------------------------------------------------------------------- 1 | name: Luacheck 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | luacheck: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v4 12 | - name: Luacheck 13 | uses: lunarmodules/luacheck@v1 14 | -------------------------------------------------------------------------------- /.github/workflows/unix_build.yml: -------------------------------------------------------------------------------- 1 | name: "Unix build" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | luaVersion: ["5.1", "5.2", "5.3", "5.4", "luajit-2.1.0-beta3", "luajit-openresty"] 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - uses: hishamhm/gh-actions-lua@master 18 | with: 19 | luaVersion: ${{ matrix.luaVersion }} 20 | 21 | - uses: hishamhm/gh-actions-luarocks@master 22 | with: 23 | luaRocksVersion: "3.11.0" 24 | 25 | - name: dependencies 26 | run: | 27 | luarocks install busted 28 | luarocks install luacov-coveralls 29 | 30 | - name: build 31 | run: | 32 | luarocks remove penlight --force 33 | luarocks make 34 | 35 | - name: Busted tests 36 | run: | 37 | busted --coverage --Xoutput "--color" 38 | 39 | - name: Old test suite 40 | run: | 41 | lua run.lua tests --luacov 42 | 43 | - name: Examples 44 | run: | 45 | lua run.lua examples 46 | 47 | - name: Report test coverage 48 | if: success() 49 | continue-on-error: true 50 | run: luacov-coveralls 51 | env: 52 | COVERALLS_REPO_TOKEN: ${{ github.token }} 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | luacov.stats.out 2 | *.rock 3 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | unused_args = false 2 | redefined = false 3 | max_line_length = false 4 | 5 | globals = { 6 | "ngx", 7 | } 8 | 9 | not_globals = { 10 | "string.len", 11 | "table.getn", 12 | } 13 | 14 | include_files = { 15 | "**/*.lua", 16 | "*.rockspec", 17 | ".busted", 18 | ".luacheckrc", 19 | } 20 | 21 | files["spec/**/*.lua"] = { 22 | std = "+busted", 23 | } 24 | 25 | exclude_files = { 26 | "tests/*.lua", 27 | "tests/**/*.lua", 28 | -- Travis Lua environment 29 | "here/*.lua", 30 | "here/**/*.lua", 31 | -- GH Actions Lua Environment 32 | ".lua", 33 | ".luarocks", 34 | ".install", 35 | 36 | -- TODO: fix these files 37 | "examples/symbols.lua", 38 | "examples/test-symbols.lua", 39 | } 40 | 41 | -------------------------------------------------------------------------------- /.luacov: -------------------------------------------------------------------------------- 1 | modules = { 2 | ["pl"] = "lua/pl/init.lua", 3 | ["pl.*"] = "lua" 4 | } 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Penlight 2 | ======================== 3 | 4 | So you want to contribute to Penlight? Fantastic! Here's a brief overview on 5 | how best to do so. 6 | 7 | ## What to change 8 | 9 | Here's some examples of things you might want to make a pull request for: 10 | 11 | * New features 12 | * Bugfixes 13 | * Inefficient blocks of code 14 | 15 | If you have a more deeply-rooted problem with how the library is built or some 16 | of the stylistic decisions made in the code, it's best to 17 | [create an issue](https://github.com/lunarmodules/Penlight/issues) before putting 18 | the effort into a pull request. The same goes for new features - it might be 19 | best to check the project's direction, existing pull requests, and currently open 20 | and closed issues first. 21 | 22 | ## Using Git appropriately 23 | 24 | Here's how to go about contributing to Penlight: 25 | 26 | 1. [Fork the repository](https://github.com/lunarmodules/Penlight/fork) to 27 | your Github account. 28 | 2. Create a *topical branch* - a branch whose name is succinct but explains what 29 | you're doing, such as _"added-klingon-cloacking-device"_ - from `master` branch. 30 | 3. Make your changes, committing at logical breaks. 31 | 4. Push your branch to your personal account 32 | 5. [Create a pull request](https://help.github.com/articles/using-pull-requests) 33 | 6. Watch for comments or acceptance 34 | 35 | If you wanna be a rockstar; 36 | 37 | 1. Update the [CHANGELOG.md](https://github.com/lunarmodules/Penlight/blob/master/CHANGELOG.md) file 38 | 2. [Add tests](https://github.com/lunarmodules/Penlight/tree/master/tests) that show the defect your fix repairs, or that tests your new feature 39 | 40 | Please note - if you want to change multiple things that don't depend on each 41 | other, make sure you check out the `master` branch again and create a different topical branch 42 | before making more changes - that way we can take in each change separately. 43 | 44 | ## Release instructions for a new version 45 | 46 | - create a new release branch 47 | - update `./lua/pl/utils.lua` (the `_VERSION` constant) 48 | - update `./config.ld` with the new version number 49 | - create a new rockspec file for the version in `./rockspecs` 50 | - check the `./CHANGELOG.md` files for completeness 51 | - commit the release related changes with `release x.y.z` 52 | - render the documentation using `ldoc .` 53 | - commit the documentation as a separate commit with `release x.y.z docs` 54 | - push the release branch and create a PR 55 | - merge the PR 56 | - tag the release as `x.y.z` and push the tag to the github repo 57 | - upload the rockspec, and source rock files to LuaRocks 58 | - test installing through LuaRocks 59 | - announce the release on the Lua mailing list 60 | 61 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (C) 2009-2016 Steve Donovan, David Manura. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 14 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 15 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 17 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 18 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 21 | OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | shallow_clone: true 2 | 3 | environment: 4 | COVERALLS_REPO_TOKEN: 5 | secure: Ot23JDCk/sDpsIa8DkjX6u1ym09mVht+aFyIOmY09Ro6VFs/+VzQzqcldP0haP7r 6 | matrix: 7 | - LUA: "lua 5.1" 8 | - LUA: "lua 5.2" 9 | - LUA: "lua 5.3" 10 | - LUA: "lua 5.4" 11 | - LUA: "luajit 2.0" 12 | - LUA: "luajit 2.0 --compat 5.2" 13 | - LUA: "luajit 2.1" 14 | - LUA: "luajit 2.1 --compat 5.2" 15 | 16 | before_build: 17 | - set PATH=C:\Python27\Scripts;%PATH% 18 | - pip install --upgrade certifi 19 | - FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "import certifi;print(certifi.where())"`) DO ( SET SSL_CERT_FILE=%%F ) 20 | - pip install hererocks 21 | - hererocks here --%LUA% -rlatest 22 | - call here\bin\activate 23 | - luarocks install luacov-coveralls 24 | - luarocks install busted 25 | 26 | build_script: 27 | - luarocks make 28 | 29 | test_script: 30 | - busted --coverage 31 | - lua run.lua tests --luacov 32 | - lua run.lua examples 33 | 34 | on_success: 35 | # secure coveralls token not available on PR builds, only BRANCH builds 36 | - "if not \"%COVERALLS_REPO_TOKEN%\"==\"\" ( 37 | luacov-coveralls 38 | )" 39 | -------------------------------------------------------------------------------- /config.ld: -------------------------------------------------------------------------------- 1 | project = 'Penlight' 2 | description = 'Penlight Lua Libraries 1.14.0' 3 | full_description = 'Penlight is a set of pure Lua libraries for making it easier to work with common tasks like iterating over directories, reading configuration files and the like. Provides functional operations on tables and sequences. Visit the GitHub project to review the code or file issues. Skip to the @{01-introduction.md|introduction}.' 4 | title = 'Penlight Documentation' 5 | dir = 'docs' 6 | style = '!fixed' 7 | template = true 8 | use_markdown_titles = true 9 | topics = 'docs_topics' 10 | examples = {'./examples','./tests/test-data.lua'} 11 | package = 'pl' 12 | format = 'discount' 13 | sort_modules=true 14 | file = './lua/pl' 15 | kind_names={topic='Manual',module='Libraries'} 16 | tparam_alias('array','array') 17 | tparam_alias('array2d','array') 18 | alias('ret',{'return',modifiers={type="$1"}}) 19 | -------------------------------------------------------------------------------- /docs_topics/05-dates.md: -------------------------------------------------------------------------------- 1 | ## Date and Time 2 | 3 | 4 | 5 | NOTE: the Date module is deprecated 6 | 7 | ### Creating and Displaying Dates 8 | 9 | The `Date` class provides a simplified way to work with [date and 10 | time](https://www.lua.org/pil/22.1.html) in Lua; it leans heavily on the functions 11 | `os.date` and `os.time`. 12 | 13 | A `Date` object can be constructed from a table, just like with `os.time`. 14 | Methods are provided to get and set the various parts of the date. 15 | 16 | > d = Date {year = 2011, month = 3, day = 2 } 17 | > = d 18 | 2011-03-02 12:00:00 19 | > = d:month(),d:year(),d:day() 20 | 3 2011 2 21 | > d:month(4) 22 | > = d 23 | 2011-04-02 12:00:00 24 | > d:add {day=1} 25 | > = d 26 | 2011-04-03 12:00:00 27 | 28 | `add` takes a table containing one of the date table fields. 29 | 30 | > = d:weekday_name() 31 | Sun 32 | > = d:last_day() 33 | 2011-04-30 12:00:00 34 | > = d:month_name(true) 35 | April 36 | 37 | There is a default conversion to text for date objects, but `Date.Format` gives 38 | you full control of the format for both parsing and displaying dates: 39 | 40 | > iso = Date.Format 'yyyy-mm-dd' 41 | > d = iso:parse '2010-04-10' 42 | > amer = Date.Format 'mm/dd/yyyy' 43 | > = amer:tostring(d) 44 | 04/10/2010 45 | 46 | With the 0.9.7 release, the `Date` constructor has become more flexible. You may 47 | omit any of the 'year', 'month' or 'day' fields: 48 | 49 | > = Date { year = 2008 } 50 | 2008-01-01 12:00:00 51 | > = Date { month = 3 } 52 | 2011-03-01 12:00:00 53 | > = Date { day = 20 } 54 | 2011-10-20 12:00:00 55 | > = Date { hour = 14, min = 30 } 56 | 2011-10-13 14:30:00 57 | 58 | If 'year' is omitted, then the current year is assumed, and likewise for 'month'. 59 | 60 | To set the time on such a partial date, you can use the fact that the 'setter' 61 | methods return the date object and so you can 'chain' these methods. 62 | 63 | > d = Date { day = 03 } 64 | > = d:hour(18):min(30) 65 | 2011-10-03 18:30:00 66 | 67 | Finally, `Date` also now accepts positional arguments: 68 | 69 | > = Date(2011,10,3) 70 | 2011-10-03 12:00:00 71 | > = Date(2011,10,3,18,30,23) 72 | 2011-10-03 18:30:23 73 | 74 | `Date.format` has been extended. If you construct an instance without a pattern, 75 | then it will try to match against a set of known formats. This is useful for 76 | human-input dates since keeping to a strict format is not one of the strong 77 | points of users. It assumes that there will be a date, and then a date. 78 | 79 | > df = Date.Format() 80 | > = df:parse '5.30pm' 81 | 2011-10-13 17:30:00 82 | > = df:parse '1730' 83 | nil day out of range: 1730 is not between 1 and 31 84 | > = df:parse '17.30' 85 | 2011-10-13 17:30:00 86 | > = df:parse 'mar' 87 | 2011-03-01 12:00:00 88 | > = df:parse '3 March' 89 | 2011-03-03 12:00:00 90 | > = df:parse '15 March' 91 | 2011-03-15 12:00:00 92 | > = df:parse '15 March 2008' 93 | 2008-03-15 12:00:00 94 | > = df:parse '15 March 2008 1.30pm' 95 | 2008-03-15 13:30:00 96 | > = df:parse '2008-10-03 15:30:23' 97 | 2008-10-03 15:30:23 98 | 99 | ISO date format is of course a good idea if you need to deal with users from 100 | different countries. Here is the default behaviour for 'short' dates: 101 | 102 | > = df:parse '24/02/12' 103 | 2012-02-24 12:00:00 104 | 105 | That's not what Americans expect! It's tricky to work out in a cross-platform way 106 | exactly what the expected format is, so there is an explicit flag: 107 | 108 | > df:US_order(true) 109 | > = df:parse '9/11/01' 110 | 2001-11-09 12:00:00 111 | 112 | -------------------------------------------------------------------------------- /docs_topics/09-discussion.md: -------------------------------------------------------------------------------- 1 | ## Technical Choices 2 | 3 | ### Modularity and Granularity 4 | 5 | In an ideal world, a program should only load the libraries it needs. Penlight is 6 | intended to work in situations where an extra 100Kb of bytecode could be a 7 | problem. It is straightforward but tedious to load exactly what you need: 8 | 9 | local data = require 'pl.data' 10 | local List = require 'pl.List' 11 | local array2d = require 'pl.array2d' 12 | local seq = require 'pl.seq' 13 | local utils = require 'pl.utils' 14 | 15 | This is the style that I follow in Penlight itself, so that modules don't mess 16 | with the global environment; also, `stringx.import()` is not used because it will 17 | update the global `string` table. 18 | 19 | But `require 'pl'` is more convenient in scripts; the question is how to ensure 20 | that one doesn't load the whole kitchen sink as the price of convenience. The 21 | strategy is to only load modules when they are referenced. In 'init.lua' (which 22 | is loaded by `require 'pl'`) a metatable is attached to the global table with an 23 | `__index` metamethod. Any unknown name is looked up in the list of modules, and 24 | if found, we require it and make that module globally available. So when 25 | `tablex.deepcompare` is encountered, looking up `tablex` causes 'pl.tablex' to be 26 | required. . 27 | 28 | Modifying the behaviour of the global table has consequences. For instance, there 29 | is the famous module `strict` which comes with Lua itself (perhaps the only 30 | standard Lua module written in Lua itself) which also does this modification so 31 | that global variiables must be defined before use. So the implementation in 32 | 'init.lua' allows for a 'not found' hook, which 'pl.strict.lua' uses. Other 33 | libraries may install their own metatables for `_G`, but Penlight will now 34 | forward any unknown name to the `__index` defined by the original metatable. 35 | 36 | But the strategy is worth the effort: the old 'kitchen sink' 'init.lua' would 37 | pull in about 260K of bytecode, whereas now typical programs use about 100K less, 38 | and short scripts even better - for instance, if they were only needing 39 | functionality in `utils`. 40 | 41 | There are some functions which mark their output table with a special metatable, 42 | when it seems particularly appropriate. For instance, `tablex.makeset` creates a 43 | `Set`, and `seq.copy` creates a `List`. But this does not automatically result in 44 | the loading of `pl.Set` and `pl.List`; only if you try to access any of these 45 | methods. In 'utils.lua', there is an exported table called `stdmt`: 46 | 47 | stdmt = { List = {}, Map = {}, Set = {}, MultiMap = {} } 48 | 49 | If you go through 'init.lua', then these plain little 'identity' tables get an 50 | `__index` metamethod which forces the loading of the full functionality. Here is 51 | the code from 'list.lua' which starts the ball rolling for lists: 52 | 53 | List = utils.stdmt.List 54 | List.__index = List 55 | List._name = "List" 56 | List._class = List 57 | 58 | The 'load-on-demand' strategy helps to modularize the library. Especially for 59 | more casual use, `require 'pl'` is a good compromise between convenience and 60 | modularity. 61 | 62 | In this current version, I have generally reduced the amount of trickery 63 | involved. Previously, `Map` was defined in `pl.class`; now it is sensibly defined 64 | in `pl.Map`; `pl.class` only contains the basic class mechanism (and returns that 65 | function.) For consistency, `List` is returned directly by `require 'pl.List'` 66 | (note the uppercase 'L'), Also, the amount of module dependencies in the 67 | non-core libraries like `pl.config` have been reduced. 68 | 69 | ### Defining what is Callable 70 | 71 | 'utils.lua' exports `function_arg` which is used extensively throughout Penlight. 72 | It defines what is meant by 'callable'. Obviously true functions are immediately 73 | passed back. But what about strings? The first option is that it represents an 74 | operator in 'operator.lua', so that '<' is just an alias for `operator.lt`. 75 | 76 | We then check whether there is a _function factory_ defined for the metatable of 77 | the value. 78 | 79 | (It is true that strings can be made callable, but in practice this turns out to 80 | be a cute but dubious idea, since _all_ strings share the same metatable. A 81 | common programming error is to pass the wrong kind of object to a function, and 82 | it's better to get a nice clean 'attempting to call a string' message rather than 83 | some obscure trace from the bowels of your library.) 84 | 85 | The other module that registers a function factory is `pl.func`. Placeholder 86 | expressions cannot be directly calleable, and so need to be instantiated and 87 | cached in as efficient way as possible. 88 | 89 | (An inconsistency is that `utils.is_callable` does not do this thorough check.) 90 | 91 | 92 | -------------------------------------------------------------------------------- /examples/seesubst.lua: -------------------------------------------------------------------------------- 1 | -- shows how replacing '@see module' in the Markdown documentation 2 | -- can be done more elegantly using PL. 3 | -- We either have something like 'pl.config' (a module reference) 4 | -- or 'pl.seq.map' (a function reference); these cases must be distinguished 5 | -- and a Markdown link generated pointing to the LuaDoc file. 6 | 7 | local sip = require 'pl.sip' 8 | local stringx = require 'pl.stringx' 9 | 10 | local res = {} 11 | local s = [[ 12 | (@see pl.bonzo.dog) 13 | remember about @see pl.bonzo 14 | 15 | ]] 16 | 17 | local _gsub_patterns = {} 18 | 19 | local function gsub (s,pat,subst,start) 20 | local fpat = _gsub_patterns[pat] 21 | if not fpat then 22 | -- use SIP to generate a proper string pattern. 23 | -- the _whole thing_ is a capture, to get the whole match 24 | -- and the unnamed capture. 25 | fpat = '('..sip.create_pattern(pat)..')' 26 | _gsub_patterns[pat] = fpat 27 | end 28 | return s:gsub(fpat,subst,start) 29 | end 30 | 31 | 32 | local mod = sip.compile '$v.$v' 33 | local fun = sip.compile '$v.$v.$v' 34 | 35 | for line in stringx.lines(s) do 36 | line = gsub(line,'@see $p',function(see,path) 37 | if fun(path,res) or mod(path,res) then 38 | local ret = ('[see %s](%s.%s.html'):format(path,res[1],res[2]) 39 | if res[3] then 40 | return ret..'#'..res[3]..')' 41 | else 42 | return ret..')' 43 | end 44 | end 45 | end) 46 | print(line) 47 | end 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /examples/sipscan.lua: -------------------------------------------------------------------------------- 1 | -- another SIP example, shows how an awkward log file format 2 | -- can be parsed. It also prints out the actual Lua string 3 | -- pattern generated: 4 | -- SYNC%s*%[([+%-%d]%d*)%]%s*([+%-%d]%d*)%s*([+%-%d]%d*) 5 | 6 | local sip = require 'pl.sip' 7 | local stringx = require 'pl.stringx' 8 | 9 | local s = [[ 10 | SYNC [1] 0 547 (14679 sec) 11 | SYNC [2] 0 555 (14679 sec) 12 | SYNC [3] 0 563 (14679 sec) 13 | SYNC [4] 0 571 (14679 sec) 14 | SYNC [5] -1 580 (14679 sec) 15 | SYNC [6] 0 587 (14679 sec) 16 | ]] 17 | 18 | 19 | local first = true 20 | local expected 21 | local res = {} 22 | local pat = 'SYNC [$i{seq}] $i{diff} $i{val}' 23 | print(sip.create_pattern(pat)) 24 | local match = sip.compile(pat) 25 | for line in stringx.lines(s) do 26 | if match(line,res) then 27 | if first then 28 | expected = res.val 29 | first = false 30 | end 31 | print(res.val,expected - res.val) 32 | expected = expected + 8 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /examples/test-cmp.lua: -------------------------------------------------------------------------------- 1 | local A = require 'pl.tablex' 2 | print(A.compare_no_order({1,2,3},{2,1,3})) 3 | print(A.compare_no_order({1,2,3},{2,1,3},'==')) 4 | -------------------------------------------------------------------------------- /examples/test-listcallbacks.lua: -------------------------------------------------------------------------------- 1 | -- demonstrates how to use a list of callbacks 2 | local List = require 'pl.List' 3 | local utils = require 'pl.utils' 4 | local actions = List() 5 | local L = utils.string_lambda 6 | 7 | actions:append(function() print 'hello' end) 8 | actions:append(L '|| print "yay"') 9 | 10 | -- '()' is a shortcut for operator.call or function(x) return x() end 11 | actions:foreach '()' 12 | -------------------------------------------------------------------------------- /examples/test-pretty.lua: -------------------------------------------------------------------------------- 1 | local pretty = require 'pl.pretty' 2 | 3 | local tb = { 4 | 'one','two','three',{1,2,3}, 5 | alpha=1,beta=2,gamma=3,['&']=true,[0]=false, 6 | _fred = {true,true}, 7 | s = [[ 8 | hello dolly 9 | you're so fine 10 | ]] 11 | } 12 | 13 | print(pretty.write(tb)) 14 | -------------------------------------------------------------------------------- /examples/test-symbols.lua: -------------------------------------------------------------------------------- 1 | require 'pl' 2 | -- force us to look in the script's directory when requiring... 3 | app.require_here() 4 | require 'symbols' 5 | 6 | local MT = getmetatable(_1) 7 | 8 | add = MT.__add 9 | mul = MT.__mul 10 | pow = MT.__pow 11 | 12 | 13 | function testeq (e1,e2) 14 | if not equals(e1,e2) then 15 | print ('Not equal',repr(e1),repr(e2)) 16 | end 17 | end 18 | 19 | sin = register(math.sin,'sin') 20 | 21 | f = register(function(x,y,z) end) 22 | 23 | --[[ 24 | testeq (_1,_1) 25 | testeq (_1+_2,_1+_2) 26 | testeq (_1 + 3*_2,_1 + 3*_2) 27 | testeq (_2+_1,_1+_2) 28 | testeq (sin(_1),sin(_1)) 29 | testeq (1+f(10,20,'ok'),f(10,20,'ok')+1) 30 | --]] 31 | 32 | 33 | function testexpand (e) 34 | print(repr(fold(expand(e)))) --fold 35 | end 36 | 37 | --[[ 38 | testexpand (a*(a+1)) 39 | 40 | testexpand ((x+2)*(b+1)) 41 | ]]-- 42 | 43 | function testfold (e) 44 | print(repr(fold(e))) 45 | end 46 | 47 | a,b,c,x,y = Var 'a,b,c,x,y' 48 | 49 | --~ testfold(_1 + _2) 50 | --~ testfold(add(10,20)) 51 | --~ testfold(add(mul(2,_1),mul(3,_2))) 52 | --[[ 53 | testfold(sin(a)) 54 | e = a^(b+2) 55 | testfold(e) 56 | bindval(b,1) 57 | testfold(e) 58 | bindval(a,2) 59 | testfold(e) 60 | 61 | bindval(a) 62 | bindval(b) 63 | ]] 64 | 65 | 66 | 67 | function testdiff (e) 68 | balance(e) 69 | e = diff(e,x) 70 | balance(e) 71 | print('+ ',e) 72 | e = fold(e) 73 | print('- ',e) 74 | end 75 | 76 | 77 | testdiff(x^2+1) 78 | testdiff(3*x^2) 79 | testdiff(x^2 + 2*x^3) 80 | testdiff(x^2 + 2*a*x^3 + x^4) 81 | testdiff(2*a*x^3) 82 | testdiff(x*x*x) 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /examples/testclone.lua: -------------------------------------------------------------------------------- 1 | --cloning a directory tree. 2 | local lfs = require 'lfs' 3 | local path = require 'pl.path' 4 | local dir = require 'pl.dir' 5 | 6 | local p1 = [[examples]] 7 | local p2 = [[copy/of/examples]] 8 | 9 | if not path.isfile 'examples/testclone.lua' then 10 | return print 'please run this in the penlight folder (below examples)' 11 | end 12 | 13 | -- make a copy of the examples folder 14 | dir.clonetree(p1,p2,dir.copyfile) 15 | 16 | assert(path.isdir 'copy') 17 | 18 | print '---' 19 | local t = os.time() 20 | print(lfs.touch('examples/testclone.lua',t,t+10)) 21 | 22 | -- this should only update this file 23 | dir.clonetree(p1,p2, 24 | function(f1,f2) 25 | local t1 = path.getmtime(f1) 26 | local t2 = path.getmtime(f2) 27 | --print(f1,t1,f2,t2) 28 | if t1 > t2 then 29 | dir.copyfile(f1,f2) 30 | print(f1,f2,t1,t2) 31 | end 32 | return true 33 | end) 34 | 35 | -- and get rid of the whole copy directory, with subdirs 36 | dir.rmtree 'copy' 37 | 38 | assert(not path.exists 'copy') 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/testconfig.lua: -------------------------------------------------------------------------------- 1 | local stringio = require 'pl.stringio' 2 | local config = require 'pl.config' 3 | 4 | local function dump(t,indent) 5 | if type(t) == 'table' then 6 | io.write(indent,'{\n') 7 | local newindent = indent..' ' 8 | for k,v in pairs(t) do 9 | io.write(newindent,k,'=') 10 | dump(v,indent) 11 | io.write('\n') 12 | end 13 | io.write(newindent,'},\n') 14 | else 15 | io.write(indent,t,'(',type(t),')') 16 | end 17 | end 18 | 19 | 20 | local function testconfig(test) 21 | local f = stringio.open(test) 22 | local c = config.read(f) 23 | f:close() 24 | dump(c,' ') 25 | print '-----' 26 | end 27 | 28 | testconfig [[ 29 | ; comment 2 (an ini file) 30 | [section!] 31 | bonzo.dog=20,30 32 | config_parm=here we go again 33 | depth = 2 34 | [another] 35 | felix="cat" 36 | ]] 37 | 38 | testconfig [[ 39 | # this is a more Unix-y config file 40 | fred = 1 41 | alice = 2 42 | home = /bonzo/dog/etc 43 | ]] 44 | 45 | testconfig [[ 46 | # this is just a set of comma-separated values 47 | 1000,444,222 48 | 44,555,224 49 | ]] 50 | 51 | 52 | -------------------------------------------------------------------------------- /examples/testglobal.lua: -------------------------------------------------------------------------------- 1 | -- very simple lexer program which looks at all identifiers in a Lua 2 | -- file and checks whether they're in the global namespace. 3 | -- At the end, we dump out the result of count_map, which will give us 4 | -- unique identifiers with their usage count. 5 | -- (an example of a program which itself needs to be careful about what 6 | -- goes into the global namespace) 7 | 8 | local utils = require 'pl.utils' 9 | local file = require 'pl.file' 10 | local lexer = require 'pl.lexer' 11 | local List = require 'pl.List' 12 | local pretty = require 'pl.pretty' 13 | local seq = require 'pl.seq' 14 | local path = require 'pl.path' 15 | 16 | utils.on_error 'quit' 17 | 18 | local txt = file.read(arg[1] or path.normpath('examples/testglobal.lua')) 19 | local globals = List() 20 | for t,v in lexer.lua(txt) do 21 | if t == 'iden' and rawget(_G,v) then 22 | globals:append(v) 23 | end 24 | end 25 | 26 | pretty.dump(seq.count_map(globals)) 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/testinputfields.lua: -------------------------------------------------------------------------------- 1 | local input = require 'pl.input' 2 | local sum = 0.0 3 | local count = 0 4 | local text = [[ 5 | 981124001 2.0 18988.4 10047.1 4149.7 6 | 981125001 0.8 19104.0 9970.4 5088.7 7 | 981127003 0.5 19012.5 9946.9 3831.2 8 | ]] 9 | for id,magn,x in input.fields(3,' ',text) do 10 | sum = sum + x 11 | count = count + 1 12 | end 13 | print('average x coord is ',sum/count) 14 | -------------------------------------------------------------------------------- /examples/testinputfields2.lua: -------------------------------------------------------------------------------- 1 | local input = require 'pl.input' 2 | local seq = require 'pl.seq' 3 | local text = [[ 4 | 981124001 2.0 18988.4 10047.1 4149.7 5 | 981125001 0.8 19104.0 9970.4 5088.7 6 | 981127003 0.5 19012.5 9946.9 3831.2 7 | ]] 8 | local sum,count = seq.sum(input.fields ({3},' ',text)) 9 | print(sum/count) 10 | -------------------------------------------------------------------------------- /examples/testxml.lua: -------------------------------------------------------------------------------- 1 | -- an example showing 'pl.lexer' doing some serious work. 2 | -- The resulting Lua table is in the same LOM format used by luaexpat. 3 | -- This is (clearly) not a professional XML parser, so don't use it 4 | -- on your homework! 5 | 6 | local lexer = require 'pl.lexer' 7 | local pretty = require 'pl.pretty' 8 | 9 | local append = table.insert 10 | local skipws,expecting = lexer.skipws,lexer.expecting 11 | 12 | local function parse_element (tok,tag) 13 | local tbl,t,v,attrib 14 | tbl = {} 15 | tbl.tag = tag -- LOM 'tag' is the element tag 16 | t,v = skipws(tok) 17 | while v ~= '/' and v ~= '>' do 18 | if t ~= 'iden' then error('expecting attribute identifier') end 19 | attrib = v 20 | expecting(tok,'=') 21 | v = expecting(tok,'string') 22 | -- LOM: 'attr' subtable contains attrib/value pairs and an ordered list of attribs 23 | if not tbl.attr then tbl.attr = {} end 24 | tbl.attr[attrib] = v 25 | append(tbl.attr,attrib) 26 | t,v = skipws(tok) 27 | end 28 | if v == '/' then 29 | expecting(tok,'>') 30 | return tbl 31 | end 32 | -- pick up element data 33 | t,v = tok() 34 | while true do 35 | if t == '<' then 36 | t,v = skipws(tok) 37 | if t == '/' then -- element end tag 38 | t,v = tok() 39 | if t == '>' then return tbl end 40 | if t == 'iden' and v == tag then 41 | if tok() == '>' then return tbl end 42 | end 43 | error('expecting end tag '..tag) 44 | else 45 | append(tbl,parse_element(tok,v)) -- LOM: child elements added to table 46 | t,v = skipws(tok) 47 | end 48 | else 49 | append(tbl,v) -- LOM: text added to table 50 | t,v = skipws(tok) 51 | end 52 | end 53 | end 54 | 55 | local function parse_xml (tok) 56 | local t = skipws(tok) 57 | local v 58 | while t == '<' do 59 | t,v = tok() 60 | if t == '?' or t == '!' then 61 | -- skip meta stuff and commentary 62 | repeat t = tok() until t == '>' 63 | t = expecting(tok,'<') 64 | else 65 | return parse_element(tok,v) 66 | end 67 | end 68 | end 69 | 70 | local s = [[ 71 | 72 | 73 | 77 | 78 | ]] 79 | 80 | local tok = lexer.scan(s,nil,{space=false},{string=true}) 81 | local res = parse_xml(tok) 82 | print(pretty.write(res)) 83 | 84 | -------------------------------------------------------------------------------- /examples/which.lua: -------------------------------------------------------------------------------- 1 | -- a simple implementation of the which command. This looks for 2 | -- the given file on the path. On windows, it will assume an extension 3 | -- of .exe if no extension is given. 4 | local List = require 'pl.List' 5 | local path = require 'pl.path' 6 | local app = require 'pl.app' 7 | 8 | local pathl = List.split(os.getenv 'PATH',path.dirsep) 9 | 10 | local function which (file) 11 | local res = pathl:map(path.join,file) 12 | res = res:filter(path.exists) 13 | if res then return res[1] end 14 | end 15 | 16 | local _,lua = app.lua() 17 | local file = arg[1] or lua -- i.e. location of lua executable 18 | local try 19 | 20 | if not file then return print 'must provide a filename' end 21 | 22 | if path.extension(file) == '' and path.is_windows then 23 | try = which(file..'.exe') 24 | else 25 | try = which(file) 26 | end 27 | 28 | if try then print(try) else print 'cannot find on path' end 29 | 30 | 31 | -------------------------------------------------------------------------------- /lua/pl/Map.lua: -------------------------------------------------------------------------------- 1 | --- A Map class. 2 | -- 3 | -- > Map = require 'pl.Map' 4 | -- > m = Map{one=1,two=2} 5 | -- > m:update {three=3,four=4,two=20} 6 | -- > = m == M{one=1,two=20,three=3,four=4} 7 | -- true 8 | -- 9 | -- Dependencies: `pl.utils`, `pl.class`, `pl.tablex`, `pl.pretty` 10 | -- @classmod pl.Map 11 | 12 | local tablex = require 'pl.tablex' 13 | local utils = require 'pl.utils' 14 | local stdmt = utils.stdmt 15 | local deepcompare = tablex.deepcompare 16 | 17 | local pretty_write = require 'pl.pretty' . write 18 | local Map = stdmt.Map 19 | local Set = stdmt.Set 20 | 21 | local class = require 'pl.class' 22 | 23 | -- the Map class --------------------- 24 | class(nil,nil,Map) 25 | 26 | function Map:_init (t) 27 | local mt = getmetatable(t) 28 | if mt == Set or mt == Map then 29 | self:update(t) 30 | else 31 | return t -- otherwise assumed to be a map-like table 32 | end 33 | end 34 | 35 | 36 | local function makelist(t) 37 | return setmetatable(t, require('pl.List')) 38 | end 39 | 40 | --- return a List of all keys. 41 | -- @class function 42 | -- @name Map:keys 43 | Map.keys = tablex.keys 44 | 45 | --- return a List of all values. 46 | -- @class function 47 | -- @name Map:values 48 | Map.values = tablex.values 49 | 50 | --- return an iterator over all key-value pairs. 51 | function Map:iter () 52 | return pairs(self) 53 | end 54 | 55 | --- return a List of all key-value pairs, sorted by the keys in ascending order. 56 | function Map:items() 57 | local ls = makelist(tablex.pairmap (function (k,v) return makelist {k,v} end, self)) 58 | ls:sort(function(t1,t2) return t1[1] < t2[1] end) 59 | return ls 60 | end 61 | 62 | --- set a value in the map if it doesn't exist yet. 63 | -- @param key the key 64 | -- @param default value to set 65 | -- @return the value stored in the map (existing value, or the new value) 66 | function Map:setdefault(key, default) 67 | local val = self[key] 68 | if val ~= nil then 69 | return val 70 | end 71 | self:set(key,default) 72 | return default 73 | end 74 | 75 | --- size of map. 76 | -- note: this is a relatively expensive operation! 77 | -- @class function 78 | -- @name Map:len 79 | Map.len = tablex.size 80 | 81 | --- put a value into the map. 82 | -- This will remove the key if the value is `nil` 83 | -- @param key the key 84 | -- @param val the value 85 | function Map:set (key,val) 86 | self[key] = val 87 | end 88 | 89 | --- get a value from the map. 90 | -- @param key the key 91 | -- @return the value, or nil if not found. 92 | function Map:get (key) 93 | return rawget(self,key) 94 | end 95 | 96 | local index_by = tablex.index_by 97 | 98 | --- get a list of values indexed by a list of keys. 99 | -- @param keys a list-like table of keys 100 | -- @return a new list 101 | function Map:getvalues (keys) 102 | return makelist(index_by(self,keys)) 103 | end 104 | 105 | --- update the map using key/value pairs from another table. 106 | -- @tab table 107 | -- @function Map:update 108 | Map.update = tablex.update 109 | 110 | --- equality between maps. 111 | -- @within metamethods 112 | -- @tparam Map m another map. 113 | function Map:__eq (m) 114 | -- note we explicitly ask deepcompare _not_ to use __eq! 115 | return deepcompare(self,m,true) 116 | end 117 | 118 | --- string representation of a map. 119 | -- @within metamethods 120 | function Map:__tostring () 121 | return pretty_write(self,'') 122 | end 123 | 124 | return Map 125 | -------------------------------------------------------------------------------- /lua/pl/MultiMap.lua: -------------------------------------------------------------------------------- 1 | --- MultiMap, a Map which has multiple values per key. 2 | -- 3 | -- Dependencies: `pl.utils`, `pl.class`, `pl.List`, `pl.Map` 4 | -- @classmod pl.MultiMap 5 | 6 | local utils = require 'pl.utils' 7 | local class = require 'pl.class' 8 | local List = require 'pl.List' 9 | local Map = require 'pl.Map' 10 | 11 | -- MultiMap is a standard MT 12 | local MultiMap = utils.stdmt.MultiMap 13 | 14 | class(Map,nil,MultiMap) 15 | MultiMap._name = 'MultiMap' 16 | 17 | function MultiMap:_init (t) 18 | if not t then return end 19 | self:update(t) 20 | end 21 | 22 | --- update a MultiMap using a table. 23 | -- @param t either a Multimap or a map-like table. 24 | -- @return the map 25 | function MultiMap:update (t) 26 | utils.assert_arg(1,t,'table') 27 | if Map:class_of(t) then 28 | for k,v in pairs(t) do 29 | self[k] = List() 30 | self[k]:append(v) 31 | end 32 | else 33 | for k,v in pairs(t) do 34 | self[k] = List(v) 35 | end 36 | end 37 | end 38 | 39 | --- add a new value to a key. Setting a nil value removes the key. 40 | -- @param key the key 41 | -- @param val the value 42 | -- @return the map 43 | function MultiMap:set (key,val) 44 | if val == nil then 45 | self[key] = nil 46 | else 47 | if not self[key] then 48 | self[key] = List() 49 | end 50 | self[key]:append(val) 51 | end 52 | end 53 | 54 | return MultiMap 55 | -------------------------------------------------------------------------------- /lua/pl/file.lua: -------------------------------------------------------------------------------- 1 | --- File manipulation functions: reading, writing, moving and copying. 2 | -- 3 | -- This module wraps a number of functions from other modules into a 4 | -- file related module for convenience. 5 | -- 6 | -- Dependencies: `pl.utils`, `pl.dir`, `pl.path` 7 | -- @module pl.file 8 | local os = os 9 | local utils = require 'pl.utils' 10 | local dir = require 'pl.dir' 11 | local path = require 'pl.path' 12 | 13 | local file = {} 14 | 15 | --- return the contents of a file as a string. 16 | -- This function is a copy of `utils.readfile`. 17 | -- @function file.read 18 | file.read = utils.readfile 19 | 20 | --- write a string to a file. 21 | -- This function is a copy of `utils.writefile`. 22 | -- @function file.write 23 | file.write = utils.writefile 24 | 25 | --- copy a file. 26 | -- This function is a copy of `dir.copyfile`. 27 | -- @function file.copy 28 | file.copy = dir.copyfile 29 | 30 | --- move a file. 31 | -- This function is a copy of `dir.movefile`. 32 | -- @function file.move 33 | file.move = dir.movefile 34 | 35 | --- Return the time of last access as the number of seconds since the epoch. 36 | -- This function is a copy of `path.getatime`. 37 | -- @function file.access_time 38 | file.access_time = path.getatime 39 | 40 | ---Return when the file was created. 41 | -- This function is a copy of `path.getctime`. 42 | -- @function file.creation_time 43 | file.creation_time = path.getctime 44 | 45 | --- Return the time of last modification. 46 | -- This function is a copy of `path.getmtime`. 47 | -- @function file.modified_time 48 | file.modified_time = path.getmtime 49 | 50 | --- Delete a file. 51 | -- This function is a copy of `os.remove`. 52 | -- @function file.delete 53 | file.delete = os.remove 54 | 55 | return file 56 | -------------------------------------------------------------------------------- /lua/pl/import_into.lua: -------------------------------------------------------------------------------- 1 | -------------- 2 | -- PL loader, for loading all PL libraries, only on demand. 3 | -- Whenever a module is implicitly accessed, the table will have the module automatically injected. 4 | -- (e.g. `_ENV.tablex`) 5 | -- then that module is dynamically loaded. The submodules are all brought into 6 | -- the table that is provided as the argument, or returned in a new table. 7 | -- If a table is provided, that table's metatable is clobbered, but the values are not. 8 | -- This module returns a single function, which is passed the environment. 9 | -- If this is `true`, then return a 'shadow table' as the module 10 | -- See @{01-introduction.md.To_Inject_or_not_to_Inject_|the Guide} 11 | 12 | -- @module pl.import_into 13 | 14 | return function(env) 15 | local mod 16 | if env == true then 17 | mod = {} 18 | env = {} 19 | end 20 | local env = env or {} 21 | 22 | local modules = { 23 | utils = true,path=true,dir=true,tablex=true,stringio=true,sip=true, 24 | input=true,seq=true,lexer=true,stringx=true, 25 | config=true,pretty=true,data=true,func=true,text=true, 26 | operator=true,lapp=true,array2d=true, 27 | comprehension=true,xml=true,types=true, 28 | test = true, app = true, file = true, class = true, 29 | luabalanced = true, permute = true, template = true, 30 | url = true, compat = true, 31 | -- classes -- 32 | List = true, Map = true, Set = true, 33 | OrderedMap = true, MultiMap = true, Date = true, 34 | } 35 | rawset(env,'utils',require 'pl.utils') 36 | 37 | for name,klass in pairs(env.utils.stdmt) do 38 | klass.__index = function(t,key) 39 | return require ('pl.'..name)[key] 40 | end; 41 | end 42 | 43 | -- ensure that we play nice with libraries that also attach a metatable 44 | -- to the global table; always forward to a custom __index if we don't 45 | -- match 46 | 47 | local _hook,_prev_index 48 | local gmt = {} 49 | local prevenvmt = getmetatable(env) 50 | if prevenvmt then 51 | _prev_index = prevenvmt.__index 52 | if prevenvmt.__newindex then 53 | gmt.__newindex = prevenvmt.__newindex 54 | end 55 | end 56 | 57 | function gmt.hook(handler) 58 | _hook = handler 59 | end 60 | 61 | function gmt.__index(t,name) 62 | local found = modules[name] 63 | -- either true, or the name of the module containing this class. 64 | -- either way, we load the required module and make it globally available. 65 | if found then 66 | -- e..g pretty.dump causes pl.pretty to become available as 'pretty' 67 | rawset(env,name,require('pl.'..name)) 68 | return env[name] 69 | else 70 | local res 71 | if _hook then 72 | res = _hook(t,name) 73 | if res then return res end 74 | end 75 | if _prev_index then 76 | return _prev_index(t,name) 77 | end 78 | end 79 | end 80 | 81 | if mod then 82 | function gmt.__newindex(t,name,value) 83 | mod[name] = value 84 | rawset(t,name,value) 85 | end 86 | end 87 | 88 | setmetatable(env,gmt) 89 | 90 | return env,mod or env 91 | end 92 | -------------------------------------------------------------------------------- /lua/pl/init.lua: -------------------------------------------------------------------------------- 1 | -------------- 2 | -- Entry point for loading all PL libraries only on demand, into the global space. 3 | -- Requiring 'pl' means that whenever a module is implicitly accessed 4 | -- (e.g. `utils.split`) 5 | -- then that module is dynamically loaded. The submodules are all brought into 6 | -- the global space. 7 | --Updated to use @{pl.import_into} 8 | -- @module pl 9 | require'pl.import_into'(_G) 10 | 11 | if rawget(_G,'PENLIGHT_STRICT') then require 'pl.strict' end 12 | -------------------------------------------------------------------------------- /lua/pl/strict.lua: -------------------------------------------------------------------------------- 1 | --- Checks uses of undeclared global variables. 2 | -- All global variables must be 'declared' through a regular assignment 3 | -- (even assigning `nil` will do) in a main chunk before being used 4 | -- anywhere or assigned to inside a function. Existing metatables `__newindex` and `__index` 5 | -- metamethods are respected. 6 | -- 7 | -- You can set any table to have strict behaviour using `strict.module`. Creating a new 8 | -- module with `strict.closed_module` makes the module immune to monkey-patching, if 9 | -- you don't wish to encourage monkey business. 10 | -- 11 | -- If the global `PENLIGHT_NO_GLOBAL_STRICT` is defined, then this module won't make the 12 | -- global environment strict - if you just want to explicitly set table strictness. 13 | -- 14 | -- @module pl.strict 15 | 16 | require 'debug' -- for Lua 5.2 17 | local getinfo, error, rawset, rawget = debug.getinfo, error, rawset, rawget 18 | local strict = {} 19 | 20 | local function what () 21 | local d = getinfo(3, "S") 22 | return d and d.what or "C" 23 | end 24 | 25 | --- make an existing table strict. 26 | -- @string[opt] name name of table 27 | -- @tab[opt] mod the table to protect - if `nil` then we'll return a new table 28 | -- @tab[opt] predeclared - table of variables that are to be considered predeclared. 29 | -- @return the given table, or a new table 30 | -- @usage 31 | -- local M = { hello = "world" } 32 | -- strict.module ("Awesome_Module", M, { 33 | -- Lua = true, -- defines allowed keys 34 | -- }) 35 | -- 36 | -- assert(M.hello == "world") 37 | -- assert(M.Lua == nil) -- access allowed, but has no value yet 38 | -- M.Lua = "Rocks" 39 | -- assert(M.Lua == "Rocks") 40 | -- M.not_allowed = "bad boy" -- throws an error 41 | function strict.module (name,mod,predeclared) 42 | local mt, old_newindex, old_index, old_index_type, global 43 | if predeclared then 44 | global = predeclared.__global 45 | end 46 | if type(mod) == 'table' then 47 | mt = getmetatable(mod) 48 | if mt and rawget(mt,'__declared') then return end -- already patched... 49 | else 50 | mod = {} 51 | end 52 | if mt == nil then 53 | mt = {} 54 | setmetatable(mod, mt) 55 | else 56 | old_newindex = mt.__newindex 57 | old_index = mt.__index 58 | old_index_type = type(old_index) 59 | end 60 | mt.__declared = predeclared or {} 61 | mt.__newindex = function(t, n, v) 62 | if old_newindex then 63 | old_newindex(t, n, v) 64 | if rawget(t,n)~=nil then return end 65 | end 66 | if not mt.__declared[n] then 67 | if global then 68 | local w = what() 69 | if w ~= "main" and w ~= "C" then 70 | error("assign to undeclared global '"..n.."'", 2) 71 | end 72 | end 73 | mt.__declared[n] = true 74 | end 75 | rawset(t, n, v) 76 | end 77 | mt.__index = function(t,n) 78 | if not mt.__declared[n] and what() ~= "C" then 79 | if old_index then 80 | if old_index_type == "table" then 81 | local fallback = old_index[n] 82 | if fallback ~= nil then 83 | return fallback 84 | end 85 | else 86 | local res = old_index(t, n) 87 | if res ~= nil then 88 | return res 89 | end 90 | end 91 | end 92 | local msg = "variable '"..n.."' is not declared" 93 | if name then 94 | msg = msg .. " in '"..tostring(name).."'" 95 | end 96 | error(msg, 2) 97 | end 98 | return rawget(t, n) 99 | end 100 | return mod 101 | end 102 | 103 | --- make all tables in a table strict. 104 | -- So `strict.make_all_strict(_G)` prevents monkey-patching 105 | -- of any global table 106 | -- @tab T the table containing the tables to protect. Table `T` itself will NOT be protected. 107 | function strict.make_all_strict (T) 108 | for k,v in pairs(T) do 109 | if type(v) == 'table' and v ~= T then 110 | strict.module(k,v) 111 | end 112 | end 113 | end 114 | 115 | --- make a new module table which is closed to further changes. 116 | -- @tab mod module table 117 | -- @string name module name 118 | function strict.closed_module (mod,name) 119 | -- No clue to what this is useful for? see tests 120 | -- Deprecate this and remove??? 121 | local M = {} 122 | mod = mod or {} 123 | local mt = getmetatable(mod) 124 | if not mt then 125 | mt = {} 126 | setmetatable(mod,mt) 127 | end 128 | mt.__newindex = function(t,k,v) 129 | M[k] = v 130 | end 131 | return strict.module(name,M) 132 | end 133 | 134 | if not rawget(_G,'PENLIGHT_NO_GLOBAL_STRICT') then 135 | strict.module(nil,_G,{_PROMPT=true,_PROMPT2=true,__global=true}) 136 | end 137 | 138 | return strict 139 | -------------------------------------------------------------------------------- /lua/pl/stringio.lua: -------------------------------------------------------------------------------- 1 | --- Reading and writing strings using file-like objects.
2 | -- 3 | -- f = stringio.open(text) 4 | -- l1 = f:read() -- read first line 5 | -- n,m = f:read ('*n','*n') -- read two numbers 6 | -- for line in f:lines() do print(line) end -- iterate over all lines 7 | -- f = stringio.create() 8 | -- f:write('hello') 9 | -- f:write('dolly') 10 | -- assert(f:value(),'hellodolly') 11 | -- 12 | -- See @{03-strings.md.File_style_I_O_on_Strings|the Guide}. 13 | -- @module pl.stringio 14 | 15 | local unpack = rawget(_G,'unpack') or rawget(table,'unpack') 16 | local tonumber = tonumber 17 | local concat,append = table.concat,table.insert 18 | 19 | local stringio = {} 20 | 21 | -- Writer class 22 | local SW = {} 23 | SW.__index = SW 24 | 25 | local function xwrite(self,...) 26 | local args = {...} --arguments may not be nil! 27 | for i = 1, #args do 28 | append(self.tbl,args[i]) 29 | end 30 | end 31 | 32 | function SW:write(arg1,arg2,...) 33 | if arg2 then 34 | xwrite(self,arg1,arg2,...) 35 | else 36 | append(self.tbl,arg1) 37 | end 38 | end 39 | 40 | function SW:writef(fmt,...) 41 | self:write(fmt:format(...)) 42 | end 43 | 44 | function SW:value() 45 | return concat(self.tbl) 46 | end 47 | 48 | function SW:__tostring() 49 | return self:value() 50 | end 51 | 52 | function SW:close() -- for compatibility only 53 | end 54 | 55 | function SW:seek() 56 | end 57 | 58 | -- Reader class 59 | local SR = {} 60 | SR.__index = SR 61 | 62 | function SR:_read(fmt) 63 | local i,str = self.i,self.str 64 | local sz = #str 65 | if i > sz then return nil end 66 | local res 67 | if fmt == '*l' or fmt == '*L' then 68 | local idx = str:find('\n',i) or (sz+1) 69 | res = str:sub(i,fmt == '*l' and idx-1 or idx) 70 | self.i = idx+1 71 | elseif fmt == '*a' then 72 | res = str:sub(i) 73 | self.i = sz 74 | elseif fmt == '*n' then 75 | local _,i2,idx 76 | _,idx = str:find ('%s*%d+',i) 77 | _,i2 = str:find ('^%.%d+',idx+1) 78 | if i2 then idx = i2 end 79 | _,i2 = str:find ('^[eE][%+%-]*%d+',idx+1) 80 | if i2 then idx = i2 end 81 | local val = str:sub(i,idx) 82 | res = tonumber(val) 83 | self.i = idx+1 84 | elseif type(fmt) == 'number' then 85 | res = str:sub(i,i+fmt-1) 86 | self.i = i + fmt 87 | else 88 | error("bad read format",2) 89 | end 90 | return res 91 | end 92 | 93 | function SR:read(...) 94 | if select('#',...) == 0 then 95 | return self:_read('*l') 96 | else 97 | local res, fmts = {},{...} 98 | for i = 1, #fmts do 99 | res[i] = self:_read(fmts[i]) 100 | end 101 | return unpack(res) 102 | end 103 | end 104 | 105 | function SR:seek(whence,offset) 106 | local base 107 | whence = whence or 'cur' 108 | offset = offset or 0 109 | if whence == 'set' then 110 | base = 1 111 | elseif whence == 'cur' then 112 | base = self.i 113 | elseif whence == 'end' then 114 | base = #self.str 115 | end 116 | self.i = base + offset 117 | return self.i 118 | end 119 | 120 | function SR:lines(...) 121 | local n, args = select('#',...) 122 | if n > 0 then 123 | args = {...} 124 | end 125 | return function() 126 | if n == 0 then 127 | return self:_read '*l' 128 | else 129 | return self:read(unpack(args)) 130 | end 131 | end 132 | end 133 | 134 | function SR:close() -- for compatibility only 135 | end 136 | 137 | --- create a file-like object which can be used to construct a string. 138 | -- The resulting object has an extra `value()` method for 139 | -- retrieving the string value. Implements `file:write`, `file:seek`, `file:lines`, 140 | -- plus an extra `writef` method which works like `utils.printf`. 141 | -- @usage f = create(); f:write('hello, dolly\n'); print(f:value()) 142 | function stringio.create() 143 | return setmetatable({tbl={}},SW) 144 | end 145 | 146 | --- create a file-like object for reading from a given string. 147 | -- Implements `file:read`. 148 | -- @string s The input string. 149 | -- @usage fs = open '20 10'; x,y = f:read ('*n','*n'); assert(x == 20 and y == 10) 150 | function stringio.open(s) 151 | return setmetatable({str=s,i=1},SR) 152 | end 153 | 154 | function stringio.lines(s,...) 155 | return stringio.open(s):lines(...) 156 | end 157 | 158 | return stringio 159 | -------------------------------------------------------------------------------- /lua/pl/text.lua: -------------------------------------------------------------------------------- 1 | --- Text processing utilities. 2 | -- 3 | -- This provides a Template class (modeled after the same from the Python 4 | -- libraries, see string.Template). It also provides similar functions to those 5 | -- found in the textwrap module. 6 | -- 7 | -- IMPORTANT: this module has been deprecated and will be removed in a future 8 | -- version (2.0). The contents of this module have moved to the `pl.stringx` 9 | -- module. 10 | -- 11 | -- See @{03-strings.md.String_Templates|the Guide}. 12 | -- 13 | -- Dependencies: `pl.stringx`, `pl.utils` 14 | -- @module pl.text 15 | 16 | local utils = require("pl.utils") 17 | 18 | utils.raise_deprecation { 19 | source = "Penlight " .. utils._VERSION, 20 | message = "the contents of module 'pl.text' has moved into 'pl.stringx'", 21 | version_removed = "2.0.0", 22 | deprecated_after = "1.11.0", 23 | no_trace = true, 24 | } 25 | 26 | return require "pl.stringx" 27 | -------------------------------------------------------------------------------- /lua/pl/url.lua: -------------------------------------------------------------------------------- 1 | --- Python-style URL quoting library. 2 | -- 3 | -- @module pl.url 4 | 5 | local url = {} 6 | 7 | local function quote_char(c) 8 | return string.format("%%%02X", string.byte(c)) 9 | end 10 | 11 | --- Quote the url, replacing special characters using the '%xx' escape. 12 | -- @string s the string 13 | -- @bool quote_plus Also escape slashes and replace spaces by plus signs. 14 | -- @return The quoted string, or if `s` wasn't a string, just plain unaltered `s`. 15 | function url.quote(s, quote_plus) 16 | if type(s) ~= "string" then 17 | return s 18 | end 19 | 20 | s = s:gsub("\n", "\r\n") 21 | s = s:gsub("([^A-Za-z0-9 %-_%./])", quote_char) 22 | if quote_plus then 23 | s = s:gsub(" ", "+") 24 | s = s:gsub("/", quote_char) 25 | else 26 | s = s:gsub(" ", "%%20") 27 | end 28 | 29 | return s 30 | end 31 | 32 | local function unquote_char(h) 33 | return string.char(tonumber(h, 16)) 34 | end 35 | 36 | --- Unquote the url, replacing '%xx' escapes and plus signs. 37 | -- @string s the string 38 | -- @return The unquoted string, or if `s` wasn't a string, just plain unaltered `s`. 39 | function url.unquote(s) 40 | if type(s) ~= "string" then 41 | return s 42 | end 43 | 44 | s = s:gsub("+", " ") 45 | s = s:gsub("%%(%x%x)", unquote_char) 46 | s = s:gsub("\r\n", "\n") 47 | 48 | return s 49 | end 50 | 51 | return url 52 | -------------------------------------------------------------------------------- /penlight-dev-1.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "dev" 3 | local rockspec_revision = "1" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | rockspec_format = "3.0" 10 | package = package_name 11 | version = package_version .. "-" .. rockspec_revision 12 | 13 | source = { 14 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 15 | branch = git_checkout 16 | } 17 | 18 | description = { 19 | summary = "Lua utility libraries loosely based on the Python standard libraries", 20 | detailed = [[ 21 | Penlight is a set of pure Lua libraries focusing on input data handling 22 | (such as reading configuration files), functional programming 23 | (such as map, reduce, placeholder expressions,etc), and OS path management. 24 | Much of the functionality is inspired by the Python standard libraries. 25 | ]], 26 | license = "MIT/X11", 27 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 28 | issues_url = "https://github.com/"..github_account_name.."/"..github_repo_name.."/issues", 29 | maintainer = "thijs@thijsschreijer.nl", 30 | } 31 | 32 | dependencies = { 33 | "lua >= 5.1", 34 | "luafilesystem" 35 | } 36 | 37 | test_dependencies = { 38 | "busted", 39 | } 40 | 41 | test = { 42 | type = "busted", 43 | } 44 | 45 | build = { 46 | type = "builtin", 47 | modules = { 48 | ["pl"] = "lua/pl/init.lua", 49 | ["pl.app"] = "lua/pl/app.lua", 50 | ["pl.array2d"] = "lua/pl/array2d.lua", 51 | ["pl.class"] = "lua/pl/class.lua", 52 | ["pl.compat"] = "lua/pl/compat.lua", 53 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 54 | ["pl.config"] = "lua/pl/config.lua", 55 | ["pl.data"] = "lua/pl/data.lua", 56 | ["pl.Date"] = "lua/pl/Date.lua", 57 | ["pl.dir"] = "lua/pl/dir.lua", 58 | ["pl.file"] = "lua/pl/file.lua", 59 | ["pl.func"] = "lua/pl/func.lua", 60 | ["pl.import_into"] = "lua/pl/import_into.lua", 61 | ["pl.input"] = "lua/pl/input.lua", 62 | ["pl.lapp"] = "lua/pl/lapp.lua", 63 | ["pl.lexer"] = "lua/pl/lexer.lua", 64 | ["pl.List"] = "lua/pl/List.lua", 65 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 66 | ["pl.Map"] = "lua/pl/Map.lua", 67 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 68 | ["pl.operator"] = "lua/pl/operator.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.path"] = "lua/pl/path.lua", 71 | ["pl.permute"] = "lua/pl/permute.lua", 72 | ["pl.pretty"] = "lua/pl/pretty.lua", 73 | ["pl.Set"] = "lua/pl/Set.lua", 74 | ["pl.seq"] = "lua/pl/seq.lua", 75 | ["pl.sip"] = "lua/pl/sip.lua", 76 | ["pl.strict"] = "lua/pl/strict.lua", 77 | ["pl.stringio"] = "lua/pl/stringio.lua", 78 | ["pl.stringx"] = "lua/pl/stringx.lua", 79 | ["pl.tablex"] = "lua/pl/tablex.lua", 80 | ["pl.template"] = "lua/pl/template.lua", 81 | ["pl.test"] = "lua/pl/test.lua", 82 | ["pl.text"] = "lua/pl/text.lua", 83 | ["pl.types"] = "lua/pl/types.lua", 84 | ["pl.url"] = "lua/pl/url.lua", 85 | ["pl.utils"] = "lua/pl/utils.lua", 86 | ["pl.xml"] = "lua/pl/xml.lua", 87 | }, 88 | copy_directories = {"docs", "tests"} 89 | } 90 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.10.0-1.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.10.0" 3 | local rockspec_revision = "1" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.10.0-2.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.10.0" 3 | local rockspec_revision = "2" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.11.0-1.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.11.0" 3 | local rockspec_revision = "1" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.11.0-2.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.11.0" 3 | local rockspec_revision = "2" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.12.0-1.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.12.0" 3 | local rockspec_revision = "1" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.12.0-2.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.12.0" 3 | local rockspec_revision = "2" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.13.0-1.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.13.0" 3 | local rockspec_revision = "1" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.13.1-1.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.13.1" 3 | local rockspec_revision = "1" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.14.0-1.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.14.0" 3 | local rockspec_revision = "1" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | rockspec_format = "3.0" 10 | package = package_name 11 | version = package_version .. "-" .. rockspec_revision 12 | 13 | source = { 14 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 15 | branch = git_checkout 16 | } 17 | 18 | description = { 19 | summary = "Lua utility libraries loosely based on the Python standard libraries", 20 | detailed = [[ 21 | Penlight is a set of pure Lua libraries focusing on input data handling 22 | (such as reading configuration files), functional programming 23 | (such as map, reduce, placeholder expressions,etc), and OS path management. 24 | Much of the functionality is inspired by the Python standard libraries. 25 | ]], 26 | license = "MIT/X11", 27 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 28 | issues_url = "https://github.com/"..github_account_name.."/"..github_repo_name.."/issues", 29 | maintainer = "thijs@thijsschreijer.nl", 30 | } 31 | 32 | dependencies = { 33 | "lua >= 5.1", 34 | "luafilesystem" 35 | } 36 | 37 | test_dependencies = { 38 | "busted", 39 | } 40 | 41 | test = { 42 | type = "busted", 43 | } 44 | 45 | build = { 46 | type = "builtin", 47 | modules = { 48 | ["pl"] = "lua/pl/init.lua", 49 | ["pl.strict"] = "lua/pl/strict.lua", 50 | ["pl.dir"] = "lua/pl/dir.lua", 51 | ["pl.operator"] = "lua/pl/operator.lua", 52 | ["pl.input"] = "lua/pl/input.lua", 53 | ["pl.config"] = "lua/pl/config.lua", 54 | ["pl.seq"] = "lua/pl/seq.lua", 55 | ["pl.stringio"] = "lua/pl/stringio.lua", 56 | ["pl.text"] = "lua/pl/text.lua", 57 | ["pl.test"] = "lua/pl/test.lua", 58 | ["pl.tablex"] = "lua/pl/tablex.lua", 59 | ["pl.app"] = "lua/pl/app.lua", 60 | ["pl.stringx"] = "lua/pl/stringx.lua", 61 | ["pl.lexer"] = "lua/pl/lexer.lua", 62 | ["pl.utils"] = "lua/pl/utils.lua", 63 | ["pl.compat"] = "lua/pl/compat.lua", 64 | ["pl.sip"] = "lua/pl/sip.lua", 65 | ["pl.permute"] = "lua/pl/permute.lua", 66 | ["pl.pretty"] = "lua/pl/pretty.lua", 67 | ["pl.class"] = "lua/pl/class.lua", 68 | ["pl.List"] = "lua/pl/List.lua", 69 | ["pl.data"] = "lua/pl/data.lua", 70 | ["pl.Date"] = "lua/pl/Date.lua", 71 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 72 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 73 | ["pl.path"] = "lua/pl/path.lua", 74 | ["pl.array2d"] = "lua/pl/array2d.lua", 75 | ["pl.func"] = "lua/pl/func.lua", 76 | ["pl.lapp"] = "lua/pl/lapp.lua", 77 | ["pl.file"] = "lua/pl/file.lua", 78 | ['pl.template'] = "lua/pl/template.lua", 79 | ["pl.Map"] = "lua/pl/Map.lua", 80 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 81 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 82 | ["pl.Set"] = "lua/pl/Set.lua", 83 | ["pl.xml"] = "lua/pl/xml.lua", 84 | ["pl.url"] = "lua/pl/url.lua", 85 | ["pl.types"] = "lua/pl/types.lua", 86 | ["pl.import_into"] = "lua/pl/import_into.lua" 87 | }, 88 | copy_directories = {"docs", "tests"} 89 | } 90 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.14.0-2.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.14.0" 3 | local rockspec_revision = "2" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.strict"] = "lua/pl/strict.lua", 37 | ["pl.dir"] = "lua/pl/dir.lua", 38 | ["pl.operator"] = "lua/pl/operator.lua", 39 | ["pl.input"] = "lua/pl/input.lua", 40 | ["pl.config"] = "lua/pl/config.lua", 41 | ["pl.compat"] = "lua/pl/config.lua", 42 | ["pl.seq"] = "lua/pl/seq.lua", 43 | ["pl.stringio"] = "lua/pl/stringio.lua", 44 | ["pl.text"] = "lua/pl/text.lua", 45 | ["pl.test"] = "lua/pl/test.lua", 46 | ["pl.tablex"] = "lua/pl/tablex.lua", 47 | ["pl.app"] = "lua/pl/app.lua", 48 | ["pl.stringx"] = "lua/pl/stringx.lua", 49 | ["pl.lexer"] = "lua/pl/lexer.lua", 50 | ["pl.utils"] = "lua/pl/utils.lua", 51 | ["pl.sip"] = "lua/pl/sip.lua", 52 | ["pl.permute"] = "lua/pl/permute.lua", 53 | ["pl.pretty"] = "lua/pl/pretty.lua", 54 | ["pl.class"] = "lua/pl/class.lua", 55 | ["pl.List"] = "lua/pl/List.lua", 56 | ["pl.data"] = "lua/pl/data.lua", 57 | ["pl.Date"] = "lua/pl/Date.lua", 58 | ["pl.init"] = "lua/pl/init.lua", 59 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 60 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 61 | ["pl.path"] = "lua/pl/path.lua", 62 | ["pl.array2d"] = "lua/pl/array2d.lua", 63 | ["pl.func"] = "lua/pl/func.lua", 64 | ["pl.lapp"] = "lua/pl/lapp.lua", 65 | ["pl.file"] = "lua/pl/file.lua", 66 | ['pl.template'] = "lua/pl/template.lua", 67 | ["pl.Map"] = "lua/pl/Map.lua", 68 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 69 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 70 | ["pl.Set"] = "lua/pl/Set.lua", 71 | ["pl.xml"] = "lua/pl/xml.lua", 72 | ["pl.url"] = "lua/pl/url.lua", 73 | ["pl.import_into"] = "lua/pl/import_into.lua", 74 | ["pl.types"] = "lua/pl/types.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.14.0-3.rockspec: -------------------------------------------------------------------------------- 1 | local package_name = "penlight" 2 | local package_version = "1.14.0" 3 | local rockspec_revision = "3" 4 | local github_account_name = "lunarmodules" 5 | local github_repo_name = package_name 6 | local git_checkout = package_version == "dev" and "master" or package_version 7 | 8 | 9 | package = package_name 10 | version = package_version .. "-" .. rockspec_revision 11 | 12 | source = { 13 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", 14 | branch = git_checkout 15 | } 16 | 17 | description = { 18 | summary = "Lua utility libraries loosely based on the Python standard libraries", 19 | homepage = "https://"..github_account_name..".github.io/"..github_repo_name, 20 | license = "MIT/X11", 21 | maintainer = "thijs@thijsschreijer.nl", 22 | detailed = [[ 23 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 24 | iterating over directories, reading configuration files and the like. Provides functional operations 25 | on tables and sequences. 26 | ]] 27 | } 28 | 29 | dependencies = { 30 | "luafilesystem", 31 | } 32 | 33 | build = { 34 | type = "builtin", 35 | modules = { 36 | ["pl.app"] = "lua/pl/app.lua", 37 | ["pl.array2d"] = "lua/pl/array2d.lua", 38 | ["pl.class"] = "lua/pl/class.lua", 39 | ["pl.compat"] = "lua/pl/compat.lua", 40 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 41 | ["pl.config"] = "lua/pl/config.lua", 42 | ["pl.data"] = "lua/pl/data.lua", 43 | ["pl.Date"] = "lua/pl/Date.lua", 44 | ["pl.dir"] = "lua/pl/dir.lua", 45 | ["pl.file"] = "lua/pl/file.lua", 46 | ["pl.func"] = "lua/pl/func.lua", 47 | ["pl.import_into"] = "lua/pl/import_into.lua", 48 | ["pl.init"] = "lua/pl/init.lua", 49 | ["pl.input"] = "lua/pl/input.lua", 50 | ["pl.lapp"] = "lua/pl/lapp.lua", 51 | ["pl.lexer"] = "lua/pl/lexer.lua", 52 | ["pl.List"] = "lua/pl/List.lua", 53 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 54 | ["pl.Map"] = "lua/pl/Map.lua", 55 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 56 | ["pl.operator"] = "lua/pl/operator.lua", 57 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 58 | ["pl.path"] = "lua/pl/path.lua", 59 | ["pl.permute"] = "lua/pl/permute.lua", 60 | ["pl.pretty"] = "lua/pl/pretty.lua", 61 | ["pl.seq"] = "lua/pl/seq.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.sip"] = "lua/pl/sip.lua", 64 | ["pl.strict"] = "lua/pl/strict.lua", 65 | ["pl.stringio"] = "lua/pl/stringio.lua", 66 | ["pl.stringx"] = "lua/pl/stringx.lua", 67 | ["pl.tablex"] = "lua/pl/tablex.lua", 68 | ["pl.test"] = "lua/pl/test.lua", 69 | ["pl.text"] = "lua/pl/text.lua", 70 | ["pl.types"] = "lua/pl/types.lua", 71 | ["pl.url"] = "lua/pl/url.lua", 72 | ["pl.utils"] = "lua/pl/utils.lua", 73 | ["pl.xml"] = "lua/pl/xml.lua", 74 | ['pl.template'] = "lua/pl/template.lua", 75 | }, 76 | copy_directories = {"docs", "tests"} 77 | } 78 | 79 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.6.0-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.6.0-1" 3 | 4 | source = { 5 | url = "git://github.com/Tieske/Penlight.git", 6 | branch = "1.6.0" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "http://tieske.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.6.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.6.0-2" 3 | 4 | source = { 5 | url = "git+https://github.com/Tieske/Penlight.git", 6 | branch = "1.6.0" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "http://tieske.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.7.0-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.7.0-1" 3 | 4 | source = { 5 | url = "git://github.com/Tieske/Penlight.git", 6 | branch = "1.7.0" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "http://tieske.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.7.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.7.0-2" 3 | 4 | source = { 5 | url = "git+https://github.com/Tieske/Penlight.git", 6 | branch = "1.7.0" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "http://tieske.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.8.0-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.8.0-1" 3 | 4 | source = { 5 | url = "git://github.com/Tieske/Penlight.git", 6 | branch = "1.8.0" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "http://tieske.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.8.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.8.0-2" 3 | 4 | source = { 5 | url = "git+https://github.com/Tieske/Penlight.git", 6 | branch = "1.8.0" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "http://tieske.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.8.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.8.1-1" 3 | 4 | source = { 5 | url = "git://github.com/lunarmodules/Penlight.git", 6 | tag = "1.8.1" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "https://lunarmodules.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.8.1-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.8.1-2" 3 | 4 | source = { 5 | url = "git+https://github.com/lunarmodules/Penlight.git", 6 | tag = "1.8.1" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "https://lunarmodules.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.9.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.9.1-1" 3 | 4 | source = { 5 | url = "git://github.com/lunarmodules/Penlight.git", 6 | tag = "1.9.1" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "https://lunarmodules.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.9.1-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.9.1-2" 3 | 4 | source = { 5 | url = "git+https://github.com/lunarmodules/Penlight.git", 6 | tag = "1.9.1" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "https://lunarmodules.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.9.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.9.2-1" 3 | 4 | source = { 5 | url = "git://github.com/lunarmodules/Penlight.git", 6 | tag = "1.9.2" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "https://lunarmodules.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /rockspecs/penlight-1.9.2-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "penlight" 2 | version = "1.9.2-2" 3 | 4 | source = { 5 | url = "git+https://github.com/lunarmodules/Penlight.git", 6 | tag = "1.9.2" 7 | } 8 | 9 | description = { 10 | summary = "Lua utility libraries loosely based on the Python standard libraries", 11 | homepage = "https://lunarmodules.github.io/Penlight", 12 | license = "MIT/X11", 13 | maintainer = "thijs@thijsschreijer.nl", 14 | detailed = [[ 15 | Penlight is a set of pure Lua libraries for making it easier to work with common tasks like 16 | iterating over directories, reading configuration files and the like. Provides functional operations 17 | on tables and sequences. 18 | ]] 19 | } 20 | 21 | dependencies = { 22 | "luafilesystem", 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | ["pl.strict"] = "lua/pl/strict.lua", 29 | ["pl.dir"] = "lua/pl/dir.lua", 30 | ["pl.operator"] = "lua/pl/operator.lua", 31 | ["pl.input"] = "lua/pl/input.lua", 32 | ["pl.config"] = "lua/pl/config.lua", 33 | ["pl.compat"] = "lua/pl/config.lua", 34 | ["pl.seq"] = "lua/pl/seq.lua", 35 | ["pl.stringio"] = "lua/pl/stringio.lua", 36 | ["pl.text"] = "lua/pl/text.lua", 37 | ["pl.test"] = "lua/pl/test.lua", 38 | ["pl.tablex"] = "lua/pl/tablex.lua", 39 | ["pl.app"] = "lua/pl/app.lua", 40 | ["pl.stringx"] = "lua/pl/stringx.lua", 41 | ["pl.lexer"] = "lua/pl/lexer.lua", 42 | ["pl.utils"] = "lua/pl/utils.lua", 43 | ["pl.sip"] = "lua/pl/sip.lua", 44 | ["pl.permute"] = "lua/pl/permute.lua", 45 | ["pl.pretty"] = "lua/pl/pretty.lua", 46 | ["pl.class"] = "lua/pl/class.lua", 47 | ["pl.List"] = "lua/pl/List.lua", 48 | ["pl.data"] = "lua/pl/data.lua", 49 | ["pl.Date"] = "lua/pl/Date.lua", 50 | ["pl.init"] = "lua/pl/init.lua", 51 | ["pl.luabalanced"] = "lua/pl/luabalanced.lua", 52 | ["pl.comprehension"] = "lua/pl/comprehension.lua", 53 | ["pl.path"] = "lua/pl/path.lua", 54 | ["pl.array2d"] = "lua/pl/array2d.lua", 55 | ["pl.func"] = "lua/pl/func.lua", 56 | ["pl.lapp"] = "lua/pl/lapp.lua", 57 | ["pl.file"] = "lua/pl/file.lua", 58 | ['pl.template'] = "lua/pl/template.lua", 59 | ["pl.Map"] = "lua/pl/Map.lua", 60 | ["pl.MultiMap"] = "lua/pl/MultiMap.lua", 61 | ["pl.OrderedMap"] = "lua/pl/OrderedMap.lua", 62 | ["pl.Set"] = "lua/pl/Set.lua", 63 | ["pl.xml"] = "lua/pl/xml.lua", 64 | ["pl.url"] = "lua/pl/url.lua", 65 | ["pl.import_into"] = "lua/pl/import_into.lua", 66 | ["pl.types"] = "lua/pl/types.lua", 67 | }, 68 | copy_directories = {"docs", "tests"} 69 | } 70 | 71 | -------------------------------------------------------------------------------- /run.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | -- Running tests and/or examples. 4 | local lfs = require "lfs" 5 | 6 | local directories = {} 7 | local luacov = false 8 | 9 | for _, argument in ipairs(arg) do 10 | if argument == "--help" then 11 | print("Usage: lua run.lua [--luacov] []...") 12 | os.exit(0) 13 | elseif argument == "--luacov" then 14 | luacov = true 15 | else 16 | table.insert(directories, argument) 17 | end 18 | end 19 | 20 | if #directories == 0 then 21 | directories = {"tests", "examples"} 22 | end 23 | 24 | local lua = "lua" 25 | local i = -1 26 | while arg[i] do 27 | lua = arg[i] 28 | i = i - 1 29 | end 30 | 31 | if luacov then 32 | lua = lua .. " -lluacov" 33 | end 34 | 35 | local dir_sep = package.config:sub(1, 1) 36 | local quote = dir_sep == "/" and "'" or '"' 37 | local pl_src = "lua/?.lua;lua/?/init.lua" 38 | lua = lua .. " -e " .. quote .. "package.path=[[" .. pl_src .. ";]]..package.path" .. quote 39 | 40 | local function run_directory(dir) 41 | local files = {} 42 | for path in lfs.dir(dir) do 43 | local full_path = dir .. dir_sep .. path 44 | if path:find("%.lua$") and lfs.attributes(full_path, "mode") == "file" then 45 | table.insert(files, full_path) 46 | end 47 | end 48 | table.sort(files) 49 | 50 | for _, file in ipairs(files) do 51 | local cmd = lua .. " " .. file 52 | print("Running " .. file) 53 | local code1, _, code2 = os.execute(cmd) 54 | local code = type(code1) == "number" and code1 or code2 55 | 56 | if code ~= 0 then 57 | print(("Running %s failed with code %d"):format(file, code)) 58 | os.exit(1) 59 | end 60 | end 61 | end 62 | 63 | for _, dir in ipairs(directories) do 64 | print("Running files in " .. dir) 65 | run_directory(dir) 66 | end 67 | 68 | print("Run completed successfully") 69 | -------------------------------------------------------------------------------- /spec/app_spec.lua: -------------------------------------------------------------------------------- 1 | local app = require("pl.app") 2 | 3 | describe("pl.app.lua", function () 4 | 5 | local invocation = app.lua() 6 | 7 | it("should pick up the arguments used to run this test", function () 8 | assert.is.truthy(invocation:match("lua.+package.+busted")) 9 | end) 10 | 11 | it("should be reusable to invoke Lua", function () 12 | assert.is.truthy(os.execute(app.lua()..' -e "n=1;os.exit(n-1)"')) 13 | end) 14 | 15 | end) 16 | 17 | describe("pl.app.platform", function () 18 | 19 | -- TODO: Find a reliable alternate way to determine platform to check that 20 | -- this is returning the right answer, not just any old answer. 21 | it("should at least return a valid platform", function () 22 | local platforms = { Linux = true, OSX = true, Windows = true } 23 | local detected = app.platform() 24 | assert.is.truthy(platforms[detected]) 25 | end) 26 | 27 | end) 28 | -------------------------------------------------------------------------------- /spec/date_spec.lua: -------------------------------------------------------------------------------- 1 | local Date = require("pl.Date") 2 | 3 | describe("pl.Date", function () 4 | 5 | describe("function", function () 6 | 7 | describe("Format()", function () 8 | 9 | it("should output parsable inputs", function () 10 | local function assert_date_format(expected, format) 11 | local df = Date.Format(format) 12 | local d = df:parse(expected) 13 | assert.is.equal(expected, df:tostring(d)) 14 | end 15 | assert_date_format('02/04/10', 'dd/mm/yy') 16 | assert_date_format('04/02/2010', 'mm/dd/yyyy') 17 | assert_date_format('2011-02-20', 'yyyy-mm-dd') 18 | assert_date_format('20070320', 'yyyymmdd') 19 | assert_date_format('23:10', 'HH:MM') 20 | end) 21 | 22 | it("should parse 'slack' fields", function () 23 | local df = Date.Format("m/d/yy") 24 | -- TODO: Re-enable when issue #359 fixed 25 | -- assert.is.equal('01/05/99', df:tostring(df:parse('1/5/99'))) 26 | assert.is.equal('01/05/01', df:tostring(df:parse('1/5/01'))) 27 | assert.is.equal('01/05/32', df:tostring(df:parse('1/5/32'))) 28 | end) 29 | 30 | end) 31 | 32 | end) 33 | 34 | describe("meta method", function () 35 | 36 | describe("__tostring()", function () 37 | 38 | it("should be suitable for serialization", function () 39 | local df = Date.Format() 40 | local du = df:parse("2008-07-05") 41 | assert.is.equal(du, du:toUTC()) 42 | end) 43 | 44 | end) 45 | 46 | end) 47 | 48 | end) 49 | -------------------------------------------------------------------------------- /spec/func_spec.lua: -------------------------------------------------------------------------------- 1 | local func = require("pl.func") 2 | 3 | describe("pl.func", function () 4 | 5 | describe("compose", function () 6 | 7 | it("compose(f)(x) == f(x)", function () 8 | local f = function(x) return x + 1 end 9 | assert.equals(func.compose(f)(1), f(1)) 10 | end) 11 | 12 | it("compose(f, g)(x) == f(g(x))", function () 13 | local f = function(x) return x + 1 end 14 | local g = function(x) return x + 2 end 15 | assert.equals(func.compose(f, g)(1), f(g(1))) 16 | end) 17 | 18 | it("compose(f, g, h)(x) == f(g(h(x)))", function () 19 | local f = function(x) return x + 1 end 20 | local g = function(x) return x + 2 end 21 | local h = function(x) return x + 3 end 22 | assert.equals(func.compose(f, g, h)(1), f(g(h(1)))) 23 | end) 24 | 25 | it("compose(f)(x, y) == f(x, y)", function () 26 | local f = function(x, y) return x + 1, y + 1 end 27 | local ax, ay = func.compose(f)(1, 2) 28 | local bx, by = f(1, 2) 29 | assert.equals(ax, bx) 30 | assert.equals(ay, by) 31 | end) 32 | 33 | it("compose(f, g)(x, y) == f(g(x, y))", function () 34 | local f = function(x, y) return x + 1, y + 1 end 35 | local g = function(x, y) return x + 2, y + 2 end 36 | local ax, ay = func.compose(f, g)(1, 2) 37 | local bx, by = f(g(1, 2)) 38 | assert.equals(ax, bx) 39 | assert.equals(ay, by) 40 | end) 41 | 42 | it("compose(f, g, h)(x, y) == f(g(h(x, y)))", function () 43 | local f = function(x, y) return x + 1, y + 1 end 44 | local g = function(x, y) return x + 2, y + 2 end 45 | local h = function(x, y) return x + 3, y + 3 end 46 | local ax, ay = func.compose(f, g, h)(1, 2) 47 | local bx, by = f(g(h(1, 2))) 48 | assert.equals(ax, bx) 49 | assert.equals(ay, by) 50 | end) 51 | 52 | end) 53 | 54 | end) 55 | -------------------------------------------------------------------------------- /spec/multimap_spec.lua: -------------------------------------------------------------------------------- 1 | local MultiMap = require("pl.MultiMap") 2 | 3 | describe("pl.MultiMap", function () 4 | 5 | it("should hold multiple values per key", function () 6 | local map = MultiMap() 7 | map:set('foo', 1) 8 | map:set('bar', 3) 9 | map:set('foo', 2) 10 | local expected = { foo = { 1, 2 }, bar = { 3 } } 11 | assert.is.same(expected, map) 12 | end) 13 | 14 | end) 15 | -------------------------------------------------------------------------------- /spec/path_spec.lua: -------------------------------------------------------------------------------- 1 | 2 | -- conditional it/pending blocks per platform 3 | local function nix_it(desc, ...) 4 | if package.config:sub(1,1) == "\\" then 5 | pending("Skip test on Windows: " .. desc, ...) 6 | else 7 | it(desc, ...) 8 | end 9 | end 10 | local function win_it(desc, ...) 11 | if package.config:sub(1,1) == "\\" then 12 | it(desc, ...) 13 | else 14 | pending("Skip test on Unix: " .. desc, ...) 15 | end 16 | end 17 | 18 | 19 | 20 | describe("pl.path", function() 21 | 22 | local path 23 | local mock_envs 24 | local old_get_env 25 | 26 | before_each(function() 27 | mock_envs = {} 28 | old_get_env = os.getenv 29 | os.getenv = function(name) -- luacheck: ignore 30 | return mock_envs[name] 31 | end 32 | package.loaded["pl.path"] = nil 33 | path = require "pl.path" 34 | end) 35 | 36 | after_each(function() 37 | package.loaded["pl.path"] = nil 38 | os.getenv = old_get_env -- luacheck: ignore 39 | end) 40 | 41 | 42 | 43 | describe("expanduser()", function() 44 | 45 | it("should expand ~ to the user's home directory", function() 46 | mock_envs = { 47 | HOME = "/home/user", 48 | } 49 | assert.equal("/home/user/file", path.expanduser("~/file")) 50 | end) 51 | 52 | 53 | nix_it("returns an error if expansion fails: HOME not set", function() 54 | mock_envs = {} 55 | assert.same( 56 | { nil, "failed to expand '~' (HOME not set)" }, 57 | { path.expanduser("~/file")} 58 | ) 59 | end) 60 | 61 | 62 | win_it("returns an error if expansion fails: all Windows vars", function() 63 | mock_envs = {} 64 | assert.same( 65 | { nil, "failed to expand '~' (HOME, USERPROFILE, and HOMEDRIVE and/or HOMEPATH not set)" }, 66 | { path.expanduser("~/file")} 67 | ) 68 | end) 69 | 70 | 71 | win_it("HOME is first in line", function() 72 | mock_envs = { 73 | HOME = "\\home\\user1", 74 | USERPROFILE = "\\home\\user2", 75 | HOMEDRIVE = "C:", 76 | HOMEPATH = "\\home\\user3", 77 | } 78 | assert.equal("\\home\\user1\\file", path.expanduser("~\\file")) 79 | end) 80 | 81 | 82 | win_it("USERPROFILE is second in line", function() 83 | mock_envs = { 84 | --HOME = "\\home\\user1", 85 | USERPROFILE = "\\home\\user2", 86 | HOMEDRIVE = "C:", 87 | HOMEPATH = "\\home\\user3", 88 | } 89 | assert.equal("\\home\\user2\\file", path.expanduser("~\\file")) 90 | end) 91 | 92 | 93 | win_it("HOMEDRIVE/PATH is third in line", function() 94 | mock_envs = { 95 | -- HOME = "\\home\\user1", 96 | -- USERPROFILE = "\\home\\user2", 97 | HOMEDRIVE = "C:", 98 | HOMEPATH = "\\home\\user3", 99 | } 100 | assert.equal("C:\\home\\user3\\file", path.expanduser("~\\file")) 101 | end) 102 | 103 | end) 104 | 105 | end) 106 | 107 | -------------------------------------------------------------------------------- /spec/pretty_spec.lua: -------------------------------------------------------------------------------- 1 | local pretty = require("pl.pretty") 2 | 3 | describe("pl.pretty.number", function () 4 | 5 | it("should format memory", function () 6 | local function assert_memory (expected, input) 7 | assert.is.equal(expected, pretty.number(input, "M")) 8 | end 9 | assert_memory("123B", 123) 10 | assert_memory("1.2KiB", 1234) 11 | assert_memory("10.0KiB", 10*1024) 12 | assert_memory("1.0MiB", 1024*1024) 13 | assert_memory("1.0GiB", 1024*1024*1024) 14 | end) 15 | 16 | it("should format postfixes", function () 17 | local function assert_postfix(expected, input) 18 | assert.is.equal(expected, pretty.number(input, "N", 2)) 19 | end 20 | assert_postfix("123", 123) 21 | assert_postfix("1.23K", 1234) 22 | assert_postfix("10.24K", 10*1024) 23 | assert_postfix("1.05M", 1024*1024) 24 | assert_postfix("1.07B", 1024*1024*1024) 25 | end) 26 | 27 | it("should format postfixes", function () 28 | local function assert_separator(expected, input) 29 | assert.is.equal(expected, pretty.number(input, "T")) 30 | end 31 | assert_separator('123', 123) 32 | assert_separator('1,234', 1234) 33 | assert_separator('12,345', 12345) 34 | assert_separator('123,456', 123456) 35 | assert_separator('1,234,567', 1234567) 36 | assert_separator('12,345,678', 12345678) 37 | end) 38 | 39 | 40 | end) 41 | -------------------------------------------------------------------------------- /spec/set_spec.lua: -------------------------------------------------------------------------------- 1 | local Set = require("pl.Set") 2 | 3 | describe("pl.Set", function () 4 | 5 | local s = Set() 6 | local s1_2 = Set({ 1, 2 }) 7 | local s1_2_3 = Set({ 1, 2, 3 }) 8 | local s1_3 = Set({ 1, 3 }) 9 | local s2 = Set({ 2 }) 10 | local s2_1 = Set({ 2, 1 }) 11 | local s2_3 = Set({ 2, 3 }) 12 | local s3 = Set({ 3 }) 13 | local sm = Set({ "foo", "bar" }) 14 | 15 | it("should produce a set object", function () 16 | assert.is.same({ true, true }, s1_2) 17 | end) 18 | 19 | it("should produce identical sets for any ordered input", function () 20 | assert.is.same(s1_2, s2_1) 21 | end) 22 | 23 | describe("should have an operator for", function () 24 | 25 | it("union", function () 26 | assert.is.same(s1_2_3, s1_2 + s3) 27 | assert.is.same(s1_2_3, s1_2 + 3) 28 | end) 29 | 30 | it("intersection", function () 31 | assert.is.same(s2, s1_2 * s2_3) 32 | end) 33 | 34 | it("difference", function () 35 | assert.is.same(s2_1, s1_2_3 - s3) 36 | assert.is.same(s2_3, s1_2_3 - 1) 37 | end) 38 | 39 | it("symmetric difference", function () 40 | assert.is.same(s1_3, s1_2 ^ s2_3) 41 | end) 42 | 43 | it("tostring", function () 44 | -- Cannot test multi-entry sets because of non-deterministic key order 45 | assert.is.same('[2]', tostring(s2)) 46 | end) 47 | 48 | end) 49 | 50 | describe("should provide functions", function () 51 | 52 | it("isempty", function () 53 | assert.is.truthy(Set.isempty(s)) 54 | assert.is.falsy(Set.isempty(s3)) 55 | end) 56 | 57 | it("set", function () 58 | local m = Set() 59 | Set.set(m, 'foo', true) 60 | m.bar = true 61 | assert.is.same(m, sm) 62 | assert.is_not.same(m, s1_2) 63 | end) 64 | 65 | end) 66 | 67 | describe("should have a comparison operator for", function () 68 | 69 | it("supersets/subsets than", function () 70 | assert.is.truthy(s1_2 > s2) 71 | assert.is.falsy(s1_3 > s2) 72 | assert.is.falsy(s1_2 > s2_3) 73 | assert.is.truthy(s1_2 < s1_2_3) 74 | assert.is.falsy(s1_2_3 < s1_2) 75 | end) 76 | 77 | it("equality", function () 78 | assert.is.truthy(s1_2 == s2_1) 79 | assert.is.falsy(s1_2 == s2_3) 80 | end) 81 | 82 | end) 83 | 84 | end) 85 | -------------------------------------------------------------------------------- /spec/text_spec.lua: -------------------------------------------------------------------------------- 1 | describe("pl.text", function() 2 | 3 | it("forwarded to stringx", function() 4 | assert.equal( 5 | require "pl.stringx", 6 | require "pl.text" 7 | ) 8 | end) 9 | 10 | end) 11 | -------------------------------------------------------------------------------- /spec/utils-choose_spec.lua: -------------------------------------------------------------------------------- 1 | local utils = require("pl.utils") 2 | 3 | describe("pl.utils", function() 4 | 5 | describe("choose", function () 6 | 7 | it("handles normal values", function() 8 | assert.equal(utils.choose(true, 1, 2), 1) 9 | assert.equal(utils.choose(false, 1, 2), 2) 10 | end) 11 | 12 | it("handles nils", function() 13 | assert.equal(utils.choose(true, nil, 2), nil) 14 | assert.equal(utils.choose(false, nil, 2), 2) 15 | assert.equal(utils.choose(true, 1, nil), 1) 16 | assert.equal(utils.choose(false, 1, nil), nil) 17 | end) 18 | 19 | end) 20 | 21 | end) 22 | -------------------------------------------------------------------------------- /spec/utils-deprecate_spec.lua: -------------------------------------------------------------------------------- 1 | local utils = require("pl.utils") 2 | 3 | describe("pl.utils", function () 4 | 5 | local old_fn, last_msg, last_trace 6 | 7 | before_each(function() 8 | old_fn = function() end 9 | last_msg = nil 10 | last_trace = nil 11 | utils.set_deprecation_func(function(msg, trace) 12 | last_msg = msg 13 | last_trace = trace 14 | end) 15 | end) 16 | 17 | 18 | after_each(function() 19 | utils.deprecation_warning = old_fn 20 | end) 21 | 22 | 23 | 24 | describe("set_deprecation_func", function () 25 | 26 | it("accepts nil as callback", function() 27 | assert.has.no.error(function() 28 | utils.set_deprecation_func() 29 | end) 30 | end) 31 | 32 | 33 | it("accepts function as callback", function() 34 | assert.has.no.error(function() 35 | utils.set_deprecation_func(function() end) 36 | end) 37 | end) 38 | 39 | 40 | it("fails on non-functions", function() 41 | assert.has.error(function() 42 | utils.set_deprecation_func("not a function") 43 | end, "argument 1 expected a 'function', got a 'string'") 44 | end) 45 | 46 | end) 47 | 48 | 49 | 50 | describe("raise_deprecation", function () 51 | 52 | it("requires the opts table", function() 53 | assert.has.error(function() utils.raise_deprecation(nil) end, 54 | "argument 1 expected a 'table', got a 'nil'") 55 | end) 56 | 57 | 58 | it("requires the opts.message field", function() 59 | assert.has.error(function() utils.raise_deprecation({}) end, 60 | "field 'message' of the options table must be a string") 61 | end) 62 | 63 | 64 | it("should output the message", function () 65 | utils.raise_deprecation { 66 | message = "hello world" 67 | } 68 | assert.equal("hello world", last_msg) 69 | end) 70 | 71 | 72 | it("should output the deprecated version", function () 73 | utils.raise_deprecation { 74 | message = "hello world", 75 | deprecated_after = "2.0.0", 76 | } 77 | assert.equal("hello world (deprecated after 2.0.0)", last_msg) 78 | end) 79 | 80 | 81 | it("should output the removal version", function () 82 | utils.raise_deprecation { 83 | message = "hello world", 84 | version_removed = "3.0.0", 85 | } 86 | assert.equal("hello world (scheduled for removal in 3.0.0)", last_msg) 87 | end) 88 | 89 | 90 | it("should output the deprecated and removal versions", function () 91 | utils.raise_deprecation { 92 | message = "hello world", 93 | deprecated_after = "2.0.0", 94 | version_removed = "3.0.0", 95 | } 96 | assert.equal("hello world (deprecated after 2.0.0, scheduled for removal in 3.0.0)", last_msg) 97 | end) 98 | 99 | 100 | it("should output the application/module name", function () 101 | utils.raise_deprecation { 102 | source = "MyApp 1.2.3", 103 | message = "hello world", 104 | deprecated_after = "2.0.0", 105 | version_removed = "3.0.0", 106 | } 107 | assert.equal("[MyApp 1.2.3] hello world (deprecated after 2.0.0, scheduled for removal in 3.0.0)", last_msg) 108 | end) 109 | 110 | 111 | it("should add a stracktrace", function () 112 | local function my_function_name() 113 | utils.raise_deprecation { 114 | source = "MyApp 1.2.3", 115 | message = "hello world", 116 | deprecated_after = "2.0.0", 117 | version_removed = "3.0.0", 118 | } 119 | end 120 | my_function_name() 121 | 122 | assert.Not.match("raise_deprecation", last_trace) 123 | assert.match("my_function_name", last_trace) 124 | end) 125 | 126 | end) 127 | 128 | end) 129 | -------------------------------------------------------------------------------- /spec/utils-enum_spec.lua: -------------------------------------------------------------------------------- 1 | describe("pl.utils", function () 2 | 3 | describe("enum()", function () 4 | local enum, t 5 | 6 | before_each(function() 7 | enum = require("pl.utils").enum 8 | end) 9 | 10 | 11 | describe("creating", function() 12 | 13 | it("accepts a vararg", function() 14 | t = enum("ONE", "two", "THREE") 15 | assert.same({ 16 | ONE = "ONE", 17 | two = "two", 18 | THREE = "THREE", 19 | }, t) 20 | end) 21 | 22 | 23 | it("vararg entries must be strings", function() 24 | assert.has.error(function() 25 | t = enum("hello", true, "world") 26 | end, "argument 2 expected a 'string', got a 'boolean'") 27 | -- no holes 28 | assert.has.error(function() 29 | t = enum("hello", nil, "world") 30 | end, "argument 2 expected a 'string', got a 'nil'") 31 | end) 32 | 33 | 34 | it("vararg requires at least 1 entry", function() 35 | assert.has.error(function() 36 | t = enum() 37 | end, "expected at least 1 entry") 38 | end) 39 | 40 | 41 | it("accepts an array", function() 42 | t = enum { "ONE", "two", "THREE" } 43 | assert.same({ 44 | ONE = "ONE", 45 | two = "two", 46 | THREE = "THREE", 47 | }, t) 48 | end) 49 | 50 | 51 | it("array entries must be strings", function() 52 | assert.has.error(function() 53 | t = enum { "ONE", 999, "THREE" } 54 | end, "expected 'string' but got 'number' at index 2") 55 | end) 56 | 57 | 58 | it("array requires at least 1 entry", function() 59 | assert.has.error(function() 60 | t = enum {} 61 | end, "expected at least 1 entry") 62 | end) 63 | 64 | 65 | it("accepts a hash-table", function() 66 | t = enum { 67 | FILE_NOT_FOUND = "The file was not found in the filesystem", 68 | FILE_READ_ONLY = "The file is read-only", 69 | } 70 | assert.same({ 71 | FILE_NOT_FOUND = "The file was not found in the filesystem", 72 | FILE_READ_ONLY = "The file is read-only", 73 | }, t) 74 | end) 75 | 76 | 77 | it("hash-table keys must be strings", function() 78 | assert.has.error(function() 79 | t = enum { [{}] = "ONE" } 80 | end, "expected key to be 'string' but got 'table'") 81 | end) 82 | 83 | 84 | it("hash-table requires at least 1 entry", function() 85 | assert.has.error(function() 86 | t = enum {} 87 | end, "expected at least 1 entry") 88 | end) 89 | 90 | 91 | it("accepts a combined array/hash-table", function() 92 | t = enum { 93 | "BAD_FD", 94 | FILE_NOT_FOUND = "The file was not found in the filesystem", 95 | FILE_READ_ONLY = "The file is read-only", 96 | } 97 | assert.same({ 98 | BAD_FD = "BAD_FD", 99 | FILE_NOT_FOUND = "The file was not found in the filesystem", 100 | FILE_READ_ONLY = "The file is read-only", 101 | }, t) 102 | end) 103 | 104 | 105 | it("keys must be unique with combined array/has-table", function() 106 | assert.has.error(function() 107 | t = enum { 108 | "FILE_NOT_FOUND", 109 | FILE_NOT_FOUND = "The file was not found in the filesystem", 110 | } 111 | end, "duplicate entry in array and hash part: 'FILE_NOT_FOUND'") 112 | end) 113 | 114 | end) 115 | 116 | 117 | 118 | describe("accessing", function() 119 | 120 | before_each(function() 121 | t = enum("ONE", "two", "THREE") 122 | end) 123 | 124 | 125 | it("errors on unknown values", function() 126 | assert.has.error(function() 127 | print(t.four) 128 | end, "'four' is not a valid value (expected one of: 'ONE', 'two', 'THREE')") 129 | end) 130 | 131 | 132 | it("errors on setting new keys", function() 133 | assert.has.error(function() 134 | t.four = "four" 135 | end, "the Enum object is read-only") 136 | end) 137 | 138 | 139 | it("keys can have 'format' placeholders", function() 140 | t = enum("hello", "contains: %s") 141 | assert.has.error(function() 142 | print(t["%s"]) -- should still format error properly 143 | end, "'%s' is not a valid value (expected one of: 'hello', 'contains: %s')") 144 | end) 145 | 146 | end) 147 | 148 | 149 | 150 | describe("calling", function() 151 | 152 | before_each(function() 153 | t = enum("ONE", "two", "THREE") 154 | end) 155 | 156 | 157 | it("returns error on unknown values", function() 158 | local ok, err = t("four") 159 | assert.equal(err, "'four' is not a valid value (expected one of: 'ONE', 'two', 'THREE')") 160 | assert.equal(nil, ok) 161 | end) 162 | 163 | 164 | it("returns value on success", function() 165 | local ok, err = t("THREE") 166 | assert.equal(nil, err) 167 | assert.equal("THREE", ok) 168 | end) 169 | 170 | end) 171 | 172 | end) 173 | 174 | end) 175 | -------------------------------------------------------------------------------- /spec/utils-kpairs_spec.lua: -------------------------------------------------------------------------------- 1 | local utils = require("pl.utils") 2 | 3 | describe("pl.utils", function () 4 | 5 | describe("kpairs", function () 6 | local kpairs 7 | 8 | before_each(function() 9 | kpairs = utils.kpairs 10 | end) 11 | 12 | 13 | it("iterates over non-integers", function() 14 | local func = function() end 15 | local bool = true 16 | local string = "a string" 17 | local float = 123.45 18 | local r = {} 19 | for k, v in kpairs { 20 | [func] = 1, 21 | [bool] = 2, 22 | [string] = 3, 23 | [float] = 4, 24 | 5, 6, 7, 25 | } do 26 | r[k] = v 27 | end 28 | 29 | assert.same({ 30 | [func] = 1, 31 | [bool] = 2, 32 | [string] = 3, 33 | [float] = 4 }, r) 34 | end) 35 | 36 | end) 37 | 38 | end) 39 | -------------------------------------------------------------------------------- /spec/utils-npairs_spec.lua: -------------------------------------------------------------------------------- 1 | local utils = require("pl.utils") 2 | 3 | describe("pl.utils", function () 4 | 5 | describe("npairs", function () 6 | local npairs = utils.npairs 7 | 8 | it("start index defaults to 1", function() 9 | local t1 = { 1, 2, 3 } 10 | local t2 = {} 11 | for i, v in npairs(t1, nil, 2) do t2[i] = v end 12 | assert.are.same({ 1, 2 }, t2) 13 | end) 14 | 15 | 16 | it("end index defaults to `t.n`", function() 17 | local t1 = { n = 2, 1, 2, 3 } 18 | local t2 = {} 19 | for i, v in npairs(t1) do t2[i] = v end 20 | assert.are.same({1, 2}, t2) 21 | end) 22 | 23 | 24 | it("step size defaults to 1", function() 25 | local t1 = { 1, 2, 3 } 26 | local t2 = {} 27 | for i, v in npairs(t1) do t2[i] = v end 28 | assert.are.same({1, 2, 3}, t2) 29 | end) 30 | 31 | 32 | it("step size cannot be 0", function() 33 | local t1 = { 1, 2, 3 } 34 | assert.has.error(function() 35 | npairs(t1, nil, nil, 0) 36 | end, "iterator step-size cannot be 0") 37 | end) 38 | 39 | 40 | it("end index defaults to `#t` if there is no `t.n`", function() 41 | local t1 = { 1, 2, 3 } 42 | local t2 = {} 43 | for i, v in npairs(t1) do t2[i] = v end 44 | assert.are.same({1, 2, 3}, t2) 45 | end) 46 | 47 | 48 | it("returns nothing if start index is beyond end index", function() 49 | local t1 = { 1, 2, 3 } 50 | local t2 = {} 51 | for i, v in npairs(t1, 5, 3) do t2[i] = v end 52 | assert.are.same({}, t2) 53 | end) 54 | 55 | 56 | it("returns nothing if start index is beyond end index, with negative step size", function() 57 | local t1 = { 1, 2, 3 } 58 | local t2 = {} 59 | for i, v in npairs(t1, 3, 1, -1) do t2[#t2+1] = v end 60 | assert.are.same({ 3, 2, 1}, t2) 61 | end) 62 | 63 | 64 | it("returns 1 key/value if end == start index", function() 65 | local t1 = { 1, 2, 3 } 66 | local t2 = {} 67 | for i, v in npairs(t1, 2, 2) do t2[i] = v end 68 | assert.are.same({ [2] = 2 }, t2) 69 | end) 70 | 71 | 72 | it("returns negative to positive ranges", function() 73 | local t1 = { [-5] = -5, [-4] = -4, [-3] = -3, [-2] = -2, [-1] = -1, [0] = 0, 1, 2, 3 } 74 | local t2 = {} 75 | for i, v in npairs(t1, -4, 1) do t2[i] = v end 76 | assert.are.same({ [-4] = -4, [-3] = -3, [-2] = -2, [-1] = -1, [0] = 0, 1 }, t2) 77 | end) 78 | 79 | 80 | it("returns nil values with the range", function() 81 | local t1 = { n = 3 } 82 | local t2 = {} 83 | for i, v in npairs(t1) do t2[i] = tostring(v) end 84 | assert.are.same({ "nil", "nil", "nil" }, t2) 85 | end) 86 | 87 | 88 | it("honours positive step size", function() 89 | local t1 = { [-5] = -5, [-4] = -4, [-3] = -3, [-2] = -2, [-1] = -1, [0] = 0, 1, 2, 3 } 90 | local t2 = {} 91 | for i, v in npairs(t1, -4, 1, 2) do t2[#t2+1] = v end 92 | assert.are.same({ -4, -2, 0}, t2) 93 | end) 94 | 95 | 96 | it("honours negative step size", function() 97 | local t1 = { [-5] = -5, [-4] = -4, [-3] = -3, [-2] = -2, [-1] = -1, [0] = 0, 1, 2, 3 } 98 | local t2 = {} 99 | for i, v in npairs(t1, 0, -5, -2) do t2[#t2+1] = v end 100 | assert.are.same({ 0, -2, -4 }, t2) 101 | end) 102 | 103 | end) 104 | 105 | end) 106 | -------------------------------------------------------------------------------- /tests/lua/animal.lua: -------------------------------------------------------------------------------- 1 | -- Module containing classes 2 | local class = require 'pl.class' 3 | local utils = require 'pl.utils' 4 | local error = error 5 | if utils.lua51 then 6 | module 'animal' 7 | else 8 | _ENV = {} 9 | end 10 | 11 | class.Animal() 12 | 13 | function Animal:_init(name) 14 | self.name = name 15 | end 16 | 17 | function Animal:__tostring() 18 | return self.name..': '..self:speak() 19 | end 20 | 21 | class.Dog(Animal) 22 | 23 | function Dog:speak() 24 | return 'bark' 25 | end 26 | 27 | class.Cat(Animal) 28 | 29 | function Cat:_init(name,breed) 30 | self:super(name) -- must init base! 31 | self.breed = breed 32 | end 33 | 34 | function Cat:speak() 35 | return 'meow' 36 | end 37 | 38 | -- you may declare the methods in-line like so; 39 | -- note the meaning of `_base`! 40 | class.Lion { 41 | _base = Cat; 42 | speak = function(self) 43 | return 'roar' 44 | end 45 | } 46 | 47 | -- a class may handle unknown methods with `catch`: 48 | Lion:catch(function(self,name) 49 | return function() error("no such method "..name,2) end 50 | end) 51 | 52 | if not utils.lua51 then 53 | return _ENV 54 | end 55 | -------------------------------------------------------------------------------- /tests/lua/bar.lua: -------------------------------------------------------------------------------- 1 | --- test module for demonstrating app.require_here() 2 | local bar = {} 3 | 4 | function bar.name () 5 | return 'bar' 6 | end 7 | 8 | return bar 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/lua/foo/args.lua: -------------------------------------------------------------------------------- 1 | --- test module for demonstrating app.require_here() 2 | local args = {} 3 | 4 | function args.answer () 5 | return 42 6 | end 7 | 8 | return args 9 | 10 | -------------------------------------------------------------------------------- /tests/lua/mod52.lua: -------------------------------------------------------------------------------- 1 | local test = require 'pl.test' 2 | local LUA_VERSION = _VERSION 3 | print(LUA_VERSION) 4 | 5 | -- if STRICT is true, then M is distinct from _ENV, and ONLY contains 6 | -- the exported functions! 7 | 8 | local _ENV,M = require 'pl.import_into' (rawget(_G,'STRICT')) 9 | 10 | function answer () 11 | -- of course, you don't have the usual global environment available 12 | -- so define it as a local up above, or use utils.import(_G). 13 | 14 | local versioned_errors = { 15 | ["1"] = "attempt to call global 'print'", 16 | ["2"] = "attempt to call global 'print'", 17 | ["3"] = "attempt to call a nil value", 18 | ["4"] = "a nil value", 19 | } 20 | local expected = versioned_errors[LUA_VERSION:match("Lua 5.(%d)")] 21 | test.assertraise(function() 22 | print 'hello' 23 | end, expected) 24 | 25 | -- but all the Penlight modules are available 26 | return pretty.write(utils.split '10 20 30', '') 27 | end 28 | 29 | return M 30 | 31 | -------------------------------------------------------------------------------- /tests/lua/mymod.lua: -------------------------------------------------------------------------------- 1 | local strict = require 'pl.strict' 2 | local test = require 'pl.test' 3 | local M = strict.module (...) 4 | 5 | function M.answer () 6 | Boo = false -- fine, it's a declared global 7 | -- in strict mode, you cannot assign to globals if you aren't in main 8 | test.assertraise(function() 9 | Foo = true 10 | end," assign to undeclared global 'Foo'") 11 | return 42 12 | end 13 | 14 | function M.question () 15 | return 'what is the answer to Life, the Universe and Everything?' 16 | end 17 | 18 | return M 19 | 20 | -------------------------------------------------------------------------------- /tests/test-__vector.lua: -------------------------------------------------------------------------------- 1 | ---- deriving specialized classes from List 2 | -- illustrating covariance of List methods 3 | local test = require 'pl.test' 4 | local class = require 'pl.class' 5 | local types = require 'pl.types' 6 | local operator = require 'pl.operator' 7 | local List = require 'pl.List' 8 | 9 | local asserteq = test.asserteq 10 | 11 | class.Vector(List) 12 | 13 | 14 | function Vector.range (x1,x2,delta) 15 | return Vector(List.range(x1,x2,delta)) 16 | end 17 | 18 | local function vbinop (op,v1,v2,scalar) 19 | if not Vector:class_of(v1) then 20 | v2, v1 = v1, v2 21 | end 22 | if type(v2) ~= 'table' then 23 | return v1:map(op,v2) 24 | else 25 | if scalar then error("operation not permitted on two vectors",3) end 26 | if #v1 ~= #v2 then error("vectors have different lengths",3) end 27 | return v1:map2(op,v2) 28 | end 29 | end 30 | 31 | function Vector.__add (v1,v2) 32 | return vbinop(operator.add,v1,v2) 33 | end 34 | 35 | function Vector.__sub (v1,v2) 36 | return vbinop(operator.sub,v1,v2) 37 | end 38 | 39 | function Vector.__mul (v1,v2) 40 | return vbinop(operator.mul,v1,v2,true) 41 | end 42 | 43 | function Vector.__div (v1,v2) 44 | return vbinop(operator.div,v1,v2,true) 45 | end 46 | 47 | function Vector.__unm (v) 48 | return v:map(operator.unm) 49 | end 50 | 51 | Vector:catch(List.default_map_with(math)) 52 | 53 | v = Vector() 54 | 55 | assert(v:is_a(Vector)) 56 | assert(Vector:class_of(v)) 57 | 58 | v:append(10) 59 | v:append(20) 60 | asserteq(1+v,v+1) 61 | 62 | -- covariance: the inherited Vector.map returns a Vector 63 | asserteq(List{1,2} + v:map '2*_',{21,42}) 64 | 65 | u = Vector{1,2} 66 | 67 | asserteq(v + u,{11,22}) 68 | asserteq(v - u,{9,18}) 69 | asserteq (v - 1, {9,19}) 70 | asserteq(2 * v, {20,40}) 71 | -- print(v * v) -- throws error: not permitted 72 | -- print(v + Vector{1,2,3}) -- throws error: different lengths 73 | asserteq(2*v + u, {21,42}) 74 | asserteq(-v, {-10,-20}) 75 | 76 | -- Vector.slice returns the Right Thing due to covariance 77 | asserteq( 78 | Vector.range(0,1,0.1):slice(1,3)+1, 79 | {1,1.1,1.2}, 80 | 1e-8) 81 | 82 | u:transform '_+1' 83 | asserteq(u,{2,3}) 84 | 85 | u = Vector.range(0,1,0.1) 86 | asserteq( 87 | u:map(math.sin), 88 | {0,0.0998,0.1986,0.2955,0.3894,0.4794,0.5646,0.6442,0.7173,0.7833,0.8414}, 89 | 0.001) 90 | 91 | -- unknown Vector methods are assumed to be math.* functions 92 | asserteq(Vector{-1,2,3,-4}:abs(),Vector.range(1,4)) 93 | 94 | local R = Vector.range 95 | 96 | -- concatenating two Vectors returns another vector (covariance again) 97 | -- note the operator precedence here... 98 | asserteq(( 99 | R(0,1,0.1)..R(1.2,2,0.2)) + 1, 100 | {1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2,2.2,2.4,2.6,2.8,3}, 101 | 1e-8) 102 | 103 | 104 | class.Strings(List) 105 | 106 | Strings:catch(List.default_map_with(string)) 107 | 108 | ls = Strings{'one','two','three'} 109 | asserteq(ls:upper(),{'ONE','TWO','THREE'}) 110 | asserteq(ls:sub(1,2),{'on','tw','th'}) 111 | 112 | -- all map operations on specialized lists 113 | -- results in another list of that type! This isn't necessarily 114 | -- what you want. 115 | local sizes = ls:map '#' 116 | asserteq(sizes, {3,3,5}) 117 | asserteq(types.type(sizes),'Strings') 118 | asserteq(sizes:is_a(Strings),true) 119 | sizes = Vector:cast(sizes) 120 | asserteq(types.type(sizes),'Vector') 121 | asserteq(sizes+1,{4,4,6}) 122 | 123 | 124 | -------------------------------------------------------------------------------- /tests/test-app/require_here-link-target.lua: -------------------------------------------------------------------------------- 1 | -- This file is used as a symbolic link target in test-app.lua, to verify the 2 | -- behaviors of pl.app.require_here() 3 | 4 | local p = package.path 5 | require("pl.app").require_here(nil, #arg > 0) 6 | print(package.path:sub(1, -#p-1)) 7 | -------------------------------------------------------------------------------- /tests/test-class.lua: -------------------------------------------------------------------------------- 1 | local class = require 'pl.class' 2 | local test = require 'pl.test' 3 | asserteq = test.asserteq 4 | T = test.tuple 5 | 6 | A = class() 7 | 8 | function A:_init () 9 | self.a = 1 10 | end 11 | 12 | -- calling base class' ctor automatically 13 | A1 = class(A) 14 | 15 | asserteq(A1(),{a=1}) 16 | 17 | -- explicitly calling base ctor with super 18 | 19 | B = class(A) 20 | 21 | function B:_init () 22 | self:super() 23 | self.b = 2 24 | end 25 | 26 | function B:foo () 27 | self.eee = 1 28 | end 29 | 30 | function B:foo2 () 31 | self.g = 8 32 | end 33 | 34 | asserteq(B(),{a=1,b=2}) 35 | 36 | -- can continue this chain 37 | 38 | C = class(B) 39 | 40 | function C:_init () 41 | self:super() 42 | self.c = 3 43 | end 44 | 45 | function C:foo () 46 | -- recommended way to call inherited version of method... 47 | B.foo(self) 48 | end 49 | 50 | c = C() 51 | c:foo() 52 | 53 | asserteq(c,{a=1,b=2,c=3,eee=1}) 54 | 55 | -- test indirect inherit 56 | 57 | D = class(C) 58 | 59 | E = class(D) 60 | 61 | function E:_init () 62 | self:super() 63 | self.e = 4 64 | end 65 | 66 | function E:foo () 67 | -- recommended way to call inherited version of method... 68 | self.eeee = 5 69 | C.foo(self) 70 | end 71 | 72 | F = class(E) 73 | 74 | function F:_init () 75 | self:super() 76 | self.f = 6 77 | end 78 | 79 | f = F() 80 | f:foo() 81 | f:foo2() -- Test : invocation inherits this function from all the way up in B 82 | 83 | asserteq(f,{a=1,b=2,c=3,eee=1,e=4,eeee=5,f=6,g=8}) 84 | 85 | -- Test that inappropriate calls to super() fail gracefully 86 | 87 | G = class() -- Class with no init 88 | 89 | H = class(G) -- Class with an init that wrongly calls super() 90 | 91 | function H:_init() 92 | self:super() -- Notice: G has no _init 93 | end 94 | 95 | I = class(H) -- Inherits the init with a bad super 96 | J = class(I) -- Grandparent-inits the init with a bad super 97 | 98 | K = class(J) -- Has an init, which calls the init with a bad super 99 | 100 | function K:_init() 101 | self:super() 102 | end 103 | 104 | local function createG() 105 | return G() 106 | end 107 | 108 | local function createH() -- Wrapper function for pcall 109 | return H() 110 | end 111 | 112 | local function createJ() 113 | return J() 114 | end 115 | 116 | local function createK() 117 | return K() 118 | end 119 | 120 | assert(pcall(createG)) -- Should succeed 121 | assert(not pcall(createH)) -- These three should fail 122 | assert(not pcall(createJ)) 123 | assert(not pcall(createK)) 124 | 125 | --- class methods! 126 | assert(c:is_a(C)) 127 | assert(c:is_a(B)) 128 | assert(c:is_a(A)) 129 | assert(c:is_a() == C) 130 | assert(C:class_of(c)) 131 | assert(B:class_of(c)) 132 | assert(A:class_of(c)) 133 | 134 | --- metamethods! 135 | 136 | function C:__tostring () 137 | return ("%d:%d:%d"):format(self.a,self.b,self.c) 138 | end 139 | 140 | function C.__eq (c1,c2) 141 | return c1.a == c2.a and c1.b == c2.b and c1.c == c2.c 142 | end 143 | 144 | asserteq(C(),{a=1,b=2,c=3}) 145 | 146 | asserteq(tostring(C()),"1:2:3") 147 | 148 | asserteq(C()==C(),true) 149 | 150 | ----- properties ----- 151 | 152 | local MyProps = class(class.properties) 153 | local setted_a, got_b 154 | 155 | function MyProps:_init () 156 | self._a = 1 157 | self._b = 2 158 | end 159 | 160 | function MyProps:set_a (v) 161 | setted_a = true 162 | self._a = v 163 | end 164 | 165 | function MyProps:get_b () 166 | got_b = true 167 | return self._b 168 | end 169 | 170 | function MyProps:set (a,b) 171 | self._a = a 172 | self._b = b 173 | end 174 | 175 | local mp = MyProps() 176 | 177 | mp.a = 10 178 | 179 | asserteq(mp.a,10) 180 | asserteq(mp.b,2) 181 | asserteq(setted_a and got_b, true) 182 | 183 | class.MoreProps(MyProps) 184 | local setted_c 185 | 186 | function MoreProps:_init() 187 | self:super() 188 | self._c = 3 189 | end 190 | 191 | function MoreProps:set_c (c) 192 | setted_c = true 193 | self._c = c 194 | end 195 | 196 | mm = MoreProps() 197 | 198 | mm:set(10,20) 199 | mm.c = 30 200 | 201 | asserteq(setted_c, true) 202 | asserteq(T(mm.a, mm.b, mm.c),T(10,20,30)) 203 | 204 | 205 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /tests/test-class2.lua: -------------------------------------------------------------------------------- 1 | -- animal.lua 2 | require 'pl.app'.require_here 'lua' 3 | 4 | local test = require 'pl.test' 5 | local asserteq = test.asserteq 6 | 7 | local A = require 'animal' 8 | 9 | local fido, felix, leo 10 | fido = A.Dog('Fido') 11 | felix = A.Cat('Felix','Tabby') 12 | leo = A.Lion('Leo','African') 13 | 14 | asserteq(fido:speak(),'bark') 15 | asserteq(felix:speak(),'meow') 16 | asserteq(leo:speak(),'roar') 17 | 18 | asserteq(tostring(leo),'Leo: roar') 19 | 20 | test.assertraise(function() leo:circus_act() end, "no such method circus_act") 21 | 22 | asserteq(leo:is_a(A.Animal),true) 23 | asserteq(leo:is_a(A.Dog),false) 24 | asserteq(leo:is_a(A.Cat),true) 25 | 26 | asserteq(A.Dog:class_of(leo),false) 27 | asserteq(A.Cat:class_of(leo),true) 28 | asserteq(A.Lion:class_of(leo),true) 29 | -------------------------------------------------------------------------------- /tests/test-class3.lua: -------------------------------------------------------------------------------- 1 | -- another way to define classes. Works particularly well 2 | -- with Moonscript 3 | local class = require('pl.class') 4 | local A = class{ 5 | _init = function(self, name) 6 | self.name = name 7 | end, 8 | greet = function(self) 9 | return "hello " .. self.name 10 | end, 11 | __tostring = function(self) 12 | return self.name 13 | end 14 | } 15 | 16 | local B = class{ 17 | _base = A, 18 | 19 | greet = function(self) 20 | return "hola " .. self.name 21 | end 22 | } 23 | 24 | local a = A('john') 25 | assert(a:greet()=="hello john") 26 | assert(tostring(a) == "john") 27 | local b = B('juan') 28 | assert(b:greet()=="hola juan") 29 | assert(tostring(b)=="juan") 30 | -------------------------------------------------------------------------------- /tests/test-class4.lua: -------------------------------------------------------------------------------- 1 | local class = require 'pl.class' 2 | local A = class() 3 | function A:_init() 4 | self.init_chain = "A" 5 | end 6 | local B = class(A) 7 | local C = class(B) 8 | function C:_init() 9 | self:super() 10 | self.init_chain = self.init_chain.."C" 11 | end 12 | local D = class(C) 13 | local E = class(D) 14 | function E:_init() 15 | self:super() 16 | self.init_chain = self.init_chain.."E" 17 | end 18 | local F = class(E) 19 | local G = class(F) 20 | function G:_init() 21 | self:super() 22 | self.init_chain = self.init_chain.."G" 23 | end 24 | 25 | local i = G() 26 | assert(i.init_chain == "ACEG") 27 | -------------------------------------------------------------------------------- /tests/test-compat.lua: -------------------------------------------------------------------------------- 1 | local test = require 'pl.test' 2 | local asserteq = test.asserteq 3 | 4 | local compat = require "pl.compat" 5 | local coroutine = require "coroutine" 6 | 7 | local code_generator = coroutine.wrap(function() 8 | local result = {"ret", "urn \"Hello World!\""} 9 | for _,v in ipairs(result) do 10 | coroutine.yield(v) 11 | end 12 | coroutine.yield(nil) 13 | end) 14 | 15 | local f, err = compat.load(code_generator) 16 | asserteq(err, nil) 17 | asserteq(f(), "Hello World!") 18 | 19 | 20 | -- package.searchpath 21 | if compat.lua51 and not compat.jit then 22 | assert(package.searchpath("pl.compat", package.path):match("lua[/\\]pl[/\\]compat")) 23 | 24 | local path = "some/?/nice.path;another/?.path" 25 | local ok, err = package.searchpath("my.file.name", path, ".", "/") 26 | asserteq(err, "\tno file 'some/my/file/name/nice.path'\n\tno file 'another/my/file/name.path'") 27 | local ok, err = package.searchpath("my/file/name", path, "/", ".") 28 | asserteq(err, "\tno file 'some/my.file.name/nice.path'\n\tno file 'another/my.file.name.path'") 29 | end -------------------------------------------------------------------------------- /tests/test-comprehension.lua: -------------------------------------------------------------------------------- 1 | -- test-comprehension.lua 2 | -- test of comprehension.lua 3 | local utils = require 'pl.utils' 4 | local comp = require 'pl.comprehension' . new() 5 | local asserteq = require 'pl.test' . asserteq 6 | 7 | -- test of list building 8 | asserteq(comp 'x for x' {}, {}) 9 | asserteq(comp 'x for x' {2,3}, {2,3}) 10 | asserteq(comp 'x^2 for x' {2,3}, {2^2,3^2}) 11 | asserteq(comp 'x for x if x % 2 == 0' {4,5,6,7}, {4,6}) 12 | asserteq(comp '{x,y} for x for y if x>2 if y>4' ({2,3},{4,5}), {{3,5}}) 13 | 14 | -- test of table building 15 | local t = comp 'table(x,x+1 for x)' {3,4} 16 | assert(t[3] == 3+1 and t[4] == 4+1) 17 | local t = comp 'table(x,x+y for x for y)' ({3,4}, {2}) 18 | assert(t[3] == 3+2 and t[4] == 4+2) 19 | local t = comp 'table(v,k for k,v in pairs(_1))' {[3]=5, [5]=7} 20 | assert(t[5] == 3 and t[7] == 5) 21 | 22 | -- test of sum 23 | assert(comp 'sum(x for x)' {} == 0) 24 | assert(comp 'sum(x for x)' {2,3} == 2+3) 25 | assert(comp 'sum(x^2 for x)' {2,3} == 2^2+3^2) 26 | assert(comp 'sum(x*y for x for y)' ({2,3}, {4,5}) == 2*4+2*5+3*4+3*5) 27 | assert(comp 'sum(x^2 for x if x % 2 == 0)' {4,5,6,7} == 4^2+6^2) 28 | assert(comp 'sum(x*y for x for y if x>2 if y>4)' ({2,3}, {4,5}) == 3*5) 29 | 30 | -- test of min/max 31 | assert(comp 'min(x for x)' {3,5,2,4} == 2) 32 | assert(comp 'max(x for x)' {3,5,2,4} == 5) 33 | 34 | -- test of placeholder parameters -- 35 | assert(comp 'sum(x^_1 + _3 for x if x >= _4)' (2, nil, 3, 4, {3,4,5}) 36 | == 4^2+3 + 5^2+3) 37 | 38 | -- test of for = 39 | assert(comp 'sum(x^2 for x=2,3)' () == 2^2+3^2) 40 | assert(comp 'sum(x^2 for x=2,6,1+1)' () == 2^2+4^2+6^2) 41 | assert(comp 'sum(x*y*z for x=1,2 for y=3,3 for z)' {5,6} == 42 | 1*3*5 + 2*3*5 + 1*3*6 + 2*3*6) 43 | assert(comp 'sum(x*y*z for z for x=1,2 for y=3,3)' {5,6} == 44 | 1*3*5 + 2*3*5 + 1*3*6 + 2*3*6) 45 | 46 | -- test of for in 47 | assert(comp 'sum(i*v for i,v in ipairs(_1))' {2,3} == 1*2+2*3) 48 | assert(comp 'sum(i*v for i,v in _1,_2,_3)' (ipairs{2,3}) == 1*2+2*3) 49 | 50 | -- test of difficult syntax 51 | asserteq(comp '" x for x " for x' {2}, {' x for x '}) 52 | asserteq(comp 'x --[=[for x\n\n]=] for x' {2}, {2}) 53 | asserteq(comp '(function() for i = 1,1 do return x*2 end end)() for x' 54 | {2}, {4}) 55 | assert(comp 'sum(("_5" and x)^_1 --[[_6]] for x)' (2, {4,5}) == 4^2 + 5^2) 56 | 57 | -- error checking 58 | assert(({pcall(function() comp 'x for __result' end)})[2] 59 | :find'not contain __ prefix') 60 | 61 | -- environment. 62 | -- Note: generated functions are set to the environment of the 'new' call. 63 | asserteq(5,(function() 64 | local env = {d = 5} 65 | local comp = comp.new(env) 66 | return comp 'sum(d for x)' {1} 67 | end)()); 68 | print 'DONE' 69 | -------------------------------------------------------------------------------- /tests/test-data2.lua: -------------------------------------------------------------------------------- 1 | local utils = require 'pl.utils' 2 | local stringio = require 'pl.stringio' 3 | local data = require 'pl.data' 4 | local test = require 'pl.test' 5 | 6 | utils.on_error 'quit' 7 | 8 | stuff = [[ 9 | Department Name,Employee ID,Project,Hours Booked 10 | sales, 1231,overhead,4 11 | sales,1255,overhead,3 12 | engineering,1501,development,5 13 | engineering,1501,maintenance,3 14 | engineering,1433,maintenance,10 15 | ]] 16 | 17 | t = data.read(stringio.open(stuff)) 18 | 19 | q = t:select 'Employee_ID,Hours_Booked where Department_Name == "engineering"' 20 | 21 | test.asserteq2(1501,5,q()) 22 | test.asserteq2(1501,3,q()) 23 | test.asserteq2(1433,10,q()) 24 | -------------------------------------------------------------------------------- /tests/test-date.lua: -------------------------------------------------------------------------------- 1 | local test = require 'pl.test' 2 | local asserteq, assertmatch = test.asserteq, test.assertmatch 3 | local dump = require 'pl.pretty'.dump 4 | local T = require 'pl.test'.tuple 5 | 6 | local Date = require 'pl.Date' 7 | 8 | iso = Date.Format 'yyyy-mm-dd' -- ISO date 9 | d = iso:parse '2010-04-10' 10 | asserteq(T(d:day(),d:month(),d:year()),T(10,4,2010)) 11 | amer = Date.Format 'mm/dd/yyyy' -- American style 12 | s = amer:tostring(d) 13 | dc = amer:parse(s) 14 | asserteq(d,dc) 15 | 16 | d = Date() -- today 17 | d:add { day = 1 } -- tomorrow 18 | assert(d > Date()) 19 | 20 | --------- Time intervals ----- 21 | -- new explicit Date.Interval class; also returned by Date:diff 22 | d1 = Date.Interval(1202) 23 | d2 = Date.Interval(1500) 24 | asserteq(tostring(d2:diff(d1)),"4 min 58 sec ") 25 | 26 | -------- testing 'flexible' date parsing --------- 27 | 28 | 29 | local df = Date.Format() 30 | 31 | function parse_date (s) 32 | return df:parse(s) 33 | end 34 | 35 | -- ISO 8601 36 | -- specified as UTC plus/minus offset 37 | 38 | function parse_utc (s) 39 | local d = parse_date(s) 40 | return d:toUTC() 41 | end 42 | 43 | asserteq(parse_utc '2010-05-10 12:35:23Z', Date(2010,05,10,12,35,23)) 44 | asserteq(parse_utc '2008-10-03T14:30+02', Date(2008,10,03,12,30)) 45 | asserteq(parse_utc '2008-10-03T14:00-02:00',Date(2008,10,03,16,0)) 46 | 47 | ---- can't do anything before 1970, which is somewhat unfortunate.... 48 | --parse_date '20/03/59' 49 | 50 | asserteq(parse_date '15:30', Date {hour=15,min=30}) 51 | asserteq(parse_date '8.05pm', Date {hour=20,min=5}) 52 | asserteq(parse_date '28/10/02', Date {year=2002,month=10,day=28}) 53 | asserteq(parse_date ' 5 Feb 2012 ', Date {year=2012,month=2,day=5}) 54 | asserteq(parse_date '20 Jul ', Date {month=7,day=20}) 55 | asserteq(parse_date '05/04/02 15:30:43', Date{year=2002,month=4,day=5,hour=15,min=30,sec=43}) 56 | asserteq(parse_date 'march', Date {month=3}) 57 | asserteq(parse_date '2010-05-23T0130', Date{year=2010,month=5,day=23,hour=1,min=30}) 58 | asserteq(parse_date '2008-10-03T14:30:45', Date{year=2008,month=10,day=3,hour=14,min=30,sec=45}) 59 | 60 | -- allow for a comma after the month... 61 | asserteq(parse_date '18 July, 2013 12:00:00', Date{year=2013,month=07,day=18,hour=12,min=0,sec=0}) 62 | 63 | -- This ISO format must result in a UTC date 64 | local d = parse_date '2016-05-01T14:30:00Z' 65 | asserteq(d:year(),2016) 66 | asserteq(d:month(),5) 67 | asserteq(d:day(),1) 68 | asserteq(d:hour(),14) 69 | asserteq(d:min(),30) 70 | asserteq(d:sec(),0) 71 | 72 | function err (status,e) 73 | return e 74 | end 75 | 76 | assertmatch(err(parse_date('2005-10-40 01:30')),'40 is not between 1 and 31') 77 | assertmatch(err(parse_date('14.20pm')),'14 is not between 0 and 12') 78 | 79 | local d = parse_date '2007-08-10' 80 | -- '+' works like add, but can also work with intervals 81 | local nxt = d + {month=1} 82 | -- '-' is an alias for diff method 83 | asserteq(tostring(nxt - d), '1 month ') 84 | 85 | --- Can explicitly get UTC date; these of course refer to same time 86 | local now,utc = Date(), Date 'utc' 87 | asserteq(tostring(now - utc),'zero') 88 | -------------------------------------------------------------------------------- /tests/test-func.lua: -------------------------------------------------------------------------------- 1 | local utils = require 'pl.utils' 2 | local List = require 'pl.List' 3 | local tablex = require 'pl.tablex' 4 | asserteq = require('pl.test').asserteq 5 | utils.import('pl.func') 6 | 7 | -- _DEBUG = true 8 | 9 | function pprint (t) 10 | print(pretty.write(t)) 11 | end 12 | 13 | function test (e) 14 | local v = {} 15 | print('test',collect_values(e,v)) 16 | if #v > 0 then pprint(v) end 17 | local rep = repr(e) 18 | print(rep) 19 | end 20 | 21 | function teste (e,rs,ve) 22 | local v = {} 23 | collect_values(e,v) 24 | if #v > 0 then asserteq(v,ve,nil,1) end 25 | local rep = repr(e) 26 | asserteq(rep,rs, nil, 1) 27 | end 28 | 29 | teste(_1+_2('hello'),'_1 + _2(_C1)',{"hello"}) 30 | teste(_1:method(),'_1[_C1](_1)',{"method"}) 31 | teste(Not(_1),'not _1') 32 | 33 | asserteq(instantiate(_1+_2)(10,20),30) 34 | asserteq(instantiate(_1+20)(10),30) 35 | asserteq(instantiate(Or(Not(_1),_2))(true,true),true) 36 | 37 | teste(_1() + _2() + _3(),'_1() + _2() + _3()',30) 38 | asserteq(I(_1+_2)(10,20),30) 39 | 40 | teste(_1() - -_2() % _3(), '_1() - - _2() % _3()') 41 | teste((_1() - -_2()) % _3(), '(_1() - - _2()) % _3()') 42 | 43 | teste(_1() - _2() + _3(), '_1() - _2() + _3()') 44 | teste(_1() - (_2() + _3()), '_1() - (_2() + _3())') 45 | teste((_1() - _2()) + _3(), '_1() - _2() + _3()') 46 | 47 | teste(_1() .. _2() .. _3(), '_1() .. _2() .. _3()') 48 | teste(_1() .. (_2() .. _3()), '_1() .. _2() .. _3()') 49 | teste((_1() .. _2()) .. _3(), '(_1() .. _2()) .. _3()') 50 | 51 | teste(_1() ^ _2() ^ _3(), '_1() ^ _2() ^ _3()') 52 | teste(_1() ^ (_2() ^ _3()), '_1() ^ _2() ^ _3()') 53 | teste((_1() ^ _2()) ^ _3(), '(_1() ^ _2()) ^ _3()') 54 | 55 | teste(-_1() * _2(), '- _1() * _2()') 56 | teste(-(_1() * _2()), '- (_1() * _2())') 57 | teste((-_1()) * _2(), '- _1() * _2()') 58 | teste(-_1() ^ _2(), '- _1() ^ _2()') 59 | teste(-(_1() ^ _2()), '- _1() ^ _2()') 60 | teste((-_1()) ^ _2(), '(- _1()) ^ _2()') 61 | 62 | asserteq(instantiate(_1+_2)(10,20),30) 63 | 64 | ls = List {1,2,3,4} 65 | res = ls:map(10*_1 - 1) 66 | asserteq(res,List {9,19,29,39}) 67 | 68 | -- note that relational operators can't be overloaded for _different_ types 69 | ls = List {10,20,30,40} 70 | asserteq(ls:filter(Gt(_1,20)),List {30,40}) 71 | 72 | 73 | local map,map2 = tablex.map,tablex.map2 74 | 75 | --~ test(Len(_1)) 76 | 77 | -- methods can be applied to all items in a table with map 78 | asserteq (map(_1:sub(1,2),{'one','four'}),{'on','fo'}) 79 | 80 | --~ -- or you can do this using List:map 81 | asserteq( List({'one','four'}):map(_1:sub(1,2)), List{'on','fo'}) 82 | 83 | --~ -- note that Len can't be represented generally by #, since this can only be overridden by userdata 84 | asserteq( map(Len(_1),{'one','four'}), {3,4} ) 85 | 86 | --~ -- simularly, 'and' and 'or' are not really operators in Lua, so we need a function notation for them 87 | asserteq (map2(Or(_1,_2),{false,'b'},{'.lua',false}),{'.lua','b'}) 88 | 89 | --~ -- binary operators: + - * / % ^ .. 90 | asserteq (map2(_1.._2,{'a','b'},{'.lua','.c'}),{'a.lua','b.c'}) 91 | 92 | t1 = {alice=23,fred=34} 93 | t2 = {bob=25,fred=34} 94 | 95 | intersection = bind(tablex.merge,_1,_2,false) 96 | 97 | asserteq(intersection(t1,t2),{fred=34}) 98 | 99 | union = bind(tablex.merge,_1,_2,true) 100 | 101 | asserteq(union(t1,t2),{bob=25,fred=34,alice=23}) 102 | 103 | asserteq(repr(_1+_2),"_1 + _2") 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /tests/test-import_into.lua: -------------------------------------------------------------------------------- 1 | local test = require 'pl.test' 2 | local utils = require 'pl.utils' 3 | 4 | require 'pl.app'.require_here 'lua' 5 | 6 | if not utils.lua51 then 7 | --- look at lua/mod52.lua 8 | local m = require 'mod52' 9 | test.asserteq(m.answer(),'{"10","20","30"}') 10 | assert(m.utils) -- !! implementation is leaky! 11 | 12 | -- that's a bugger. However, if 'pl.import_into' is passed true, 13 | -- then the returned module will _only_ contain the newly defined functions 14 | -- So reload after setting the global STRICT 15 | package.loaded.mod52 = nil 16 | STRICT = true 17 | m = require 'mod52' 18 | assert (m.answer) -- as before 19 | assert (not m.utils) -- cool! No underwear showing 20 | end 21 | 22 | local pl = require 'pl.import_into' () 23 | 24 | assert(pl.utils) 25 | assert(pl.tablex) 26 | assert(pl.data) 27 | assert(not _G.utils) 28 | assert(not _G.tablex) 29 | assert(not _G.data) 30 | 31 | require 'pl.import_into'(_G) 32 | assert(_G.utils) 33 | assert(_G.tablex) 34 | assert(_G.data) 35 | 36 | require 'pl.import_into'(_G) 37 | assert(_G.utils) 38 | assert(_G.tablex) 39 | assert(_G.data) 40 | -------------------------------------------------------------------------------- /tests/test-lexer.lua: -------------------------------------------------------------------------------- 1 | local asserteq = require('pl.test').asserteq 2 | local lexer = require 'pl.lexer' 3 | local seq = require 'pl.seq' 4 | local List = require('pl.List') 5 | local open = require('pl.stringio').open 6 | local copy2 = seq.copy2 7 | 8 | local function test_scan(str, filter, options, expected_tokens, lang) 9 | local matches 10 | if lang then 11 | matches, filter = filter, options 12 | else 13 | lang = 'scan' 14 | end 15 | 16 | asserteq(copy2(lexer[lang](str, matches, filter, options)), expected_tokens) 17 | if lang == 'scan' then 18 | asserteq(copy2(lexer[lang](open(str), matches, filter, options)), expected_tokens) 19 | end 20 | end 21 | 22 | local s = '20 = hello' 23 | test_scan(s, {space=false}, {number=false}, { 24 | {'number', '20'}, {'space', ' '}, {'=', '='}, {'space', ' '}, {'iden', 'hello'} 25 | }) 26 | test_scan(s, {space=true}, {number=true}, { 27 | {'number', 20}, {'=', '='}, {'iden', 'hello'} 28 | }) 29 | s = [[ 'help' "help" "dolly you're fine" "a \"quote\" here"]] 30 | test_scan(s, nil, nil, { 31 | {'string', 'help'}, {'string', 'help'}, 32 | {'string', "dolly you're fine"}, {'string', 'a \\\"quote\\\" here'} -- Escapes are preserved literally. 33 | }) 34 | test_scan([[\abc\]], nil, nil, { 35 | {'\\', '\\'}, {'iden', 'abc'}, {'\\', '\\'} 36 | }) 37 | test_scan([["" ""]], nil, nil, { 38 | {'string', ''}, {'string', ''} 39 | }) 40 | test_scan([["abc" "def\\"]], nil, nil, { 41 | {'string', 'abc'}, {'string', 'def\\\\'} 42 | }) 43 | test_scan([["abc\\" "def"]], nil, nil, { 44 | {'string', 'abc\\\\'}, {'string', 'def'} 45 | }) 46 | test_scan([["abc\\\" "]], nil, nil, { 47 | {'string', 'abc\\\\\\" '} 48 | }) 49 | 50 | local function test_roundtrip(str) 51 | test_scan(str, {}, {string=false}, {{'string', str}}) 52 | end 53 | 54 | test_roundtrip [["hello\\"]] 55 | test_roundtrip [["hello\"dolly"]] 56 | test_roundtrip [['hello\'dolly']] 57 | test_roundtrip [['']] 58 | test_roundtrip [[""]] 59 | 60 | test_scan('test(20 and a > b)', nil, nil, { 61 | {'iden', 'test'}, {'(', '('}, {'number', 20}, {'keyword', 'and'}, 62 | {'iden', 'a'}, {'>', '>'}, {'iden', 'b'}, {')', ')'} 63 | }, 'lua') 64 | test_scan('10+2.3', nil, nil, { 65 | {'number', 10}, {'+', '+'}, {'number', 2.3} 66 | }, 'lua') 67 | 68 | local txt = [==[ 69 | -- comment 70 | --[[ 71 | block 72 | comment 73 | ]][[ 74 | hello dammit 75 | ]][[hello]] 76 | ]==] 77 | 78 | test_scan(txt, {}, nil, { 79 | {'comment', '-- comment\n'}, 80 | {'comment', '--[[\nblock\ncomment\n]]'}, 81 | {'string', 'hello dammit\n'}, 82 | {'string', 'hello'}, 83 | {'space', '\n'} 84 | }, 'lua') 85 | 86 | local lines = [[ 87 | for k,v in pairs(t) do 88 | if type(k) == 'number' then 89 | print(v) -- array-like case 90 | else 91 | print(k,v) 92 | end -- if 93 | end 94 | ]] 95 | 96 | local ls = List() 97 | for tp,val in lexer.lua(lines,{space=true,comments=true}) do 98 | assert(tp ~= 'space' and tp ~= 'comment') 99 | if tp == 'keyword' then ls:append(val) end 100 | end 101 | asserteq(ls,List{'for','in','do','if','then','else','end','end'}) 102 | 103 | txt = [[ 104 | // comment 105 | /* a long 106 | set of words */ // more 107 | ]] 108 | 109 | test_scan(txt, {}, nil, { 110 | {'comment', '// comment\n'}, 111 | {'comment', '/* a long\nset of words */'}, 112 | {'space', ' '}, 113 | {'comment', '// more\n'} 114 | }, 'cpp') 115 | 116 | test_scan([['' "" " \\" '\'' "'"]], nil, nil, { 117 | {'char', ''}, -- Char literals with no or more than one characters are not a lexing error. 118 | {'string', ''}, 119 | {'string', ' \\\\'}, 120 | {'char', "\\'"}, 121 | {'string', "'"} 122 | }, 'cpp') 123 | 124 | local iter = lexer.lua([[ 125 | foo 126 | bar 127 | ]]) 128 | 129 | asserteq(lexer.lineno(iter), 0) 130 | iter() 131 | asserteq(lexer.lineno(iter), 1) 132 | asserteq(lexer.lineno(iter), 1) 133 | iter() 134 | asserteq(lexer.lineno(iter), 2) 135 | iter() 136 | asserteq(lexer.lineno(iter), 3) 137 | iter() 138 | iter() 139 | asserteq(lexer.lineno(iter), 3) 140 | 141 | do -- numbers without leading zero; ".123" 142 | local s = 'hello = +.234' 143 | test_scan(s, {space=true}, {number=true}, { 144 | {'iden', 'hello'}, {'=', '='}, {'number', .234} 145 | }) 146 | end 147 | -------------------------------------------------------------------------------- /tests/test-list.lua: -------------------------------------------------------------------------------- 1 | local List = require 'pl.List' 2 | local class = require 'pl.class' 3 | local test = require 'pl.test' 4 | local asserteq, T = test.asserteq, test.tuple 5 | 6 | -- note that a _plain table_ is made directly into a list 7 | local t = {10,20,30} 8 | local ls = List(t) 9 | asserteq(t,ls) 10 | 11 | asserteq(List({}):reverse(), {}) 12 | asserteq(List({1}):reverse(), {1}) 13 | asserteq(List({1,2}):reverse(), {2,1}) 14 | asserteq(List({1,2,3}):reverse(), {3,2,1}) 15 | asserteq(List({1,2,3,4}):reverse(), {4,3,2,1}) 16 | 17 | -- you may derive classes from pl.List, and the result is covariant. 18 | -- That is, slice() etc will return a list of the derived type, not List. 19 | 20 | local NA = class(List) 21 | 22 | local function mapm(a1,op,a2) 23 | local M = type(a2)=='table' and List.map2 or List.map 24 | return M(a1,op,a2) 25 | end 26 | 27 | --- elementwise arithmetric operations 28 | function NA.__unm(a) return a:map '|X|-X' end 29 | function NA.__pow(a,s) return a:map '|X,Y|X^Y' end 30 | function NA.__add(a1,a2) return mapm(a1,'|X,Y|X+Y',a2) end 31 | function NA.__sub(a1,a2) return mapm(a1,'|X,Y|X-Y',a2) end 32 | function NA.__div(a1,a2) return mapm(a1,'|X,Y|X/Y',a2) end 33 | function NA.__mul(a1,a2) return mapm(a2,'|X,Y|X*Y',a1) end 34 | 35 | function NA:minmax () 36 | local min,max = math.huge,-math.huge 37 | for i = 1,#self do 38 | local val = self[i] 39 | if val > max then max = val end 40 | if val < min then min = val end 41 | end 42 | return min,max 43 | end 44 | 45 | function NA:sum () 46 | local res = 0 47 | for i = 1,#self do 48 | res = res + self[i] 49 | end 50 | return res 51 | end 52 | 53 | function NA:normalize () 54 | return self:transform('|X,Y|X/Y',self:sum()) 55 | end 56 | 57 | n1 = NA{10,20,30} 58 | n2 = NA{1,2,3} 59 | ns = n1 + 2*n2 60 | 61 | asserteq(List:class_of(ns),true) 62 | asserteq(NA:class_of(ns),true) 63 | asserteq(ns:is_a(NA),true) 64 | asserteq(ns,{12,24,36}) 65 | min,max = ns:slice(1,2):minmax() 66 | asserteq(T(min,max),T(12,24)) 67 | 68 | asserteq(n1:normalize():sum(),1,1e-8) 69 | -------------------------------------------------------------------------------- /tests/test-list2.lua: -------------------------------------------------------------------------------- 1 | local List = require 'pl.List' 2 | local asserteq = require 'pl.test' . asserteq 3 | 4 | local s = List{1,2,3,4,5} 5 | 6 | -- test using: lua pylist.lua 7 | local lst = List() 8 | lst:append(20) 9 | lst:extend{30,40,50} 10 | lst:put(10) 11 | asserteq (lst,List{10,20,30,40,50}) 12 | asserteq (lst:len(),5) 13 | lst:insert(3,11) 14 | lst:remove_value(40) 15 | asserteq (lst,List{10,20,11,30,50}) 16 | asserteq (lst:contains(11),true) 17 | asserteq (lst:contains(40),false) 18 | local _ = lst:pop() 19 | asserteq( lst:index(30),4 ) 20 | asserteq( lst:count(10),1 ) 21 | lst:sort() 22 | lst:reverse() 23 | asserteq (lst , List{30,20,11,10}) 24 | asserteq (lst[#lst] , 10) 25 | asserteq (lst[#lst-2] , 20) 26 | asserteq (tostring(lst) , '{30,20,11,10}') 27 | 28 | lst = List {10,20,30,40,50} 29 | asserteq (lst:slice(2),{20,30,40,50}) 30 | asserteq (lst:slice(-2),{40,50}) 31 | asserteq (lst:slice(nil,3),{10,20,30}) 32 | asserteq (lst:slice(2,4),{20,30,40}) 33 | asserteq (lst:slice(-4,-2),{20,30,40}) 34 | 35 | lst = List.range(0,9) 36 | local seq = List{0,1,2,3,4,5,6,7,8,9} 37 | asserteq(List.range(4),{1,2,3,4}) 38 | asserteq(List.range(0,8,2),{0,2,4,6,8}) 39 | asserteq(List.range(0,1,0.2),{0,0.2,0.4,0.6,0.8,1},1e-9) 40 | asserteq(lst, seq) 41 | asserteq(lst:reduce '+', 45) 42 | 43 | local part = seq:partition(function(v) return v % 2 end) 44 | asserteq (part[0], List{0,2,4,6,8}) 45 | asserteq (part[1], List{1,3,5,7,9}) 46 | 47 | asserteq (List('abcd'),List{'a','b','c','d'}) 48 | local caps = List() 49 | List('abcd'):foreach(function(v) caps:append(v:upper()) end) 50 | asserteq (caps,List{'A','B','C','D'}) 51 | local ls = List{10,20,30,40} 52 | ls:slice_assign(2,3,{21,31}) 53 | asserteq (ls , List{10,21,31,40}) 54 | asserteq (ls:remove(2), List{10,31,40}) 55 | asserteq (ls:clear(), List{}) 56 | asserteq (ls:len(), 0) 57 | 58 | s = 'here the dog is just a dog' 59 | assert (List.split(s) == List{'here', 'the', 'dog', 'is', 'just', 'a', 'dog'}) 60 | assert (List.split('foo;bar;baz', ';') == List{'foo', 'bar', 'baz'}) 61 | -------------------------------------------------------------------------------- /tests/test-map.lua: -------------------------------------------------------------------------------- 1 | -- testing Map functionality 2 | 3 | local test = require 'pl.test' 4 | local Map = require 'pl.Map' 5 | local tablex = require 'pl.tablex' 6 | local Set = require 'pl.Set' 7 | local utils = require 'pl.utils' 8 | 9 | local asserteq = test.asserteq 10 | local cmp = tablex.compare_no_order 11 | 12 | 13 | 14 | -- construction, plain 15 | local m = Map{alpha=1,beta=2,gamma=3} 16 | 17 | assert(cmp( 18 | m:values(), 19 | {1, 2, 3} 20 | )) 21 | 22 | assert(cmp( 23 | m:keys(), 24 | {'alpha', 'beta', 'gamma'} 25 | )) 26 | 27 | asserteq( 28 | m:items(), 29 | { 30 | {'alpha', 1}, 31 | {'beta', 2}, 32 | {'gamma', 3}, 33 | } 34 | ) 35 | 36 | asserteq (m:getvalues {'alpha','gamma'}, {1,3}) 37 | 38 | 39 | 40 | -- construction, from a set 41 | local s = Set{'red','orange','green','blue'} 42 | m = Map(s) 43 | 44 | asserteq( 45 | m:items(), 46 | { 47 | {'blue', true}, 48 | {'green', true}, 49 | {'orange', true}, 50 | {'red', true}, 51 | } 52 | ) 53 | 54 | 55 | -- iter() 56 | m = Map{alpha=1,beta=2,gamma=3} 57 | local t = {alpha=1,beta=2,gamma=3} 58 | for k,v in m:iter() do 59 | asserteq(v, t[k]) 60 | t[k] = nil 61 | end 62 | assert(next(t) == nil, "expected the table to be empty by now") 63 | 64 | 65 | 66 | -- setdefault() 67 | m = Map{alpha=1,beta=2,gamma=3} 68 | local v = m:setdefault("charlie", 4) 69 | asserteq(v, 4) 70 | v = m:setdefault("alpha", 10) 71 | asserteq(v, 1) 72 | asserteq( 73 | m:items(), 74 | { 75 | {'alpha', 1}, 76 | {'beta', 2}, 77 | {'charlie', 4}, 78 | {'gamma', 3}, 79 | } 80 | ) 81 | v = m:set("alpha", false) 82 | v = m:setdefault("alpha", true) -- falsy value should not be altered 83 | asserteq(false, m:get("alpha")) 84 | 85 | 86 | 87 | -- len() 88 | m = Map{alpha=1,beta=2,gamma=3} 89 | asserteq(3, m:len()) 90 | m = Map{} 91 | asserteq(0, m:len()) 92 | m:set("charlie", 4) 93 | asserteq(1, m:len()) 94 | 95 | 96 | 97 | -- set() & get() 98 | m = Map{} 99 | m:set("charlie", 4) 100 | asserteq(4, m:get("charlie")) 101 | m:set("charlie", 5) 102 | asserteq(5, m:get("charlie")) 103 | m:set("charlie", nil) 104 | asserteq(nil, m:get("charlie")) 105 | 106 | 107 | 108 | -- getvalues() 109 | m = Map{alpha=1,beta=2,gamma=3} 110 | local x = m:getvalues{"gamma", "beta"} 111 | asserteq({3, 2}, x) 112 | 113 | 114 | 115 | -- __eq() -- equality 116 | local m1 = Map{alpha=1,beta=2,gamma=3} 117 | local m2 = Map{alpha=1,beta=2,gamma=3} 118 | assert(m1 == m2) 119 | m1 = Map() 120 | m2 = Map() 121 | assert(m1 == m2) 122 | 123 | 124 | 125 | -- __tostring() 126 | m = Map() 127 | asserteq("{}", tostring(m)) 128 | m = Map{alpha=1} 129 | asserteq("{alpha=1}", tostring(m)) 130 | m = Map{alpha=1,beta=2} 131 | assert(({ -- test 2 versions, since we cannot rely on order 132 | ["{alpha=1,beta=2}"] = true, 133 | ["{beta=2,alpha=1}"] = true, 134 | })[tostring(m)]) 135 | -------------------------------------------------------------------------------- /tests/test-orderedmap.lua: -------------------------------------------------------------------------------- 1 | local List = require 'pl.List' 2 | 3 | local asserteq = require 'pl.test' . asserteq 4 | local asserteq2 = require 'pl.test' . asserteq2 5 | local OrderedMap = require 'pl.OrderedMap' 6 | 7 | 8 | m = OrderedMap() 9 | m:set('one',1) 10 | m:set('two',2) 11 | m:set('three',3) 12 | 13 | asserteq(m:values(),List{1,2,3}) 14 | 15 | -- usually exercized like this: 16 | --for k,v in m:iter() do print(k,v) end 17 | 18 | local fn = m:iter() 19 | asserteq2 ('one',1,fn()) 20 | asserteq2 ('two',2,fn()) 21 | asserteq2 ('three',3,fn()) 22 | 23 | -- Keys overriding methods can be used. 24 | m:set('set', 4) 25 | asserteq(m:values(),List{1,2,3,4}) 26 | 27 | local o1 = OrderedMap {{z=2},{beta=1},{name='fred'}} 28 | asserteq(tostring(o1),'{z=2,beta=1,name="fred"}') 29 | 30 | -- order of keys is not preserved here! 31 | local o2 = OrderedMap {z=4,beta=1.1,name='alice',extra='dolly'} 32 | 33 | o1:update(o2) 34 | asserteq(tostring(o1),'{z=4,beta=1.1,name="alice",extra="dolly"}') 35 | 36 | o1:set('beta',nil) 37 | asserteq(o1,OrderedMap{{z=4},{name='alice'},{extra='dolly'}}) 38 | 39 | local o3 = OrderedMap() 40 | o3:set('dog',10) 41 | o3:set('cat',20) 42 | o3:set('mouse',30) 43 | 44 | asserteq(o3:keys(),{'dog','cat','mouse'}) 45 | 46 | o3:set('dog',nil) 47 | 48 | asserteq(o3:keys(),{'cat','mouse'}) 49 | 50 | -- Vadim found a problem when clearing a key which did not exist already. 51 | -- The keys list would then contain the key, although the map would not 52 | o3:set('lizard',nil) 53 | 54 | asserteq(o3:keys(),{'cat','mouse'}) 55 | asserteq(o3:values(), {20,30}) 56 | asserteq(tostring(o3),'{cat=20,mouse=30}') 57 | 58 | -- copy constructor 59 | local o4 = OrderedMap(o3) 60 | 61 | asserteq(o4,o3) 62 | 63 | -- constructor throws an error if the argument is bad 64 | -- (errors same as OrderedMap:update) 65 | asserteq(false,pcall(function() 66 | m = OrderedMap('string') 67 | end)) 68 | 69 | ---- changing order of key/value pairs ---- 70 | 71 | o3 = OrderedMap{{cat=20},{mouse=30}} 72 | 73 | o3:insert(1,'bird',5) -- adds key/value before specified position 74 | o3:insert(1,'mouse') -- moves key keeping old value 75 | asserteq(o3:keys(),{'mouse','bird','cat'}) 76 | asserteq(tostring(o3),'{mouse=30,bird=5,cat=20}') 77 | o3:insert(2,'cat',21) -- moves key and sets new value 78 | asserteq(tostring(o3),'{mouse=30,cat=21,bird=5}') 79 | -- if you don't specify a value for an unknown key, nothing happens to the map 80 | o3:insert(3,'alligator') 81 | asserteq(tostring(o3),'{mouse=30,cat=21,bird=5}') 82 | 83 | ---- short-cut notation 84 | 85 | local o5 = OrderedMap() 86 | o5.alpha = 1 87 | o5.beta = 2 88 | o5.gamma = 3 89 | 90 | asserteq(o5,OrderedMap{{alpha=1},{beta=2},{gamma=3}}) 91 | 92 | o5.alpha = 10 93 | o5.beta = 20 94 | o5.gamma = 30 95 | o5.delta = 40 96 | o5.checked = false 97 | 98 | asserteq(o5,OrderedMap{{alpha=10},{beta=20},{gamma=30},{delta=40},{checked=false}}) 99 | -------------------------------------------------------------------------------- /tests/test-pretty.lua: -------------------------------------------------------------------------------- 1 | local pretty = require 'pl.pretty' 2 | local utils = require 'pl.utils' 3 | local test = require 'pl.test' 4 | local asserteq, assertmatch = test.asserteq, test.assertmatch 5 | 6 | t1 = { 7 | 'one','two','three',{1,2,3}, 8 | alpha=1,beta=2,gamma=3,['&']=true,[0]=false, 9 | _fred = {true,true}, 10 | s = [[ 11 | hello dolly 12 | you're so fine 13 | ]] 14 | } 15 | 16 | s = pretty.write(t1) --,' ',true) 17 | t2,err = pretty.read(s) 18 | if err then return print(err) end 19 | asserteq(t1,t2) 20 | 21 | res,err = pretty.read [[ 22 | { 23 | ['function'] = true, 24 | ['do'] = true, 25 | } 26 | ]] 27 | assert(res) 28 | 29 | res,err = pretty.read [[ 30 | { 31 | ['function'] = true, 32 | ['do'] = "no function here...", 33 | } 34 | ]] 35 | assert(res) 36 | 37 | res,err = pretty.read [[ 38 | { 39 | ['function'] = true, 40 | ['do'] = function() return end 41 | } 42 | ]] 43 | assertmatch(err,'cannot have functions in table definition') 44 | 45 | res,err = pretty.load([[ 46 | -- comments are ok 47 | a = 2 48 | bonzo = 'dog' 49 | t = {1,2,3} 50 | ]]) 51 | 52 | asserteq(res,{a=2,bonzo='dog',t={1,2,3}}) 53 | 54 | --- another potential problem is string functions called implicitly as methods-- 55 | res,err = pretty.read [[ 56 | {s = ('woo'):gsub('w','wwwwww'):gsub('w','wwwwww')} 57 | ]] 58 | 59 | assertmatch(err,(_VERSION ~= "Lua 5.2") and 'attempt to index a string value' or "attempt to index constant 'woo'") 60 | 61 | ---- pretty.load has a _paranoid_ option 62 | res,err = pretty.load([[ 63 | k = 0 64 | for i = 1,1e12 do k = k + 1 end 65 | ]],{},true) 66 | 67 | assertmatch(err,'looping not allowed') 68 | 69 | -- Check to make sure that no spaces exist when write is told not to 70 | local tbl = { "a", 2, "c", false, 23, 453, "poot", 34 } 71 | asserteq( pretty.write( tbl, "" ), [[{"a",2,"c",false,23,453,"poot",34}]] ) 72 | 73 | -- Check that write correctly prevents cycles 74 | 75 | local t1,t2 = {},{} 76 | t1[1] = t1 77 | asserteq( pretty.write(t1,""), [[{}]] ) 78 | t1[1],t1[2],t2[1] = 42,t2,t1 79 | asserteq( pretty.write(t1,""), [[{42,{}}]] ) 80 | 81 | -- Check false positives in write's cycles prevention 82 | 83 | t2 = {} 84 | t1[1],t1[2] = t2,t2 85 | asserteq( pretty.write(t1,""), [[{{},{}}]] ) 86 | 87 | -- Check that write correctly print table with non number or string as keys 88 | 89 | t1 = { [true] = "boolean", [false] = "untrue", a = "a", b = "b", [1] = 1, [0] = 0 } 90 | asserteq( pretty.write(t1,""), [[{1,["false"]="untrue",["true"]="boolean",a="a",b="b",[0]=0}]] ) 91 | 92 | 93 | -- Check number formatting 94 | asserteq(pretty.write({1/0, -1/0, 0/0, 1, 1/2}, ""), "{Inf,-Inf,NaN,1,0.5}") 95 | 96 | if _VERSION == "Lua 5.3" or _VERSION == "Lua 5.4" then 97 | asserteq(pretty.write({1.0}, ""), "{1.0}") 98 | else 99 | asserteq(pretty.write({1.0}, ""), "{1}") 100 | end 101 | 102 | do -- issue #203, item 3 103 | local t = {}; t[t] = 1 104 | pretty.write(t) -- should not crash 105 | end 106 | 107 | 108 | do 109 | local float = 1e100 110 | local max_int = 9007199254740991 -- 1 << 53 - 1 111 | local min_int = -9007199254740991 112 | 113 | asserteq(pretty.write(float), "1.0e+100") 114 | if _VERSION == "Lua 5.3" or _VERSION == "Lua 5.4" then 115 | --There is no way to portably format with %d before 5.3 116 | asserteq(pretty.write(min_int - 3), "-9007199254740994") 117 | asserteq(pretty.write(max_int + 3), "9007199254740994") 118 | asserteq(pretty.write(min_int), "-9007199254740991") 119 | asserteq(pretty.write(max_int), "9007199254740991") 120 | end 121 | end 122 | 123 | -- pretty.write fails if an __index metatable raises an error #257 124 | -- only applies to 5.3+ where iterators respect metamethods 125 | do 126 | local t = setmetatable({},{ 127 | __index = function(self, key) 128 | error("oops... couldn't find " .. tostring(key)) 129 | end 130 | }) 131 | asserteq(pretty.write(t), "{\n}") 132 | end 133 | -------------------------------------------------------------------------------- /tests/test-seq.lua: -------------------------------------------------------------------------------- 1 | local input = require 'pl.input' 2 | local seq = require 'pl.seq' 3 | local asserteq = require('pl.test').asserteq 4 | local utils = require 'pl.utils' 5 | local stringio = require 'pl.stringio' 6 | local unpack = utils.unpack 7 | 8 | local L = utils.string_lambda 9 | local S = seq.list 10 | local C = seq.copy 11 | local C2 = seq.copy2 12 | 13 | 14 | asserteq (seq.sum(input.numbers '10 20 30 40 50'),150) 15 | local x,y = unpack(C(input.numbers('10 20'))) 16 | assert (x == 10 and y == 20) 17 | 18 | 19 | local test = {{1,10},{2,20},{3,30}} 20 | asserteq(C2(ipairs{10,20,30}),test) 21 | local res = C2(input.fields({1,2},',','1,10\n2,20\n3,30\n')) 22 | asserteq(res,test) 23 | 24 | asserteq( 25 | seq.copy(seq.filter(seq.list{10,20,5,15},seq.greater_than(10))), 26 | {20,15} 27 | ) 28 | 29 | asserteq( 30 | seq.copy(seq.filter(seq.list{10,20,5,15},seq.less_than(15))), 31 | {10,5} 32 | ) 33 | 34 | asserteq( 35 | #C(seq.filter(seq.list{10,20,5,10,15},seq.equal_to(10))), 36 | 2 37 | ) 38 | 39 | asserteq( 40 | #seq{'green','yellow','red','blue','red'}:filter(seq.equal_to'red'):copy(), 41 | 2 42 | ) 43 | 44 | asserteq( 45 | seq{'apple','orange','pineapple'}:filter(seq.matching'apple'):copy(), 46 | {'apple','pineapple'} 47 | ) 48 | 49 | asserteq( 50 | C(seq.sort(seq.keys{[11] = true, [17]= true, [23] = true})), 51 | {11,17,23} 52 | ) 53 | 54 | asserteq( 55 | C(seq.range(2,5)), 56 | {2,3,4,5} 57 | ) 58 | 59 | asserteq(seq.reduce('-',{1,2,3,4,5}),-13) 60 | 61 | asserteq(seq.count(S{10,20,30,40},L'|x| x > 20'), 2) 62 | 63 | asserteq(C2(seq.zip({1,2,3},{10,20,30})),test) 64 | 65 | asserteq(C(seq.splice({10,20},{30,40})),{10,20,30,40}) 66 | 67 | asserteq(C(seq.map(L'#_',{'one','tw'})),{3,2}) 68 | 69 | --for l1,l2 in seq.last{10,20,30} do print(l1,l2) end 70 | 71 | asserteq( C2(seq.last{10,20,30}),{{20,10},{30,20}} ) 72 | 73 | asserteq( C2(seq.last{40}),{} ) 74 | 75 | asserteq( C2(seq.last{}),{} ) 76 | 77 | asserteq( 78 | seq{10,20,30}:map(L'_+1'):copy(), 79 | {11,21,31} 80 | ) 81 | 82 | asserteq( 83 | seq {1,2,3,4,5}:reduce ('*'), 120 84 | ) 85 | 86 | -- test reduce with an initial value 87 | asserteq( 88 | seq {1,2,3,4,5}:reduce ('+', 42), 57 89 | ) 90 | 91 | -- test reduce with a short sequence 92 | asserteq( 93 | seq {7}:reduce ('+'), 7 94 | ) 95 | 96 | asserteq( 97 | seq {5}:reduce ('/', 40), 8 98 | ) 99 | 100 | asserteq( 101 | seq {}:reduce ('+', 42), 42 102 | ) 103 | 104 | asserteq( 105 | seq {}:reduce ('-'), nil 106 | ) 107 | 108 | asserteq( 109 | seq{'one','two'}:upper():copy(), 110 | {'ONE','TWO'} 111 | ) 112 | 113 | asserteq( 114 | seq{'one','two','three'}:skip(1):copy(), 115 | {'two','three'} 116 | ) 117 | 118 | -- test skipping pass sequence 119 | asserteq( 120 | seq{'one','two','three'}:skip(4):copy(), 121 | {} 122 | ) 123 | 124 | asserteq( 125 | seq{7,8,9,10}:take(3):copy(), 126 | {7,8,9} 127 | ) 128 | 129 | asserteq( 130 | seq{7,8,9,10}:take(6):copy(), 131 | {7,8,9,10} 132 | ) 133 | 134 | asserteq( 135 | seq{7,8,9,10}:take(0):copy(), 136 | {} 137 | ) 138 | 139 | asserteq( 140 | seq{7,8,9,10}:take(-1):copy(), 141 | {} 142 | ) 143 | 144 | local l, u = 50, 100 145 | local rand_seq = seq(seq.random(7, l, u)) 146 | asserteq( 147 | #rand_seq:filter(seq.less_than(u+1)):filter(seq.greater_than(l-1)):copy(), 148 | 7 149 | ) 150 | 151 | rand_seq = seq(seq.random(7, u)) 152 | asserteq( 153 | #rand_seq:filter(seq.less_than(u+1)):filter(seq.greater_than(0)):copy(), 154 | 7 155 | ) 156 | 157 | rand_seq = seq(seq.random(7)) 158 | asserteq( 159 | #rand_seq:filter(seq.less_than(1)):filter(seq.greater_than(0)):copy(), 160 | 7 161 | ) 162 | 163 | test = {275,127,286,590,961,687,802,453,705,182} 164 | asserteq( 165 | C(seq.sort{seq(test):minmax()}), 166 | {127,961} 167 | ) 168 | 169 | asserteq( 170 | seq(test):take(5):enum():copy_tuples(), 171 | {{1,275},{2,127},{3,286},{4,590},{5,961}} 172 | ) 173 | 174 | asserteq( 175 | C(seq.unique(seq.list{1,2,3,2,1})), 176 | {1,2,3} 177 | ) 178 | 179 | local actualstr = {} 180 | local expectedstr = "275.00 127.00 286.00 590.00 961.00 687.00 802.00\n".. 181 | "453.00 705.00 182.00 \n" 182 | local function proxywrite_printall(head, ...) 183 | table.insert(actualstr, tostring(head)) 184 | if select('#', ...) == 0 then return true end 185 | return proxywrite_printall(...) 186 | end 187 | 188 | local iowrite = io.write 189 | io.write = proxywrite_printall 190 | seq(test):printall(nil,nil,'%.2f') 191 | io.write = iowrite 192 | asserteq( 193 | table.concat(actualstr), 194 | expectedstr 195 | ) 196 | 197 | 198 | local f = stringio.open '1 2 3 4' 199 | 200 | -- seq.lines may take format specifiers if using Lua 5.2, or a 5.2-compatible 201 | -- file object like that returned by stringio. 202 | asserteq( 203 | seq.lines(f,'*n'):copy(), 204 | {1,2,3,4} 205 | ) 206 | 207 | -- the seq() constructor can now take an iterator which consists of two parts, 208 | -- a function and an object - as returned e.g. by lfs.dir() 209 | 210 | local function my_iter(T) 211 | local idx = 0 212 | return function(self) 213 | idx = idx + 1 214 | return self[idx] 215 | end, 216 | T 217 | end 218 | 219 | asserteq( 220 | seq(my_iter{10,20,30}):copy(), 221 | {10,20,30} 222 | ) 223 | 224 | -------------------------------------------------------------------------------- /tests/test-sip.lua: -------------------------------------------------------------------------------- 1 | local sip = require 'pl.sip' 2 | local tablex = require 'pl.tablex' 3 | local test = require 'pl.test' 4 | 5 | local function check(pat,line,tbl) 6 | local parms = {} 7 | if type(pat) == 'string' then 8 | pat = sip.compile(pat) 9 | end 10 | if pat(line,parms) then 11 | test.asserteq(parms,tbl) 12 | else -- only should happen if we're passed a nil! 13 | assert(tbl == nil) 14 | end 15 | end 16 | 17 | local c = sip.compile('ref=$S{file}:$d{line}') 18 | check(c,'ref=bonzo:23',{file='bonzo',line=23}) 19 | check(c,'here we go ref=c:\\bonzo\\dog.txt:53',{file='c:\\bonzo\\dog.txt',line=53}) 20 | check(c,'here is a line ref=xxxx:xx',nil) 21 | 22 | c = sip.compile('($i{x},$i{y},$i{z})') 23 | check(c,'(10,20,30)',{x=10,y=20,z=30}) 24 | check(c,' (+233,+99,-40) ',{x=233,y=99,z=-40}) 25 | 26 | local pat = '$v{name} = $q{str}' 27 | --assert(sip.create_pattern(pat) == [[([%a_][%w_]*)%s*=%s*(["'])(.-)%2]]) 28 | local m = sip.compile(pat) 29 | 30 | check(m,'a = "hello"',{name='a',str='hello'}) 31 | check(m,"a = 'hello'",{name='a',str='hello'}) 32 | check(m,'_fred="some text"',{name='_fred',str='some text'}) 33 | 34 | -- some cases broken in 0.6b release 35 | check('$v is $v','bonzo is dog for sure',{'bonzo','dog'}) 36 | check('$v is $','bonzo is dog for sure',{'bonzo','dog for sure'}) 37 | 38 | -- spaces 39 | check('$v $d','age 23',{'age',23}) 40 | check('$v $d','age 23',{'age',23}) 41 | check('$v $d','age23') -- the space is 'imcompressible' 42 | check('a b c $r', 'a bc d') 43 | check('a b c $r', 'a b c d',{'d'}) 44 | 45 | -- the spaces in this pattern, however, are compressible. 46 | check('$v = $d','age=23',{'age',23}) 47 | 48 | -- patterns without patterns 49 | check('just a string', 'just a string', {}) 50 | check('just a string', 'not that string') 51 | 52 | local months={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"} 53 | 54 | local function adjust_year(res) 55 | if res.year < 100 then 56 | if res.year < 70 then 57 | res.year = res.year + 2000 58 | else 59 | res.year = res.year + 1900 60 | end 61 | end 62 | end 63 | 64 | local shortdate = sip.compile('$d{day}/$d{month}/$d{year}') 65 | local longdate = sip.compile('$d{day} $v{month} $d{year}') 66 | local isodate = sip.compile('$d{year}-$d{month}-$d{day}') 67 | 68 | local function dcheck (d1,d2) 69 | adjust_year(d1) 70 | test.asserteq(d1, d2) 71 | end 72 | 73 | local function dates(str,tbl) 74 | local res = {} 75 | if shortdate(str,res) then 76 | dcheck(res,tbl) 77 | elseif isodate(str,res) then 78 | dcheck(res,tbl) 79 | elseif longdate(str,res) then 80 | res.month = tablex.find(months,res.month) 81 | dcheck(res,tbl) 82 | else 83 | assert(tbl == nil) 84 | end 85 | end 86 | 87 | dates ('10/12/2007',{year=2007,month=12,day=10}) 88 | dates ('2006-03-01',{year=2006,month=3,day=1}) 89 | dates ('25/07/05',{year=2005,month=7,day=25}) 90 | dates ('20 Mar 1959',{year=1959,month=3,day=20}) 91 | 92 | local sio = require 'pl.stringio' 93 | local lines = [[ 94 | dodge much amazement 95 | kitteh cheezburger 96 | ]] 97 | sip.read(sio.open(lines),{ 98 | {'dodge $',function(rest) test.asserteq(rest,'much amazement') end}, 99 | {'kitteh $',function(rest) test.asserteq(rest,'cheezburger') end} 100 | }) 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /tests/test-strict.lua: -------------------------------------------------------------------------------- 1 | require 'pl.compat' -- require this one before loading strict 2 | local strict = require 'pl.strict' 3 | local test = require 'pl.test' 4 | local app = require 'pl.app' 5 | 6 | -- in strict mode, you must assign to a global first, even if just nil. 7 | test.assertraise(function() 8 | print(x) 9 | print 'ok?' 10 | end,"variable 'x' is not declared") 11 | 12 | -- can assign to globals in main (or from C extensions) but not anywhere else! 13 | test.assertraise(function() 14 | Boo = 3 15 | end,"assign to undeclared global 'Boo'") 16 | 17 | Boo = true 18 | Boo2 = nil 19 | 20 | -- once declared, you can assign to globals from anywhere 21 | (function() Boo = 42; Boo2 = 6*7 end)() 22 | 23 | --- a module may use strict.module() to generate a simularly strict environment 24 | -- (see lua/mymod.lua) 25 | app.require_here 'lua' 26 | local M = require 'mymod' 27 | 28 | --- these are fine 29 | M.answer() 30 | M.question() 31 | 32 | -- spelling mistakes become errors... 33 | test.assertraise(function() 34 | print(M.Answer()) 35 | end,"variable 'Answer' is not declared in 'mymod'") 36 | 37 | --- for the extra paranoid, you can choose to make all global tables strict... 38 | strict.make_all_strict(_G) 39 | 40 | test.assertraise(function() 41 | print(math.sine(1.2)) 42 | end,"variable 'sine' is not declared in 'math'") 43 | 44 | 45 | 46 | -- module 47 | do 48 | local testmodule = { 49 | hello = function() return "supremacy" end 50 | } 51 | -- make strict and allow extra field "world" 52 | strict.module("my_test", testmodule, { world = true }) 53 | 54 | test.asserteq(testmodule.hello(), "supremacy") 55 | test.assertraise(function() 56 | print(testmodule.not_allowed_key) 57 | end, "variable 'not_allowed_key' is not declared in 'my_test'") 58 | 59 | test.asserteq(testmodule.world, nil) 60 | testmodule.world = "supremacy" 61 | test.asserteq(testmodule.world, "supremacy") 62 | 63 | 64 | -- table with a __newindex method 65 | local mod1 = strict.module("mod1", setmetatable( 66 | { 67 | hello = "world", 68 | }, { 69 | __newindex = function(self, key, value) 70 | if key == "Lua" then 71 | rawset(self, key, value) 72 | end 73 | end, 74 | } 75 | )) 76 | test.asserteq(mod1.hello, "world") 77 | mod1.Lua = "hello world" 78 | test.asserteq(mod1.Lua, "hello world") 79 | test.assertraise(function() 80 | print(mod1.not_allowed_key) 81 | end, "variable 'not_allowed_key' is not declared in 'mod1'") 82 | 83 | 84 | -- table with a __index method 85 | local mod1 = strict.module("mod1", setmetatable( 86 | { 87 | hello = "world", 88 | }, { 89 | __index = function(self, key) 90 | if key == "Lua" then 91 | return "rocks" 92 | end 93 | end, 94 | } 95 | )) 96 | test.asserteq(mod1.hello, "world") 97 | test.asserteq(mod1.Lua, "rocks") 98 | test.assertraise(function() 99 | print(mod1.not_allowed_key) 100 | end, "variable 'not_allowed_key' is not declared in 'mod1'") 101 | 102 | 103 | -- table with a __index table 104 | local mod1 = strict.module("mod1", setmetatable( 105 | { 106 | hello = "world", 107 | }, { 108 | __index = { 109 | Lua = "rocks!" 110 | } 111 | } 112 | )) 113 | test.asserteq(mod1.hello, "world") 114 | test.asserteq(mod1.Lua, "rocks!") 115 | test.assertraise(function() 116 | print(mod1.not_allowed_key) 117 | end, "variable 'not_allowed_key' is not declared in 'mod1'") 118 | 119 | end 120 | 121 | 122 | do 123 | -- closed_module 124 | -- what does this do? this does not seem a usefull function??? 125 | 126 | local testmodule = { 127 | hello = function() return "supremacy" end 128 | } 129 | local M = strict.closed_module(testmodule, "my_test") 130 | 131 | -- read acces to original is granted, but not to the new one 132 | test.asserteq(testmodule.hello(), "supremacy") 133 | test.assertraise(function() 134 | print(M.hello()) 135 | end, "variable 'hello' is not declared in 'my_test'") 136 | 137 | -- write access to both is granted 138 | testmodule.world = "domination" 139 | M.world = "domination" 140 | 141 | -- read acces to set field in original is granted, but not set 142 | test.asserteq(testmodule.world, nil) 143 | test.asserteq(M.world, "domination") 144 | 145 | end 146 | -------------------------------------------------------------------------------- /tests/test-stringio.lua: -------------------------------------------------------------------------------- 1 | local stringio = require 'pl.stringio' 2 | local test = require 'pl.test' 3 | local asserteq = test.asserteq 4 | local T = test.tuple 5 | 6 | function fprintf(f,fmt,...) 7 | f:write(fmt:format(...)) 8 | end 9 | 10 | fs = stringio.create() 11 | for i = 1,100 do 12 | fs:write('hello','\n','dolly','\n') 13 | end 14 | asserteq(#fs:value(),1200) 15 | 16 | fs = stringio.create() 17 | fs:writef("%s %d",'answer',42) -- note writef() extension method 18 | asserteq(fs:value(),"answer 42") 19 | 20 | inf = stringio.open('10 20 30') 21 | asserteq(T(inf:read('*n','*n','*n')),T(10,20,30)) 22 | 23 | local txt = [[ 24 | Some lines 25 | here are they 26 | not for other 27 | english? 28 | 29 | ]] 30 | 31 | inf = stringio.open (txt) 32 | fs = stringio.create() 33 | for l in inf:lines() do 34 | fs:write(l,'\n') 35 | end 36 | asserteq(txt,fs:value()) 37 | 38 | inf = stringio.open '1234567890ABCDEF' 39 | asserteq(T(inf:read(3), inf:read(5), inf:read()),T('123','45678','90ABCDEF')) 40 | 41 | s = stringio.open 'one\ntwo' 42 | asserteq(s:read() , 'one') 43 | asserteq(s:read() , 'two') 44 | asserteq(s:read() , nil) 45 | s = stringio.open 'one\ntwo' 46 | iter = s:lines() 47 | asserteq(iter() , 'one') 48 | asserteq(iter() , 'two') 49 | asserteq(iter() , nil) 50 | s = stringio.open 'ABC' 51 | iter = s:lines(1) 52 | asserteq(iter() , 'A') 53 | asserteq(iter() , 'B') 54 | asserteq(iter() , 'C') 55 | asserteq(iter() , nil) 56 | 57 | s = stringio.open '20 5.2e-2 52.3' 58 | x,y,z = s:read('*n','*n','*n') 59 | out = stringio.create() 60 | fprintf(out,"%5.2f %5.2f %5.2f!",x,y,z) 61 | asserteq(out:value(),"20.00 0.05 52.30!") 62 | 63 | s = stringio.open 'one\ntwo\n\n' 64 | iter = s:lines '*L' 65 | asserteq(iter(),'one\n') 66 | asserteq(iter(),'two\n') 67 | asserteq(iter(),'\n') 68 | asserteq(iter(),nil) 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /tests/test-tablex3.lua: -------------------------------------------------------------------------------- 1 | -- tablex.move when the tables are the same 2 | -- and there are overlapping ranges 3 | T = require 'pl.tablex' 4 | asserteq = require 'pl.test'.asserteq 5 | 6 | t1 = {1,2,3,4,5,6,7,8,9,10} 7 | t2 = T.copy(t1) 8 | t3 = T.copy(t1) 9 | 10 | T.move(t1,t2,4,1,4) 11 | T.move(t3,t3,4,1,4) 12 | asserteq(t1,t3) 13 | -------------------------------------------------------------------------------- /tests/test-template2.lua: -------------------------------------------------------------------------------- 1 | local T = require 'pl.text' 2 | local utils = require 'pl.utils' 3 | local Template = T.Template 4 | local asserteq = require 'pl.test'.asserteq 5 | local OrderedMap = require 'pl.OrderedMap' 6 | local template = require 'pl.template' 7 | 8 | local t = [[ 9 | # for i = 1,3 do 10 | print($(i+1)) 11 | # end 12 | ]] 13 | 14 | asserteq(template.substitute(t),[[ 15 | print(2) 16 | print(3) 17 | print(4) 18 | ]]) 19 | 20 | t = [[ 21 | > for i = 1,3 do 22 | print(${i+1}) 23 | > end 24 | ]] 25 | 26 | asserteq(template.substitute(t,{_brackets='{}',_escape='>'}),[[ 27 | print(2) 28 | print(3) 29 | print(4) 30 | ]]) 31 | 32 | t = [[ 33 | #@ for i = 1,3 do 34 | print(@{i+1}) 35 | #@ end 36 | ]] 37 | 38 | asserteq(template.substitute(t,{_brackets='{}',_escape='#@',_inline_escape='@'}),[[ 39 | print(2) 40 | print(3) 41 | print(4) 42 | ]]) 43 | 44 | --- iteration using pairs is usually unordered. But using OrderedMap 45 | --- we can get the exact original ordering. 46 | 47 | t = [[ 48 | # for k,v in pairs(T) do 49 | "$(k)", -- $(v) 50 | # end 51 | ]] 52 | 53 | if utils.lua51 then 54 | -- easy enough to define a general pairs in Lua 5.1 55 | local rawpairs = pairs 56 | function pairs(t) 57 | local mt = getmetatable(t) 58 | local f = mt and mt.__pairs 59 | if f then 60 | return f(t) 61 | else 62 | return rawpairs(t) 63 | end 64 | end 65 | end 66 | 67 | 68 | local Tee = OrderedMap{{Dog = 'Bonzo'}, {Cat = 'Felix'}, {Lion = 'Leo'}} 69 | 70 | -- note that the template will also look up global functions using _parent 71 | asserteq(template.substitute(t,{T=Tee,_parent=_G}),[[ 72 | "Dog", -- Bonzo 73 | "Cat", -- Felix 74 | "Lion", -- Leo 75 | ]]) 76 | 77 | -------------------------------------------------------------------------------- /tests/test-types.lua: -------------------------------------------------------------------------------- 1 | ---- testing types 2 | local types = require 'pl.types' 3 | local asserteq = require 'pl.test'.asserteq 4 | local List = require 'pl.List' 5 | 6 | local list = List() 7 | local array = {10,20,30} 8 | local map = {one=1,two=2} 9 | 10 | -- extended type() function 11 | asserteq(types.type(array),'table') 12 | asserteq(types.type('hello'),'string') 13 | -- knows about Lua file objects 14 | asserteq(types.type(io.stdin),'file') 15 | local f = io.open("tests/test-types.lua") 16 | asserteq(types.type(f),'file') 17 | f:close() 18 | -- and class names 19 | asserteq(types.type(list),'List') 20 | -- tables with unknown metatable 21 | asserteq(types.type(setmetatable({},{})), "unknown table") 22 | -- userdata with unknown metatable 23 | if newproxy then 24 | asserteq(types.type(newproxy(true)), "unknown userdata") 25 | end 26 | 27 | asserteq(types.is_integer(10),true) 28 | asserteq(types.is_integer(10.1),false) 29 | asserteq(types.is_integer(-10),true) 30 | asserteq(types.is_integer(-10.1),false) 31 | -- do note that for Lua < 5.3, 10.0 is the same as 10; an integer. 32 | 33 | asserteq(types.is_callable(asserteq),true) 34 | asserteq(types.is_callable(List),true) 35 | do 36 | local mt = setmetatable({}, { 37 | __index = { 38 | __call = function() return "ok" end 39 | } 40 | }) 41 | asserteq(type(mt.__call), "function") -- __call is looked-up through another metatable 42 | local nc = setmetatable({}, mt) 43 | -- proof-of-pudding, let's call it. To verify Lua behaves the same on all engines 44 | local success, result = pcall(function() return nc() end) 45 | assert(result ~= "ok", "expected result to not be 'ok'") 46 | asserteq(success, false) 47 | -- real test now 48 | asserteq(types.is_callable(nc), false) -- NOT callable, since __call is fetched using RAWget by Lua 49 | end 50 | 51 | asserteq(types.is_indexable(array),true) 52 | asserteq(types.is_indexable('hello'),nil) 53 | asserteq(types.is_indexable(10),nil) 54 | if newproxy then 55 | local v = newproxy(true) 56 | local mt = getmetatable(v) 57 | mt.__len = true 58 | mt.__index = true 59 | asserteq(types.is_indexable(v), true) 60 | end 61 | if newproxy then 62 | local v = newproxy(true) 63 | asserteq(types.is_indexable(v), nil) 64 | end 65 | 66 | asserteq(types.is_iterable(array),true) 67 | asserteq(types.is_iterable(true),nil) 68 | asserteq(types.is_iterable(42),nil) 69 | asserteq(types.is_iterable("array"),nil) 70 | if newproxy then 71 | local v = newproxy(true) 72 | local mt = getmetatable(v) 73 | mt.__pairs = true 74 | asserteq(types.is_iterable(v), true) 75 | end 76 | if newproxy then 77 | local v = newproxy(true) 78 | asserteq(types.is_iterable(v), nil) 79 | end 80 | 81 | asserteq(types.is_writeable(array),true) 82 | asserteq(types.is_writeable(true),nil) 83 | asserteq(types.is_writeable(42),nil) 84 | asserteq(types.is_writeable("array"),nil) 85 | if newproxy then 86 | local v = newproxy(true) 87 | local mt = getmetatable(v) 88 | mt.__newindex = true 89 | asserteq(types.is_writeable(v), true) 90 | end 91 | if newproxy then 92 | local v = newproxy(true) 93 | asserteq(types.is_writeable(v), nil) 94 | end 95 | 96 | asserteq(types.is_empty(nil),true) 97 | asserteq(types.is_empty({}),true) 98 | asserteq(types.is_empty({[false] = false}),false) 99 | asserteq(types.is_empty(""),true) 100 | asserteq(types.is_empty(" ",true),true) 101 | asserteq(types.is_empty(" "),false) 102 | asserteq(types.is_empty(true),true) 103 | -- Numbers 104 | asserteq(types.is_empty(0), true) 105 | asserteq(types.is_empty(20), true) 106 | -- Booleans 107 | asserteq(types.is_empty(false), true) 108 | asserteq(types.is_empty(true), true) 109 | -- Functions 110 | asserteq(types.is_empty(print), true) 111 | -- Userdata 112 | --asserteq(types.is_empty(newproxy()), true) --newproxy was removed in Lua 5.2 113 | 114 | -- a more relaxed kind of truthiness.... 115 | asserteq(types.to_bool('yes'),true) 116 | asserteq(types.to_bool('true'),true) 117 | asserteq(types.to_bool('y'),true) 118 | asserteq(types.to_bool('t'),true) 119 | asserteq(types.to_bool('YES'),true) 120 | asserteq(types.to_bool('1'),true) 121 | asserteq(types.to_bool('no'),false) 122 | asserteq(types.to_bool('false'),false) 123 | asserteq(types.to_bool('n'),false) 124 | asserteq(types.to_bool('f'),false) 125 | asserteq(types.to_bool('NO'),false) 126 | asserteq(types.to_bool('0'),false) 127 | asserteq(types.to_bool(1),true) 128 | asserteq(types.to_bool(0),false) 129 | local de_fr = { 'ja', 'oui' } 130 | asserteq(types.to_bool('ja', de_fr),true) 131 | asserteq(types.to_bool('OUI', de_fr),true) 132 | local t_e = {} 133 | local t_ne = { "not empty" } 134 | asserteq(types.to_bool(t_e,nil,false),false) 135 | asserteq(types.to_bool(t_e,nil,true),false) 136 | asserteq(types.to_bool(t_ne,nil,false),false) 137 | asserteq(types.to_bool(t_ne,nil,true),true) 138 | asserteq(types.to_bool(coroutine.create(function() end),nil,true),true) 139 | asserteq(types.to_bool(coroutine.create(function() end),nil,false),false) 140 | -------------------------------------------------------------------------------- /tests/test-url.lua: -------------------------------------------------------------------------------- 1 | local url = require 'pl.url' 2 | local asserteq = require 'pl.test' . asserteq 3 | 4 | asserteq(url.quote(''), '') 5 | asserteq(url.quote('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') 6 | asserteq(url.quote('abcdefghijklmnopqrstuvwxyz'), 'abcdefghijklmnopqrstuvwxyz') 7 | asserteq(url.quote('0123456789'), '0123456789') 8 | asserteq(url.quote(' -_./'), '%20-_./') 9 | asserteq(url.quote('`~!@#$%^&*()'), '%60%7E%21%40%23%24%25%5E%26%2A%28%29') 10 | asserteq(url.quote('%2'), '%252') 11 | asserteq(url.quote('2R%1%%'), '2R%251%25%25') 12 | 13 | asserteq(url.quote('', true), '') 14 | asserteq(url.quote('ABCDEFGHIJKLMNOPQRSTUVWXYZ', true), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') 15 | asserteq(url.quote('abcdefghijklmnopqrstuvwxyz', true), 'abcdefghijklmnopqrstuvwxyz') 16 | asserteq(url.quote('0123456789'), '0123456789', true) 17 | asserteq(url.quote(' -_./', true), '+-_.%2F') 18 | asserteq(url.quote('`~!@#$%^&*()', true), '%60%7E%21%40%23%24%25%5E%26%2A%28%29') 19 | asserteq(url.quote('%2', true), '%252') 20 | asserteq(url.quote('2R%1%%', true), '2R%251%25%25') 21 | 22 | asserteq(url.unquote(''), '') 23 | asserteq(url.unquote('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') 24 | asserteq(url.unquote('abcdefghijklmnopqrstuvwxyz'), 'abcdefghijklmnopqrstuvwxyz') 25 | asserteq(url.unquote('0123456789'), '0123456789') 26 | asserteq(url.unquote(' -_./'), ' -_./') 27 | asserteq(url.unquote('+-_.%2F'), ' -_./') 28 | asserteq(url.unquote('%20-_./'), ' -_./') 29 | asserteq(url.unquote('%60%7E%21%40%23%24%25%5E%26%2A%28%29'), '`~!@#$%^&*()') 30 | asserteq(url.unquote('%252'), '%2') 31 | asserteq(url.unquote('2%52%1%%'), '2R%1%%') 32 | asserteq(url.unquote('2R%251%25%25'), '2R%1%%') 33 | 34 | asserteq(url.quote(true), true) 35 | asserteq(url.quote(42), 42) 36 | asserteq(url.unquote(true), true) 37 | asserteq(url.unquote(42), 42) 38 | -------------------------------------------------------------------------------- /tests/test-utils2.lua: -------------------------------------------------------------------------------- 1 | local path = require 'pl.path' 2 | local utils = require 'pl.utils' 3 | local asserteq = require 'pl.test'.asserteq 4 | 5 | local echo_lineending = "\n" 6 | if path.is_windows then 7 | echo_lineending = " \n" 8 | end 9 | 10 | local function test_executeex(cmd, expected_successful, expected_retcode, expected_stdout, expected_stderr) 11 | --print("\n"..cmd) 12 | --print(os.execute(cmd)) 13 | --print(utils.executeex(cmd)) 14 | local successful, retcode, stdout, stderr = utils.executeex(cmd) 15 | asserteq(successful, expected_successful) 16 | asserteq(retcode, expected_retcode) 17 | asserteq(stdout, expected_stdout) 18 | asserteq(stderr, expected_stderr) 19 | end 20 | 21 | -- Check the return codes 22 | if utils.is_windows then 23 | test_executeex("exit", true, 0, "", "") 24 | test_executeex("exit 0", true, 0, "", "") 25 | test_executeex("exit 1", false, 1, "", "") 26 | test_executeex("exit 13", false, 13, "", "") 27 | test_executeex("exit 255", false, 255, "", "") 28 | test_executeex("exit 256", false, 256, "", "") 29 | test_executeex("exit 257", false, 257, "", "") 30 | test_executeex("exit 3809", false, 3809, "", "") 31 | test_executeex("exit -1", false, -1, "", "") 32 | test_executeex("exit -13", false, -13, "", "") 33 | test_executeex("exit -255", false, -255, "", "") 34 | test_executeex("exit -256", false, -256, "", "") 35 | test_executeex("exit -257", false, -257, "", "") 36 | test_executeex("exit -3809", false, -3809, "", "") 37 | else 38 | test_executeex("exit", true, 0, "", "") 39 | test_executeex("exit 0", true, 0, "", "") 40 | test_executeex("exit 1", false, 1, "", "") 41 | test_executeex("exit 13", false, 13, "", "") 42 | test_executeex("exit 255", false, 255, "", "") 43 | -- on posix anything other than 0-255 is undefined 44 | test_executeex("exit 256", true, 0, "", "") 45 | test_executeex("exit 257", false, 1, "", "") 46 | test_executeex("exit 3809", false, 225, "", "") 47 | end 48 | 49 | -- Check output strings 50 | test_executeex("echo stdout", true, 0, "stdout" .. echo_lineending, "") 51 | test_executeex("(echo stderr 1>&2)", true, 0, "", "stderr" .. echo_lineending) 52 | test_executeex("(echo stdout && (echo stderr 1>&2))", true, 0, "stdout" .. echo_lineending, "stderr" .. echo_lineending) 53 | 54 | -------------------------------------------------------------------------------- /tests/test-utils3.lua: -------------------------------------------------------------------------------- 1 | --- testing Lua 5.1/5.2 compatibility functions 2 | -- these are global side-effects of pl.utils 3 | local utils = require 'pl.utils' 4 | local test = require 'pl.test' 5 | local asserteq = test.asserteq 6 | local _,lua = require 'pl.app'. lua() 7 | local setfenv,getfenv = utils.setfenv, utils.getfenv 8 | 9 | -- utils.execute is a compromise between 5.1 and 5.2 for os.execute changes 10 | -- can we call Lua ? 11 | local ok,code = utils.execute(lua..' -v') 12 | asserteq(ok,true) 13 | asserteq(code,0) 14 | -- does it return false when it fails ? 15 | asserteq(utils.execute('most-likely-nonexistent-command'),false) 16 | 17 | -- table.pack is defined for 5.1 18 | local t = table.pack(1,nil,'hello') 19 | asserteq(t.n,3) 20 | assert(t[1] == 1 and t[3] == 'hello') 21 | 22 | -- unpack is not globally available for 5.2 unless in compat mode. 23 | -- But utils.unpack is always defined. 24 | local a,b = utils.unpack{10,'wow'} 25 | assert(a == 10 and b == 'wow') 26 | 27 | -- utils.load() is Lua 5.2 style 28 | chunk = utils.load('return x+y','tmp','t',{x=1,y=2}) 29 | asserteq(chunk(),3) 30 | 31 | -- can only load a binary chunk if the mode permits! 32 | local f = string.dump(function() end) 33 | local res,err = utils.load(f,'tmp','t') 34 | test.assertmatch(err,'attempt to load') 35 | 36 | -- package.searchpath for Lua 5.1 37 | -- nota bene: depends on ./?.lua being in the package.path! 38 | -- So we hack it if not found 39 | if not package.path:find '.[/\\]%?' then 40 | package.path = './?.lua;'..package.path 41 | end 42 | 43 | asserteq( 44 | package.searchpath('tests.test-utils3',package.path):gsub('\\','/'), 45 | './tests/test-utils3.lua' 46 | ) 47 | 48 | -- testing getfenv and setfenv for both interpreters 49 | 50 | function test() 51 | return X + Y + Z 52 | end 53 | 54 | t = {X = 1, Y = 2, Z = 3} 55 | 56 | setfenv(test,t) 57 | 58 | assert(test(),6) 59 | 60 | t.X = 10 61 | 62 | assert(test(),15) 63 | 64 | local getfenv,_G = getfenv,_G 65 | 66 | function test2() 67 | local env = {x=2} 68 | setfenv(1,env) 69 | asserteq(getfenv(1),env) 70 | asserteq(x,2) 71 | end 72 | 73 | test2() 74 | 75 | 76 | 77 | --------------------------------------------------------------------------------