From 42ec7286b2d36a9ba22925f816a17cb1cc2aa5ce Mon Sep 17 00:00:00 2001 From: chai Date: Sat, 30 Oct 2021 11:32:16 +0800 Subject: + Penlight --- Data/Libraries/Penlight/docs/classes/pl.Date.html | 1049 +++++++++++ Data/Libraries/Penlight/docs/classes/pl.List.html | 1443 ++++++++++++++ Data/Libraries/Penlight/docs/classes/pl.Map.html | 454 +++++ .../Penlight/docs/classes/pl.MultiMap.html | 207 ++ .../Penlight/docs/classes/pl.OrderedMap.html | 417 +++++ Data/Libraries/Penlight/docs/classes/pl.Set.html | 655 +++++++ .../Penlight/docs/examples/seesubst.lua.html | 174 ++ .../Penlight/docs/examples/sipscan.lua.html | 161 ++ .../Penlight/docs/examples/symbols.lua.html | 347 ++++ .../Penlight/docs/examples/test-cmp.lua.html | 130 ++ .../Penlight/docs/examples/test-data.lua.html | 372 ++++ .../docs/examples/test-listcallbacks.lua.html | 138 ++ .../Penlight/docs/examples/test-pretty.lua.html | 140 ++ .../Penlight/docs/examples/test-symbols.lua.html | 209 +++ .../Penlight/docs/examples/testapp.lua.html | 133 ++ .../Penlight/docs/examples/testclone.lua.html | 165 ++ .../Penlight/docs/examples/testconfig.lua.html | 176 ++ .../Penlight/docs/examples/testglobal.lua.html | 153 ++ .../docs/examples/testinputfields.lua.html | 140 ++ .../docs/examples/testinputfields2.lua.html | 136 ++ .../Penlight/docs/examples/testxml.lua.html | 209 +++ .../Penlight/docs/examples/which.lua.html | 155 ++ Data/Libraries/Penlight/docs/index.html | 392 ++++ Data/Libraries/Penlight/docs/ldoc_fixed.css | 311 +++ Data/Libraries/Penlight/docs/libraries/pl.Set.html | 650 +++++++ Data/Libraries/Penlight/docs/libraries/pl.app.html | 397 ++++ .../Penlight/docs/libraries/pl.array2d.html | 1319 +++++++++++++ .../Penlight/docs/libraries/pl.class.html | 332 ++++ .../Penlight/docs/libraries/pl.compat.html | 580 ++++++ .../Penlight/docs/libraries/pl.comprehension.html | 165 ++ .../Penlight/docs/libraries/pl.config.html | 259 +++ .../Libraries/Penlight/docs/libraries/pl.data.html | 571 ++++++ Data/Libraries/Penlight/docs/libraries/pl.dir.html | 615 ++++++ .../Libraries/Penlight/docs/libraries/pl.file.html | 301 +++ .../Libraries/Penlight/docs/libraries/pl.func.html | 460 +++++ Data/Libraries/Penlight/docs/libraries/pl.html | 139 ++ .../Penlight/docs/libraries/pl.import_into.html | 142 ++ .../Penlight/docs/libraries/pl.input.html | 336 ++++ .../Libraries/Penlight/docs/libraries/pl.lapp.html | 382 ++++ .../Penlight/docs/libraries/pl.lexer.html | 524 ++++++ .../Penlight/docs/libraries/pl.luabalanced.html | 149 ++ .../Penlight/docs/libraries/pl.operator.html | 819 ++++++++ .../Libraries/Penlight/docs/libraries/pl.path.html | 1070 +++++++++++ .../Penlight/docs/libraries/pl.permute.html | 354 ++++ .../Penlight/docs/libraries/pl.pretty.html | 402 ++++ Data/Libraries/Penlight/docs/libraries/pl.seq.html | 888 +++++++++ Data/Libraries/Penlight/docs/libraries/pl.sip.html | 399 ++++ .../Penlight/docs/libraries/pl.strict.html | 270 +++ .../Penlight/docs/libraries/pl.stringio.html | 215 +++ .../Penlight/docs/libraries/pl.stringx.html | 1239 ++++++++++++ .../Penlight/docs/libraries/pl.tablex.html | 1980 ++++++++++++++++++++ .../Penlight/docs/libraries/pl.template.html | 336 ++++ .../Libraries/Penlight/docs/libraries/pl.test.html | 445 +++++ .../Libraries/Penlight/docs/libraries/pl.text.html | 381 ++++ .../Penlight/docs/libraries/pl.types.html | 475 +++++ Data/Libraries/Penlight/docs/libraries/pl.url.html | 212 +++ .../Penlight/docs/libraries/pl.utils.html | 1384 ++++++++++++++ Data/Libraries/Penlight/docs/libraries/pl.xml.html | 835 +++++++++ .../Penlight/docs/manual/01-introduction.md.html | 843 +++++++++ .../Penlight/docs/manual/02-arrays.md.html | 914 +++++++++ .../Penlight/docs/manual/03-strings.md.html | 397 ++++ .../Penlight/docs/manual/04-paths.md.html | 329 ++++ .../Penlight/docs/manual/05-dates.md.html | 269 +++ .../Libraries/Penlight/docs/manual/06-data.md.html | 1633 ++++++++++++++++ .../Penlight/docs/manual/07-functional.md.html | 834 +++++++++ .../Penlight/docs/manual/08-additional.md.html | 815 ++++++++ .../Penlight/docs/manual/09-discussion.md.html | 233 +++ 67 files changed, 33158 insertions(+) create mode 100644 Data/Libraries/Penlight/docs/classes/pl.Date.html create mode 100644 Data/Libraries/Penlight/docs/classes/pl.List.html create mode 100644 Data/Libraries/Penlight/docs/classes/pl.Map.html create mode 100644 Data/Libraries/Penlight/docs/classes/pl.MultiMap.html create mode 100644 Data/Libraries/Penlight/docs/classes/pl.OrderedMap.html create mode 100644 Data/Libraries/Penlight/docs/classes/pl.Set.html create mode 100644 Data/Libraries/Penlight/docs/examples/seesubst.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/sipscan.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/symbols.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/test-cmp.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/test-data.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/test-listcallbacks.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/test-pretty.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/test-symbols.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/testapp.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/testclone.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/testconfig.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/testglobal.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/testinputfields.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/testinputfields2.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/testxml.lua.html create mode 100644 Data/Libraries/Penlight/docs/examples/which.lua.html create mode 100644 Data/Libraries/Penlight/docs/index.html create mode 100644 Data/Libraries/Penlight/docs/ldoc_fixed.css create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.Set.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.app.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.array2d.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.class.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.compat.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.comprehension.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.config.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.data.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.dir.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.file.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.func.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.import_into.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.input.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.lapp.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.lexer.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.luabalanced.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.operator.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.path.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.permute.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.pretty.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.seq.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.sip.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.strict.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.stringio.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.stringx.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.tablex.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.template.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.test.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.text.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.types.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.url.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.utils.html create mode 100644 Data/Libraries/Penlight/docs/libraries/pl.xml.html create mode 100644 Data/Libraries/Penlight/docs/manual/01-introduction.md.html create mode 100644 Data/Libraries/Penlight/docs/manual/02-arrays.md.html create mode 100644 Data/Libraries/Penlight/docs/manual/03-strings.md.html create mode 100644 Data/Libraries/Penlight/docs/manual/04-paths.md.html create mode 100644 Data/Libraries/Penlight/docs/manual/05-dates.md.html create mode 100644 Data/Libraries/Penlight/docs/manual/06-data.md.html create mode 100644 Data/Libraries/Penlight/docs/manual/07-functional.md.html create mode 100644 Data/Libraries/Penlight/docs/manual/08-additional.md.html create mode 100644 Data/Libraries/Penlight/docs/manual/09-discussion.md.html (limited to 'Data/Libraries/Penlight/docs') diff --git a/Data/Libraries/Penlight/docs/classes/pl.Date.html b/Data/Libraries/Penlight/docs/classes/pl.Date.html new file mode 100644 index 0000000..47d3d65 --- /dev/null +++ b/Data/Libraries/Penlight/docs/classes/pl.Date.html @@ -0,0 +1,1049 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class pl.Date

+

Date and Date Format classes.

+

See the Guide.

+ +

NOTE: the date module is deprecated! see + https://github.com/lunarmodules/Penlight/issues/285

+ +

Dependencies: pl.class, pl.stringx, pl.utils

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Date:set (t)set the current time of this Date object.
Date.tzone (ts)get the time zone offset from UTC.
Date:toUTC ()convert this date to UTC.
Date:toLocal ()convert this UTC date to local.
Date:year (y)set the year.
Date:month (m)set the month.
Date:day (d)set the day.
Date:hour (h)set the hour.
Date:min (min)set the minutes.
Date:sec (sec)set the seconds.
Date:yday (yday)set the day of year.
Date:year (y)get the year.
Date:month ()get the month.
Date:day ()get the day.
Date:hour ()get the hour.
Date:min ()get the minutes.
Date:sec ()get the seconds.
Date:yday ()get the day of year.
Date:weekday_name (full)name of day of week.
Date:month_name (full)name of month.
Date:is_weekend ()is this day on a weekend?.
Date:add (t)add to a date object.
Date:last_day ()last day of the month.
Date:diff (other)difference between two Date objects.
Date:__tostring ()long numerical ISO data format version of this date.
Date:__eq (other)equality between Date objects.
Date:__lt (other)ordering between Date objects.
Date:__sub ()difference between Date objects.
Date:__add (other)add a date and an interval.
Date.Interval (t)Date.Interval constructor
Date.Interval:__tostring ()If it's an interval then the format is '2 hours 29 sec' etc.
Date.Format (fmt.)Date.Format constructor.
Date.Format:parse (str)parse a string into a Date object.
Date.Format:tostring (d)convert a Date object into a string.
Date.Format:US_order (yesno)force US order in dates like 9/11/2001
+

Methods

+ + + + + +
pl.Date:Date (t, ...)Date constructor.
+ +
+
+ + +

Functions

+ +
+
+ + Date:set (t) +
+
+ set the current time of this Date object. + + +

Parameters:

+
    +
  • t + int + seconds since epoch +
  • +
+ + + + + +
+
+ + Date.tzone (ts) +
+
+ get the time zone offset from UTC. + + +

Parameters:

+
    +
  • ts + int + seconds ahead of UTC +
  • +
+ + + + + +
+
+ + Date:toUTC () +
+
+ convert this date to UTC. + + + + + + + +
+
+ + Date:toLocal () +
+
+ convert this UTC date to local. + + + + + + + +
+
+ + Date:year (y) +
+
+ set the year. + + +

Parameters:

+
    +
  • y + int + Four-digit year +
  • +
+ + + + + +
+
+ + Date:month (m) +
+
+ set the month. + + +

Parameters:

+
    +
  • m + int + month +
  • +
+ + + + + +
+
+ + Date:day (d) +
+
+ set the day. + + +

Parameters:

+
    +
  • d + int + day +
  • +
+ + + + + +
+
+ + Date:hour (h) +
+
+ set the hour. + + +

Parameters:

+
    +
  • h + int + hour +
  • +
+ + + + + +
+
+ + Date:min (min) +
+
+ set the minutes. + + +

Parameters:

+
    +
  • min + int + minutes +
  • +
+ + + + + +
+
+ + Date:sec (sec) +
+
+ set the seconds. + + +

Parameters:

+
    +
  • sec + int + seconds +
  • +
+ + + + + +
+
+ + Date:yday (yday) +
+
+ set the day of year. + + +

Parameters:

+
    +
  • yday + int + day of year +
  • +
+ + + + + +
+
+ + Date:year (y) +
+
+ get the year. + + +

Parameters:

+
    +
  • y + int + Four-digit year +
  • +
+ + + + + +
+
+ + Date:month () +
+
+ get the month. + + + + + + + +
+
+ + Date:day () +
+
+ get the day. + + + + + + + +
+
+ + Date:hour () +
+
+ get the hour. + + + + + + + +
+
+ + Date:min () +
+
+ get the minutes. + + + + + + + +
+
+ + Date:sec () +
+
+ get the seconds. + + + + + + + +
+
+ + Date:yday () +
+
+ get the day of year. + + + + + + + +
+
+ + Date:weekday_name (full) +
+
+ name of day of week. + + +

Parameters:

+
    +
  • full + bool + abbreviated if true, full otherwise. +
  • +
+ +

Returns:

+
    + + string + name +
+ + + + +
+
+ + Date:month_name (full) +
+
+ name of month. + + +

Parameters:

+
    +
  • full + int + abbreviated if true, full otherwise. +
  • +
+ +

Returns:

+
    + + string + name +
+ + + + +
+
+ + Date:is_weekend () +
+
+ is this day on a weekend?. + + + + + + + +
+
+ + Date:add (t) +
+
+ add to a date object. + + +

Parameters:

+ + +

Returns:

+
    + + this date +
+ + + + +
+
+ + Date:last_day () +
+
+ last day of the month. + + + +

Returns:

+
    + + int day +
+ + + + +
+
+ + Date:diff (other) +
+
+ difference between two Date objects. + + +

Parameters:

+
    +
  • other + Date + Date object +
  • +
+ +

Returns:

+
    + + Date.Interval + object +
+ + + + +
+
+ + Date:__tostring () +
+
+ long numerical ISO data format version of this date. + + + + + + + +
+
+ + Date:__eq (other) +
+
+ equality between Date objects. + + +

Parameters:

+
    +
  • other + + + +
  • +
+ + + + + +
+
+ + Date:__lt (other) +
+
+ ordering between Date objects. + + +

Parameters:

+
    +
  • other + + + +
  • +
+ + + + + +
+
+ + Date:__sub () +
+
+ difference between Date objects. + + + + + + + +
+
+ + Date:__add (other) +
+
+ add a date and an interval. + + +

Parameters:

+ + + + + + +
+
+ + Date.Interval (t) +
+
+ Date.Interval constructor + + +

Parameters:

+
    +
  • t + int + an interval in seconds +
  • +
+ + + + + +
+
+ + Date.Interval:__tostring () +
+
+ If it's an interval then the format is '2 hours 29 sec' etc. + + + + + + + +
+
+ + Date.Format (fmt.) +
+
+ Date.Format constructor. + + +

Parameters:

+
    +
  • fmt. + string + A string where the following fields are significant:

    + +
      +
    • d day (either d or dd)
    • +
    • y year (either yy or yyy)
    • +
    • m month (either m or mm)
    • +
    • H hour (either H or HH)
    • +
    • M minute (either M or MM)
    • +
    • S second (either S or SS)
    • +
    + +

    Alternatively, if fmt is nil then this returns a flexible date parser + that tries various date/time schemes in turn:

    + +
      +
    • ISO 8601, like 2010-05-10 12:35:23Z or 2008-10-03T14:30+02
    • +
    • times like 15:30 or 8.05pm (assumed to be today's date)
    • +
    • dates like 28/10/02 (European order!) or 5 Feb 2012
    • +
    • month name like march or Mar (case-insensitive, first 3 letters); here the + day will be 1 and the year this current year
    • +
    + +

    A date in format 3 can be optionally followed by a time in format 2. + Please see test-date.lua in the tests folder for more examples. +

  • +
+ + + + +

Usage:

+
    +
    df = Date.Format("yyyy-mm-dd HH:MM:SS")
    +
+ +
+
+ + Date.Format:parse (str) +
+
+ parse a string into a Date object. + + +

Parameters:

+
    +
  • str + string + a date string +
  • +
+ +

Returns:

+
    + + date object +
+ + + + +
+
+ + Date.Format:tostring (d) +
+
+ convert a Date object into a string. + + +

Parameters:

+
    +
  • d + a date object, or a time value as returned by os.time +
  • +
+ +

Returns:

+
    + + string +
+ + + + +
+
+ + Date.Format:US_order (yesno) +
+
+ force US order in dates like 9/11/2001 + + +

Parameters:

+
    +
  • yesno + + + +
  • +
+ + + + + +
+
+

Methods

+ +
+
+ + pl.Date:Date (t, ...) +
+
+ Date constructor. + + +

Parameters:

+
    +
  • t + +

    this can be either

    + +
      +
    • nil or empty - use current date and time
    • +
    • number - seconds since epoch (as returned by os.time). Resulting time is UTC
    • +
    • Date - make a copy of this date
    • +
    • table - table containing year, month, etc as for os.time. You may leave out year, month or day, + in which case current values will be used.
    • +
    • year (will be followed by month, day etc)
    • +
    + + +
  • +
  • ... + true if Universal Coordinated Time, or two to five numbers: month,day,hour,min,sec +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/classes/pl.List.html b/Data/Libraries/Penlight/docs/classes/pl.List.html new file mode 100644 index 0000000..b84209f --- /dev/null +++ b/Data/Libraries/Penlight/docs/classes/pl.List.html @@ -0,0 +1,1443 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class pl.List

+

Python-style list class.

+

Please Note: methods that change the list will return the list. + This is to allow for method chaining, but please note that ls = ls:sort() + does not mean that a new copy of the list is made. In-place (mutable) methods + are marked as returning 'the list' in this documentation.

+ +

See the Guide for further discussion

+ +

See http://www.python.org/doc/current/tut/tut.html, section 5.1

+ +

Note: The comments before some of the functions are from the Python docs + and contain Python code.

+ +

Written for Lua version Nick Trout 4.0; Redone for Lua 5.1, Steve Donovan.

+ +

Dependencies: pl.utils, pl.tablex, pl.class

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
List.new ([t])Create a new list.
List:clone ()Make a copy of an existing list.
List:append (i)Add an item to the end of the list.
List:extend (L)Extend the list by appending all the items in the given list.
List:insert (i, x)Insert an item at a given position.
List:put (x)Insert an item at the begining of the list.
List:remove (i)Remove an element given its index.
List:remove_value (x)Remove the first item from the list whose value is given.
List:pop ([i])Remove the item at the given position in the list, and return it.
List:index (x[, idx=1])Return the index in the list of the first item whose value is given.
List:contains (x)Does this list contain the value?
List:count (x)Return the number of times value appears in the list.
List:sort ([cmp='<'])Sort the items of the list, in place.
List:sorted ([cmp='<'])Return a sorted copy of this list.
List:reverse ()Reverse the elements of the list, in place.
List:minmax ()Return the minimum and the maximum value of the list.
List:slice (first, last)Emulate list slicing.
List:clear ()Empty the list.
List.range (start[, finish[, incr=1]])Emulate Python's range(x) function.
List:len ()list:len() is the same as #list.
List:chop (i1, i2)Remove a subrange of elements.
List:splice (idx, list)Insert a sublist into a list + equivalent to 's[idx:idx] = list' in Python
List:slice_assign (i1, i2, seq)General slice assignment s[i1:i2] = seq.
List:join ([delim=''])Join the elements of a list using a delimiter.
List:concat ([delim=''])Join a list of strings.
List:foreach (fun, ...)Call the function on each element of the list.
List:foreachm (name, ...)Call the named method on each element of the list.
List:filter (fun[, arg])Create a list of all elements which match a function.
List.split (s[, delim])Split a string using a delimiter.
List:map (fun, ...)Apply a function to all elements.
List:transform (fun, ...)Apply a function to all elements, in-place.
List:map2 (fun, ls, ...)Apply a function to elements of two lists.
List:mapm (name, ...)apply a named method to all elements.
List:reduce (fun)'reduce' a list using a binary function.
List:partition (fun, ...)Partition a list using a classifier function.
List:iter ()return an iterator over all values.
List.iterate (seq)Create an iterator over a seqence.
+

metamethods

+ + + + + + + + + + + + + +
List:__concat (L)Concatenation operator.
List:__eq (L)Equality operator ==.
List:__tostring ()How our list should be rendered as a string.
+ +
+
+ + +

Functions

+ +
+
+ + List.new ([t]) +
+
+ Create a new list. Can optionally pass a table; + passing another instance of List will cause a copy to be created; + this will return a plain table with an appropriate metatable. + we pass anything which isn't a simple table to iterate() to work out + an appropriate iterator + + +

Parameters:

+
    +
  • t + An optional list-like table + (optional) +
  • +
+ +

Returns:

+
    + + a new List +
+ + +

See also:

+ + +

Usage:

+
    +
    ls = List();  ls = List {1,2,3,4}
    +
+ +
+
+ + List:clone () +
+
+ Make a copy of an existing list. + The difference from a plain 'copy constructor' is that this returns + the actual List subtype. + + + + + + + +
+
+ + List:append (i) +
+
+ Add an item to the end of the list. + + +

Parameters:

+
    +
  • i + An item +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:extend (L) +
+
+ Extend the list by appending all the items in the given list. + equivalent to 'a[len(a):] = L'. + + +

Parameters:

+
    +
  • L + List + Another List +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:insert (i, x) +
+
+ Insert an item at a given position. i is the index of the + element before which to insert. + + +

Parameters:

+
    +
  • i + int + index of element before whichh to insert +
  • +
  • x + A data item +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:put (x) +
+
+ Insert an item at the begining of the list. + + +

Parameters:

+
    +
  • x + a data item +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:remove (i) +
+
+ Remove an element given its index. + (equivalent of Python's del s[i]) + + +

Parameters:

+
    +
  • i + int + the index +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:remove_value (x) +
+
+ Remove the first item from the list whose value is given. + (This is called 'remove' in Python; renamed to avoid confusion + with table.remove) + Return nil if there is no such item. + + +

Parameters:

+
    +
  • x + A data value +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:pop ([i]) +
+
+ Remove the item at the given position in the list, and return it. + If no index is specified, a:pop() returns the last item in the list. + The item is also removed from the list. + + +

Parameters:

+
    +
  • i + int + An index + (optional) +
  • +
+ +

Returns:

+
    + + the item +
+ + + + +
+
+ + List:index (x[, idx=1]) +
+
+ Return the index in the list of the first item whose value is given. + Return nil if there is no such item. + + +

Parameters:

+
    +
  • x + A data value +
  • +
  • idx + int + where to start search + (default 1) +
  • +
+ +

Returns:

+
    + + the index, or nil if not found. +
+ + + + +
+
+ + List:contains (x) +
+
+ Does this list contain the value? + + +

Parameters:

+
    +
  • x + A data value +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + List:count (x) +
+
+ Return the number of times value appears in the list. + + +

Parameters:

+
    +
  • x + A data value +
  • +
+ +

Returns:

+
    + + number of times x appears +
+ + + + +
+
+ + List:sort ([cmp='<']) +
+
+ Sort the items of the list, in place. + + +

Parameters:

+
    +
  • cmp + func + an optional comparison function + (default '<') +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:sorted ([cmp='<']) +
+
+ Return a sorted copy of this list. + + +

Parameters:

+
    +
  • cmp + func + an optional comparison function + (default '<') +
  • +
+ +

Returns:

+
    + + a new list +
+ + + + +
+
+ + List:reverse () +
+
+ Reverse the elements of the list, in place. + + + +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:minmax () +
+
+ Return the minimum and the maximum value of the list. + + + +

Returns:

+
    +
  1. + minimum value
  2. +
  3. + maximum value
  4. +
+ + + + +
+
+ + List:slice (first, last) +
+
+ Emulate list slicing. like 'list[first:last]' in Python. + If first or last are negative then they are relative to the end of the list + eg. slice(-2) gives last 2 entries in a list, and + slice(-4,-2) gives from -4th to -2nd + + +

Parameters:

+
    +
  • first + An index +
  • +
  • last + An index +
  • +
+ +

Returns:

+
    + + a new List +
+ + + + +
+
+ + List:clear () +
+
+ Empty the list. + + + +

Returns:

+
    + + the list +
+ + + + +
+
+ + List.range (start[, finish[, incr=1]]) +
+
+ Emulate Python's range(x) function. + Include it in List table for tidiness + + +

Parameters:

+
    +
  • start + int + A number +
  • +
  • finish + int + A number greater than start; if absent, + then start is 1 and finish is start + (optional) +
  • +
  • incr + int + an increment (may be less than 1) + (default 1) +
  • +
+ +

Returns:

+
    + + a List from start .. finish +
+ + + +

Usage:

+
    +
  • List.range(0,3) == List{0,1,2,3}
  • +
  • List.range(4) = List{1,2,3,4}
  • +
  • List.range(5,1,-1) == List{5,4,3,2,1}
  • +
+ +
+
+ + List:len () +
+
+ list:len() is the same as #list. + + + + + + + +
+
+ + List:chop (i1, i2) +
+
+ Remove a subrange of elements. + equivalent to 'del s[i1:i2]' in Python. + + +

Parameters:

+
    +
  • i1 + int + start of range +
  • +
  • i2 + int + end of range +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:splice (idx, list) +
+
+ Insert a sublist into a list + equivalent to 's[idx:idx] = list' in Python + + +

Parameters:

+
    +
  • idx + int + index +
  • +
  • list + List + list to insert +
  • +
+ +

Returns:

+
    + + the list +
+ + + +

Usage:

+
    +
    l = List{10,20}; l:splice(2,{21,22});  assert(l == List{10,21,22,20})
    +
+ +
+
+ + List:slice_assign (i1, i2, seq) +
+
+ General slice assignment s[i1:i2] = seq. + + +

Parameters:

+
    +
  • i1 + int + start index +
  • +
  • i2 + int + end index +
  • +
  • seq + List + a list +
  • +
+ +

Returns:

+
    + + the list +
+ + + + +
+
+ + List:join ([delim='']) +
+
+ Join the elements of a list using a delimiter. + This method uses tostring on all elements. + + +

Parameters:

+
    +
  • delim + string + a delimiter string, can be empty. + (default '') +
  • +
+ +

Returns:

+
    + + a string +
+ + + + +
+
+ + List:concat ([delim='']) +
+
+ Join a list of strings.
+ Uses table.concat directly. + + +

Parameters:

+
    +
  • delim + string + a delimiter + (default '') +
  • +
+ +

Returns:

+
    + + a string +
+ + + + +
+
+ + List:foreach (fun, ...) +
+
+ Call the function on each element of the list. + + +

Parameters:

+
    +
  • fun + func + a function or callable object +
  • +
  • ... + optional values to pass to function +
  • +
+ + + + + +
+
+ + List:foreachm (name, ...) +
+
+ Call the named method on each element of the list. + + +

Parameters:

+
    +
  • name + string + the method name +
  • +
  • ... + optional values to pass to function +
  • +
+ + + + + +
+
+ + List:filter (fun[, arg]) +
+
+ Create a list of all elements which match a function. + + +

Parameters:

+
    +
  • fun + func + a boolean function +
  • +
  • arg + optional argument to be passed as second argument of the predicate + (optional) +
  • +
+ +

Returns:

+
    + + a new filtered list. +
+ + + + +
+
+ + List.split (s[, delim]) +
+
+ Split a string using a delimiter. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • delim + string + the delimiter (default spaces) + (optional) +
  • +
+ +

Returns:

+
    + + a List of strings +
+ + +

See also:

+ + + +
+
+ + List:map (fun, ...) +
+
+ Apply a function to all elements. + Any extra arguments will be passed to the function. + + +

Parameters:

+
    +
  • fun + func + a function of at least one argument +
  • +
  • ... + arbitrary extra arguments. +
  • +
+ +

Returns:

+
    + + a new list: {f(x) for x in self} +
+ + +

See also:

+ + +

Usage:

+
    +
    List{'one','two'}:map(string.upper) == {'ONE','TWO'}
    +
+ +
+
+ + List:transform (fun, ...) +
+
+ Apply a function to all elements, in-place. + Any extra arguments are passed to the function. + + +

Parameters:

+
    +
  • fun + func + A function that takes at least one argument +
  • +
  • ... + arbitrary extra arguments. +
  • +
+ +

Returns:

+
    + + the list. +
+ + + + +
+
+ + List:map2 (fun, ls, ...) +
+
+ Apply a function to elements of two lists. + Any extra arguments will be passed to the function + + +

Parameters:

+
    +
  • fun + func + a function of at least two arguments +
  • +
  • ls + List + another list +
  • +
  • ... + arbitrary extra arguments. +
  • +
+ +

Returns:

+
    + + a new list: {f(x,y) for x in self, for x in arg1} +
+ + +

See also:

+ + + +
+
+ + List:mapm (name, ...) +
+
+ apply a named method to all elements. + Any extra arguments will be passed to the method. + + +

Parameters:

+
    +
  • name + string + name of method +
  • +
  • ... + extra arguments +
  • +
+ +

Returns:

+
    + + a new list of the results +
+ + +

See also:

+ + + +
+
+ + List:reduce (fun) +
+
+ 'reduce' a list using a binary function. + + +

Parameters:

+
    +
  • fun + func + a function of two arguments +
  • +
+ +

Returns:

+
    + + result of the function +
+ + +

See also:

+ + + +
+
+ + List:partition (fun, ...) +
+
+ Partition a list using a classifier function. + The function may return nil, but this will be converted to the string key ''. + + +

Parameters:

+
    +
  • fun + func + a function of at least one argument +
  • +
  • ... + will also be passed to the function +
  • +
+ +

Returns:

+
    + + MultiMap + a table where the keys are the returned values, and the values are Lists + of values where the function returned that key. +
+ + +

See also:

+ + + +
+
+ + List:iter () +
+
+ return an iterator over all values. + + + + + + + +
+
+ + List.iterate (seq) +
+
+ Create an iterator over a seqence. + This captures the Python concept of 'sequence'. + For tables, iterates over all values with integer indices. + + +

Parameters:

+
    +
  • seq + a sequence; a string (over characters), a table, a file object (over lines) or an iterator function +
  • +
+ + + + +

Usage:

+
    +
  • for x in iterate {1,10,22,55} do io.write(x,',') end ==> 1,10,22,55
  • +
  • for ch in iterate 'help' do do io.write(ch,' ') end ==> h e l p
  • +
+ +
+
+

metamethods

+ +
+
+ + List:__concat (L) +
+
+ Concatenation operator. + + +

Parameters:

+
    +
  • L + List + another List +
  • +
+ +

Returns:

+
    + + a new list consisting of the list with the elements of the new list appended +
+ + + + +
+
+ + List:__eq (L) +
+
+ Equality operator ==. True iff all elements of two lists are equal. + + +

Parameters:

+
    +
  • L + List + another List +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + List:__tostring () +
+
+ How our list should be rendered as a string. Uses join(). + + + + + +

See also:

+ + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/classes/pl.Map.html b/Data/Libraries/Penlight/docs/classes/pl.Map.html new file mode 100644 index 0000000..72b4b40 --- /dev/null +++ b/Data/Libraries/Penlight/docs/classes/pl.Map.html @@ -0,0 +1,454 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class pl.Map

+

A Map class.

+

+ + + +

+> Map = require 'pl.Map'
+> m = Map{one=1,two=2}
+> m:update {three=3,four=4,two=20}
+> = m == M{one=1,two=20,three=3,four=4}
+true
+
+ +

Dependencies: pl.utils, pl.class, pl.tablex, pl.pretty

+

+ + +

Fields

+ + + + + + + + + +
pl.Map.keyslist of keys.
pl.Map.valueslist of values.
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pl.Map:iter ()return an iterator over all key-value pairs.
pl.Map:items ()return a List of all key-value pairs, sorted by the keys.
pl.Map:setdefault (key, default)set a value in the map if it doesn't exist yet.
pl.Map:len ()size of map.
pl.Map:set (key, val)put a value into the map.
pl.Map:get (key)get a value from the map.
pl.Map:getvalues (keys)get a list of values indexed by a list of keys.
pl.Map:update (table)update the map using key/value pairs from another table.
+

Metamethods

+ + + + + + + + + +
pl.Map:__eq (m)equality between maps.
pl.Map:__tostring ()string representation of a map.
+ +
+
+ + +

Fields

+ +
+
+ + pl.Map.keys +
+
+ list of keys. + + + + + + + +
+
+ + pl.Map.values +
+
+ list of values. + + + + + + + +
+
+

Methods

+ +
+
+ + pl.Map:iter () +
+
+ return an iterator over all key-value pairs. + + + + + + + +
+
+ + pl.Map:items () +
+
+ return a List of all key-value pairs, sorted by the keys. + + + + + + + +
+
+ + pl.Map:setdefault (key, default) +
+
+ set a value in the map if it doesn't exist yet. + + +

Parameters:

+
    +
  • key + the key +
  • +
  • default + value to set +
  • +
+ +

Returns:

+
    + + the value stored in the map (existing value, or the new value) +
+ + + + +
+
+ + pl.Map:len () +
+
+ size of map. + note: this is a relatively expensive operation! + + + + + + + +
+
+ + pl.Map:set (key, val) +
+
+ put a value into the map. + This will remove the key if the value is nil + + +

Parameters:

+
    +
  • key + the key +
  • +
  • val + the value +
  • +
+ + + + + +
+
+ + pl.Map:get (key) +
+
+ get a value from the map. + + +

Parameters:

+
    +
  • key + the key +
  • +
+ +

Returns:

+
    + + the value, or nil if not found. +
+ + + + +
+
+ + pl.Map:getvalues (keys) +
+
+ get a list of values indexed by a list of keys. + + +

Parameters:

+
    +
  • keys + a list-like table of keys +
  • +
+ +

Returns:

+
    + + a new list +
+ + + + +
+
+ + pl.Map:update (table) +
+
+ update the map using key/value pairs from another table. + + +

Parameters:

+
    +
  • table + tab + + + +
  • +
+ + + + + +
+
+

Metamethods

+ +
+
+ + pl.Map:__eq (m) +
+
+ equality between maps. + + +

Parameters:

+
    +
  • m + Map + another map. +
  • +
+ + + + + +
+
+ + pl.Map:__tostring () +
+
+ string representation of a map. + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/classes/pl.MultiMap.html b/Data/Libraries/Penlight/docs/classes/pl.MultiMap.html new file mode 100644 index 0000000..b711b54 --- /dev/null +++ b/Data/Libraries/Penlight/docs/classes/pl.MultiMap.html @@ -0,0 +1,207 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class pl.MultiMap

+

MultiMap, a Map which has multiple values per key.

+

Dependencies: pl.utils, pl.class, pl.List, pl.Map

+ + +

Methods

+ + + + + + + + + +
pl.MultiMap:update (t)update a MultiMap using a table.
pl.MultiMap:set (key, val)add a new value to a key.
+ +
+
+ + +

Methods

+ +
+
+ + pl.MultiMap:update (t) +
+
+ update a MultiMap using a table. + + +

Parameters:

+
    +
  • t + either a Multimap or a map-like table. +
  • +
+ +

Returns:

+
    + + the map +
+ + + + +
+
+ + pl.MultiMap:set (key, val) +
+
+ add a new value to a key. Setting a nil value removes the key. + + +

Parameters:

+
    +
  • key + the key +
  • +
  • val + the value +
  • +
+ +

Returns:

+
    + + the map +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/classes/pl.OrderedMap.html b/Data/Libraries/Penlight/docs/classes/pl.OrderedMap.html new file mode 100644 index 0000000..537af37 --- /dev/null +++ b/Data/Libraries/Penlight/docs/classes/pl.OrderedMap.html @@ -0,0 +1,417 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class pl.OrderedMap

+

OrderedMap, a map which preserves ordering.

+

Derived from pl.Map.

+ +

Dependencies: pl.utils, pl.tablex, pl.class, pl.List, pl.Map

+ + +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pl.OrderedMap:_init (t)construct an OrderedMap.
pl.OrderedMap:update (t)update an OrderedMap using a table.
pl.OrderedMap:set (key, val)set the key's value.
pl.OrderedMap:insert (pos, key, val)insert a key/value pair before a given position.
pl.OrderedMap:keys ()return the keys in order.
pl.OrderedMap:values ()return the values in order.
pl.OrderedMap:sort (cmp)sort the keys.
pl.OrderedMap:iter ()iterate over key-value pairs in order.
+

Metamethods

+ + + + + + + + + +
pl.OrderedMap:__pairs ()iterate over an ordered map (5.2).
pl.OrderedMap:__tostring ()string representation of an ordered map.
+ +
+
+ + +

Methods

+ +
+
+ + pl.OrderedMap:_init (t) +
+
+ construct an OrderedMap. + Will throw an error if the argument is bad. + + +

Parameters:

+ + + + + + +
+
+ + pl.OrderedMap:update (t) +
+
+ update an OrderedMap using a table. + If the table is itself an OrderedMap, then its entries will be appended. + if it s a table of the form {{key1=val1},{key2=val2},...} these will be appended.

+ +

Otherwise, it is assumed to be a map-like table, and order of extra entries is arbitrary. + + +

Parameters:

+
    +
  • t + tab + a table. +
  • +
+ +

Returns:

+
    +
  1. + the map, or nil in case of error
  2. +
  3. + the error message
  4. +
+ + + + +
+
+ + pl.OrderedMap:set (key, val) +
+
+ set the key's value. This key will be appended at the end of the map.

+ +

If the value is nil, then the key is removed. + + +

Parameters:

+
    +
  • key + the key +
  • +
  • val + the value +
  • +
+ +

Returns:

+
    + + the map +
+ + + + +
+
+ + pl.OrderedMap:insert (pos, key, val) +
+
+ insert a key/value pair before a given position. + Note: if the map already contains the key, then this effectively + moves the item to the new position by first removing at the old position. + Has no effect if the key does not exist and val is nil + + +

Parameters:

+
    +
  • pos + int + a position starting at 1 +
  • +
  • key + the key +
  • +
  • val + the value; if nil use the old value +
  • +
+ + + + + +
+
+ + pl.OrderedMap:keys () +
+
+ return the keys in order. + (Not a copy!) + + + +

Returns:

+
    + + List +
+ + + + +
+
+ + pl.OrderedMap:values () +
+
+ return the values in order. + this is relatively expensive. + + + +

Returns:

+
    + + List +
+ + + + +
+
+ + pl.OrderedMap:sort (cmp) +
+
+ sort the keys. + + +

Parameters:

+
    +
  • cmp + func + a comparison function as for table.sort +
  • +
+ +

Returns:

+
    + + the map +
+ + + + +
+
+ + pl.OrderedMap:iter () +
+
+ iterate over key-value pairs in order. + + + + + + + +
+
+

Metamethods

+ +
+
+ + pl.OrderedMap:__pairs () +
+
+ iterate over an ordered map (5.2). + + + + + + + +
+
+ + pl.OrderedMap:__tostring () +
+
+ string representation of an ordered map. + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/classes/pl.Set.html b/Data/Libraries/Penlight/docs/classes/pl.Set.html new file mode 100644 index 0000000..31cfcee --- /dev/null +++ b/Data/Libraries/Penlight/docs/classes/pl.Set.html @@ -0,0 +1,655 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class pl.Set

+

A Set class.

+

+ + + +

+> Set = require 'pl.Set'
+> = Set{'one','two'} == Set{'two','one'}
+true
+> fruit = Set{'apple','banana','orange'}
+> = fruit['banana']
+true
+> = fruit['hazelnut']
+nil
+> colours = Set{'red','orange','green','blue'}
+> = fruit,colours
+[apple,orange,banana]   [blue,green,orange,red]
+> = fruit+colours
+[blue,green,apple,red,orange,banana]
+[orange]
+> more_fruits = fruit + 'apricot'
+> = fruit*colours
+ =  more_fruits, fruit
+banana,apricot,apple,orange]    [banana,apple,orange]
+
+ +

Dependencies: pl.utils, pl.tablex, pl.class, pl.Map, (pl.List if __tostring is used)

+

+ + +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pl.Set:Set (t)create a set.
pl.Set:values (self)get a list of the values in a set.
pl.Set:map (self, fn, ...)map a function over the values of a set.
pl.Set:union (self, set)union of two sets (also +).
pl.Set:intersection (self, set)intersection of two sets (also *).
pl.Set:difference (self, set)new set with elements in the set that are not in the other (also -).
pl.Set:issubset (self, set)is the first set a subset of the second (also <)?.
pl.Set:isempty (self)is the set empty?.
pl.Set:isdisjoint (s1, s2)are the sets disjoint?
pl.Set:len (s)size of this set (also # for 5.2).
+

Metamethods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pl.Set:__tostring ()string representation of a set.
pl.Set:__add ()union of sets.
pl.Set:__mul ()intersection of sets.
pl.Set:__sub ()difference of sets.
pl.Set:__pow ()symmetric difference of sets.
pl.Set:__lt ()first set subset of second?
pl.Set:__len ()cardinality of set (5.2).
pl.Set:__eq (s1, s2)equality between sets.
+ +
+
+ + +

Methods

+ +
+
+ + pl.Set:Set (t) +
+
+ create a set.
+ + +

Parameters:

+
    +
  • t + may be a Set, Map or list-like table. +
  • +
+ + + + + +
+
+ + pl.Set:values (self) +
+
+ get a list of the values in a set. + + +

Parameters:

+
    +
  • self + a Set +
  • +
+ +

Returns:

+
    + + a list +
+ + + + +
+
+ + pl.Set:map (self, fn, ...) +
+
+ map a function over the values of a set. + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • fn + a function +
  • +
  • ... + extra arguments to pass to the function. +
  • +
+ +

Returns:

+
    + + a new set +
+ + + + +
+
+ + pl.Set:union (self, set) +
+
+ union of two sets (also +). + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • set + another set +
  • +
+ +

Returns:

+
    + + a new set +
+ + + + +
+
+ + pl.Set:intersection (self, set) +
+
+ intersection of two sets (also *). + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • set + another set +
  • +
+ +

Returns:

+
    + + a new set +
+ + + +

Usage:

+
    +
    > s = Set{10,20,30}
    +> t = Set{20,30,40}
    +> = t
    +[20,30,40]
    +> = Set.intersection(s,t)
    +[30,20]
    +> = s*t
    +[30,20]
    +
+ +
+
+ + pl.Set:difference (self, set) +
+
+ new set with elements in the set that are not in the other (also -). + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • set + another set +
  • +
+ +

Returns:

+
    + + a new set +
+ + + + +
+
+ + pl.Set:issubset (self, set) +
+
+ is the first set a subset of the second (also <)?. + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • set + another set +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + pl.Set:isempty (self) +
+
+ is the set empty?. + + +

Parameters:

+
    +
  • self + a Set +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + pl.Set:isdisjoint (s1, s2) +
+
+ are the sets disjoint? (no elements in common). + Uses naive definition, i.e. that intersection is empty + + +

Parameters:

+
    +
  • s1 + a Set +
  • +
  • s2 + another set +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + pl.Set:len (s) +
+
+ size of this set (also # for 5.2). + + +

Parameters:

+
    +
  • s + a Set +
  • +
+ +

Returns:

+
    + + size +
+ + + + +
+
+

Metamethods

+ +
+
+ + pl.Set:__tostring () +
+
+ string representation of a set. + + + + + + + +
+
+ + pl.Set:__add () +
+
+ union of sets. + + + + + + + +
+
+ + pl.Set:__mul () +
+
+ intersection of sets. + + + + + + + +
+
+ + pl.Set:__sub () +
+
+ difference of sets. + + + + + + + +
+
+ + pl.Set:__pow () +
+
+ symmetric difference of sets. + + + + + + + +
+
+ + pl.Set:__lt () +
+
+ first set subset of second? + + + + + + + +
+
+ + pl.Set:__len () +
+
+ cardinality of set (5.2). + + + + + + + +
+
+ + pl.Set:__eq (s1, s2) +
+
+ equality between sets. + + +

Parameters:

+
    +
  • s1 + + + +
  • +
  • s2 + + + +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/seesubst.lua.html b/Data/Libraries/Penlight/docs/examples/seesubst.lua.html new file mode 100644 index 0000000..e850122 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/seesubst.lua.html @@ -0,0 +1,174 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

seesubst.lua

+
+-- shows how replacing '@see module' in the Markdown documentation
+-- can be done more elegantly using PL.
+-- We either have something like 'pl.config' (a module reference)
+-- or 'pl.seq.map' (a function reference); these cases must be distinguished
+-- and a Markdown link generated pointing to the LuaDoc file.
+
+local sip = require 'pl.sip'
+local stringx = require 'pl.stringx'
+
+local res = {}
+local s = [[
+(@see pl.bonzo.dog)
+remember about @see pl.bonzo
+
+]]
+
+local _gsub_patterns = {}
+
+local function gsub (s,pat,subst,start)
+    local fpat = _gsub_patterns[pat]
+    if not fpat then
+        -- use SIP to generate a proper string pattern.
+        -- the _whole thing_ is a capture, to get the whole match
+        -- and the unnamed capture.
+        fpat = '('..sip.create_pattern(pat)..')'
+        _gsub_patterns[pat] = fpat
+    end
+    return s:gsub(fpat,subst,start)
+end
+
+
+local mod = sip.compile '$v.$v'
+local fun = sip.compile '$v.$v.$v'
+
+for line in stringx.lines(s) do
+    line = gsub(line,'@see $p',function(see,path)
+        if fun(path,res) or mod(path,res) then
+            local ret = ('[see %s](%s.%s.html'):format(path,res[1],res[2])
+            if res[3] then
+                return ret..'#'..res[3]..')'
+            else
+                return ret..')'
+            end
+        end
+    end)
+    print(line)
+end
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/sipscan.lua.html b/Data/Libraries/Penlight/docs/examples/sipscan.lua.html new file mode 100644 index 0000000..8848423 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/sipscan.lua.html @@ -0,0 +1,161 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

sipscan.lua

+
+-- another SIP example, shows how an awkward log file format
+-- can be parsed. It also prints out the actual Lua string
+-- pattern generated:
+-- SYNC%s*%[([+%-%d]%d*)%]%s*([+%-%d]%d*)%s*([+%-%d]%d*)
+
+local sip = require 'pl.sip'
+local stringx = require 'pl.stringx'
+
+local s = [[
+SYNC [1] 0 547 (14679 sec)
+SYNC [2] 0 555 (14679 sec)
+SYNC [3] 0 563 (14679 sec)
+SYNC [4] 0 571 (14679 sec)
+SYNC [5] -1 580 (14679 sec)
+SYNC [6] 0 587 (14679 sec)
+]]
+
+
+local first = true
+local expected
+local res = {}
+local pat = 'SYNC [$i{seq}] $i{diff} $i{val}'
+print(sip.create_pattern(pat))
+local match = sip.compile(pat)
+for line in stringx.lines(s) do
+  if match(line,res) then
+    if first then
+      expected = res.val
+      first = false
+    end
+    print(res.val,expected - res.val)
+    expected = expected + 8
+  end
+end
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/symbols.lua.html b/Data/Libraries/Penlight/docs/examples/symbols.lua.html new file mode 100644 index 0000000..0dafb21 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/symbols.lua.html @@ -0,0 +1,347 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

symbols.lua

+
+require 'pl'
+utils.import 'pl.func'
+local ops = require 'pl.operator'
+local List = require 'pl.List'
+local append,concat = table.insert,table.concat
+local compare,find_if,compare_no_order,imap,reduce,count_map = tablex.compare,tablex.find_if,tablex.compare_no_order,tablex.imap,tablex.reduce,tablex.count_map
+local unpack = table.unpack
+
+function bindval (self,val)
+    rawset(self,'value',val)
+end
+
+local optable = ops.optable
+
+function sexpr (e)
+	if isPE(e) then
+		if e.op ~= 'X' then
+			local args = tablex.imap(sexpr,e)
+			return '('..e.op..' '..table.concat(args,' ')..')'
+		else
+			return e.repr
+		end
+	else
+		return tostring(e)
+	end
+end
+
+
+psexpr = compose(print,sexpr)
+
+
+
+function equals (e1,e2)
+    local p1,p2 = isPE(e1),isPE(e2)
+    if p1 ~= p2 then return false end  -- different kinds of animals!
+    if p1 and p2 then -- both PEs
+        -- operators must be the same
+        if e1.op ~= e2.op then return false end
+        -- PHs are equal if their representations are equal
+        if e1.op == 'X' then return e1.repr == e2.repr
+        -- commutative operators
+        elseif e1.op == '+' or e1.op == '*' then
+            return compare_no_order(e1,e2,equals)
+        else
+            -- arguments must be the same
+            return compare(e1,e2,equals)
+        end
+    else -- fall back on simple equality for non PEs
+        return e1 == e2
+    end
+end
+
+-- run down an unbalanced operator chain (like a+b+c) and return the arguments {a,b,c}
+function tcollect (op,e,ls)
+    if isPE(e) and e.op == op then
+        for i = 1,#e do
+            tcollect(op,e[i],ls)
+        end
+    else
+        ls:append(e)
+        return
+    end
+end
+
+function rcollect (e)
+    local res = List()
+    tcollect(e.op,e,res)
+    return res
+end
+
+
+-- balance ensures that +/* chains are collected together, operates in-place.
+-- thus (+(+ a b) c) or (+ a (+ b c)) becomes (+ a b c), order immaterial
+function balance (e)
+    if isPE(e) and e.op ~= 'X' then
+        local op,args = e.op
+        if op == '+' or op == '*' then
+            args = rcollect(e)
+        else
+            args = imap(balance,e)
+        end
+        for i = 1,#args do
+            e[i] = args[i]
+        end
+    end
+    return e
+end
+
+-- fold constants in an expression
+function fold (e)
+    if isPE(e) then
+        if e.op == 'X' then
+            -- there could be _bound values_!
+            local val = rawget(e,'value')
+            return val and val or e
+        else
+            local op = e.op
+            local addmul = op == '*' or op == '+'
+            -- first fold all arguments
+            local args = imap(fold,e)
+            if not addmul and not find_if(args,isPE) then
+                -- no placeholders in these args, we can fold the expression.
+                local opfn = optable[op]
+                if opfn then
+                    return opfn(unpack(args))
+                else
+                    return '?'
+                end
+            elseif addmul then
+                -- enforce a few rules for + and *
+                -- split the args into two classes, PE args and non-PE args.
+                local classes = List.partition(args,isPE)
+                local pe,npe = classes[true],classes[false]
+                if npe then -- there's at least one non PE argument
+                    -- so fold them
+                    if #npe == 1 then npe = npe[1]
+                    else npe = npe:reduce(optable[op])
+                    end
+                    -- if the result is a constant, return it
+                    if not pe then return npe end
+
+                    -- either (* 1 x) => x or (* 1 x y ...) => (* x y ...)
+                    if op == '*' then
+                        if npe == 0 then return 0
+                        elseif npe == 1 then -- identity
+                            if #pe == 1 then return pe[1] else npe = nil end
+                        end
+                    else -- special cases for +
+                        if npe == 0 then -- identity
+                            if #pe == 1 then return pe[1] else npe = nil end
+                        end
+                    end
+                end
+                -- build up the final arguments
+                local res = {}
+                if npe then append(res,npe) end
+                for val,count in pairs(count_map(pe,equals)) do
+                    if count > 1 then
+                        if op == '*' then val = val ^ count
+                        else val = val * count
+                        end
+                    end
+                    append(res,val)
+                end
+                if #res == 1 then return res[1] end
+                return PE{op=op,unpack(res)}
+            elseif op == '^' then
+                if args[2] == 1 then return args[1] end -- identity
+                if args[2] == 0 then return 1 end
+            end
+            return PE{op=op,unpack(args)}
+        end
+    else
+        return e
+    end
+end
+
+function expand (e)
+    if isPE(e) and e.op == '*' and isPE(e[2]) and e[2].op == '+' then
+        local a,b = e[1],e[2]
+        return expand(b[1]*a) + expand(b[2]*a)
+    else
+        return e
+    end
+end
+
+function isnumber (x)
+    return type(x) == 'number'
+end
+
+-- does this PE contain a reference to x?
+function references (e,x)
+    if isPE(e) then
+        if e.op == 'X' then return x.repr == e.repr
+        else
+            return find_if(e,references,x)
+        end
+    else
+        return false
+    end
+end
+
+local function muli (args)
+    return PE{op='*',unpack(args)}
+end
+
+local function addi (args)
+    return PE{op='+',unpack(args)}
+end
+
+function diff (e,x)
+    if isPE(e) and references(e,x) then
+        local op = e.op
+        if op == 'X' then
+            return 1
+        else
+            local a,b = e[1],e[2]
+            if op == '+' then -- differentiation is linear
+                local args = imap(diff,e,x)
+                return balance(addi(args))
+            elseif op == '*' then -- product rule
+                local res,d,ee = {}
+                for i = 1,#e do
+                    d = fold(diff(e[i],x))
+                    if d ~= 0 then
+                        ee = {unpack(e)}
+                        ee[i] = d
+                        append(res,balance(muli(ee)))
+                    end
+                end
+                if #res > 1 then return addi(res)
+                else return res[1] end
+            elseif op == '^' and isnumber(b) then -- power rule
+                return b*x^(b-1)
+            end
+        end
+    else
+        return 0
+    end
+end
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/test-cmp.lua.html b/Data/Libraries/Penlight/docs/examples/test-cmp.lua.html new file mode 100644 index 0000000..ac6e44a --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/test-cmp.lua.html @@ -0,0 +1,130 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + + +
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/test-data.lua.html b/Data/Libraries/Penlight/docs/examples/test-data.lua.html new file mode 100644 index 0000000..8128411 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/test-data.lua.html @@ -0,0 +1,372 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

test-data.lua

+
+local data = require 'pl.data'
+local List = require 'pl.List'
+local array = require 'pl.array2d'
+local func = require 'pl.func'
+local seq = require 'pl.seq'
+local stringio = require 'pl.stringio'
+local open = stringio. open
+local asserteq = require 'pl.test' . asserteq
+local T = require 'pl.test'. tuple
+
+--[=[
+dat,err = data.read(open [[
+1.0 0.1
+0.2 1.3
+]])
+
+if err then print(err) end
+
+require 'pl.pretty'.dump(dat)
+os.exit(0)
+--]=]
+
+-- tab-separated data, explicit column names
+local t1f = open [[
+EventID	Magnitude	LocationX	LocationY	LocationZ	LocationError	EventDate	DataFile
+981124001	2.0	18988.4	10047.1	4149.7	33.8	24/11/1998 11:18:05	981124DF.AAB
+981125001	0.8	19104.0	9970.4	5088.7	3.0	25/11/1998 05:44:54	981125DF.AAB
+981127003	0.5	19012.5	9946.9	3831.2	46.0	27/11/1998 17:15:17	981127DF.AAD
+981127005	0.6	18676.4	10606.2	3761.9	4.4	27/11/1998 17:46:36	981127DF.AAF
+981127006	0.2	19109.9	9716.5	3612.0	11.8	27/11/1998 19:29:51	981127DF.AAG
+]]
+
+local t1 = data.read (t1f)
+-- column_by_name returns a List
+asserteq(t1:column_by_name 'Magnitude',List{2,0.8,0.5,0.6,0.2})
+-- can use array.column as well
+asserteq(array.column(t1,2),{2,0.8,0.5,0.6,0.2})
+
+-- only numerical columns (deduced from first data row) are converted by default
+-- can look up indices in the list fieldnames.
+local EDI = t1.fieldnames:index 'EventDate'
+assert(type(t1[1][EDI]) == 'string')
+
+-- select method returns a sequence, in this case single-valued.
+-- (Note that seq.copy returns a List)
+asserteq(seq(t1:select 'LocationX where Magnitude > 0.5'):copy(),List{18988.4,19104,18676.4})
+
+--[[
+--a common select usage pattern:
+for event,mag in t1:select 'EventID,Magnitude sort by Magnitude desc' do
+    print(event,mag)
+end
+--]]
+
+-- space-separated, but with last field containing spaces.
+local t2f = open [[
+USER PID %MEM %CPU COMMAND
+sdonovan 2333  0.3 0.1 background --n=2
+root 2332  0.4  0.2 fred --start=yes
+root 2338  0.2  0.1 backyard-process
+]]
+
+local t2,err = data.read(t2f,{last_field_collect=true})
+if not t2 then return print (err) end
+
+-- the last_field_collect option is useful with space-delimited data where the last
+-- field may contain spaces. Otherwise, a record count mismatch should be an error!
+local lt2 = List(t2[2])
+asserteq(lt2:join ',','root,2332,0.4,0.2,fred --start=yes')
+
+-- fieldnames are converted into valid identifiers by substituting _
+-- (we do this to make select queries parseable by Lua)
+asserteq(t2.fieldnames,List{'USER','PID','_MEM','_CPU','COMMAND'})
+
+-- select queries are NOT SQL so remember to use == ! (and no 'between' operator, sorry)
+--s,err = t2:select('_MEM where USER="root"')
+--assert(err == [[[string "tmp"]:9: unexpected symbol near '=']])
+
+local s = t2:select('_MEM where USER=="root"')
+assert(s() == 0.4)
+assert(s() == 0.2)
+assert(s() == nil)
+
+-- CSV, Excel style. Double-quoted fields are allowed, and they may contain commas!
+local t3f = open [[
+"Department Name","Employee ID",Project,"Hours Booked"
+sales,1231,overhead,4
+sales,1255,overhead,3
+engineering,1501,development,5
+engineering,1501,maintenance,3
+engineering,1433,maintenance,10
+]]
+
+local t3 = data.read(t3f,{csv=true})
+
+-- although fieldnames are turned in valid Lua identifiers, there is always original_fieldnames
+asserteq(t3.fieldnames,List{'Department_Name','Employee_ID','Project','Hours_Booked'})
+asserteq(t3.original_fieldnames,List{'Department Name','Employee ID','Project','Hours Booked'})
+
+-- a common operation is to select using a given list of columns, and each row
+-- on some explicit condition. The select() method can take a table with these
+-- parameters
+local keepcols = {'Employee_ID','Hours_Booked'}
+
+local q = t3:select { fields = keepcols,
+    where = function(row) return row[1]=='engineering' end
+    }
+
+asserteq(seq.copy2(q),{{1501,5},{1501,3},{1433,10}})
+
+-- another pattern is doing a select to restrict rows & columns, process some
+-- fields and write out the modified rows.
+
+local outf = stringio.create()
+
+local names = {[1501]='don',[1433]='dilbert'}
+
+t3:write_row (outf,{'Employee','Hours_Booked'})
+q = t3:select_row {fields=keepcols,where=func.Eq(func._1[1],'engineering')}
+for row in q do
+    row[1] = names[row[1]]
+    t3:write_row(outf,row)
+end
+
+asserteq(outf:value(),
+[[
+Employee,Hours_Booked
+don,5
+don,3
+dilbert,10
+]])
+
+-- data may not always have column headers. When creating a data object
+-- from a two-dimensional array, may specify the fieldnames, as a list or a string.
+-- The delimiter is deduced from the fieldname string, so a string just containing
+-- the delimiter will set it,  and the fieldnames will be empty.
+local dat = List()
+local row = List.range(1,10)
+for i = 1,10 do
+    dat:append(row:map('*',i))
+end
+dat = data.new(dat,',')
+local out = stringio.create()
+dat:write(out,',')
+asserteq(out:value(), [[
+1,2,3,4,5,6,7,8,9,10
+2,4,6,8,10,12,14,16,18,20
+3,6,9,12,15,18,21,24,27,30
+4,8,12,16,20,24,28,32,36,40
+5,10,15,20,25,30,35,40,45,50
+6,12,18,24,30,36,42,48,54,60
+7,14,21,28,35,42,49,56,63,70
+8,16,24,32,40,48,56,64,72,80
+9,18,27,36,45,54,63,72,81,90
+10,20,30,40,50,60,70,80,90,100
+]])
+
+-- you can always use numerical field indices, AWK-style;
+-- note how the copy_select method gives you a data object instead of an
+-- iterator over the fields
+local res = dat:copy_select '$1,$3 where $1 > 5'
+local L = List
+asserteq(L(res),L{
+    L{6, 18},
+    L{7,21},
+    L{8,24},
+    L{9,27},
+    L{10,30},
+})
+
+-- the column_by_name method may take a fieldname or an index
+asserteq(dat:column_by_name(2), L{2,4,6,8,10,12,14,16,18,20})
+
+-- the field list may contain expressions or even constants
+local q = dat:select '$3,2*$4 where $1 == 8'
+asserteq(T(q()),T(24,64))
+
+dat,err = data.read(open [[
+1.0 0.1
+0.2 1.3
+]])
+
+if err then print(err) end
+
+-- if a method cannot be found, then we look up in array2d
+-- array2d.flatten(t) makes a 1D list out of a 2D array,
+-- and then List.minmax() gets the extrema.
+
+asserteq(T(dat:flatten():minmax()),T(0.1,1.3))
+
+local f = open [[
+Time Message
+1266840760 +# EE7C0600006F0D00C00F06010302054000000308010A00002B00407B00
+1266840760 closure data 0.000000 1972 1972 0
+1266840760 ++ 1266840760 EE 1
+1266840760 +# EE7C0600006F0D00C00F06010302054000000408020A00002B00407B00
+1266840764 closure data 0.000000 1972 1972 0
+1266840764 ++ 1266840764 EE 1
+1266840764 +# EE7C0600006F0D00C00F06010302054000000508030A00002B00407B00
+1266840768 duplicate?
+1266840768 +# EE7C0600006F0D00C00F06010302054000000508030A00002B00407B00
+1266840768 closure data 0.000000 1972 1972 0
+]]
+
+-- the convert option provides custom converters for each specified column.
+-- Here we convert the timestamps into Date objects and collect everything
+-- else into one field
+local Date = require 'pl.Date'
+
+local function date_convert (ds)
+    return Date(tonumber(ds))
+end
+
+local d = data.read(f,{convert={[1]=date_convert},last_field_collect=true})
+
+asserteq(#d[1],2)
+asserteq(d[2][1]:year(),2010)
+
+d = {{1,2,3},{10,20,30}}
+out = stringio.create()
+data.write(d,out,{'A','B','C'},',')
+asserteq(out:value(),
+[[
+A,B,C
+1,2,3
+10,20,30
+]])
+
+out = stringio.create()
+d.fieldnames = {'A','B','C'}
+data.write(d,out)
+
+asserteq(out:value(),
+[[
+A	B	C
+1	2	3
+10	20	30
+]])
+
+
+d = data.read(stringio.open 'One,Two\n1,\n,20\n',{csv=true})
+asserteq(d,{
+    {1,0},{0,20},
+    original_fieldnames={"One","Two"},fieldnames={"One","Two"},delim=","
+})
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/test-listcallbacks.lua.html b/Data/Libraries/Penlight/docs/examples/test-listcallbacks.lua.html new file mode 100644 index 0000000..4416532 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/test-listcallbacks.lua.html @@ -0,0 +1,138 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

test-listcallbacks.lua

+
+-- demonstrates how to use a list of callbacks
+local List = require 'pl.List'
+local utils = require 'pl.utils'
+local actions = List()
+local L = utils.string_lambda
+
+actions:append(function() print 'hello' end)
+actions:append(L '|| print "yay"')
+
+-- '()' is a shortcut for operator.call or function(x) return x() end
+actions:foreach '()'
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/test-pretty.lua.html b/Data/Libraries/Penlight/docs/examples/test-pretty.lua.html new file mode 100644 index 0000000..a7493f3 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/test-pretty.lua.html @@ -0,0 +1,140 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

test-pretty.lua

+
+local pretty = require 'pl.pretty'
+
+local tb = {
+    'one','two','three',{1,2,3},
+    alpha=1,beta=2,gamma=3,['&']=true,[0]=false,
+    _fred = {true,true},
+    s = [[
+hello dolly
+you're so fine
+]]
+}
+
+print(pretty.write(tb))
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/test-symbols.lua.html b/Data/Libraries/Penlight/docs/examples/test-symbols.lua.html new file mode 100644 index 0000000..a847ab9 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/test-symbols.lua.html @@ -0,0 +1,209 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

test-symbols.lua

+
+require 'pl'
+-- force us to look in the script's directory when requiring...
+app.require_here()
+require 'symbols'
+
+local MT = getmetatable(_1)
+
+add = MT.__add
+mul = MT.__mul
+pow = MT.__pow
+
+
+function testeq (e1,e2)
+    if not equals(e1,e2) then
+        print ('Not equal',repr(e1),repr(e2))
+    end
+end
+
+sin = register(math.sin,'sin')
+
+f = register(function(x,y,z) end)
+
+--[[
+testeq (_1,_1)
+testeq (_1+_2,_1+_2)
+testeq (_1 + 3*_2,_1 + 3*_2)
+testeq (_2+_1,_1+_2)
+testeq (sin(_1),sin(_1))
+testeq (1+f(10,20,'ok'),f(10,20,'ok')+1)
+--]]
+
+
+function testexpand (e)
+    print(repr(fold(expand(e)))) --fold
+end
+
+--[[
+testexpand (a*(a+1))
+
+testexpand ((x+2)*(b+1))
+]]--
+
+function testfold (e)
+    print(repr(fold(e)))
+end
+
+a,b,c,x,y = Var 'a,b,c,x,y'
+
+--~ testfold(_1 + _2)
+--~ testfold(add(10,20))
+--~ testfold(add(mul(2,_1),mul(3,_2)))
+--[[
+testfold(sin(a))
+e = a^(b+2)
+testfold(e)
+bindval(b,1)
+testfold(e)
+bindval(a,2)
+testfold(e)
+
+bindval(a)
+bindval(b)
+]]
+
+
+
+function testdiff (e)
+    balance(e)
+    e = diff(e,x)
+    balance(e)
+    print('+ ',e)
+    e = fold(e)
+    print('- ',e)
+end
+
+
+testdiff(x^2+1)
+testdiff(3*x^2)
+testdiff(x^2 + 2*x^3)
+testdiff(x^2 + 2*a*x^3 + x^4)
+testdiff(2*a*x^3)
+testdiff(x*x*x)
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/testapp.lua.html b/Data/Libraries/Penlight/docs/examples/testapp.lua.html new file mode 100644 index 0000000..56ae5a3 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/testapp.lua.html @@ -0,0 +1,133 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

testapp.lua

+
+-- shows how a script can get a private file path
+-- the output on my Windows machine is:
+-- C:\Documents and Settings\steve\.testapp\test.txt
+local app = require 'pl.app'
+print(app.appfile 'test.txt')
+ + +
+
+
+generated by LDoc 1.4.6 +Last updated 2018-11-23 21:07:42 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/testclone.lua.html b/Data/Libraries/Penlight/docs/examples/testclone.lua.html new file mode 100644 index 0000000..1e48839 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/testclone.lua.html @@ -0,0 +1,165 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

testclone.lua

+
+--cloning a directory tree.
+local lfs = require 'lfs'
+local path = require 'pl.path'
+local dir = require 'pl.dir'
+
+local p1 = [[examples]]
+local p2 = [[copy/of/examples]]
+
+if not path.isfile 'examples/testclone.lua' then
+	return print 'please run this in the penlight folder (below examples)'
+end
+
+-- make a copy of the examples folder
+dir.clonetree(p1,p2,dir.copyfile)
+
+assert(path.isdir 'copy')
+
+print '---'
+local t = os.time()
+print(lfs.touch('examples/testclone.lua',t,t+10))
+
+-- this should only update this file
+dir.clonetree(p1,p2,
+function(f1,f2)
+  local t1 = path.getmtime(f1)
+  local t2 = path.getmtime(f2)
+  --print(f1,t1,f2,t2)
+  if t1 > t2 then
+	dir.copyfile(f1,f2)
+	print(f1,f2,t1,t2)
+  end
+  return true
+end)
+
+-- and get rid of the whole copy directory, with subdirs
+dir.rmtree 'copy'
+
+assert(not path.exists 'copy')
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/testconfig.lua.html b/Data/Libraries/Penlight/docs/examples/testconfig.lua.html new file mode 100644 index 0000000..4ba947f --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/testconfig.lua.html @@ -0,0 +1,176 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

testconfig.lua

+
+local stringio = require 'pl.stringio'
+local config = require 'pl.config'
+
+local function dump(t,indent)
+    if type(t) == 'table' then
+        io.write(indent,'{\n')
+        local newindent = indent..'  '
+        for k,v in pairs(t) do
+            io.write(newindent,k,'=')
+            dump(v,indent)
+            io.write('\n')
+        end
+        io.write(newindent,'},\n')
+    else
+        io.write(indent,t,'(',type(t),')')
+    end
+end
+
+
+local function testconfig(test)
+    local f = stringio.open(test)
+    local c = config.read(f)
+    f:close()
+    dump(c,'  ')
+    print '-----'
+end
+
+testconfig [[
+ ; comment 2 (an ini file)
+[section!]
+bonzo.dog=20,30
+config_parm=here we go again
+depth = 2
+[another]
+felix="cat"
+]]
+
+testconfig [[
+# this is a more Unix-y config file
+fred = 1
+alice = 2
+home = /bonzo/dog/etc
+]]
+
+testconfig [[
+# this is just a set of comma-separated values
+1000,444,222
+44,555,224
+]]
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/testglobal.lua.html b/Data/Libraries/Penlight/docs/examples/testglobal.lua.html new file mode 100644 index 0000000..e05a1f8 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/testglobal.lua.html @@ -0,0 +1,153 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

testglobal.lua

+
+-- very simple lexer program which looks at all identifiers in a Lua
+-- file and checks whether they're in the global namespace.
+-- At the end, we dump out the result of count_map, which will give us
+-- unique identifiers with their usage count.
+-- (an example of a program which itself needs to be careful about what
+-- goes into the global namespace)
+
+local utils = require 'pl.utils'
+local file = require 'pl.file'
+local lexer = require 'pl.lexer'
+local List = require 'pl.List'
+local pretty = require 'pl.pretty'
+local seq = require 'pl.seq'
+local path = require 'pl.path'
+
+utils.on_error 'quit'
+
+local txt = file.read(arg[1] or path.normpath('examples/testglobal.lua'))
+local globals = List()
+for t,v in lexer.lua(txt) do
+	if t == 'iden' and rawget(_G,v) then
+		globals:append(v)
+	end
+end
+
+pretty.dump(seq.count_map(globals))
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/testinputfields.lua.html b/Data/Libraries/Penlight/docs/examples/testinputfields.lua.html new file mode 100644 index 0000000..0fa63e4 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/testinputfields.lua.html @@ -0,0 +1,140 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

testinputfields.lua

+
+local input = require 'pl.input'
+local sum = 0.0
+local count = 0
+local text = [[
+    981124001	2.0	18988.4	10047.1	4149.7
+    981125001	0.8	19104.0	9970.4	5088.7
+    981127003	0.5	19012.5	9946.9	3831.2
+]]
+for id,magn,x in input.fields(3,' ',text) do
+  sum = sum + x
+  count = count + 1
+end
+print('average x coord is ',sum/count)
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/testinputfields2.lua.html b/Data/Libraries/Penlight/docs/examples/testinputfields2.lua.html new file mode 100644 index 0000000..51a5acf --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/testinputfields2.lua.html @@ -0,0 +1,136 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

testinputfields2.lua

+
+local input = require 'pl.input'
+local seq = require 'pl.seq'
+local text = [[
+    981124001	2.0	18988.4	10047.1	4149.7
+    981125001	0.8	19104.0	9970.4	5088.7
+    981127003	0.5	19012.5	9946.9	3831.2
+]]
+local sum,count = seq.sum(input.fields ({3},' ',text))
+print(sum/count)
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/testxml.lua.html b/Data/Libraries/Penlight/docs/examples/testxml.lua.html new file mode 100644 index 0000000..c01fe3b --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/testxml.lua.html @@ -0,0 +1,209 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

testxml.lua

+
+-- an example showing 'pl.lexer' doing some serious work.
+-- The resulting Lua table is in the same LOM format used by luaexpat.
+-- This is (clearly) not a professional XML parser, so don't use it
+-- on your homework!
+
+local lexer = require 'pl.lexer'
+local pretty = require 'pl.pretty'
+
+local append = table.insert
+local skipws,expecting = lexer.skipws,lexer.expecting
+
+local function parse_element (tok,tag)
+	local tbl,t,v,attrib
+	tbl = {}
+	tbl.tag = tag  -- LOM 'tag' is the element tag
+	t,v = skipws(tok)
+	while v ~= '/' and v ~= '>' do
+		if t ~= 'iden' then error('expecting attribute identifier') end
+		attrib = v
+		expecting(tok,'=')
+		v = expecting(tok,'string')
+		-- LOM: 'attr' subtable contains attrib/value pairs and an ordered list of attribs
+		if not tbl.attr then tbl.attr = {} end
+		tbl.attr[attrib] = v
+		append(tbl.attr,attrib)
+		t,v = skipws(tok)
+	end
+	if v == '/' then
+		expecting(tok,'>')
+		return tbl
+	end
+	-- pick up element data
+	t,v = tok()
+	while true do
+		if t == '<' then
+			t,v = skipws(tok)
+			if t == '/' then -- element end tag
+				t,v = tok()
+				if t == '>' then return tbl end
+				if t == 'iden' and v == tag then
+					if tok() == '>' then return tbl end
+				end
+				error('expecting end tag '..tag)
+			else
+				append(tbl,parse_element(tok,v)) -- LOM: child elements added to table
+				t,v = skipws(tok)
+			end
+		else
+			append(tbl,v) -- LOM: text added to table
+			t,v = skipws(tok)
+		end
+	end
+end
+
+local function parse_xml (tok)
+	local t = skipws(tok)
+	local v
+	while t == '<' do
+		t,v = tok()
+		if t == '?' or t == '!' then
+			-- skip meta stuff and commentary
+			repeat t = tok() until t == '>'
+			t = expecting(tok,'<')
+		else
+			return parse_element(tok,v)
+		end
+	end
+end
+
+local s = [[
+<?xml version="1.0" encoding="UTF-8"?>
+<sensor name="closure-meter-2" id="7D7D0600006F0D00" loc="100,100,0" device="closure-meter" init="true">
+<detector name="closure-meter" phenomenon="closure" units="mm" id="1"
+    vmin="0" vmax="5000" device="closure-meter" calib="0,0;5000,5000"
+    sampling_interval="25000" measurement_interval="600000"
+/>
+</sensor>
+]]
+
+local tok = lexer.scan(s,nil,{space=false},{string=true})
+local res = parse_xml(tok)
+print(pretty.write(res))
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/examples/which.lua.html b/Data/Libraries/Penlight/docs/examples/which.lua.html new file mode 100644 index 0000000..d5e8961 --- /dev/null +++ b/Data/Libraries/Penlight/docs/examples/which.lua.html @@ -0,0 +1,155 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

which.lua

+
+-- a simple implementation of the which command. This looks for
+-- the given file on the path. On windows, it will assume an extension
+-- of .exe if no extension is given.
+local List = require 'pl.List'
+local path = require 'pl.path'
+local app = require 'pl.app'
+
+local pathl = List.split(os.getenv 'PATH',path.dirsep)
+
+local function which (file)
+    local res = pathl:map(path.join,file)
+    res = res:filter(path.exists)
+    if res then return res[1] end
+end
+
+local _,lua = app.lua()
+local file = arg[1] or lua -- i.e. location of lua executable
+local try
+
+if not file then return print 'must provide a filename' end
+
+if path.extension(file) == '' and path.is_windows then
+    try = which(file..'.exe')
+else
+    try = which(file)
+end
+
+if try then print(try) else print 'cannot find on path' end
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/index.html b/Data/Libraries/Penlight/docs/index.html new file mode 100644 index 0000000..b7e9465 --- /dev/null +++ b/Data/Libraries/Penlight/docs/index.html @@ -0,0 +1,392 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Penlight Lua Libraries 1.11.0

+

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 introduction.

+ +

Libraries

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
plEntry point for loading all PL libraries only on demand, into the global space.
pl.appApplication support functions.
pl.array2dOperations on two-dimensional arrays.
pl.classProvides a reuseable and convenient framework for creating classes in Lua.
pl.compatLua 5.1/5.2/5.3 compatibility.
pl.comprehensionList comprehensions implemented in Lua.
pl.configReads configuration files into a Lua table.
pl.dataReading and querying simple tabular data.
pl.dirListing files in directories and creating/removing directory paths.
pl.fileFile manipulation functions: reading, writing, moving and copying.
pl.funcFunctional helpers like composition, binding and placeholder expressions.
pl.import_intoPL loader, for loading all PL libraries, only on demand.
pl.inputIterators for extracting words or numbers from an input source.
pl.lappSimple command-line parsing using human-readable specification.
pl.lexerLexical scanner for creating a sequence of tokens from text.
pl.luabalancedExtract delimited Lua sequences from strings.
pl.operatorLua operators available as functions.
pl.pathPath manipulation and file queries.
pl.permutePermutation operations.
pl.prettyPretty-printing Lua tables.
pl.seqManipulating iterators as sequences.
pl.sipSimple Input Patterns (SIP).
pl.strictChecks uses of undeclared global variables.
pl.stringioReading and writing strings using file-like objects.
pl.stringxPython-style extended string library.
pl.tablexExtended operations on Lua tables.
pl.templateA template preprocessor.
pl.testUseful test utilities.
pl.textText processing utilities.
pl.typesDealing with Detailed Type Information
pl.urlPython-style URL quoting library.
pl.utilsGenerally useful routines.
pl.xmlXML LOM Utilities.
+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + +
pl.DateDate and Date Format classes.
pl.ListPython-style list class.
pl.MapA Map class.
pl.MultiMapMultiMap, a Map which has multiple values per key.
pl.OrderedMapOrderedMap, a map which preserves ordering.
pl.SetA Set class.
+

Manual

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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-data.lua
test-listcallbacks.lua
test-pretty.lua
test-symbols.lua
testclone.lua
testconfig.lua
testglobal.lua
testinputfields.lua
testinputfields2.lua
testxml.lua
which.lua
+ +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/ldoc_fixed.css b/Data/Libraries/Penlight/docs/ldoc_fixed.css new file mode 100644 index 0000000..9b0fc00 --- /dev/null +++ b/Data/Libraries/Penlight/docs/ldoc_fixed.css @@ -0,0 +1,311 @@ +/* BEGIN RESET + +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +html { + color: #000; + background: #FFF; +} +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { + margin: 0; + padding: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +fieldset,img { + border: 0; +} +address,caption,cite,code,dfn,em,strong,th,var,optgroup { + font-style: inherit; + font-weight: inherit; +} +del,ins { + text-decoration: none; +} +li { + margin-left: 20px; +} +caption,th { + text-align: left; +} +h1,h2,h3,h4,h5,h6 { + font-size: 100%; + font-weight: bold; +} +q:before,q:after { + content: ''; +} +abbr,acronym { + border: 0; + font-variant: normal; +} +sup { + vertical-align: baseline; +} +sub { + vertical-align: baseline; +} +legend { + color: #000; +} +input,button,textarea,select,optgroup,option { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; +} +input,button,textarea,select {*font-size:100%; +} +/* END RESET */ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; font-size: 1.1em; } +span.parameter { font-family:monospace; } +span.parameter:after { content:":"; } +span.types:before { content:"("; } +span.types:after { content:")"; } +.type { font-weight: bold; font-style:italic } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 0px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 0 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; +} + +pre { + background-color: rgb(245, 245, 245); + border: 1px solid #C0C0C0; /* silver */ + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: "Andale Mono", monospace; +} + +pre.example { + font-size: .85em; +} + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #ffffff; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color:#FFFFFF; // #f0f0f0; + border-left: 1px solid #cccccc; +} + +#navigation { + position: fixed; + top: 0; + left: 0; + float: left; + width: 14em; + vertical-align: top; + background-color:#FFFFFF; // #f0f0f0; + border-right: 2px solid #cccccc; + overflow: visible; + overflow-y: scroll; + height: 100%; + padding-left: 1em; +} + +#navigation h2 { + background-color:#FFFFFF;//:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; + padding: 1em; + padding-left: 2em; + width: 700px; + border-left: 2px solid #cccccc; + // border-right: 2px solid #cccccc; + background-color: #ffffff; +} + +#about { + clear: both; + padding-left: 1em; + margin-left: 14em; // avoid the damn sidebar! + border-top: 2px solid #cccccc; + border-left: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f0f0f0; ; min-width: 200px; } +table.module_list td.summary { width: 100%; } + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f6f6ff; ; min-width: 200px; } +table.function_list td.summary { width: 100%; } + +dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + +ul.nowrap { + overflow:auto; + whitespace:nowrap; +} + +/* stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* make the target distinct; helps when we're navigating to a function */ +a:target + * { + background-color: #FF9; +} + + +/* styles for prettification of source */ +pre .comment { color: #558817; } +pre .constant { color: #a8660d; } +pre .escape { color: #844631; } +pre .keyword { color: #aa5050; font-weight: bold; } +pre .library { color: #0e7c6b; } +pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; } +pre .string { color: #8080ff; } +pre .number { color: #f8660d; } +pre .operator { color: #2239a8; font-weight: bold; } +pre .preprocessor, pre .prepro { color: #a33243; } +pre .global { color: #800080; } +pre .user-keyword { color: #800080; } +pre .prompt { color: #558817; } +pre .url { color: #272fc2; text-decoration: underline; } + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.Set.html b/Data/Libraries/Penlight/docs/libraries/pl.Set.html new file mode 100644 index 0000000..8eda41e --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.Set.html @@ -0,0 +1,650 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.Set

+

A Set class.

+

+ +

+> Set = require 'pl.Set'
+> = Set{'one','two'} == Set{'two','one'}
+true
+> fruit = Set{'apple','banana','orange'}
+> = fruit['banana']
+true
+> = fruit['hazelnut']
+nil
+> colours = Set{'red','orange','green','blue'}
+> = fruit,colours
+[apple,orange,banana]   [blue,green,orange,red]
+> = fruit+colours
+[blue,green,apple,red,orange,banana]
+[orange]
+> more_fruits = fruit + 'apricot'
+> = fruit*colours
+ =  more_fruits, fruit
+banana,apricot,apple,orange]    [banana,apple,orange]
+
+ + +

Dependencies: pl.utils, pl.tablex, pl.class, pl.Map, (pl.List if __tostring is used)

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Set (t)create a set.
values (self)get a list of the values in a set.
map (self, fn, ...)map a function over the values of a set.
union (self, set)union of two sets (also +).
intersection (self, set)intersection of two sets (also *).
difference (self, set)new set with elements in the set that are not in the other (also -).
issubset (self, set)is the first set a subset of the second (also <)?.
isempty (self)is the set empty?.
isdisjoint (s1, s2)are the sets disjoint?
len (s)size of this set (also # for 5.2).
+

metamethods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
__tostring ()string representation of a set.
__add ()union of sets.
__mul ()intersection of sets.
__sub ()difference of sets.
__pow ()symmetric difference of sets.
__lt ()first set subset of second?
__len ()cardinality of set (5.2).
__eq (s1, s2)equality between sets.
+ +
+
+ + +

Functions

+ +
+
+ + Set (t) +
+
+ create a set.
+ + +

Parameters:

+
    +
  • t + may be a Set, Map or list-like table. +
  • +
+ + + + + +
+
+ + values (self) +
+
+ get a list of the values in a set. + + +

Parameters:

+
    +
  • self + a Set +
  • +
+ +

Returns:

+
    + + a list +
+ + + + +
+
+ + map (self, fn, ...) +
+
+ map a function over the values of a set. + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • fn + a function +
  • +
  • ... + extra arguments to pass to the function. +
  • +
+ +

Returns:

+
    + + a new set +
+ + + + +
+
+ + union (self, set) +
+
+ union of two sets (also +). + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • set + another set +
  • +
+ +

Returns:

+
    + + a new set +
+ + + + +
+
+ + intersection (self, set) +
+
+ intersection of two sets (also *). + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • set + another set +
  • +
+ +

Returns:

+
    + + a new set +
+ + + +

Usage:

+
    +
    > s = Set{10,20,30}
    +> t = Set{20,30,40}
    +> = t
    +[20,30,40]
    +> = Set.intersection(s,t)
    +[30,20]
    +> = s*t
    +[30,20]
    +
+ +
+
+ + difference (self, set) +
+
+ new set with elements in the set that are not in the other (also -). + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • set + another set +
  • +
+ +

Returns:

+
    + + a new set +
+ + + + +
+
+ + issubset (self, set) +
+
+ is the first set a subset of the second (also <)?. + + +

Parameters:

+
    +
  • self + a Set +
  • +
  • set + another set +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + isempty (self) +
+
+ is the set empty?. + + +

Parameters:

+
    +
  • self + a Set +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + isdisjoint (s1, s2) +
+
+ are the sets disjoint? (no elements in common). + Uses naive definition, i.e. that intersection is empty + + +

Parameters:

+
    +
  • s1 + a Set +
  • +
  • s2 + another set +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + len (s) +
+
+ size of this set (also # for 5.2). + + +

Parameters:

+
    +
  • s + a Set +
  • +
+ +

Returns:

+
    + + size +
+ + + + +
+
+

metamethods

+ +
+
+ + __tostring () +
+
+ string representation of a set. + + + + + + + +
+
+ + __add () +
+
+ union of sets. + + + + + + + +
+
+ + __mul () +
+
+ intersection of sets. + + + + + + + +
+
+ + __sub () +
+
+ difference of sets. + + + + + + + +
+
+ + __pow () +
+
+ symmetric difference of sets. + + + + + + + +
+
+ + __lt () +
+
+ first set subset of second? + + + + + + + +
+
+ + __len () +
+
+ cardinality of set (5.2). + + + + + + + +
+
+ + __eq (s1, s2) +
+
+ equality between sets. + + +

Parameters:

+
    +
  • s1 + +
  • +
  • s2 + +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +Last updated 2018-11-23 21:07:42 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.app.html b/Data/Libraries/Penlight/docs/libraries/pl.app.html new file mode 100644 index 0000000..4417e8f --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.app.html @@ -0,0 +1,397 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.app

+

Application support functions.

+

See the Guide

+ +

Dependencies: pl.utils, pl.path

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + +
script_name ()return the name of the current script running.
require_here (base)prefixes the current script's path to the Lua module path.
appfile (file)return a suitable path for files private to this application.
platform ()return string indicating operating system.
lua ()return the full command-line used to invoke this script.
parse_args (args, flags_with_values, flags_valid)parse command-line arguments into flags and parameters.
+ +
+
+ + +

Functions

+ +
+
+ + script_name () +
+
+ return the name of the current script running. + The name will be the name as passed on the command line + + + +

Returns:

+
    + + string filename +
+ + + + +
+
+ + require_here (base) +
+
+ prefixes the current script's path to the Lua module path. + Applies to both the source and the binary module paths. It makes it easy for + the main file of a multi-file program to access its modules in the same directory. + base allows these modules to be put in a specified subdirectory, to allow for + cleaner deployment and resolve potential conflicts between a script name and its + library directory.

+ +

Note: the path is prefixed, so it is searched first when requiring modules. + + +

Parameters:

+
    +
  • base + string + optional base directory (absolute, or relative path). +
  • +
+ +

Returns:

+
    + + string + the current script's path with a trailing slash +
+ + + + +
+
+ + appfile (file) +
+
+ return a suitable path for files private to this application. + These will look like '~/.SNAME/file', with '~' as with expanduser and + SNAME is the name of the script without .lua extension. + If the directory does not exist, it will be created. + + +

Parameters:

+
    +
  • file + string + a filename (w/out path) +
  • +
+ +

Returns:

+
    +
  1. + a full pathname, or nil
  2. +
  3. + cannot create directory error
  4. +
+ + + +

Usage:

+
    +
    -- when run from a script called 'testapp' (on Windows):
    +local app = require 'pl.app'
    +print(app.appfile 'test.txt')
    +-- C:\Documents and Settings\steve\.testapp\test.txt
    +
+ +
+
+ + platform () +
+
+ return string indicating operating system. + + + +

Returns:

+
    + + 'Windows','OSX' or whatever uname returns (e.g. 'Linux') +
+ + + + +
+
+ + lua () +
+
+ return the full command-line used to invoke this script. + It will not include the scriptname itself, see app.script_name. + + + +

Returns:

+
    +
  1. + command-line
  2. +
  3. + name of Lua program used
  4. +
+ + + +

Usage:

+
    +
    -- execute:  lua -lluacov -e 'print(_VERSION)' myscript.lua
    +
    +-- myscript.lua
    +print(require("pl.app").lua())  --> "lua -lluacov -e 'print(_VERSION)'", "lua"
    +
+ +
+
+ + parse_args (args, flags_with_values, flags_valid) +
+
+ parse command-line arguments into flags and parameters. + Understands GNU-style command-line flags; short (-f) and long (--flag).

+ +

These may be given a value with either '=' or ':' (-k:2,--alpha=3.2,-n2), + a number value can be given without a space. If the flag is marked + as having a value, then a space-separated value is also accepted (-i hello), + see the flags_with_values argument).

+ +

Multiple short args can be combined like so: ( -abcd).

+ +

When specifying the flags_valid parameter, its contents can also contain + aliasses, to convert short/long flags to the same output name. See the + example below.

+ +

Note: if a flag is repeated, the last value wins. + + +

Parameters:

+
    +
  • args + {string} + an array of strings (default is the global arg) +
  • +
  • flags_with_values + tab + any flags that take values, either list or hash + table e.g. { out=true } or { "out" }. +
  • +
  • flags_valid + tab + (optional) flags that are valid, either list or hashtable. + If not given, everything + will be accepted(everything in flags_with_values will automatically be allowed) +
  • +
+ +

Returns:

+
    +
  1. + a table of flags (flag=value pairs)
  2. +
  3. + an array of parameters
  4. +
+ +

Raises:

+ if args is nil, then the global args must be available! + + +

Usage:

+
    +
    -- Simple form:
    +local flags, params = app.parse_args(nil,
    +     { "hello", "world" },  -- list of flags taking values
    +     { "l", "a", "b"})      -- list of allowed flags (value ones will be added)
    +
    +-- More complex example using aliasses:
    +local valid = {
    +    long = "l",           -- if 'l' is specified, it is reported as 'long'
    +    new = { "n", "old" }, -- here both 'n' and 'old' will go into 'new'
    +}
    +local values = {
    +    "value",   -- will automatically be added to the allowed set of flags
    +    "new",     -- will mark 'n' and 'old' as requiring a value as well
    +}
    +local flags, params = app.parse_args(nil, values, valid)
    +
    +-- command:  myapp.lua -l --old:hello --value world param1 param2
    +-- will yield:
    +flags = {
    +    long = true,     -- input from 'l'
    +    new = "hello",   -- input from 'old'
    +    value = "world", -- allowed because it was in 'values', note: space separated!
    +}
    +params = {
    +    [1] = "param1"
    +    [2] = "param2"
    +}
    +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.array2d.html b/Data/Libraries/Penlight/docs/libraries/pl.array2d.html new file mode 100644 index 0000000..8ee905b --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.array2d.html @@ -0,0 +1,1319 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.array2d

+

Operations on two-dimensional arrays.

+

See The Guide

+ +

The size of the arrays is determined by using the length operator # hence + the module is not nil safe, and the usual precautions apply.

+ +

Note: all functions taking i1,j1,i2,j2 as arguments will normalize the + arguments using default_range.

+ +

Dependencies: pl.utils, pl.tablex, pl.types

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
size (a)return the row and column size.
column (a, j)extract a column from the 2D array.
row (a, i)extract a row from the 2D array.
map (f, a, arg)map a function over a 2D array
reduce_rows (f, a)reduce the rows using a function.
reduce_cols (f, a)reduce the columns using a function.
reduce2 (opc, opr, a)reduce a 2D array into a scalar, using two operations.
map2 (f, ad, bd, a, b, arg)map a function over two arrays.
product (f, t1, t2)cartesian product of two 1d arrays.
flatten (t)flatten a 2D array.
reshape (t, nrows, co)reshape a 2D array.
transpose (t)transpose a 2D array.
swap_rows (t, i1, i2)swap two rows of an array.
swap_cols (t, j1, j2)swap two columns of an array.
extract_rows (t, ridx)extract the specified rows.
extract_cols (t, cidx)extract the specified columns.
remove_row (t, i)remove a row from an array.
remove_col (t, j)remove a column from an array.
parse_range (s)parse a spreadsheet range.
range (t, rstr)get a slice of a 2D array using spreadsheet range notation.
default_range (t, i1, j1, i2, j2)normalizes coordinates to valid positive entries and defaults.
slice (t, i1, j1, i2, j2)get a slice of a 2D array.
set (t, value, i1, j1, i2, j2)set a specified range of an array to a value.
write (t, f, fmt, i1, j1, i2, j2)write a 2D array to a file.
forall (t, row_op, end_row_op, i1, j1, i2, j2)perform an operation for all values in a 2D array.
move (dest, di, dj, src, i1, j1, i2, j2)move a block from the destination to the source.
iter (a, indices, i1, j1, i2, j2)iterate over all elements in a 2D array, with optional indices.
columns (a)iterate over all columns.
rows (a)iterate over all rows.
new (rows, cols, val)new array of specified dimensions
+ +
+
+ + +

Functions

+ +
+
+ + size (a) +
+
+ return the row and column size. + Size is calculated using the Lua length operator #, so usual precautions + regarding nil values apply. + + +

Parameters:

+
    +
  • a + array + a 2d array +
  • +
+ +

Returns:

+
    +
  1. + int + number of rows (#a)
  2. +
  3. + int + number of cols (#a[1])
  4. +
+ + + + +
+
+ + column (a, j) +
+
+ extract a column from the 2D array. + + +

Parameters:

+
    +
  • a + array + 2d array +
  • +
  • j + column index +
  • +
+ +

Returns:

+
    + + 1d array +
+ + + + +
+
+ + row (a, i) +
+
+ extract a row from the 2D array. + Added in line with column, for read-only purposes directly + accessing a[i] is more performant. + + +

Parameters:

+
    +
  • a + array + 2d array +
  • +
  • i + row index +
  • +
+ +

Returns:

+
    + + 1d array (copy of the row) +
+ + + + +
+
+ + map (f, a, arg) +
+
+ map a function over a 2D array + + +

Parameters:

+
    +
  • f + func + a function of at least one argument +
  • +
  • a + array + 2d array +
  • +
  • arg + an optional extra argument to be passed to the function. +
  • +
+ +

Returns:

+
    + + 2d array +
+ + + + +
+
+ + reduce_rows (f, a) +
+
+ reduce the rows using a function. + + +

Parameters:

+
    +
  • f + func + a binary function +
  • +
  • a + array + 2d array +
  • +
+ +

Returns:

+
    + + 1d array +
+ + +

See also:

+ + + +
+
+ + reduce_cols (f, a) +
+
+ reduce the columns using a function. + + +

Parameters:

+
    +
  • f + func + a binary function +
  • +
  • a + array + 2d array +
  • +
+ +

Returns:

+
    + + 1d array +
+ + +

See also:

+ + + +
+
+ + reduce2 (opc, opr, a) +
+
+ reduce a 2D array into a scalar, using two operations. + + +

Parameters:

+
    +
  • opc + func + operation to reduce the final result +
  • +
  • opr + func + operation to reduce the rows +
  • +
  • a + 2D array +
  • +
+ + + + + +
+
+ + map2 (f, ad, bd, a, b, arg) +
+
+ map a function over two arrays. + They can be both or either 2D arrays + + +

Parameters:

+
    +
  • f + func + function of at least two arguments +
  • +
  • ad + int + order of first array (1 if a is a list/array, 2 if it is a 2d array) +
  • +
  • bd + int + order of second array (1 if b is a list/array, 2 if it is a 2d array) +
  • +
  • a + tab + 1d or 2d array +
  • +
  • b + tab + 1d or 2d array +
  • +
  • arg + optional extra argument to pass to function +
  • +
+ +

Returns:

+
    + + 2D array, unless both arrays are 1D +
+ + + + +
+
+ + product (f, t1, t2) +
+
+ cartesian product of two 1d arrays. + + +

Parameters:

+
    +
  • f + func + a function of 2 arguments +
  • +
  • t1 + array + a 1d table +
  • +
  • t2 + array + a 1d table +
  • +
+ +

Returns:

+
    + + 2d table +
+ + + +

Usage:

+
    +
    product('..',{1,2},{'a','b'}) == {{'1a','2a'},{'1b','2b'}}
    +
+ +
+
+ + flatten (t) +
+
+ flatten a 2D array. + (this goes over columns first.) + + +

Parameters:

+
    +
  • t + array + 2d table +
  • +
+ +

Returns:

+
    + + a 1d table +
+ + + +

Usage:

+
    +
    flatten {{1,2},{3,4},{5,6}} == {1,2,3,4,5,6}
    +
+ +
+
+ + reshape (t, nrows, co) +
+
+ reshape a 2D array. Reshape the aray by specifying a new nr of rows. + + +

Parameters:

+
    +
  • t + array + 2d array +
  • +
  • nrows + int + new number of rows +
  • +
  • co + bool + use column-order (Fortran-style) (default false) +
  • +
+ +

Returns:

+
    + + a new 2d array +
+ + + + +
+
+ + transpose (t) +
+
+ transpose a 2D array. + + +

Parameters:

+
    +
  • t + array + 2d array +
  • +
+ +

Returns:

+
    + + a new 2d array +
+ + + + +
+
+ + swap_rows (t, i1, i2) +
+
+ swap two rows of an array. + + +

Parameters:

+
    +
  • t + array + a 2d array +
  • +
  • i1 + int + a row index +
  • +
  • i2 + int + a row index +
  • +
+ +

Returns:

+
    + + t (same, modified 2d array) +
+ + + + +
+
+ + swap_cols (t, j1, j2) +
+
+ swap two columns of an array. + + +

Parameters:

+
    +
  • t + array + a 2d array +
  • +
  • j1 + int + a column index +
  • +
  • j2 + int + a column index +
  • +
+ +

Returns:

+
    + + t (same, modified 2d array) +
+ + + + +
+
+ + extract_rows (t, ridx) +
+
+ extract the specified rows. + + +

Parameters:

+
    +
  • t + array + 2d array +
  • +
  • ridx + {int} + a table of row indices +
  • +
+ +

Returns:

+
    + + a new 2d array with the extracted rows +
+ + + + +
+
+ + extract_cols (t, cidx) +
+
+ extract the specified columns. + + +

Parameters:

+
    +
  • t + array + 2d array +
  • +
  • cidx + {int} + a table of column indices +
  • +
+ +

Returns:

+
    + + a new 2d array with the extracted colums +
+ + + + +
+
+ + remove_row (t, i) +
+
+ remove a row from an array. + + +

Parameters:

+
    +
  • t + array + a 2d array +
  • +
  • i + int + a row index +
  • +
+ + + + + +
+
+ + remove_col (t, j) +
+
+ remove a column from an array. + + +

Parameters:

+
    +
  • t + array + a 2d array +
  • +
  • j + int + a column index +
  • +
+ + + + + +
+
+ + parse_range (s) +
+
+ parse a spreadsheet range. + The range can be specified either as 'A1:B2' or 'R1C1:R2C2'; + a special case is a single element (e.g 'A1' or 'R1C1') + + +

Parameters:

+
    +
  • s + string + a range (case insensitive). +
  • +
+ +

Returns:

+
    +
  1. + int + start row
  2. +
  3. + int + start col
  4. +
  5. + int + end row
  6. +
  7. + int + end col
  8. +
+ + + + +
+
+ + range (t, rstr) +
+
+ get a slice of a 2D array using spreadsheet range notation. @see parse_range + + +

Parameters:

+
    +
  • t + array + a 2D array +
  • +
  • rstr + string + range expression +
  • +
+ +

Returns:

+
    + + a slice +
+ + +

See also:

+ + + +
+
+ + default_range (t, i1, j1, i2, j2) +
+
+ normalizes coordinates to valid positive entries and defaults. + Negative indices will be counted from the end, too low, or too high + will be limited by the array sizes. + + +

Parameters:

+
    +
  • t + array + a 2D array +
  • +
  • i1 + int + start row (default 1) +
  • +
  • j1 + int + start col (default 1) +
  • +
  • i2 + int + end row (default N) +
  • +
  • j2 + int + end col (default M) + return i1, j1, i2, j2 +
  • +
+ + + + + +
+
+ + slice (t, i1, j1, i2, j2) +
+
+ get a slice of a 2D array. Note that if the specified range has + a 1D result, the rank of the result will be 1. + + +

Parameters:

+
    +
  • t + array + a 2D array +
  • +
  • i1 + int + start row (default 1) +
  • +
  • j1 + int + start col (default 1) +
  • +
  • i2 + int + end row (default N) +
  • +
  • j2 + int + end col (default M) +
  • +
+ +

Returns:

+
    + + an array, 2D in general but 1D in special cases. +
+ + + + +
+
+ + set (t, value, i1, j1, i2, j2) +
+
+ set a specified range of an array to a value. + + +

Parameters:

+
    +
  • t + array + a 2D array +
  • +
  • value + the value (may be a function, called as val(i,j)) +
  • +
  • i1 + int + start row (default 1) +
  • +
  • j1 + int + start col (default 1) +
  • +
  • i2 + int + end row (default N) +
  • +
  • j2 + int + end col (default M) +
  • +
+ + + +

See also:

+ + + +
+
+ + write (t, f, fmt, i1, j1, i2, j2) +
+
+ write a 2D array to a file. + + +

Parameters:

+
    +
  • t + array + a 2D array +
  • +
  • f + a file object (default stdout) +
  • +
  • fmt + string + a format string (default is just to use tostring) +
  • +
  • i1 + int + start row (default 1) +
  • +
  • j1 + int + start col (default 1) +
  • +
  • i2 + int + end row (default N) +
  • +
  • j2 + int + end col (default M) +
  • +
+ + + + + +
+
+ + forall (t, row_op, end_row_op, i1, j1, i2, j2) +
+
+ perform an operation for all values in a 2D array. + + +

Parameters:

+
    +
  • t + array + 2D array +
  • +
  • row_op + func + function to call on each value; row_op(row,j) +
  • +
  • end_row_op + func + function to call at end of each row; end_row_op(i) +
  • +
  • i1 + int + start row (default 1) +
  • +
  • j1 + int + start col (default 1) +
  • +
  • i2 + int + end row (default N) +
  • +
  • j2 + int + end col (default M) +
  • +
+ + + + + +
+
+ + move (dest, di, dj, src, i1, j1, i2, j2) +
+
+ move a block from the destination to the source. + + +

Parameters:

+
    +
  • dest + array + a 2D array +
  • +
  • di + int + start row in dest +
  • +
  • dj + int + start col in dest +
  • +
  • src + array + a 2D array +
  • +
  • i1 + int + start row (default 1) +
  • +
  • j1 + int + start col (default 1) +
  • +
  • i2 + int + end row (default N) +
  • +
  • j2 + int + end col (default M) +
  • +
+ + + + + +
+
+ + iter (a, indices, i1, j1, i2, j2) +
+
+ iterate over all elements in a 2D array, with optional indices. + + +

Parameters:

+
    +
  • a + array + 2D array +
  • +
  • indices + bool + with indices (default false) +
  • +
  • i1 + int + start row (default 1) +
  • +
  • j1 + int + start col (default 1) +
  • +
  • i2 + int + end row (default N) +
  • +
  • j2 + int + end col (default M) +
  • +
+ +

Returns:

+
    + + either value or i,j,value depending on the value of indices +
+ + + + +
+
+ + columns (a) +
+
+ iterate over all columns. + + +

Parameters:

+
    +
  • a + array + a 2D array +
  • +
+ +

Returns:

+
    + + column, column-index +
+ + + + +
+
+ + rows (a) +
+
+ iterate over all rows. + Returns a copy of the row, for read-only purrposes directly iterating + is more performant; ipairs(a) + + +

Parameters:

+
    +
  • a + array + a 2D array +
  • +
+ +

Returns:

+
    + + row, row-index +
+ + + + +
+
+ + new (rows, cols, val) +
+
+ new array of specified dimensions + + +

Parameters:

+
    +
  • rows + int + number of rows +
  • +
  • cols + int + number of cols +
  • +
  • val + initial value; if it's a function then use val(i,j) +
  • +
+ +

Returns:

+
    + + new 2d array +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.class.html b/Data/Libraries/Penlight/docs/libraries/pl.class.html new file mode 100644 index 0000000..b623e94 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.class.html @@ -0,0 +1,332 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.class

+

Provides a reuseable and convenient framework for creating classes in Lua.

+

Two possible notations:

+ + +
+B = class(A)
+class.B(A)
+
+ +

The latter form creates a named class within the current environment. Note + that this implicitly brings in pl.utils as a dependency.

+ +

See the Guide for further discussion

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + +
_init (...)initializes an instance upon creation.
instance:is_a (some_class)checks whether an instance is derived from some class.
some_class:class_of (some_instance)checks whether an instance is derived from some class.
some_class:cast (some_instance)cast an object to another class.
class (base, c_arg, c)create a new class, derived from a given base class.
+ +
+
+ + +

Functions

+ +
+
+ + _init (...) +
+
+ initializes an instance upon creation. + + +

Parameters:

+
    +
  • ... + parameters passed to the constructor +
  • +
+ + + + +

Usage:

+
    +
    local Cat = class()
    +function Cat:_init(name)
    +  --self:super(name)   -- call the ancestor initializer if needed
    +  self.name = name
    +end
    +
    +local pussycat = Cat("pussycat")
    +print(pussycat.name)  --> pussycat
    +
+ +
+
+ + instance:is_a (some_class) +
+
+ checks whether an instance is derived from some class. + Works the other way around as class_of. It has two ways of using; + 1) call with a class to check against, 2) call without params. + + +

Parameters:

+
    +
  • some_class + class to check against, or nil to return the class +
  • +
+ +

Returns:

+
    + + true if instance is derived from some_class, or if some_class == nil then + it returns the class table of the instance +
+ + + +

Usage:

+
    +
    local pussycat = Lion()  -- assuming Lion derives from Cat
    +if pussycat:is_a(Cat) then
    +  -- it's true, it is a Lion, but also a Cat
    +end
    +
    +if pussycat:is_a() == Lion then
    +  -- It's true
    +end
    +
+ +
+
+ + some_class:class_of (some_instance) +
+
+ checks whether an instance is derived from some class. + Works the other way around as is_a. + + +

Parameters:

+
    +
  • some_instance + instance to check against +
  • +
+ +

Returns:

+
    + + true if some_instance is derived from some_class +
+ + + +

Usage:

+
    +
    local pussycat = Lion()  -- assuming Lion derives from Cat
    +if Cat:class_of(pussycat) then
    +  -- it's true
    +end
    +
+ +
+
+ + some_class:cast (some_instance) +
+
+ cast an object to another class. + It is not clever (or safe!) so use carefully. + + +

Parameters:

+
    +
  • some_instance + the object to be changed +
  • +
+ + + + + +
+
+ + class (base, c_arg, c) +
+
+ create a new class, derived from a given base class. + Supporting two class creation syntaxes: + either Name = class(base) or class.Name(base). + The first form returns the class directly and does not set its _name. + The second form creates a variable Name in the current environment set + to the class, and also sets _name. + + +

Parameters:

+
    +
  • base + optional base class +
  • +
  • c_arg + optional parameter to class constructor +
  • +
  • c + optional table to be used as class +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.compat.html b/Data/Libraries/Penlight/docs/libraries/pl.compat.html new file mode 100644 index 0000000..6680030 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.compat.html @@ -0,0 +1,580 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.compat

+

Lua 5.1/5.2/5.3 compatibility.

+

Injects table.pack, table.unpack, and package.searchpath in the global + environment, to make sure they are available for Lua 5.1 and LuaJIT.

+ +

All other functions are exported as usual in the returned module table.

+ +

NOTE: everything in this module is also available in pl.utils.

+ + +

Functions

+ + + + + + + + + + + + + + + + + +
execute (cmd)execute a shell command, in a compatible and platform independent way.
load (ld[, source[, mode[, env]]])Load Lua code as a text or binary chunk (in a Lua 5.2 compatible way).
getfenv (f)Get environment of a function (in a Lua 5.1 compatible way).
setfenv (f, env)Set environment of a function (in a Lua 5.1 compatible way).
+

Fields

+ + + + + + + + + + + + + + + + + + + + + +
lua51boolean flag this is Lua 5.1 (or LuaJIT).
jitboolean flag this is LuaJIT.
jit52boolean flag this is LuaJIT with 5.2 compatibility compiled in.
dir_separatorthe directory separator character for the current platform.
is_windowsboolean flag this is a Windows platform.
+

Global exported functions (for Lua 5.1 & LuaJIT)

+ + + + + + + + + + + + + +
table.pack (...)pack an argument list into a table.
table.unpack (t[, i[, t]])unpack a table and return the elements.
package.searchpath (name, path[, sep[, rep]])return the full path where a file name would be matched.
+

Global exported functions (for Lua < 5.4)

+ + + + + +
warn (...)raise a warning message.
+ +
+
+ + +

Functions

+ +
+
+ + execute (cmd) +
+
+ execute a shell command, in a compatible and platform independent way. + This is a compatibility function that returns the same for Lua 5.1 and + Lua 5.2+.

+ +

NOTE: Windows systems can use signed 32bit integer exitcodes. Posix systems + only use exitcodes 0-255, anything else is undefined.

+ +

NOTE2: In Lua 5.2 and 5.3 a Windows exitcode of -1 would not properly be + returned, this function will return it properly for all versions. + + +

Parameters:

+
    +
  • cmd + a shell command +
  • +
+ +

Returns:

+
    +
  1. + true if successful
  2. +
  3. + actual return code
  4. +
+ + + + +
+
+ + load (ld[, source[, mode[, env]]]) +
+
+ Load Lua code as a text or binary chunk (in a Lua 5.2 compatible way). + + +

Parameters:

+
    +
  • ld + code string or loader +
  • +
  • source + name of chunk for errors + (optional) +
  • +
  • mode + 'b', 't' or 'bt' + (optional) +
  • +
  • env + environment to load the chunk in + (optional) +
  • +
+ + + + + +
+
+ + getfenv (f) +
+
+ Get environment of a function (in a Lua 5.1 compatible way). + Not 100% compatible, so with Lua 5.2 it may return nil for a function with no + global references! + Based on code by Sergey Rozhenko + + +

Parameters:

+
    +
  • f + a function or a call stack reference +
  • +
+ + + + + +
+
+ + setfenv (f, env) +
+
+ Set environment of a function (in a Lua 5.1 compatible way). + + +

Parameters:

+
    +
  • f + a function or a call stack reference +
  • +
  • env + a table that becomes the new environment of f +
  • +
+ + + + + +
+
+

Fields

+ +
+
+ + lua51 +
+
+ boolean flag this is Lua 5.1 (or LuaJIT). + + +
    +
  • lua51 + + + +
  • +
+ + + + + +
+
+ + jit +
+
+ boolean flag this is LuaJIT. + + +
    +
  • jit + + + +
  • +
+ + + + + +
+
+ + jit52 +
+
+ boolean flag this is LuaJIT with 5.2 compatibility compiled in. + + +
    +
  • jit52 + + + +
  • +
+ + + + + +
+
+ + dir_separator +
+
+ the directory separator character for the current platform. + + +
    +
  • dir_separator + + + +
  • +
+ + + + + +
+
+ + is_windows +
+
+ boolean flag this is a Windows platform. + + +
    +
  • is_windows + + + +
  • +
+ + + + + +
+
+

Global exported functions (for Lua 5.1 & LuaJIT)

+ +
+
+ + table.pack (...) +
+
+ pack an argument list into a table. + + +

Parameters:

+
    +
  • ... + any arguments +
  • +
+ +

Returns:

+
    + + a table with field n set to the length +
+ + + + +
+
+ + table.unpack (t[, i[, t]]) +
+
+ unpack a table and return the elements.

+ +

NOTE: this version does NOT honor the n field, and hence it is not nil-safe. + See utils.unpack for a version that is nil-safe. + + +

Parameters:

+
    +
  • t + index of the last element to unpack, defaults to #t + (optional) +
  • +
  • i + index from which to start unpacking, defaults to 1 + (optional) +
  • +
  • t + index of the last element to unpack, defaults to #t + (optional) +
  • +
+ +

Returns:

+
    + + multiple return values from the table +
+ + +

See also:

+ + + +
+
+ + package.searchpath (name, path[, sep[, rep]]) +
+
+ return the full path where a file name would be matched. + This function was introduced in Lua 5.2, so this compatibility version + will be injected in Lua 5.1 engines. + + +

Parameters:

+
    +
  • name + string + file name, possibly dotted +
  • +
  • path + string + a path-template in the same form as package.path or package.cpath +
  • +
  • sep + string + template separate character to be replaced by path separator. Default: "." + (optional) +
  • +
  • rep + string + the path separator to use, defaults to system separator. Default; "/" on Unixes, "\" on Windows. + (optional) +
  • +
+ +

Returns:

+
    +
  1. + on success: path of the file
  2. +
  3. + on failure: nil, error string listing paths tried
  4. +
+ + +

See also:

+ + + +
+
+

Global exported functions (for Lua < 5.4)

+ +
+
+ + warn (...) +
+
+ raise a warning message. + This functions mimics the warn function added in Lua 5.4. + + +

Parameters:

+
    +
  • ... + any arguments +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.comprehension.html b/Data/Libraries/Penlight/docs/libraries/pl.comprehension.html new file mode 100644 index 0000000..4c31b64 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.comprehension.html @@ -0,0 +1,165 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.comprehension

+

List comprehensions implemented in Lua.

+

See the wiki page

+ + +
+local C= require 'pl.comprehension' . new()
+
+C ('x for x=1,10') ()
+==> {1,2,3,4,5,6,7,8,9,10}
+C 'x^2 for x=1,4' ()
+==> {1,4,9,16}
+C '{x,x^2} for x=1,4' ()
+==> {{1,1},{2,4},{3,9},{4,16}}
+C '2*x for x' {1,2,3}
+==> {2,4,6}
+dbl = C '2*x for x'
+dbl {10,20,30}
+==> {20,40,60}
+C 'x for x if x % 2 == 0' {1,2,3,4,5}
+==> {2,4}
+C '{x,y} for x = 1,2 for y = 1,2' ()
+==> {{1,1},{1,2},{2,1},{2,2}}
+C '{x,y} for x for y' ({1,2},{10,20})
+==> {{1,10},{1,20},{2,10},{2,20}}
+assert(C 'sum(x^2 for x)' {2,3,4} == 2^2+3^2+4^2)
+
+ +

(c) 2008 David Manura. Licensed under the same terms as Lua (MIT license).

+ +

Dependencies: pl.utils, pl.luabalanced

+ +

See the Guide

+ + + +
+
+ + + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.config.html b/Data/Libraries/Penlight/docs/libraries/pl.config.html new file mode 100644 index 0000000..1ad8833 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.config.html @@ -0,0 +1,259 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.config

+

Reads configuration files into a Lua table.

+

+ +

Understands INI files, classic Unix config files, and simple + delimited columns of values. See the Guide

+ + +
+# test.config
+# Read timeout in seconds
+read.timeout=10
+# Write timeout in seconds
+write.timeout=5
+#acceptable ports
+ports = 1002,1003,1004
+
+-- readconfig.lua
+local config = require 'config'
+local t = config.read 'test.config'
+print(pretty.write(t))
+
+### output #####
+{
+  ports = {
+    1002,
+    1003,
+    1004
+  },
+  write_timeout = 5,
+  read_timeout = 10
+}
+
+ +

+ + +

Functions

+ + + + + + + + + +
lines (file)like io.lines(), but allows for lines to be continued with ''.
read (file[, cnfg])read a configuration file into a table
+ +
+
+ + +

Functions

+ +
+
+ + lines (file) +
+
+ like io.lines(), but allows for lines to be continued with ''. + + +

Parameters:

+
    +
  • file + a file-like object (anything where read() returns the next line) or a filename. + Defaults to stardard input. +
  • +
+ +

Returns:

+
    +
  1. + an iterator over the lines, or nil
  2. +
  3. + error 'not a file-like object' or 'file is nil'
  4. +
+ + + + +
+
+ + read (file[, cnfg]) +
+
+ read a configuration file into a table + + +

Parameters:

+
    +
  • file + either a file-like object or a string, which must be a filename +
  • +
  • cnfg + tab + +

    a configuration table that may contain these fields:

    + +
      +
    • smart try to deduce what kind of config file we have (default false)
    • +
    • variabilize make names into valid Lua identifiers (default true)
    • +
    • convert_numbers try to convert values into numbers (default true)
    • +
    • trim_space ensure that there is no starting or trailing whitespace with values (default true)
    • +
    • trim_quotes remove quotes from strings (default false)
    • +
    • list_delim delimiter to use when separating columns (default ',')
    • +
    • keysep separator between key and value pairs (default '=')
    • +
    + + + (optional) +
  • +
+ +

Returns:

+
    +
  1. + a table containing items, or nil
  2. +
  3. + error message (same as config.lines
  4. +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.data.html b/Data/Libraries/Penlight/docs/libraries/pl.data.html new file mode 100644 index 0000000..736e82e --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.data.html @@ -0,0 +1,571 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.data

+

Reading and querying simple tabular data.

+

+ + + +

+data.read 'test.txt'
+==> {{10,20},{2,5},{40,50},fieldnames={'x','y'},delim=','}
+
+ +

Provides a way of creating basic SQL-like queries.

+ + +
+require 'pl'
+local d = data.read('xyz.txt')
+local q = d:select('x,y,z where x > 3 and z < 2 sort by y')
+for x,y,z in q do
+    print(x,y,z)
+end
+
+ +

See the Guide

+ +

Dependencies: pl.utils, pl.array2d (fallback methods)

+

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Data.column_by_name (name)return a particular column as a list of values (method).
Data.select (condn)return a query iterator on this data (method).
Data.select_row (condn)return a row iterator on this data (method).
Data.copy_select (condn)return a new data object based on this query (method).
Data.column_names ()return the field names of this data object (method).
Data.write_row (f)write out a row (method).
Data.write (f)write data out to file (method).
read (file, cnfg)read a delimited file in a Lua table.
write (data, file[, fieldnames[, delim='\t']])write 2D data to a file.
new (d[, fieldnames])create a new dataset from a table of rows.
query (data, condn, context, return_row)create a query iterator from a select string.
filter (Q, infile, outfile, dont_fail)Filter input using a query.
+ +
+
+ + +

Functions

+ +
+
+ + Data.column_by_name (name) +
+
+ return a particular column as a list of values (method). + + +

Parameters:

+
    +
  • name + either name of column, or numerical index. +
  • +
+ + + + + +
+
+ + Data.select (condn) +
+
+ return a query iterator on this data (method). + + +

Parameters:

+
    +
  • condn + string + the query expression +
  • +
+ + + +

See also:

+ + + +
+
+ + Data.select_row (condn) +
+
+ return a row iterator on this data (method). + + +

Parameters:

+
    +
  • condn + string + the query expression +
  • +
+ + + + + +
+
+ + Data.copy_select (condn) +
+
+ return a new data object based on this query (method). + + +

Parameters:

+
    +
  • condn + string + the query expression +
  • +
+ + + + + +
+
+ + Data.column_names () +
+
+ return the field names of this data object (method). + + + + + + + +
+
+ + Data.write_row (f) +
+
+ write out a row (method). + + +

Parameters:

+
    +
  • f + file-like object +
  • +
+ + + + + +
+
+ + Data.write (f) +
+
+ write data out to file (method). + + +

Parameters:

+
    +
  • f + file-like object +
  • +
+ + + + + +
+
+ + read (file, cnfg) +
+
+ read a delimited file in a Lua table. + By default, attempts to treat first line as separated list of fieldnames. + + +

Parameters:

+
    +
  • file + a filename or a file-like object +
  • +
  • cnfg parsing options +
      +
    • delim + string + a string pattern to split fields +
    • +
    • fieldnames + array + (i.e. don't read from first line) +
    • +
    • no_convert + bool + (default is to try conversion on first data line) +
    • +
    • convert + tab + table of custom conversion functions with column keys +
    • +
    • numfields + int + indices of columns known to be numbers +
    • +
    • last_field_collect + bool + only split as many fields as fieldnames. +
    • +
    • thousands_dot + int + thousands separator in Excel CSV is '.' +
    • +
    • csv + bool + fields may be double-quoted and contain commas; + Also, empty fields are considered to be equivalent to zero. +
    • +
    +
+ +

Returns:

+
    +
  1. + data object, or nil
  2. +
  3. + error message. May be a file error, 'not a file-like object' + or a conversion error
  4. +
+ + + + +
+
+ + write (data, file[, fieldnames[, delim='\t']]) +
+
+ write 2D data to a file. + Does not assume that the data has actually been + generated with new or read. + + +

Parameters:

+
    +
  • data + 2D array +
  • +
  • file + filename or file-like object +
  • +
  • fieldnames + {string} + list of fields (optional) + (optional) +
  • +
  • delim + string + delimiter (default tab) + (default '\t') +
  • +
+ +

Returns:

+
    + + true or nil, error +
+ + + + +
+
+ + new (d[, fieldnames]) +
+
+ create a new dataset from a table of rows. + Can specify the fieldnames, else the table must have a field called + 'fieldnames', which is either a string of delimiter-separated names, + or a table of names.
+ If the table does not have a field called 'delim', then an attempt will be + made to guess it from the fieldnames string, defaults otherwise to tab. + + +

Parameters:

+
    +
  • d + the table. +
  • +
  • fieldnames + {string} + optional fieldnames + (optional) +
  • +
+ +

Returns:

+
    + + the table. +
+ + + + +
+
+ + query (data, condn, context, return_row) +
+
+ create a query iterator from a select string. + Select string has this format:
+ FIELDLIST [ where LUA-CONDN [ sort by FIELD] ]
+ FIELDLIST is a comma-separated list of valid fields, or '*'.

+ The condition can also be a table, with fields 'fields' (comma-sep string or + table), 'sort_by' (string) and 'where' (Lua expression string or function) + + +

Parameters:

+
    +
  • data + table produced by read +
  • +
  • condn + select string or table +
  • +
  • context + a list of tables to be searched when resolving functions +
  • +
  • return_row + if true, wrap the results in a row table +
  • +
+ +

Returns:

+
    +
  1. + an iterator over the specified fields, or nil
  2. +
  3. + an error message
  4. +
+ + + + +
+
+ + filter (Q, infile, outfile, dont_fail) +
+
+ Filter input using a query. + + +

Parameters:

+
    +
  • Q + string + a query string +
  • +
  • infile + filename or file-like object +
  • +
  • outfile + filename or file-like object +
  • +
  • dont_fail + bool + true if you want to return an error, not just fail +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.dir.html b/Data/Libraries/Penlight/docs/libraries/pl.dir.html new file mode 100644 index 0000000..5dfa0f6 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.dir.html @@ -0,0 +1,615 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.dir

+

Listing files in directories and creating/removing directory paths.

+

Dependencies: pl.utils, pl.path

+ +

Soft Dependencies: alien, ffi (either are used on Windows for copying/moving files)

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
fnmatch (filename, pattern)Test whether a file name matches a shell pattern.
filter (filenames, pattern)Return a list of all file names within an array which match a pattern.
getfiles (dirname, mask)return a list of all files in a directory which match a shell pattern.
getdirectories (dirname)return a list of all subdirectories of the directory.
copyfile (src, dest, flag)copy a file.
movefile (src, dest)move a file.
walk (root, bottom_up, follow_links)return an iterator which walks through a directory tree starting at root.
rmtree (fullpath)remove a whole directory tree.
makepath (p)create a directory path.
clonetree (path1, path2, file_fun, verbose)clone a directory tree.
dirtree (d)return an iterator over all entries in a directory tree
getallfiles (start_path, shell_pattern)Recursively returns all the file starting at path.
+ +
+
+ + +

Functions

+ +
+
+ + fnmatch (filename, pattern) +
+
+ Test whether a file name matches a shell pattern. + Both parameters are case-normalized if operating system is + case-insensitive. + + +

Parameters:

+
    +
  • filename + string + A file name. +
  • +
  • pattern + string + A shell pattern. The only special characters are + '*' and '?': '*' matches any sequence of characters and + '?' matches any single character. +
  • +
+ +

Returns:

+
    + + bool + + + +
+ +

Raises:

+ dir and mask must be strings + + + +
+
+ + filter (filenames, pattern) +
+
+ Return a list of all file names within an array which match a pattern. + + +

Parameters:

+
    +
  • filenames + tab + An array containing file names. +
  • +
  • pattern + string + A shell pattern. +
  • +
+ +

Returns:

+
    + + List(string) + List of matching file names. +
+ +

Raises:

+ dir and mask must be strings + + + +
+
+ + getfiles (dirname, mask) +
+
+ return a list of all files in a directory which match a shell pattern. + + +

Parameters:

+
    +
  • dirname + string + A directory. If not given, all files in current directory are returned. +
  • +
  • mask + string + A shell pattern. If not given, all files are returned. +
  • +
+ +

Returns:

+
    + + {string} + list of files +
+ +

Raises:

+ dirname and mask must be strings + + + +
+
+ + getdirectories (dirname) +
+
+ return a list of all subdirectories of the directory. + + +

Parameters:

+
    +
  • dirname + string + A directory +
  • +
+ +

Returns:

+
    + + {string} + a list of directories +
+ +

Raises:

+ dir must be a a valid directory + + + +
+
+ + copyfile (src, dest, flag) +
+
+ copy a file. + + +

Parameters:

+
    +
  • src + string + source file +
  • +
  • dest + string + destination file or directory +
  • +
  • flag + bool + true if you want to force the copy (default) +
  • +
+ +

Returns:

+
    + + bool + operation succeeded +
+ +

Raises:

+ src and dest must be strings + + + +
+
+ + movefile (src, dest) +
+
+ move a file. + + +

Parameters:

+
    +
  • src + string + source file +
  • +
  • dest + string + destination file or directory +
  • +
+ +

Returns:

+
    + + bool + operation succeeded +
+ +

Raises:

+ src and dest must be strings + + + +
+
+ + walk (root, bottom_up, follow_links) +
+
+ return an iterator which walks through a directory tree starting at root. + The iterator returns (root,dirs,files) + Note that dirs and files are lists of names (i.e. you must say path.join(root,d) + to get the actual full path) + If bottom_up is false (or not present), then the entries at the current level are returned + before we go deeper. This means that you can modify the returned list of directories before + continuing. + This is a clone of os.walk from the Python libraries. + + +

Parameters:

+
    +
  • root + string + A starting directory +
  • +
  • bottom_up + bool + False if we start listing entries immediately. +
  • +
  • follow_links + bool + follow symbolic links +
  • +
+ +

Returns:

+
    + + an iterator returning root,dirs,files +
+ +

Raises:

+ root must be a directory + + + +
+
+ + rmtree (fullpath) +
+
+ remove a whole directory tree. + Symlinks in the tree will be deleted without following them. + + +

Parameters:

+
    +
  • fullpath + string + A directory path (must be an actual directory, not a symlink) +
  • +
+ +

Returns:

+
    +
  1. + true or nil
  2. +
  3. + error if failed
  4. +
+ +

Raises:

+ fullpath must be a string + + + +
+
+ + makepath (p) +
+
+ create a directory path. + This will create subdirectories as necessary! + + +

Parameters:

+
    +
  • p + string + A directory path +
  • +
+ +

Returns:

+
    + + true on success, nil + errormsg on failure +
+ +

Raises:

+ failure to create + + + +
+
+ + clonetree (path1, path2, file_fun, verbose) +
+
+ clone a directory tree. Will always try to create a new directory structure + if necessary. + + +

Parameters:

+
    +
  • path1 + string + the base path of the source tree +
  • +
  • path2 + string + the new base path for the destination +
  • +
  • file_fun + func + an optional function to apply on all files +
  • +
  • verbose + bool + an optional boolean to control the verbosity of the output. + It can also be a logging function that behaves like print() +
  • +
+ +

Returns:

+
    +
  1. + true, or nil
  2. +
  3. + error message, or list of failed directory creations
  4. +
  5. + list of failed file operations
  6. +
+ +

Raises:

+ path1 and path2 must be strings + + +

Usage:

+
    +
    clonetree('.','../backup',copyfile)
    +
+ +
+
+ + dirtree (d) +
+
+ return an iterator over all entries in a directory tree + + +

Parameters:

+
    +
  • d + string + a directory +
  • +
+ +

Returns:

+
    + + an iterator giving pathname and mode (true for dir, false otherwise) +
+ +

Raises:

+ d must be a non-empty string + + + +
+
+ + getallfiles (start_path, shell_pattern) +
+
+ Recursively returns all the file starting at path. It can optionally take a shell pattern and + only returns files that match shellpattern_. If a pattern is given it will do a case insensitive search. + + +

Parameters:

+
    +
  • start_path + string + A directory. If not given, all files in current directory are returned. +
  • +
  • shell_pattern + string + A shell pattern. If not given, all files are returned. +
  • +
+ +

Returns:

+
    + + List(string) + containing all the files found recursively starting at path and filtered by shellpattern_. +
+ +

Raises:

+ start_path must be a directory + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.file.html b/Data/Libraries/Penlight/docs/libraries/pl.file.html new file mode 100644 index 0000000..bd36aca --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.file.html @@ -0,0 +1,301 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.file

+

File manipulation functions: reading, writing, moving and copying.

+

This module wraps a number of functions from other modules into a + file related module for convenience.

+ +

Dependencies: pl.utils, pl.dir, pl.path

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
read ()return the contents of a file as a string.
write ()write a string to a file.
copy ()copy a file.
move ()move a file.
access_time ()Return the time of last access as the number of seconds since the epoch.
creation_time ()Return when the file was created.
modified_time ()Return the time of last modification.
delete ()Delete a file.
+ +
+
+ + +

Functions

+ +
+
+ + read () +
+
+ return the contents of a file as a string. + This function is a copy of utils.readfile. + + + + + + + +
+
+ + write () +
+
+ write a string to a file. + This function is a copy of utils.writefile. + + + + + + + +
+
+ + copy () +
+
+ copy a file. + This function is a copy of dir.copyfile. + + + + + + + +
+
+ + move () +
+
+ move a file. + This function is a copy of dir.movefile. + + + + + + + +
+
+ + access_time () +
+
+ Return the time of last access as the number of seconds since the epoch. + This function is a copy of path.getatime. + + + + + + + +
+
+ + creation_time () +
+
+ Return when the file was created. + This function is a copy of path.getctime. + + + + + + + +
+
+ + modified_time () +
+
+ Return the time of last modification. + This function is a copy of path.getmtime. + + + + + + + +
+
+ + delete () +
+
+ Delete a file. + This function is a copy of os.remove. + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.func.html b/Data/Libraries/Penlight/docs/libraries/pl.func.html new file mode 100644 index 0000000..22e84a1 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.func.html @@ -0,0 +1,460 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.func

+

Functional helpers like composition, binding and placeholder expressions.

+

Placeholder expressions are useful for short anonymous functions, and were + inspired by the Boost Lambda library.

+ + +
+> utils.import 'pl.func'
+> ls = List{10,20,30}
+> = ls:map(_1+1)
+{11,21,31}
+
+ +

They can also be used to bind particular arguments of a function.

+ + +
+> p = bind(print,'start>',_0)
+> p(10,20,30)
+> start>   10   20  30
+
+ +

See the Guide

+ +

Dependencies: pl.utils, pl.tablex

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
import (tname, context)wrap a table of functions.
register (fun[, name])register a function for use in placeholder expressions.
tail (ls)all elements of a table except the first.
repr (e, lastpred)create a string representation of a placeholder expression.
instantiate (e)instantiate a PE into an actual function.
I (e)instantiate a PE unless it has already been done.
bind1 (fn, p)bind the first parameter of the function to a value.
compose (f, g)create a function which chains two functions.
bind (fn, ...)bind the arguments of a function to given values.
+ +
+
+ + +

Functions

+ +
+
+ + import (tname, context) +
+
+ wrap a table of functions. This makes them available for use in + placeholder expressions. + + +

Parameters:

+
    +
  • tname + string + a table name +
  • +
  • context + tab + context to put results, defaults to environment of caller +
  • +
+ + + + + +
+
+ + register (fun[, name]) +
+
+ register a function for use in placeholder expressions. + + +

Parameters:

+
    +
  • fun + func + a function +
  • +
  • name + string + an optional name + (optional) +
  • +
+ +

Returns:

+
    + + a placeholder functiond +
+ + + + +
+
+ + tail (ls) +
+
+ all elements of a table except the first. + + +

Parameters:

+
    +
  • ls + tab + a list-like table. +
  • +
+ + + + + +
+
+ + repr (e, lastpred) +
+
+ create a string representation of a placeholder expression. + + +

Parameters:

+
    +
  • e + a placeholder expression +
  • +
  • lastpred + not used +
  • +
+ + + + + +
+
+ + instantiate (e) +
+
+ instantiate a PE into an actual function. First we find the largest placeholder used, + e.g. 2; from this a list of the formal parameters can be build. Then we collect and replace + any non-PE values from the PE, and build up a constant binding list. + Finally, the expression can be compiled, and e.PEfunction is set. + + +

Parameters:

+
    +
  • e + a placeholder expression +
  • +
+ +

Returns:

+
    + + a function +
+ + + + +
+
+ + I (e) +
+
+ instantiate a PE unless it has already been done. + + +

Parameters:

+
    +
  • e + a placeholder expression +
  • +
+ +

Returns:

+
    + + the function +
+ + + + +
+
+ + bind1 (fn, p) +
+
+ bind the first parameter of the function to a value. + + +

Parameters:

+
    +
  • fn + func + a function of one or more arguments +
  • +
  • p + a value +
  • +
+ +

Returns:

+
    + + a function of one less argument +
+ + + +

Usage:

+
    +
    (bind1(math.max,10))(20) == math.max(10,20)
    +
+ +
+
+ + compose (f, g) +
+
+ create a function which chains two functions. + + +

Parameters:

+
    +
  • f + func + a function of at least one argument +
  • +
  • g + func + a function of at least one argument +
  • +
+ +

Returns:

+
    + + a function +
+ + + +

Usage:

+
    +
    printf = compose(io.write,string.format)
    +
+ +
+
+ + bind (fn, ...) +
+
+ bind the arguments of a function to given values. + bind(fn,v,_2) is equivalent to bind1(fn,v). + + +

Parameters:

+
    +
  • fn + func + a function of at least one argument +
  • +
  • ... + values or placeholder variables +
  • +
+ +

Returns:

+
    + + a function +
+ + + +

Usage:

+
    +
  • (bind(f,_1,a))(b) == f(a,b)
  • +
  • (bind(f,_2,_1))(a,b) == f(b,a)
  • +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.html b/Data/Libraries/Penlight/docs/libraries/pl.html new file mode 100644 index 0000000..f3d134f --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.html @@ -0,0 +1,139 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl

+

Entry point for loading all PL libraries only on demand, into the global space.

+

Requiring 'pl' means that whenever a module is implicitly accesssed + (e.g. utils.split) + then that module is dynamically loaded. The submodules are all brought into + the global space. +Updated to use pl.import_into

+ + + +
+
+ + + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.import_into.html b/Data/Libraries/Penlight/docs/libraries/pl.import_into.html new file mode 100644 index 0000000..5f92459 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.import_into.html @@ -0,0 +1,142 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.import_into

+

PL loader, for loading all PL libraries, only on demand.

+

Whenever a module is implicitly accesssed, the table will have the module automatically injected. + (e.g. _ENV.tablex) + then that module is dynamically loaded. The submodules are all brought into + the table that is provided as the argument, or returned in a new table. + If a table is provided, that table's metatable is clobbered, but the values are not. + This module returns a single function, which is passed the environment. + If this is true, then return a 'shadow table' as the module + See the Guide

+ + + +
+
+ + + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.input.html b/Data/Libraries/Penlight/docs/libraries/pl.input.html new file mode 100644 index 0000000..d0086fd --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.input.html @@ -0,0 +1,336 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.input

+

Iterators for extracting words or numbers from an input source.

+

+ + + +

+require 'pl'
+local total,n = seq.sum(input.numbers())
+print('average',total/n)
+
+ +

source is defined as a string or a file-like object (i.e. has a read() method which returns the next line)

+ +

See here

+ +

Dependencies: pl.utils

+

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + +
alltokens (getter, pattern[, fn])create an iterator over all tokens.
create_getter (f)create a function which grabs the next value from a source.
numbers (f)generate a sequence of numbers from a source.
words (f)generate a sequence of words from a source.
fields (ids, delim, f, opts)parse an input source into fields.
+ +
+
+ + +

Functions

+ +
+
+ + alltokens (getter, pattern[, fn]) +
+
+ create an iterator over all tokens. + based on allwords from PiL, 7.1 + + +

Parameters:

+
    +
  • getter + func + any function that returns a line of text +
  • +
  • pattern + string + + + +
  • +
  • fn + string + Optionally can pass a function to process each token as it's found. + (optional) +
  • +
+ +

Returns:

+
    + + an iterator +
+ + + + +
+
+ + create_getter (f) +
+
+ create a function which grabs the next value from a source. If the source is a string, then the getter + will return the string and thereafter return nil. If not specified then the source is assumed to be stdin. + + +

Parameters:

+
    +
  • f + a string or a file-like object (i.e. has a read() method which returns the next line) +
  • +
+ +

Returns:

+
    + + a getter function +
+ + + + +
+
+ + numbers (f) +
+
+ generate a sequence of numbers from a source. + + +

Parameters:

+
    +
  • f + A source +
  • +
+ +

Returns:

+
    + + An iterator +
+ + + + +
+
+ + words (f) +
+
+ generate a sequence of words from a source. + + +

Parameters:

+
    +
  • f + A source +
  • +
+ +

Returns:

+
    + + An iterator +
+ + + + +
+
+ + fields (ids, delim, f, opts) +
+
+ parse an input source into fields. + By default, will fail if it cannot convert a field to a number. + + +

Parameters:

+
    +
  • ids + a list of field indices, or a maximum field index +
  • +
  • delim + string + delimiter to parse fields (default space) +
  • +
  • f + a source @see create_getter +
  • +
  • opts + tab + option table, {no_fail=true} +
  • +
+ +

Returns:

+
    + + an iterator with the field values +
+ + + +

Usage:

+
    +
    for x,y in fields {2,3} do print(x,y) end -- 2nd and 3rd fields from stdin
    +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.lapp.html b/Data/Libraries/Penlight/docs/libraries/pl.lapp.html new file mode 100644 index 0000000..24a1079 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.lapp.html @@ -0,0 +1,382 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.lapp

+

Simple command-line parsing using human-readable specification.

+

Supports GNU-style parameters.

+ + +
+lapp = require 'pl.lapp'
+local args = lapp [[
+Does some calculations
+  -o,--offset (default 0.0)  Offset to add to scaled number
+  -s,--scale  (number)  Scaling factor
+  <number> (number) Number to be scaled
+]]
+
+print(args.offset + args.scale * args.number)
+
+ +

Lines beginning with '-' are flags; there may be a short and a long name; + lines beginning with '<var>' are arguments. Anything in parens after + the flag/argument is either a default, a type name or a range constraint.

+ +

See the Guide

+ +

Dependencies: pl.sip

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + +
quit (msg, no_usage)quit this script immediately.
error (msg, no_usage)print an error to stderr and quit.
open (file[, opt])open a file.
assert (condn, msg)quit if the condition is false.
add_type (name, converter[, constraint])add a new type to Lapp.
process_options_string (str, args)process a Lapp options string.
+

Fields

+ + + + + +
show_usage_errorcontrols whether to dump usage on error.
+ +
+
+ + +

Functions

+ +
+
+ + quit (msg, no_usage) +
+
+ quit this script immediately. + + +

Parameters:

+
    +
  • msg + string + optional message +
  • +
  • no_usage + bool + suppress 'usage' display +
  • +
+ + + + + +
+
+ + error (msg, no_usage) +
+
+ print an error to stderr and quit. + + +

Parameters:

+
    +
  • msg + string + a message +
  • +
  • no_usage + bool + suppress 'usage' display +
  • +
+ + + + + +
+
+ + open (file[, opt]) +
+
+ open a file. + This will quit on error, and keep a list of file objects for later cleanup. + + +

Parameters:

+
    +
  • file + string + filename +
  • +
  • opt + string + same as second parameter of io.open + (optional) +
  • +
+ + + + + +
+
+ + assert (condn, msg) +
+
+ quit if the condition is false. + + +

Parameters:

+
    +
  • condn + bool + a condition +
  • +
  • msg + string + message text +
  • +
+ + + + + +
+
+ + add_type (name, converter[, constraint]) +
+
+ add a new type to Lapp. These appear in parens after the value like + a range constraint, e.g. ' (integer) Process PID' + + +

Parameters:

+
    +
  • name + string + name of type +
  • +
  • converter + either a function to convert values, or a Lua type name. +
  • +
  • constraint + func + optional function to verify values, should use lapp.error + if failed. + (optional) +
  • +
+ + + + + +
+
+ + process_options_string (str, args) +
+
+ process a Lapp options string. + Usually called as lapp(). + + +

Parameters:

+
    +
  • str + string + the options text +
  • +
  • args + {string} + a table of arguments (default is _G.arg) +
  • +
+ +

Returns:

+
    + + a table with parameter-value pairs +
+ + + + +
+
+

Fields

+ +
+
+ + show_usage_error +
+
+ controls whether to dump usage on error. + Defaults to true + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.lexer.html b/Data/Libraries/Penlight/docs/libraries/pl.lexer.html new file mode 100644 index 0000000..7b3d6fd --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.lexer.html @@ -0,0 +1,524 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.lexer

+

Lexical scanner for creating a sequence of tokens from text.

+

lexer.scan(s) returns an iterator over all tokens found in the + string s. This iterator returns two values, a token type string + (such as 'string' for quoted string, 'iden' for identifier) and the value of the + token.

+ +

Versions specialized for Lua and C are available; these also handle block comments + and classify keywords as 'keyword' tokens. For example:

+ + +
+> s = 'for i=1,n do'
+> for t,v in lexer.lua(s)  do print(t,v) end
+keyword for
+iden    i
+=       =
+number  1
+,       ,
+iden    n
+keyword do
+
+ +

See the Guide for further discussion

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
scan (s, matches[, filter[, options]])create a plain token iterator from a string or file-like object.
insert (tok, a1, a2)insert tokens into a stream.
getline (tok)get everything in a stream upto a newline.
lineno (tok)get current line number.
getrest (tok)get the rest of the stream.
get_keywords ()get the Lua keywords as a set-like table.
lua (s[, filter[, options]])create a Lua token iterator from a string or file-like object.
cpp (s[, filter[, options]])create a C/C++ token iterator from a string or file-like object.
get_separated_list (tok[, endtoken=')'[, delim=']])get a list of parameters separated by a delimiter from a stream.
skipws (tok)get the next non-space token from the stream.
expecting (tok, expected_type, no_skip_ws)get the next token, which must be of the expected type.
+ +
+
+ + +

Functions

+ +
+
+ + scan (s, matches[, filter[, options]]) +
+
+ create a plain token iterator from a string or file-like object. + + +

Parameters:

+
    +
  • s + string or file + a string or a file-like object with :read() method returning lines. +
  • +
  • matches + tab + an optional match table - array of token descriptions. + A token is described by a {pattern, action} pair, where pattern should match + token body and action is a function called when a token of described type is found. +
  • +
  • filter + tab + a table of token types to exclude, by default {space=true} + (optional) +
  • +
  • options + tab + a table of options; by default, {number=true,string=true}, + which means convert numbers and strip string quotes. + (optional) +
  • +
+ + + + + +
+
+ + insert (tok, a1, a2) +
+
+ insert tokens into a stream. + + +

Parameters:

+
    +
  • tok + a token stream +
  • +
  • a1 + a string is the type, a table is a token list and + a function is assumed to be a token-like iterator (returns type & value) +
  • +
  • a2 + string + a string is the value +
  • +
+ + + + + +
+
+ + getline (tok) +
+
+ get everything in a stream upto a newline. + + +

Parameters:

+
    +
  • tok + a token stream +
  • +
+ +

Returns:

+
    + + a string +
+ + + + +
+
+ + lineno (tok) +
+
+ get current line number. + + +

Parameters:

+
    +
  • tok + a token stream +
  • +
+ +

Returns:

+
    + + the line number. + if the input source is a file-like object, + also return the column. +
+ + + + +
+
+ + getrest (tok) +
+
+ get the rest of the stream. + + +

Parameters:

+
    +
  • tok + a token stream +
  • +
+ +

Returns:

+
    + + a string +
+ + + + +
+
+ + get_keywords () +
+
+ get the Lua keywords as a set-like table. + So res["and"] etc would be true. + + + +

Returns:

+
    + + a table +
+ + + + +
+
+ + lua (s[, filter[, options]]) +
+
+ create a Lua token iterator from a string or file-like object. + Will return the token type and value. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • filter + tab + a table of token types to exclude, by default {space=true,comments=true} + (optional) +
  • +
  • options + tab + a table of options; by default, {number=true,string=true}, + which means convert numbers and strip string quotes. + (optional) +
  • +
+ + + + + +
+
+ + cpp (s[, filter[, options]]) +
+
+ create a C/C++ token iterator from a string or file-like object. + Will return the token type type and value. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • filter + tab + a table of token types to exclude, by default {space=true,comments=true} + (optional) +
  • +
  • options + tab + a table of options; by default, {number=true,string=true}, + which means convert numbers and strip string quotes. + (optional) +
  • +
+ + + + + +
+
+ + get_separated_list (tok[, endtoken=')'[, delim=']]) +
+
+ get a list of parameters separated by a delimiter from a stream. + + +

Parameters:

+
    +
  • tok + the token stream +
  • +
  • endtoken + string + end of list. Can be '\n' + (default ')') +
  • +
  • delim + string + separator + (default ') +
  • +
+ +

Returns:

+
    + + a list of token lists. +
+ + + + +
+
+ + skipws (tok) +
+
+ get the next non-space token from the stream. + + +

Parameters:

+
    +
  • tok + the token stream. +
  • +
+ + + + + +
+
+ + expecting (tok, expected_type, no_skip_ws) +
+
+ get the next token, which must be of the expected type. + Throws an error if this type does not match! + + +

Parameters:

+
    +
  • tok + the token stream +
  • +
  • expected_type + string + the token type +
  • +
  • no_skip_ws + bool + whether we should skip whitespace +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.luabalanced.html b/Data/Libraries/Penlight/docs/libraries/pl.luabalanced.html new file mode 100644 index 0000000..48f6c63 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.luabalanced.html @@ -0,0 +1,149 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.luabalanced

+

Extract delimited Lua sequences from strings.

+

Inspired by Damian Conway's Text::Balanced in Perl.
+

    +
  • [1] Lua Wiki Page
  • +
  • [2] http://search.cpan.org/dist/Text-Balanced/lib/Text/Balanced.pm
  • +

+
+ local lb = require "pl.luabalanced"
+ --Extract Lua expression starting at position 4.
+  print(lb.match_expression("if x^2 + x > 5 then print(x) end", 4))
+  --> x^2 + x > 5     16
+ --Extract Lua string starting at (default) position 1.
+ print(lb.match_string([["test\"123" .. "more"]]))
+ --> "test\"123"     12
+ 
+ (c) 2008, David Manura, Licensed under the same terms as Lua (MIT license).

+ + + +
+
+ + + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.operator.html b/Data/Libraries/Penlight/docs/libraries/pl.operator.html new file mode 100644 index 0000000..fdd4cfb --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.operator.html @@ -0,0 +1,819 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.operator

+

Lua operators available as functions.

+

(similar to the Python module of the same name)

+ +

There is a module field optable which maps the operator strings + onto these functions, e.g. operator.optable['()']==operator.call

+ +

Operator strings like '>' and '{}' can be passed to most Penlight functions + expecting a function argument.

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
call (fn, ...)apply function to some arguments ()
index (t, k)get the indexed value from a table []
eq (a, b)returns true if arguments are equal ==
neq (a, b)returns true if arguments are not equal ~=
lt (a, b)returns true if a is less than b <
le (a, b)returns true if a is less or equal to b <=
gt (a, b)returns true if a is greater than b >
ge (a, b)returns true if a is greater or equal to b >=
len (a)returns length of string or table #
add (a, b)add two values +
sub (a, b)subtract b from a -
mul (a, b)multiply two values *
div (a, b)divide first value by second /
pow (a, b)raise first to the power of second ^
mod (a, b)modulo; remainder of a divided by b %
concat (a, b)concatenate two values (either strings or __concat defined) ..
unm (a)return the negative of a value -
lnot (a)false if value evaluates as true not
land (a, b)true if both values evaluate as true and
lor (a, b)true if either value evaluate as true or
table (...)make a table from the arguments {}
match (a, b)match two strings ~.
nop (...)the null operation.
+

Tables

+ + + + + +
optableMap from operator symbol to function.
+ +
+
+ + +

Functions

+ +
+
+ + call (fn, ...) +
+
+ apply function to some arguments () + + +

Parameters:

+
    +
  • fn + a function or callable object +
  • +
  • ... + arguments +
  • +
+ + + + + +
+
+ + index (t, k) +
+
+ get the indexed value from a table [] + + +

Parameters:

+
    +
  • t + a table or any indexable object +
  • +
  • k + the key +
  • +
+ + + + + +
+
+ + eq (a, b) +
+
+ returns true if arguments are equal == + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + neq (a, b) +
+
+ returns true if arguments are not equal ~= + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + lt (a, b) +
+
+ returns true if a is less than b < + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + le (a, b) +
+
+ returns true if a is less or equal to b <= + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + gt (a, b) +
+
+ returns true if a is greater than b > + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + ge (a, b) +
+
+ returns true if a is greater or equal to b >= + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + len (a) +
+
+ returns length of string or table # + + +

Parameters:

+
    +
  • a + a string or a table +
  • +
+ + + + + +
+
+ + add (a, b) +
+
+ add two values + + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + sub (a, b) +
+
+ subtract b from a - + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + mul (a, b) +
+
+ multiply two values * + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + div (a, b) +
+
+ divide first value by second / + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + pow (a, b) +
+
+ raise first to the power of second ^ + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + mod (a, b) +
+
+ modulo; remainder of a divided by b % + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + concat (a, b) +
+
+ concatenate two values (either strings or __concat defined) .. + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + unm (a) +
+
+ return the negative of a value - + + +

Parameters:

+
    +
  • a + value +
  • +
+ + + + + +
+
+ + lnot (a) +
+
+ false if value evaluates as true not + + +

Parameters:

+
    +
  • a + value +
  • +
+ + + + + +
+
+ + land (a, b) +
+
+ true if both values evaluate as true and + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + lor (a, b) +
+
+ true if either value evaluate as true or + + +

Parameters:

+
    +
  • a + value +
  • +
  • b + value +
  • +
+ + + + + +
+
+ + table (...) +
+
+ make a table from the arguments {} + + +

Parameters:

+
    +
  • ... + non-nil arguments +
  • +
+ +

Returns:

+
    + + a table +
+ + + + +
+
+ + match (a, b) +
+
+ match two strings ~. + uses string.find + + +

Parameters:

+
    +
  • a + + + +
  • +
  • b + + + +
  • +
+ + + + + +
+
+ + nop (...) +
+
+ the null operation. + + +

Parameters:

+
    +
  • ... + arguments +
  • +
+ +

Returns:

+
    + + the arguments +
+ + + + +
+
+

Tables

+ +
+
+ + optable +
+
+ +

Map from operator symbol to function. + Most of these map directly from operators; + But note these extras

+ + + + + + +

Fields:

+
    +
  • operator + + + +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.path.html b/Data/Libraries/Penlight/docs/libraries/pl.path.html new file mode 100644 index 0000000..6345f6b --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.path.html @@ -0,0 +1,1070 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.path

+

Path manipulation and file queries.

+

This is modelled after Python's os.path library (10.1); see the Guide.

+ +

NOTE: the functions assume the paths being dealt with to originate + from the OS the application is running on. Windows drive letters are not + to be used when running on a Unix system for example. The one exception + is Windows paths to allow both forward and backward slashes (since Lua + also accepts those)

+ +

Dependencies: pl.utils, lfs

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
dir ()Lua iterator over the entries of a given directory.
mkdir ()Creates a directory.
rmdir ()Removes a directory.
attrib ()Gets attributes.
currentdir ()Get the working directory.
link_attrib ()Gets symlink attributes.
chdir ()Changes the working directory.
isdir (P)is this a directory?
isfile (P)is this a file?
getsize (P)return size of a file.
exists (P)does a path exist?
getatime (P)Return the time of last access as the number of seconds since the epoch.
getmtime (P)Return the time of last modification as the number of seconds since the epoch.
getctime (P)Return the system's ctime as the number of seconds since the epoch.
splitpath (P)given a path, return the directory part and a file part.
abspath (P[, pwd])return an absolute path.
splitext (P)given a path, return the root part and the extension part.
dirname (P)return the directory part of a path
basename (P)return the file part of a path
extension (P)get the extension part of a path.
isabs (P)is this an absolute path?
join (p1, p2, ...)return the path resulting from combining the individual paths.
normcase (P)normalize the case of a pathname.
normpath (P)normalize a path name.
relpath (P[, start])relative path from current directory or optional start point
expanduser (P)Replace a starting '~' with the user's home directory.
tmpname ()Return a suitable full path to a new temporary file name.
common_prefix (path1, path2)return the largest common prefix path of two paths.
package_path (mod)return the full path where a particular Lua module would be found.
+

Fields

+ + + + + + + + + + + + + +
is_windowsare we running Windows?
seppath separator for this platform.
dirsepseparator for PATH for this platform
+ +
+
+ + +

Functions

+ +
+
+ + dir () +
+
+ Lua iterator over the entries of a given directory. + Implicit link to luafilesystem.dir + + + + + + + +
+
+ + mkdir () +
+
+ Creates a directory. + Implicit link to luafilesystem.mkdir + + + + + + + +
+
+ + rmdir () +
+
+ Removes a directory. + Implicit link to luafilesystem.rmdir + + + + + + + +
+
+ + attrib () +
+
+ Gets attributes. + Implicit link to luafilesystem.attributes + + + + + + + +
+
+ + currentdir () +
+
+ Get the working directory. + Implicit link to luafilesystem.currentdir + + + + + + + +
+
+ + link_attrib () +
+
+ Gets symlink attributes. + Implicit link to luafilesystem.symlinkattributes + + + + + + + +
+
+ + chdir () +
+
+ Changes the working directory. + On Windows, if a drive is specified, it also changes the current drive. If + only specifying the drive, it will only switch drive, but not modify the path. + Implicit link to luafilesystem.chdir + + + + + + + +
+
+ + isdir (P) +
+
+ is this a directory? + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + + +
+
+ + isfile (P) +
+
+ is this a file? + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + + +
+
+ + getsize (P) +
+
+ return size of a file. + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + + +
+
+ + exists (P) +
+
+ does a path exist? + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ +

Returns:

+
    + + the file path if it exists (either as file, directory, socket, etc), nil otherwise +
+ + + + +
+
+ + getatime (P) +
+
+ Return the time of last access as the number of seconds since the epoch. + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + + +
+
+ + getmtime (P) +
+
+ Return the time of last modification as the number of seconds since the epoch. + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + + +
+
+ + getctime (P) +
+
+ Return the system's ctime as the number of seconds since the epoch. + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + + +
+
+ + splitpath (P) +
+
+ given a path, return the directory part and a file part. + if there's no directory part, the first value will be empty + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ +

Returns:

+
    +
  1. + directory part
  2. +
  3. + file part
  4. +
+ + + +

Usage:

+
    +
    local dir, file = path.splitpath("some/dir/myfile.txt")
    +assert(dir == "some/dir")
    +assert(file == "myfile.txt")
    +
    +local dir, file = path.splitpath("some/dir/")
    +assert(dir == "some/dir")
    +assert(file == "")
    +
    +local dir, file = path.splitpath("some_dir")
    +assert(dir == "")
    +assert(file == "some_dir")
    +
+ +
+
+ + abspath (P[, pwd]) +
+
+ return an absolute path. + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
  • pwd + string + optional start path to use (default is current dir) + (optional) +
  • +
+ + + + + +
+
+ + splitext (P) +
+
+ given a path, return the root part and the extension part. + if there's no extension part, the second value will be empty + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ +

Returns:

+
    +
  1. + string + root part (everything upto the "."", maybe empty)
  2. +
  3. + string + extension part (including the ".", maybe empty)
  4. +
+ + + +

Usage:

+
    +
    local file_path, ext = path.splitext("/bonzo/dog_stuff/cat.txt")
    +assert(file_path == "/bonzo/dog_stuff/cat")
    +assert(ext == ".txt")
    +
    +local file_path, ext = path.splitext("")
    +assert(file_path == "")
    +assert(ext == "")
    +
+ +
+
+ + dirname (P) +
+
+ return the directory part of a path + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ +

Returns:

+
    + + string + everything before the last dir-separator +
+ + +

See also:

+ + +

Usage:

+
    +
    path.dirname("/some/path/file.txt")   -- "/some/path"
    +path.dirname("file.txt")              -- "" (empty string)
    +
+ +
+
+ + basename (P) +
+
+ return the file part of a path + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ +

Returns:

+
    + + string + + + +
+ + +

See also:

+ + +

Usage:

+
    +
    path.basename("/some/path/file.txt")  -- "file.txt"
    +path.basename("/some/path/file/")     -- "" (empty string)
    +
+ +
+
+ + extension (P) +
+
+ get the extension part of a path. + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ +

Returns:

+
    + + string + + + +
+ + +

See also:

+ + +

Usage:

+
    +
    path.extension("/some/path/file.txt") -- ".txt"
    +path.extension("/some/path/file_txt") -- "" (empty string)
    +
+ +
+
+ + isabs (P) +
+
+ is this an absolute path? + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + +

Usage:

+
    +
    path.isabs("hello/path")    -- false
    +path.isabs("/hello/path")   -- true
    +-- Windows;
    +path.isabs("hello\path")    -- false
    +path.isabs("\hello\path")   -- true
    +path.isabs("C:\hello\path") -- true
    +path.isabs("C:hello\path")  -- false
    +
+ +
+
+ + join (p1, p2, ...) +
+
+ return the path resulting from combining the individual paths. + if the second (or later) path is absolute, we return the last absolute path (joined with any non-absolute paths following). + empty elements (except the last) will be ignored. + + +

Parameters:

+
    +
  • p1 + string + A file path +
  • +
  • p2 + string + A file path +
  • +
  • ... + string + more file paths +
  • +
+ +

Returns:

+
    + + string + the combined path +
+ + + +

Usage:

+
    +
    path.join("/first","second","third")   -- "/first/second/third"
    +path.join("first","second/third")      -- "first/second/third"
    +path.join("/first","/second","third")  -- "/second/third"
    +
+ +
+
+ + normcase (P) +
+
+ +

normalize the case of a pathname. On Unix, this returns the path unchanged, + for Windows it converts;

+ +
    +
  • the path to lowercase
  • +
  • forward slashes to backward slashes
  • +
+ + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + +

Usage:

+
    +
    path.normcase("/Some/Path/File.txt")
    +-- Windows: "\some\path\file.txt"
    +-- Others : "/Some/Path/File.txt"
    +
+ +
+
+ + normpath (P) +
+
+ normalize a path name. + A//B, A/./B, and A/foo/../B all become A/B.

+ +

An empty path results in '.'. + + +

Parameters:

+
    +
  • P + string + a file path +
  • +
+ + + + + +
+
+ + relpath (P[, start]) +
+
+ relative path from current directory or optional start point + + +

Parameters:

+
    +
  • P + string + a path +
  • +
  • start + string + optional start point (default current directory) + (optional) +
  • +
+ + + + + +
+
+ + expanduser (P) +
+
+ Replace a starting '~' with the user's home directory. + In windows, if HOME isn't set, then USERPROFILE is used in preference to + HOMEDRIVE HOMEPATH. This is guaranteed to be writeable on all versions of Windows. + + +

Parameters:

+
    +
  • P + string + A file path +
  • +
+ + + + + +
+
+ + tmpname () +
+
+ Return a suitable full path to a new temporary file name. + unlike os.tmpname(), it always gives you a writeable path (uses TEMP environment variable on Windows) + + + + + + + +
+
+ + common_prefix (path1, path2) +
+
+ return the largest common prefix path of two paths. + + +

Parameters:

+
    +
  • path1 + string + a file path +
  • +
  • path2 + string + a file path +
  • +
+ +

Returns:

+
    + + the common prefix (Windows: separators will be normalized, casing will be original) +
+ + + + +
+
+ + package_path (mod) +
+
+ return the full path where a particular Lua module would be found. + Both package.path and package.cpath is searched, so the result may + either be a Lua file or a shared library. + + +

Parameters:

+
    +
  • mod + string + name of the module +
  • +
+ +

Returns:

+
    +
  1. + on success: path of module, lua or binary
  2. +
  3. + on error: nil, error string listing paths tried
  4. +
+ + + + +
+
+

Fields

+ +
+
+ + is_windows +
+
+ are we running Windows? + + + + + + + +
+
+ + sep +
+
+ path separator for this platform. + + + + + + + +
+
+ + dirsep +
+
+ separator for PATH for this platform + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.permute.html b/Data/Libraries/Penlight/docs/libraries/pl.permute.html new file mode 100644 index 0000000..afb887e --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.permute.html @@ -0,0 +1,354 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.permute

+

Permutation operations.

+

Dependencies: pl.utils, pl.tablex

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + +
order_iter (a)an iterator over all order-permutations of the elements of a list.
order_table (a)construct a table containing all the order-permutations of a list.
list_iter (...)an iterator over all permutations of the elements of the given lists.
list_table (...)construct a table containing all the permutations of a set of lists.
iter (...)deprecated.
table (...)deprecated.
+ +
+
+ + +

Functions

+ +
+
+ + order_iter (a) +
+
+ an iterator over all order-permutations of the elements of a list. + Please note that the same list is returned each time, so do not keep references! + + +

Parameters:

+
    +
  • a + list-like table +
  • +
+ +

Returns:

+
    + + an iterator which provides the next permutation as a list +
+ + + + +
+
+ + order_table (a) +
+
+ construct a table containing all the order-permutations of a list. + + +

Parameters:

+
    +
  • a + list-like table +
  • +
+ +

Returns:

+
    + + a table of tables +
+ + + +

Usage:

+
    +
    permute.order_table {1,2,3} --> {{2,3,1},{3,2,1},{3,1,2},{1,3,2},{2,1,3},{1,2,3}}
    +
+ +
+
+ + list_iter (...) +
+
+ an iterator over all permutations of the elements of the given lists. + + +

Parameters:

+
    +
  • ... + list-like tables, they are nil-safe if a length-field n is provided (see utils.pack) +
  • +
+ +

Returns:

+
    + + an iterator which provides the next permutation as return values in the same order as the provided lists, preceeded by an index +
+ + + +

Usage:

+
    +
    local strs = utils.pack("one", nil, "three")  -- adds an 'n' field for nil-safety
    +local bools = utils.pack(true, false)
    +local iter = permute.list_iter(strs, bools)
    +
    +print(iter())    --> 1, one, true
    +print(iter())    --> 2, nil, true
    +print(iter())    --> 3, three, true
    +print(iter())    --> 4, one, false
    +print(iter())    --> 5, nil, false
    +print(iter())    --> 6, three, false
    +
+ +
+
+ + list_table (...) +
+
+ construct a table containing all the permutations of a set of lists. + + +

Parameters:

+
    +
  • ... + list-like tables, they are nil-safe if a length-field n is provided +
  • +
+ +

Returns:

+
    + + a list of lists, the sub-lists have an 'n' field for nil-safety +
+ + + +

Usage:

+
    +
    local strs = utils.pack("one", nil, "three")  -- adds an 'n' field for nil-safety
    +local bools = utils.pack(true, false)
    +local results = permute.list_table(strs, bools)
    +-- results = {
    +--   { "one, true, n = 2 }
    +--   { nil, true, n = 2 },
    +--   { "three, true, n = 2 },
    +--   { "one, false, n = 2 },
    +--   { nil, false, n = 2 },
    +--   { "three", false, n = 2 },
    +-- }
    +
+ +
+
+ + iter (...) +
+
+ deprecated. + + +

Parameters:

+
    +
  • ... + + + +
  • +
+ + + +

See also:

+ + + +
+
+ + table (...) +
+
+ deprecated. + + +

Parameters:

+
    +
  • ... + + + +
  • +
+ + + +

See also:

+ + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.pretty.html b/Data/Libraries/Penlight/docs/libraries/pl.pretty.html new file mode 100644 index 0000000..4561699 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.pretty.html @@ -0,0 +1,402 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.pretty

+

Pretty-printing Lua tables.

+

Also provides a sandboxed Lua table reader and + a function to present large numbers in human-friendly format.

+ +

Dependencies: pl.utils, pl.lexer, pl.stringx, debug

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + +
read (s)Read a string representation of a Lua table.
load (s[, env[, paranoid]])Read a Lua chunk.
write (tbl[, space[, not_clever]])Create a string representation of a Lua table.
dump (t[, filename])Dump a Lua table out to a file or stdout.
debug (...)Dump a series of arguments to stdout for debug purposes.
number (num[, kind[, prec]])Format large numbers nicely for human consumption.
+ +
+
+ + +

Functions

+ +
+
+ + read (s) +
+
+ Read a string representation of a Lua table. + This function loads and runs the string as Lua code, but bails out + if it contains a function definition. + Loaded string is executed in an empty environment. + + +

Parameters:

+
    +
  • s + string + string to read in {...} format, possibly with some whitespace + before or after the curly braces. A single line comment may be present + at the beginning. +
  • +
+ +

Returns:

+
    + + a table in case of success. + If loading the string failed, return nil and error message. + If executing loaded string failed, return nil and the error it raised. +
+ + + + +
+
+ + load (s[, env[, paranoid]]) +
+
+ Read a Lua chunk. + + +

Parameters:

+
    +
  • s + string + Lua code. +
  • +
  • env + tab + environment used to run the code, empty by default. + (optional) +
  • +
  • paranoid + bool + abort loading if any looping constructs a found in the code + and disable string methods. + (optional) +
  • +
+ +

Returns:

+
    + + the environment in case of success or nil and syntax or runtime error + if something went wrong. +
+ + + + +
+
+ + write (tbl[, space[, not_clever]]) +
+
+ Create a string representation of a Lua table. + This function never fails, but may complain by returning an + extra value. Normally puts out one item per line, using + the provided indent; set the second parameter to an empty string + if you want output on one line.

+ +

NOTE: this is NOT a serialization function, not a full blown + debug function. Checkout out respectively the + serpent + or inspect + Lua modules for that if you need them. + + +

Parameters:

+
    +
  • tbl + tab + Table to serialize to a string. +
  • +
  • space + string + The indent to use. + Defaults to two spaces; pass an empty string for no indentation. + (optional) +
  • +
  • not_clever + bool + Pass true for plain output, e.g {['key']=1}. + Defaults to false. + (optional) +
  • +
+ +

Returns:

+
    +
  1. + a string
  2. +
  3. + an optional error message
  4. +
+ + + + +
+
+ + dump (t[, filename]) +
+
+ Dump a Lua table out to a file or stdout. + + +

Parameters:

+
    +
  • t + tab + The table to write to a file or stdout. +
  • +
  • filename + string + File name to write too. Defaults to writing + to stdout. + (optional) +
  • +
+ + + + + +
+
+ + debug (...) +
+
+ Dump a series of arguments to stdout for debug purposes. + This function is attached to the module table __call method, to make it + extra easy to access. So the full:

+ +
 print(require("pl.pretty").write({...}))
+
+ +

Can be shortened to:

+ +
 require"pl.pretty" (...)
+
+ +

Any nil entries will be printed as "<nil>" to make them explicit. + + +

Parameters:

+
    +
  • ... + the parameters to dump to stdout. +
  • +
+ + + + +

Usage:

+
    +
    -- example debug output
    +require"pl.pretty" ("hello", nil, "world", { bye = "world", true} )
    +
    +-- output:
    +{
    +  ["arg 1"] = "hello",
    +  ["arg 2"] = "<nil>",
    +  ["arg 3"] = "world",
    +  ["arg 4"] = {
    +    true,
    +    bye = "world"
    +  }
    +}
    +
+ +
+
+ + number (num[, kind[, prec]]) +
+
+ Format large numbers nicely for human consumption. + + +

Parameters:

+
    +
  • num + number + a number. +
  • +
  • kind + string + one of 'M' (memory in KiB, MiB, etc.), + 'N' (postfixes are 'K', 'M' and 'B'), + or 'T' (use commas as thousands separator), 'N' by default. + (optional) +
  • +
  • prec + int + number of digits to use for 'M' and 'N', 1 by default. + (optional) +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.seq.html b/Data/Libraries/Penlight/docs/libraries/pl.seq.html new file mode 100644 index 0000000..e694581 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.seq.html @@ -0,0 +1,888 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.seq

+

Manipulating iterators as sequences.

+

See The Guide

+ +

Dependencies: pl.utils, pl.types, debug

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matching (s)given a string, return a function(y) which matches y against the string.
list (t)sequence adaptor for a table.
keys (t)return the keys of the table.
range (start, finish)create an iterator over a numerical range.
minmax (iter)return the minimum and the maximum value of the sequence.
sum (iter, fn)return the sum and element count of the sequence.
copy (iter)create a table from the sequence.
copy2 (iter, i1, i2)create a table of pairs from the double-valued sequence.
copy_tuples (iter)create a table of 'tuples' from a multi-valued sequence.
random (n, l, u)return an iterator of random numbers.
sort (iter, comp)return an iterator to the sorted elements of a sequence.
zip (iter1, iter2)return an iterator which returns elements of two sequences.
count_map (iter)Makes a table where the key/values are the values and value counts of the sequence.
printall (iter, sep, nfields, fmt)print out a sequence iter with a separator.
map (fn, iter, arg)return a sequence where every element of a sequence has been transformed + by a function.
filter (iter, pred, arg)filter a sequence using a predicate function.
reduce (fn, iter, initval)'reduce' a sequence using a binary function.
take (iter, n)take the first n values from the sequence.
skip (iter, n)skip the first n values of a sequence
enum (iter)a sequence with a sequence count and the original value.
mapmethod (iter, name, arg1, arg2)map using a named method over a sequence.
last (iter)a sequence of (last,current) values from another sequence.
foreach (iter, fn)call the function on each element of the sequence.
lines (f, ...)create a wrapped iterator over all lines in the file.
+ +
+
+ + +

Functions

+ +
+
+ + matching (s) +
+
+ given a string, return a function(y) which matches y against the string. + + +

Parameters:

+
    +
  • s + a string +
  • +
+ + + + + +
+
+ + list (t) +
+
+ sequence adaptor for a table. Note that if any generic function is + passed a table, it will automatically use seq.list() + + +

Parameters:

+
    +
  • t + a list-like table +
  • +
+ + + + +

Usage:

+
    +
  • sum(list(t)) is the sum of all elements of t
  • +
  • for x in list(t) do...end
  • +
+ +
+
+ + keys (t) +
+
+ return the keys of the table. + + +

Parameters:

+
    +
  • t + an arbitrary table +
  • +
+ +

Returns:

+
    + + iterator over keys +
+ + + + +
+
+ + range (start, finish) +
+
+ create an iterator over a numerical range. Like the standard Python function xrange. + + +

Parameters:

+
    +
  • start + a number +
  • +
  • finish + a number greater than start +
  • +
+ + + + + +
+
+ + minmax (iter) +
+
+ return the minimum and the maximum value of the sequence. + + +

Parameters:

+
    +
  • iter + a sequence +
  • +
+ +

Returns:

+
    +
  1. + minimum value
  2. +
  3. + maximum value
  4. +
+ + + + +
+
+ + sum (iter, fn) +
+
+ return the sum and element count of the sequence. + + +

Parameters:

+
    +
  • iter + a sequence +
  • +
  • fn + an optional function to apply to the values +
  • +
+ + + + + +
+
+ + copy (iter) +
+
+ create a table from the sequence. (This will make the result a List.) + + +

Parameters:

+
    +
  • iter + a sequence +
  • +
+ +

Returns:

+
    + + a List +
+ + + +

Usage:

+
    +
  • copy(list(ls)) is equal to ls
  • +
  • copy(list {1,2,3}) == List{1,2,3}
  • +
+ +
+
+ + copy2 (iter, i1, i2) +
+
+ create a table of pairs from the double-valued sequence. + + +

Parameters:

+
    +
  • iter + a double-valued sequence +
  • +
  • i1 + used to capture extra iterator values +
  • +
  • i2 + as with pairs & ipairs +
  • +
+ +

Returns:

+
    + + a list-like table +
+ + + +

Usage:

+
    +
    copy2(ipairs{10,20,30}) == {{1,10},{2,20},{3,30}}
    +
+ +
+
+ + copy_tuples (iter) +
+
+ create a table of 'tuples' from a multi-valued sequence. + A generalization of copy2 above + + +

Parameters:

+
    +
  • iter + a multiple-valued sequence +
  • +
+ +

Returns:

+
    + + a list-like table +
+ + + + +
+
+ + random (n, l, u) +
+
+ return an iterator of random numbers. + + +

Parameters:

+
    +
  • n + the length of the sequence +
  • +
  • l + same as the first optional argument to math.random +
  • +
  • u + same as the second optional argument to math.random +
  • +
+ +

Returns:

+
    + + a sequence +
+ + + + +
+
+ + sort (iter, comp) +
+
+ return an iterator to the sorted elements of a sequence. + + +

Parameters:

+
    +
  • iter + a sequence +
  • +
  • comp + an optional comparison function (comp(x,y) is true if x < y) +
  • +
+ + + + + +
+
+ + zip (iter1, iter2) +
+
+ return an iterator which returns elements of two sequences. + + +

Parameters:

+
    +
  • iter1 + a sequence +
  • +
  • iter2 + a sequence +
  • +
+ + + + +

Usage:

+
    +
    for x,y in seq.zip(ls1,ls2) do....end
    +
+ +
+
+ + count_map (iter) +
+
+ Makes a table where the key/values are the values and value counts of the sequence. + This version works with 'hashable' values like strings and numbers. + pl.tablex.count_map is more general. + + +

Parameters:

+
    +
  • iter + a sequence +
  • +
+ +

Returns:

+
    +
  1. + a map-like table
  2. +
  3. + a table
  4. +
+ + +

See also:

+ + + +
+
+ + printall (iter, sep, nfields, fmt) +
+
+ print out a sequence iter with a separator. + + +

Parameters:

+
    +
  • iter + a sequence +
  • +
  • sep + the separator (default space) +
  • +
  • nfields + maximum number of values per line (default 7) +
  • +
  • fmt + optional format function for each value +
  • +
+ + + + + +
+
+ + map (fn, iter, arg) +
+
+ return a sequence where every element of a sequence has been transformed + by a function. If you don't supply an argument, then the function will + receive both values of a double-valued sequence, otherwise behaves rather like + tablex.map. + + +

Parameters:

+
    +
  • fn + a function to apply to elements; may take two arguments +
  • +
  • iter + a sequence of one or two values +
  • +
  • arg + optional argument to pass to function. +
  • +
+ + + + + +
+
+ + filter (iter, pred, arg) +
+
+ filter a sequence using a predicate function. + + +

Parameters:

+
    +
  • iter + a sequence of one or two values +
  • +
  • pred + a boolean function; may take two arguments +
  • +
  • arg + optional argument to pass to function. +
  • +
+ + + + + +
+
+ + reduce (fn, iter, initval) +
+
+ 'reduce' a sequence using a binary function. + + +

Parameters:

+
    +
  • fn + func + a function of two arguments +
  • +
  • iter + a sequence +
  • +
  • initval + optional initial value +
  • +
+ + + + +

Usage:

+
    +
  • seq.reduce(operator.add,seq.list{1,2,3,4}) == 10
  • +
  • seq.reduce('-',{1,2,3,4,5}) == -13
  • +
+ +
+
+ + take (iter, n) +
+
+ take the first n values from the sequence. + + +

Parameters:

+
    +
  • iter + a sequence of one or two values +
  • +
  • n + number of items to take +
  • +
+ +

Returns:

+
    + + a sequence of at most n items +
+ + + + +
+
+ + skip (iter, n) +
+
+ skip the first n values of a sequence + + +

Parameters:

+
    +
  • iter + a sequence of one or more values +
  • +
  • n + number of items to skip +
  • +
+ + + + + +
+
+ + enum (iter) +
+
+ a sequence with a sequence count and the original value. + enum(copy(ls)) is a roundabout way of saying ipairs(ls). + + +

Parameters:

+
    +
  • iter + a single or double valued sequence +
  • +
+ +

Returns:

+
    + + sequence of (i,v), i = 1..n and v is from iter. +
+ + + + +
+
+ + mapmethod (iter, name, arg1, arg2) +
+
+ map using a named method over a sequence. + + +

Parameters:

+
    +
  • iter + a sequence +
  • +
  • name + the method name +
  • +
  • arg1 + optional first extra argument +
  • +
  • arg2 + optional second extra argument +
  • +
+ + + + + +
+
+ + last (iter) +
+
+ a sequence of (last,current) values from another sequence. + This will return S(i-1),S(i) if given S(i) + + +

Parameters:

+
    +
  • iter + a sequence +
  • +
+ + + + + +
+
+ + foreach (iter, fn) +
+
+ call the function on each element of the sequence. + + +

Parameters:

+
    +
  • iter + a sequence with up to 3 values +
  • +
  • fn + a function +
  • +
+ + + + + +
+
+ + lines (f, ...) +
+
+ create a wrapped iterator over all lines in the file. + + +

Parameters:

+
    +
  • f + either a filename, file-like object, or 'STDIN' (for standard input) +
  • +
  • ... + for Lua 5.2 only, optional format specifiers, as in io.read. +
  • +
+ +

Returns:

+
    + + a sequence wrapper +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.sip.html b/Data/Libraries/Penlight/docs/libraries/pl.sip.html new file mode 100644 index 0000000..d488b09 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.sip.html @@ -0,0 +1,399 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.sip

+

Simple Input Patterns (SIP).

+

SIP patterns start with '$', then a + one-letter type, and then an optional variable in curly braces.

+ + +
+sip.match('$v=$q','name="dolly"',res)
+==> res=={'name','dolly'}
+sip.match('($q{first},$q{second})','("john","smith")',res)
+==> res=={second='smith',first='john'}
+
+ +

Type names:

+ + +
+v     identifier
+i     integer
+f     floating-point
+q     quoted string
+([{<  match up to closing bracket
+
+ +

See the Guide

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
create_pattern (spec, options)convert a SIP pattern into the equivalent Lua string pattern.
compile (spec, options)convert a SIP pattern into a matching function.
match (spec, line, res, options)match a SIP pattern against a string.
match_at_start (spec, line, res)match a SIP pattern against the start of a string.
fields (spec, f)given a pattern and a file object, return an iterator over the results
pattern (spec, fun)register a match which will be used in the read function.
read (f, matches)enter a loop which applies all registered matches to the input file.
+ +
+
+ + +

Functions

+ +
+
+ + create_pattern (spec, options) +
+
+ convert a SIP pattern into the equivalent Lua string pattern. + + +

Parameters:

+
    +
  • spec + a SIP pattern +
  • +
  • options + a table; only the at_start field is + currently meaningful and ensures that the pattern is anchored + at the start of the string. +
  • +
+ +

Returns:

+
    + + a Lua string pattern. +
+ + + + +
+
+ + compile (spec, options) +
+
+ convert a SIP pattern into a matching function. + The returned function takes two arguments, the line and an empty table. + If the line matched the pattern, then this function returns true + and the table is filled with field-value pairs. + + +

Parameters:

+
    +
  • spec + a SIP pattern +
  • +
  • options + optional table; {at_start=true} ensures that the pattern + is anchored at the start of the string. +
  • +
+ +

Returns:

+
    + + a function if successful, or nil,error +
+ + + + +
+
+ + match (spec, line, res, options) +
+
+ match a SIP pattern against a string. + + +

Parameters:

+
    +
  • spec + a SIP pattern +
  • +
  • line + a string +
  • +
  • res + a table to receive values +
  • +
  • options + (optional) option table +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + match_at_start (spec, line, res) +
+
+ match a SIP pattern against the start of a string. + + +

Parameters:

+
    +
  • spec + a SIP pattern +
  • +
  • line + a string +
  • +
  • res + a table to receive values +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + fields (spec, f) +
+
+ given a pattern and a file object, return an iterator over the results + + +

Parameters:

+
    +
  • spec + a SIP pattern +
  • +
  • f + a file-like object. +
  • +
+ + + + + +
+
+ + pattern (spec, fun) +
+
+ register a match which will be used in the read function. + + +

Parameters:

+
    +
  • spec + string + a SIP pattern +
  • +
  • fun + func + a function to be called with the results of the match +
  • +
+ + + +

See also:

+ + + +
+
+ + read (f, matches) +
+
+ enter a loop which applies all registered matches to the input file. + + +

Parameters:

+
    +
  • f + a file-like object +
  • +
  • matches + array + optional list of {spec,fun} pairs, as for pattern above. +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.strict.html b/Data/Libraries/Penlight/docs/libraries/pl.strict.html new file mode 100644 index 0000000..3c9c0bd --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.strict.html @@ -0,0 +1,270 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.strict

+

Checks uses of undeclared global variables.

+

All global variables must be 'declared' through a regular assignment + (even assigning nil will do) in a main chunk before being used + anywhere or assigned to inside a function. Existing metatables __newindex and __index + metamethods are respected.

+ +

You can set any table to have strict behaviour using strict.module. Creating a new + module with strict.closed_module makes the module immune to monkey-patching, if + you don't wish to encourage monkey business.

+ +

If the global PENLIGHT_NO_GLOBAL_STRICT is defined, then this module won't make the + global environment strict - if you just want to explicitly set table strictness.

+ + +

Functions

+ + + + + + + + + + + + + +
module ([name[, mod[, predeclared]]])make an existing table strict.
make_all_strict (T)make all tables in a table strict.
closed_module (mod, name)make a new module table which is closed to further changes.
+ +
+
+ + +

Functions

+ +
+
+ + module ([name[, mod[, predeclared]]]) +
+
+ make an existing table strict. + + +

Parameters:

+
    +
  • name + string + name of table + (optional) +
  • +
  • mod + tab + the table to protect - if nil then we'll return a new table + (optional) +
  • +
  • predeclared + tab + +
      +
    • table of variables that are to be considered predeclared.
    • +
    + + (optional) +
  • +
+ +

Returns:

+
    + + the given table, or a new table +
+ + + +

Usage:

+
    +
    local M = { hello = "world" }
    +strict.module ("Awesome_Module", M, {
    +  Lua = true,  -- defines allowed keys
    +})
    +
    +assert(M.hello == "world")
    +assert(M.Lua == nil)       -- access allowed, but has no value yet
    +M.Lua = "Rocks"
    +assert(M.Lua == "Rocks")
    +M.not_allowed = "bad boy"  -- throws an error
    +
+ +
+
+ + make_all_strict (T) +
+
+ make all tables in a table strict. + So strict.make_all_strict(_G) prevents monkey-patching + of any global table + + +

Parameters:

+
    +
  • T + tab + the table containing the tables to protect. Table T itself will NOT be protected. +
  • +
+ + + + + +
+
+ + closed_module (mod, name) +
+
+ make a new module table which is closed to further changes. + + +

Parameters:

+
    +
  • mod + tab + module table +
  • +
  • name + string + module name +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.stringio.html b/Data/Libraries/Penlight/docs/libraries/pl.stringio.html new file mode 100644 index 0000000..7505d34 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.stringio.html @@ -0,0 +1,215 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.stringio

+

Reading and writing strings using file-like objects.

+


+ + +
+f = stringio.open(text)
+l1 = f:read()  -- read first line
+n,m = f:read ('*n','*n') -- read two numbers
+for line in f:lines() do print(line) end -- iterate over all lines
+f = stringio.create()
+f:write('hello')
+f:write('dolly')
+assert(f:value(),'hellodolly')
+
+ +

See the Guide.

+ + +

Functions

+ + + + + + + + + +
create ()create a file-like object which can be used to construct a string.
open (s)create a file-like object for reading from a given string.
+ +
+
+ + +

Functions

+ +
+
+ + create () +
+
+ create a file-like object which can be used to construct a string. + The resulting object has an extra value() method for + retrieving the string value. Implements file:write, file:seek, file:lines, + plus an extra writef method which works like utils.printf. + + + + + + +

Usage:

+
    +
    f = create(); f:write('hello, dolly\n'); print(f:value())
    +
+ +
+
+ + open (s) +
+
+ create a file-like object for reading from a given string. + Implements file:read. + + +

Parameters:

+
    +
  • s + string + The input string. +
  • +
+ + + + +

Usage:

+
    +
    fs = open '20 10'; x,y = f:read ('*n','*n'); assert(x == 20 and y == 10)
    +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.stringx.html b/Data/Libraries/Penlight/docs/libraries/pl.stringx.html new file mode 100644 index 0000000..4fd08cd --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.stringx.html @@ -0,0 +1,1239 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.stringx

+

Python-style extended string library.

+

see 3.6.1 of the Python reference. + If you want to make these available as string methods, then say + stringx.import() to bring them into the standard string table.

+ +

See the Guide

+ +

Dependencies: pl.utils

+ + +

String Predicates

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
isalpha (s)does s only contain alphabetic characters?
isdigit (s)does s only contain digits?
isalnum (s)does s only contain alphanumeric characters?
isspace (s)does s only contain spaces?
islower (s)does s only contain lower case characters?
isupper (s)does s only contain upper case characters?
startswith (s, prefix)does s start with prefix or one of prefixes?
endswith (s, suffix)does s end with suffix or one of suffixes?
+

Strings and Lists

+ + + + + + + + + + + + + + + + + +
join (s, seq)concatenate the strings using this string as a delimiter.
splitlines (s[, keep_ends])Split a string into a list of lines.
split (s[, re[, n]])split a string into a list of strings using a delimiter.
expandtabs (s, tabsize)replace all tabs in s with tabsize spaces.
+

Finding and Replacing

+ + + + + + + + + + + + + + + + + +
lfind (s, sub[, first[, last]])find index of first instance of sub in s from the left.
rfind (s, sub[, first[, last]])find index of first instance of sub in s from the right.
replace (s, old, new[, n])replace up to n instances of old by new in the string s.
count (s, sub[, allow_overlap])count all instances of substring in string.
+

Stripping and Justifying

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ljust (s, w[, ch=' '])left-justify s with width w.
rjust (s, w[, ch=' '])right-justify s with width w.
center (s, w[, ch=' '])center-justify s with width w.
lstrip (s[, chrs='%s'])trim any whitespace on the left of s.
rstrip (s[, chrs='%s'])trim any whitespace on the right of s.
strip (s[, chrs='%s'])trim any whitespace on both left and right of s.
+

Partioning Strings

+ + + + + + + + + + + + + + + + + +
splitv (s[, re='%s'])split a string using a pattern.
partition (s, ch)partition the string using first occurance of a delimiter
rpartition (s, ch)partition the string p using last occurance of a delimiter
at (s, idx)return the 'character' at the index.
+

Miscelaneous

+ + + + + + + + + + + + + + + + + +
lines (s)return an iterator over all lines in a string
title (s)inital word letters uppercase ('title case').
shorten (s, w, tail)Return a shortened version of a string.
quote_string (s)Quote the given string and preserve any control or escape characters, such that reloading the string in Lua returns the same result.
+ +
+
+ + +

String Predicates

+ +
+
+ + isalpha (s) +
+
+ does s only contain alphabetic characters? + + +

Parameters:

+ + + + + + +
+
+ + isdigit (s) +
+
+ does s only contain digits? + + +

Parameters:

+ + + + + + +
+
+ + isalnum (s) +
+
+ does s only contain alphanumeric characters? + + +

Parameters:

+ + + + + + +
+
+ + isspace (s) +
+
+ does s only contain spaces? + + +

Parameters:

+ + + + + + +
+
+ + islower (s) +
+
+ does s only contain lower case characters? + + +

Parameters:

+ + + + + + +
+
+ + isupper (s) +
+
+ does s only contain upper case characters? + + +

Parameters:

+ + + + + + +
+
+ + startswith (s, prefix) +
+
+ does s start with prefix or one of prefixes? + + +

Parameters:

+
    +
  • s + string + a string +
  • +
  • prefix + a string or an array of strings +
  • +
+ + + + + +
+
+ + endswith (s, suffix) +
+
+ does s end with suffix or one of suffixes? + + +

Parameters:

+
    +
  • s + string + a string +
  • +
  • suffix + a string or an array of strings +
  • +
+ + + + + +
+
+

Strings and Lists

+ +
+
+ + join (s, seq) +
+
+ concatenate the strings using this string as a delimiter. + Note that the arguments are reversed from string.concat. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • seq + a table of strings or numbers +
  • +
+ + + + +

Usage:

+
    +
    stringx.join(' ', {1,2,3}) == '1 2 3'
    +
+ +
+
+ + splitlines (s[, keep_ends]) +
+
+ Split a string into a list of lines. + "\r", "\n", and "\r\n" are considered line ends. + They are not included in the lines unless keepends is passed. + Terminal line end does not produce an extra line. + Splitting an empty string results in an empty list. + + +

Parameters:

+
    +
  • s + string + the string. +
  • +
  • keep_ends + bool + include line ends. + (optional) +
  • +
+ +

Returns:

+
    + + List of lines +
+ + + + +
+
+ + split (s[, re[, n]]) +
+
+ split a string into a list of strings using a delimiter. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • re + string + a delimiter (defaults to whitespace) + (optional) +
  • +
  • n + int + maximum number of results + (optional) +
  • +
+ +

Returns:

+
    + + List +
+ + + +

Usage:

+
    +
  • #(stringx.split('one two')) == 2
  • +
  • stringx.split('one,two,three', ',') == List{'one','two','three'}
  • +
  • stringx.split('one,two,three', ',', 2) == List{'one','two,three'}
  • +
+ +
+
+ + expandtabs (s, tabsize) +
+
+ replace all tabs in s with tabsize spaces. If not specified, tabsize defaults to 8. + Tab stops will be honored. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • tabsize + int + [opt=8] number of spaces to expand each tab +
  • +
+ +

Returns:

+
    + + expanded string +
+ + + +

Usage:

+
    +
  • stringx.expandtabs('\tone,two,three', 4)   == '    one,two,three'
  • +
  • stringx.expandtabs('  \tone,two,three', 4) == '    one,two,three'
  • +
+ +
+
+

Finding and Replacing

+ +
+
+ + lfind (s, sub[, first[, last]]) +
+
+ find index of first instance of sub in s from the left. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • sub + string + substring +
  • +
  • first + int + first index + (optional) +
  • +
  • last + int + last index + (optional) +
  • +
+ +

Returns:

+
    + + start index, or nil if not found +
+ + + + +
+
+ + rfind (s, sub[, first[, last]]) +
+
+ find index of first instance of sub in s from the right. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • sub + string + substring +
  • +
  • first + int + first index + (optional) +
  • +
  • last + int + last index + (optional) +
  • +
+ +

Returns:

+
    + + start index, or nil if not found +
+ + + + +
+
+ + replace (s, old, new[, n]) +
+
+ replace up to n instances of old by new in the string s. + If n is not present, replace all instances. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • old + string + the target substring +
  • +
  • new + string + the substitution +
  • +
  • n + int + optional maximum number of substitutions + (optional) +
  • +
+ +

Returns:

+
    + + result string +
+ + + + +
+
+ + count (s, sub[, allow_overlap]) +
+
+ count all instances of substring in string. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • sub + string + substring +
  • +
  • allow_overlap + bool + allow matches to overlap + (optional) +
  • +
+ + + + +

Usage:

+
    +
    assert(stringx.count('banana', 'ana') == 1)
    +assert(stringx.count('banana', 'ana', true) == 2)
    +
+ +
+
+

Stripping and Justifying

+ +
+
+ + ljust (s, w[, ch=' ']) +
+
+ left-justify s with width w. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • w + int + width of justification +
  • +
  • ch + string + padding character + (default ' ') +
  • +
+ + + + +

Usage:

+
    +
    stringx.ljust('hello', 10, '*') == '*****hello'
    +
+ +
+
+ + rjust (s, w[, ch=' ']) +
+
+ right-justify s with width w. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • w + int + width of justification +
  • +
  • ch + string + padding character + (default ' ') +
  • +
+ + + + +

Usage:

+
    +
    stringx.rjust('hello', 10, '*') == 'hello*****'
    +
+ +
+
+ + center (s, w[, ch=' ']) +
+
+ center-justify s with width w. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • w + int + width of justification +
  • +
  • ch + string + padding character + (default ' ') +
  • +
+ + + + +

Usage:

+
    +
    stringx.center('hello', 10, '*') == '**hello***'
    +
+ +
+
+ + lstrip (s[, chrs='%s']) +
+
+ trim any whitespace on the left of s. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • chrs + string + default any whitespace character, + but can be a string of characters to be trimmed + (default '%s') +
  • +
+ + + + + +
+
+ + rstrip (s[, chrs='%s']) +
+
+ trim any whitespace on the right of s. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • chrs + string + default any whitespace character, + but can be a string of characters to be trimmed + (default '%s') +
  • +
+ + + + + +
+
+ + strip (s[, chrs='%s']) +
+
+ trim any whitespace on both left and right of s. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • chrs + string + default any whitespace character, + but can be a string of characters to be trimmed + (default '%s') +
  • +
+ + + + + +
+
+

Partioning Strings

+ +
+
+ + splitv (s[, re='%s']) +
+
+ split a string using a pattern. Note that at least one value will be returned! + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • re + string + a Lua string pattern (defaults to whitespace) + (default '%s') +
  • +
+ +

Returns:

+
    + + the parts of the string +
+ + +

See also:

+ + +

Usage:

+
    +
    a,b = line:splitv('=')
    +
+ +
+
+ + partition (s, ch) +
+
+ partition the string using first occurance of a delimiter + + +

Parameters:

+ + +

Returns:

+
    +
  1. + part before ch
  2. +
  3. + ch
  4. +
  5. + part after ch
  6. +
+ + + +

Usage:

+
    +
  • {stringx.partition('a,b,c', ','))} == {'a', ',', 'b,c'}
  • +
  • {stringx.partition('abc', 'x'))} == {'abc', '', ''}
  • +
+ +
+
+ + rpartition (s, ch) +
+
+ partition the string p using last occurance of a delimiter + + +

Parameters:

+ + +

Returns:

+
    +
  1. + part before ch
  2. +
  3. + ch
  4. +
  5. + part after ch
  6. +
+ + + +

Usage:

+
    +
  • {stringx.rpartition('a,b,c', ','))} == {'a,b', ',', 'c'}
  • +
  • {stringx.rpartition('abc', 'x'))} == {'', '', 'abc'}
  • +
+ +
+
+ + at (s, idx) +
+
+ return the 'character' at the index. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • idx + int + an index (can be negative) +
  • +
+ +

Returns:

+
    + + a substring of length 1 if successful, empty string otherwise. +
+ + + + +
+
+

Miscelaneous

+ +
+
+ + lines (s) +
+
+ return an iterator over all lines in a string + + +

Parameters:

+
    +
  • s + string + the string +
  • +
+ +

Returns:

+
    + + an iterator +
+ + + +

Usage:

+
    +
    local line_no = 1
    +for line in stringx.lines(some_text) do
    +  print(line_no, line)
    +  line_no = line_no + 1
    +end
    +
+ +
+
+ + title (s) +
+
+ inital word letters uppercase ('title case'). + Here 'words' mean chunks of non-space characters. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
+ +

Returns:

+
    + + a string with each word's first letter uppercase +
+ + + +

Usage:

+
    +
    stringx.title("hello world") == "Hello World")
    +
+ +
+
+ + shorten (s, w, tail) +
+
+ Return a shortened version of a string. + Fits string within w characters. Removed characters are marked with ellipsis. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • w + int + the maxinum size allowed +
  • +
  • tail + bool + true if we want to show the end of the string (head otherwise) +
  • +
+ + + + +

Usage:

+
    +
  • ('1234567890'):shorten(8) == '12345...'
  • +
  • ('1234567890'):shorten(8, true) == '...67890'
  • +
  • ('1234567890'):shorten(20) == '1234567890'
  • +
+ +
+
+ + quote_string (s) +
+
+ Quote the given string and preserve any control or escape characters, such that reloading the string in Lua returns the same result. + + +

Parameters:

+
    +
  • s + The string to be quoted. +
  • +
+ +

Returns:

+
    + + The quoted string. +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.tablex.html b/Data/Libraries/Penlight/docs/libraries/pl.tablex.html new file mode 100644 index 0000000..2e07080 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.tablex.html @@ -0,0 +1,1980 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.tablex

+

Extended operations on Lua tables.

+

See the Guide

+ +

Dependencies: pl.utils, pl.types

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
size (t)total number of elements in this table.
index_by (tbl, idx)return a list of all values in a table indexed by another list.
transform (fun, t, ...)apply a function to all values of a table, in-place.
range (start, finish[, step=1])generate a table of all numbers in a range.
reduce (fun, t, memo)'reduce' a list using a binary function.
index_map (t)create an index map from a list-like table.
makeset (t)create a set from a list-like table.
union (t1, t2)the union of two map-like tables.
intersection (t1, t2)the intersection of two map-like tables.
count_map (t, cmp)A table where the key/values are the values and value counts of the table.
set (t, val[, i1=1[, i2=#t]])set an array range to a value.
new (n, val)create a new array of specified size with initial value.
clear (t, istart)clear out the contents of a table.
removevalues (t, i1, i2)remove a range of values from a table.
readonly (t)modifies a table to be read only.
+

Copying

+ + + + + + + + + + + + + + + + + + + + + + + + + +
update (t1, t2)copy a table into another, in-place.
copy (t)make a shallow copy of a table
deepcopy (t)make a deep copy of a table, recursively copying all the keys and fields.
icopy (dest, src[, idest=1[, isrc=1[, nsrc=#src]]])copy an array into another one, clearing dest after idest+nsrc, if necessary.
move (dest, src[, idest=1[, isrc=1[, nsrc=#src]]])copy an array into another one.
insertvalues (t[, position], values)insert values into a table.
+

Comparing

+ + + + + + + + + + + + + +
deepcompare (t1, t2[, ignore_mt[, eps]])compare two values.
compare (t1, t2, cmp)compare two arrays using a predicate.
compare_no_order (t1, t2, cmp)compare two list-like tables using an optional predicate, without regard for element order.
+

Finding

+ + + + + + + + + + + + + + + + + +
find (t, val, idx)return the index of a value in a list.
rfind (t, val, idx)return the index of a value in a list, searching from the end.
find_if (t, cmp, arg)return the index (or key) of a value in a table using a comparison function.
search (t, value[, exclude])find a value in a table by recursive search.
+

MappingAndFiltering

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
map (fun, t, ...)apply a function to all values of a table.
imap (fun, t, ...)apply a function to all values of a list.
map_named_method (name, t, ...)apply a named method to values from a table.
map2 (fun, t1, t2, ...)apply a function to values from two tables.
imap2 (fun, t1, t2, ...)apply a function to values from two arrays.
mapn (fun, ..., fun)Apply a function to a number of tables.
pairmap (fun, t, ...)call the function with the key and value pairs from a table.
filter (t, pred, arg)filter an array's values using a predicate function
+

Iterating

+ + + + + + + + + + + + + + + + + +
foreach (t, fun, ...)apply a function to all elements of a table.
foreachi (t, fun, ...)apply a function to all elements of a list-like table in order.
sort (t, f)return an iterator to a table sorted by its keys
sortv (t, f)return an iterator to a table sorted by its values
+

Extraction

+ + + + + + + + + + + + + +
keys (t)return all the keys of a table in arbitrary order.
values (t)return all the values of the table in arbitrary order
sub (t, first, last)Extract a range from a table, like 'string.sub'.
+

Merging

+ + + + + + + + + + + + + +
merge (t1, t2, dup)combine two tables, either as union or intersection.
difference (s1, s2, symm)a new table which is the difference of two tables.
zip (...)return a table where each element is a table of the ith values of an arbitrary + number of tables.
+ +
+
+ + +

Functions

+ +
+
+ + size (t) +
+
+ total number of elements in this table. + Note that this is distinct from #t, which is the number + of values in the array part; this value will always + be greater or equal. The difference gives the size of + the hash part, for practical purposes. Works for any + object with a __pairs metamethod. + + +

Parameters:

+
    +
  • t + tab + a table +
  • +
+ +

Returns:

+
    + + the size +
+ + + + +
+
+ + index_by (tbl, idx) +
+
+ return a list of all values in a table indexed by another list. + + +

Parameters:

+
    +
  • tbl + tab + a table +
  • +
  • idx + array + an index table (a list of keys) +
  • +
+ +

Returns:

+
    + + a list-like table +
+ + + +

Usage:

+
    +
  • index_by({10,20,30,40},{2,4}) == {20,40}
  • +
  • index_by({one=1,two=2,three=3},{'one','three'}) == {1,3}
  • +
+ +
+
+ + transform (fun, t, ...) +
+
+ apply a function to all values of a table, in-place. + Any extra arguments are passed to the function. + + +

Parameters:

+
    +
  • fun + func + A function that takes at least one argument +
  • +
  • t + tab + a table +
  • +
  • ... + extra arguments passed to fun +
  • +
+ + + +

See also:

+ + + +
+
+ + range (start, finish[, step=1]) +
+
+ generate a table of all numbers in a range. + This is consistent with a numerical for loop. + + +

Parameters:

+
    +
  • start + int + number +
  • +
  • finish + int + number +
  • +
  • step + int + make this negative for start < finish + (default 1) +
  • +
+ + + + + +
+
+ + reduce (fun, t, memo) +
+
+ 'reduce' a list using a binary function. + + +

Parameters:

+
    +
  • fun + func + a function of two arguments +
  • +
  • t + array + a list-like table +
  • +
  • memo + array + optional initial memo value. Defaults to first value in table. +
  • +
+ +

Returns:

+
    + + the result of the function +
+ + + +

Usage:

+
    +
    reduce('+',{1,2,3,4}) == 10
    +
+ +
+
+ + index_map (t) +
+
+ create an index map from a list-like table. The original values become keys, + and the associated values are the indices into the original list. + + +

Parameters:

+
    +
  • t + array + a list-like table +
  • +
+ +

Returns:

+
    + + a map-like table +
+ + + + +
+
+ + makeset (t) +
+
+ create a set from a list-like table. A set is a table where the original values + become keys, and the associated values are all true. + + +

Parameters:

+
    +
  • t + array + a list-like table +
  • +
+ +

Returns:

+
    + + a set (a map-like table) +
+ + + + +
+
+ + union (t1, t2) +
+
+ the union of two map-like tables. + If there are duplicate keys, the second table wins. + + +

Parameters:

+
    +
  • t1 + tab + a table +
  • +
  • t2 + tab + a table +
  • +
+ +

Returns:

+
    + + tab + + + +
+ + +

See also:

+ + + +
+
+ + intersection (t1, t2) +
+
+ the intersection of two map-like tables. + + +

Parameters:

+
    +
  • t1 + tab + a table +
  • +
  • t2 + tab + a table +
  • +
+ +

Returns:

+
    + + tab + + + +
+ + +

See also:

+ + + +
+
+ + count_map (t, cmp) +
+
+ A table where the key/values are the values and value counts of the table. + + +

Parameters:

+
    +
  • t + array + a list-like table +
  • +
  • cmp + func + a function that defines equality (otherwise uses ==) +
  • +
+ +

Returns:

+
    + + a map-like table +
+ + +

See also:

+ + + +
+
+ + set (t, val[, i1=1[, i2=#t]]) +
+
+ set an array range to a value. If it's a function we use the result + of applying it to the indices. + + +

Parameters:

+
    +
  • t + array + a list-like table +
  • +
  • val + a value +
  • +
  • i1 + int + start range + (default 1) +
  • +
  • i2 + int + end range + (default #t) +
  • +
+ + + + + +
+
+ + new (n, val) +
+
+ create a new array of specified size with initial value. + + +

Parameters:

+
    +
  • n + int + size +
  • +
  • val + initial value (can be nil, but don't expect # to work!) +
  • +
+ +

Returns:

+
    + + the table +
+ + + + +
+
+ + clear (t, istart) +
+
+ clear out the contents of a table. + + +

Parameters:

+
    +
  • t + array + a list +
  • +
  • istart + optional start position +
  • +
+ + + + + +
+
+ + removevalues (t, i1, i2) +
+
+ remove a range of values from a table. + End of range may be negative. + + +

Parameters:

+
    +
  • t + array + a list-like table +
  • +
  • i1 + int + start index +
  • +
  • i2 + int + end index +
  • +
+ +

Returns:

+
    + + the table +
+ + + + +
+
+ + readonly (t) +
+
+ modifies a table to be read only. + This only offers weak protection. Tables can still be modified with + table.insert and rawset.

+ +

NOTE: for Lua 5.1 length, pairs and ipairs will not work, since the + equivalent metamethods are only available in Lua 5.2 and newer. + + +

Parameters:

+
    +
  • t + tab + the table +
  • +
+ +

Returns:

+
    + + the table read only (a proxy). +
+ + + + +
+
+

Copying

+ +
+
+ + update (t1, t2) +
+
+ copy a table into another, in-place. + + +

Parameters:

+
    +
  • t1 + tab + destination table +
  • +
  • t2 + tab + source (actually any iterable object) +
  • +
+ +

Returns:

+
    + + first table +
+ + + + +
+
+ + copy (t) +
+
+ make a shallow copy of a table + + +

Parameters:

+
    +
  • t + tab + an iterable source +
  • +
+ +

Returns:

+
    + + new table +
+ + + + +
+
+ + deepcopy (t) +
+
+ make a deep copy of a table, recursively copying all the keys and fields. + This supports cycles in tables; cycles will be reproduced in the copy. + This will also set the copied table's metatable to that of the original. + + +

Parameters:

+
    +
  • t + tab + A table +
  • +
+ +

Returns:

+
    + + new table +
+ + + + +
+
+ + icopy (dest, src[, idest=1[, isrc=1[, nsrc=#src]]]) +
+
+ copy an array into another one, clearing dest after idest+nsrc, if necessary. + + +

Parameters:

+
    +
  • dest + array + a list-like table +
  • +
  • src + array + a list-like table +
  • +
  • idest + int + where to start copying values into destination + (default 1) +
  • +
  • isrc + int + where to start copying values from source + (default 1) +
  • +
  • nsrc + int + number of elements to copy from source + (default #src) +
  • +
+ + + + + +
+
+ + move (dest, src[, idest=1[, isrc=1[, nsrc=#src]]]) +
+
+ copy an array into another one. + + +

Parameters:

+
    +
  • dest + array + a list-like table +
  • +
  • src + array + a list-like table +
  • +
  • idest + int + where to start copying values into destination + (default 1) +
  • +
  • isrc + int + where to start copying values from source + (default 1) +
  • +
  • nsrc + int + number of elements to copy from source + (default #src) +
  • +
+ + + + + +
+
+ + insertvalues (t[, position], values) +
+
+ insert values into a table. + similar to table.insert but inserts values from given table values, + not the object itself, into table t at position pos. + + +

Parameters:

+
    +
  • t + array + the list +
  • +
  • position + int + (default is at end) + (optional) +
  • +
  • values + array + + + +
  • +
+ + + + + +
+
+

Comparing

+ +
+
+ + deepcompare (t1, t2[, ignore_mt[, eps]]) +
+
+ compare two values. + if they are tables, then compare their keys and fields recursively. + + +

Parameters:

+
    +
  • t1 + A value +
  • +
  • t2 + A value +
  • +
  • ignore_mt + bool + if true, ignore __eq metamethod (default false) + (optional) +
  • +
  • eps + number + if defined, then used for any number comparisons + (optional) +
  • +
+ +

Returns:

+
    + + true or false +
+ + + + +
+
+ + compare (t1, t2, cmp) +
+
+ compare two arrays using a predicate. + + +

Parameters:

+
    +
  • t1 + array + an array +
  • +
  • t2 + array + an array +
  • +
  • cmp + func + A comparison function; bool = cmp(t1_value, t2_value) +
  • +
+ +

Returns:

+
    + + true or false +
+ + + +

Usage:

+
    +
    assert(tablex.compare({ 1, 2, 3 }, { 1, 2, 3 }, "=="))
    +
    +assert(tablex.compare(
    +   {1,2,3, hello = "world"},  -- fields are not compared!
    +   {1,2,3}, function(v1, v2) return v1 == v2 end)
    +
+ +
+
+ + compare_no_order (t1, t2, cmp) +
+
+ compare two list-like tables using an optional predicate, without regard for element order. + + +

Parameters:

+
    +
  • t1 + array + a list-like table +
  • +
  • t2 + array + a list-like table +
  • +
  • cmp + A comparison function (may be nil) +
  • +
+ + + + + +
+
+

Finding

+ +
+
+ + find (t, val, idx) +
+
+ return the index of a value in a list. + Like string.find, there is an optional index to start searching, + which can be negative. + + +

Parameters:

+
    +
  • t + array + A list-like table +
  • +
  • val + A value +
  • +
  • idx + int + index to start; -1 means last element,etc (default 1) +
  • +
+ +

Returns:

+
    + + index of value or nil if not found +
+ + + +

Usage:

+
    +
  • find({10,20,30},20) == 2
  • +
  • find({'a','b','a','c'},'a',2) == 3
  • +
+ +
+
+ + rfind (t, val, idx) +
+
+ return the index of a value in a list, searching from the end. + Like string.find, there is an optional index to start searching, + which can be negative. + + +

Parameters:

+
    +
  • t + array + A list-like table +
  • +
  • val + A value +
  • +
  • idx + index to start; -1 means last element,etc (default #t) +
  • +
+ +

Returns:

+
    + + index of value or nil if not found +
+ + + +

Usage:

+
    +
    rfind({10,10,10},10) == 3
    +
+ +
+
+ + find_if (t, cmp, arg) +
+
+ return the index (or key) of a value in a table using a comparison function.

+ +

NOTE: the 2nd return value of this function, the value returned + by the comparison function, has a limitation that it cannot be false. + Because if it is, then it indicates the comparison failed, and the + function will continue the search. See examples. + + +

Parameters:

+
    +
  • t + tab + A table +
  • +
  • cmp + func + A comparison function +
  • +
  • arg + an optional second argument to the function +
  • +
+ +

Returns:

+
    +
  1. + index of value, or nil if not found
  2. +
  3. + value returned by comparison function (cannot be false!)
  4. +
+ + + +

Usage:

+
    +
    -- using an operator
    +local lst = { "Rudolph", true, false, 15 }
    +local idx, cmp_result = tablex.rfind(lst, "==", "Rudolph")
    +assert(idx == 1)
    +assert(cmp_result == true)
    +
    +local idx, cmp_result = tablex.rfind(lst, "==", false)
    +assert(idx == 3)
    +assert(cmp_result == true)       -- looking up 'false' works!
    +
    +-- using a function returning the value looked up
    +local cmp = function(v1, v2) return v1 == v2 and v2 end
    +local idx, cmp_result = tablex.rfind(lst, cmp, "Rudolph")
    +assert(idx == 1)
    +assert(cmp_result == "Rudolph")  -- the value is returned
    +
    +-- NOTE: this fails, since 'false' cannot be returned!
    +local idx, cmp_result = tablex.rfind(lst, cmp, false)
    +assert(idx == nil)               -- looking up 'false' failed!
    +assert(cmp_result == nil)
    +
+ +
+
+ + search (t, value[, exclude]) +
+
+ find a value in a table by recursive search. + + +

Parameters:

+
    +
  • t + tab + the table +
  • +
  • value + the value +
  • +
  • exclude + array + any tables to avoid searching + (optional) +
  • +
+ +

Returns:

+
    + + a fieldspec, e.g. 'a.b' or 'math.sin' +
+ + + +

Usage:

+
    +
    search(_G,math.sin,{package.path}) == 'math.sin'
    +
+ +
+
+

MappingAndFiltering

+ +
+
+ + map (fun, t, ...) +
+
+ apply a function to all values of a table. + This returns a table of the results. + Any extra arguments are passed to the function. + + +

Parameters:

+
    +
  • fun + func + A function that takes at least one argument +
  • +
  • t + tab + A table +
  • +
  • ... + optional arguments +
  • +
+ + + + +

Usage:

+
    +
    map(function(v) return v*v end, {10,20,30,fred=2}) is {100,400,900,fred=4}
    +
+ +
+
+ + imap (fun, t, ...) +
+
+ apply a function to all values of a list. + This returns a table of the results. + Any extra arguments are passed to the function. + + +

Parameters:

+
    +
  • fun + func + A function that takes at least one argument +
  • +
  • t + array + a table (applies to array part) +
  • +
  • ... + optional arguments +
  • +
+ +

Returns:

+
    + + a list-like table +
+ + + +

Usage:

+
    +
    imap(function(v) return v*v end, {10,20,30,fred=2}) is {100,400,900}
    +
+ +
+
+ + map_named_method (name, t, ...) +
+
+ apply a named method to values from a table. + + +

Parameters:

+
    +
  • name + string + the method name +
  • +
  • t + array + a list-like table +
  • +
  • ... + any extra arguments to the method +
  • +
+ +

Returns:

+
    + + a List with the results of the method (1st result only) +
+ + + +

Usage:

+
    +
    local Car = {}
    +Car.__index = Car
    +function Car.new(car)
    +  return setmetatable(car or {}, Car)
    +end
    +Car.speed = 0
    +function Car:faster(increase)
    +  self.speed = self.speed + increase
    +  return self.speed
    +end
    +
    +local ferrari = Car.new{ name = "Ferrari" }
    +local lamborghini = Car.new{ name = "Lamborghini", speed = 50 }
    +local cars = { ferrari, lamborghini }
    +
    +assert(ferrari.speed == 0)
    +assert(lamborghini.speed == 50)
    +tablex.map_named_method("faster", cars, 10)
    +assert(ferrari.speed == 10)
    +assert(lamborghini.speed == 60)
    +
+ +
+
+ + map2 (fun, t1, t2, ...) +
+
+ apply a function to values from two tables. + + +

Parameters:

+
    +
  • fun + func + a function of at least two arguments +
  • +
  • t1 + tab + a table +
  • +
  • t2 + tab + a table +
  • +
  • ... + extra arguments +
  • +
+ +

Returns:

+
    + + a table +
+ + + +

Usage:

+
    +
    map2('+',{1,2,3,m=4},{10,20,30,m=40}) is {11,22,23,m=44}
    +
+ +
+
+ + imap2 (fun, t1, t2, ...) +
+
+ apply a function to values from two arrays. + The result will be the length of the shortest array. + + +

Parameters:

+
    +
  • fun + func + a function of at least two arguments +
  • +
  • t1 + array + a list-like table +
  • +
  • t2 + array + a list-like table +
  • +
  • ... + extra arguments +
  • +
+ + + + +

Usage:

+
    +
    imap2('+',{1,2,3,m=4},{10,20,30,m=40}) is {11,22,23}
    +
+ +
+
+ + mapn (fun, ..., fun) +
+
+ Apply a function to a number of tables. + A more general version of map + The result is a table containing the result of applying that function to the + ith value of each table. Length of output list is the minimum length of all the lists + + +

Parameters:

+
    +
  • fun + A function that takes as many arguments as there are tables +
  • +
  • ... + tab + n tables +
  • +
  • fun + A function that takes as many arguments as there are tables +
  • +
+ + + + +

Usage:

+
    +
  • mapn(function(x,y,z) return x+y+z end, {1,2,3},{10,20,30},{100,200,300}) is {111,222,333}
  • +
  • mapn(math.max, {1,20,300},{10,2,3},{100,200,100}) is    {100,200,300}
  • +
+ +
+
+ + pairmap (fun, t, ...) +
+
+ call the function with the key and value pairs from a table. + The function can return a value and a key (note the order!). If both + are not nil, then this pair is inserted into the result: if the key already exists, we convert the value for that + key into a table and append into it. If only value is not nil, then it is appended to the result. + + +

Parameters:

+
    +
  • fun + func + A function which will be passed each key and value as arguments, plus any extra arguments to pairmap. +
  • +
  • t + tab + A table +
  • +
  • ... + optional arguments +
  • +
+ + + + +

Usage:

+
    +
  • pairmap(function(k,v) return v end,{fred=10,bonzo=20}) is {10,20} _or_ {20,10}
  • +
  • pairmap(function(k,v) return {k,v},k end,{one=1,two=2}) is {one={'one',1},two={'two',2}}
  • +
+ +
+
+ + filter (t, pred, arg) +
+
+ filter an array's values using a predicate function + + +

Parameters:

+
    +
  • t + array + a list-like table +
  • +
  • pred + func + a boolean function +
  • +
  • arg + optional argument to be passed as second argument of the predicate +
  • +
+ + + + + +
+
+

Iterating

+ +
+
+ + foreach (t, fun, ...) +
+
+ apply a function to all elements of a table. + The arguments to the function will be the value, + the key and finally any extra arguments passed to this function. + Note that the Lua 5.0 function table.foreach passed the key first. + + +

Parameters:

+
    +
  • t + tab + a table +
  • +
  • fun + func + a function on the elements; function(value, key, ...) +
  • +
  • ... + extra arguments passed to fun +
  • +
+ + + +

See also:

+ + + +
+
+ + foreachi (t, fun, ...) +
+
+ apply a function to all elements of a list-like table in order. + The arguments to the function will be the value, + the index and finally any extra arguments passed to this function + + +

Parameters:

+
    +
  • t + array + a table +
  • +
  • fun + func + a function with at least one argument +
  • +
  • ... + optional arguments +
  • +
+ + + + + +
+
+ + sort (t, f) +
+
+ return an iterator to a table sorted by its keys + + +

Parameters:

+
    +
  • t + tab + the table +
  • +
  • f + func + an optional comparison function (f(x,y) is true if x < y) +
  • +
+ +

Returns:

+
    + + an iterator to traverse elements sorted by the keys +
+ + + +

Usage:

+
    +
    for k,v in tablex.sort(t) do print(k,v) end
    +
+ +
+
+ + sortv (t, f) +
+
+ return an iterator to a table sorted by its values + + +

Parameters:

+
    +
  • t + tab + the table +
  • +
  • f + func + an optional comparison function (f(x,y) is true if x < y) +
  • +
+ +

Returns:

+
    + + an iterator to traverse elements sorted by the values +
+ + + +

Usage:

+
    +
    for k,v in tablex.sortv(t) do print(k,v) end
    +
+ +
+
+

Extraction

+ +
+
+ + keys (t) +
+
+ return all the keys of a table in arbitrary order. + + +

Parameters:

+
    +
  • t + tab + A table +
  • +
+ + + + + +
+
+ + values (t) +
+
+ return all the values of the table in arbitrary order + + +

Parameters:

+
    +
  • t + tab + A table +
  • +
+ + + + + +
+
+ + sub (t, first, last) +
+
+ Extract a range from a table, like 'string.sub'. + If first or last are negative then they are relative to the end of the list + eg. sub(t,-2) gives last 2 entries in a list, and + sub(t,-4,-2) gives from -4th to -2nd + + +

Parameters:

+
    +
  • t + array + a list-like table +
  • +
  • first + int + An index +
  • +
  • last + int + An index +
  • +
+ +

Returns:

+
    + + a new List +
+ + + + +
+
+

Merging

+ +
+
+ + merge (t1, t2, dup) +
+
+ combine two tables, either as union or intersection. Corresponds to + set operations for sets () but more general. Not particularly + useful for list-like tables. + + +

Parameters:

+
    +
  • t1 + tab + a table +
  • +
  • t2 + tab + a table +
  • +
  • dup + bool + true for a union, false for an intersection. +
  • +
+ + + +

See also:

+ + +

Usage:

+
    +
  • merge({alice=23,fred=34},{bob=25,fred=34}) is {fred=34}
  • +
  • merge({alice=23,fred=34},{bob=25,fred=34},true) is {bob=25,fred=34,alice=23}
  • +
+ +
+
+ + difference (s1, s2, symm) +
+
+ a new table which is the difference of two tables. + With sets (where the values are all true) this is set difference and + symmetric difference depending on the third parameter. + + +

Parameters:

+
    +
  • s1 + tab + a map-like table or set +
  • +
  • s2 + tab + a map-like table or set +
  • +
  • symm + bool + symmetric difference (default false) +
  • +
+ +

Returns:

+
    + + a map-like table or set +
+ + + + +
+
+ + zip (...) +
+
+ return a table where each element is a table of the ith values of an arbitrary + number of tables. It is equivalent to a matrix transpose. + + +

Parameters:

+
    +
  • ... + array + arrays to be zipped +
  • +
+ + + + +

Usage:

+
    +
    zip({10,20,30},{100,200,300}) is {{10,100},{20,200},{30,300}}
    +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.template.html b/Data/Libraries/Penlight/docs/libraries/pl.template.html new file mode 100644 index 0000000..c2ac2c0 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.template.html @@ -0,0 +1,336 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.template

+

A template preprocessor.

+

Originally by Ricki Lake

+ +

There are two rules:

+ +
    +
  • lines starting with # are Lua
  • +
  • otherwise, $(expr) is the result of evaluating expr
  • +
+ +

Example:

+ + +
+#  for i = 1,3 do
+   $(i) Hello, Word!
+#  end
+===>
+1 Hello, Word!
+2 Hello, Word!
+3 Hello, Word!
+
+ +

Other escape characters can be used, when the defaults conflict + with the output language.

+ + +
+> for _,n in pairs{'one','two','three'} do
+static int l_${n} (luaState *state);
+> end
+
+ +

See the Guide.

+ +

Dependencies: pl.utils

+ + +

Functions

+ + + + + + + + + + + + + +
substitute (str[, env])expand the template using the specified environment.
ct:render ([env[, parent[, db]]])executes the previously compiled template and renders it.
compile (str[, opts])compiles the template.
+ +
+
+ + +

Functions

+ +
+
+ + substitute (str[, env]) +
+
+ +

expand the template using the specified environment. + This function will compile and render the template. For more performant + recurring usage use the two step approach by using compile and ct:render. + There are six special fields in the environment table env

+ +
    +
  • _parent: continue looking up in this table (e.g. _parent=_G).
  • +
  • _brackets: bracket pair that wraps inline Lua expressions, default is '()'.
  • +
  • _escape: character marking Lua lines, default is '#'
  • +
  • _inline_escape: character marking inline Lua expression, default is '$'.
  • +
  • _chunk_name: chunk name for loaded templates, used if there + is an error in Lua code. Default is 'TMP'.
  • +
  • _debug: if truthy, the generated code will be printed upon a render error
  • +
+ + + + +

Parameters:

+
    +
  • str + string + the template string +
  • +
  • env + tab + the environment + (optional) +
  • +
+ +

Returns:

+
    + + rendered template + nil + source_code, or nil + error + source_code. The last + return value (source_code) is only returned if the debug option is used. +
+ + + + +
+
+ + ct:render ([env[, parent[, db]]]) +
+
+ executes the previously compiled template and renders it. + + +

Parameters:

+
    +
  • env + tab + the environment. + (optional) +
  • +
  • parent + tab + continue looking up in this table (e.g. parent=_G). + (optional) +
  • +
  • db + bool + if thruthy, it will print the code upon a render error + (provided the template was compiled with the debug option). + (optional) +
  • +
+ +

Returns:

+
    + + rendered template + nil + source_code, or nil + error + source_code. The last return value + (source_code) is only returned if the template was compiled with the debug option. +
+ + + +

Usage:

+
    +
    local ct, err = template.compile(my_template)
    +local rendered , err = ct:render(my_env, parent)
    +
+ +
+
+ + compile (str[, opts]) +
+
+ +

compiles the template. + Returns an object that can repeatedly be rendered without parsing/compiling + the template again. + The options passed in the opts table support the following options:

+ +
    +
  • chunk_name: chunk name for loaded templates, used if there + is an error in Lua code. Default is 'TMP'.
  • +
  • escape: character marking Lua lines, default is '#'
  • +
  • inline_escape: character marking inline Lua expression, default is '$'.
  • +
  • inline_brackets: bracket pair that wraps inline Lua expressions, default is '()'.
  • +
  • newline: string to replace newline characters, default is nil (not replacing newlines).
  • +
  • debug: if truthy, the generated source code will be retained within the compiled template object, default is nil.
  • +
+ + + + +

Parameters:

+
    +
  • str + string + the template string +
  • +
  • opts + tab + the compilation options to use + (optional) +
  • +
+ +

Returns:

+
    + + template object, or nil + error + source_code +
+ + + +

Usage:

+
    +
    local ct, err = template.compile(my_template)
    +local rendered , err = ct:render(my_env, parent)
    +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.test.html b/Data/Libraries/Penlight/docs/libraries/pl.test.html new file mode 100644 index 0000000..72aff1d --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.test.html @@ -0,0 +1,445 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.test

+

Useful test utilities.

+

+ + + +

+test.asserteq({1,2},{1,2}) -- can compare tables
+test.asserteq(1.2,1.19,0.02) -- compare FP numbers within precision
+T = test.tuple -- used for comparing multiple results
+test.asserteq(T(string.find(" me","me")),T(2,3))
+
+ +

Dependencies: pl.utils, pl.tablex, pl.pretty, pl.path, debug

+

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
error_handler (file, line, got_text, needed_text, msg)error handling for test results.
complain (x, y, msg, where)general test complain message.
asserteq (x, y, eps, where)like assert, except takes two arguments that must be equal and can be tables.
assertmatch (s1, s2, where)assert that the first string matches the second.
assertraise (fn, e, where)assert that the function raises a particular error.
asserteq2 (x1, x2, y1, y2, where)a version of asserteq that takes two pairs of values.
tuple (...)encode an arbitrary argument list as a tuple.
timer (msg, n, fun, ...)Time a function.
+ +
+
+ + +

Functions

+ +
+
+ + error_handler (file, line, got_text, needed_text, msg) +
+
+ error handling for test results. + By default, this writes to stderr and exits the program. + Re-define this function to raise an error and/or redirect output + + +

Parameters:

+
    +
  • file + + + +
  • +
  • line + + + +
  • +
  • got_text + + + +
  • +
  • needed_text + + + +
  • +
  • msg + + + +
  • +
+ + + + + +
+
+ + complain (x, y, msg, where) +
+
+ general test complain message. + Useful for composing new test functions (see tests/tablex.lua for an example) + + +

Parameters:

+
    +
  • x + a value +
  • +
  • y + value to compare first value against +
  • +
  • msg + message +
  • +
  • where + extra level offset for errors +
  • +
+ + + + + +
+
+ + asserteq (x, y, eps, where) +
+
+ like assert, except takes two arguments that must be equal and can be tables. + If they are plain tables, it will use tablex.deepcompare. + + +

Parameters:

+
    +
  • x + any value +
  • +
  • y + a value equal to x +
  • +
  • eps + an optional tolerance for numerical comparisons +
  • +
  • where + extra level offset +
  • +
+ + + + + +
+
+ + assertmatch (s1, s2, where) +
+
+ assert that the first string matches the second. + + +

Parameters:

+
    +
  • s1 + a string +
  • +
  • s2 + a string +
  • +
  • where + extra level offset +
  • +
+ + + + + +
+
+ + assertraise (fn, e, where) +
+
+ assert that the function raises a particular error. + + +

Parameters:

+
    +
  • fn + a function or a table of the form {function,arg1,...} +
  • +
  • e + a string to match the error against +
  • +
  • where + extra level offset +
  • +
+ + + + + +
+
+ + asserteq2 (x1, x2, y1, y2, where) +
+
+ a version of asserteq that takes two pairs of values. + x1==y1 and x2==y2 must be true. Useful for functions that naturally + return two values. + + +

Parameters:

+
    +
  • x1 + any value +
  • +
  • x2 + any value +
  • +
  • y1 + any value +
  • +
  • y2 + any value +
  • +
  • where + extra level offset +
  • +
+ + + + + +
+
+ + tuple (...) +
+
+ encode an arbitrary argument list as a tuple. + This can be used to compare to other argument lists, which is + very useful for testing functions which return a number of values. + Unlike regular array-like tables ('sequences') they may contain nils. + Tuples understand equality and know how to print themselves out. + The # operator is defined to be the size, irrespecive of any nils, + and there is an unpack method. + + +

Parameters:

+
    +
  • ... + + + +
  • +
+ + + + +

Usage:

+
    +
    asserteq(tuple( ('ab'):find 'a'), tuple(1,1))
    +
+ +
+
+ + timer (msg, n, fun, ...) +
+
+ Time a function. Call the function a given number of times, and report the number of seconds taken, + together with a message. Any extra arguments will be passed to the function. + + +

Parameters:

+
    +
  • msg + string + a descriptive message +
  • +
  • n + int + number of times to call the function +
  • +
  • fun + func + the function +
  • +
  • ... + optional arguments to fun +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.text.html b/Data/Libraries/Penlight/docs/libraries/pl.text.html new file mode 100644 index 0000000..77b7db1 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.text.html @@ -0,0 +1,381 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.text

+

Text processing utilities.

+

This provides a Template class (modeled after the same from the Python + libraries, see string.Template). It also provides similar functions to those + found in the textwrap module.

+ +

See the Guide.

+ +

Calling text.format_operator() overloads the % operator for strings to give Python/Ruby style formated output. + This is extended to also do template-like substitution for map-like data.

+ + +
+> require 'pl.text'.format_operator()
+> = '%s = %5.3f' % {'PI',math.pi}
+PI = 3.142
+> = '$name = $value' % {name='dog',value='Pluto'}
+dog = Pluto
+
+ +

Dependencies: pl.utils, pl.types

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
indent (s, n, ch)indent a multiline string.
dedent (s)dedent a multiline string by removing any initial indent.
wrap (s, width)format a paragraph into lines so that they fit into a line width.
fill (s, width)format a paragraph so that it fits into a line width.
Template:substitute (tbl)substitute values into a template, throwing an error.
Template:safe_substitute (tbl)substitute values into a template.
Template:indent_substitute (tbl)substitute values into a template, preserving indentation.
+ +
+
+ + +

Functions

+ +
+
+ + indent (s, n, ch) +
+
+ indent a multiline string. + + +

Parameters:

+
    +
  • s + the string +
  • +
  • n + the size of the indent +
  • +
  • ch + the character to use when indenting (default ' ') +
  • +
+ +

Returns:

+
    + + indented string +
+ + + + +
+
+ + dedent (s) +
+
+ dedent a multiline string by removing any initial indent. + useful when working with [[..]] strings. + + +

Parameters:

+
    +
  • s + the string +
  • +
+ +

Returns:

+
    + + a string with initial indent zero. +
+ + + + +
+
+ + wrap (s, width) +
+
+ format a paragraph into lines so that they fit into a line width. + It will not break long words, so lines can be over the length + to that extent. + + +

Parameters:

+
    +
  • s + the string +
  • +
  • width + the margin width, default 70 +
  • +
+ +

Returns:

+
    + + a list of lines (List object) +
+ + +

See also:

+ + + +
+
+ + fill (s, width) +
+
+ format a paragraph so that it fits into a line width. + + +

Parameters:

+
    +
  • s + the string +
  • +
  • width + the margin width, default 70 +
  • +
+ +

Returns:

+
    + + a string +
+ + +

See also:

+ + + +
+
+ + Template:substitute (tbl) +
+
+ substitute values into a template, throwing an error. + This will throw an error if no name is found. + + +

Parameters:

+
    +
  • tbl + a table of name-value pairs. +
  • +
+ + + + + +
+
+ + Template:safe_substitute (tbl) +
+
+ substitute values into a template. + This version just passes unknown names through. + + +

Parameters:

+
    +
  • tbl + a table of name-value pairs. +
  • +
+ + + + + +
+
+ + Template:indent_substitute (tbl) +
+
+ substitute values into a template, preserving indentation.
+ If the value is a multiline string or a template, it will insert + the lines at the correct indentation.
+ Furthermore, if a template, then that template will be subsituted + using the same table. + + +

Parameters:

+
    +
  • tbl + a table of name-value pairs. +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.types.html b/Data/Libraries/Penlight/docs/libraries/pl.types.html new file mode 100644 index 0000000..252005e --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.types.html @@ -0,0 +1,475 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.types

+

Dealing with Detailed Type Information

+

+ +

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
is_callable (obj)is the object either a function or a callable object?.
is_type (obj, tp)is the object of the specified type?.
type (obj)a string representation of a type.
is_integer (x)is this number an integer?
is_empty (o, ignore_spaces)Check if the object is "empty".
is_indexable (val)is an object 'array-like'?
is_iterable (val)can an object be iterated over with pairs?
is_writeable (val)can an object accept new key/pair values?
to_bool (o[, true_strs[, check_objs]])Convert to a boolean value.
+ +
+
+ + +

Functions

+ +
+
+ + is_callable (obj) +
+
+ is the object either a function or a callable object?. + + +

Parameters:

+
    +
  • obj + Object to check. +
  • +
+ + + + + +
+
+ + is_type (obj, tp) +
+
+ is the object of the specified type?. + If the type is a string, then use type, otherwise compare with metatable.

+ +

NOTE: this function is imported from utils.is_type. + + +

Parameters:

+
    +
  • obj + An object to check +
  • +
  • tp + The expected type +
  • +
+ + + +

See also:

+ + + +
+
+ + type (obj) +
+
+ a string representation of a type. + For tables and userdata with metatables, we assume that the metatable has a _name + field. If the field is not present it will return 'unknown table' or + 'unknown userdata'. + Lua file objects return the type 'file'. + + +

Parameters:

+
    +
  • obj + an object +
  • +
+ +

Returns:

+
    + + a string like 'number', 'table', 'file' or 'List' +
+ + + + +
+
+ + is_integer (x) +
+
+ is this number an integer? + + +

Parameters:

+
    +
  • x + a number +
  • +
+ +

Returns:

+
    + + boolean +
+ +

Raises:

+ error if x is not a number + + + +
+
+ + is_empty (o, ignore_spaces) +
+
+ +

Check if the object is "empty". + An object is considered empty if it is:

+ +
    +
  • nil
  • +
  • a table without any items (key-value pairs or indexes)
  • +
  • a string with no content ("")
  • +
  • not a nil/table/string
  • +
+ + + +

Parameters:

+
    +
  • o + The object to check if it is empty. +
  • +
  • ignore_spaces + If the object is a string and this is true the string is + considered empty if it only contains spaces. +
  • +
+ +

Returns:

+
    + + true if the object is empty, otherwise a falsy value. +
+ + + + +
+
+ + is_indexable (val) +
+
+ is an object 'array-like'? + An object is array like if:

+ +
    +
  • it is a table, or
  • +
  • it has a metatable with __len and __index methods
  • +
+ +

NOTE: since __len is 5.2+, on 5.1 is usually returns false for userdata + + +

Parameters:

+
    +
  • val + any value. +
  • +
+ +

Returns:

+
    + + true if the object is array-like, otherwise a falsy value. +
+ + + + +
+
+ + is_iterable (val) +
+
+ can an object be iterated over with pairs? + An object is iterable if:

+ +
    +
  • it is a table, or
  • +
  • it has a metatable with a __pairs meta method
  • +
+ +

NOTE: since __pairs is 5.2+, on 5.1 is usually returns false for userdata + + +

Parameters:

+
    +
  • val + any value. +
  • +
+ +

Returns:

+
    + + true if the object is iterable, otherwise a falsy value. +
+ + + + +
+
+ + is_writeable (val) +
+
+ +

can an object accept new key/pair values? + An object is iterable if:

+ +
    +
  • it is a table, or
  • +
  • it has a metatable with a __newindex meta method
  • +
+ + + + +

Parameters:

+
    +
  • val + any value. +
  • +
+ +

Returns:

+
    + + true if the object is writeable, otherwise a falsy value. +
+ + + + +
+
+ + to_bool (o[, true_strs[, check_objs]]) +
+
+ +

Convert to a boolean value. + True values are:

+ +
    +
  • boolean: true.
  • +
  • string: 'yes', 'y', 'true', 't', '1' or additional strings specified by true_strs.
  • +
  • number: Any non-zero value.
  • +
  • table: Is not empty and check_objs is true.
  • +
  • everything else: Is not nil and check_objs is true.
  • +
+ + + + +

Parameters:

+
    +
  • o + The object to evaluate. +
  • +
  • true_strs + optional Additional strings that when matched should evaluate to true. Comparison is case insensitive. + This should be a List of strings. E.g. "ja" to support German. + (optional) +
  • +
  • check_objs + True if objects should be evaluated. + (optional) +
  • +
+ +

Returns:

+
    + + true if the input evaluates to true, otherwise false. +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.url.html b/Data/Libraries/Penlight/docs/libraries/pl.url.html new file mode 100644 index 0000000..7c97371 --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.url.html @@ -0,0 +1,212 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.url

+

Python-style URL quoting library.

+

+ +

+ + +

Functions

+ + + + + + + + + +
quote (s, quote_plus)Quote the url, replacing special characters using the '%xx' escape.
unquote (s)Unquote the url, replacing '%xx' escapes and plus signs.
+ +
+
+ + +

Functions

+ +
+
+ + quote (s, quote_plus) +
+
+ Quote the url, replacing special characters using the '%xx' escape. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
  • quote_plus + bool + Also escape slashes and replace spaces by plus signs. +
  • +
+ +

Returns:

+
    + + The quoted string, or if s wasn't a string, just plain unaltered s. +
+ + + + +
+
+ + unquote (s) +
+
+ Unquote the url, replacing '%xx' escapes and plus signs. + + +

Parameters:

+
    +
  • s + string + the string +
  • +
+ +

Returns:

+
    + + The unquoted string, or if s wasn't a string, just plain unaltered s. +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.utils.html b/Data/Libraries/Penlight/docs/libraries/pl.utils.html new file mode 100644 index 0000000..ee1773a --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.utils.html @@ -0,0 +1,1384 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.utils

+

Generally useful routines.

+

See the Guide.

+ +

Dependencies: pl.compat, all exported fields and functions from + pl.compat are also available in this module.

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pack (...)pack an argument list into a table.
unpack (t[, i[, t]])unpack a table and return its contents.
printf (fmt, ...)print an arbitrary number of arguments using a format.
fprintf (f, fmt, ...)write an arbitrary number of arguments to a file using a format.
import (t, T)take a table and 'inject' it into the local namespace.
choose (cond, value1, value2)return either of two values, depending on a condition.
array_tostring (t[, temp[, tostr]])convert an array of values to strings.
is_type (obj, tp)is the object of the specified type?
+

Tables

+ + + + + + + + + +
patternsSome standard patterns
stdmtStandard meta-tables as used by other Penlight modules
+

Error handling

+ + + + + + + + + + + + + + + + + + + + + +
assert_arg (n, val, tp, verify, msg, lev)assert that the given argument is in fact of the correct type.
function_arg (idx, f, msg)process a function argument.
assert_string (n, val)assert the common case that the argument is a string.
on_error (mode)control the error strategy used by Penlight.
raise (err)used by Penlight functions to return errors.
+

File handling

+ + + + + + + + + + + + + +
readfile (filename, is_bin)return the contents of a file as a string
writefile (filename, str, is_bin)write a string to a file
readlines (filename)return the contents of a file as a list of lines
+

OS functions

+ + + + + + + + + + + + + +
executeex (cmd, bin)execute a shell command and return the output.
quote_arg (argument)Quote and escape an argument of a command.
quit ([code], msg, ...)error out of this program gracefully.
+

String functions

+ + + + + + + + + + + + + +
escape (s)escape any Lua 'magic' characters in a string
split (s, re, plain, n)split a string into a list of strings separated by a delimiter.
splitv (s, re, plain, n)split a string into a number of return values.
+

Functional

+ + + + + + + + + + + + + + + + + + + + + +
memoize (func)'memoize' a function (cache returned value for next call).
add_function_factory (mt, fun)associate a function factory with a type.
string_lambda (lf)an anonymous function as a string.
bind1 (fn, p)bind the first argument of the function to a value.
bind2 (fn, p)bind the second argument of the function to a value.
+

Deprecation

+ + + + + + + + + +
set_deprecation_func (func)Sets a deprecation warning function.
raise_deprecation (opts)raises a deprecation warning.
+ +
+
+ + +

Functions

+ +
+
+ + pack (...) +
+
+ pack an argument list into a table. + + +

Parameters:

+
    +
  • ... + any arguments +
  • +
+ +

Returns:

+
    + + a table with field n set to the length +
+ + +

See also:

+ + + +
+
+ + unpack (t[, i[, t]]) +
+
+ unpack a table and return its contents.

+ +

NOTE: this implementation differs from the Lua implementation in the way + that this one DOES honor the n field in the table t, such that it is 'nil-safe'. + + +

Parameters:

+
    +
  • t + index of the last element to unpack, defaults to t.n or #t + (optional) +
  • +
  • i + index from which to start unpacking, defaults to 1 + (optional) +
  • +
  • t + index of the last element to unpack, defaults to t.n or #t + (optional) +
  • +
+ +

Returns:

+
    + + multiple return values from the table +
+ + +

See also:

+ + +

Usage:

+
    +
    local t = table.pack(nil, nil, nil, 4)
    +local a, b, c, d = table.unpack(t)   -- this unpack is NOT nil-safe, so d == nil
    +
    +local a, b, c, d = utils.unpack(t)   -- this is nil-safe, so d == 4
    +
+ +
+
+ + printf (fmt, ...) +
+
+ print an arbitrary number of arguments using a format. + Output will be sent to stdout. + + +

Parameters:

+
    +
  • fmt + The format (see string.format) +
  • +
  • ... + Extra arguments for format +
  • +
+ + + + + +
+
+ + fprintf (f, fmt, ...) +
+
+ write an arbitrary number of arguments to a file using a format. + + +

Parameters:

+
    +
  • f + File handle to write to. +
  • +
  • fmt + The format (see string.format). +
  • +
  • ... + Extra arguments for format +
  • +
+ + + + + +
+
+ + import (t, T) +
+
+ take a table and 'inject' it into the local namespace. + + +

Parameters:

+
    +
  • t + The table (table), or module name (string), defaults to this utils module table +
  • +
  • T + An optional destination table (defaults to callers environment) +
  • +
+ + + + + +
+
+ + choose (cond, value1, value2) +
+
+ return either of two values, depending on a condition. + + +

Parameters:

+
    +
  • cond + A condition +
  • +
  • value1 + Value returned if cond is truthy +
  • +
  • value2 + Value returned if cond is falsy +
  • +
+ + + + + +
+
+ + array_tostring (t[, temp[, tostr]]) +
+
+ convert an array of values to strings. + + +

Parameters:

+
    +
  • t + a list-like table +
  • +
  • temp + (table) buffer to use, otherwise allocate + (optional) +
  • +
  • tostr + custom tostring function, called with (value,index). Defaults to tostring. + (optional) +
  • +
+ +

Returns:

+
    + + the converted buffer +
+ + + + +
+
+ + is_type (obj, tp) +
+
+ is the object of the specified type? + If the type is a string, then use type, otherwise compare with metatable + + +

Parameters:

+
    +
  • obj + An object to check +
  • +
  • tp + String of what type it should be +
  • +
+ +

Returns:

+
    + + boolean +
+ + + +

Usage:

+
    +
    utils.is_type("hello world", "string")   --> true
    +-- or check metatable
    +local my_mt = {}
    +local my_obj = setmetatable(my_obj, my_mt)
    +utils.is_type(my_obj, my_mt)  --> true
    +
+ +
+
+

Tables

+ +
+
+ + patterns +
+
+ Some standard patterns + + +

Fields:

+
    +
  • FLOAT + floating point number +
  • +
  • INTEGER + integer number +
  • +
  • IDEN + identifier +
  • +
  • FILE + file +
  • +
+ + + + + +
+
+ + stdmt +
+
+ Standard meta-tables as used by other Penlight modules + + +

Fields:

+
    +
  • List + the List metatable +
  • +
  • Map + the Map metatable +
  • +
  • Set + the Set metatable +
  • +
  • MultiMap + the MultiMap metatable +
  • +
+ + + + + +
+
+

Error handling

+ +
+
+ + assert_arg (n, val, tp, verify, msg, lev) +
+
+ assert that the given argument is in fact of the correct type. + + +

Parameters:

+
    +
  • n + argument index +
  • +
  • val + the value +
  • +
  • tp + the type +
  • +
  • verify + an optional verification function +
  • +
  • msg + an optional custom message +
  • +
  • lev + optional stack position for trace, default 2 +
  • +
+ +

Returns:

+
    + + the validated value +
+ +

Raises:

+ if val is not the correct type + + +

Usage:

+
    +
    local param1 = assert_arg(1,"hello",'table')  --> error: argument 1 expected a 'table', got a 'string'
    +local param4 = assert_arg(4,'!@#$%^&*','string',path.isdir,'not a directory')
    +     --> error: argument 4: '!@#$%^&*' not a directory
    +
+ +
+
+ + function_arg (idx, f, msg) +
+
+ process a function argument. + This is used throughout Penlight and defines what is meant by a function: + Something that is callable, or an operator string as defined by pl.operator, + such as '>' or '#'. If a function factory has been registered for the type, it will + be called to get the function. + + +

Parameters:

+
    +
  • idx + argument index +
  • +
  • f + a function, operator string, or callable object +
  • +
  • msg + optional error message +
  • +
+ +

Returns:

+
    + + a callable +
+ +

Raises:

+ if idx is not a number or if f is not callable + + + +
+
+ + assert_string (n, val) +
+
+ assert the common case that the argument is a string. + + +

Parameters:

+
    +
  • n + argument index +
  • +
  • val + a value that must be a string +
  • +
+ +

Returns:

+
    + + the validated value +
+ +

Raises:

+ val must be a string + + +

Usage:

+
    +
    local val = 42
    +local param2 = utils.assert_string(2, val) --> error: argument 2 expected a 'string', got a 'number'
    +
+ +
+
+ + on_error (mode) +
+
+ +

control the error strategy used by Penlight. + This is a global setting that controls how utils.raise behaves:

+ +
    +
  • 'default': return nil + error (this is the default)
  • +
  • 'error': throw a Lua error
  • +
  • 'quit': exit the program
  • +
+ + + + +

Parameters:

+
    +
  • mode + either 'default', 'quit' or 'error' +
  • +
+ + + +

See also:

+ + + +
+
+ + raise (err) +
+
+ used by Penlight functions to return errors. Its global behaviour is controlled + by utils.on_error. + To use this function you MUST use it in conjunction with return, since it might + return nil + error. + + +

Parameters:

+
    +
  • err + the error string. +
  • +
+ + + +

See also:

+ + +

Usage:

+
    +
    if some_condition then
    +  return utils.raise("some condition was not met")  -- MUST use 'return'!
    +end
    +
+ +
+
+

File handling

+ +
+
+ + readfile (filename, is_bin) +
+
+ return the contents of a file as a string + + +

Parameters:

+
    +
  • filename + The file path +
  • +
  • is_bin + open in binary mode +
  • +
+ +

Returns:

+
    + + file contents +
+ + + + +
+
+ + writefile (filename, str, is_bin) +
+
+ write a string to a file + + +

Parameters:

+
    +
  • filename + The file path +
  • +
  • str + The string +
  • +
  • is_bin + open in binary mode +
  • +
+ +

Returns:

+
    +
  1. + true or nil
  2. +
  3. + error message
  4. +
+ +

Raises:

+ error if filename or str aren't strings + + + +
+
+ + readlines (filename) +
+
+ return the contents of a file as a list of lines + + +

Parameters:

+
    +
  • filename + The file path +
  • +
+ +

Returns:

+
    + + file contents as a table +
+ +

Raises:

+ error if filename is not a string + + + +
+
+

OS functions

+ +
+
+ + executeex (cmd, bin) +
+
+ execute a shell command and return the output. + This function redirects the output to tempfiles and returns the content of those files. + + +

Parameters:

+
    +
  • cmd + a shell command +
  • +
  • bin + boolean, if true, read output as binary file +
  • +
+ +

Returns:

+
    +
  1. + true if successful
  2. +
  3. + actual return code
  4. +
  5. + stdout output (string)
  6. +
  7. + errout output (string)
  8. +
+ + + + +
+
+ + quote_arg (argument) +
+
+ Quote and escape an argument of a command. + Quotes a single (or list of) argument(s) of a command to be passed + to os.execute, pl.utils.execute or pl.utils.executeex. + + +

Parameters:

+
    +
  • argument + (string or table/list) the argument to quote. If a list then + all arguments in the list will be returned as a single string quoted. +
  • +
+ +

Returns:

+
    + + quoted and escaped argument. +
+ + + +

Usage:

+
    +
    local options = utils.quote_arg {
    +    "-lluacov",
    +    "-e",
    +    "utils = print(require('pl.utils')._VERSION",
    +}
    +-- returns: -lluacov -e 'utils = print(require('\''pl.utils'\'')._VERSION'
    +
+ +
+
+ + quit ([code], msg, ...) +
+
+ error out of this program gracefully. + + +

Parameters:

+
    +
  • code + The exit code, defaults to -1 if omitted + (optional) +
  • +
  • msg + The exit message will be sent to stderr (will be formatted with the extra parameters) +
  • +
  • ... + extra arguments for message's format' +
  • +
+ + + +

See also:

+ + +

Usage:

+
    +
    utils.quit(-1, "Error '%s' happened", "42")
    +-- is equivalent to
    +utils.quit("Error '%s' happened", "42")  --> Error '42' happened
    +
+ +
+
+

String functions

+ +
+
+ + escape (s) +
+
+ escape any Lua 'magic' characters in a string + + +

Parameters:

+
    +
  • s + The input string +
  • +
+ + + + + +
+
+ + split (s, re, plain, n) +
+
+ split a string into a list of strings separated by a delimiter. + + +

Parameters:

+
    +
  • s + The input string +
  • +
  • re + optional A Lua string pattern; defaults to '%s+' +
  • +
  • plain + optional If truthy don't use Lua patterns +
  • +
  • n + optional maximum number of elements (if there are more, the last will remian un-split) +
  • +
+ +

Returns:

+
    + + a list-like table +
+ +

Raises:

+ error if s is not a string + +

See also:

+ + + +
+
+ + splitv (s, re, plain, n) +
+
+ split a string into a number of return values. + Identical to split but returns multiple sub-strings instead of + a single list of sub-strings. + + +

Parameters:

+
    +
  • s + the string +
  • +
  • re + A Lua string pattern; defaults to '%s+' +
  • +
  • plain + don't use Lua patterns +
  • +
  • n + optional maximum number of splits +
  • +
+ +

Returns:

+
    + + n values +
+ + +

See also:

+ + +

Usage:

+
    +
    first,next = splitv('user=jane=doe','=', false, 2)
    +assert(first == "user")
    +assert(next == "jane=doe")
    +
+ +
+
+

Functional

+ +
+
+ + memoize (func) +
+
+ 'memoize' a function (cache returned value for next call). + This is useful if you have a function which is relatively expensive, + but you don't know in advance what values will be required, so + building a table upfront is wasteful/impossible. + + +

Parameters:

+
    +
  • func + a function of at least one argument +
  • +
+ +

Returns:

+
    + + a function with at least one argument, which is used as the key. +
+ + + + +
+
+ + add_function_factory (mt, fun) +
+
+ associate a function factory with a type. + A function factory takes an object of the given type and + returns a function for evaluating it + + +

Parameters:

+
    +
  • mt + tab + metatable +
  • +
  • fun + func + a callable that returns a function +
  • +
+ + + + + +
+
+ + string_lambda (lf) +
+
+ an anonymous function as a string. This string is either of the form + '|args| expression' or is a function of one argument, '_' + + +

Parameters:

+
    +
  • lf + function as a string +
  • +
+ +

Returns:

+
    + + a function +
+ + + +

Usage:

+
    +
    string_lambda '|x|x+1' (2) == 3
    +string_lambda '_+1' (2) == 3
    +
+ +
+
+ + bind1 (fn, p) +
+
+ bind the first argument of the function to a value. + + +

Parameters:

+
    +
  • fn + a function of at least two values (may be an operator string) +
  • +
  • p + a value +
  • +
+ +

Returns:

+
    + + a function such that f(x) is fn(p,x) +
+ +

Raises:

+ same as function_arg + +

See also:

+ + +

Usage:

+
    +
    local function f(msg, name)
    +  print(msg .. " " .. name)
    +end
    +
    +local hello = utils.bind1(f, "Hello")
    +
    +print(hello("world"))     --> "Hello world"
    +print(hello("sunshine"))  --> "Hello sunshine"
    +
+ +
+
+ + bind2 (fn, p) +
+
+ bind the second argument of the function to a value. + + +

Parameters:

+
    +
  • fn + a function of at least two values (may be an operator string) +
  • +
  • p + a value +
  • +
+ +

Returns:

+
    + + a function such that f(x) is fn(x,p) +
+ +

Raises:

+ same as function_arg + + +

Usage:

+
    +
    local function f(a, b, c)
    +  print(a .. " " .. b .. " " .. c)
    +end
    +
    +local hello = utils.bind1(f, "world")
    +
    +print(hello("Hello", "!"))  --> "Hello world !"
    +print(hello("Bye", "?"))    --> "Bye world ?"
    +
+ +
+
+

Deprecation

+ +
+
+ + set_deprecation_func (func) +
+
+ Sets a deprecation warning function. + An application can override this function to support proper output of + deprecation warnings. The warnings can be generated from libraries or + functions by calling utils.raise_deprecation. The default function + will write to the 'warn' system (introduced in Lua 5.4, or the compatibility + function from the compat module for earlier versions).

+ +

Note: only applications should set/change this function, libraries should not. + + +

Parameters:

+
    +
  • func + a callback with signature: function(msg, trace) both arguments are strings, the latter being optional. +
  • +
+ + + +

See also:

+ + +

Usage:

+
    +
    -- write to the Nginx logs with OpenResty
    +utils.set_deprecation_func(function(msg, trace)
    +  ngx.log(ngx.WARN, msg, (trace and (" " .. trace) or nil))
    +end)
    +
    +-- disable deprecation warnings
    +utils.set_deprecation_func()
    +
+ +
+
+ + raise_deprecation (opts) +
+
+ raises a deprecation warning. + For options see the usage example below.

+ +

Note: the opts.deprecated_after field is the last version in which + a feature or option was NOT YET deprecated! Because when writing the code it + is quite often not known in what version the code will land. But the last + released version is usually known. + + +

Parameters:

+
    +
  • opts + options table +
  • +
+ + + +

See also:

+ + +

Usage:

+
    +
    warn("@on")   -- enable Lua warnings, they are usually off by default
    +
    +function stringx.islower(str)
    +  raise_deprecation {
    +    source = "Penlight " .. utils._VERSION,                   -- optional
    +    message = "function 'islower' was renamed to 'is_lower'", -- required
    +    version_removed = "2.0.0",                                -- optional
    +    deprecated_after = "1.2.3",                               -- optional
    +    no_trace = true,                                          -- optional
    +  }
    +  return stringx.is_lower(str)
    +end
    +-- output: "[Penlight 1.9.2] function 'islower' was renamed to 'is_lower' (deprecated after 1.2.3, scheduled for removal in 2.0.0)"
    +
+ +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/libraries/pl.xml.html b/Data/Libraries/Penlight/docs/libraries/pl.xml.html new file mode 100644 index 0000000..fb280ab --- /dev/null +++ b/Data/Libraries/Penlight/docs/libraries/pl.xml.html @@ -0,0 +1,835 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module pl.xml

+

XML LOM Utilities.

+

This implements some useful things on LOM documents, such as returned by lxp.lom.parse. + In particular, it can convert LOM back into XML text, with optional pretty-printing control. + It is s based on stanza.lua from Prosody

+ + +
+> d = xml.parse "<nodes><node id='1'>alice</node></nodes>"
+> = d
+<nodes><node id='1'>alice</node></nodes>
+> = xml.tostring(d,'','  ')
+<nodes>
+   <node id='1'>alice</node>
+</nodes>
+
+ +

Can be used as a lightweight one-stop-shop for simple XML processing; a simple XML parser is included + but the default is to use lxp.lom if it can be found. +

+ Prosody IM
+ Copyright (C) 2008-2010 Matthew Wild
+ Copyright (C) 2008-2010 Waqas Hussain--
+ classic Lua XML parser by Roberto Ierusalimschy.
+ modified to output LOM format.
+ http://lua-users.org/wiki/LuaXml
+ 
+ See the Guide

+ +

Dependencies: pl.utils

+ +

Soft Dependencies: lxp.lom (fallback is to use basic Lua parser)

+ + +

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
new (tag, attr)create a new document node.
parse (text_or_file, is_file, use_basic)parse an XML document.
Doc:addtag (tag, attrs)convenient function to add a document node, This updates the last inserted position.
Doc:text (text)convenient function to add a text node.
Doc:up ()go up one level in a document
Doc:add_direct_child (child)append a child to a document directly.
Doc:add_child (child)append a child to a document at the last element added
Doc:set_attribs (t)set attributes of a document node.
Doc:set_attrib (a, v)set a single attribute of a document node.
Doc:get_attribs ()access the attributes of a document node.
elem (tag, items)function to create an element with a given tag name and a set of children.
tags (list)given a list of names, return a number of element constructors.
Doc.subst (templ, data)create a substituted copy of a document,
Doc:child_with_name (tag)get the first child with a given tag name.
Doc:get_elements_with_name (tag, dont_recurse)get all elements in a document that have a given tag.
Doc:childtags ()iterate over all child elements of a document node.
Doc:maptags (callback)visit child element of a node and call a function, possibility modifying the document.
tostring (t, idn, indent, attr_indent, xml)pretty-print an XML document
Doc:get_text ()get the full text value of an element
clone (doc, strsubst)make a copy of a document
compare (t1, t2)compare two documents.
is_tag (d)is this value a document element?
walk (doc, depth_first, operation)call the desired function recursively over the document.
parsehtml (s)Parse a well-formed HTML file as a string.
basic_parse (s, all_text, html)Parse a simple XML document using a pure Lua parser based on Robero Ierusalimschy's original version.
+ +
+
+ + +

Functions

+ +
+
+ + new (tag, attr) +
+
+ create a new document node. + + +

Parameters:

+
    +
  • tag + the tag name +
  • +
  • attr + optional attributes (table of name-value pairs) +
  • +
+ + + + + +
+
+ + parse (text_or_file, is_file, use_basic) +
+
+ parse an XML document. By default, this uses lxp.lom.parse, but + falls back to basicparse, or if usebasic is true + + +

Parameters:

+
    +
  • text_or_file + file or string representation +
  • +
  • is_file + whether textorfile is a file name or not +
  • +
  • use_basic + do a basic parse +
  • +
+ +

Returns:

+
    +
  1. + a parsed LOM document with the document metatatables set
  2. +
  3. + nil, error the error can either be a file error or a parse error
  4. +
+ + + + +
+
+ + Doc:addtag (tag, attrs) +
+
+ convenient function to add a document node, This updates the last inserted position. + + +

Parameters:

+
    +
  • tag + a tag name +
  • +
  • attrs + optional set of attributes (name-string pairs) +
  • +
+ + + + + +
+
+ + Doc:text (text) +
+
+ convenient function to add a text node. This updates the last inserted position. + + +

Parameters:

+
    +
  • text + a string +
  • +
+ + + + + +
+
+ + Doc:up () +
+
+ go up one level in a document + + + + + + + +
+
+ + Doc:add_direct_child (child) +
+
+ append a child to a document directly. + + +

Parameters:

+
    +
  • child + a child node (either text or a document) +
  • +
+ + + + + +
+
+ + Doc:add_child (child) +
+
+ append a child to a document at the last element added + + +

Parameters:

+
    +
  • child + a child node (either text or a document) +
  • +
+ + + + + +
+
+ + Doc:set_attribs (t) +
+
+ set attributes of a document node. + + +

Parameters:

+
    +
  • t + a table containing attribute/value pairs +
  • +
+ + + + + +
+
+ + Doc:set_attrib (a, v) +
+
+ set a single attribute of a document node. + + +

Parameters:

+
    +
  • a + attribute +
  • +
  • v + its value +
  • +
+ + + + + +
+
+ + Doc:get_attribs () +
+
+ access the attributes of a document node. + + + + + + + +
+
+ + elem (tag, items) +
+
+ function to create an element with a given tag name and a set of children. + + +

Parameters:

+
    +
  • tag + a tag name +
  • +
  • items + either text or a table where the hash part is the attributes and the list part is the children. +
  • +
+ + + + + +
+
+ + tags (list) +
+
+ given a list of names, return a number of element constructors. + + +

Parameters:

+
    +
  • list + a list of names, or a comma-separated string. +
  • +
+ + + + +

Usage:

+
    +
    local parent,children = doc.tags 'parent,children' <br>
    +  doc = parent {child 'one', child 'two'}
    +
+ +
+
+ + Doc.subst (templ, data) +
+
+ create a substituted copy of a document, + + +

Parameters:

+
    +
  • templ + may be a document or a string representation which will be parsed and cached +
  • +
  • data + a table of name-value pairs or a list of such tables +
  • +
+ +

Returns:

+
    + + an XML document +
+ + + + +
+
+ + Doc:child_with_name (tag) +
+
+ get the first child with a given tag name. + + +

Parameters:

+
    +
  • tag + the tag name +
  • +
+ + + + + +
+
+ + Doc:get_elements_with_name (tag, dont_recurse) +
+
+ get all elements in a document that have a given tag. + + +

Parameters:

+
    +
  • tag + a tag name +
  • +
  • dont_recurse + optionally only return the immediate children with this tag name +
  • +
+ +

Returns:

+
    + + a list of elements +
+ + + + +
+
+ + Doc:childtags () +
+
+ iterate over all child elements of a document node. + + + + + + + +
+
+ + Doc:maptags (callback) +
+
+ visit child element of a node and call a function, possibility modifying the document. + + +

Parameters:

+
    +
  • callback + a function passed the node (text or element). If it returns nil, that node will be removed. + If it returns a value, that will replace the current node. +
  • +
+ + + + + +
+
+ + tostring (t, idn, indent, attr_indent, xml) +
+
+ pretty-print an XML document + + +

Parameters:

+
    +
  • t + an XML document +
  • +
  • idn + an initial indent (indents are all strings) +
  • +
  • indent + an indent for each level +
  • +
  • attr_indent + if given, indent each attribute pair and put on a separate line +
  • +
  • xml + force prefacing with default or custom +
  • +
+ +

Returns:

+
    + + a string representation +
+ + + + +
+
+ + Doc:get_text () +
+
+ get the full text value of an element + + + + + + + +
+
+ + clone (doc, strsubst) +
+
+ make a copy of a document + + +

Parameters:

+
    +
  • doc + the original document +
  • +
  • strsubst + an optional function for handling string copying which could do substitution, etc. +
  • +
+ + + + + +
+
+ + compare (t1, t2) +
+
+ compare two documents. + + +

Parameters:

+
    +
  • t1 + any value +
  • +
  • t2 + any value +
  • +
+ + + + + +
+
+ + is_tag (d) +
+
+ is this value a document element? + + +

Parameters:

+
    +
  • d + any value +
  • +
+ + + + + +
+
+ + walk (doc, depth_first, operation) +
+
+ call the desired function recursively over the document. + + +

Parameters:

+
    +
  • doc + the document +
  • +
  • depth_first + visit child notes first, then the current node +
  • +
  • operation + a function which will receive the current tag name and current node. +
  • +
+ + + + + +
+
+ + parsehtml (s) +
+
+ Parse a well-formed HTML file as a string. + Tags are case-insenstive, DOCTYPE is ignored, and empty elements can be .. empty. + + +

Parameters:

+
    +
  • s + the HTML +
  • +
+ + + + + +
+
+ + basic_parse (s, all_text, html) +
+
+ Parse a simple XML document using a pure Lua parser based on Robero Ierusalimschy's original version. + + +

Parameters:

+
    +
  • s + the XML document to be parsed. +
  • +
  • all_text + if true, preserves all whitespace. Otherwise only text containing non-whitespace is included. +
  • +
  • html + if true, uses relaxed HTML rules for parsing +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/01-introduction.md.html b/Data/Libraries/Penlight/docs/manual/01-introduction.md.html new file mode 100644 index 0000000..fe42256 --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/01-introduction.md.html @@ -0,0 +1,843 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Introduction

+ +

+

Purpose

+ +

It is often said of Lua that it does not include batteries. That is because the +goal of Lua is to produce a lean expressive language that will be used on all +sorts of machines, (some of which don't even have hierarchical filesystems). The +Lua language is the equivalent of an operating system kernel; the creators of Lua +do not see it as their responsibility to create a full software ecosystem around +the language. That is the role of the community.

+ +

A principle of software design is to recognize common patterns and reuse them. If +you find yourself writing things like `io.write(string.format('the answer is %d +',42))` more than a number of times then it becomes useful just to define a +function printf. This is good, not just because repeated code is harder to +maintain, but because such code is easier to read, once people understand your +libraries.

+ +

Penlight captures many such code patterns, so that the intent of your code +becomes clearer. For instance, a Lua idiom to copy a table is {unpack(t)}, but +this will only work for 'small' tables (for a given value of 'small') so it is +not very robust. Also, the intent is not clear. So tablex.deepcopy is provided, +which will also copy nested tables and and associated metatables, so it can be +used to clone complex objects.

+ +

The default error handling policy follows that of the Lua standard libraries: if +a argument is the wrong type, then an error will be thrown, but otherwise we +return nil,message if there is a problem. There are some exceptions; functions +like input.fields default to shutting down the program immediately with a +useful message. This is more appropriate behaviour for a script than providing +a stack trace. (However, this default can be changed.) The lexer functions always +throw errors, to simplify coding, and so should be wrapped in pcall.

+ +

If you are used to Python conventions, please note that all indices consistently +start at 1.

+ +

The Lua function table.foreach has been deprecated in favour of the for in +statement, but such an operation becomes particularly useful with the +higher-order function support in Penlight. Note that tablex.foreach reverses +the order, so that the function is passed the value and then the key. Although +perverse, this matches the intended use better.

+ +

The only important external dependence of Penlight is +LuaFileSystem +(lfs), and if you want dir.copyfile to work cleanly on Windows, you will need +either alien or be using +LuaJIT as well. (The fallback is to call the equivalent +shell commands.)

+ +

+

To Inject or not to Inject?

+ +

It was realized a long time ago that large programs needed a way to keep names +distinct by putting them into tables (Lua), namespaces (C++) or modules +(Python). It is obviously impossible to run a company where everyone is called +'Bruce', except in Monty Python skits. These 'namespace clashes' are more of a +problem in a simple language like Lua than in C++, because C++ does more +complicated lookup over 'injected namespaces'. However, in a small group of +friends, 'Bruce' is usually unique, so in particular situations it's useful to +drop the formality and not use last names. It depends entirely on what kind of +program you are writing, whether it is a ten line script or a ten thousand line +program.

+ +

So the Penlight library provides the formal way and the informal way, without +imposing any preference. You can do it formally like:

+ + +
+local utils = require 'pl.utils'
+utils.printf("%s\n","hello, world!")
+
+ +

or informally like:

+ + +
+require 'pl'
+utils.printf("%s\n","That feels better")
+
+ +

require 'pl' makes all the separate Penlight modules available, without needing +to require them each individually.

+ +

Generally, the formal way is better when writing modules, since then there are no +global side-effects and the dependencies of your module are made explicit.

+ +

Andrew Starks has contributed another way, which balances nicely between the +formal need to keep the global table uncluttered and the informal need for +convenience. require'pl.import_into' returns a function, which accepts a table +for injecting Penlight into, or if no table is given, it passes back a new one.

+ + +
+local pl = require'pl.import_into'()
+
+ +

The table pl is a 'lazy table' which loads modules as needed, so we can then +use pl.utils.printf and so forth, without an explicit `require' or harming any +globals.

+ +

If you are using _ENV with Lua 5.2 to define modules, then here is a way to +make Penlight available within a module:

+ + +
+local _ENV,M = require 'pl.import_into' ()
+
+function answer ()
+    -- all the Penlight modules are available!
+    return pretty.write(utils.split '10 20  30', '')
+end
+
+return M
+
+ +

The default is to put Penlight into \_ENV, which has the unintended effect of +making it available from the module (much as module(...,package.seeall) does). +To satisfy both convenience and safety, you may pass true to this function, and +then the module M is not the same as \_ENV, but only contains the exported +functions.

+ +

Otherwise, Penlight will not bring in functions into the global table, or +clobber standard tables like 'io'. require('pl') will bring tables like +'utils','tablex',etc into the global table if they are used. This +'load-on-demand' strategy ensures that the whole kitchen sink is not loaded up +front, so this method is as efficient as explicitly loading required modules.

+ +

You have an option to bring the pl.stringx methods into the standard string +table. All strings have a metatable that allows for automatic lookup in string, +so we can say s:upper(). Importing stringx allows for its functions to also +be called as methods: s:strip(),etc:

+ + +
+require 'pl'
+stringx.import()
+
+ +

or, more explicitly:

+ + +
+require('pl.stringx').import()
+
+ +

A more delicate operation is importing tables into the local environment. This is +convenient when the context makes the meaning of a name very clear:

+ + +
+> require 'pl'
+> utils.import(math)
+> = sin(1.2)
+0.93203908596723
+
+ +

utils.import can also be passed a module name as a string, which is first +required and then imported. If used in a module, import will bring the symbols +into the module context.

+ +

Keeping the global scope simple is very necessary with dynamic languages. Using +global variables in a big program is always asking for trouble, especially since +you do not have the spell-checking provided by a compiler. The pl.strict +module enforces a simple rule: globals must be 'declared'. This means that they +must be assigned before use; assigning to nil is sufficient.

+ + +
+> require 'pl.strict'
+> print(x)
+stdin:1: variable 'x' is not declared
+> x = nil
+> print(x)
+nil
+
+ +

The strict module provided by Penlight is compatible with the 'load-on-demand' +scheme used by require 'pl.

+ +

strict also disallows assignment to global variables, except in the main +program. Generally, modules have no business messing with global scope; if you +must do it, then use a call to rawset. Similarly, if you have to check for the +existence of a global, use rawget.

+ +

If you wish to enforce strictness globally, then just add require 'pl.strict' +at the end of pl/init.lua, otherwise call it from your main program.

+ +

As from 1.1.0, this module provides a strict.module function which creates (or +modifies) modules so that accessing an unknown function or field causes an error.

+ +

For example,

+ + +
+-- mymod.lua
+local strict = require 'pl.strict'
+local M = strict.module (...)
+
+function M.answer ()
+    return 42
+end
+
+return M
+
+ +

If you were to accidently type mymod.Answer(), then you would get a runtime +error: "variable 'Answer' is not declared in 'mymod'".

+ +

This can be applied to existing modules. You may desire to have the same level +of checking for the Lua standard libraries:

+ + +
+strict.make_all_strict(_G)
+
+ +

Thereafter a typo such as math.cosine will give you an explicit error, rather +than merely returning a nil that will cause problems later.

+ +

+

What are function arguments in Penlight?

+ +

Many functions in Penlight themselves take function arguments, like map which +applies a function to a list, element by element. You can use existing +functions, like math.max, anonymous functions (like `function(x,y) return x > y +end ), or operations by name (e.g '*' or '..'). The module pl.operator` exports +all the standard Lua operations, like the Python module of the same name. +Penlight allows these to be referred to by name, so operator.gt can be more +concisely expressed as '>'.

+ +

Note that the map functions pass any extra arguments to the function, so we can +have ls:filter('>',0), which is a shortcut for +ls:filter(function(x) return x > 0 end).

+ +

Finally, pl.func supports placeholder expressions in the Boost lambda style, +so that an anonymous function to multiply the two arguments can be expressed as +\1*\2.

+ +

To use them directly, note that all function arguments in Penlight go through +utils.function_arg. pl.func registers itself with this function, so that you +can directly use placeholder expressions with standard methods:

+ + +
+> _1 = func._1
+> = List{10,20,30}:map(_1+1)
+{11,21,31}
+
+ +

Another option for short anonymous functions is provided by +utils.string_lambda; this is invoked automatically:

+ + +
+> = List{10,20,30}:map '|x| x + 1'
+{11,21,31}
+
+ +

+

Pros and Cons of Loopless Programming

+ +

The standard loops-and-ifs 'imperative' style of programming is dominant, and +often seems to be the 'natural' way of telling a machine what to do. It is in +fact very much how the machine does things, but we need to take a step back and +find ways of expressing solutions in a higher-level way. For instance, applying +a function to all elements of a list is a common operation:

+ + +
+local res = {}
+for i = 1,#ls do
+    res[i] = fun(ls[i])
+end
+
+ +

This can be efficiently and succintly expressed as ls:map(fun). Not only is +there less typing but the intention of the code is clearer. If readers of your +code spend too much time trying to guess your intention by analyzing your loops, +then you have failed to express yourself clearly. Similarly, ls:filter('>',0) +will give you all the values in a list greater than zero. (Of course, if you +don't feel like using List, or have non-list-like tables, then pl.tablex +offers the same facilities. In fact, the List methods are implemented using +tablex functions.)

+ +

A common observation is that loopless programming is less efficient, particularly +in the way it uses memory. ls1:map2('*',ls2):reduce '+' will give you the dot +product of two lists, but an unnecessary temporary list is created. But +efficiency is relative to the actual situation, it may turn out to be fast +enough, or may not appear in any crucial inner loops, etc.

+ +

Writing loops is 'error-prone and tedious', as Stroustrup says. But any +half-decent editor can be taught to do much of that typing for you. The question +should actually be: is it tedious to read loops? As with natural language, +programmers tend to read chunks at a time. A for-loop causes no surprise, and +probably little brain activity. One argument for loopless programming is the +loops that you do write stand out more, and signal 'something different +happening here'. It should not be an all-or-nothing thing, since most programs +require a mixture of idioms that suit the problem. Some languages (like APL) do +nearly everything with map and reduce operations on arrays, and so solutions can +sometimes seem forced. Wisdom is knowing when a particular idiom makes a +particular problem easy to solve and the solution easy to explain afterwards.

+ +

+

Generally useful functions.

+ +

The function printf discussed earlier is included in pl.utils because it +makes properly formatted output easier. (There is an equivalent fprintf which +also takes a file object parameter, just like the C function.)

+ +

Splitting a string using a delimiter is a fairly common operation, hence split.

+ +

Utility functions like is_type help with identifying what +kind of animal you are dealing with. +The Lua type function handles the basic types, but can't distinguish between +different kinds of objects, which are all tables. So is_type handles both +cases, like is_type(s,"string") and is_type(ls,List).

+ +

A common pattern when working with Lua varargs is capturing all the arguments in +a table:

+ + +
+function t(...)
+    local args = {...}
+    ...
+end
+
+ +

But this will bite you someday when nil is one of the arguments, since this +will put a 'hole' in your table. In particular, #ls will only give you the size +upto the nil value. Hence the need for table.pack - this is a new Lua 5.2 +function which Penlight defines also for Lua 5.1.

+ + +
+function t(...)
+    local args,n = table.pack(...)
+    for i = 1,n do
+      ...
+    end
+end
+
+ +

The 'memoize' pattern occurs when you have a function which is expensive to call, +but will always return the same value subsequently. utils.memoize is given a +function, and returns another function. This calls the function the first time, +saves the value for that argument, and thereafter for that argument returns the +saved value. This is a more flexible alternative to building a table of values +upfront, since in general you won't know what values are needed.

+ + +
+sum = utils.memoize(function(n)
+    local sum = 0
+    for i = 1,n do sum = sum + i end
+    return sum
+end)
+...
+s = sum(1e8) --takes time!
+...
+s = sum(1e8) --returned saved value!
+
+ +

Penlight is fully compatible with Lua 5.1, 5.2 and LuaJIT 2. To ensure this, +utils also defines the global Lua 5.2 +load function as utils.load

+ +
    +
  • the input (either a string or a function)
  • +
  • the source name used in debug information
  • +
  • the mode is a string that can have either or both of 'b' or 't', depending on + whether the source is a binary chunk or text code (default is 'bt')
  • +
  • the environment for the compiled chunk
  • +
+ +

Using utils.load should reduce the need to call the deprecated function setfenv, +and make your Lua 5.1 code 5.2-friendly.

+ +

The utils module exports getfenv and setfenv for +Lua 5.2 as well, based on code by Sergey Rozhenko. Note that these functions can fail +for functions which don't access any globals.

+ +

+

Application Support

+ +

app.parse_args is a simple command-line argument parser. If called without any +arguments, it tries to use the global arg array. It returns the flags +(options begining with '-') as a table of name/value pairs, and the arguments +as an array. It knows about long GNU-style flag names, e.g. --value, and +groups of short flags are understood, so that -ab is short for -a -b. The +flags result would then look like {value=true,a=true,b=true}.

+ +

Flags may take values. The command-line --value=open -n10 would result in +{value='open',n='10'}; generally you can use '=' or ':' to separate the flag +from its value, except in the special case where a short flag is followed by an +integer. Or you may specify upfront that some flags have associated values, and +then the values will follow the flag.

+ + +
+> require 'pl'
+> flags,args = app.parse_args({'-o','fred','-n10','fred.txt'},{o=true})
+> pretty.dump(flags)
+{o='fred',n='10'}
+
+ +

parse_args is not intelligent or psychic; it will not convert any flag values +or arguments for you, or raise errors. For that, have a look at +Lapp.

+ +

An application which consists of several files usually cannot use require to +load files in the same directory as the main script. app.require_here() +ensures that the Lua module path is modified so that files found locally are +found first. In the examples directory, test-symbols.lua uses this function +to ensure that it can find symbols.lua even if it is not run from this directory.

+ +

app.appfile will create a filename that your application can use to store its +private data, based on the script name. For example, app.appfile "test.txt" +from a script called testapp.lua produces the following file on my Windows +machine:

+ +
C:\Documents and Settings\SJDonova\.testapp\test.txt
+
+ + +

and the equivalent on my Linux machine:

+ +
/home/sdonovan/.testapp/test.txt
+
+ + +

If .testapp does not exist, it will be created.

+ +

Penlight makes it convenient to save application data in Lua format. You can use +pretty.dump(t,file) to write a Lua table in a human-readable form to a file, +and pretty.read(file.read(file)) to generate the table again, using the +pretty module.

+ + +

+

Simplifying Object-Oriented Programming in Lua

+ +

Lua is similar to JavaScript in that the concept of class is not directly +supported by the language. In fact, Lua has a very general mechanism for +extending the behaviour of tables which makes it straightforward to implement +classes. A table's behaviour is controlled by its metatable. If that metatable +has a \\index function or table, this will handle looking up anything which is +not found in the original table. A class is just a table with an __index key +pointing to itself. Creating an object involves making a table and setting its +metatable to the class; then when handling obj.fun, Lua first looks up fun in +the table obj, and if not found it looks it up in the class. obj:fun(a) is +just short for obj.fun(obj,a). So with the metatable mechanism and this bit of +syntactic sugar, it is straightforward to implement classic object orientation.

+ + +
+-- animal.lua
+
+class = require 'pl.class'
+
+class.Animal()
+
+function Animal:_init(name)
+    self.name = name
+end
+
+function Animal:__tostring()
+  return self.name..': '..self:speak()
+end
+
+class.Dog(Animal)
+
+function Dog:speak()
+  return 'bark'
+end
+
+class.Cat(Animal)
+
+function Cat:_init(name,breed)
+    self:super(name)  -- must init base!
+    self.breed = breed
+end
+
+function Cat:speak()
+  return 'meow'
+end
+
+class.Lion(Cat)
+
+function Lion:speak()
+  return 'roar'
+end
+
+fido = Dog('Fido')
+felix = Cat('Felix','Tabby')
+leo = Lion('Leo','African')
+
+$ lua -i animal.lua
+> = fido,felix,leo
+Fido: bark      Felix: meow     Leo: roar
+> = leo:is_a(Animal)
+true
+> = leo:is_a(Dog)
+false
+> = leo:is_a(Cat)
+true
+
+ +

All Animal does is define \\tostring, which Lua will use whenever a string +representation is needed of the object. In turn, this relies on speak, which is +not defined. So it's what C++ people would call an abstract base class; the +specific derived classes like Dog define speak. Please note that if derived +classes have their own constructors, they must explicitly call the base +constructor for their base class; this is conveniently available as the super +method.

+ +

Note that (as always) there are multiple ways to implement OOP in Lua; this method +uses the classic 'a class is the __index of its objects' but does 'fat inheritance'; +methods from the base class are copied into the new class. The advantage of this is +that you are not penalized for long inheritance chains, for the price of larger classes, +but generally objects outnumber classes! (If not, something odd is going on with your design.)

+ +

All such objects will have a is_a method, which looks up the inheritance chain +to find a match. Another form is class_of, which can be safely called on all +objects, so instead of leo:is_a(Animal) one can say Animal:class_of(leo).

+ +

There are two ways to define a class, either class.Name() or Name = class(); +both work identically, except that the first form will always put the class in +the current environment (whether global or module); the second form provides more +flexibility about where to store the class. The first form does name the class +by setting the _name field, which can be useful in identifying the objects of +this type later. This session illustrates the usefulness of having named classes, +if no __tostring method is explicitly defined.

+ + +
+> class.Fred()
+> a = Fred()
+> = a
+Fred: 00459330
+> Alice = class()
+> b = Alice()
+> = b
+table: 00459AE8
+> Alice._name = 'Alice'
+> = b
+Alice: 00459AE8
+
+ +

So Alice = class(); Alice._name = 'Alice' is exactly the same as class.Alice().

+ +

This useful notation is borrowed from Hugo Etchegoyen's +classlib which further +extends this concept to allow for multiple inheritance. Notice that the +more convenient form puts the class name in the current environment! That is, +you may use it safely within modules using the old-fashioned module() +or the new _ENV mechanism.

+ +

There is always more than one way of doing things in Lua; some may prefer this +style for creating classes:

+ + +
+local class = require 'pl.class'
+
+class.Named {
+    _init = function(self,name)
+        self.name = name
+    end;
+
+    __tostring = function(self)
+        return 'boo '..self.name
+    end;
+}
+
+b = Named 'dog'
+print(b)
+--> boo dog
+
+ +

Note that you have to explicitly declare self and end each function definition +with a semi-colon or comma, since this is a Lua table. To inherit from a base class, +set the special field _base to the class in this table.

+ +

Penlight provides a number of useful classes; there is List, which is a Lua +clone of the standard Python list object, and Set which represents sets. There +are three kinds of map defined: Map, MultiMap (where a key may have +multiple values) and OrderedMap (where the order of insertion is remembered.). +There is nothing special about these classes and you may inherit from them.

+ +

A powerful thing about dynamic languages is that you can redefine existing classes +and functions, which is often called 'monkey patching' It's entertaining and convenient, +but ultimately anti-social; you may modify List but then any other modules using +this shared resource can no longer be sure about its behaviour. (This is why you +must say stringx.import() explicitly if you want the extended string methods - it +would be a bad default.) Lua is particularly open to modification but the +community is not as tolerant of monkey-patching as the Ruby community, say. You may +wish to add some new methods to List? Cool, but that's what subclassing is for.

+ + +
+class.Strings(List)
+
+function Strings:my_method()
+...
+end
+
+ +

It's definitely more useful to define exactly how your objects behave +in unknown conditions. All classes have a catch method you can use to set +a handler for unknown lookups; the function you pass looks exactly like the +__index metamethod.

+ + +
+Strings:catch(function(self,name)
+    return function() error("no such method "..name,2) end
+end)
+
+ +

In this case we're just customizing the error message, but +creative things can be done. Consider this code from test-vector.lua:

+ + +
+Strings:catch(List.default_map_with(string))
+
+ls = Strings{'one','two','three'}
+asserteq(ls:upper(),{'ONE','TWO','THREE'})
+asserteq(ls:sub(1,2),{'on','tw','th'})
+
+ +

So we've converted a unknown method invocation into a map using the function of +that name found in string. So for a Vector (which is a specialization of List +for numbers) it makes sense to make math the default map so that v:sin() makes +sense.

+ +

Note that map operations return a object of the same type - this is often called +covariance. So ls:upper() itself returns a Strings object.

+ +

This is not always what you want, but objects can always be cast to the desired type. +(cast doesn't create a new object, but returns the object passed.)

+ + +
+local sizes = ls:map '#'
+asserteq(sizes, {3,3,5})
+asserteq(utils.type(sizes),'Strings')
+asserteq(sizes:is_a(Strings),true)
+sizes = Vector:cast(sizes)
+asserteq(utils.type(sizes),'Vector')
+asserteq(sizes+1,{4,4,6})
+
+ +

About utils.type: it can only return a string for a class type if that class does +in fact have a _name field.

+ + +

Properties are a useful object-oriented pattern. We wish to control access to a +field, but don't wish to force the user of the class to say obj:get_field() +etc. This excerpt from tests/test-class.lua shows how it is done:

+ + + +
+local MyProps = class(class.properties)
+local setted_a, got_b
+
+function MyProps:_init ()
+    self._a = 1
+    self._b = 2
+end
+
+function MyProps:set_a (v)
+    setted_a = true
+    self._a = v
+end
+
+function MyProps:get_b ()
+    got_b = true
+    return self._b
+end
+
+local mp = MyProps()
+
+mp.a = 10
+
+asserteq(mp.a,10)
+asserteq(mp.b,2)
+asserteq(setted_a and got_b, true)
+
+ +

The convention is that the internal field name is prefixed with an underscore; +when reading mp.a, first a check for an explicit getter get_a and then only +look for _a. Simularly, writing mp.a causes the setter set_a to be used.

+ +

This is cool behaviour, but like much Lua metaprogramming, it is not free. Method +lookup on such objects goes through \\index as before, but now \\index is a +function which has to explicitly look up methods in the class, before doing any +property indexing, which is not going to be as fast as field lookup. If however, +your accessors actually do non-trivial things, then the extra overhead could be +worth it.

+ +

This is not really intended for access control because external code can write +to mp._a directly. It is possible to have this kind of control in Lua, but it +again comes with run-time costs.

+ + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/02-arrays.md.html b/Data/Libraries/Penlight/docs/manual/02-arrays.md.html new file mode 100644 index 0000000..28dc6a2 --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/02-arrays.md.html @@ -0,0 +1,914 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Tables and Arrays

+ +

+ +

+

Python-style Lists

+ +

One of the elegant things about Lua is that tables do the job of both lists and +dicts (as called in Python) or vectors and maps, (as called in C++), and they do +it efficiently. However, if we are dealing with 'tables with numerical indices' +we may as well call them lists and look for operations which particularly make +sense for lists. The Penlight List class was originally written by Nick Trout +for Lua 5.0, and translated to 5.1 and extended by myself. It seemed that +borrowing from Python was a good idea, and this eventually grew into Penlight.

+ +

Here is an example showing List in action; it redefines __tostring, so that +it can print itself out more sensibly:

+ + +
+> List = require 'pl.List'  --> automatic with require 'pl' <---
+> l = List()
+> l:append(10)
+> l:append(20)
+> = l
+{10,20}
+> l:extend {30,40}
+{10,20,30,40}
+> l:insert(1,5)
+{5,10,20,30,40}
+> = l:pop()
+40
+> = l
+{5,10,20,30}
+> = l:index(30)
+4
+> = l:contains(30)
+true
+> = l:reverse()  ---> note: doesn't make a copy!
+{30,20,10,5}
+
+ +

Although methods like sort and reverse operate in-place and change the list, +they do return the original list. This makes it possible to do method chaining, +like ls = ls:append(10):append(20):reverse():append(1). But (and this is an +important but) no extra copy is made, so ls does not change identity. List +objects (like tables) are mutable, unlike strings. If you want a copy of a +list, then List(ls) will do the job, i.e. it acts like a copy constructor. +However, if passed any other table, List will just set the metatable of the +table and not make a copy.

+ +

A particular feature of Python lists is slicing. This is fully supported in +this version of List, except we use 1-based indexing. So List.slice works +rather like string.sub:

+ + +
+> l = List {10,20,30,40}
+> = l:slice(1,1)  ---> note: creates a new list!
+{10}
+> = l:slice(2,2)
+{20}
+> = l:slice(2,3)
+{20,30}
+> = l:slice(2,-2)
+{20,30}
+> = l:slice_assign(2,2,{21,22,23})
+{10,21,22,23,30,40}
+> = l:chop(1,1)
+{21,22,23,30,40}
+
+ +

Functions like slice_assign and chop modify the list; the first is equivalent +to Pythonl[i1:i2] = seq and the second to del l[i1:i2].

+ +

List objects are ultimately just Lua 'list-like' tables, but they have extra +operations defined on them, such as equality and concatention. For regular +tables, equality is only true if the two tables are identical objects, whereas +two lists are equal if they have the same contents, i.e. that l1[i]==l2[i] for +all elements.

+ + +
+> l1 = List {1,2,3}
+> l2 = List {1,2,3}
+> = l1 == l2
+true
+> = l1..l2
+{1,2,3,1,2,3}
+
+ +

The List constructor can be passed a function. If so, it's assumed that this is +an iterator function that can be repeatedly called to generate a sequence. One +such function is io.lines; the following short, intense little script counts +the number of lines in standard input:

+ + +
+-- linecount.lua
+require 'pl'
+ls = List(io.lines())
+print(#ls)
+
+ +

List.iterate captures what List considers a sequence. In particular, it can +also iterate over all 'characters' in a string:

+ + +
+> for ch in List.iterate 'help' do io.write(ch,' ') end
+h e l p >
+
+ +

Since the function iterate is used internally by the List constructor, +strings can be made into lists of character strings very easily.

+ +

There are a number of operations that go beyond the standard Python methods. For +instance, you can partition a list into a table of sublists using a function. +In the simplest form, you use a predicate (a function returning a boolean value) +to partition the list into two lists, one of elements matching and another of +elements not matching. But you can use any function; if we use type then the +keys will be the standard Lua type names.

+ + +
+> ls = List{1,2,3,4}
+> ops = require 'pl.operator'
+> ls:partition(function(x) return x > 2 end)
+{false={1,2},true={3,4}}
+> ls = List{'one',math.sin,List{1},10,20,List{1,2}}
+> ls:partition(type)
+{function={function: 00369110},string={one},number={10,20},table={{1},{1,2}}}
+
+ +

This is one List method which returns a table which is not a List. Bear in +mind that you can always call a List method on a plain table argument, so +List.partition(t,type) works as expected. But these functions will only operate +on the array part of the table.

+ +

The 'nominal' type of the returned table is pl.Multimap, which describes a mapping +between keys and multiple values. This does not mean that pl.Multimap is automatically +loaded whenever you use partition (or List for that matter); this is one of the +standard metatables which are only filled out when the appropriate module is loaded. +This allows tables to be tagged appropriately without causing excessive coupling.

+ +

Stacks occur everywhere in computing. List supports stack-like operations; +there is already pop (remove and return last value) and append acts like +push (add a value to the end). push is provided as an alias for append, and +the other stack operation (size) is simply the size operator #. Queues can +also be implemented; you use pop to take values out of the queue, and put to +insert a value at the begining.

+ +

You may derive classes from List, and since the list-returning methods +are covariant, the result of slice etc will return lists of the derived type, +not List. For instance, consider the specialization of a List type that contains +numbers in tests/test-list.lua:

+ + +
+n1 = NA{10,20,30}
+n2 = NA{1,2,3}
+ns = n1 + 2*n2
+asserteq(ns,{12,24,36})
+min,max = ns:slice(1,2):minmax()
+asserteq(T(min,max),T(12,24))
+asserteq(n1:normalize():sum(),1,1e-8)
+
+ +

+

Map and Set classes

+ +

The Map class exposes what Python would call a 'dict' interface, and accesses +the hash part of the table. The name 'Map' is used to emphasize the interface, +not the implementation; it is an object which maps keys onto values; m['alice'] +or the equivalent m.alice is the access operation. This class also provides +explicit set and get methods, which are trivial for regular maps but get +interesting when Map is subclassed. The other operation is update, which +extends a map by copying the keys and values from another table, perhaps +overwriting existing keys:

+ + +
+> Map = require 'pl.Map'
+> m = Map{one=1,two=2}
+> m:update {three=3,four=4,two=20}
+> = m == M{one=1,two=20,three=3,four=4}
+true
+
+ +

The method values returns a list of the values, and keys returns a list of +the keys; there is no guarantee of order. getvalues is given a list of keys and +returns a list of values associated with these keys:

+ + +
+> m = Map{one=1,two=2,three=3}
+> = m:getvalues {'one','three'}
+{1,3}
+> = m:getvalues(m:keys()) == m:values()
+true
+
+ +

When querying the value of a Map, it is best to use the get method:

+ + +
+> print(m:get 'one', m:get 'two')
+1     2
+
+ +

The reason is that m[key] can be ambiguous; due to the current implementation, +m["get"] will always succeed, because if a value is not present in the map, it +will be looked up in the Map metatable, which contains a method get. There is +currently no simple solution to this annoying restriction.

+ +

There are some useful classes which inherit from Map. An OrderedMap behaves +like a Map but keeps its keys in order if you use its set method to add keys +and values. Like all the 'container' classes in Penlight, it defines an iter +method for iterating over its values; this will return the keys and values in the +order of insertion; the keys and values methods likewise.

+ +

A MultiMap allows multiple values to be associated with a given key. So set +(as before) takes a key and a value, but calling it with the same key and a +different value does not overwrite but adds a new value. get (or using []) +will return a list of values.

+ +

A Set can be seen as a special kind of Map, where all the values are true, +the keys are the values, and the order is not important. So in this case +Set.values is defined to return a list of the keys. Sets can display +themselves, and the basic operations like union (+) and intersection (*) +are defined.

+ + +
+> Set = require 'pl.Set'
+> = Set{'one','two'} == Set{'two','one'}
+true
+> fruit = Set{'apple','banana','orange'}
+> = fruit['banana']
+true
+> = fruit['hazelnut']
+nil
+> = fruit:values()
+{apple,orange,banana}
+> colours = Set{'red','orange','green','blue'}
+> = fruit,colours
+[apple,orange,banana]   [blue,green,orange,red]
+> = fruit+colours
+[blue,green,apple,red,orange,banana]
+> = fruit*colours
+[orange]
+
+ +

There are also the functions Set.difference and Set.symmetric_difference. The +first answers the question 'what fruits are not colours?' and the second 'what +are fruits and colours but not both?'

+ + +
+> = fruit - colours
+[apple,banana]
+> = fruit ^ colours
+[blue,green,apple,red,banana]
+
+ +

Adding elements to a set is simply fruit['peach'] = true and removing is +fruit['apple'] = nil . To make this simplicity work properly, the Set class has no +methods - either you use the operator forms or explicitly use Set.intersect +etc. In this way we avoid the ambiguity that plagues Map.

+ + +

(See pl.Map and pl.Set)

+ +

+

Useful Operations on Tables

+ + +

Some notes on terminology: Lua tables are usually list-like (like an array) or +map-like (like an associative array or dict); they can of course have a +list-like and a map-like part. Some of the table operations only make sense for +list-like tables, and some only for map-like tables. (The usual Lua terminology +is the array part and the hash part of the table, which reflects the actual +implementation used; it is more accurate to say that a Lua table is an +associative map which happens to be particularly efficient at acting like an +array.)

+ +

The functions provided in table provide all the basic manipulations on Lua +tables, but as we saw with the List class, it is useful to build higher-level +operations on top of those functions. For instance, to copy a table involves this +kind of loop:

+ + +
+local res = {}
+for k,v in pairs(T) do
+    res[k] = v
+end
+return res
+
+ +

The tablex module provides this as copy, which does a shallow copy of a +table. There is also deepcopy which goes further than a simple loop in two +ways; first, it also gives the copy the same metatable as the original (so it can +copy objects like List above) and any nested tables will also be copied, to +arbitrary depth. There is also icopy which operates on list-like tables, where +you can set optionally set the start index of the source and destination as well. +It ensures that any left-over elements will be deleted:

+ + +
+asserteq(icopy({1,2,3,4,5,6},{20,30}),{20,30})   -- start at 1
+asserteq(icopy({1,2,3,4,5,6},{20,30},2),{1,20,30}) -- start at 2
+asserteq(icopy({1,2,3,4,5,6},{20,30},2,2),{1,30}) -- start at 2, copy from 2
+
+ +

(This code from the tablex test module shows the use of pl.test.asserteq)

+ +

Whereas, move overwrites but does not delete the rest of the destination:

+ + +
+asserteq(move({1,2,3,4,5,6},{20,30}),{20,30,3,4,5,6})
+asserteq(move({1,2,3,4,5,6},{20,30},2),{1,20,30,4,5,6})
+asserteq(move({1,2,3,4,5,6},{20,30},2,2),{1,30,3,4,5,6})
+
+ +

(The difference is somewhat like that between C's strcpy and memmove.)

+ +

To summarize, use copy or deepcopy to make a copy of an arbitrary table. To +copy into a map-like table, use update; to copy into a list-like table use +icopy, and move if you are updating a range in the destination.

+ +

To complete this set of operations, there is insertvalues which works like +table.insert except that one provides a table of values to be inserted, and +removevalues which removes a range of values.

+ + +
+asserteq(insertvalues({1,2,3,4},2,{20,30}),{1,20,30,2,3,4})
+asserteq(insertvalues({1,2},{3,4}),{1,2,3,4})
+
+ +

Another example:

+ + +
+> T = require 'pl.tablex'
+> t = {10,20,30,40}
+> = T.removevalues(t,2,3)
+{10,40}
+> = T.insertvalues(t,2,{20,30})
+{10,20,30,40}
+
+ +

In a similar spirit to deepcopy, deepcompare will take two tables and return +true only if they have exactly the same values and structure.

+ + +
+> t1 = {1,{2,3},4}
+> t2 = deepcopy(t1)
+> = t1 == t2
+false
+> = deepcompare(t1,t2)
+true
+
+ +

find will return the index of a given value in a list-like table. Note that +like string.find you can specify an index to start searching, so that all +instances can be found. There is an optional fourth argument, which makes the +search start at the end and go backwards, so we could define rfind like so:

+ + +
+function rfind(t,val,istart)
+    return tablex.find(t,val,istart,true)
+end
+
+ +

find does a linear search, so it can slow down code that depends on it. If +efficiency is required for large tables, consider using an index map. +index_map will return a table where the keys are the original values of the +list, and the associated values are the indices. (It is almost exactly the +representation needed for a set.)

+ + +
+> t = {'one','two','three'}
+> = tablex.find(t,'two')
+2
+> = tablex.find(t,'four')
+nil
+> il = tablex.index_map(t)
+> = il['two']
+2
+> = il.two
+2
+
+ +

A version of index_map called makeset is also provided, where the values are +just true. This is useful because two such sets can be compared for equality +using deepcompare:

+ + +
+> = deepcompare(makeset {1,2,3},makeset {2,1,3})
+true
+
+ +

Consider the problem of determining the new employees that have joined in a +period. Assume we have two files of employee names:

+ + +
+(last-month.txt)
+smith,john
+brady,maureen
+mongale,thabo
+
+(this-month.txt)
+smith,john
+smit,johan
+brady,maureen
+mogale,thabo
+van der Merwe,Piet
+
+ +

To find out differences, just make the employee lists into sets, like so:

+ + +
+require 'pl'
+
+function read_employees(file)
+  local ls = List(io.lines(file)) -- a list of employees
+  return tablex.makeset(ls)
+end
+
+last = read_employees 'last-month.txt'
+this = read_employees 'this-month.txt'
+
+-- who is in this but not in last?
+diff = tablex.difference(this,last)
+
+-- in a set, the keys are the values...
+for e in pairs(diff) do print(e) end
+
+--  *output*
+-- van der Merwe,Piet
+-- smit,johan
+
+ +

The difference operation is easy to write and read:

+ + +
+for e in pairs(this) do
+  if not last[e] then
+    print(e)
+  end
+end
+
+ +

Using difference here is not that it is a tricky thing to code, it is that you +are stating your intentions clearly to other readers of your code. (And naturally +to your future self, in six months time.)

+ +

find_if will search a table using a function. The optional third argument is a +value which will be passed as a second argument to the function. pl.operator +provides the Lua operators conveniently wrapped as functions, so the basic +comparison functions are available:

+ + +
+> ops = require 'pl.operator'
+> = tablex.find_if({10,20,30,40},ops.gt,20)
+3       true
+
+ +

Note that find_if will also return the actual value returned by the function, +which of course is usually just true for a boolean function, but any value +which is not nil and not false can be usefully passed back.

+ +

deepcompare does a thorough recursive comparison, but otherwise using the +default equality operator. compare allows you to specify exactly what function +to use when comparing two list-like tables, and compare_no_order is true if +they contain exactly the same elements. Do note that the latter does not need an +explicit comparison function - in this case the implementation is actually to +compare the two sets, as above:

+ + +
+> = compare_no_order({1,2,3},{2,1,3})
+true
+> = compare_no_order({1,2,3},{2,1,3},'==')
+true
+
+ +

(Note the special string '==' above; instead of saying ops.gt or ops.eq we +can use the strings '>' or '==' respectively.)

+ +

sort and sortv return iterators that will iterate through the +sorted elements of a table. sort iterates by sorted key order, and +sortv iterates by sorted value order. For example, given a table +with names and ages, it is trivial to iterate over the elements:

+ + +
+> t = {john=27,jane=31,mary=24}
+> for name,age in tablex.sort(t) do print(name,age) end
+jane    31
+john    27
+mary    24
+> for name,age in tablex.sortv(t) do print(name,age) end
+mary    24
+john    27
+jane    31
+
+ +

There are several ways to merge tables in PL. If they are list-like, then see the +operations defined by pl.List, like concatenation. If they are map-like, then +merge provides two basic operations. If the third arg is false, then the result +only contains the keys that are in common between the two tables, and if true, +then the result contains all the keys of both tables. These are in fact +generalized set union and intersection operations:

+ + +
+> S1 = {john=27,jane=31,mary=24}
+> S2 = {jane=31,jones=50}
+> = tablex.merge(S1, S2, false)
+{jane=31}
+> = tablex.merge(S1, S2, true)
+{mary=24,jane=31,john=27,jones=50}
+
+ +

When working with tables, you will often find yourself writing loops like in the +first example. Loops are second nature to programmers, but they are often not the +most elegant and self-describing way of expressing an operation. Consider the +map function, which creates a new table by applying a function to each element +of the original:

+ + +
+> = map(math.sin, {1,2,3,4})
+{  0.84,  0.91,  0.14, -0.76}
+> = map(function(x) return x*x end, {1,2,3,4})
+{1,4,9,16}
+
+ +

map saves you from writing a loop, and the resulting code is often clearer, as +well as being shorter. This is not to say that 'loops are bad' (although you will +hear that from some extremists), just that it's good to capture standard +patterns. Then the loops you do write will stand out and acquire more significance.

+ +

pairmap is interesting, because the function works with both the key and the +value.

+ + +
+> t = {fred=10,bonzo=20,alice=4}
+> = pairmap(function(k,v) return v end, t)
+{4,10,20}
+> = pairmap(function(k,v) return k end, t)
+{'alice','fred','bonzo'}
+
+ +

(These are common enough operations that the first is defined as values and the +second as keys.) If the function returns two values, then the second value is +considered to be the new key:

+ + +
+> = pairmap(t,function(k,v) return v+10, k:upper() end)
+{BONZO=30,FRED=20,ALICE=14}
+
+ +

map2 applies a function to two tables:

+ + +
+> map2(ops.add,{1,2},{10,20})
+{11,22}
+> map2('*',{1,2},{10,20})
+{10,40}
+
+ +

The various map operations generate tables; reduce applies a function of two +arguments over a table and returns the result as a scalar:

+ + +
+> reduce ('+', {1,2,3})
+6
+> reduce ('..', {'one','two','three'})
+'onetwothree'
+
+ +

Finally, zip sews different tables together:

+ + +
+> = zip({1,2,3},{10,20,30})
+{{1,10},{2,20},{3,30}}
+
+ +

Browsing through the documentation, you will find that tablex and List share +methods. For instance, tablex.imap and List.map are basically the same +function; they both operate over the array-part of the table and generate another +table. This can also be expressed as a list comprehension C 'f(x) for x' (t) +which makes the operation more explicit. So why are there different ways to do +the same thing? The main reason is that not all tables are Lists: the expression +ls:map('#') will return a list of the lengths of any elements of ls. A list +is a thin wrapper around a table, provided by the metatable List. Sometimes you +may wish to work with ordinary Lua tables; the List interface is not a +compulsory way to use Penlight table operations.

+ +

+

Operations on two-dimensional tables

+ + +

Two-dimensional tables are of course easy to represent in Lua, for instance +{{1,2},{3,4}} where we store rows as subtables and index like so A[col][row]. +This is the common representation used by matrix libraries like +LuaMatrix. pl.array2d does not provide +matrix operations, since that is the job for a specialized library, but rather +provides generalizations of the higher-level operations provided by pl.tablex +for one-dimensional arrays.

+ +

iter is a useful generalization of ipairs. (The extra parameter determines +whether you want the indices as well.)

+ + +
+> a = {{1,2},{3,4}}
+> for i,j,v in array2d.iter(a,true) do print(i,j,v) end
+1       1       1
+1       2       2
+2       1       3
+2       2       4
+
+ +

Note that you can always convert an arbitrary 2D array into a 'list of lists' +with List(tablex.map(List,a))

+ +

map will apply a function over all elements (notice that extra arguments can be +provided, so this operation is in effect function(x) return x-1 end)

+ + +
+> array2d.map('-',a,1)
+{{0,1},{2,3}}
+
+ +

2D arrays are stored as an array of rows, but columns can be extracted:

+ + +
+> array2d.column(a,1)
+{1,3}
+
+ +

There are three equivalents to tablex.reduce. You can either reduce along the +rows (which is the most efficient) or reduce along the columns. Either one will +give you a 1D array. And reduce2 will apply two operations: the first one +reduces the rows, and the second reduces the result.

+ + +
+> array2d.reduce_rows('+',a)
+{3,7}
+> array2d.reduce_cols('+',a)
+{4,6}
+> -- same as tablex.reduce('*',array.reduce_rows('+',a))
+> array2d.reduce2('*','+',a)
+21    `
+
+ +

tablex.map2 applies an operation to two tables, giving another table. +array2d.map2 does this for 2D arrays. Note that you have to provide the rank +of the arrays involved, since it's hard to always correctly deduce this from the +data:

+ + +
+> b = {{10,20},{30,40}}
+> a = {{1,2},{3,4}}
+> = array2d.map2('+',2,2,a,b)  -- two 2D arrays
+{{11,22},{33,44}}
+> = array2d.map2('+',1,2,{10,100},a)  -- 1D, 2D
+{{11,102},{13,104}}
+> = array2d.map2('*',2,1,a,{1,-1})  -- 2D, 1D
+{{1,-2},{3,-4}}
+
+ +

Of course, you are not limited to simple arithmetic. Say we have a 2D array of +strings, and wish to print it out with proper right justification. The first step +is to create all the string lengths by mapping string.len over the array, the +second is to reduce this along the columns using math.max to get maximum column +widths, and last, apply stringx.rjust with these widths.

+ + +
+maxlens = reduce_cols(math.max,map('#',lines))
+lines = map2(stringx.rjust,2,1,lines,maxlens)
+
+ +

There is product which returns the Cartesian product of two 1D arrays. The +result is a 2D array formed from applying the function to all possible pairs from +the two arrays.

+ + +
+> array2d.product('{}',{1,2},{'a','b'})
+{{{1,'b'},{2,'a'}},{{1,'a'},{2,'b'}}}
+
+ +

There is a set of operations which work in-place on 2D arrays. You can +swap_rows and swap_cols; the first really is a simple one-liner, but the idea +here is to give the operation a name. remove_row and remove_col are +generalizations of table.remove. Likewise, extract_rows and extract_cols +are given arrays of indices and discard anything else. So, for instance, +extract_cols(A,{2,4}) will leave just columns 2 and 4 in the array.

+ +

List.slice is often useful on 1D arrays; slice does the same thing, but is +generally given a start (row,column) and a end (row,column).

+ + +
+> A = {{1,2,3},{4,5,6},{7,8,9}}
+> B = slice(A,1,1,2,2)
+> write(B)
+ 1 2
+ 4 5
+> B = slice(A,2,2)
+> write(B,nil,'%4.1f')
+ 5.0 6.0
+ 8.0 9.0
+
+ +

Here write is used to print out an array nicely; the second parameter is nil, +which is the default (stdout) but can be any file object and the third parameter +is an optional format (as used in string.format).

+ +

parse_range will take a spreadsheet range like 'A1:B2' or 'R1C1:R2C2' and +return the range as four numbers, which can be passed to slice. The rule is +that slice will return an array of the appropriate shape depending on the +range; if a range represents a row or a column, the result is 1D, otherwise 2D.

+ +

This applies to iter as well, which can also optionally be given a range:

+ + + +
+> for i,j,v in iter(A,true,2,2) do print(i,j,v) end
+2       2       5
+2       3       6
+3       2       8
+3       3       9
+
+ +

new will construct a new 2D array with the given dimensions. You provide an +initial value for the elements, which is interpreted as a function if it's +callable. With L being utils.string_lambda we then have the following way to +make an identity matrix:

+ + +
+asserteq(
+    array.new(3,3,L'|i,j| i==j and 1 or 0'),
+    {{1,0,0},{0,1,0},{0,0,1}}
+)
+
+ +

Please note that most functions in array2d are covariant, that is, they +return an array of the same type as they receive. In particular, any objects +created with data.new or matrix.new will remain data or matrix objects when +reshaped or sliced, etc. Data objects have the array2d functions available as +methods.

+ + + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/03-strings.md.html b/Data/Libraries/Penlight/docs/manual/03-strings.md.html new file mode 100644 index 0000000..a629192 --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/03-strings.md.html @@ -0,0 +1,397 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Strings. Higher-level operations on strings.

+ +

+

Extra String Methods

+ + +

These are convenient borrowings from Python, as described in 3.6.1 of the Python +reference, but note that indices in Lua always begin at one. stringx defines +functions like isalpha and isdigit, which return true if s is only composed +of letters or digits respectively. startswith and endswith are convenient +ways to find substrings. (endswith works as in Python 2.5, so that `f:endswith +{'.bat','.exe','.cmd'}` will be true for any filename which ends with these +extensions.) There are justify methods and whitespace trimming functions like +strip.

+ + +
+> stringx.import()
+> ('bonzo.dog'):endswith {'.dog','.cat'}
+true
+> ('bonzo.txt'):endswith {'.dog','.cat'}
+false
+> ('bonzo.cat'):endswith {'.dog','.cat'}
+true
+> (' stuff'):ljust(20,'+')
+'++++++++++++++ stuff'
+> ('  stuff '):lstrip()
+'stuff '
+> ('  stuff '):rstrip()
+'  stuff'
+> ('  stuff '):strip()
+'stuff'
+> for s in ('one\ntwo\nthree\n'):lines() do print(s) end
+one
+two
+three
+
+ +

Most of these can be fairly easily implemented using the Lua string library, +which is more general and powerful. But they are convenient operations to have +easily at hand. Note that can be injected into the string table if you use +stringx.import, but a simple alias like local stringx = require 'pl.stringx' +is preferrable. This is the recommended practice when writing modules for +consumption by other people, since it is bad manners to change the global state +of the rest of the system. Magic may be used for convenience, but there is always +a price.

+ + +

+

String Templates

+ + +

Another borrowing from Python, string templates allow you to substitute values +looked up in a table:

+ + +
+local Template = require ('pl.text').Template
+t = Template('${here} is the $answer')
+print(t:substitute {here = 'Lua', answer = 'best'})
+==>
+Lua is the best
+
+ +

'$ variables' can optionally have curly braces; this form is useful if you are +glueing text together to make variables, e.g ${prefix}_name_${postfix}. The +substitute method will throw an error if a $ variable is not found in the +table, and the safe_substitute method will not.

+ +

The Lua implementation has an extra method, indent_substitute which is very +useful for inserting blocks of text, because it adjusts indentation. Consider +this example:

+ + +
+-- testtemplate.lua
+local Template = require ('pl.text').Template
+
+t = Template [[
+    for i = 1,#$t do
+        $body
+    end
+]]
+
+body = Template [[
+local row = $t[i]
+for j = 1,#row do
+    fun(row[j])
+end
+]]
+
+print(t:indent_substitute {body=body,t='tbl'})
+
+ +

And the output is:

+ + +
+for i = 1,#tbl do
+    local row = tbl[i]
+    for j = 1,#row do
+        fun(row[j])
+    end
+end
+
+ +

indent_substitute can substitute templates, and in which case they themselves +will be substituted using the given table. So in this case, $t was substituted +twice.

+ +

pl.text also has a number of useful functions like dedent, which strips all +the initial indentation from a multiline string. As in Python, this is useful for +preprocessing multiline strings if you like indenting them with your code. The +function wrap is passed a long string (a paragraph) and returns a list of +lines that fit into a desired line width. As an extension, there is also indent +for indenting multiline strings.

+ +

New in Penlight with the 0.9 series is text.format_operator. Calling this +enables Python-style string formating using the modulo operator %:

+ + +
+> text.format_operator()
+> = '%s[%d]' % {'dog',1}
+dog[1]
+
+ +

So in its simplest form it saves the typing involved with string.format; it +will also expand $ variables using named fields:

+ + +
+> = '$animal[$num]' % {animal='dog',num=1}
+dog[1]
+
+ +

As with stringx.import you have to do this explicitly, since all strings share the same +metatable. But in your own scripts you can feel free to do this.

+ +

+

Another Style of Template

+ +

A new module is template, which is a version of Rici Lake's Lua +Preprocessor. This +allows you to mix Lua code with your templates in a straightforward way. There +are only two rules:

+ +
    +
  • Lines begining with # are Lua
  • +
  • Otherwise, anything inside $() is a Lua expression.
  • +
+ +

So a template generating an HTML list would look like this:

+ + +
+<ul>
+# for i,val in ipairs(T) do
+<li>$(i) = $(val:upper())</li>
+# end
+</ul>
+
+ +

Assume the text is inside tmpl, then the template can be expanded using:

+ + +
+local template = require 'pl.template'
+local my_env = {
+  ipairs = ipairs,
+  T = {'one','two','three'}
+}
+res = template.substitute(tmpl, my_env)
+
+ +

and we get

+ + +
+<ul>
+<li>1 = ONE</li>
+<li>2 = TWO</li>
+<li>3 = THREE</li>
+</ul>
+
+ +

There is a single function, template.substitute which is passed a template +string and an environment table. This table may contain some special fields, +like \_parent which can be set to a table representing a 'fallback' environment +in case a symbol was not found. \_brackets is usually '()' and \_escape is +usually '#' but it's sometimes necessary to redefine these if the defaults +interfere with the target language - for instance, $(V) has another meaning in +Make, and # means a preprocessor line in C/C++.

+ +

Finally, if something goes wrong, passing _debug will cause the intermediate +Lua code to be dumped if there's a problem.

+ +

Here is a C code generation example; something that could easily be extended to +be a minimal Lua extension skeleton generator.

+ + +
+local subst = require 'pl.template'.substitute
+
+local templ = [[
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+> for _,f in ipairs(mod) do
+static int l_$(f.name) (lua_State *L) {
+
+}
+> end
+
+static const luaL_reg $(mod.name)[] = {
+> for _,f in ipairs(mod) do
+    {"$(f.name)",l_$(f.name)},
+> end
+    {NULL,NULL}
+};
+
+int luaopen_$(mod.name) {
+   luaL_register (L, "$(mod.name)", $(mod.name));
+    return 1;
+}
+]]
+
+print(subst(templ,{
+    _escape = '>',
+    ipairs = ipairs,
+    mod = {
+        name = 'baggins';
+        {name='frodo'},
+        {name='bilbo'}
+    }
+}))
+
+ +

+

File-style I/O on Strings

+ +

pl.stringio provides just three functions; stringio.open is passed a string, +and returns a file-like object for reading. It supports a read method, which +takes the same arguments as standard file objects:

+ + +
+> f = stringio.open 'first line\n10 20 30\n'
+> = f:read()
+first line
+> = f:read('*n','*n','*n')
+10    20    30
+
+ +

lines and seek are also supported.

+ +

stringio.lines is a useful short-cut for iterating over all the lines in a +string.

+ +

stringio.create creates a writeable file-like object. You then use write to +this stream, and finally extract the builded string using value. This 'string +builder' pattern is useful for efficiently creating large strings.

+ + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/04-paths.md.html b/Data/Libraries/Penlight/docs/manual/04-paths.md.html new file mode 100644 index 0000000..070a3ea --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/04-paths.md.html @@ -0,0 +1,329 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Paths and Directories

+ +

+

Working with Paths

+ +

Programs should not depend on quirks of your operating system. They will be +harder to read, and need to be ported for other systems. The worst of course is +hardcoding paths like 'c:\' in programs, and wondering why Vista complains so +much. But even something like dir..'\'..file is a problem, since Unix can't +understand backslashes in this way. dir..'/'..file is usually portable, but +it's best to put this all into a simple function, path.join. If you +consistently use path.join, then it's much easier to write cross-platform code, +since it handles the directory separator for you.

+ +

pl.path provides the same functionality as Python's os.path module (11.1).

+ + +
+> p = 'c:\\bonzo\\DOG.txt'
+> = path.normcase (p)  ---> only makes sense on Windows
+c:\bonzo\dog.txt
+> = path.splitext (p)
+c:\bonzo\DOG    .txt
+> = path.extension (p)
+.txt
+> = path.basename (p)
+DOG.txt
+> = path.exists(p)
+false
+> = path.join ('fred','alice.txt')
+fred\alice.txt
+> = path.exists 'pretty.lua'
+true
+> = path.getsize 'pretty.lua'
+2125
+> = path.isfile 'pretty.lua'
+true
+> = path.isdir 'pretty.lua'
+false
+
+ +

It is very important for all programmers, not just on Unix, to only write to +where they are allowed to write. path.expanduser will expand '~' (tilde) into +the home directory. Depending on your OS, this will be a guaranteed place where +you can create files:

+ + +
+> = path.expanduser '~/mydata.txt'
+'C:\Documents and Settings\SJDonova/mydata.txt'
+
+> = path.expanduser '~/mydata.txt'
+/home/sdonovan/mydata.txt
+
+ +

Under Windows, os.tmpname returns a path which leads to your drive root full of +temporary files. (And increasingly, you do not have access to this root folder.) +This is corrected by path.tmpname, which uses the environment variable TMP:

+ + +
+> os.tmpname()  -- not a good place to put temporary files!
+'\s25g.'
+> path.tmpname()
+'C:\DOCUME~1\SJDonova\LOCALS~1\Temp\s25g.1'
+
+ +

A useful extra function is pl.path.package_path, which will tell you the path +of a particular Lua module. So on my system, package_path('pl.path') returns +'C:\Program Files\Lua\5.1\lualibs\pl\path.lua', and package_path('ifs') returns +'C:\Program Files\Lua\5.1\clibs\lfs.dll'. It is implemented in terms of +package.searchpath, which is a new function in Lua 5.2 which has been +implemented for Lua 5.1 in Penlight.

+ +

+

File Operations

+ +

pl.file is a new module that provides more sensible names for common file +operations. For instance, file.read and file.write are aliases for +utils.readfile and utils.writefile.

+ +

Smaller files can be efficiently read and written in one operation. file.read +is passed a filename and returns the contents as a string, if successful; if not, +then it returns nil and the actual error message. There is an optional boolean +parameter if you want the file to be read in binary mode (this makes no +difference on Unix but remains important with Windows.)

+ +

In previous versions of Penlight, utils.readfile would read standard input if +the file was not specified, but this can lead to nasty bugs; use io.read '*a' +to grab all of standard input.

+ +

Similarly, file.write takes a filename and a string which will be written to +that file.

+ +

For example, this little script converts a file into upper case:

+ + +
+require 'pl'
+assert(#arg == 2, 'supply two filenames')
+text = assert(file.read(arg[1]))
+assert(file.write(arg[2],text:upper()))
+
+ +

Copying files is suprisingly tricky. file.copy and file.move attempt to use +the best implementation possible. On Windows, they link to the API functions +CopyFile and MoveFile, but only if the alien package is installed (this is +true for Lua for Windows.) Otherwise, the system copy command is used. This can +be ugly when writing Windows GUI applications, because of the dreaded flashing +black-box problem with launching processes.

+ +

+

Directory Operations

+ +

pl.dir provides some useful functions for working with directories. fnmatch +will match a filename against a shell pattern, and filter will return any files +in the supplied list which match the given pattern, which correspond to the +functions in the Python fnmatch module. getdirectories will return all +directories contained in a directory, and getfiles will return all files in a +directory which match a shell pattern. These functions return the files as a +table, unlike lfs.dir which returns an iterator.)

+ +

dir.makepath can create a full path, creating subdirectories as necessary; +rmtree is the Nuclear Option of file deleting functions, since it will +recursively clear out and delete all directories found begining at a path (there +is a similar function with this name in the Python shutils module.)

+ + +
+> = dir.makepath 't\\temp\\bonzo'
+> = path.isdir 't\\temp\\bonzo'
+true
+> = dir.rmtree 't'
+
+ +

dir.rmtree depends on dir.walk, which is a powerful tool for scanning a whole +directory tree. Here is the implementation of dir.rmtree:

+ + +
+--- remove a whole directory tree.
+-- @param path A directory path
+function dir.rmtree(fullpath)
+    for root,dirs,files in dir.walk(fullpath) do
+        for i,f in ipairs(files) do
+            os.remove(path.join(root,f))
+        end
+        lfs.rmdir(root)
+    end
+end
+
+ +

dir.clonetree clones directory trees. The first argument is a path that must +exist, and the second path is the path to be cloned. (Note that this path cannot +be inside the first path, since this leads to madness.) By default, it will +then just recreate the directory structure. You can in addition provide a +function, which will be applied for all files found.

+ + +
+-- make a copy of my libs folder
+require 'pl'
+p1 = [[d:\dev\lua\libs]]
+p2 = [[D:\dev\lua\libs\..\tests]]
+dir.clonetree(p1,p2,dir.copyfile)
+
+ +

A more sophisticated version, which only copies files which have been modified:

+ + +
+-- p1 and p2 as before, or from arg[1] and arg[2]
+dir.clonetree(p1,p2,function(f1,f2)
+  local res
+  local t1,t2 = path.getmtime(f1),path.getmtime(f2)
+  -- f2 might not exist, so be careful about t2
+  if not t2 or t1 > t2 then
+    res = dir.copyfile(f1,f2)
+  end
+  return res -- indicates successful operation
+end)
+
+ +

dir.clonetree uses path.common_prefix. With p1 and p2 defined above, the +common path is 'd:\dev\lua'. So 'd:\dev\lua\libs\testfunc.lua' is copied to +'d:\dev\lua\test\testfunc.lua', etc.

+ +

If you need to find the common path of list of files, then tablex.reduce will +do the job:

+ + +
+> p3 = [[d:\dev]]
+> = tablex.reduce(path.common_prefix,{p1,p2,p3})
+'d:\dev'
+
+ + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/05-dates.md.html b/Data/Libraries/Penlight/docs/manual/05-dates.md.html new file mode 100644 index 0000000..c04b036 --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/05-dates.md.html @@ -0,0 +1,269 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Date and Time

+ +

+ +

NOTE: the Date module is deprecated

+ +

+

Creating and Displaying Dates

+ +

The Date class provides a simplified way to work with date and +time in Lua; it leans heavily on the functions +os.date and os.time.

+ +

A Date object can be constructed from a table, just like with os.time. +Methods are provided to get and set the various parts of the date.

+ + +
+> d = Date {year = 2011, month = 3, day = 2 }
+> = d
+2011-03-02 12:00:00
+> = d:month(),d:year(),d:day()
+3    2011    2
+> d:month(4)
+> = d
+2011-04-02 12:00:00
+> d:add {day=1}
+> = d
+2011-04-03 12:00:00
+
+ +

add takes a table containing one of the date table fields.

+ + +
+> = d:weekday_name()
+Sun
+> = d:last_day()
+2011-04-30 12:00:00
+> = d:month_name(true)
+April
+
+ +

There is a default conversion to text for date objects, but Date.Format gives +you full control of the format for both parsing and displaying dates:

+ + +
+> iso = Date.Format 'yyyy-mm-dd'
+> d = iso:parse '2010-04-10'
+> amer = Date.Format 'mm/dd/yyyy'
+> = amer:tostring(d)
+04/10/2010
+
+ +

With the 0.9.7 relase, the Date constructor has become more flexible. You may +omit any of the 'year', 'month' or 'day' fields:

+ + +
+> = Date { year = 2008 }
+2008-01-01 12:00:00
+> = Date { month = 3 }
+2011-03-01 12:00:00
+> = Date { day = 20 }
+2011-10-20 12:00:00
+> = Date { hour = 14, min = 30 }
+2011-10-13 14:30:00
+
+ +

If 'year' is omitted, then the current year is assumed, and likewise for 'month'.

+ +

To set the time on such a partial date, you can use the fact that the 'setter' +methods return the date object and so you can 'chain' these methods.

+ + +
+> d = Date { day = 03 }
+> = d:hour(18):min(30)
+2011-10-03 18:30:00
+
+ +

Finally, Date also now accepts positional arguments:

+ + +
+> = Date(2011,10,3)
+2011-10-03 12:00:00
+> = Date(2011,10,3,18,30,23)
+2011-10-03 18:30:23
+
+ +

Date.format has been extended. If you construct an instance without a pattern, +then it will try to match against a set of known formats. This is useful for +human-input dates since keeping to a strict format is not one of the strong +points of users. It assumes that there will be a date, and then a date.

+ + +
+> df = Date.Format()
+> = df:parse '5.30pm'
+2011-10-13 17:30:00
+> = df:parse '1730'
+nil     day out of range: 1730 is not between 1 and 31
+> = df:parse '17.30'
+2011-10-13 17:30:00
+> = df:parse 'mar'
+2011-03-01 12:00:00
+> = df:parse '3 March'
+2011-03-03 12:00:00
+> = df:parse '15 March'
+2011-03-15 12:00:00
+> = df:parse '15 March 2008'
+2008-03-15 12:00:00
+> = df:parse '15 March 2008 1.30pm'
+2008-03-15 13:30:00
+> = df:parse '2008-10-03 15:30:23'
+2008-10-03 15:30:23
+
+ +

ISO date format is of course a good idea if you need to deal with users from +different countries. Here is the default behaviour for 'short' dates:

+ + +
+> = df:parse '24/02/12'
+2012-02-24 12:00:00
+
+ +

That's not what Americans expect! It's tricky to work out in a cross-platform way +exactly what the expected format is, so there is an explicit flag:

+ + +
+> df:US_order(true)
+> = df:parse '9/11/01'
+2001-11-09 12:00:00
+
+ + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/06-data.md.html b/Data/Libraries/Penlight/docs/manual/06-data.md.html new file mode 100644 index 0000000..585e23e --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/06-data.md.html @@ -0,0 +1,1633 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Data

+ +

+

Reading Data Files

+ +

The first thing to consider is this: do you actually need to write a custom file +reader? And if the answer is yes, the next question is: can you write the reader +in as clear a way as possible? Correctness, Robustness, and Speed; pick the first +two and the third can be sorted out later, if necessary.

+ +

A common sort of data file is the configuration file format commonly used on Unix +systems. This format is often called a property file in the Java world.

+ + +
+# Read timeout in seconds
+read.timeout=10
+
+# Write timeout in seconds
+write.timeout=10
+
+ +

Here is a simple Lua implementation:

+ + +
+-- property file parsing with Lua string patterns
+props = []
+for line in io.lines() do
+    if line:find('#',1,true) ~= 1 and not line:find('^%s*$') then
+        local var,value = line:match('([^=]+)=(.*)')
+        props[var] = value
+    end
+end
+
+ +

Very compact, but it suffers from a similar disease in equivalent Perl programs; +it uses odd string patterns which are 'lexically noisy'. Noisy code like this +slows the casual reader down. (For an even more direct way of doing this, see the +next section, 'Reading Configuration Files')

+ +

Another implementation, using the Penlight libraries:

+ + +
+-- property file parsing with extended string functions
+require 'pl'
+stringx.import()
+props = []
+for line in io.lines() do
+    if not line:startswith('#') and not line:isspace() then
+        local var,value = line:splitv('=')
+        props[var] = value
+    end
+end
+
+ +

This is more self-documenting; it is generally better to make the code express +the intention, rather than having to scatter comments everywhere - comments are +necessary, of course, but mostly to give the higher view of your intention that +cannot be expressed in code. It is slightly slower, true, but in practice the +speed of this script is determined by I/O, so further optimization is unnecessary.

+ +

+

Reading Unstructured Text Data

+ +

Text data is sometimes unstructured, for example a file containing words. The +pl.input module has a number of functions which makes processing such files +easier. For example, a script to count the number of words in standard input +using import.words:

+ + +
+-- countwords.lua
+require 'pl'
+local k = 1
+for w in input.words(io.stdin) do
+    k = k + 1
+end
+print('count',k)
+
+ +

Or this script to calculate the average of a set of numbers using input.numbers:

+ + +
+-- average.lua
+require 'pl'
+local k = 1
+local sum = 0
+for n in input.numbers(io.stdin) do
+    sum = sum + n
+    k = k + 1
+end
+print('average',sum/k)
+
+ +

These scripts can be improved further by eliminating loops In the last case, +there is a perfectly good function seq.sum which can already take a sequence of +numbers and calculate these numbers for us:

+ + +
+-- average2.lua
+require 'pl'
+local total,n = seq.sum(input.numbers())
+print('average',total/n)
+
+ +

A further simplification here is that if numbers or words are not passed an +argument, they will grab their input from standard input. The first script can +be rewritten:

+ + +
+-- countwords2.lua
+require 'pl'
+print('count',seq.count(input.words()))
+
+ +

A useful feature of a sequence generator like numbers is that it can read from +a string source. Here is a script to calculate the sums of the numbers on each +line in a file:

+ + +
+-- sums.lua
+for line in io.lines() do
+    print(seq.sum(input.numbers(line))
+end
+
+ +

+

Reading Columnar Data

+ +

It is very common to find data in columnar form, either space or comma-separated, +perhaps with an initial set of column headers. Here is a typical example:

+ + +
+EventID    Magnitude    LocationX    LocationY    LocationZ
+981124001    2.0    18988.4    10047.1    4149.7
+981125001    0.8    19104.0    9970.4    5088.7
+981127003    0.5    19012.5    9946.9    3831.2
+...
+
+ +

input.fields is designed to extract several columns, given some delimiter +(default to whitespace). Here is a script to calculate the average X location of +all the events:

+ + +
+-- avg-x.lua
+require 'pl'
+io.read() -- skip the header line
+local sum,count = seq.sum(input.fields {3})
+print(sum/count)
+
+ +

input.fields is passed either a field count, or a list of column indices, +starting at one as usual. So in this case we're only interested in column 3. If +you pass it a field count, then you get every field up to that count:

+ + +
+for id,mag,locX,locY,locZ in input.fields (5) do
+....
+end
+
+ +

input.fields by default tries to convert each field to a number. It will skip +lines which clearly don't match the pattern, but will abort the script if there +are any fields which cannot be converted to numbers.

+ +

The second parameter is a delimiter, by default spaces. ' ' is understood to mean +'any number of spaces', i.e. '%s+'. Any Lua string pattern can be used.

+ +

The third parameter is a data source, by default standard input (defined by +input.create_getter.) It assumes that the data source has a read method which +brings in the next line, i.e. it is a 'file-like' object. As a special case, a +string will be split into its lines:

+ + +
+> for x,y in input.fields(2,' ','10 20\n30 40\n') do print(x,y) end
+10      20
+30      40
+
+ +

Note the default behaviour for bad fields, which is to show the offending line +number:

+ + +
+> for x,y in input.fields(2,' ','10 20\n30 40x\n') do print(x,y) end
+10      20
+line 2: cannot convert '40x' to number
+
+ +

This behaviour of input.fields is appropriate for a script which you want to +fail immediately with an appropriate user error message if conversion fails. +The fourth optional parameter is an options table: {no_fail=true} means that +conversion is attempted but if it fails it just returns the string, rather as AWK +would operate. You are then responsible for checking the type of the returned +field. {no_convert=true} switches off conversion altogether and all fields are +returned as strings.

+ + +

Sometimes it is useful to bring a whole dataset into memory, for operations such +as extracting columns. Penlight provides a flexible reader specifically for +reading this kind of data, using the data module. Given a file looking like this:

+ + +
+x,y
+10,20
+2,5
+40,50
+
+ +

Then data.read will create a table like this, with each row represented by a +sublist:

+ + +
+> t = data.read 'test.txt'
+> pretty.dump(t)
+{{10,20},{2,5},{40,50},fieldnames={'x','y'},delim=','}
+
+ +

You can now analyze this returned table using the supplied methods. For instance, +the method column_by_name returns a table of all the values of that column.

+ + +
+-- testdata.lua
+require 'pl'
+d = data.read('fev.txt')
+for _,name in ipairs(d.fieldnames) do
+    local col = d:column_by_name(name)
+    if type(col[1]) == 'number' then
+        local total,n = seq.sum(col)
+        utils.printf("Average for %s is %f\n",name,total/n)
+    end
+end
+
+ +

data.read tries to be clever when given data; by default it expects a first +line of column names, unless any of them are numbers. It tries to deduce the +column delimiter by looking at the first line. Sometimes it guesses wrong; these +things can be specified explicitly. The second optional parameter is an options +table: can override delim (a string pattern), fieldnames (a list or +comma-separated string), specify no_convert (default is to convert), numfields +(indices of columns known to be numbers, as a list) and thousands_dot (when the +thousands separator in Excel CSV is '.')

+ +

A very powerful feature is a way to execute SQL-like queries on such data:

+ + +
+-- queries on tabular data
+require 'pl'
+local d = data.read('xyz.txt')
+local q = d:select('x,y,z where x > 3 and z < 2 sort by y')
+for x,y,z in q do
+    print(x,y,z)
+end
+
+ +

Please note that the format of queries is restricted to the following syntax:

+ + +
+FIELDLIST [ 'where' CONDITION ] [ 'sort by' FIELD [asc|desc]]
+
+ +

Any valid Lua code can appear in CONDITION; remember it is not SQL and you +have to use == (this warning comes from experience.)

+ +

For this to work, field names must be Lua identifiers. So read will massage +fieldnames so that all non-alphanumeric chars are replaced with underscores. +However, the original_fieldnames field always contains the original un-massaged +fieldnames.

+ +

read can handle standard CSV files fine, although doesn't try to be a +full-blown CSV parser. With the csv=true option, it's possible to have +double-quoted fields, which may contain commas; then trailing commas become +significant as well.

+ +

Spreadsheet programs are not always the best tool to +process such data, strange as this might seem to some people. This is a toy CSV +file; to appreciate the problem, imagine thousands of rows and dozens of columns +like this:

+ + +
+Department Name,Employee ID,Project,Hours Booked
+sales,1231,overhead,4
+sales,1255,overhead,3
+engineering,1501,development,5
+engineering,1501,maintenance,3
+engineering,1433,maintenance,10
+
+ +

The task is to reduce the dataset to a relevant set of rows and columns, perhaps +do some processing on row data, and write the result out to a new CSV file. The +write_row method uses the delimiter to write the row to a file; +Data.select_row is like Data.select, except it iterates over rows, not +fields; this is necessary if we are dealing with a lot of columns!

+ + +
+names = {[1501]='don',[1433]='dilbert'}
+keepcols = {'Employee_ID','Hours_Booked'}
+t:write_row (outf,{'Employee','Hours_Booked'})
+q = t:select_row {
+    fields=keepcols,
+    where=function(row) return row[1]=='engineering' end
+}
+for row in q do
+    row[1] = names[row[1]]
+    t:write_row(outf,row)
+end
+
+ +

Data.select_row and Data.select can be passed a table specifying the query; a +list of field names, a function defining the condition and an optional parameter +sort_by. It isn't really necessary here, but if we had a more complicated row +condition (such as belonging to a specified set) then it is not generally +possible to express such a condition as a query string, without resorting to +hackery such as global variables.

+ +

With 1.0.3, you can specify explicit conversion functions for selected columns. +For instance, this is a log file with a Unix date stamp:

+ + +
+Time Message
+1266840760 +# EE7C0600006F0D00C00F06010302054000000308010A00002B00407B00
+1266840760 closure data 0.000000 1972 1972 0
+1266840760 ++ 1266840760 EE 1
+1266840760 +# EE7C0600006F0D00C00F06010302054000000408020A00002B00407B00
+1266840764 closure data 0.000000 1972 1972 0
+
+ +

We would like the first column as an actual date object, so the convert +field sets an explicit conversion for column 1. (Note that we have to explicitly +convert the string to a number first.)

+ + +
+Date = require 'pl.Date'
+
+function date_convert (ds)
+    return Date(tonumber(ds))
+end
+
+d = data.read(f,{convert={[1]=date_convert},last_field_collect=true})
+
+ +

This gives us a two-column dataset, where the first column contains Date objects +and the second column contains the rest of the line. Queries can then easily +pick out events on a day of the week:

+ + +
+q = d:select "Time,Message where Time:weekday_name()=='Sun'"
+
+ +

Data does not have to come from files, nor does it necessarily come from the lab +or the accounts department. On Linux, ps aux gives you a full listing of all +processes running on your machine. It is straightforward to feed the output of +this command into data.read and perform useful queries on it. Notice that +non-identifier characters like '%' get converted into underscores:

+ + +
+require 'pl'
+f = io.popen 'ps aux'
+s = data.read (f,{last_field_collect=true})
+f:close()
+print(s.fieldnames)
+print(s:column_by_name 'USER')
+qs = 'COMMAND,_MEM where _MEM > 5 and USER=="steve"'
+for name,mem in s:select(qs) do
+    print(mem,name)
+end
+
+ +

I've always been an admirer of the AWK programming language; with filter you +can get Lua programs which are just as compact:

+ + +
+-- printxy.lua
+require 'pl'
+data.filter 'x,y where x > 3'
+
+ +

It is common enough to have data files without headers of field names. +data.read makes a special exception for such files if all fields are numeric. +Since there are no column names to use in query expressions, you can use AWK-like +column indexes, e.g. '$1,$2 where $1 > 3'. I have a little executable script on +my system called lf which looks like this:

+ + +
+#!/usr/bin/env lua
+require 'pl.data'.filter(arg[1])
+
+ +

And it can be used generally as a filter command to extract columns from data. +(The column specifications may be expressions or even constants.)

+ + +
+$ lf '$1,$5/10' < test.dat
+
+ +

(As with AWK, please note the single-quotes used in this command; this prevents +the shell trying to expand the column indexes. If you are on Windows, then you +must quote the expression in double-quotes so +it is passed as one argument to your batch file.)

+ +

As a tutorial resource, have a look at test-data.lua in the PL tests directory +for other examples of use, plus comments.

+ +

The data returned by read or constructed by Data.copy_select from a query is +basically just an array of rows: {{1,2},{3,4}}. So you may use read to pull +in any array-like dataset, and process with any function that expects such a +implementation. In particular, the functions in array2d will work fine with +this data. In fact, these functions are available as methods; e.g. +array2d.flatten can be called directly like so to give us a one-dimensional list:

+ + +
+v = data.read('dat.txt'):flatten()
+
+ +

The data is also in exactly the right shape to be treated as matrices by +LuaMatrix:

+ + +
+> matrix = require 'matrix'
+> m = matrix(data.read 'mat.txt')
+> = m
+1       0.2     0.3
+0.2     1       0.1
+0.1     0.2     1
+> = m^2  -- same as m*m
+1.07    0.46    0.62
+0.41    1.06    0.26
+0.24    0.42    1.05
+
+ +

write will write matrices back to files for you.

+ +

Finally, for the curious, the global variable _DEBUG can be used to print out +the actual iterator function which a query generates and dynamically compiles. By +using code generation, we can get pretty much optimal performance out of +arbitrary queries.

+ + +
+> lua -lpl -e "_DEBUG=true" -e "data.filter 'x,y where x > 4 sort by x'" < test.txt
+return function (t)
+        local i = 0
+        local v
+        local ls = {}
+        for i,v in ipairs(t) do
+            if v[1] > 4  then
+                    ls[#ls+1] = v
+            end
+        end
+        table.sort(ls,function(v1,v2)
+            return v1[1] < v2[1]
+        end)
+        local n = #ls
+        return function()
+            i = i + 1
+            v = ls[i]
+            if i > n then return end
+            return v[1],v[2]
+        end
+end
+
+10,20
+40,50
+
+ +

+

Reading Configuration Files

+ +

The config module provides a simple way to convert several kinds of +configuration files into a Lua table. Consider the simple example:

+ + +
+# test.config
+# Read timeout in seconds
+read.timeout=10
+
+# Write timeout in seconds
+write.timeout=5
+
+#acceptable ports
+ports = 1002,1003,1004
+
+ +

This can be easily brought in using config.read and the result shown using +pretty.write:

+ + +
+-- readconfig.lua
+local config = require 'pl.config'
+local pretty= require 'pl.pretty'
+
+local t = config.read(arg[1])
+print(pretty.write(t))
+
+ +

and the output of lua readconfig.lua test.config is:

+ + +
+{
+  ports = {
+    1002,
+    1003,
+    1004
+  },
+  write_timeout = 5,
+  read_timeout = 10
+}
+
+ +

That is, config.read will bring in all key/value pairs, ignore # comments, and +ensure that the key names are proper Lua identifiers by replacing non-identifier +characters with '_'. If the values are numbers, then they will be converted. (So +the value of t.write_timeout is the number 5). In addition, any values which +are separated by commas will be converted likewise into an array.

+ +

Any line can be continued with a backslash. So this will all be considered one +line:

+ + +
+names=one,two,three, \
+four,five,six,seven, \
+eight,nine,ten
+
+ +

Windows-style INI files are also supported. The section structure of INI files +translates naturally to nested tables in Lua:

+ + +
+; test.ini
+[timeouts]
+read=10 ; Read timeout in seconds
+write=5 ; Write timeout in seconds
+[portinfo]
+ports = 1002,1003,1004
+
+ +

The output is:

+ + +
+{
+  portinfo = {
+    ports = {
+      1002,
+      1003,
+      1004
+    }
+  },
+  timeouts = {
+    write = 5,
+    read = 10
+  }
+}
+
+ +

You can now refer to the write timeout as t.timeouts.write.

+ +

As a final example of the flexibility of config.read, if passed this simple +comma-delimited file

+ + +
+one,two,three
+10,20,30
+40,50,60
+1,2,3
+
+ +

it will produce the following table:

+ + +
+{
+  { "one", "two", "three" },
+  { 10, 20, 30 },
+  { 40, 50, 60  },
+  { 1, 2, 3 }
+}
+
+ +

config.read isn't designed to read all CSV files in general, but intended to +support some Unix configuration files not structured as key-value pairs, such as +'/etc/passwd'.

+ +

This function is intended to be a Swiss Army Knife of configuration readers, but +it does have to make assumptions, and you may not like them. So there is an +optional extra parameter which allows some control, which is table that may have +the following fields:

+ + +
+{
+   variablilize = true,
+   convert_numbers = tonumber,
+   trim_space = true,
+   list_delim = ',',
+   trim_quotes = true,
+   ignore_assign = false,
+   keysep = '=',
+   smart = false,
+}
+
+ +

variablilize is the option that converted write.timeout in the first example +to the valid Lua identifier write_timeout. If convert_numbers is true, then +an attempt is made to convert any string that starts like a number. You can +specify your own function (say one that will convert a string like '5224 kb' into +a number.)

+ +

trim_space ensures that there is no starting or trailing whitespace with +values, and list_delim is the character that will be used to decide whether to +split a value up into a list (it may be a Lua string pattern such as '%s+'.)

+ +

For instance, the password file in Unix is colon-delimited:

+ + +
+t = config.read('/etc/passwd',{list_delim=':'})
+
+ +

This produces the following output on my system (only last two lines shown):

+ + +
+{
+  ...
+  {
+    "user",
+    "x",
+    "1000",
+    "1000",
+    "user,,,",
+    "/home/user",
+    "/bin/bash"
+  },
+  {
+    "sdonovan",
+    "x",
+    "1001",
+    "1001",
+    "steve donovan,28,,",
+    "/home/sdonovan",
+    "/bin/bash"
+  }
+}
+
+ +

You can get this into a more sensible format, where the usernames are the keys, +with this (the tablex.pairmap function must return value, key!)

+ + +
+t = tablex.pairmap(function(k,v) return v,v[1] end,t)
+
+ +

and you get:

+ + +
+{ ...
+  sdonovan = {
+    "sdonovan",
+    "x",
+    "1001",
+    "1001",
+    "steve donovan,28,,",
+    "/home/sdonovan",
+    "/bin/bash"
+  }
+...
+}
+
+ +

Many common Unix configuration files can be read by tweaking these parameters. +For /etc/fstab, the options {list_delim='%s+',ignore_assign=true} will +correctly separate the columns. It's common to find 'KEY VALUE' assignments in +files such as /etc/ssh/ssh_config; the options {keysep=' '} make +config.read return a table where each KEY has a value VALUE.

+ +

Files in the Linux procfs usually use ':` as the field delimiter:

+ + +
+> t = config.read('/proc/meminfo',{keysep=':'})
+> = t.MemFree
+220140 kB
+
+ +

That result is a string, since tonumber doesn't like it, but defining the +convert_numbers option as `function(s) return tonumber((s:gsub(' kB$',''))) +end` will get the memory figures as actual numbers in the result. (The extra +parentheses are necessary so that tonumber only gets the first result from +gsub). From `tests/test-config.lua':

+ + +
+testconfig([[
+MemTotal:        1024748 kB
+MemFree:          220292 kB
+]],
+{ MemTotal = 1024748, MemFree = 220292 },
+{
+ keysep = ':',
+ convert_numbers = function(s)
+    s = s:gsub(' kB$','')
+    return tonumber(s)
+  end
+ }
+)
+
+ +

The smart option lets config.read make a reasonable guess for you; there +are examples in tests/test-config.lua, but basically these common file +formats (and those following the same pattern) can be processed directly in +smart mode: 'etc/fstab', '/proc/XXXX/status', 'ssh_config' and 'pdatedb.conf'.

+ +

Please note that config.read can be passed a file-like object; if it's not a +string and supports the read method, then that will be used. For instance, to +read a configuration from a string, use stringio.open.

+ + +

+ +

+

Lexical Scanning

+ +

Although Lua's string pattern matching is very powerful, there are times when +something more powerful is needed. pl.lexer.scan provides lexical scanners +which tokenize a string, classifying tokens into numbers, strings, etc.

+ + +
+> lua -lpl
+Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
+> tok = lexer.scan 'alpha = sin(1.5)'
+> = tok()
+iden    alpha
+> = tok()
+=       =
+> = tok()
+iden    sin
+> = tok()
+(       (
+> = tok()
+number  1.5
+> = tok()
+)       )
+> = tok()
+(nil)
+
+ +

The scanner is a function, which is repeatedly called and returns the type and +value of the token. Recognized basic types are 'iden','string','number', and +'space'. and everything else is represented by itself. Note that by default the +scanner will skip any 'space' tokens.

+ +

'comment' and 'keyword' aren't applicable to the plain scanner, which is not +language-specific, but a scanner which understands Lua is available. It +recognizes the Lua keywords, and understands both short and long comments and +strings.

+ + +
+> for t,v in lexer.lua 'for i=1,n do' do print(t,v) end
+keyword for
+iden    i
+=       =
+number  1
+,       ,
+iden    n
+keyword do
+
+ +

A lexical scanner is useful where you have highly-structured data which is not +nicely delimited by newlines. For example, here is a snippet of a in-house file +format which it was my task to maintain:

+ + +
+points
+    (818344.1,-20389.7,-0.1),(818337.9,-20389.3,-0.1),(818332.5,-20387.8,-0.1)
+    ,(818327.4,-20388,-0.1),(818322,-20387.7,-0.1),(818316.3,-20388.6,-0.1)
+    ,(818309.7,-20389.4,-0.1),(818303.5,-20390.6,-0.1),(818295.8,-20388.3,-0.1)
+    ,(818290.5,-20386.9,-0.1),(818285.2,-20386.1,-0.1),(818279.3,-20383.6,-0.1)
+    ,(818274,-20381.2,-0.1),(818274,-20380.7,-0.1);
+
+ +

Here is code to extract the points using pl.lexer:

+ + +
+-- assume 's' contains the text above...
+local lexer = require 'pl.lexer'
+local expecting = lexer.expecting
+local append = table.insert
+
+local tok = lexer.scan(s)
+
+local points = {}
+local t,v = tok() -- should be 'iden','points'
+
+while t ~= ';' do
+    c = {}
+    expecting(tok,'(')
+    c.x = expecting(tok,'number')
+    expecting(tok,',')
+    c.y = expecting(tok,'number')
+    expecting(tok,',')
+    c.z = expecting(tok,'number')
+    expecting(tok,')')
+    t,v = tok()  -- either ',' or ';'
+    append(points,c)
+end
+
+ +

The expecting function grabs the next token and if the type doesn't match, it +throws an error. (pl.lexer, unlike other PL libraries, raises errors if +something goes wrong, so you should wrap your code in pcall to catch the error +gracefully.)

+ +

The scanners all have a second optional argument, which is a table which controls +whether you want to exclude spaces and/or comments. The default for lexer.lua +is {space=true,comments=true}. There is a third optional argument which +determines how string and number tokens are to be processsed.

+ +

The ultimate highly-structured data is of course, program source. Here is a +snippet from 'text-lexer.lua':

+ + +
+require 'pl'
+
+lines = [[
+for k,v in pairs(t) do
+    if type(k) == 'number' then
+        print(v) -- array-like case
+    else
+        print(k,v)
+    end
+end
+]]
+
+ls = List()
+for tp,val in lexer.lua(lines,{space=true,comments=true}) do
+    assert(tp ~= 'space' and tp ~= 'comment')
+    if tp == 'keyword' then ls:append(val) end
+end
+test.asserteq(ls,List{'for','in','do','if','then','else','end','end'})
+
+ +

Here is a useful little utility that identifies all common global variables found +in a lua module (ignoring those declared locally for the moment):

+ + +
+-- testglobal.lua
+require 'pl'
+
+local txt,err = utils.readfile(arg[1])
+if not txt then return print(err) end
+
+local globals = List()
+for t,v in lexer.lua(txt) do
+    if t == 'iden' and _G[v] then
+        globals:append(v)
+    end
+end
+pretty.dump(seq.count_map(globals))
+
+ +

Rather then dumping the whole list, with its duplicates, we pass it through +seq.count_map which turns the list into a table where the keys are the values, +and the associated values are the number of times those values occur in the +sequence. Typical output looks like this:

+ + +
+{
+  type = 2,
+  pairs = 2,
+  table = 2,
+  print = 3,
+  tostring = 2,
+  require = 1,
+  ipairs = 4
+}
+
+ +

You could further pass this through tablex.keys to get a unique list of +symbols. This can be useful when writing 'strict' Lua modules, where all global +symbols must be defined as locals at the top of the file.

+ +

For a more detailed use of lexer.scan, please look at testxml.lua in the +examples directory.

+ +

+

XML

+ +

New in the 0.9.7 release is some support for XML. This is a large topic, and +Penlight does not provide a full XML stack, which is properly the task of a more +specialized library.

+ +

Parsing and Pretty-Printing

+ +

The semi-standard XML parser in the Lua universe is lua-expat. +In particular, +it has a function called lxp.lom.parse which will parse XML into the Lua Object +Model (LOM) format. However, it does not provide a way to convert this data back +into XML text. xml.parse will use this function, if lua-expat is +available, and otherwise switches back to a pure Lua parser originally written by +Roberto Ierusalimschy.

+ +

The resulting document object knows how to render itself as a string, which is +useful for debugging:

+ + +
+> d = xml.parse "<nodes><node id='1'>alice</node></nodes>"
+> = d
+<nodes><node id='1'>alice</node></nodes>
+> pretty.dump (d)
+{
+  {
+    "alice",
+    attr = {
+      "id",
+      id = "1"
+    },
+    tag = "node"
+  },
+  attr = {
+  },
+  tag = "nodes"
+}
+
+ +

Looking at the actual shape of the data reveals the structure of LOM:

+ +
    +
  • every element has a tag field with its name
  • +
  • plus a attr field which is a table containing the attributes as fields, and + also as an array. It is always present.
  • +
  • the children of the element are the array part of the element, so d[1] is + the first child of d, etc.
  • +
+ +

It could be argued that having attributes also as the array part of attr is not +essential (you cannot depend on attribute order in XML) but that's how +it goes with this standard.

+ +

lua-expat is another soft dependency of Penlight; generally, the fallback +parser is good enough for straightforward XML as is commonly found in +configuration files, etc. doc.basic_parse is not intended to be a proper +conforming parser (it's only sixty lines) but it handles simple kinds of +documents that do not have comments or DTD directives. It is intelligent enough +to ignore the <?xml directive and that is about it.

+ +

You can get pretty-printing by explicitly calling xml.tostring and passing it +the initial indent and the per-element indent:

+ + +
+> = xml.tostring(d,'','  ')
+
+<nodes>
+  <node id='1'>alice</node>
+</nodes>
+
+ +

There is a fourth argument which is the attribute indent:

+ + +
+> a = xml.parse "<frodo name='baggins' age='50' type='hobbit'/>"
+> = xml.tostring(a,'','  ','  ')
+
+<frodo
+  type='hobbit'
+  name='baggins'
+  age='50'
+/>
+
+ +

Parsing and Working with Configuration Files

+ +

It's common to find configurations expressed with XML these days. It's +straightforward to 'walk' the LOM +data and extract the data in the form you want:

+ + +
+require 'pl'
+
+local config = [[
+<config>
+    <alpha>1.3</alpha>
+    <beta>10</beta>
+    <name>bozo</name>
+</config>
+]]
+local d,err = xml.parse(config)
+
+local t = {}
+for item in d:childtags() do
+    t[item.tag] = item[1]
+end
+
+pretty.dump(t)
+--->
+{
+  beta = "10",
+  alpha = "1.3",
+  name = "bozo"
+}
+
+ +

The only gotcha is that here we must use the Doc:childtags method, which will +skip over any text elements.

+ +

A more involved example is this excerpt from serviceproviders.xml, which is +usually found at /usr/share/mobile-broadband-provider-info/serviceproviders.xml +on Debian/Ubuntu Linux systems.

+ + +
+d = xml.parse [[
+<serviceproviders format="2.0">
+...
+<country code="za">
+    <provider>
+        <name>Cell-c</name>
+        <gsm>
+            <network-id mcc="655" mnc="07"/>
+            <apn value="internet">
+                <username>Cellcis</username>
+                <dns>196.7.0.138</dns>
+                <dns>196.7.142.132</dns>
+            </apn>
+        </gsm>
+    </provider>
+    <provider>
+        <name>MTN</name>
+        <gsm>
+            <network-id mcc="655" mnc="10"/>
+            <apn value="internet">
+                <dns>196.11.240.241</dns>
+                <dns>209.212.97.1</dns>
+            </apn>
+        </gsm>
+    </provider>
+    <provider>
+        <name>Vodacom</name>
+        <gsm>
+            <network-id mcc="655" mnc="01"/>
+            <apn value="internet">
+                <dns>196.207.40.165</dns>
+                <dns>196.43.46.190</dns>
+            </apn>
+            <apn value="unrestricted">
+                <name>Unrestricted</name>
+                <dns>196.207.32.69</dns>
+                <dns>196.43.45.190</dns>
+            </apn>
+        </gsm>
+    </provider>
+    <provider>
+        <name>Virgin Mobile</name>
+        <gsm>
+            <apn value="vdata">
+                <dns>196.7.0.138</dns>
+                <dns>196.7.142.132</dns>
+            </apn>
+        </gsm>
+    </provider>
+</country>
+....
+</serviceproviders>
+]]
+
+ +

Getting the names of the providers per-country is straightforward:

+ + +
+local t = {}
+for country in d:childtags() do
+    local providers = {}
+    t[country.attr.code] = providers
+    for provider in country:childtags() do
+        table.insert(providers,provider:child_with_name('name'):get_text())
+    end
+end
+
+pretty.dump(t)
+-->
+{
+  za = {
+    "Cell-c",
+    "MTN",
+    "Vodacom",
+    "Virgin Mobile"
+  }
+  ....
+}
+
+ +

Generating XML with 'xmlification'

+ +

This feature is inspired by the htmlify function used by +Orbit to simplify HTML generation, +except that no function environment magic is used; the tags function returns a +set of constructors for elements of the given tag names.

+ + +
+> nodes, node = xml.tags 'nodes, node'
+> = node 'alice'
+<node>alice</node>
+> = nodes { node {id='1','alice'}}
+<nodes><node id='1'>alice</node></nodes>
+
+ +

The flexibility of Lua tables is very useful here, since both the attributes and +the children of an element can be encoded naturally. The argument to these tag +constructors is either a single value (like a string) or a table where the +attributes are the named keys and the children are the array values.

+ +

Generating XML using Templates

+ +

A template is a little XML document which contains dollar-variables. The subst +method on a document is fed an array of tables containing values for these +variables. Note how the parent tag name is specified:

+ + +
+> templ = xml.parse "<node id='$id'>$name</node>"
+> = templ:subst {tag='nodes', {id=1,name='alice'},{id=2,name='john'}}
+<nodes><node id='1'>alice</node><node id='2'>john</node></nodes>
+
+ +

Substitution is very related to filtering documents. One of the annoying things +about XML is that it is a document markup language first, and a data language +second. Standard parsers will assume you really care about all those extra +text elements. Consider this fragment, which has been changed by a five-year old:

+ + +
+T = [[
+  <weather>
+    boops!
+    <current_conditions>
+      <condition data='$condition'/>
+      <temp_c data='$temp'/>
+      <bo>whoops!</bo>
+    </current_conditions>
+  </weather>
+]]
+
+ +

Conformant parsers will give you text elements with the line feed after <current_conditions> +although it makes handling the data more irritating.

+ + +
+local function parse (str)
+    return xml.parse(str,false,true)
+end
+
+ +

Second argument means 'string, not file' and third argument means use the built-in +Lua parser (instead of LuaExpat if available) which by default is not interested in +keeping such strings.

+ +

How to remove the string boops!? clone (also called filter when called as a +method) copies a LOM document. It can be passed a filter function, which is applied +to each string found. The powerful thing about this is that this function receives +structural information - the parent node, and whether this was a tag name, a text +element or a attribute name:

+ + +
+d = parse (T)
+c = d:filter(function(s,kind,parent)
+    print(stringx.strip(s),kind,parent and parent.tag or '?')
+    if kind == '*TEXT' and #parent > 1 then return nil end
+    return s
+end)
+--->
+weather    *TAG    ?
+boops!    *TEXT    weather
+current_conditions    *TAG    weather
+condition    *TAG    current_conditions
+$condition    data    condition
+temp_c    *TAG    current_conditions
+$temp    data    temp_c
+bo    *TAG    current_conditions
+whoops!    *TEXT    bo
+
+ +

We can pull out 'boops' and not 'whoops' by discarding text elements which are not +the single child of an element.

+ + + +

Extracting Data using Templates

+ +

Matching goes in the opposite direction. We have a document, and would like to +extract values from it using a pattern.

+ +

A common use of this is parsing the XML result of API queries. The +(undocumented and subsequently discontinued) Google Weather +API is a +good example. Grabbing the result of +`http://www.google.com/ig/api?weather=Johannesburg,ZA" we get something like +this, after pretty-printing:

+ + +
+<xml_api_reply version='1'>
+  <weather module_id='0' tab_id='0' mobile_zipped='1' section='0' row='0'
+
+ +

mobile_row='0'>

+ +
+<forecast_information>
+  <city data='Johannesburg, Gauteng'/>
+  <postal_code data='Johannesburg,ZA'/>
+  <latitude_e6 data=''/>
+  <longitude_e6 data=''/>
+  <forecast_date data='2010-10-02'/>
+  <current_date_time data='2010-10-02 18:30:00 +0000'/>
+  <unit_system data='US'/>
+</forecast_information>
+<current_conditions>
+  <condition data='Clear'/>
+  <temp_f data='75'/>
+  <temp_c data='24'/>
+  <humidity data='Humidity: 19%'/>
+  <icon data='/ig/images/weather/sunny.gif'/>
+  <wind_condition data='Wind: NW at 7 mph'/>
+</current_conditions>
+<forecast_conditions>
+  <day_of_week data='Sat'/>
+  <low data='60'/>
+  <high data='89'/>
+  <icon data='/ig/images/weather/sunny.gif'/>
+  <condition data='Clear'/>
+</forecast_conditions>
+....
+/weather>
+l_api_reply>
+
+ +

Assume that the above XML has been read into google. The idea is to write a +pattern looking like a template, and use it to extract some values of interest:

+ + +
+t = [[
+  <weather>
+    <current_conditions>
+      <condition data='$condition'/>
+      <temp_c data='$temp'/>
+    </current_conditions>
+  </weather>
+]]
+
+local res, ret = google:match(t)
+pretty.dump(res)
+
+ +

And the output is:

+ + +
+{
+  condition = "Clear",
+  temp = "24"
+}
+
+ +

The match method can be passed a LOM document or some text, which will be +parsed first.

+ +

But what if we need to extract values from repeated elements? Match templates may +contain 'array matches' which are enclosed in '{{..}}':

+ + +
+<weather>
+  {{<forecast_conditions>
+    <day_of_week data='$day'/>
+    <low data='$low'/>
+    <high data='$high'/>
+    <condition data='$condition'/>
+  </forecast_conditions>}}
+</weather>
+
+ +

And the match result is:

+ + +
+{
+  {
+    low = "60",
+    high = "89",
+    day = "Sat",
+    condition = "Clear",
+  },
+  {
+    low = "53",
+    high = "86",
+    day = "Sun",
+    condition = "Clear",
+  },
+  {
+    low = "57",
+    high = "87",
+    day = "Mon",
+    condition = "Clear",
+  },
+  {
+    low = "60",
+    high = "84",
+    day = "Tue",
+    condition = "Clear",
+  }
+}
+
+ +

With this array of tables, you can use tablex or List +to reshape into the desired form, if you choose. Just as with reading a Unix password +file with config, you can make the array into a map of days to conditions using:

+ + +
+tablex.pairmap('|k,v| v,v.day',conditions)
+
+ +

(Here using the alternative string lambda option)

+ +

However, xml matches can shape the structure of the output. By replacing the day_of_week +line of the template with <day_of_week data='$_'/> we get the same effect; $_ is +a special symbol that means that this captured value (or simply capture) becomes the key.

+ +

Note that $NUMBER means a numerical index, so +that $1 is the first element of the resulting array, and so forth. You can mix +numbered and named captures, but it's strongly advised to make the numbered captures +form a proper array sequence (everything from 1 to n inclusive). $0 has a +special meaning; if it is the only capture ({[0]='foo'}) then the table is +collapsed into 'foo'.

+ + +
+<weather>
+  {{<forecast_conditions>
+    <day_of_week data='$_'/>
+    <low data='$1'/>
+    <high data='$2'/>
+    <condition data='$3'/>
+  </forecast_conditions>}}
+</weather>
+
+ +

Now the result is:

+ + +
+{
+  Tue = {
+    "60",
+    "84",
+    "Clear"
+  },
+  Sun = {
+    "53",
+    "86",
+    "Clear"
+  },
+  Sat = {
+    "60",
+    "89",
+    "Clear"
+  },
+  Mon = {
+    "57",
+    "87",
+    "Clear"
+  }
+}
+
+ +

Applying matches to this config file poses another problem, because the actual +tags matched are themselves meaningful.

+ + +
+<config>
+    <alpha>1.3</alpha>
+    <beta>10</beta>
+    <name>bozo</name>
+</config>
+
+ +

So there are tag 'wildcards' which are element names ending with a hyphen.

+ + +
+<config>
+    {{<key->$value</key->}}
+</config>
+
+ +

You will then get {{alpha='1.3'},...}. The most convenient format would be +returned by this (note that _- behaves just like $_):

+ + +
+<config>
+    {{<_->$0</_->}}
+</config>
+
+ +

which would return {alpha='1.3',beta='10',name='bozo'}.

+ +

We could play this game endlessly, and encode ways of converting captures, but +the scheme is complex enough, and it's easy to do the conversion later

+ + +
+local numbers = {alpha=true,beta=true}
+for k,v in pairs(res) do
+    if numbers[v] then res[k] = tonumber(v) end
+end
+
+ +

HTML Parsing

+ +

HTML is an unusually degenerate form of XML, and Dennis Schridde has contributed +a feature which makes parsing it easier. For instance, from the tests:

+ + +
+doc = xml.parsehtml [[
+<BODY>
+Hello dolly<br>
+HTML is <b>slack</b><br>
+</BODY>
+]]
+
+asserteq(xml.tostring(doc),[[
+<body>
+Hello dolly<br/>
+HTML is <b>slack</b><br/></body>]])
+
+ +

That is, all tags are converted to lowercase, and empty HTML elements like br +are properly closed; attributes do not need to be quoted.

+ +

Also, DOCTYPE directives and comments are skipped. For truly badly formed HTML, +this is not the tool for you!

+ + + + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/07-functional.md.html b/Data/Libraries/Penlight/docs/manual/07-functional.md.html new file mode 100644 index 0000000..d4ca655 --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/07-functional.md.html @@ -0,0 +1,834 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Functional Programming

+ +

+

Sequences

+ + +

A Lua iterator (in its simplest form) is a function which can be repeatedly +called to return a set of one or more values. The for in statement understands +these iterators, and loops until the function returns nil. There are standard +sequence adapters for tables in Lua (ipairs and pairs), and io.lines +returns an iterator over all the lines in a file. In the Penlight libraries, such +iterators are also called sequences. A sequence of single values (say from +io.lines) is called single-valued, whereas the sequence defined by pairs is +double-valued.

+ +

pl.seq provides a number of useful iterators, and some functions which operate +on sequences. At first sight this example looks like an attempt to write Python +in Lua, (with the sequence being inclusive):

+ + +
+> for i in seq.range(1,4) do print(i) end
+1
+2
+3
+4
+
+ +

But range is actually equivalent to Python's xrange, since it generates a +sequence, not a list. To get a list, use seq.copy(seq.range(1,10)), which +takes any single-value sequence and makes a table from the result. seq.list is +like ipairs except that it does not give you the index, just the value.

+ + +
+> for x in seq.list {1,2,3} do print(x) end
+1
+2
+3
+
+ +

enum takes a sequence and turns it into a double-valued sequence consisting of +a sequence number and the value, so enum(list(ls)) is actually equivalent to +ipairs. A more interesting example prints out a file with line numbers:

+ + +
+for i,v in seq.enum(io.lines(fname)) do print(i..' '..v) end
+
+ +

Sequences can be combined, either by 'zipping' them or by concatenating them.

+ + +
+> for x,y in seq.zip(l1,l2) do print(x,y) end
+10      1
+20      2
+30      3
+> for x in seq.splice(l1,l2) do print(x) end
+10
+20
+30
+1
+2
+3
+
+ +

seq.printall is useful for printing out single-valued sequences, and provides +some finer control over formating, such as a delimiter, the number of fields per +line, and a format string to use (@see string.format)

+ + +
+> seq.printall(seq.random(10))
+0.0012512588885159 0.56358531449324 0.19330423902097 ....
+> seq.printall(seq.random(10), ',', 4, '%4.2f')
+0.17,0.86,0.71,0.51
+0.30,0.01,0.09,0.36
+0.15,0.17,
+
+ +

map will apply a function to a sequence.

+ + +
+> seq.printall(seq.map(string.upper, {'one','two'}))
+ONE TWO
+> seq.printall(seq.map('+', {10,20,30}, 1))
+11 21 31
+
+ +

filter will filter a sequence using a boolean function (often called a +predicate). For instance, this code only prints lines in a file which are +composed of digits:

+ + +
+for l in seq.filter(io.lines(file), stringx.isdigit) do print(l) end
+
+ +

The following returns a table consisting of all the positive values in the +original table (equivalent to tablex.filter(ls, '>', 0))

+ + +
+ls = seq.copy(seq.filter(ls, '>', 0))
+
+ +

We're already encounted seq.sum when discussing input.numbers. This can also +be expressed with seq.reduce:

+ + +
+> seq.reduce(function(x,y) return x + y end, seq.list{1,2,3,4})
+10
+
+ +

seq.reduce applies a binary function in a recursive fashion, so that:

+ + +
+reduce(op,{1,2,3}) => op(1,reduce(op,{2,3}) => op(1,op(2,3))
+
+ +

it's now possible to easily generate other cumulative operations; the standard +operations declared in pl.operator are useful here:

+ + +
+> ops = require 'pl.operator'
+> -- can also say '*' instead of ops.mul
+> = seq.reduce(ops.mul,input.numbers '1 2 3 4')
+24
+
+ +

There are functions to extract statistics from a sequence of numbers:

+ + +
+> l1 = List {10,20,30}
+> l2 = List {1,2,3}
+> = seq.minmax(l1)
+10      30
+> = seq.sum(l1)
+60      3
+
+ +

It is common to get sequences where values are repeated, say the words in a file. +count_map will take such a sequence and count the values, returning a table +where the keys are the unique values, and the value associated with each key is +the number of times they occurred:

+ + +
+> t = seq.count_map {'one','fred','two','one','two','two'}
+> = t
+{one=2,fred=1,two=3}
+
+ +

This will also work on numerical sequences, but you cannot expect the result to +be a proper list, i.e. having no 'holes'. Instead, you always need to use pairs +to iterate over the result - note that there is a hole at index 5:

+ + +
+> t = seq.count_map {1,2,4,2,2,3,4,2,6}
+> for k,v in pairs(t) do print(k,v) end
+1       1
+2       4
+3       1
+4       2
+6       1
+
+ +

unique uses count_map to return a list of the unique values, that is, just +the keys of the resulting table.

+ +

last turns a single-valued sequence into a double-valued sequence with the +current value and the last value:

+ + +
+> for current,last in seq.last {10,20,30,40} do print (current,last) end
+20      10
+30      20
+40      30
+
+ +

This makes it easy to do things like identify repeated lines in a file, or +construct differences between values. filter can handle double-valued sequences +as well, so one could filter such a sequence to only return cases where the +current value is less than the last value by using operator.lt or just '<'. +This code then copies the resulting code into a table.

+ + +
+> ls = {10,9,10,3}
+> = seq.copy(seq.filter(seq.last(s),'<'))
+{9,3}
+
+ +

+

Sequence Wrappers

+ +

The functions in pl.seq cover the common patterns when dealing with sequences, +but chaining these functions together can lead to ugly code. Consider the last +example of the previous section; seq is repeated three times and the resulting +expression has to be read right-to-left. The first issue can be helped by local +aliases, so that the expression becomes copy(filter(last(s),'<')) but the +second issue refers to the somewhat unnatural order of functional application. +We tend to prefer reading operations from left to right, which is one reason why +object-oriented notation has become popular. Sequence adapters allow this +expression to be written like so:

+ + +
+seq(s):last():filter('<'):copy()
+
+ +

With this notation, the operation becomes a chain of method calls running from +left to right.

+ +

'Sequence' is not a basic Lua type, they are generally functions or callable +objects. The expression seq(s) wraps a sequence in a sequence wrapper, which +is an object which understands all the functions in pl.seq as methods. This +object then explicitly represents sequences.

+ +

As a special case, the constructor (which is when you call the table seq) will +make a wrapper for a plain list-like table. Here we apply the length operator to +a sequence of strings, and print them out.

+ + +
+> seq{'one','tw','t'} :map '#' :printall()
+3 2 1
+
+ +

As a convenience, there is a function seq.lines which behaves just like +io.lines except it wraps the result as an explicit sequence type. This takes +the first 10 lines from standard input, makes it uppercase, turns it into a +sequence with a count and the value, glues these together with the concatenation +operator, and finally prints out the sequence delimited by a newline.

+ + +
+seq.lines():take(10):upper():enum():map('..'):printall '\n'
+
+ +

Note the method upper, which is not a seq function. if an unknown method is +called, sequence wrappers apply that method to all the values in the sequence +(this is implicit use of mapmethod)

+ +

It is straightforward to create custom sequences that can be used in this way. On +Unix, /dev/random gives you an endless sequence of random bytes, so we use +take to limit the sequence, and then map to scale the result into the desired +range. The key step is to use seq to wrap the iterator function:

+ + +
+-- random.lua
+local seq = require 'pl.seq'
+
+function dev_random()
+    local f = io.open('/dev/random')
+    local byte = string.byte
+    return seq(function()
+        -- read two bytes into a string and convert into a 16-bit number
+        local s = f:read(2)
+        return byte(s,1) + 256*byte(s,2)
+    end)
+end
+
+-- print 10 random numbers from 0 to 1 !
+dev_random():take(10):map('%',100):map('/',100):printall ','
+
+ +

Another Linux one-liner depends on the /proc filesystem and makes a list of all +the currently running processes:

+ + +
+pids = seq(lfs.dir '/proc'):filter(stringx.isdigit):map(tonumber):copy()
+
+ +

This version of Penlight has an experimental feature which relies on the fact +that all Lua types can have metatables, including functions. This makes +implicit sequence wrapping possible:

+ + +
+> seq.import()
+> seq.random(5):printall(',',5,'%4.1f')
+ 0.0, 0.1, 0.4, 0.1, 0.2
+
+ +

This avoids the awkward seq(seq.random(5)) construction. Or the iterator can +come from somewhere else completely:

+ + +
+> ('one two three'):gfind('%a+'):printall(',')
+one,two,three,
+
+ +

After seq.import, it is no longer necessary to explicitly wrap sequence +functions.

+ +

But there is a price to pay for this convenience. Every function is affected, +so that any function can be used, appropriate or not:

+ + +
+> math.sin:printall()
+..seq.lua:287: bad argument #1 to '(for generator)' (number expected, got nil)
+> a = tostring
+> = a:find(' ')
+function: 0042C920
+
+ +

What function is returned? It's almost certain to be something that makes no +sense in the current context. So implicit sequences may make certain kinds of +programming mistakes harder to catch - they are best used for interactive +exploration and small scripts.

+ +

+ +

+

List Comprehensions

+ +

List comprehensions are a compact way to create tables by specifying their +elements. In Python, you can say this:

+ + +
+ls = [x for x in range(5)]  # == [0,1,2,3,4]
+
+ +

In Lua, using pl.comprehension:

+ + +
+> C = require('pl.comprehension').new()
+> = C ('x for x=1,10') ()
+{1,2,3,4,5,6,7,8,9,10}
+
+ +

C is a function which compiles a list comprehension string into a function. +In this case, the function has no arguments. The parentheses are redundant for a +function taking a string argument, so this works as well:

+ + +
+> = C 'x^2 for x=1,4' ()
+{1,4,9,16}
+> = C '{x,x^2} for x=1,4' ()
+{{1,1},{2,4},{3,9},{4,16}}
+
+ +

Note that the expression can be any function of the variable x!

+ +

The basic syntax so far is <expr> for <set>, where <set> can be anything that +the Lua for statement understands. <set> can also just be the variable, in +which case the values will come from the argument of the comprehension. Here +I'm emphasizing that a comprehension is a function which can take a list argument:

+ + +
+> = C '2*x for x' {1,2,3}
+{2,4,6}
+> dbl = C '2*x for x'
+> = dbl {10,20,30}
+{20,40,60}
+
+ +

Here is a somewhat more explicit way of saying the same thing; _1 is a +placeholder refering to the first argument passed to the comprehension.

+ + +
+> = C '2*x for _,x in pairs(_1)' {10,20,30}
+{20,40,60}
+> = C '_1(x) for x'(tostring,{1,2,3,4})
+{'1','2','3','4'}
+
+ +

This extended syntax is useful when you wish to collect the result of some +iterator, such as io.lines. This comprehension creates a function which creates +a table of all the lines in a file:

+ + +
+> f = io.open('array.lua')
+> lines = C 'line for line in _1:lines()' (f)
+> = #lines
+118
+
+ +

There are a number of functions that may be applied to the result of a +comprehension:

+ + +
+> = C 'min(x for x)' {1,44,0}
+0
+> = C 'max(x for x)' {1,44,0}
+44
+> = C 'sum(x for x)' {1,44,0}
+45
+
+ +

(These are equivalent to a reduce operation on a list.)

+ +

After the for part, there may be a condition, which filters the output. This +comprehension collects the even numbers from a list:

+ + +
+> = C 'x for x if x % 2 == 0' {1,2,3,4,5}
+{2,4}
+
+ +

There may be a number of for parts:

+ + +
+> = C '{x,y} for x = 1,2 for y = 1,2' ()
+{{1,1},{1,2},{2,1},{2,2}}
+> = C '{x,y} for x for y' ({1,2},{10,20})
+{{1,10},{1,20},{2,10},{2,20}}
+
+ +

These comprehensions are useful when dealing with functions of more than one +variable, and are not so easily achieved with the other Penlight functional forms.

+ +

+ +

+

Creating Functions from Functions

+ + +

Lua functions may be treated like any other value, although of course you cannot +multiply or add them. One operation that makes sense is function composition, +which chains function calls (so (f * g)(x) is f(g(x)).)

+ + +
+> func = require 'pl.func'
+> printf = func.compose(io.write,string.format)
+> printf("hello %s\n",'world')
+hello world
+true
+
+ +

Many functions require you to pass a function as an argument, say to apply to all +values of a sequence or as a callback. Often useful functions have the wrong +number of arguments. So there is a need to construct a function of one argument +from one of two arguments, binding the extra argument to a given value.

+ +

partial application takes a function of n arguments and returns a function of n-1 +arguments where the first argument is bound to some value:

+ + +
+> p2 = func.bind1(print,'start>')
+> p2('hello',2)
+start>  hello   2
+> ops = require 'pl.operator'
+> = tablex.filter({1,-2,10,-1,2},bind1(ops.gt,0))
+{-2,-1}
+> tablex.filter({1,-2,10,-1,2},bind1(ops.le,0))
+{1,10,2}
+
+ +

The last example unfortunately reads backwards, because bind1 alway binds the +first argument! Also unfortunately, in my youth I confused 'currying' with +'partial application', so the old name for bind1 is curry - this alias still exists.

+ +

This is a specialized form of function argument binding. Here is another way +to say the print example:

+ + +
+> p2 = func.bind(print,'start>',func._1,func._2)
+> p2('hello',2)
+start>  hello   2
+
+ +

where _1 and _2 are placeholder variables, corresponding to the first and +second argument respectively.

+ +

Having func all over the place is distracting, so it's useful to pull all of +pl.func into the local context. Here is the filter example, this time the right +way around:

+ + +
+> utils.import 'pl.func'
+> tablex.filter({1,-2,10,-1,2},bind(ops.gt, _1, 0))
+{1,10,2}
+
+ +

tablex.merge does a general merge of two tables. This example shows the +usefulness of binding the last argument of a function.

+ + +
+> S1 = {john=27, jane=31, mary=24}
+> S2 = {jane=31, jones=50}
+> intersection = bind(tablex.merge, _1, _2, false)
+> union = bind(tablex.merge, _1, _2, true)
+> = intersection(S1,S2)
+{jane=31}
+> = union(S1,S2)
+{mary=24,jane=31,john=27,jones=50}
+
+ +

When using bind with print, we got a function of precisely two arguments, +whereas we really want our function to use varargs like print. This is the role +of _0:

+ + +
+> _DEBUG = true
+> p = bind(print,'start>', _0)
+return function (fn,_v1)
+    return function(...) return fn(_v1,...) end
+end
+
+> p(1,2,3,4,5)
+start>  1       2       3       4       5
+
+ +

I've turned on the global _DEBUG flag, so that the function generated is +printed out. It is actually a function which generates the required function; +the first call binds the value of _v1 to 'start>'.

+ +

+

Placeholder Expressions

+ +

A common pattern in Penlight is a function which applies another function to all +elements in a table or a sequence, such as tablex.map or seq.filter. Lua does +anonymous functions well, although they can be a bit tedious to type:

+ + +
+> = tablex.map(function(x) return x*x end, {1,2,3,4})
+{1,4,9,16}
+
+ +

pl.func allows you to define placeholder expressions, which can cut down on +the typing required, and also make your intent clearer. First, we bring contents +of pl.func into our context, and then supply an expression using placeholder +variables, such as _1,_2,etc. (C++ programmers will recognize this from the +Boost libraries.)

+ + +
+> utils.import 'pl.func'
+> = tablex.map(_1*_1, {1,2,3,4})
+{1,4,9,16}
+
+ +

Functions of up to 5 arguments can be generated.

+ + +
+> = tablex.map2(_1+_2,{1,2,3}, {10,20,30})
+{11,22,33}
+
+ +

These expressions can use arbitrary functions, altho they must first be +registered with the functional library. func.register brings in a single +function, and func.import brings in a whole table of functions, such as math.

+ + +
+> sin = register(math.sin)
+> = tablex.map(sin(_1), {1,2,3,4})
+{0.8414709848079,0.90929742682568,0.14112000805987,-0.75680249530793}
+> import 'math'
+> = tablex.map(cos(2*_1),{1,2,3,4})
+{-0.41614683654714,-0.65364362086361,0.96017028665037,-0.14550003380861}
+
+ +

A common operation is calling a method of a set of objects:

+ + +
+> = tablex.map(_1:sub(1,1), {'one','four','x'})
+{'o','f','x'}
+
+ +

There are some restrictions on what operators can be used in PEs. For instance, +because the __len metamethod cannot be overriden by plain Lua tables, we need +to define a special function to express `#_1':

+ + +
+> = tablex.map(Len(_1), {'one','four','x'})
+{3,4,1}
+
+ +

Likewise for comparison operators, which cannot be overloaded for different +types, and thus also have to be expressed as a special function:

+ + +
+> = tablex.filter(Gt(_1,0), {1,-1,2,4,-3})
+{1,2,4}
+
+ +

It is useful to express the fact that a function returns multiple values. For +instance, tablex.pairmap expects a function that will be called with the key +and the value, and returns the new value and the key, in that order.

+ + +
+> = pairmap(Args(_2,_1:upper()),{fred=1,alice=2})
+{ALICE=2,FRED=1}
+
+ +

PEs cannot contain nil values, since PE function arguments are represented as +an array. Instead, a special value called Nil is provided. So say +_1:f(Nil,1) instead of _1:f(nil,1).

+ +

A placeholder expression cannot be automatically used as a Lua function. The +technical reason is that the call operator must be overloaded to construct +function calls like _1(1). If you want to force a PE to return a function, use +func.I.

+ + +
+> = tablex.map(_1(10),{I(2*_1),I(_1*_1),I(_1+2)})
+{20,100,12}
+
+ +

Here we make a table of functions taking a single argument, and then call them +all with a value of 10.

+ +

The essential idea with PEs is to 'quote' an expression so that it is not +immediately evaluated, but instead turned into a function that can be applied +later to some arguments. The basic mechanism is to wrap values and placeholders +so that the usual Lua operators have the effect of building up an expression +tree. (It turns out that you can do symbolic algebra using PEs, see +symbols.lua in the examples directory, and its test runner testsym.lua, which +demonstrates symbolic differentiation.)

+ +

The rule is that if any operator has a PE operand, the result will be quoted. +Sometimes we need to quote things explicitly. For instance, say we want to pass a +function to a filter that must return true if the element value is in a set. +set[_1] is the obvious expression, but it does not give the desired result, +since it evaluates directly, giving nil. Indexing works differently than a +binary operation like addition (set+_1 is properly quoted) so there is a need +for an explicit quoting or wrapping operation. This is the job of the _ +function; the PE in this case should be _(set)[_1]. This works for functions +as well, as a convenient alternative to registering functions: _(math.sin)(_1). +This is equivalent to using the `lines' method:

+ + +
+for line in I(_(f):read()) do print(line) end
+
+ +

Now this will work for any 'file-like' object which which has a read method +returning the next line. If you had a LuaSocket client which was being 'pushed' +by lines sent from a server, then _(s):receive '*l' would create an iterator +for accepting input. These forms can be convenient for adapting your data flow so +that it can be passed to the sequence functions in `pl.seq'.

+ +

Placeholder expressions can be mixed with sequence wrapper expressions. +lexer.lua will give us a double-valued sequence of tokens, where the first +value is a type, and the second is a value. We filter out only the values where +the type is 'iden', extract the actual value using map, get the unique values +and finally copy to a list.

+ + +
+> str = 'for i=1,10 do for j = 1,10 do print(i,j) end end'
+> = seq(lexer.lua(str)):filter('==','iden'):map(_2):unique():copy()
+{i,print,j}
+
+ +

This is a particularly intense line (and I don't always suggest making everything +a one-liner!); the key is the behaviour of map, which will take both values of +the sequence, so _2 returns the value part. (Since filter here takes extra +arguments, it only operates on the type values.)

+ +

There are some performance considerations to using placeholder expressions. +Instantiating a PE requires constructing and compiling a function, which is not +such a fast operation. So to get best performance, factor out PEs from loops like +this;

+ + +
+local fn = I(_1:f() + _2:g())
+for i = 1,n do
+    res[i] = tablex.map2(fn,first[i],second[i])
+end
+
+ + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/08-additional.md.html b/Data/Libraries/Penlight/docs/manual/08-additional.md.html new file mode 100644 index 0000000..d13ac6e --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/08-additional.md.html @@ -0,0 +1,815 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Additional Libraries

+ +

Libraries in this section are no longer considered to be part of the Penlight +core, but still provide specialized functionality when needed.

+ +

+ +

+

Simple Input Patterns

+ +

Lua string pattern matching is very powerful, and usually you will not need a +traditional regular expression library. Even so, sometimes Lua code ends up +looking like Perl, which happens because string patterns are not always the +easiest things to read, especially for the casual reader. Here is a program +which needs to understand three distinct date formats:

+ + +
+-- parsing dates using Lua string patterns
+months={Jan=1,Feb=2,Mar=3,Apr=4,May=5,Jun=6,
+Jul=7,Aug=8,Sep=9,Oct=10,Nov=11,Dec=12}
+
+function check_and_process(d,m,y)
+    d = tonumber(d)
+    m = tonumber(m)
+    y = tonumber(y)
+    ....
+end
+
+for line in f:lines() do
+    -- ordinary (English) date format
+    local d,m,y = line:match('(%d+)/(%d+)/(%d+)')
+    if d then
+        check_and_process(d,m,y)
+    else -- ISO date??
+        y,m,d = line:match('(%d+)%-(%d+)%-(%d+)')
+        if y then
+            check_and_process(d,m,y)
+        else -- <day> <month-name> <year>?
+            d,mm,y = line:match('%(d+)%s+(%a+)%s+(%d+)')
+            m = months[mm]
+            check_and_process(d,m,y)
+        end
+    end
+end
+
+ +

These aren't particularly difficult patterns, but already typical issues are +appearing, such as having to escape '-'. Also, string.match returns its +captures, so that we're forced to use a slightly awkward nested if-statement.

+ +

Verification issues will further cloud the picture, since regular expression +people try to enforce constraints (like year cannot be more than four digits) +using regular expressions, on the usual grounds that you shouldn't stop using a +hammer when you are enjoying yourself.

+ +

pl.sip provides a simple, intuitive way to detect patterns in strings and +extract relevant parts.

+ + +
+> sip = require 'pl.sip'
+> dump = require('pl.pretty').dump
+> res = {}
+> c = sip.compile 'ref=$S{file}:$d{line}'
+> = c('ref=hello.c:10',res)
+true
+> dump(res)
+{
+  line = 10,
+  file = "hello.c"
+}
+> = c('ref=long name, no line',res)
+false
+
+ +

sip.compile creates a pattern matcher function, which takes a string and a +table as arguments. If the string matches the pattern, then true is returned +and the table is populated according to the captures within the pattern.

+ +

Here is another version of the date parser:

+ + +
+-- using SIP patterns
+function check(t)
+    check_and_process(t.day,t.month,t.year)
+end
+
+shortdate = sip.compile('$d{day}/$d{month}/$d{year}')
+longdate = sip.compile('$d{day} $v{mon} $d{year}')
+isodate = sip.compile('$d{year}-$d{month}-$d{day}')
+
+for line in f:lines() do
+    local res = {}
+    if shortdate(str,res) then
+        check(res)
+    elseif isodate(str,res) then
+        check(res)
+    elseif longdate(str,res) then
+        res.month = months[res.mon]
+        check(res)
+    end
+end
+
+ +

SIP captures start with '$', then a one-character type, and then an +optional variable name in curly braces.

+ + +
+Type      Meaning
+v         identifier
+i         possibly signed integer
+f         floating-point number
+r         rest of line
+q         quoted string (quoted using either ' or ")
+p         a path name
+(         anything inside balanced parentheses
+[         anything inside balanced brackets
+{         anything inside balanced curly brackets
+<         anything inside balanced angle brackets
+
+ +

If a type is not one of the above, then it's assumed to be one of the standard +Lua character classes, and will match one or more repetitions of that class. +Any spaces you leave in your pattern will match any number of spaces, including +zero, unless the spaces are between two identifier characters or patterns +matching them; in that case, at least one space will be matched.

+ +

SIP captures (like $v{mon}) do not have to be named. You can use just $v, but +you have to be consistent; if a pattern contains unnamed captures, then all +captures must be unnamed. In this case, the result table is a simple list of +values.

+ +

sip.match is a useful shortcut if you want to compile and match in one call, +without saving the compiled pattern. It caches the result, so it is not much +slower than explicitly using sip.compile.

+ + +
+> sip.match('($q{first},$q{second})','("john","smith")',res)
+true
+> res
+{second='smith',first='john'}
+> res = {}
+> sip.match('($q,$q)','("jan","smit")',res)  -- unnamed captures
+true
+> res
+{'jan','smit'}
+> sip.match('($q,$q)','("jan", "smit")',res)
+false   ---> oops! Can't handle extra space!
+> sip.match('( $q , $q )','("jan", "smit")',res)
+true
+
+ +

As a general rule, allow for whitespace in your patterns.

+ +

Finally, putting a '$' at the end of a pattern means 'capture the rest of the +line, starting at the first non-space'. It is a shortcut for '$r{rest}', +or just '$r' if no named captures are used.

+ + +
+> sip.match('( $q , $q ) $','("jan", "smit") and a string',res)
+true
+> res
+{'jan','smit','and a string'}
+> res = {}
+> sip.match('( $q{first} , $q{last} ) $','("jan", "smit") and a string',res)
+true
+> res
+{first='jan',rest='and a string',last='smit'}
+
+ +

+ +

+

Command-line Programs with Lapp

+ +

pl.lapp is a small and focused Lua module which aims to make standard +command-line parsing easier and intuitive. It implements the standard GNU style, +i.e. short flags with one letter start with '-', and there may be an additional +long flag which starts with '--'. Generally options which take an argument expect +to find it as the next parameter (e.g. 'gcc test.c -o test') but single short +options taking a value can dispense with the space (e.g. 'head -n4 +test.c' or gcc -I/usr/include/lua/5.1 ...)

+ +

As far as possible, Lapp will convert parameters into their equivalent Lua types, +i.e. convert numbers and convert filenames into file objects. If any conversion +fails, or a required parameter is missing, an error will be issued and the usage +text will be written out. So there are two necessary tasks, supplying the flag +and option names and associating them with a type.

+ +

For any non-trivial script, even for personal consumption, it's necessary to +supply usage text. The novelty of Lapp is that it starts from that point and +defines a loose format for usage strings which can specify the names and types of +the parameters.

+ +

An example will make this clearer:

+ + +
+-- scale.lua
+  lapp = require 'pl.lapp'
+  local args = lapp [[
+  Does some calculations
+    -o,--offset (default 0.0)  Offset to add to scaled number
+    -s,--scale  (number)  Scaling factor
+    <number> (number)  Number to be scaled
+  ]]
+
+  print(args.offset + args.scale * args.number)
+
+ +

Here is a command-line session using this script:

+ + +
+$ lua scale.lua
+scale.lua:missing required parameter: scale
+
+Does some calculations
+ -o,--offset (default 0.0)  Offset to add to scaled number
+ -s,--scale  (number)  Scaling factor
+  <number> (number )  Number to be scaled
+
+$ lua scale.lua -s 2.2 10
+22
+
+$ lua scale.lua -s 2.2 x10
+scale.lua:unable to convert to number: x10
+
+....(usage as before)
+
+ +

There are two kinds of lines in Lapp usage strings which are meaningful; option +and parameter lines. An option line gives the short option, optionally followed +by the corresponding long option. A type specifier in parentheses may follow. +Similarly, a parameter line starts with '', followed by a type +specifier.

+ +

Type specifiers usually start with a type name: one of 'boolean', 'string','number','file-in' or +'file-out'. You may leave this out, but then must say 'default' followed by a value. +If a flag or parameter has a default, it is not required and is set to the default. The actual +type is deduced from this value (number, string, file or boolean) if not provided directly. +'Deduce' is a fancy word for 'guess' and it can be wrong, e.g '(default 1)' +will always be a number. You can say '(string default 1)' to override the guess. +There are file values for the predefined console streams: stdin, stdout, stderr.

+ +

The boolean type is the default for flags. Not providing the type specifier is equivalent to +'(boolean default false)`. If the flag is meant to be 'turned off' then either the full +'(boolean default true)` or the shortcut '(default true)' will work.

+ +

An alternative to default is optional:

+ + +
+local lapp = require 'pl.lapp'
+local args = lapp [[
+   --cmd (optional string) Command to run.
+]]
+
+if args.cmd then
+  os.execute(args.cmd)
+end
+
+ +

Here we're implying that cmd need not be specified (just as with default) but if not +present, then args.cmd is nil, which will always test false.

+ +

The rest of the line is ignored and can be used for explanatory text.

+ +

This script shows the relation between the specified parameter names and the +fields in the output table.

+ + +
+-- simple.lua
+local args = require ('pl.lapp') [[
+Various flags and option types
+  -p          A simple optional flag, defaults to false
+  -q,--quiet  A simple flag with long name
+  -o  (string)  A required option with argument
+  -s  (default 'save') Optional string with default 'save' (single quotes ignored)
+  -n  (default 1) Optional numerical flag with default 1
+  -b  (string default 1)  Optional string flag with default '1' (type explicit)
+  <input> (default stdin)  Optional input file parameter, reads from stdin
+]]
+
+for k,v in pairs(args) do
+    print(k,v)
+end
+
+ +

I've just dumped out all values of the args table; note that args.quiet has +become true, because it's specified; args.p defaults to false. If there is a long +name for an option, that will be used in preference as a field name. A type or +default specifier is not necessary for simple flags, since the default type is +boolean.

+ + +
+$ simple -o test -q simple.lua
+p       false
+input   file (781C1BD8)
+quiet   true
+o       test
+input_name      simple.lua
+D:\dev\lua\lapp>simple -o test simple.lua one two three
+1       one
+2       two
+3       three
+p       false
+quiet   false
+input   file (781C1BD8)
+o       test
+input_name      simple.lua
+
+ +

The parameter input has been set to an open read-only file object - we know it +must be a read-only file since that is the type of the default value. The field +input_name is automatically generated, since it's often useful to have access to +the original filename.

+ +

Notice that any extra parameters supplied will be put in the result table with +integer indices, i.e. args[i] where i goes from 1 to #args.

+ +

Files don't really have to be closed explicitly for short scripts with a quick +well-defined mission, since the result of garbage-collecting file objects is to +close them.

+ +

Enforcing a Range and Enumerations

+ +

The type specifier can also be of the form '(' MIN '..' MAX ')' or a set of strings +separated by '|'.

+ + +
+local lapp = require 'pl.lapp'
+local args = lapp [[
+    Setting ranges
+    <x> (1..10)  A number from 1 to 10
+    <y> (-5..1e6) Bigger range
+    <z> (slow|medium|fast)
+]]
+
+print(args.x,args.y)
+
+ +

Here the meaning of ranges is that the value is greater or equal to MIN and less or equal +to MAX. +An 'enum' is a string that can only have values from a specified set.

+ +

Custom Types

+ +

There is no builti-in way to force a parameter to be a whole number, but +you may define a custom type that does this:

+ + +
+lapp = require ('pl.lapp')
+
+lapp.add_type('integer','number',
+    function(x)
+        lapp.assert(math.ceil(x) == x, 'not an integer!')
+    end
+)
+
+local args =  lapp [[
+    <ival> (integer) Process PID
+]]
+
+print(args.ival)
+
+ +

lapp.add_type takes three parameters, a type name, a converter and a constraint +function. The constraint function is expected to throw an assertion if some +condition is not true; we use lapp.assert because it fails in the standard way +for a command-line script. The converter argument can either be a type name known +to Lapp, or a function which takes a string and generates a value.

+ +

Here's a useful custom type that allows dates to be input as pl.Date values:

+ + +
+local df = Date.Format()
+
+lapp.add_type('date',
+    function(s)
+        local d,e = df:parse(s)
+        lapp.assert(d,e)
+        return d
+    end
+)
+
+ +

'varargs' Parameter Arrays

+ + +
+lapp = require 'pl.lapp'
+local args = lapp [[
+Summing numbers
+    <numbers...> (number) A list of numbers to be summed
+]]
+
+local sum = 0
+for i,x in ipairs(args.numbers) do
+    sum = sum + x
+end
+print ('sum is '..sum)
+
+ +

The parameter number has a trailing '...', which indicates that this parameter is +a 'varargs' parameter. It must be the last parameter, and args.number will be an +array.

+ +

Consider this implementation of the head utility from Mac OS X:

+ + +
+-- implements a BSD-style head
+-- (see http://www.manpagez.com/man/1/head/osx-10.3.php)
+
+lapp = require ('pl.lapp')
+
+local args = lapp [[
+Print the first few lines of specified files
+   -n         (default 10)    Number of lines to print
+   <files...> (default stdin) Files to print
+]]
+
+-- by default, lapp converts file arguments to an actual Lua file object.
+-- But the actual filename is always available as <file>_name.
+-- In this case, 'files' is a varargs array, so that 'files_name' is
+-- also an array.
+local nline = args.n
+local nfile = #args.files
+for i = 1,nfile do
+    local file = args.files[i]
+    if nfile > 1 then
+        print('==> '..args.files_name[i]..' <==')
+    end
+    local n = 0
+    for line in file:lines() do
+        print(line)
+        n = n + 1
+        if n == nline then break end
+    end
+end
+
+ +

Note how we have access to all the filenames, because the auto-generated field +files_name is also an array!

+ +

(This is probably not a very considerate script, since Lapp will open all the +files provided, and only close them at the end of the script. See the xhead.lua +example for another implementation.)

+ +

Flags and options may also be declared as vararg arrays, and can occur anywhere. +If there is both a short and long form, then the trailing "..." must happen after the long form, +for example "-x,--network... (string)...",

+ +

Bear in mind that short options can be combined (like 'tar -xzf'), so it's +perfectly legal to have '-vvv'. But normally the value of args.v is just a simple +true value.

+ + +
+local args = require ('pl.lapp') [[
+   -v...  Verbosity level; can be -v, -vv or -vvv
+]]
+vlevel = not args.v[1] and 0 or #args.v
+print(vlevel)
+
+ +

The vlevel assigment is a bit of Lua voodoo, so consider the cases:

+ + +
+* No -v flag, v is just { false }
+* One -v flags, v is { true }
+* Two -v flags, v is { true, true }
+* Three -v flags, v is { true, true, true }
+
+ +

Defining a Parameter Callback

+ +

If a script implements lapp.callback, then Lapp will call it after each +argument is parsed. The callback is passed the parameter name, the raw unparsed +value, and the result table. It is called immediately after assignment of the +value, so the corresponding field is available.

+ + +
+lapp = require ('pl.lapp')
+
+function lapp.callback(parm,arg,args)
+    print('+',parm,arg)
+end
+
+local args = lapp [[
+Testing parameter handling
+    -p               Plain flag (defaults to false)
+    -q,--quiet       Plain flag with GNU-style optional long name
+    -o  (string)     Required string option
+    -n  (number)     Required number option
+    -s (default 1.0) Option that takes a number, but will default
+    <start> (number) Required number argument
+    <input> (default stdin)  A parameter which is an input file
+    <output> (default stdout) One that is an output file
+]]
+print 'args'
+for k,v in pairs(args) do
+    print(k,v)
+end
+
+ +

This produces the following output:

+ + +
+$ args -o name -n 2 10 args.lua
++       o       name
++       n       2
++       start   10
++       input   args.lua
+args
+p       false
+s       1
+input_name      args.lua
+quiet   false
+output  file (781C1B98)
+start   10
+input   file (781C1BD8)
+o       name
+n       2
+
+ +

Callbacks are needed when you want to take action immediately on parsing an +argument.

+ +

Slack Mode

+ +

If you'd like to use a multi-letter 'short' parameter you need to set +the lapp.slack variable to true.

+ +

In the following example we also see how default false and default true flags can be used +and how to overwrite the default -h help flag (--help still works fine) - this applies +to non-slack mode as well.

+ + +
+-- Parsing the command line ----------------------------------------------------
+-- test.lua
+local lapp = require 'pl.lapp'
+local pretty = require 'pl.pretty'
+lapp.slack = true
+local args = lapp [[
+Does some calculations
+   -v, --video              (string)             Specify input video
+   -w, --width              (default 256)        Width of the video
+   -h, --height             (default 144)        Height of the video
+   -t, --time               (default 10)         Seconds of video to process
+   -sk,--seek               (default 0)          Seek number of seconds
+   -f1,--flag1                                   A false flag
+   -f2,--flag2                                   A false flag
+   -f3,--flag3              (default true)       A true flag
+   -f4,--flag4              (default true)       A true flag
+]]
+
+pretty.dump(args)
+
+ +

And here we can see the output of test.lua:

+ + +
+$> lua test.lua -v abc --time 40 -h 20 -sk 15 --flag1 -f3
+---->
+{
+  width = 256,
+  flag1 = true,
+  flag3 = false,
+  seek = 15,
+  flag2 = false,
+  video = abc,
+  time = 40,
+  height = 20,
+  flag4 = true
+}
+
+ +

+

Simple Test Framework

+ +

pl.test was originally developed for the sole purpose of testing Penlight itself, +but you may find it useful for your own applications. (There are many other options.)

+ +

Most of the goodness is in test.asserteq. It uses tablex.deepcompare on its two arguments, +and by default quits the test application with a non-zero exit code, and an informative +message printed to stderr:

+ + +
+local test = require 'pl.test'
+
+test.asserteq({10,20,30},{10,20,30.1})
+
+--~ test-test.lua:3: assertion failed
+--~ got:    {
+--~  [1] = 10,
+--~  [2] = 20,
+--~  [3] = 30
+--~ }
+--~ needed:    {
+--~  [1] = 10,
+--~  [2] = 20,
+--~  [3] = 30.1
+--~ }
+--~ these values were not equal
+
+ +

This covers most cases but it's also useful to compare strings using string.match

+ + +
+-- must start with bonzo the dog
+test.assertmatch ('bonzo the dog is here','^bonzo the dog')
+-- must end with an integer
+test.assertmatch ('hello 42','%d+$')
+
+ +

Since Lua errors are usually strings, this matching strategy is used to test 'exceptions':

+ + +
+test.assertraise(function()
+    local t = nil
+    print(t.bonzo)
+end,'nil value')
+
+ +

(Some care is needed to match the essential part of the thrown error if you care +for portability, since in Lua 5.2 +the exact error is "attempt to index local 't' (a nil value)" and in Lua 5.3 the error +is "attempt to index a nil value (local 't')")

+ +

There is an extra optional argument to these test functions, which is helpful when writing +test helper functions. There you want to highlight the failed line, not the actual call +to asserteq or assertmatch - line 33 here is the call to is_iden

+ + +
+function is_iden(str)
+    test.assertmatch(str,'^[%a_][%w_]*$',1)
+end
+
+is_iden 'alpha_dog'
+is_iden '$dollars'
+
+--~ test-test.lua:33: assertion failed
+--~ got:    "$dollars"
+--~ needed:    "^[%a_][%w_]*$"
+--~ these strings did not match
+
+ +

Useful Lua functions often return multiple values, and test.tuple is a convenient way to +capture these values, whether they contain nils or not.

+ + +
+T = test.tuple
+
+--- common error pattern
+function failing()
+    return nil,'failed'
+end
+
+test.asserteq(T(failing()),T(nil,'failed'))
+
+ + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + diff --git a/Data/Libraries/Penlight/docs/manual/09-discussion.md.html b/Data/Libraries/Penlight/docs/manual/09-discussion.md.html new file mode 100644 index 0000000..4e7dd69 --- /dev/null +++ b/Data/Libraries/Penlight/docs/manual/09-discussion.md.html @@ -0,0 +1,233 @@ + + + + + Penlight Documentation + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Technical Choices

+ +

+

Modularity and Granularity

+ +

In an ideal world, a program should only load the libraries it needs. Penlight is +intended to work in situations where an extra 100Kb of bytecode could be a +problem. It is straightforward but tedious to load exactly what you need:

+ + +
+local data = require 'pl.data'
+local List = require 'pl.List'
+local array2d = require 'pl.array2d'
+local seq = require 'pl.seq'
+local utils = require 'pl.utils'
+
+ +

This is the style that I follow in Penlight itself, so that modules don't mess +with the global environment; also, stringx.import() is not used because it will +update the global string table.

+ +

But require 'pl' is more convenient in scripts; the question is how to ensure +that one doesn't load the whole kitchen sink as the price of convenience. The +strategy is to only load modules when they are referenced. In 'init.lua' (which +is loaded by require 'pl') a metatable is attached to the global table with an +__index metamethod. Any unknown name is looked up in the list of modules, and +if found, we require it and make that module globally available. So when +tablex.deepcompare is encountered, looking up tablex causes 'pl.tablex' to be +required. .

+ +

Modifying the behaviour of the global table has consequences. For instance, there +is the famous module strict which comes with Lua itself (perhaps the only +standard Lua module written in Lua itself) which also does this modification so +that global variiables must be defined before use. So the implementation in +'init.lua' allows for a 'not found' hook, which 'pl.strict.lua' uses. Other +libraries may install their own metatables for _G, but Penlight will now +forward any unknown name to the __index defined by the original metatable.

+ +

But the strategy is worth the effort: the old 'kitchen sink' 'init.lua' would +pull in about 260K of bytecode, whereas now typical programs use about 100K less, +and short scripts even better - for instance, if they were only needing +functionality in utils.

+ +

There are some functions which mark their output table with a special metatable, +when it seems particularly appropriate. For instance, tablex.makeset creates a +Set, and seq.copy creates a List. But this does not automatically result in +the loading of pl.Set and pl.List; only if you try to access any of these +methods. In 'utils.lua', there is an exported table called stdmt:

+ + +
+stdmt = { List = {}, Map = {}, Set = {}, MultiMap = {} }
+
+ +

If you go through 'init.lua', then these plain little 'identity' tables get an +__index metamethod which forces the loading of the full functionality. Here is +the code from 'list.lua' which starts the ball rolling for lists:

+ + +
+List = utils.stdmt.List
+List.__index = List
+List._name = "List"
+List._class = List
+
+ +

The 'load-on-demand' strategy helps to modularize the library. Especially for +more casual use, require 'pl' is a good compromise between convenience and +modularity.

+ +

In this current version, I have generally reduced the amount of trickery +involved. Previously, Map was defined in pl.class; now it is sensibly defined +in pl.Map; pl.class only contains the basic class mechanism (and returns that +function.) For consistency, List is returned directly by require 'pl.List' +(note the uppercase 'L'), Also, the amount of module dependencies in the +non-core libraries like pl.config have been reduced.

+ +

+

Defining what is Callable

+ +

'utils.lua' exports function_arg which is used extensively throughout Penlight. +It defines what is meant by 'callable'. Obviously true functions are immediately +passed back. But what about strings? The first option is that it represents an +operator in 'operator.lua', so that '<' is just an alias for operator.lt.

+ +

We then check whether there is a function factory defined for the metatable of +the value.

+ +

(It is true that strings can be made callable, but in practice this turns out to +be a cute but dubious idea, since all strings share the same metatable. A +common programming error is to pass the wrong kind of object to a function, and +it's better to get a nice clean 'attempting to call a string' message rather than +some obscure trace from the bowels of your library.)

+ +

The other module that registers a function factory is pl.func. Placeholder +expressions cannot be directly calleable, and so need to be instantiated and +cached in as efficient way as possible.

+ +

(An inconsistency is that utils.is_callable does not do this thorough check.)

+ + + + +
+
+
+generated by LDoc 1.4.6 +
+
+ + -- cgit v1.1-26-g67d0