Skip to content

Commit

Permalink
feat: add builtin function %boolval (plantuml#1873)
Browse files Browse the repository at this point in the history
This change adds the `%boolval` function to improve usability of boolean
values and conditionals. This is especially helpful when the diagram
data is generated in a previous workflow step, using a conventional
programming or scripting language.

In this first implementation, the boolean strings are defined as:

* True values: `true`, `1`
* False values: `false`, `0`

These values are case-sensitive, meaning `True` `TRUE` are also treated
as true values (likewise for false values).

This builtin function helps mitigate some user confusion with the use of
boolean values, specifically that all strings including `"0"` and
`"false"` are treated as true values.

Existing behaviour (integer `0` is false, all other numbers and strings
are true) is not affected, and can be used by simply not calling the
new `%boolval` function.

Other minor improvements:

1. Parsing error in `%intval` will now raise an exception. This improves
   tool behaviour consistency, for example, when `-noerror` flag is used
   from the CLI.
2. Functions in `TContext.java` are arranged in sorted order. This code
   readability improvement does not change the tool behaviour from the
   user's perspective.
  • Loading branch information
dragondive authored Aug 15, 2024
1 parent dac564a commit 425db1d
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 47 deletions.
90 changes: 46 additions & 44 deletions src/net/sourceforge/plantuml/tim/TContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import net.sourceforge.plantuml.tim.iterator.CodeIteratorWhile;
import net.sourceforge.plantuml.tim.stdlib.AlwaysFalse;
import net.sourceforge.plantuml.tim.stdlib.AlwaysTrue;
import net.sourceforge.plantuml.tim.stdlib.BoolVal;
import net.sourceforge.plantuml.tim.stdlib.CallUserFunction;
import net.sourceforge.plantuml.tim.stdlib.Chr;
import net.sourceforge.plantuml.tim.stdlib.Darken;
Expand Down Expand Up @@ -167,67 +168,68 @@ public Set<FileWithSuffix> getFilesUsedCurrent() {
}

private void addStandardFunctions(Defines defines) {
functionsSet.addFunction(new Strlen());
functionsSet.addFunction(new Substr());
functionsSet.addFunction(new FileExists());
functionsSet.addFunction(new Getenv());
functionsSet.addFunction(new Dirpath(defines));
functionsSet.addFunction(new Filename(defines));
functionsSet.addFunction(new DateFunction());
functionsSet.addFunction(new Strpos());
functionsSet.addFunction(new InvokeProcedure());
functionsSet.addFunction(new AlwaysFalse());
functionsSet.addFunction(new AlwaysTrue());
functionsSet.addFunction(new LogicalNot());
functionsSet.addFunction(new FunctionExists());
functionsSet.addFunction(new VariableExists());
functionsSet.addFunction(new BoolVal());
functionsSet.addFunction(new CallUserFunction());
functionsSet.addFunction(new RetrieveProcedure());
functionsSet.addFunction(new SetVariableValue());
functionsSet.addFunction(new GetVariableValue());
functionsSet.addFunction(new IntVal());
functionsSet.addFunction(new GetVersion());
functionsSet.addFunction(new Upper());
functionsSet.addFunction(new Lower());
functionsSet.addFunction(new StringFunction());
functionsSet.addFunction(new Newline());
functionsSet.addFunction(new Feature());
functionsSet.addFunction(new Lighten());
functionsSet.addFunction(new Chr());
functionsSet.addFunction(new Darken());
functionsSet.addFunction(new IsDark());
functionsSet.addFunction(new IsLight());
functionsSet.addFunction(new ReverseHsluvColor());
functionsSet.addFunction(new ReverseColor());
functionsSet.addFunction(new DateFunction());
functionsSet.addFunction(new Dec2hex());
functionsSet.addFunction(new Dirpath(defines));
functionsSet.addFunction(new Eval());
functionsSet.addFunction(new Feature());
functionsSet.addFunction(new FileExists());
functionsSet.addFunction(new Filename(defines));
functionsSet.addFunction(new FunctionExists());
functionsSet.addFunction(new GetAllStdlib());
functionsSet.addFunction(new GetAllTheme());
functionsSet.addFunction(new GetJsonKey());
functionsSet.addFunction(new GetJsonType());
functionsSet.addFunction(new GetVariableValue());
functionsSet.addFunction(new GetVersion());
functionsSet.addFunction(new Getenv());
functionsSet.addFunction(new Hex2dec());
functionsSet.addFunction(new Dec2hex());
functionsSet.addFunction(new HslColor());
functionsSet.addFunction(new IntVal());
functionsSet.addFunction(new InvokeProcedure());
functionsSet.addFunction(new IsDark());
functionsSet.addFunction(new IsLight());
functionsSet.addFunction(new JsonAdd());
functionsSet.addFunction(new JsonKeyExists());
functionsSet.addFunction(new JsonMerge());
functionsSet.addFunction(new JsonRemove());
functionsSet.addFunction(new JsonSet());
functionsSet.addFunction(new Lighten());
functionsSet.addFunction(new LoadJson());
// functionsSet.addFunction(new LoadJsonLegacy());
functionsSet.addFunction(new Chr());
functionsSet.addFunction(new Size());
functionsSet.addFunction(new GetJsonKey());
functionsSet.addFunction(new GetJsonType());
functionsSet.addFunction(new SplitStr());
functionsSet.addFunction(new JsonKeyExists());
functionsSet.addFunction(new Now());
functionsSet.addFunction(new LogicalAnd());
functionsSet.addFunction(new LogicalOr());
functionsSet.addFunction(new LogicalXor());
functionsSet.addFunction(new LogicalNand());
functionsSet.addFunction(new LogicalNor());
functionsSet.addFunction(new LogicalNot());
functionsSet.addFunction(new LogicalNxor());
functionsSet.addFunction(new Ord());
functionsSet.addFunction(new LogicalOr());
functionsSet.addFunction(new LogicalXor());
functionsSet.addFunction(new Lower());
functionsSet.addFunction(new Modulo());
functionsSet.addFunction(new Newline());
functionsSet.addFunction(new Now());
functionsSet.addFunction(new Ord());
functionsSet.addFunction(new RandomFunction());
functionsSet.addFunction(new GetAllTheme());
functionsSet.addFunction(new GetAllStdlib());
functionsSet.addFunction(new RetrieveProcedure());
functionsSet.addFunction(new ReverseColor());
functionsSet.addFunction(new ReverseHsluvColor());
functionsSet.addFunction(new SetVariableValue());
functionsSet.addFunction(new Size());
functionsSet.addFunction(new SplitStr());
functionsSet.addFunction(new SplitStrRegex());
functionsSet.addFunction(new Str2Json());
functionsSet.addFunction(new JsonAdd());
functionsSet.addFunction(new JsonRemove());
functionsSet.addFunction(new JsonSet());
functionsSet.addFunction(new JsonMerge());
functionsSet.addFunction(new StringFunction());
functionsSet.addFunction(new Strlen());
functionsSet.addFunction(new Strpos());
functionsSet.addFunction(new Substr());
functionsSet.addFunction(new Upper());
functionsSet.addFunction(new VariableExists());
// %standard_exists_function
// %str_replace
// !exit
Expand Down
76 changes: 76 additions & 0 deletions src/net/sourceforge/plantuml/tim/stdlib/BoolVal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
* Contribution: Aravind Pai
*
*/
package net.sourceforge.plantuml.tim.stdlib;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.expression.TValue;

public class BoolVal extends SimpleReturnFunction {

public TFunctionSignature getSignature() {
return new TFunctionSignature("%boolval", 1);
}

@Override
public boolean canCover(int nbArg, Set<String> namedArgument) {
return nbArg == 1;
}

@Override
public TValue executeReturnFunction(TContext context, TMemory memory, StringLocated location, List<TValue> values,
Map<String, TValue> named) throws EaterException {
final String s = values.get(0).toString().toLowerCase();
if (trueValues.contains(s)) {
return TValue.fromBoolean(true);
} else if (falseValues.contains(s)) {
return TValue.fromBoolean(false);
}

throw new EaterException("Cannot convert " + s + " to boolean.", location);
}

private final List<String> trueValues = Arrays.asList("true", "1");
private final List<String> falseValues = Arrays.asList("false", "0");
}
5 changes: 2 additions & 3 deletions src/net/sourceforge/plantuml/tim/stdlib/IntVal.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,8 @@ public TValue executeReturnFunction(TContext context, TMemory memory, StringLoca
final String s = values.get(0).toString();
try {
return TValue.fromInt(Integer.parseInt(s));
} catch (Exception e) {
Log.error("Cannot convert " + s);
} catch (NumberFormatException e) {
throw new EaterException("Cannot convert " + s + " to integer.", location);
}
return TValue.fromInt(0);
}
}
1 change: 1 addition & 0 deletions src/net/sourceforge/plantuml/tim/stdlib/Modulo.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
*
*
* Original Author: Arnaud Roques
* Contribution: Aravind Pai
*
*/
package net.sourceforge.plantuml.tim.stdlib;
Expand Down
54 changes: 54 additions & 0 deletions test/net/sourceforge/plantuml/tim/stdlib/BoolValTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.sourceforge.plantuml.tim.stdlib;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.expression.TValue;

class BoolValTest {
/**
* Tests boolval according to a list of input / expected output
*
* @throws EaterException should not
*/
@ParameterizedTest
@CsvSource(nullValues = "null", value = {
"True, true",
"true, true",
"1, true",
"False, false",
"false, false",
"0, false",
})
void executeReturnFunctionWithValidBooleanValueStringTest(String input, Boolean expected) throws EaterException {
BoolVal cut = new BoolVal();
List<TValue> values = Arrays.asList(TValue.fromString(input));

TValue tValue = cut.executeReturnFunction(null, null, null, values, null);
assertEquals(expected, tValue.toBoolean());
}

@ParameterizedTest
@CsvSource(nullValues = "null", value = {
"2",
"hello",
})
void executeReturnFunctionWithInvalidBooleanValueStringTest(String input) throws EaterException {
BoolVal cut = new BoolVal();
List<TValue> values = Arrays.asList(TValue.fromString(input));

StringLocated stringLocated = new StringLocated("test location", null);
EaterException exception = assertThrows(EaterException.class, () -> {
cut.executeReturnFunction(null, null, stringLocated, values, null);
});

assertEquals("Cannot convert " + input + " to boolean.", exception.getMessage());
}
}

0 comments on commit 425db1d

Please sign in to comment.