From notifications-return-5981-archive-asf-public=cust-asf.ponee.io@freemarker.apache.org Sun Aug 4 17:08:42 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [207.244.88.153]) by mx-eu-01.ponee.io (Postfix) with SMTP id C750B180181 for ; Sun, 4 Aug 2019 19:08:41 +0200 (CEST) Received: (qmail 52239 invoked by uid 500); 4 Aug 2019 17:08:41 -0000 Mailing-List: contact notifications-help@freemarker.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@freemarker.apache.org Delivered-To: mailing list notifications@freemarker.apache.org Received: (qmail 52227 invoked by uid 99); 4 Aug 2019 17:08:41 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 04 Aug 2019 17:08:41 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id DA23B85EDD; Sun, 4 Aug 2019 17:08:40 +0000 (UTC) Date: Sun, 04 Aug 2019 17:08:40 +0000 To: "notifications@freemarker.apache.org" Subject: [freemarker] branch 2.3-gae updated: Added more information to the Manual, related to local lambdas and related built-ins. Some clarifications. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <156493852078.3665.7684948459825095590@gitbox.apache.org> From: ddekany@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: freemarker X-Git-Refname: refs/heads/2.3-gae X-Git-Reftype: branch X-Git-Oldrev: 56249c0109f3f183d17fe78a30cb8562a6a4778e X-Git-Newrev: 070d8694d5df241abe5504f6dd8c24a5ca792f43 X-Git-Rev: 070d8694d5df241abe5504f6dd8c24a5ca792f43 X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated This is an automated email from the ASF dual-hosted git repository. ddekany pushed a commit to branch 2.3-gae in repository https://gitbox.apache.org/repos/asf/freemarker.git The following commit(s) were added to refs/heads/2.3-gae by this push: new 070d869 Added more information to the Manual, related to local lambdas and related built-ins. Some clarifications. 070d869 is described below commit 070d8694d5df241abe5504f6dd8c24a5ca792f43 Author: ddekany AuthorDate: Sun Aug 4 19:08:26 2019 +0200 Added more information to the Manual, related to local lambdas and related built-ins. Some clarifications. --- src/manual/en_US/book.xml | 222 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 189 insertions(+), 33 deletions(-) diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml index bafa8af..fda828d 100644 --- a/src/manual/en_US/book.xml +++ b/src/manual/en_US/book.xml @@ -848,6 +848,14 @@ All Rights Reserved. true of false depending on if user starts with the letter J or not. + + + animals?filter(it -> it.protected) + gives the list of protected animals. To list protected animals + only, you could use <#list animals?filter(it -> + it.protected) as + animal>...</#list>. + Built-in applications can be chained, like @@ -3828,7 +3836,7 @@ Jerry If you have a composite expression after the !, like 1 + x, - always use parenthesses, like + always use parentheses, like ${x!(1 + y)} or ${(x!1) + y)}, depending on which interpretation you meant. That's needed because due to a programming mistake in FreeMarker @@ -4034,6 +4042,26 @@ Creating mouse... before the enclosing variable scope is ended. Hence, and to differentiate them from real lambdas, these are called local lambdas. + + The syntax of lambdas is like + (name1, + name2, ..., + nameN) -> + expression. If there's only a + single argument, the parentheses can be omitted: + name1 -> + expression. + + As the right side of the -> is just a + single expression, if you need complex logic there, you probably + want to move that into a function, as the you can use + directives like if, list, etc. + In that case though, you don't need a lambda expression, as all + built-ins that support a lambda parameter, also support passing in a + function directly. For example, instead of seq?map(x -> + myMapper(x)) you should just write + seq?map(myMapper).
@@ -17033,9 +17061,11 @@ N drop while - Filters out elements that match the parameter condition - (predicate), and stops filtering out elements with the first element - that does not match the condition. See the Returns a new sequence that contains the elements fro the + input sequence starting with from the first element that does + not match the parameter predicate (condition). + After that, all elements are included, regardless if they match the + predicate or not. See the filter built-in for more details about parameters, and other details, but note that the condition in filter @@ -17062,6 +17092,10 @@ Filer for positives: match the predicate (x > 0). On the other hand, filter keeps the elements that match the same predicate, and it doesn't stop. + + See also: take_while + built-in
@@ -17081,8 +17115,9 @@ Filer for positives: This built-in is available since 2.3.29 - This built-in only keeps elements from a sequence that match - the parameter condition (predicate). For example: + Returns a new sequence that only contains the elements for + which the parameter condition (the predicate) returns + true. For example: <#assign xs = [1, -2, 3, 4, -5]> Positives: @@ -17095,9 +17130,9 @@ Negatives: Negatives: -2 -5 - This built-in has a single required parameter, which specifies - the filter condition (what to keep). The filter condition can be - specified in 3 ways: + This built-in has a single required parameter, the predicate + (filter condition, what to keep). The predicate can be specified in + 3 ways: @@ -17120,10 +17155,11 @@ Negatives: - A function - or method that has a single argument, and returns boolean. For - example, the Negatives example above could be - implemented like this: + As a function or method that + has a single argument, and returns boolean. For example, the + Negatives example above could be implemented like + this: <#function negative(x)> <#return x < 0> @@ -17541,11 +17577,29 @@ red, green, blue. map built-in - [TODO] + + sequence + + filter + + + Returns an new sequence where all elements are replaced with + the result of the parameter lambda, function, or method. For + example, you have a list of user objects in + users, but instead you need a list of user names + in variable, then you could do this: + + <#assign userNames = users?map(user -> user.name)> + + The parameter work like the parameter of the with filter + built-in (so see there), except that the + lambda/function/method you specify can return values of any + type. Regarding lazy evaluation, and handling of very long inputs, - it works on the same way - as with the works on the same + way as the filter built-in.
@@ -17908,12 +17962,11 @@ Sorted by name.last: take while - This is very similar to the filter - built-in, but it filters out all element starting with first - element that doesn't match the argument condition (predicate). See + Returns a sequence that only contains the elements of the + input sequence which are before the first element that doesn't match + the parameter predicate (filter condition). This is very similar to the filter - built-in for more details. + built-in, so see further details there. Example and comparison with filter: @@ -17935,6 +17988,10 @@ Filer for positives: the first number that didn't match the predicate (x > 0), while filter has continued finding further matches.
+ + See also: drop_while + built-in @@ -21611,9 +21668,9 @@ All rights reserved. Part repeated for each key-value pair </#list> - But these are just cases of the generic forms, which are shown - below. Note that for simplicity we only show the generic forms for - sequence listing; simply replace as + But these are just special cases of the generic forms, which + are shown below. Note that for simplicity we only show the generic + forms for sequence listing; simply replace as item with as key, value to get the @@ -21926,6 +21983,16 @@ All rights reserved. break directive + + break is deprecated for most use cases, + as it doesn't work well with <#sep> and + item?has_next. + Instead, use sequence?take_while(predicate) + to cut the sequence before you list it. See also examples here. + + You can exit the iteration at any point with the break directive. For example: @@ -21966,10 +22033,11 @@ All rights reserved. break-able directive. Using break together with - sep is generally a bad idea, as - sep can't know if you will skip the rest of - items with break, and then you end up with a - separator after the item printed last. + sep or ?has_next is + generally a bad idea, as these can't know if you will skip the + rest of items with a break. To solve such + situations see these + examples. Just like else and items, break must be @@ -21987,8 +22055,22 @@ All rights reserved. + continue is deprecated for most use + cases, as it doesn't work well with + <#sep>, + item?has_next, + item?count, + item?index, + item?item_parity, + etc. Instead, use sequence?filter(predicate) + to remove unwanted elements. See also examples here. + + + The continue directive exists since - FreeMarker 2.3.27 + FreeMarker 2.3.27. You can skip the rest of the iteration body (the section @@ -22026,10 +22108,12 @@ All rights reserved. When you call continue, the sep directive will not be executed for that iteration. Using continue together with - sep is generally a bad idea, as - sep can't know if you will skip the rest of the - items, and then you end up with a separator after the item printed - last. + sep is generally a bad idea anyway, also + ?has_next, ?count, + ?index, ?item_parity, etc. + will not work as you certainly wanted if you completely skip + items. To solve such situations see these examples. Just like break, continue must be literally inside body of the @@ -22104,6 +22188,78 @@ All rights reserved. 1}. +
+ Skipping items conditionally + + If you need to skip certain element in a list, it's + generally a bad idea to use if directive + for that, because then <#sep>, + item?has_next, + item?count, + item?index, + item?item_parity, + etc., will not be usable, as FreeMarker doesn't know what items + were and will be actually displayed. Instead, you should try to + remove the unwanted items from the sequence that you will list, + and then list it (since 2.3.29). Here are some typical examples + with and without if. + + + Filtering + + In this example, you want to show the recommended products + from products. Here's the wrong solution with + if: + + <#-- WRONG solution! The row parity classes will be possibly messed up: --> +<#list products as product> + <#if product.recommended> + <div class="${product?item_parity}Row">${product.name}</div> + </#if> +</#list> + + Here's the good solution that uses the filter + built-in: + + <#-- Good solution: --> +<#list products?filter(p -> p.recommended) as product> + <div class="${product?item_parity}Row">${product.name}</div> +</#list> + + + + Stop listing when a certain element is found + + Let's say you have a list of lines in + lines, and you need to stop at the first + empty line (if there's any). Furthermore you need to + <br> between the elements. Here's the + wrong solution with if and + break: + + <#-- WRONG solution! <br> might be added after the last printed line: --> +<#list lines as line> + <#if line == ''> + <#break> + </#if> + ${line}<#sep><br> +</#list> + + Here's the good solution that uses the take_while + built-in (note that the condition is inverted compared to + the if+break + solution): + + <#-- Good solution: --> +<#list lines?take_while(line -> line != '') as line> + ${line}<#sep><br> +</#list> + +
+
Nesting loops into each other