Parse the text according to makrell rules and put the result in $text.
require 'makrell.inc.php'; $m = new Makrell; $text = $m->parse($some_text);
Parse the text in a file and echo the result.
require 'makrell.inc.php'; $m = new Makrell; echo $m->parse_file('/path/to/file');
Parse the text in a file, execute the result as php code and echo the ouput. Here, 'user_name' is a "template variable" (only visible within the template).
require 'makrell.inc.php'; $m = new Makrell; $m->set('user_name', 'Linda'); echo $m->render('/path/to/file');
Besides that, there are a couple of utility classes that can be used to build generic regexp-based parsers. For example, here's a simple but working BB code parser.
class BBParser extends PregParser { function parse($text) { $this->clip = new PregClipboard; $text = $this->kfun($text, array( '~\[code\](.+?)\[/code\]~si' => '.code', '~\[(/?(b|i|u))\]~i' => '.tag')); return $this->clip->paste(htmlspecialchars($text)); } function code($m) { return $this->clip->copy('<code>' . htmlspecialchars($m[1]) . '</code>'); } function tag($m) { return $this->clip->copy('<' . $m[1] . '>'); } } $input = " [b]bold[/b] and [i]italic[/i] <script src=evil.js> [code] x = a[i] > a[b] [/code] "; $p = new BBParser; echo $p->parse($input);
ok {{ body }}
ok {{ body }}
ok {{ body }} BAD {{ body }}
ok {{
more
lines
}}
ok {{{{{{ weird }}}}}}
BAD
{{ foo }}
Each time makrell encounters a macro key somewhere in the text, it is replaced with the body. This is called macro expansion.
name {{ Linda }} <---- definition
Hi, name! <---- expansion
// Hi, Linda! <---- result
Keys don't have to be identifiers or be in any fixed format.
<main> {{ <h1> }}
... {{ … }}
50% {{ a half }}
Macro replacements are always global, that is, macro key is expanded even if its definition is textually below it. If there are two or more macro definitions with the same key, the textually later one overrides the earlier one.
bold(@text) {{ <b>@text</b> }}
bold(foo) bold(bar)
// Result:
// <b>foo</b> <b>bar</b>
Parameters can be placed anywhere in the macro and there is no rules on how they should be delimited. makrell performs a "non-greedy" search, that is, a parameter matches as little symbols as possible to make the whole macro match. Examples:
--@text {{ <h2>@text</h2> }}
--Hi there
// Result:
// <h2>Hi there</h2>
list @x,@y,@z {{
- @x
- @y
- @z
}}
list foo,bar,baz
// Result:
// - foo
// - bar
// - baz
compare @a to @b {{ strcmp("@b", "@a") }}
compare apples to oranges
// Result:
// strcmp("oranges", "apples")
If none or too few parameters are given, the macro is not expanded and copied literally to the output.
pair @a @b {{ [@a @b] }}
pair 10 20
pair foobar
// Result:
// [10 20]
// pair foobar
int - integer string - php string (in single or double quotes, with escaping) id - php identifier alpha - only letters alnum - only letters or numbers ns - non-whitespace nobr - anything except linebreak br - linebreaks any - anything
In the following example, the first string in parenthesis is expanded because it matches the definition (identifier required). The second string doesn't match and is left as is.
(@var:id) {{ <? echo $@var; ?> }}
(count) (just some text)
// Result:
// <?php echo $count; ?> (just some text)
foo {{
A
bar {{ xyz }}
B
}}
This defines two macros "bar" (with the body "xyz") and "foo" (whose body would be "A B" because the parser replaces macro definitions with empty strings).
Inner macros are normally parsed first, but you can change this by giving an outer macro more priority. Macro priority is designated by the number of braces around the body - the more braces are used, the higher is the priority. With nesting and priority you can define dynamic macros, i.e. the macros whose definitions are generated on the fly by expanding other macros.
design in @color {{{
h1_@color(@text) {{ <h1 style='color:@color'>@text</h1> }}
span_@color(@text) {{ <span style='color:@color'>@text</span> }}
}}}
// The following will generate a series of macros h1_red(@text), span_red(@text) etc.
design in red
Dynamic macros even allow you to change basic makrell syntax (braces) for your own taste:
<macro name="@key">@body:any</macro> {{{ @key {{@body}} }}} // from now on, macros can be defined like this <macro name="name">Linda</macro>
{{ include file }} - replaces the command with the content of the file
{{ quote text }} - ignores makrell rules in the text
{{ type name regexp }} - defines a new parameter type
Examples:
{{ include foobar }}
{{ quote
This text should be preserved as is.
Please no macro processing here.
}}
{{ type url www\.[\w\/.?&#]+ }}
New commands can be easily added by extending Makrell class.
class MyMakrell extends Makrell { function command_up($body) { return strtoupper($body); } } ... {{ up ibm }} // Result: IBM
It's important to understand that commands are executed when the template is being parsed ("at compile time"), not when it's being evaluated ("run time").
If there is no verb or it is unknown, the whole command is ignored. You can use this to comment out chunks of text.
{{ this will be ignored
(as long as there is no method command_this defined)
}}
{{* this will be always ignored }}
// file: hello
sayhello {{ <h1>hello_text</h1> }}
Here, "hello_text" has no definition, that is, it's just a placeholder. Once we define it
// file: german
{{ include hello }}
hello_text {{ Willkommen }}
the result of "sayhello" changes, although we haven't change the base file directly.
{{ include german }}
sayhello
// Result: <h1>Willkommen</h1>
To continue the analogy with a progamming language, in this example "hello_text" is a virtual method, and "german" is a class that extends the base "hello".
Template virtualization provides an easy way of building complex structures using step-by-step "refinements".
// file: website
<title>the_title</title>
<body>the_content</body>
// file: company
{{ include website }}
the_title {{ Company: company_subtitle }}
the_content {{
<h1>Company</h1>
company_content
}}
// file: company-about
{{ include company }}
company_subtitle {{ About us }}
company_content {{
<h2>About us</h2>
Hi there!
}}
Each file "extends" its parent file and provides more and more specific content to it, but the basic structure remains the same for all files.
1.5.5