----------------------------------------------------------------------------- -- Defines utility functions for Sputnik. -- -- (c) 2007, 2008 Yuri Takhteyev (yuri@freewisdom.org) -- License: MIT/X, see http://sputnik.freewisdom.org/en/License ----------------------------------------------------------------------------- module(..., package.seeall) ----------------------------------------------------------------------------- -- Splits a string on a delimiter. -- Adapted from http://lua-users.org/wiki/SplitJoin. -- -- @param text the text to be split. -- @param delimiter the delimiter. -- @return unpacked values. ----------------------------------------------------------------------------- function split(text, delimiter) local list = {} local pos = 1 if string.find("", delimiter, 1) then error("delimiter matches empty string!") end while 1 do local first, last = string.find(text, delimiter, pos) if first then -- found? table.insert(list, string.sub(text, pos, first-1)) pos = last+1 else table.insert(list, string.sub(text, pos)) break end end return unpack(list) end ----------------------------------------------------------------------------- -- Escapes a text for using in a text area. -- -- @param text the text to be escaped. -- @return the escaped text. ----------------------------------------------------------------------------- function escape(text) text = text or "" text = text:gsub("&", "&"):gsub(">",">"):gsub("<","<") return text:gsub("\"", """) end ----------------------------------------------------------------------------- -- Escapes a URL. -- -- @param text the URL to be escaped. -- @return the escaped URL. ----------------------------------------------------------------------------- function escape_url(text) return text:gsub("[^a-zA-Z0-9]", function(character) return string.format("%%%x", string.byte(character)) end) end ----------------------------------------------------------------------------- -- A template for cosmo error messages. ----------------------------------------------------------------------------- COSMO_ERROR_TEMPLATE = [[ Error in Cosmo Template:

Template

%s

Values

%s

Message

%s
]] ----------------------------------------------------------------------------- -- Like cosmo.f() but returns an HTMLized message in case of error. -- -- @param template a cosmo template. ----------------------------------------------------------------------------- function f(template) local fn = cosmo.f(template) return function(values) local function error_handler (err) local values_as_str = "" for k,v in pairs(values) do values_as_str = values_as_str..k..": <"..type(v)..">\n" end return string.format(COSMO_ERROR_TEMPLATE, escape(template), escape(values_as_str), escape(err:gsub("\nstack traceback:.*$", ""))) end local ok, result_or_error = xpcall(function() return fn(values) end, error_handler) return result_or_error, ok end end ----------------------------------------------------------------------------- -- Turns a string into something that can be used as a page name, converting -- - ? + = % ' " / \ and spaces to '_'. Note this isn't enought to ensure -- legal win2k names, since we _are_ allowing [ ] + < > : ; *, but we'll rely -- on versium to escape those later. -- -- @param text the string to be dirified. -- @return the dirified string. ----------------------------------------------------------------------------- function dirify(text) local pattern = [[[%?%+%=%%%s%'%"%\]+]] return (text or ""):gsub(pattern, "_") end ----------------------------------------------------------------------------- -- Returns value1 if condition is true and value2 otherwise. Note that if -- expressions are passed for value1 and value2, then they will be evaluated -- _before_ the choice is made. -- -- @param condition a boolean value -- @param value1 the value that gets returned in case of true -- @param value2 the value that gets returned in case of false -- @return either value1 or value2 ----------------------------------------------------------------------------- function choose(condition, value1, value2) if condition then return value1 else return value2 end end ----------------------------------------------------------------------------- -- Sends email on Sputnik's behalf. -- -- @param args a table of parameters -- @param sputnik an instance of Sputnik -- @return status (boolean) and possibly an error message ----------------------------------------------------------------------------- function sendmail(args, sputnik) assert(args.to, "No recepient specified") assert(args.subject, "No subject specified") assert(args.from, "No source specified") local smtp = require("socket.smtp") local status, err = smtp.send{ from = args.from, rcpt = "<"..args.to..">", source = smtp.message{ headers = { from = args.from, to = args.to, subject = args.subject }, body = args.body or "", }, server = sputnik.config.SMTP_SERVER or "localhost", port = sputnik.config.SMTP_SERVER_PORT or 25, user = sputnik.config.SMTP_USER, password = sputnik.config.SMTP_PASSWORD, } return status, err end ----------------------------------------------------------------------------- -- Creates a logger instance. ----------------------------------------------------------------------------- function make_logger(module_name, params, level) if module_name then require("logging."..module_name) local logger, err = logging[module_name](unpack(params)) assert(logger, "Could not initialize logger: "..(err or "")) if level then require("logging") logger:setLevel(logging[level]) end return logger else return { debug = function(...) end, -- do nothing info = function(...) end, error = function(...) end, warn = function(...) end, } end end ----------------------------------------------------------------------------- -- A cycle class. ----------------------------------------------------------------------------- local Cycle = {} local Cycle_mt = {__metatable = {}, __index = Cycle} function new_cycle(values) return setmetatable({values=values, i=1}, Cycle_mt) end function Cycle:next() self.i = (self.i % #(self.values)) + 1 end function Cycle:get() return self.values[self.i] end