summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx')
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx469
1 files changed, 274 insertions, 195 deletions
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
index dd5b118f9aa..81394be2f93 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
@@ -115,11 +115,7 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \pk{luatexbase-modutils} package}
-% \date{v0.2 2010-05-12}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase-modutils}{v0.2 2010-05-12}
%
% \maketitle
%
@@ -129,15 +125,16 @@ See source file '\inFileName' for details.
% \cs{documentclass} and \cs{RequirePackage} or \cs{ProvidesClass} and
% \cs{ProvidesFiles}} or more precisely the part of these macros that deals
% with identification and version checking (no attempt is done at implementing
-% an option mechanism). Functions for error reporting are provided too.
-%
-% It also loads \pk{luatexbase-loader}.
+% an option mechanism). It also provides functions for reporting errors and
+% warnings in a standardised format.
% \end{abstract}
%
% \tableofcontents
%
% \section{Documentation}
%
+% \subsection{Scope of this package}
+%
% Lua's standard function |require()| is similar to \tex's |\input| primitive
% but is somehow more evolved in that it makes a few checks to avoid loading
% the same module twice. In the \tex world, this needs to be taken care of by
@@ -147,57 +144,148 @@ See source file '\inFileName' for details.
% implements a complex option system, and does some identification and version
% checking. The present package doesn't try to provide anything for options,
% but implements a system for identification and version checking similar to
-% \latex's system. Both \tex macros and Lua functions are provided.
+% \latex's system.
%
-% This package also provides Lua functions for reporting errors, warnings,
-% etc.
+% \medskip
%
% It is important to notice that Lua's standard function |module()| is
-% completely unrelated to the present package. It has nothing to do with
-% identification and deals only with namespaces.\footnote{More precisely, it
-% modifies the current environment.} So, you should continue to
-% use it normally, unlike the |require()| function which can be replaced with
-% this package's |luatexbase.require_module()|.
+% completely orthogonal with the present package. It has nothing to do with
+% identification and deals only with namespaces: more precisely, it
+% modifies the current environment. So, you should continue to
+% use it normally regardless of whether you chose to use this package's
+% features for identification.
+%
+% It is recommended to always use |module()| or any other method that ensure
+% the global name space remains clean. For example, you may heavily use the
+% |local| keyword and explicitly qualify the name of every non-local symbol.
+% Chapter 15 of \href{http://www.lua.org/pil/}{Programming in Lua, 1st ed.}
+% discusses various methods for managing packages.
%
% \subsection{\tex macros}
%
-% The two macros |\luatexUseModule| and |\luatexRequireModule| are very
-% similar and are interfaces to the Lua functions |use_module| and
-% |require_module|. The only difference between those macros is the number of
-% arguments (just as the underlying Lua functions): |\luatexUseModule| only
-% take one argument: the module name\footnote{without extension} while
-% |\luatexRequireModule| takes another argument for specifying a minimal
-% version (see below). With \latex, this argument is the first and is
-% optional. Otherwise, it's the second one and it's mandatory.
+% \begin{qcode}
+% \cs{RequireLuaModule}\marg{name}\oarg{date}
+% \end{qcode}
+%
+% The macro |\RequireLuaModule| is an interface to the Lua function
+% |require_module|; it take the same arguments with the same meaning. The
+% second argument is optional.
%
% \subsection{Lua functions}
%
-% The main functions are |luatexbase.require_module| and
-% |luatexbase.use_module| which may be used as a replacement to |require()|.
-% The only difference between these functions is, |require_module| accepts a
-% second, optional argument in order to specify a minimal version. They do the
-% same as |require()| but also make sure the module loaded correctly
-% identifies itself with the name given, and its version is greater than the
-% minimal version required. The version can be given either as a (floating
-% point) number or as a date in YYYY/MM/DD format.
-%
-% Modules identify themselves using |luatexbase.provides_module|, whose only
-% argument is a table with some information about the module. The mandatory
-% fields are |name| (a string), |version| (a number), |date| (a string) and
-% |description| (a string). Other fields are optional and ignored, and usually
-% include |copyright|, |author| and |license|.
-%
-% \bigskip
-%
-% Functions for reporting are provided; similarly to \latex's |\PackageError|
-% etc. they take the module name as their first argument and include it in the
-% printed message in an appropriate way. The remaining arguments are passed to
-% |string.format()| before being printed.
-%
-% The functions provided (all found in the |luatexbase| table) are
-% |module_error|, |module_warning|, |module_info| (writes to terminal and
-% log), |module_log| (writes only to the log file) and |module_term| (writes
-% only to the terminal).
+% \begin{qcode}
+% luatexbase.require_module({\meta{name}} [, \meta{required date}])
+% \end{qcode}
+%
+% The function |luatexbase.require_module()| may be used as a replacement to
+% |require()|. If only one argument is given, the only difference with
+% |require()| is it checks that the module properly identifies itself (as
+% explained below) with the same name.
+%
+% The second argument is optional; if used, it must be a
+% string\footnote{Previous versions of the package supported floating-point
+% version numbers as well, but it caused confusion with authors trying to use
+% version strings such as |0.3a| and probably isn't worth the trouble.}
+% containing a date in |YYYY//MM/DD| format which specifies the minimum
+% version of the module required.
+%
+% \begin{qcode}
+% luatexbase.provides_module(\meta{info})
+% \end{qcode}
+% This function is used by modules to identify themselves; the argument is a
+% table containing information about the module. The required field |name|
+% must contain the name of the module. It is recommended to provide a field
+% |date| with the same format as above. Optional fields |version| (number or
+% string) and |description| may be used if present. Other fields are ignored.
+%
+% If a date was required, then a warning is issued if the required date is
+% strictly newer than the declared date (or if no date was declared). A list
+% of loaded modules and their associated information is kept, and used to
+% check the date without reloading the module (since |require()| won't reload
+% it anyway) if a module is required several times.
+%
+% \begin{qcode}
+% luatexbase.module_error(\meta{name}, \meta{message}, ...)
+% luatexbase.module_warning(\meta{name}, \meta{message}, ...)
+% luatexbase.module_info(\meta{name}, \meta{message}, ...)
+% luatexbase.module_log(\meta{name}, \meta{message}, ...)
+% \end{qcode}
+% These functions are similar to \latex's |\PackageError|, |\PackageWarning|
+% and |\PackageInfo| in the way they format the output. No automatic line
+% breaking is done, you may still use |\n| as usual for that, and the name of
+% the package will be prepended to each output line (except for |log| which is
+% intended for short messages in a non-verbose format). The first argument
+% is the name of the current module; the remaining arguments are passed to
+% |string.format()|.
+%
+% Note that |module_error| raises an actual Lua error with |error()|, which
+% currently means a call stack will be dumped. While this may not look pretty,
+% at least it provides useful information for tracking the error down.
+%
+% \begin{qcode}
+% local err, warn, info, log = luatexbase.errwarinf(\meta{name})
+% local err, warn, info, log = luatexbase.provides_module(\meta{name})
+% \end{qcode}
+% Customised versions of the above commands maybe obtained by invoking
+% |errwarinf()| and are also returned by |provides_module()|. They don't take
+% the name of the module as their first argument any more, so that you don't
+% need to repeat it all over the place. (Notice that |error| is the name of a
+% standard Lua function, so you may want to avoid overwriting it, hence the
+% use of |err| in the above example.)
+%
+% \subsection{Templates}
+%
+% Let me emphasize again that, while |luatexbase.require_module()| is meant to
+% be used as a replacement for |require()|, the function
+% |luatexbase.provides_module()| \emph{is not} a replacement for |module()|:
+% they just don't do the same thing (declaring information vs changing the
+% current name space).
+%
+% Now, here is how you module may begin:
+% \begin{verbatim}
+% local err, warn, info, log = luatexbase.provides_module({
+% -- required
+% name = 'mymodule',
+% -- recommended
+% date = '1970/01/01',
+% version = 0.0, -- or version = '0.0a',
+% description = 'a Lua module template',
+% -- optional and ignored
+% author = 'A. U. Thor',
+% licence = 'LPPL v1.3+',
+% })
+%
+% module('mynamespace', package.seeall)
+% -- or any other method (see chapter 15 of PIL for examples)
+% \end{verbatim}
+%
+% Alternatively, if you don't want to assume \pk{luatexbase-modutils} is
+% loaded, you may load your module with:
+% \begin{verbatim}
+% (luatexbase.require_module or require)('mymodule')
+% \end{verbatim}
+% and begin your module's code with:
+% \begin{verbatim}
+% if luatexbase._provides_module then
+% luatexbase.provides_module({
+% -- required
+% name = 'mymodule',
+% -- recommended
+% date = '1970/01/01',
+% version = 0.0, -- or version = '0.0a',
+% description = 'a Lua module template',
+% -- optional and ignored
+% author = 'A. U. Thor',
+% licence = 'LPPL v1.3+',
+% })
+% end
+%
+% module('mynamespace', package.seeall)
+% -- or any other method (see chapter 15 of PIL for examples)
+%
+% local function err(msg)
+% -- etc.
+% \end{verbatim}
%
% \section{Implementation}
%
@@ -263,7 +351,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase-modutils}[2010/05/27 v0.2a Module utilities for LuaTeX]
+\x{luatexbase-modutils}[2010/10/10 v0.3 Module utilities for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -277,60 +365,94 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase-modutils}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@modutils@AtEnd
\expandafter\endinput
\fi
% \end{macrocode}
%
-% Load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}) and require
-% supporting Lua module.
+% Load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}), require the
+% supporting Lua module and make sure |luaescapestring| is available.
%
% \begin{macrocode}
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname RequirePackage\endcsname\relax
- \input luatexbase-loader.sty
-\else
+\ifdefined\RequirePackage
\RequirePackage{luatexbase-loader}
+\else
+ \input luatexbase-loader.sty
\fi
\luatexbase@directlua{require('luatexbase.modutils')}
-% \end{macrocode}
-%
-% Make sure the primitives we need are available.
-%
-% \begin{macrocode}
\luatexbase@ensure@primitive{luaescapestring}
% \end{macrocode}
%
-% \subsubsection{User macros}
+% \subsection{Auxiliary definitions}
%
-% Interface to |use_module()|.
+% We need a version of |\@ifnextchar|. The definitions for the not-\latex
+% case are stolen from \pk{ltxcmds} verbatim, only the prefix is changed.
%
% \begin{macrocode}
-\def\luatexUseModule#1{\luatexbase@directlua{%
- luatexbase.use_module("\luatexluaescapestring{#1}")}}
+\ifdefined\kernel@ifnextchar
+ \let\lltxb@ifnextchar\kernel@ifnextchar
+\else
+ \chardef\lltxb@zero0
+ \chardef\lltxb@two2
+ \long\def\lltxb@ifnextchar#1#2#3{%
+ \begingroup
+ \let\lltxb@CharToken= #1\relax
+ \toks\lltxb@zero{#2}%
+ \toks\lltxb@two{#3}%
+ \futurelet\lltxb@LetToken\lltxb@ifnextchar@
+ }
+ \def\lltxb@ifnextchar@{%
+ \ifx\lltxb@LetToken\lltxb@CharToken
+ \expandafter\endgroup\the\toks\expandafter\lltxb@zero
+ \else
+ \ifx\lltxb@LetToken\lltxb@SpaceToken
+ \expandafter\expandafter\expandafter\lltxb@@ifnextchar
+ \else
+ \expandafter\endgroup\the\toks
+ \expandafter\expandafter\expandafter\lltxb@two
+ \fi
+ \fi
+ }
+ \begingroup
+ \def\x#1{\endgroup
+ \def\lltxb@@ifnextchar#1{%
+ \futurelet\lltxb@LetToken\lltxb@ifnextchar@
+ }%
+ }%
+ \x{ }
+ \begingroup
+ \def\x#1{\endgroup
+ \let\lltxb@SpaceToken= #1%
+ }%
+ \x{ }
+\fi
% \end{macrocode}
%
-% Interface to |require_module()| with syntax depending on the format.
+% \subsubsection{User macro}
+%
+% Interface to the Lua function for module loading. Avoid passing a second
+% argument to the function if empty (most probably not specified).
%
% \begin{macrocode}
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname newcommand\endcsname\relax
- \def\luatexRequireModule#1#2{%
- \luatexbase@directlua{luatexbase.require_module(
- "\luatexluaescapestring{#1}", "\luatexluaescapestring{#2}")}}
-\else
- \newcommand\luatexRequireModule[2][0]{%
- \luatexbase@directlua{luatexbase.require_module(
- "\luatexluaescapestring{#2}", "\luatexluaescapestring{#1}")}}
-\fi
+\def\RequireLuaModule#1{%
+ \lltxb@ifnextchar[{\lltxb@requirelua{#1}}{\lltxb@requirelua{#1}[]}}
+\def\lltxb@requirelua#1[#2]{%
+ \luatexbase@directlua{luatexbase.require_module(
+ "\luatexluaescapestring{#1}"
+ \expandafter\ifx\expandafter\/\detokenize{#2}\/\else
+ , "\luatexluaescapestring{#2}"
+ \fi)}}
% \end{macrocode}
%
% \begin{macrocode}
@@ -348,75 +470,75 @@ module("luatexbase", package.seeall)
% \subsection{Internal functions and data}
%
% Tables holding informations about the modules loaded and the versions
-% required.
+% required. Keys are module names and values are the info tables as passed
+% to |provides_module()|.
%
% \begin{macrocode}
local modules = modules or {}
-local requiredversions = {}
% \end{macrocode}
%
-% Convert a date in YYYY/MM/DD format into a number
+% Convert a date in YYYY/MM/DD format into a number.
%
% \begin{macrocode}
-local function datetonumber(date)
+local function date_to_int(date)
numbers = string.gsub(date, "(%d+)/(%d+)/(%d+)", "%1%2%3")
return tonumber(numbers)
end
% \end{macrocode}
%
-% Say if a string is a date in YYYY//MM/DD format.
-%
-% \begin{macrocode}
-local function isdate(date)
- for _, _ in string.gmatch(date, "%d+/%d+/%d+") do
- return true
- end
- return false
-end
-% \end{macrocode}
-%
-% Parse a version into a table indicating a type (date or number), a
-% numeric version and the original version string.
-%
-% \begin{macrocode}
-local date, number = 1, 2
-local function parse_version(version)
- if isdate(version) then
- return {type = date, version = datetonumber(version), orig = version}
- else
- return {type = number, version = tonumber(version), orig = version}
- end
-end
-% \end{macrocode}
-%
% \subsubsection{Error, warning and info function for modules}
%
-% Here are the reporting functions for the modules. For errors, Lua's
-% |error()| is used. For now, the error reports look less good than with
-% \tex's |\errmessage|, but hopefully it will be improved in future
-% versions of \luatex. We could invoke |\errmessage| using |tex.sprint()|,
-% but it may cause problems on the \tex end, and moreover |error()| will
-% still be used by Lua for other errors, so it makes messages more
-% consistent.
+% Here are the reporting functions for the modules. An internal function is
+% used for error messages, so that the calling level (last argument of
+% |error()| remains constant using either |module_error()| or a custom
+% version as returned by |errwarinf()|.
%
% \begin{macrocode}
+local function msg_format(msg_type, mod_name, ...)
+ local cont = '('..mod_name..')' .. ('Module: '..msg_type):gsub('.', ' ')
+ return 'Module '..mod_name..' '..msg_type..': '
+ .. string.format(...):gsub('\n', '\n'..cont) .. '\n'
+end
local function module_error_int(mod, ...)
- error('Module '..mod..' error: '..string.format(...), 3)
+ error(msg_format('error', mod, ...), 3)
end
function module_error(mod, ...)
module_error_int(mod, ...)
end
+% \end{macrocode}
+%
+% Split the lines explicitly in order not to depend on the value of
+% |\newlinechar|.
+%
+% \begin{macrocode}
function module_warning(mod, ...)
- texio.write_nl("Module "..mod.." warning: "..string.format(...))
+ for _, line in ipairs(msg_format('warning', mod, ...):explode('\n')) do
+ texio.write_nl(line)
+ end
end
function module_info(mod, ...)
- texio.write_nl(mod..": "..string.format(...))
+ for _, line in ipairs(msg_format('info', mod, ...):explode('\n')) do
+ texio.write_nl(line)
+ end
end
-function module_log(mod, ...)
- texio.write_nl('log', mod..": "..string.format(...))
+% \end{macrocode}
+%
+% No line splitting or advanced formating here.
+%
+% \begin{macrocode}
+function module_log(mod, msg, ...)
+ texio.write_nl('log', mod..': '..msg:format(...))
end
-function module_term(mod, ...)
- texio.write_nl('term', mod..": "..string.format(...))
+% \end{macrocode}
+%
+% Produce custom versions of the reporting functions.
+%
+% \begin{macrocode}
+function errwarinf(name)
+ return function(...) module_error_int(name, ...) end,
+ function(...) module_warning(name, ...) end,
+ function(...) module_info(name, ...) end,
+ function(...) module_log(name, ...) end
end
% \end{macrocode}
%
@@ -424,83 +546,42 @@ end
% present module.
%
% \begin{macrocode}
-local function err(...) module_error_int('luatexbase.modutils', ...) end
-local function warn(...) module_warning('luatexbase.modutils', ...) end
+local err, warn = errwarinf('luatexbase.modutils')
% \end{macrocode}
%
% \subsubsection{module loading and providing functions}
%
-% Load a module without version checking.
+% Load a module with mandatory name checking and optional version checking.
%
% \begin{macrocode}
-function use_module(name)
+function require_module(name, req_date)
require(name)
- if not modules[name] then
- warn("Module didn't properly identified itself: %s", name)
- end
-end
-% \end{macrocode}
-%
-% Load a module with optional version checking.
-%
-% \begin{macrocode}
-function require_module(name, version)
- if not version then
- return use_module(name)
- end
- luaversion = parse_version(version)
- if modules[name] then
- if luaversion.type == date then
- if datetonumber(modules[name].date) < luaversion.version then
- err("found module `%s' loaded in version %s, "
- .."but version %s was required",
- name, modules[name].date, version)
- end
- else
- if modules[name].version < luaversion.version then
- err("found module `%s' loaded in version %.02f, "
- .."but version %s was required",
- name, modules[name].version, version)
- end
+ local info = modules[name]
+ if not info then
+ warn("module '%s' was not properly identified", name)
+ elseif version then
+ if not (info.date and date_to_int(info.date) > date_to_int(req_date))
+ then
+ warn("module '%s' required in version '%s'\n"
+ .. "but found in version '%s'", name, req_date, info.date)
end
- else
- requiredversions[name] = luaversion
- use_module(name)
end
end
% \end{macrocode}
%
-% Provide identification information for a module.
+% Provide identification information for a module. As a bonus, custom
+% reporting functions are returned. No need to do any check here,
+% everything done in |require_module()|.
%
% \begin{macrocode}
-function provides_module(mod)
- if not mod then
- err('cannot provide nil module')
- return
- end
- if not mod.version or not mod.name or not mod.date
- or not mod.description then
- err("invalid module registered: "
- .."fields name, version, date and description are mandatory")
- return
- end
- requiredversion = requiredversions[mod.name]
- if requiredversion then
- if requiredversion.type == date
- and requiredversion.version > datetonumber(mod.date) then
- err("loading module %s in version %s, "
- .."but version %s was required",
- mod.name, mod.date, requiredversion.orig)
- elseif requiredversion.type == number
- and requiredversion.version > mod.version then
- err("loading module %s in version %.02f, "
- .."but version %s was required",
- mod.name, mod.version, requiredversion.orig)
- end
+function provides_module(info)
+ if not (info and info.name) then
+ err('provides_module: missing information')
end
- modules[mod.name] = mod
- texio.write_nl('log', string.format("Lua module: %s %s v%.02f %s\n",
- mod.name, mod.date, mod.version, mod.description))
+ texio.write_nl('log', string.format("Lua module: %s %s %s %s\n",
+ info.name, info.date or '', info.version or '', info.description or ''))
+ modules[info.name] = info
+ return errwarinf(info.name)
end
% \end{macrocode}
%
@@ -514,28 +595,26 @@ end
%
% \begin{macrocode}
%<*testdummy>
-luatexbase.provides_module {
+local err, warn, info, log = luatexbase.provides_module {
name = 'test-modutils',
date = '2000/01/01',
version = 1,
description = 'dummy test package',
}
+info('It works!\nOh, rly?\nYeah rly!')
+log("I'm a one-line info.")
%</testdummy>
% \end{macrocode}
%
% We just check that the package loads properly, under both LaTeX and Plain
-% TeX. Anyway, the test files of other modules using this one already are a
-% test\dots
+% TeX, is able to load and identify the above dummy module.
%
% \begin{macrocode}
%<testplain>\input luatexbase-modutils.sty
%<testlatex>\RequirePackage{luatexbase-modutils}
%<*testplain,testlatex>
-\luatexUseModule{test-modutils}
-\luatexRequireModule
-%<testlatex>[1970/01/01]
-{test-modutils}
-%<testplain>{1970/01/01}
+\RequireLuaModule{test-modutils}
+\RequireLuaModule{test-modutils}[1970/01/01]
%</testplain,testlatex>
%<testplain>\bye
%<testlatex>\stop