Templa...Method(3pm)

๐Ÿ“ฆ
version 1.022 ยท 6 versions
, in debian trixie, ubuntu resolute, ubuntu stonking

๐Ÿ’– Template::Alloy::VMethod โ€” the VMethod role ๐Ÿ’–

welcome to Templa...Method(3pm), bestie!! this is from the User Contributed Perl Documentation corner of the universe and it's literally the page that explains where all the extra sparkle in Template::Alloy comes from. part 1 of 2, so don't go anywhere ๐ŸŒธ


โœจ NAME โœจ

Template::Alloy::VMethod โ€” it's the VMethod role. that's the whole name. short. iconic. ๐Ÿ’…


๐ŸŒˆ DESCRIPTION ๐ŸŒˆ

okay so the Template::Alloy::VMethod role is the โœจglow-upโœจ layer โ€” it hands you all the extra vmethods, filters, and virtual objects that get stacked on top of Template::Alloy's base feature set. think of it as the accessories drawer for your template engine ๐ŸŽ€

most of the vmethods listed here are basically the same ones Template::Toolkit gives you. the goal is to keep Template::Alloy's versions in sync with TT's. fr fr, they're trying ๐Ÿ’ช

and because one engine can never have enough side quests, Template::Alloy also ships several extra methods that are needed for HTML::Template::Expr support. slay.


๐Ÿซถ ROLE METHODS ๐Ÿซถ

  • define_vmethod โ€” defines a vmethod. if you want the full tea, go read Template::Alloy for more details. that's where the deep lore lives ๐Ÿ“–
  • vmethod_* โ€” methods with names like this implement the virtual methods that are too complex to be one-liners. heads up though: these are not exposed via the role. they're backstage crew, not main characters ๐Ÿ™ˆ
  • filter_* โ€” same vibe, different job: methods named like this implement filters that are more complex than one liners. also not exposed via the role. internal business only, iykyk ๐Ÿ’€

๐Ÿ‘‘ VIRTUAL METHOD LIST ๐Ÿ‘‘

here's the whole menu, bestie โ€” the builtin virtual methods and filters you can call on each type of data ๐Ÿ“

so in Template::Alloy, the | operator can be used to call virtual methods exactly the same way the . operator can. same energy, different punctuation โœจ

the one big difference: when you're accessing hashrefs or objects, the | means "always call the virtual method or filter" rather than peeking inside the hashref for a key with that name, or trying to call that method on the object. no sneaky lookups, no substitutions. this is similar to how TT3 will function ๐Ÿ”ฎ

virtual methods are also made available via Virtual Objects, which get discussed in a later section. stay tuned ๐ŸŽ€


๐ŸŒธ SCALAR VIRTUAL METHODS AND FILTERS ๐ŸŒธ

this is the list of builtin virtual methods and filters you can call on scalar data types ๐Ÿ’–

in Alloy and TT3, filters and virtual methods are way more closely related than they are in TT2. in general, anywhere a virtual method can be used, a filter can be used too โ€” and likewise, all scalar virtual methods can be used as filters. it's giving flexible ๐ŸŒˆ

on top of the filters listed below, Alloy will automatically load Template::Filters and use them if Template::Toolkit is installed. free extras, no cap ๐ŸŽ

and on top of the scalar virtual methods: any scalar will be automatically converted to a single item list if a list virtual method gets called on it. surprise promotion โœจ

scalar virtual methods are also available through the Text virtual object โ€” except for true filters such as eval and redirect. those two don't get to hang out there ๐Ÿ™…โ€โ™€๏ธ

oh and all scalar virtual methods are available as top level functions as well. that is not true of TT2, so don't get it twisted. in Template::Alloy these two are equivalent:

[% "abc".length %]
[% length("abc") %]

if you want to turn that behavior off, you may set VMETHOD_FUNCTIONS to 0. your call bestie ๐Ÿ’…


๐Ÿ“ '0' ๐Ÿ“

[% item = 'foo' %][% item.0 %]

Returns foo.

allows for scalars to mask as arrays โ€” and yeah, scalars already will, but this lets you get more direct access. handy ๐Ÿ’–

not available in TT.

๐Ÿ“ abs ๐Ÿ“

[% -1.abs %]

Returns the absolute value. no negatives allowed on this page, only good vibes โœจ


๐Ÿ“ atan2 ๐Ÿ“

[% pi = 4 * 1.atan2(1) %]

Returns the arctangent. the item itself represents Y, and the passed argument represents X. math but make it cute ๐Ÿ“

not available in TT โ€” but it is available in HTML::Template::Expr.

๐Ÿ“ chunk ๐Ÿ“

[% item.chunk(60).join("\n") %]

Split the string up into a list of chunks of text, 60 chars wide. chopping it into snackable pieces ๐Ÿซ


๐Ÿ“ collapse ๐Ÿ“

[% item.collapse %]

Strip leading and trailing whitespace, and collapse all other space to one space. tidy queen behavior ๐Ÿงน


๐Ÿ“ cos ๐Ÿ“

[% item.cos %]

Returns the cosine of the item. trigonometry said periodt ๐Ÿ“

not available in TT โ€” but it is available in HTML::Template::Expr.

๐Ÿ“ defined ๐Ÿ“

[% item.defined %]

Always true โ€” because the undef sub translates all undefs to ''. so like, everything is defined now, we don't do undefined here ๐Ÿ’…


๐Ÿ“ eval ๐Ÿ“

[% item.eval %]

Process the string as though it was a template โœจ this will start the parsing engine and will use the same configuration as the current process. Alloy is several times faster at doing this than TT is, and it's considered acceptable. we love a speed demon ๐Ÿ”ฅ

this is a filter and is not available via the Text virtual object.

Template::Alloy has attempted to make the compile process painless and fast. by default an MD5 sum of evaled is taken and used to cache the AST. you can turn that behavior off using the CACHE_STR_REFS configuration item.

Template::Alloy also allows for named parameters to be passed to the eval filter ๐ŸŽ€

[% '[% 1 + 2 %]'.eval %]

[% '${ 1 + 2 }'.eval(interpolate => 1) %]

[% "#get( 1 + 2)"|eval(syntax => 'velocity') %]

[% '<TMPL_VAR EXPR="1 + 2">'.eval(syntax => 'hte') %]

[% '<TMPL_VAR EXPR="1 + 2">'.eval(syntax => 'hte') %]

๐Ÿ“ evaltt ๐Ÿ“

Same as the eval filter. literally the same. twin energy ๐Ÿ‘ฏโ€โ™€๏ธ


๐Ÿ“ exp ๐Ÿ“

[% 1.exp %]

Something like 2.71828182845905 ๐ŸŒธ

returns "e" to the power of the item. exponent realness โœจ


๐Ÿ“ file ๐Ÿ“

Same as the redirect filter. two names, one job ๐Ÿ’…


๐Ÿ“ fmt ๐Ÿ“

[% item.fmt('%d') %]
[% item.fmt('%6s') %]
[% item.fmt('%*s', 6) %]

Similar to format. returns a string formatted with the passed pattern. the default pattern is %s. this is the opposite of the sprintf vmethod ๐Ÿ‘€


๐Ÿ“ format ๐Ÿ“

[% item.format('%d') %]
[% item.format('%6s') %]
[% item.format('%*s', 6) %]

Print the string out in the specified format. it's similar to the fmt virtual method โ€” except that the item is split on newline and each line is processed separately. line by line, one at a time, very thorough ๐ŸŽ€


๐Ÿ“ hash ๐Ÿ“

[% item.hash %]

Returns a one item hash with a key of "value" and a value of the item. tiny hash, big heart ๐Ÿ’–


๐Ÿ“ hex ๐Ÿ“

[% "FF".hex %]

Returns the decimal value of the passed hex numbers. also note that you may just use [% 0xFF %] instead. shortcuts are valid โœจ

not available in TT โ€” but it is available in HTML::Template::Expr.

๐Ÿ“ html ๐Ÿ“

[% item.html %]

Performs a very basic html encoding โ€” it swaps out &, <, > and " with the corresponding html entities ๐ŸŒˆ

previously it also encoded the ', but that behavior did not match TT2's behavior. so if you want that behavior back, use .xml instead. we don't do legacy encoding here ๐Ÿ’…


๐Ÿ“ indent ๐Ÿ“

[% item.indent(3) %]

Indent by that number of spaces if an integer is passed โ€” the default is 4 โœจ

[% item.indent("Foo: ") %]

Add the string "Foo: " to the beginning of every line. cute prefix energy ๐ŸŽ€


๐Ÿ“ int ๐Ÿ“

[% item.int %]

Return the integer portion of the value โ€” and it's 0 if there is none. no decimals allowed on this one โœจ


๐Ÿ“ json ๐Ÿ“

[% item.json    %]

Returns a JSON encoded representation.

[% item.json(1) %]

Returns a pretty JSON encoded representation. yes, the 1 is the glow-up โœจ


๐Ÿ“ lc ๐Ÿ“

Same as the lower vmethod. returns the lowercased version of the item. lowercase era ๐Ÿซถ


๐Ÿ“ lcfirst ๐Ÿ“

[% item.lcfirst %]

Lowercase the leading letter. just the one. the rest stays exactly how it is ๐Ÿ’…


๐Ÿ“ length ๐Ÿ“

[% item.length %]

Return the length of the string. how many characters, bestie ๐Ÿ“


๐Ÿ“ list ๐Ÿ“

[% item.list %]

Returns a list (arrayref) with a single value โ€” that value being the item. one item, but make it a list ๐ŸŒธ


๐Ÿ“ log ๐Ÿ“

[% 8.exp.log %]

Equal to 8 ๐ŸŽ€

returns the natural log base "e" of the item.

not available in TT โ€” but it is available in HTML::Template::Expr.

๐Ÿ“ lower ๐Ÿ“

[% item.lower %]

Return the string lowercased. down bad for lowercase fr fr โœจ


๐Ÿ“ match ๐Ÿ“

[% item.match("(\w+) (\w+)") %]

Return a list of items matching the pattern.

[% item.match("(\w+) (\w+)", 1) %]

Same as before โ€” but match globally ๐ŸŒ

in Template::Alloy and TT3 you can use regular expressions notation as well:

[% item.match( /(\w+) (\w+)/ ) %]

Same as before.

[% item.match( m{(\w+) (\w+)} ) %]

Same as before.

heads up: you can't use the 'g' regex modifier here โ€” you must pass the second argument to turn on global match. that's the rule ๐Ÿ’…

๐Ÿ“ none ๐Ÿ“

Returns the item without modification. this was added as a compliment case for when the AUTO_FILTER configuration is specified ๐ŸŽ€

note that it must be called as a filter to bypass the application of the AUTO_FILTER.
[% item | none %]

Returns the item without modification. sneaky bypass unlocked ๐Ÿ”“


๐Ÿ“ null ๐Ÿ“

[% item.null %]

Return nothing. empty. void. gone ๐Ÿ’€

if the item contains a coderef it will still be executed, but the result would be ignored. so like, the work happens, you just don't get to see it ๐Ÿ™ˆ


๐Ÿ“ oct ๐Ÿ“

[% "377".oct %]

Returns the decimal value of the octal string.

on recent versions of perl you may also pass numbers starting with 0x which will be interpreted as hexadecimal, and starting with 0b which will be interpreted as binary. glow-up on the parsing rules โœจ

not available in TT โ€” but it is available in HTML::Template::Expr.

๐Ÿ“ rand ๐Ÿ“

[% item = 10; item.rand %]

Returns a number greater or equal to 0 but less than 10 ๐ŸŽฒ

[% 1.rand %]
note: this filter is not available as of TT2.15.

๐Ÿ“ remove ๐Ÿ“

[% item.remove("\s+") %]

Same as replace โ€” but it is global and replaces with nothing. it's giving delete key ๐Ÿ—‘๏ธ


๐Ÿ“ redirect ๐Ÿ“

[% item.redirect("output_file.html") %]

Writes the contents out to the specified file. the filename must be relative to the OUTPUT_PATH configuration variable, and the OUTPUT_PATH variable must be set. no path, no output, no cap ๐Ÿšจ

this is a filter and is not available via the Text virtual object.

๐Ÿ“ repeat ๐Ÿ“

[% item.repeat(3) %]

Repeat the item 3 times ๐Ÿ”

[% item.repeat(3, ' | ') %]

Repeat the item 3 times, separated with ' | '. cute little separators, we love to see it ๐ŸŽ€


๐Ÿ“ replace ๐Ÿ“

[% item.replace("\s+", "&nbsp;") %]

Globally replace all space with &nbsp; โœจ

[% item.replace("foo", "bar", 0) %]

Replace only the first instance of foo with bar.

[% item.replace("(\w+)", "($1)") %]

Surround all words with parenthesis.

in Template::Alloy and TT3 you may also use normal regular expression notation:

[% item.replace(/(\w+)/, "($1)") %]

Same as before.

heads up: you can't use the 'g' regex modifier โ€” global match is on by default. you must pass the third argument of false to turn global match off. ๐Ÿ’…

๐Ÿ“ return ๐Ÿ“

Returns the item from the inner most block, macro, or file. similar to the RETURN directive ๐Ÿซถ

[% item.return %]
[% RETURN item %]

same thing, two ways. pick your fighter ๐Ÿ’–


[% item.search("(\w+)") %]

Tests if the given pattern is in the string ๐Ÿ”

in Template::Alloy and TT3 you may also use normal regular expression notation:

[% item.search(/(\w+)/) %]

Same as before.


๐Ÿ“ sin ๐Ÿ“

[% item.sin %]

Returns the sine of the item. wave check ๐ŸŒŠ


๐Ÿ“ size ๐Ÿ“

[% item.size %]

Always returns 1. no matter what. it's committed to the bit ๐Ÿ’…


๐Ÿ“ split ๐Ÿ“

[% item.split %]

Returns an arrayref from the item split on " " โœจ

[% item.split("\s+") %]

Returns an arrayref from the item split on /\s+/.

[% item.split("\s+", 3) %]

Returns an arrayref from the item split on /\s+/, splitting until 3 elements are found.

in Template::Alloy and TT3 you may also use normal regular expression notation:

[% item.split( /\s+/, 3 ) %]

Same as before.


๐Ÿ“ sprintf ๐Ÿ“

[% item = "%d %d" %]
[% item.sprintf(7, 8) %]

Uses the pattern stored in self, and passes it to sprintf with the passed arguments. this is the opposite of the fmt vmethod ๐Ÿ”„


๐Ÿ“ sqrt ๐Ÿ“

[% item.sqrt %]

Returns the square root of the number. root math, rooted in math ๐ŸŒฑ


  • srand โ€” okay so this calls the perl srand function to set the internal random seed. This will affect future calls to the rand vmethod. ๐ŸŽฒ
  • stderr โ€” Print the item to the current STDERR handle. slay.
[% item.stderr %]
  • substr โ€” Returns a substring of item starting at i and going to the end of the string.
[% item.substr(i) %]

Returns a substring of item starting at i and going n characters.

[% item.substr(i, n) %]
  • trim โ€” Strips leading and trailing whitespace. bye bye, extra spaces.
[% item.trim %]
  • uc โ€” Same as the upper command. Returns uppercased string. LOUDER, bestie.
  • ucfirst โ€” Uppercase the leading letter. just the first one, main character energy.
[% item.ucfirst %]
  • upper โ€” Return the string uppercased. ALL CAPS VIBE.
[% item.upper %]
  • uri โ€” Perform a very basic URI encoding. basic but cute.
[% item.uri %]
  • url โ€” Perform a URI encoding - but some characters such as : and / are left intact. they're too iconic to encode.
[% item.url %]
  • xml โ€” Performs a very basic xml encoding (swaps out &, <, >, ' and " with the corresponding xml entities) entity era.
[% item.xml %]

โœจ LIST VIRTUAL METHODS โœจ

The following methods can be called on an arrayref type data structures (scalar types will automatically promote to a single element list and call these methods if needed):

Additionally, list virtual methods can be accessed via the List Virtual Object.

  • fmt โ€” Passed a pattern and an string to join on. Returns a string of the values of the list formatted with the passed pattern and joined with the passed string. Default pattern is %s and the default join string is a space. formatting? obsessed.
[% mylist.fmt('%s', ', ') %]
[% mylist.fmt('%6s', ', ') %]
[% mylist.fmt('%*s', ', ', 6) %]
  • first โ€” Returns a list of the first 3 items in the list. firsties!
[% mylist.first(3) %]
  • grep โ€” Returns a list of all items matching the pattern. filtering, but make it regex.
[% mylist.grep("^\w+\.\w+$") %]

In Template::Alloy and TT3 you may also use normal regular expression notation.

[% mylist.grep(/^\w+\.\w+$/) %]

Same as before.

[% mylist.grep(->(a){ a.foo.bar }
  • hash โ€” Returns a hashref with the array indexes as keys and the values as values. list to hash, glow up.
[% mylist.hash %]
  • join โ€” Joins on space.
[% mylist.join %]

Joins on the passed argument.

[% mylist.join(", ")
  • json โ€” Returns a JSON encoded representation.
[% mylist.json    %]

Returns a pretty JSON encoded representation. pretty print, because aesthetics.

[% mylist.json(1) %]
  • last โ€” Returns a list of the last 3 items in the list. the finale.
[% mylist.last(3) %]
  • list โ€” Returns a reference to the list. just the ref, no copy.
[% mylist.list %]
  • map (Not in TT2) โ€” Returns a list with the macro played on each item. transform era.
[% mylist.map(->{ this.upper }) %]

Same thing

[% mylist.map(->(a){ a.upper }) %]

The RETURN directive or return list, item, and hash vmethods allow for returning more interesting items.

[% [1..3].map(->(a){ [1..a].return }) %]
  • max โ€” Returns the last item in the array. the biggest, the best.
[% mylist.max %]
  • merge โ€” Returns a new list with all defined items from list2 added. merge, no cap.
[% mylist.merge(list2) %]
  • nsort โ€” Returns the numerically sorted items of the list. If the items are hashrefs, a key containing the field to sort on can be passed. numbers go brrr.
[% mylist.nsort %]
  • pop โ€” Removes and returns the last element from the arrayref (the stash is modified). bye last element.
[% mylist.pop %]
  • push โ€” Adds an element to the end of the arrayref (the stash is modified). append szn.
[% mylist.push(23) %]
  • pick โ€” Returns a random item from the list.
[% mylist.pick %]
[% ['a' .. 'z'].pick %]

An additional numeric argument is how many items to return.

[% ['a' .. 'z'].pick(8).join('') %]
Note: This filter is not available as of TT2.15. so if you're on TT2.15, bestie, it's giving missing.
  • return โ€” Returns the list from the inner most block, macro, or file. Similar to the RETURN directive.
[% mylist.return %]
[% RETURN mylist %]
  • reverse โ€” Returns the list in reverse order. backwards but make it fashion.
[% mylist.reverse %]
  • shift โ€” Removes and returns the first element of the arrayref (the stash is modified). bye first element.
[% mylist.shift %]
  • size โ€” Returns the number of elements in the array. count 'em.
[% mylist.size %]
  • slice โ€” Returns a list from the arrayref beginning at index i and continuing for n items. slice of the list, periodt.
[% mylist.slice(i, n) %]
  • sort โ€” Returns the alphabetically sorted items of the list. If the items are hashrefs, a key containing the field to sort on can be passed. alphabetical order, as you should.
[% mylist.sort %]
  • splice โ€” Removes items from array beginning at i and continuing for n items.
[% mylist.splice(i, n) %]

Same as before, but replaces removed items with the items from list2.

[% mylist.splice(i, n, list2) %]
  • unique โ€” Return a list of the unique items in the array. no duplicates, we don't do repeats.
[% mylist.unique %]
  • unshift โ€” Adds an item to the beginning of the arrayref. prepend, but make it Unix.
[% mylist.unshift(23) %]

๐Ÿ’– HASH VIRTUAL METHODS ๐Ÿ’–

The following methods can be called on hash type data structures:

Additionally, list virtual methods can be accessed via the Hash Virtual Object.

  • fmt โ€” Passed a pattern and an string to join on. Returns a string of the key/value pairs of the hash formatted with the passed pattern and joined with the passed string. Default pattern is "%s\t%s" and the default join string is a newline. formatting the hash, cute.
[% myhash.fmt('%s => %s', "\n") %]
[% myhash.fmt('%4s => %5s', "\n") %]
[% myhash.fmt('%*s => %*s', "\n", 4, 5) %]
  • defined โ€” Checks if a is defined in the hash. is it there? defined or not defined, that is the question.
[% myhash.defined('a') %]
  • delete โ€” Deletes the item from the hash. gone, deleted, no trace.
[% myhash.delete('a') %]

Unlink Perl the value is not returned. Multiple values may be passed and represent the keys to be deleted.

  • each โ€” Turns the contents of the hash into a list - subject to change as TT is changing the operations of each and list. evolving, as all things do.
[% myhash.each.join(", ") %]
  • exists โ€” Checks if a is in the hash. does it exist? vibe check.
[% myhash.exists('a') %]
  • hash โ€” Returns a reference to the hash. the ref, the whole ref, nothing but the ref.
[% myhash.hash %]
  • import โ€” Overlays the keys of hash2 over the keys of myhash. overlay, merge, slay.
[% myhash.import(hash2) %]
  • item โ€” Returns the hashes value for that key. gimme the value.
[% myhash.item(key) %]
  • items โ€” Returns a list of the key and values (flattened hash) flattened, like my emotional state during finals week.
[% myhash.items %]
  • json โ€” Returns a JSON encoded representation.
[% myhash.json    %]

Returns a pretty JSON encoded representation. pretty print, for the aesthetic.

[% myhash.json(1) %]
  • keys โ€” Returns an arrayref of the keys of the hash. all the keys, no values.
[% myhash.keys.join(', ') %]
  • list โ€” Returns an arrayref with the hash as a single value (subject to change). single value, for now.
[% myhash.list %]
  • pairs โ€” Returns an arrayref of hashrefs where each hash contains {key => $key, value => $value} for each value of the hash. key-value pairs, the dynamic duo.
[% myhash.pairs %]
  • nsort โ€” Returns a list of keys numerically sorted by the values. numbers, sorted, by value.
[% myhash.nsort.join(", ") %]
  • return โ€” Returns the hash from the inner most block, macro, or file. Similar to the RETURN directive.
[% myhash.return %]
[% RETURN myhash %]
  • size โ€” Returns the number of key/value pairs in the hash. how many pairs? count.
[% myhash.size %]
  • sort โ€” Returns a list of keys alphabetically sorted by the values. alphabetical, by values, iconic.
[% myhash.sort.join(", ")
  • values โ€” Returns an arrayref of the values of the hash. just the values, no keys attached.
[% myhash.values.join(', ') %]

๐ŸŒˆ VIRTUAL OBJECTS ๐ŸŒˆ

TT3 has a concept of Text, List, and Hash virtual objects which provide direct access to the scalar, list, and hash virtual methods. In the TT3 engine this will allow for more concise generated code. Because Alloy does not generated perl code to be executed later, Alloy provides for these virtual objects but does so as more of a namespace (using the methods does not provide a speed optimization in your template - just may help clarify things). so it's like a vibe namespace, not a speed boost.

[% a = "foo"; a.length %] => 3

[% a = "foo"; Text.length(a) %] => 3

[% a = Text.new("foo"); a.length %] => 3

[% a = [1 .. 30]; a.size %] => 30

[% a = [1 .. 30]; List.size(a) %] => 30

[% a = List.new(1 .. 30); a.size %] => 30

[% a = {a => 1, b => 2}; a.size %] => 2

[% a = {a => 1, b => 2}; Hash.size(a) %] => 2

[% a = Hash.new({a => 1, b => 2}); a.size %] => 2

[% a = Hash.new(a => 1, b => 2); a.size %] => 2

[% a = Hash.new(a = 1, b = 2); a.size %] => 2

[% a = Hash.new('a', 1, 'b', 2); a.size %] => 2

One limitation is that if you pass a key named "Text", "List", or "Hash" in your variable stash - the corresponding virtual object will be hidden. so don't name your variable "Text" unless you want to hide the Text object. iykyk.

Additionally, you can use all of the Virtual object methods with the pipe operator. pipe operator, for the aesthetic.

[% {a => 1, b => 2}
   | Hash.keys
   | List.join(", ") %] => a, b

Again, there aren't any speed optimizations to using the virtual objects in Alloy, but it can help clarify the intent in some cases. clarity is key, bestie.

Note: these aren't really objects. All of the "virtual objects" are references to the $SCALAR_OPS, $LIST_OPS, and $HASH_OPS hashes found in the $VOBJS hash of Template::Alloy. not objects, just refs. the more you know.

๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

Paul Seamons <paul@seamons.com> the legend himself.

๐Ÿ“œ LICENSE ๐Ÿ“œ

This module may be distributed under the same terms as Perl itself. same as Perl, slay.


and that's the tea โ˜• โ€” this page is from perl v5.38.2, dated 2024-03-07, and it's the Templa...Method(3pm) manpage. stay iconic, bestie. ๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from