Expand description
§masterpg
§Overview
The masterpg utility composes files by replacing placeholder tags with actual content defined elsewhere, possibly in other files. Initially it was meant for static HTML files, as an alternative to a missing
<include /> tag in HTML.
This crate provides both
- a library function,
- and a command-line utility.
Both the library function and the command-line utility were originally designed to be used web-server-side or during the publishing phase of web pages, albeit they can compose any kind of UTF-8 text files.
§Library function
pub fn compose in src/lib.rs provides this utility’s composition functionality as a public function you can call from within your own Rust applications.
It has at least two modes of input and output, as it takes an instance of an implementation of the string_io_and_mock::TextIOHandler trait for its io_handler parameter :
- files
- strings stored in memory.
In order to have masterpg work with files, you can pass an instance of string_io_and_mock::FileTextHandler.
In order to have it work with strings, you can pass an instance of string_io_and_mock::MockTextHandler.
(MockTextHandler is called that way because it can be used to mock the behaviour of FileTextHandler in unit tests, even if it is usable and tested as a component in its own right for storage and retrieval of strings in memory.)
For other needs, you can always develop your own implementation of string_io_and_mock::TextIOHandler.
In order to use the library function, execute the below command in your project’s main directory:
cargo add masterpg
§Command-line utility
The command-line utility is defined by fn main in src/main.rs and calls the library function.
In order to use it, you’ll have to install Rust, open a terminal window, and execute
cargo install masterpg
which will both download and compile masterpg for your architecture.
For more details about the file system path where the resulting executable can be found, see Cargo’s reference.
§Input file tags
masterpg functions by processing eight kinds of tags in input files :
<+output file_path/>:indicates to which file the result of the composition operation has to be written.
<+master file_path/>:indicates that a file having the given path is to be used as master page. If the file path doesn’t contain a full path, it is considered to be relative to the current active directory.
An input file can contain more than one<+master ...>tags.
<+placeholder tag_name/>:indicates that this placeholder has to be replaced by the content of an
<+actual>tag having the same tag name.
<+actual tag_name>…</+actual>:the actual content to replace placeholders with having the same tag name.
<+comment>…</comment>:will be removed from the output.
<+timestamp/>:produces a timestamp in the form of
ts=16548548678647in the output text. The digits are the number of milliseconds elapsed since the start of the Unix epoch.
<+calc tag_name [operator] [operand1] [operand2] [operand3] ... />:performs a calculation : it applies the operator +, -, *, / or others on one or more operands.
<+laconic tag_name {laconic expression or script} />:performs a calculation by interpreting a Laconic script.
Note that these tags are case-insensitive.
§Calculations in <+calc ... /> tags
The operands of a <+calc ... /> tag can be either
- literal numerical values, or else
- tag names that refer to other
<+calc tag_name .../>tags or<+actual tag_name>tags having that tag name.
This means that <+actual> tags and <+calc> tags can’t have the same tag name.
No units may be included in the operands : 10 is allowed, but not 10px.
Units, however, may follow immediately after <+calc - .../> or <+placeholder .../> tags. E.g.:
<+actual divHeight>30</+actual>
<+actual goldenCut>1.618034</+actual>
<+calc largeDivHeight * divHeight 2/>
<+calc largeDivWidth / largeDivHeight goldenCut />
...
<+placeholder largeDivWidth/>px
...
<+placeholder largeDivWidth/>px
A <+calc tag_name .../> tag, when evaluated, will be replaced by an <+/actual tag_name>result</+actual> tag, except when the tag name (the first word after <+calc) is -, in which case the result will be directly included in the output file :
<+actual price>200</+actual>
<+actual commission>20</+actual>
<+actual taxRate>0.20</+actual>
<+calc amount + price commission/> ---> <+actual amount>220</+actual>
<+calc tax * amount taxRate/> ---> <+actual>44</+actual>
<+calc - + amount tax/> $ ---> 264 $
<+calc> tags handle the below operators :
+: addition-: subtraction*: multiplicationx: multiplication also/: division:: division also÷: division also%: remaindermin: get smallest of given operandsmax: get greatest of given operandsabs: absolute value^: power**: power alsopow: power alsoexp: power alsosign: the sign of the first operand.round: rounding around 0trunc: removing fractal value, towards 0,floor: removing fractal value, towards -∞ceiling: removing fractal value, towards +∞
These operators are case-insensitive.
<+calc>,<+actual>and<+placeholder>tags may reside in the same file, in a master file or in a client file referring to a master file. Asmasterpgoperates by joining all these files’ contents to one text before resolving the said tags, you are free to put these tags wherever they serve your purpose.
§Calculations in <+laconic ... /> tags
Version 2.0.0 of the masterpg crate saw the addition of <+laconic ...> tags.
These tags offer both way more functionality and way more flexibility in calculations than the <+calc ...> tags.
A <+laconic tagname {script}/> tag contains a tagname or a - marker, just like the <+calc> tag, but next it contains a Laconic expression or script enclosed in matching multiples of curly braces. E.g.:
<+laconic - {* 200 c#gold}/>
will put the product of 200 and the golden ratio constant in the composed file.
<+laconic - {{? v#isHtml [s <style>.small {font-size: .5em;}</style>] #}}/>
will insert an HTML style tag into the composed file if variable #isHtml has a truthy value, without any need to escape the single curly braces, as the entire Laconic expression is enclosed in double curly braces.
Laconic scripts are unaware about other tags in source files, but there’s no need for that:
instead of using references to other tags by tag name, Laconic scripts can process variables assigned in other Laconic tags in the set of source files used to compose a result file.
In Laconic scripts, one way of assigning a variable is an expression like the below one:
$#varName value
E.g.:
<+laconic dummyTagName {$#width 400}/>
assigns 400 to a variable having name ‘width’.
(Mind that this way, variable names can’t have spaces.)
A subsequent Laconic tag can reuse the value of that variable by referencing it using Laconic’s
voperator:
<+laconic - {/ v#width c#gold}/>
will put the width divided by the golden ratio constant in the output file of the composition.
Note: one <+laconic …/> tag can contain multiple assignments, and even calculations, on a single line or even multiple ones, e.g.:
<+laconic generalAssignments {
$#rows 10
$#columns 4
$#cells * v#rows v#columns
}/>
Laconic offers much more than simple calculations on numeric variables! See crates.io and its documentation link for the full documentation of the Laconic language.
§How input files are processed
masterpg works by :
-
handling all the input files given on its command line;
-
executing the below steps for every input file given on the the command line :
-
finding the first
<+output>tag and storing the output file path in a variable; -
then reading an input file in a string and replacing all
<+master />-tags in this string with the content of the entire file indicated, and even doing this recursively, so even master page files can contain their own<+master />-tags; -
then, in the resulting string, replacing
- all
<+calc>tags with<+actual>tags holding the calculated value, or with the literal value; - all
<+laconic>tags with<+actual>tags holding the calculated value, or with the literal value; - all
<+placeholder>tags with the content of the corresponding<+actual>tags; - all
<timestamp/>tags with a timestamp;
- all
-
then, removing all the
<+...>tags (should only be +comment, +output and +actual); -
finally, writing the result to the file path found in the first
<+output>tag, overwriting existing files.
-
As a convention, which is not enforced by masterpg, you could use the below file name extensions :
- *.mpm for master pages;
- *.mpc for master page consumers (or clients), having an
<+master .../>tag; - *.mpx for files that both serve as a master page and consume one themselves.
Note that only the name of the final consumer file has to be passed as the first argument to the command
masterpg [consumer file]
or, if more than one output file has to be generated :
masterpg [consumer file] [consumer file] [consumer file] ...
§Example: HTML
§Given consts.mpm :
<+actual siteName>Test Pages</+actual>
<+actual author>Lenny Baxter</+actual>
§and given general.mpx :
<+master consts.mpm/>
<!doctype html>
<html>
<head>
<title><+placeholder pageTitle/></title>
</head>
<body>
<h1><+placeholder pageTitle/></h1>
<i>by <+placeholder author/></i>
<div id="main"><+placeholder pageContent/></div>
</body>
</html>
§and given testpg.mpc :
<+master general.mpx/>
<+output index.htm/>
<+actual pageContent>
<p>Welcome to my <+placeholder siteName/> site !</p>
<p>I'm <+placeholder author/> and I'm just testing the masterpg module.</p>
<p>Bye for now !</p>
</+actual>
<+actual pageTitle>Welcome</+actual>
§then the command
masterpg testpg.mpc
§creates the file index.html :
<!doctype html>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>Welcome</h1>
<i>by Lenny Baxter</i>
<div id="main">
<p>Welcome to my Test Pages site !</p>
<p>I'm Lenny Baxter and I'm just testing the masterpg module.</p>
<p>Bye for now !</p>
</div>
</body>
</html>
§Example: PostScript
§Given undecim.ps.mpm :
<+output undecim.ps/>
%!PS
newpath
<+laconic - {
$#centerX 300
$#centerY 400
$#radius 150
$#points 11
$#skip i / v#points 2
$#arch * v#skip / *2p v#points
#
}/>
<+laconic - {v#centerX}/> <+laconic - {+ v#centerY v#radius}/> moveto
<+laconic - {
o#fmt 3
$#linesCode c#n
F
1
v#points
1
#i
;(
$#nextArch + % * v#arch v#i *2p /p2
$#x + v#centerX * v#radius C v#nextArch
$#y + v#centerY * v#radius S v#nextArch
+(:#linesCode v#x [s ] v#y [s lineto] c#n)
)
v#linesCode
}/>
gsave
0 1 0.5 setrgbcolor
fill
grestore
0 0 1 setrgbcolor
4 setlinewidth
stroke
showpage
Note: the # in the last line of the first <+laconic> tag causes an empty string to be output in the result file. Without this, the value of the last expression - the $#arch assignment - would be output in the result file.
§then the command
masterpg undecim.ps.mpm
§creates the file undecim.ps:
%!PS
newpath
300.000000 550.000000 moveto
257.740 256.075 lineto
381.095 526.187 lineto
186.637 301.770 lineto
436.445 462.312 lineto
151.527 378.653 lineto
448.472 378.653 lineto
163.555 462.312 lineto
413.362 301.770 lineto
218.904 526.187 lineto
342.260 256.075 lineto
300.000 550.000 lineto
gsave
0 1 0.5 setrgbcolor
fill
grestore
0 0 1 setrgbcolor
4 setlinewidth
stroke
showpage
Functions§
- compose
- See the crate’s documentation about functionality.