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 f6b4de2c #switch #on PR post-merge adjustments: Finished Manual 
updates for #on. Minor test additions, and code cleanup.
f6b4de2c is described below

commit f6b4de2cb8856783d36c7638c4d5b3fe3ff8d44d
Author: ddekany <[email protected]>
AuthorDate: Mon Aug 19 11:53:36 2024 +0200

    #switch #on PR post-merge adjustments: Finished Manual updates for #on. 
Minor test additions, and code cleanup.
---
 .../src/main/java/freemarker/core/SwitchBlock.java |   2 +-
 .../core/BreakAndContinuePlacementTest.java        |   4 +-
 .../src/test/java/freemarker/core/SwitchTest.java  |  15 ++
 freemarker-manual/src/main/docgen/en_US/book.xml   | 166 ++++++++++++++++-----
 4 files changed, 144 insertions(+), 43 deletions(-)

diff --git a/freemarker-core/src/main/java/freemarker/core/SwitchBlock.java 
b/freemarker-core/src/main/java/freemarker/core/SwitchBlock.java
index 28cfec23..6c5641b8 100644
--- a/freemarker-core/src/main/java/freemarker/core/SwitchBlock.java
+++ b/freemarker-core/src/main/java/freemarker/core/SwitchBlock.java
@@ -112,7 +112,7 @@ final class SwitchBlock extends TemplateElement {
                 }
             } catch (BreakOrContinueException br) {
                 // This catches both break and continue, hence continue is 
incorrectly treated as a break inside a case.
-                // ("on", does have this bug.)
+                // ("on", doesn't have this bug.)
             }
         }
         return null;
diff --git 
a/freemarker-core/src/test/java/freemarker/core/BreakAndContinuePlacementTest.java
 
b/freemarker-core/src/test/java/freemarker/core/BreakAndContinuePlacementTest.java
index 769400cc..aad6ede4 100644
--- 
a/freemarker-core/src/test/java/freemarker/core/BreakAndContinuePlacementTest.java
+++ 
b/freemarker-core/src/test/java/freemarker/core/BreakAndContinuePlacementTest.java
@@ -50,8 +50,8 @@ public class BreakAndContinuePlacementTest extends 
TemplateTest {
         assertOutput("<#list 1..2 as x><#switch x><#on 
1>one<#continue></#switch>;</#list>", "one;");
         assertOutput("<#forEach x in 1..2>${x}<#break></#forEach>", "1");
         assertOutput("<#forEach x in 1..2>${x}<#continue></#forEach>", "12");
-        assertOutput("<#switch 1><#case 1>1<#break></#switch>", "1");
-        assertOutput("<#switch 1><#default>1<#break></#switch>", "1");
+        assertOutput("<#switch 1><#case 1>1<#break>unreachable</#switch>.", 
"1.");
+        assertOutput("<#switch 1><#default>1<#break>unreachable</#switch>.", 
"1.");
     }
 
     @Test
diff --git a/freemarker-core/src/test/java/freemarker/core/SwitchTest.java 
b/freemarker-core/src/test/java/freemarker/core/SwitchTest.java
index adf72388..c4a33787 100644
--- a/freemarker-core/src/test/java/freemarker/core/SwitchTest.java
+++ b/freemarker-core/src/test/java/freemarker/core/SwitchTest.java
@@ -165,6 +165,21 @@ public class SwitchTest extends TemplateTest {
                         + "]\n"
                         + "</#list>",
                 "[\nC1]\n[\nC2]\n[\nD]\n");
+        assertOutput(
+                ""
+                        + "<#list 1..3 as i>\n"
+                        + "[\n"  // <#----> is to avoid unrelated old 
white-space stripping bug
+                        + "  <#switch i>\n"
+                        + "    <#on 1>\n"
+                        + "      C1\n"
+                        + "    <#on 2>\n"
+                        + "      C2\n"
+                        + "    <#default>\n"
+                        + "      D\n"
+                        + "  </#switch>\n"
+                        + "]\n"
+                        + "</#list>",
+                "[\n      C1\n]\n[\n      C2\n]\n[\n      D\n]\n");
     }
 
 }
diff --git a/freemarker-manual/src/main/docgen/en_US/book.xml 
b/freemarker-manual/src/main/docgen/en_US/book.xml
index 12a032f0..ca4b302a 100644
--- a/freemarker-manual/src/main/docgen/en_US/book.xml
+++ b/freemarker-manual/src/main/docgen/en_US/book.xml
@@ -21199,6 +21199,10 @@ with_args_last:
             <para><link linkend="ref.directive.nt">nt</link></para>
           </listitem>
 
+          <listitem>
+            <para><link linkend="ref.directive.on">on</link></para>
+          </listitem>
+
           <listitem>
             <para><link
             linkend="ref_directive_outputformat">outputformat</link></para>
@@ -25181,12 +25185,14 @@ or
       </section>
 
       <section xml:id="ref_directive_switch">
-        <title>switch, case, default, break</title>
+        <title>switch, on, case, default, break</title>
 
         <anchor xml:id="ref.directive.switch"/>
 
         <anchor xml:id="ref.directive.case"/>
 
+        <anchor xml:id="ref.directive.on"/>
+
         <anchor xml:id="ref.directive.default"/>
 
         <anchor xml:id="ref.directive.switch.break"/>
@@ -25199,6 +25205,10 @@ or
           <primary>case directive</primary>
         </indexterm>
 
+        <indexterm>
+          <primary>on directive</primary>
+        </indexterm>
+
         <indexterm>
           <primary>default directive</primary>
         </indexterm>
@@ -25216,7 +25226,7 @@ or
 
           <programlisting role="metaTemplate"><literal>&lt;#switch 
<replaceable>value</replaceable>&gt;
   &lt;#on <replaceable>refValue1</replaceable>&gt;
-    <replaceable>... (Handles both refValue1)</replaceable>
+    <replaceable>... (Handles refValue1)</replaceable>
   &lt;#on <replaceable>refValue2, refValue3</replaceable>&gt;
     <replaceable>... (Handles both refValue2 and refValue3)</replaceable>)
   <replaceable>...</replaceable>
@@ -25231,7 +25241,7 @@ or
 
           <programlisting role="metaTemplate"><literal>&lt;#switch 
<replaceable>value</replaceable>&gt;
   &lt;#case <replaceable>refValue1</replaceable>&gt;
-    <replaceable>... (Handles both refValue1)</replaceable>
+    <replaceable>... (Handles refValue1)</replaceable>
     &lt;#break&gt;
   &lt;#case <replaceable>refValue2</replaceable>&gt;
   &lt;#case <replaceable>refValue3</replaceable>&gt;
@@ -25255,12 +25265,59 @@ or
             </listitem>
           </itemizedlist>
 
-          <para><literal>default</literal> is optional.
-          <literal>break</literal> is used with <literal>case</literal> to
-          prevent fall-through into the next <literal>case</literal>. When
-          <literal>on</literal> is used, <literal>break</literal> is not
-          allowed, except if the <literal>switch</literal> is inside something
-          that supports <literal>break</literal>.</para>
+          <para>Additional rules:</para>
+
+          <itemizedlist>
+            <listitem>
+              <para>A <literal>switch</literal> block either have
+              <literal>on</literal>-s, or <literal>case</literal>-s, but not
+              both.</para>
+            </listitem>
+
+            <listitem>
+              <para><literal>default</literal>: Optional, can occur at most
+              once. Must be after the <literal>on</literal>-s. There's no
+              ordering restriction when used with
+              <literal>case</literal>-s.</para>
+            </listitem>
+
+            <listitem>
+              <para><literal>break</literal>: </para>
+
+              <itemizedlist>
+                <listitem>
+                  <para>If the <literal>switch</literal> uses
+                  <literal>case</literal> then <literal>break</literal>
+                  immediately exits from the closes enclosing
+                  <literal>switch</literal>. This is used to prevent
+                  fall-through into the next <literal>case</literal>, or into
+                  the following (adjacent) <literal>default</literal>. (To be
+                  precise, <literal>break</literal> behaves as described if
+                  the <literal>switch</literal> doesn't contain
+                  <literal>on</literal>, and thus also if all it contains is a
+                  <literal>default</literal>.)</para>
+                </listitem>
+
+                <listitem>
+                  <para>If the <literal>switch</literal> uses
+                  <literal>on</literal> then <literal>break</literal> is not
+                  supported by <literal>switch</literal> directly, but
+                  naturally can be used when the <literal>switch</literal> is
+                  inside something else that supports <literal>break</literal>
+                  (like inside a <link
+                  linkend="ref.directive.list">list</link>).</para>
+                </listitem>
+
+                <listitem>
+                  <para>With <literal>case</literal>,
+                  <literal>continue</literal> does the same as
+                  <literal>break</literal>. This is an old bug that works for
+                  backward compatibility, but don't utilize it. With
+                  <literal>on</literal>, this is fixed.</para>
+                </listitem>
+              </itemizedlist>
+            </listitem>
+          </itemizedlist>
         </section>
 
         <section>
@@ -25276,45 +25333,72 @@ or
             instead. </para>
           </note>
 
-          <para>[TODO: Continue updating this for <literal>on</literal>
-          instead of <literal>case</literal>]</para>
-
           <para>Switch is used to choose a fragment of template depending on
-          the value of an expression:</para>
+          the value of an expression, and is a shorthand instead using <link
+          
linkend="ref.directive.if"><literal>if</literal>-<literal>elseif</literal>-<literal>else</literal></link>:</para>
+
+          <programlisting role="template">&lt;#switch animal.size&gt;
+  &lt;#on "small"&gt;
+     Processed if animal.size was "small" 
+  &lt;#on "medium"&gt;
+     Processed if animal.size was "medium" 
+  &lt;#on "large", "extra large"&gt;
+     Processed if animal.size was "large" or "extra large"
+  &lt;#default&gt;
+     Processed if animal.size is neither of the above
+&lt;/#switch&gt;</programlisting>
+
+          <para>Before FreeMarker 2.3.24, <literal>on</literal> wasn't
+          supported, only <literal>case</literal> (note the usage of
+          <literal>break</literal>, and the intentional omission of it after
+          <literal>&lt;#case "large"&gt;</literal>):</para>
 
           <programlisting role="template">&lt;#switch animal.size&gt;
   &lt;#case "small"&gt;
-     This will be processed if it is small
+     Processed if animal.size was "small" 
      &lt;#break&gt;
   &lt;#case "medium"&gt;
-     This will be processed if it is medium
+     Processed if animal.size was "medium" 
      &lt;#break&gt;
   &lt;#case "large"&gt;
-     This will be processed if it is large
+  &lt;#case "extra large"&gt;
+     Processed if animal.size was "large" or "extra large"
      &lt;#break&gt;
   &lt;#default&gt;
-     This will be processed if it is neither
+     Processed if animal.size is neither of the above
 &lt;/#switch&gt;</programlisting>
 
-          <para>Inside the <literal>switch</literal> must be one or more
-          <literal>&lt;#case <replaceable>value</replaceable>&gt;</literal>,
-          and after all such <literal>case</literal> tags optionally one
-          <literal>&lt;#default&gt;</literal>. When FM reaches the
-          <literal>switch</literal> directive, it chooses a
-          <literal>case</literal> directive where
+          <para>Above examples are basically equivalent with this:</para>
+
+          <programlisting role="template">&lt;#assign value = animal.size&gt;
+&lt;#if value == "small"&gt;
+   Processed if animal.size was "small" 
+&lt;#elseif value == "medium"&gt;
+   Processed if animal.size was "medium" 
+&lt;#elseif value == "large" || value == "extra large"&gt;
+   Processed if animal.size was "large" or "extra large"
+&lt;#else&gt;
+   Processed if animal.size is neither of the above
+&lt;/#if&gt;</programlisting>
+
+          <para>That is, when the <literal>switch</literal> directive is
+          processed, it chooses an <literal>on</literal> or
+          <literal>case</literal> directive where a
           <literal><replaceable>refValue</replaceable></literal> equals with
-          <literal><replaceable>value</replaceable></literal> and continues
+          <literal><replaceable>value</replaceable></literal>, and continues
           the processing of the template there. If there is no
-          <literal>case</literal> directive with appropriate value then it
-          continues processing at the <literal>default</literal> directive if
-          that exists, otherwise it continues the processing after the end-tag
-          of <literal>switch</literal>. And now comes the confusing thing:
-          when it has chosen a <literal>case</literal> directive, it will
-          continue the processing there, and will go ahead until it reaches a
-          <literal>break</literal> directive. That is, it will not
-          automatically leave the <literal>switch</literal> directive when it
-          reaches another <literal>case</literal> directive or the
-          <literal>&lt;#default&gt;</literal> tag. Example:</para>
+          <literal>on</literal> or <literal>case</literal> directive with
+          appropriate <literal><replaceable>refValue</replaceable></literal>,
+          then it continues processing at the <literal>default</literal>
+          directive, if that exists, otherwise it continues the processing
+          after the end-tag of <literal>switch</literal>.</para>
+
+          <para>Be careful with <literal>case</literal>'s fall-through
+          behavior! It means that after processing have jumped on the matching
+          <literal>case</literal>, it will not leave the
+          <literal>switch</literal> directive when it reaches another
+          <literal>case</literal> or <literal>default</literal>, only when it
+          reaches a <literal>break</literal>. Example:</para>
 
           <programlisting role="template">&lt;#switch x&gt;
   &lt;#case 1&gt;
@@ -25325,12 +25409,14 @@ or
     d
 &lt;/#switch&gt;</programlisting>
 
-          <para>If <literal>x</literal> is 1, then it will print 1 2 d; if
-          <literal>x</literal> is 2 then it will print 2 d; if
-          <literal>x</literal> is 3 then it will print d. This is the
-          mentioned fall-through behavior. The <literal>break</literal> tag
-          instructs FM to immediately skip past the <literal>switch</literal>
-          end-tag.</para>
+          <para>If <literal>x</literal> is <literal>1</literal>, then it will
+          print <literal>1 2 d</literal> (actually with more white-space
+          between); if <literal>x</literal> is <literal>2</literal> then it
+          will print <literal>2 d</literal>; if <literal>x</literal> is
+          <literal>3</literal> then it will print <literal>d</literal>. This
+          is usually unintended, or if it is intended then probably not
+          obvious for the reader, and that's why <literal>on</literal> is
+          recommended over <literal>case</literal>.</para>
         </section>
       </section>
 

Reply via email to