在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):weshoke/Lust开源软件地址(OpenSource Url):https://github.com/weshoke/Lust开源编程语言(OpenSource Language):Lua 100.0%开源软件介绍(OpenSource Introduction):LustLua String Templates OverviewLust is a templating system for Lua loosely based on Terrence Parr's StringTemplate. Lust has been designed to enable the simple expression of complex string synthesis problems. It is particularly well suited for generating strings from hierarchical data structures. Lust itself encompases a language for writing templates and an interpreter for applying the templates to a datastructure. Lust features
AuthorsLust is developed by Wesley Smith and Graham Wakefield with the support of Cycling '74. LicenseLust is licensed under the standard MIT license just like the Lua Language. DependenciesLust depends on the Lua Parsing Expression Grammar (LPEG) module. High-Level OverviewIn Lust, you author a set of templates, giving each one a name. Templates can be grouped together by putting them in a common namespace. To use the templates for string synthesis, a datastructure is passed to the Lust object, which initiates the synthesis process by applying the root template rule to the datastructure. As the root rule invokes subtemplates, Lust walks the datastructure passed in by following the commands described by operators embedded in the templates. Lust walks a datastructure either by iterating over arrays of values or by looking at named fields. Lust BasicsThe most fundamental structures in Lust are templates and environments. Templates are named strings, and environments represent the set of values a template has access to. The environment of a template is just like the concept of scope in a programming language. It provides a set of named values that can be referenced and operated on. StringificationStringification takes a value and renders it directly into a string. In Lust, the stringification operator is indicated by the $ symbol. -- $. applies the current environment:
Lust([[$.]]):gen("hello") -- res: "hello" -- $1 selects item from environment-as-array:
Lust([[$1 $2]]):gen{ "hello", "world" } -- res: "hello world" -- $foo selects item from environment-as-dictionary:
Lust[[$foo $bar]]:gen{ foo="hello", bar="world" } -- res: "hello world" -- $< > can be used to avoid ambiguity:
Lust[[$<1>2 $<foo>bar]]:gen{ "hello", foo="world" } -- res: "hello2 worldbar" -- selections can be constructed as paths into the environment:
Lust[[$a.b.c $1.1.1]]:gen{ a={ b={ c="hello" } }, { { "world" } } } -- res: "hello world"
Lust[[$a.1 $1.b]]:gen{ a={ "hello" }, { b="world" } } -- res: "hello world" -- the # symbol prints the length of an environment selection:
Lust[[$#.]]:gen{ 1, 2, 3 } -- res: "3"
Lust[[$#foo.bar]]:gen{ foo={ bar={ 1, 2, 3 } } } -- res: "3" -- selections can be resolved dynamically using (x):
Lust[[$(x)]]:gen{ x="foo", foo="hello" } -- res: "hello"
Lust[[$(x.y).1]]:gen{ x={ y="foo" }, foo={"hello"} } -- res: "hello" Template ApplicationTemplate application applies a template to a particular environment. The template invocation operator is indicated by the @ symbol. -- the @name invokes a statically named sub-template:
local temp = Lust[[@child]]
-- define a subtemplate:
temp.child = "$1 to child"
temp:gen{"hello"} -- res: "hello to child" -- subtemplates can also be specified in the constructor-table:
Lust{
[[@child]],
child = "$1 to child",
}:gen{"hello"} -- res: "hello to child" -- subtemplate invocations can use < > to avoid ambiguity:
Lust{
[[@<child>hood]],
child = "$1 to child",
}:gen{"hello"} -- res: "hello to childhood" -- subtemplates with subtemplates:
Lust{
[[@child, @child.grandchild]],
child = {
"$1 to child",
grandchild = "$1 to grandchild",
},
}:gen{"hello"} -- res: "hello to child, hello to grandchild" -- subtemplates with subtemplates (alternative naming):
Lust{
[[@child, @child.grandchild]],
child = "$1 to child",
["child.grandchild"] = "$1 to grandchild",
}:gen{"hello"} -- res: "hello to child, hello to grandchild" -- subtemplate names can also be resolved dynamically, according to model values, using (x):
Lust{
[[@(x), @(y)]],
child1 = "hello world",
child2 = "hi"
}:gen{ x="child1", y="child2" } -- res: "hello world, hi" -- the environment passed to a subtemplate can be specifed as a child of the current environment:
Lust{
[[@1:child @two:child]],
child = [[$. child]],
}:gen{ "one", two="two" } -- res: "one child two child" -- the symbol . can be used to explicitly refer to the current environment:
Lust{
[[@child == @.:child]],
child = [[$1 child]],
}:gen{ "hello" } -- res: "hello child == hello child" -- subtemplate paths can mix static and dynamic terms:
Lust{[[@child.(x), @(y).grandchild, @(a.b)]],
child ="$1 to child",
["child.grandchild"] = "$1 to grandchild",
}:gen{
x="grandchild",
y="child",
"hello",
a = { b="child" }
} -- res: "hello to grandchild, hello to grandchild, hello to child" -- child environments can be specified using multi-part paths:
Lust{
[[@a.1.foo:child]],
child = [[$. child]],
}:gen{ a={ { foo="hello" } } } -- res: "hello child" -- subtemplates can be specified inline using @{{ }}:
Lust([[@foo.bar:{{$1 $2}}]]):gen{ foo={ bar={ "hello", "world" } } } -- res: "hello world" -- environments can also be specified dynamically
-- the @{ } construction is similar to Lua table construction
Lust([[@{ ., greeting="hello" }:{{$greeting $1.place}}]]):gen{ place="world" } -- res: "hello world"
Lust([[@{ "hello", a.b.place }:{{$1 $2}}]]):gen{ a = { b = { place="world" } } } -- res: "hello world"
Lust([[@{ 1, place=a.b }:{{$1 $place.1}}]]):gen{ "hello", a = { b = { "world" } } } -- res: "hello world" -- dynamic environments can contain arrays:
Lust([[@{ args=["hello", a.b] }:{{$args.1 $args.2.1}}]]):gen{ a = { b = { "world" } } } -- res: "hello world" -- dynamic environments can contain subtemplate applications:
Lust{
[[@{ .:child, a=x:child.grandchild }:{{$1, $a}}]],
child = "$1 to child",
["child.grandchild"] = "$1 to grandchild",
}:gen{ "hi", x = { "hello" } } -- res: "hi to child, hello to grandchild" -- dynamic environments can be nested:
Lust{
[[@{ { "hello" }, foo={ bar="world" } }:sub]],
sub = [[$1.1 $foo.bar]],
}:gen{} -- res: "hello world" ConditionsThe @if condition takes a boolean expression and applies a template or value if it evaluates to true. If there is a corresponding else template/value, then it will be applied if the expression evaluates to false -- conditional templates have a conditional test followed by a template application
-- @if(x) tests for the existence of x in the model
local temp = Lust{
[[@if(x)<greet>]],
greet = "hello",
}
temp:gen{ x=1 } -- res: "hello"
temp:gen{ } -- res: "" -- @if(?(x)) evaluates x in the model, and then checks if the result is a valid template name
-- this example also demonstrates using dynamically evalutated template application:
local temp = Lust{
[[@if(?(op))<(op)>]],
child = "I am a child",
}
temp:gen{ op="child" } -- res: "I am a child" -- using else and inline templates:
local temp = Lust[[@if(x)<{{hello}}>else<{{bye bye}}>]]
temp:gen{ x=1 } -- res: "hello"
temp:gen{ } -- res: "bye bye" -- @if(#x > n) tests that the number of items in the model term 'x' is greater than n:
local temp = Lust[[@if(#. > "0")<{{at least one}}>]]
temp:gen{ "a" } -- res: "at least one")
temp:gen{ } -- res: "" -- compound conditions:
local temp = Lust[[@if(#x > "0" and #x < "5")<{{success}}>]]
temp:gen{ x={ "a", "b", "c", "d" } } -- res: "success"
temp:gen{ x={ "a", "b", "c", "d", "e" } } -- res: ""
temp:gen{ x={ } } -- res: ""
temp:gen{ } -- res: "" -- compound conditions:
local temp = Lust[[@if(x or not not not y)<{{success}}>else<{{fail}}>]]
temp:gen{ x=1 } -- res: "success"
temp:gen{ x=1, y=1 } -- res: "success"
temp:gen{ y=1 } -- res: "fail"
temp:gen{ } -- res: "success" -- compound conditions:
local temp = Lust[[@if(n*"2"+"1" > #x)<{{success}}>else<{{fail}}>]]
temp:gen{ n=3, x = { "a", "b", "c" } } -- res: "success"
temp:gen{ n=1, x = { "a", "b", "c" } } -- res: "fail" IterationLust has two main methods for creating iteration statements: a map function and numeric iteration. For the @map function, there are a variety of ways that it can be called depdening on the situation -- @map can iterate over arrays in the environment:
local temp = Lust[[@map{ n=numbers }:{{$n.name }}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
}
}
-- result: "one two three " -- assigning mapped values a name in the environment
local temp = Lust[[@map{ n=numbers }:{{$n }}]]
temp:gen{
numbers = { "one", "two", "three" }
}
-- result: "one two three " -- the _separator field can be used to insert elements between items:
local temp = Lust[[@map{ n=numbers, _separator=", " }:{{$n.name}}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
}
}
-- result: "one, two, three" -- _ can be used as a shorthand for _separator:
local temp = Lust[[@map{ n=numbers, _=", " }:{{$n.name}}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
}
}
-- result: "one, two, three" -- a map can iterate over multiple arrays in parallel
local temp = Lust[[@map{ a=letters, n=numbers, _=", " }:{{$a $n.name}}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
},
letters = {
"a", "b", "c",
}
}
-- res: "a one, b two, c three" -- if parallel mapped items have different lengths, the longest is used:
local temp = Lust[[@map{ a=letters, n=numbers, _=", " }:{{$a $n.name}}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
},
letters = {
"a", "b", "c", "d",
}
}
-- res: "a one, b two, c three, d " -- if parallel mapped items are not arrays, they are repeated each time:
local temp = Lust[[@map{ a=letters, n=numbers, prefix="hello", count=#letters, _=", " }:{{$prefix $a $n.name of $count}}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
},
letters = {
"a", "b", "c", "d",
}
}
-- res: "hello a one of 4, hello b two of 4, hello c three of 4, hello d of 4" -- the 'i1' and 'i0' fields are added automatically for one- and zero-based array indices:
local temp = Lust[[@map{ n=numbers }:{{$i0-$i1 $n.name }}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
}
}
-- res: "0-1 one 1-2 two 2-3 three " -- if the map only contains an un-named array, each item of the array becomes the environment applied in each iteration:
local temp = Lust[["@map{ ., _separator='", "' }:{{$name}}"]]
temp:gen{
{ name="one" },
{ name="two" },
{ name="three" },
}
-- res: '"one", "two", "three"'
local temp = Lust[[@map{ numbers, count=#numbers, _separator=", " }:{{$name of $count}}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
}
}
-- res: "one of 3, two of 3, three of 3" -- @rest is like @map, but starts from the 2nd item:
local temp = Lust[[@rest{ a=letters, n=numbers, _separator=", " }:{{$a $n.name}}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
},
letters = {
"a", "b", "c",
}
}
-- res: "b two, c three" -- @iter can be used for an explicit number of repetitions:
local temp = Lust[[@iter{ "3" }:{{repeat $i1 }}]]
temp:gen{} -- res: "repeat 1 repeat 2 repeat 3 " -- again, _separator works:
local temp = Lust[[@iter{ "3", _separator=", " }:{{repeat $i1}}]]
temp:gen{} -- res: "repeat 1, repeat 2, repeat 3" -- @iter can take an array item; it will use the length of that item:
local temp = Lust[[@iter{ numbers, _separator=", " }:{{repeat $i1}}]]
temp:gen{
numbers = {
{ name="one" },
{ name="two" },
{ name="three" },
}
}
-- res: "repeat 1, repeat 2, repeat 3"
全部评论
专题导读
上一篇:kikito/cron.lua: Time-related functions for Lua, inspired in javascript's se ...发布时间:2022-08-16下一篇:Originns/luamenus: 160+ Lua Menus for FiveM发布时间:2022-08-16热门推荐
热门话题
阅读排行榜
|
请发表评论