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><#switch
<replaceable>value</replaceable>>
<#on <replaceable>refValue1</replaceable>>
- <replaceable>... (Handles both refValue1)</replaceable>
+ <replaceable>... (Handles refValue1)</replaceable>
<#on <replaceable>refValue2, refValue3</replaceable>>
<replaceable>... (Handles both refValue2 and refValue3)</replaceable>)
<replaceable>...</replaceable>
@@ -25231,7 +25241,7 @@ or
<programlisting role="metaTemplate"><literal><#switch
<replaceable>value</replaceable>>
<#case <replaceable>refValue1</replaceable>>
- <replaceable>... (Handles both refValue1)</replaceable>
+ <replaceable>... (Handles refValue1)</replaceable>
<#break>
<#case <replaceable>refValue2</replaceable>>
<#case <replaceable>refValue3</replaceable>>
@@ -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"><#switch animal.size>
+ <#on "small">
+ Processed if animal.size was "small"
+ <#on "medium">
+ Processed if animal.size was "medium"
+ <#on "large", "extra large">
+ Processed if animal.size was "large" or "extra large"
+ <#default>
+ Processed if animal.size is neither of the above
+</#switch></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><#case "large"></literal>):</para>
<programlisting role="template"><#switch animal.size>
<#case "small">
- This will be processed if it is small
+ Processed if animal.size was "small"
<#break>
<#case "medium">
- This will be processed if it is medium
+ Processed if animal.size was "medium"
<#break>
<#case "large">
- This will be processed if it is large
+ <#case "extra large">
+ Processed if animal.size was "large" or "extra large"
<#break>
<#default>
- This will be processed if it is neither
+ Processed if animal.size is neither of the above
</#switch></programlisting>
- <para>Inside the <literal>switch</literal> must be one or more
- <literal><#case <replaceable>value</replaceable>></literal>,
- and after all such <literal>case</literal> tags optionally one
- <literal><#default></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"><#assign value = animal.size>
+<#if value == "small">
+ Processed if animal.size was "small"
+<#elseif value == "medium">
+ Processed if animal.size was "medium"
+<#elseif value == "large" || value == "extra large">
+ Processed if animal.size was "large" or "extra large"
+<#else>
+ Processed if animal.size is neither of the above
+</#if></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><#default></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"><#switch x>
<#case 1>
@@ -25325,12 +25409,14 @@ or
d
</#switch></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>