Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stevedonovan/Penlight.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstevedonovan <steve.j.donovan@gmail.com>2011-03-05 19:30:14 +0300
committerstevedonovan <steve.j.donovan@gmail.com>2011-03-05 19:30:14 +0300
commit36c96a4fc987d5c7635dda478e19cee6921dbfb7 (patch)
treeea0ee9bc79b6d2e852bb4d300139df91f4a5a193
parent59de9782361f32f46b9aa1312e2966d311c9890f (diff)
documentation changes0.9.3
-rw-r--r--docs/penlight.md117
-rw-r--r--lua/pl/Date.lua50
-rw-r--r--lua/pl/List.lua4
-rw-r--r--lua/pl/init.lua1
-rw-r--r--lua/pl/template.lua7
-rw-r--r--lua/pl/utils.lua2
6 files changed, 150 insertions, 31 deletions
diff --git a/docs/penlight.md b/docs/penlight.md
index cef9106..7ade344 100644
--- a/docs/penlight.md
+++ b/docs/penlight.md
@@ -108,7 +108,7 @@ This can be efficiently and succintly expressed as `ls:map(fun)`. Not only is th
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 suprise, 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.
+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.
### Utilities. Generally useful functions.
@@ -403,7 +403,7 @@ There are also some useful classes which also inherit from `Map`. An `OrderedMap
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.
-(@see class, @see classx)
+(@see Map, @see Set)
### Tablex. Useful Operations on Tables
@@ -768,10 +768,78 @@ New in Penlight with the 0.9 series is `text.format_operator`. Calling this enab
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}
+ > = '$animal[$num]' % {animal='dog',num=1}
+ dog[1]
+
+A new module is `template`, which is a version of Rici Lake's [Lua Preprocessor](http://lua-users.org/wiki/SlightlyLessSimpleLuaPreprocessor). 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'
+ res = template.substitute(tmpl,{T = {'one','two','three'}})
+
+and we get
+
+ <ul>
+ <li>1 = ONE</li>
+ <li>2 = TWO</li>
+ <li>3 = THREE</li>
+ </ul>
+
+There is a single function, `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.
-(@see text)
+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'}
+ }
+ }))
+
+(@see text, @see template)
### File-style I/O on Strings
@@ -911,6 +979,45 @@ If you need to find the common path of list of files, then `tablex.reduce` will
> = tablex.reduce(path.common_prefix,{p1,p2,p3})
'd:\dev'
+## Date and Time
+
+### Manipulating Dates
+
+The `Date` class provides a simplified way to work with [date and time](http://www.lua.org/pil/22.1.html) 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
+ > = d:month(),d:year(),d:day()
+ 3 2011 2
+ > d:month(4)
+ > = d
+ 2011-04-02 12:00
+ > d:add {day=1}
+ > = d
+ 2011-04-03 12:00
+
+`add` takes a table containing one of the date table fields.
+
+ > = d:weekday_name()
+ Sun
+ > = d:last_day()
+ 2011-04-30 12: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
+
+
+(@see Date)
## Data
diff --git a/lua/pl/Date.lua b/lua/pl/Date.lua
index a697324..ac9456f 100644
--- a/lua/pl/Date.lua
+++ b/lua/pl/Date.lua
@@ -1,9 +1,9 @@
--- Date and Date.Format classes. <br>
-- @class module
--- @name pl.date
+-- @name pl.Date
--[[
-module("pl.date")
+module("pl.Date")
]]
local class = require 'pl.class'.class
@@ -47,58 +47,66 @@ end
--- set the year.
-- @param y Four-digit year
-- @class function
--- @name Date.year
+-- @name Date:year
--- set the month.
-- @param m month
-- @class function
--- @name Date.year
+-- @name Date:month
+
+--- set the day.
+-- @param d day
+-- @class function
+-- @name Date:day
--- set the hour.
-- @param h hour
-- @class function
--- @name Date.year
+-- @name Date:hour
--- set the minutes.
-- @param min minutes
-- @class function
--- @name Date.year
+-- @name Date:min
--- set the seconds.
-- @param sec seconds
-- @class function
--- @name Date.year
+-- @name Date:sec
--- set the day of year.
-- @class function
-- @param yday day of year
--- @name Date.year
+-- @name Date:yday
--- get the year.
-- @param y Four-digit year
-- @class function
--- @name Date.year
+-- @name Date:year
--- get the month.
-- @class function
--- @name Date.year
+-- @name Date:month
+
+--- get the day.
+-- @class function
+-- @name Date:day
--- get the hour.
-- @class function
--- @name Date.year
+-- @name Date:hour
--- get the minutes.
-- @class function
--- @name Date.year
+-- @name Date:min
--- get the seconds.
-- @class function
--- @name Date.year
+-- @name Date:sec
--- get the day of year.
--- @param yday day of year
--- @name Date.year
-
+-- @class function
+-- @name Date:yday
for _,c in ipairs{'year','month','day','hour','min','sec','yday'} do
@@ -153,10 +161,10 @@ function Date:last_day()
end
--- difference between two Date objects.
--- @param d1
--- @param d2
-function Date.diff(d1,d2)
- local dt = d1.time - d2.time
+-- @param other Date object
+-- @return a Date object
+function Date:diff(other)
+ local dt = self.time - other.time
return Date(dt)
end
@@ -198,7 +206,7 @@ local formats = {
-- <li>H hour (either H or HH)</li>
-- <li>M minute (either M or MM)</li>
-- <li>S second (either S or SS)</li>
--- <ul>
+-- </ul>
-- @usage df = Date.Format("yyyy-mm-dd HH:MM:SS")
-- @class function
-- @name Date.Format
diff --git a/lua/pl/List.lua b/lua/pl/List.lua
index 5a6db97..f34360c 100644
--- a/lua/pl/List.lua
+++ b/lua/pl/List.lua
@@ -339,7 +339,7 @@ local function tostring_q(val)
end
--- how our list should be rendered as a string. Uses join().
--- @see pl.list.List:join
+-- @see pl.List:join
function List:__tostring()
return '{'..self:join(',',tostring_q)..'}'
end
@@ -455,7 +455,7 @@ end
-- @param ... will also be passed to the function
-- @return a table where the keys are the returned values, and the values are Lists
-- of values where the function returned that key. It is given the type of Multimap.
--- @see pl.classx.MultiMap
+-- @see pl.MultiMap
function List:partition (fun,...)
fun = function_arg(1,fun)
local res = {}
diff --git a/lua/pl/init.lua b/lua/pl/init.lua
index 2938fae..3cceb28 100644
--- a/lua/pl/init.lua
+++ b/lua/pl/init.lua
@@ -8,6 +8,7 @@ local modules = {
comprehension=true,luabalanced=true,
test = true, app = true, file = true, class = true, List = true,
Map = true, Set = true, OrderedMap = true, MultiMap = true,
+ Date = true,
-- classes --
}
utils = require 'pl.utils'
diff --git a/lua/pl/template.lua b/lua/pl/template.lua
index c70e957..11cdfed 100644
--- a/lua/pl/template.lua
+++ b/lua/pl/template.lua
@@ -70,7 +70,7 @@ function template.substitute(str,env)
if env._parent then
setmetatable(env,{__index = env._parent})
end
- local code = parseHashLines(str,env._brackets or '()',env._escape or '#')
+ local code = parseHashLines(str,env._brackets or '()',env._escape or '#')
local fn,err = loadin(env,code,'TMP')
if not fn then return nil,err end
fn = fn()
@@ -78,7 +78,10 @@ function template.substitute(str,env)
local res,err = pcall(fn,function(s)
out[#out+1] = s
end)
- if not res then return nil,err end
+ if not res then
+ if env._debug then print(code) end
+ return nil,err
+ end
return table.concat(out)
end
diff --git a/lua/pl/utils.lua b/lua/pl/utils.lua
index 9ed6a14..6b43b8b 100644
--- a/lua/pl/utils.lua
+++ b/lua/pl/utils.lua
@@ -147,7 +147,7 @@ function utils.readlines(filename)
return res
end
----- split a string into a list of strings separated by a delimiter.
+--- split a string into a list of strings separated by a delimiter.
-- @param s The input string
-- @param re A regular expression; defaults to spaces
-- @return a list-like table