Skip to content

Commit fe1e811

Browse files
authored
Merge pull request #242 from scijava/return-values
Improve behavior of return value outputs
2 parents eb2ca6f + 1e10204 commit fe1e811

File tree

3 files changed

+73
-19
lines changed

3 files changed

+73
-19
lines changed

src/main/java/org/scijava/script/ScriptInfo.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ public class ScriptInfo extends AbstractModuleInfo implements Contextual {
9494
@Parameter
9595
private ConvertService convertService;
9696

97-
/** True iff the return value is explicitly declared as an output. */
98-
private boolean returnValueDeclared;
97+
/** True iff the return value should be appended as an output. */
98+
private boolean appendReturnValue;
9999

100100
/**
101101
* Creates a script metadata object which describes the given script file.
@@ -229,7 +229,7 @@ public BufferedReader getReader() {
229229
@Override
230230
public void parseParameters() {
231231
clearParameters();
232-
returnValueDeclared = false;
232+
appendReturnValue = true;
233233

234234
try {
235235
final BufferedReader in;
@@ -254,7 +254,7 @@ public void parseParameters() {
254254
}
255255
in.close();
256256

257-
if (!returnValueDeclared) addReturnValue();
257+
if (appendReturnValue) addReturnValue();
258258
}
259259
catch (final IOException exc) {
260260
log.error("Error reading script: " + path, exc);
@@ -264,9 +264,9 @@ public void parseParameters() {
264264
}
265265
}
266266

267-
/** Gets whether the return value is explicitly declared as an output. */
268-
public boolean isReturnValueDeclared() {
269-
return returnValueDeclared;
267+
/** Gets whether the return value is appended as an additional output. */
268+
public boolean isReturnValueAppended() {
269+
return appendReturnValue;
270270
}
271271

272272
// -- ModuleInfo methods --
@@ -374,7 +374,12 @@ private void parseParam(final String param,
374374
}
375375
final Class<?> type = scriptService.lookupClass(typeName);
376376
addItem(varName, type, attrs);
377-
if (ScriptModule.RETURN_VALUE.equals(varName)) returnValueDeclared = true;
377+
378+
if (ScriptModule.RETURN_VALUE.equals(varName)) {
379+
// NB: The return value variable is declared as an explicit OUTPUT.
380+
// So we should not append the return value as an extra output.
381+
appendReturnValue = false;
382+
}
378383
}
379384

380385
/** Parses a comma-delimited list of {@code key=value} pairs into a map. */
@@ -393,7 +398,7 @@ private void checkValid(final boolean valid, final String param)
393398
}
394399

395400
/** Adds an output for the value returned by the script itself. */
396-
private void addReturnValue() throws ScriptException {
401+
private void addReturnValue() {
397402
final HashMap<String, Object> attrs = new HashMap<>();
398403
attrs.put("type", "OUTPUT");
399404
addItem(ScriptModule.RETURN_VALUE, Object.class, attrs);
@@ -409,7 +414,12 @@ private <T> void addItem(final String name, final Class<T> type,
409414
assignAttribute(item, key, value);
410415
}
411416
if (item.isInput()) registerInput(item);
412-
if (item.isOutput()) registerOutput(item);
417+
if (item.isOutput()) {
418+
registerOutput(item);
419+
// NB: Only append the return value as an extra
420+
// output when no explicit outputs are declared.
421+
appendReturnValue = false;
422+
}
413423
}
414424

415425
private <T> void assignAttribute(final DefaultMutableModuleItem<T> item,
@@ -481,4 +491,12 @@ private static String getReaderContentsAsString(final Reader reader)
481491
return builder.toString();
482492
}
483493

494+
// -- Deprecated methods --
495+
496+
/** @deprecated Use {@link #isReturnValueAppended()} instead. */
497+
@Deprecated
498+
public boolean isReturnValueDeclared() {
499+
return !isReturnValueAppended();
500+
}
501+
484502
}

src/main/java/org/scijava/script/ScriptModule.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ public class ScriptModule extends AbstractModule implements Contextual {
8888
/** Destination for standard error during script execution. */
8989
private Writer error;
9090

91+
private Object returnValue;
92+
9193
public ScriptModule(final ScriptInfo info) {
9294
this.info = info;
9395
}
@@ -130,7 +132,7 @@ public ScriptEngine getEngine() {
130132

131133
/** Gets the return value of the script. */
132134
public Object getReturnValue() {
133-
return getOutput(RETURN_VALUE);
135+
return returnValue;
134136
}
135137

136138
// -- Module methods --
@@ -167,7 +169,7 @@ public void run() {
167169
}
168170

169171
// execute script!
170-
Object returnValue = null;
172+
returnValue = null;
171173
try {
172174
final Reader reader = getInfo().getReader();
173175
if (reader == null) returnValue = engine.eval(new FileReader(path));
@@ -190,7 +192,7 @@ public void run() {
190192
final String name = item.getName();
191193
if (isResolved(name)) continue;
192194
final Object value;
193-
if (RETURN_VALUE.equals(name) && !getInfo().isReturnValueDeclared()) {
195+
if (RETURN_VALUE.equals(name) && getInfo().isReturnValueAppended()) {
194196
// NB: This is the special implicit return value output!
195197
value = returnValue;
196198
}

src/test/java/org/scijava/script/ScriptInfoTest.java

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
package org.scijava.script;
3333

3434
import static org.junit.Assert.assertEquals;
35+
import static org.junit.Assert.assertFalse;
3536
import static org.junit.Assert.assertSame;
3637
import static org.junit.Assert.assertTrue;
3738
import static org.junit.Assert.fail;
@@ -45,6 +46,7 @@
4546
import java.util.Collections;
4647
import java.util.HashMap;
4748
import java.util.List;
49+
import java.util.Map;
4850

4951
import javax.script.Bindings;
5052
import javax.script.ScriptContext;
@@ -84,6 +86,42 @@ public static void tearDown() {
8486

8587
// -- Tests --
8688

89+
/**
90+
* Tests that the return value <em>is</em> appended as an extra output when no
91+
* explicit outputs were declared.
92+
*/
93+
@Test
94+
public void testReturnValueAppended() throws Exception {
95+
final String script = "" + //
96+
"% @LogService log\n" + //
97+
"% @int value\n";
98+
final ScriptModule scriptModule =
99+
scriptService.run("include-return-value.bsizes", script, true).get();
100+
101+
final Map<String, Object> outputs = scriptModule.getOutputs();
102+
assertEquals(1, outputs.size());
103+
assertTrue(outputs.containsKey(ScriptModule.RETURN_VALUE));
104+
}
105+
106+
/**
107+
* Tests that the return value is <em>not</em> appended as an extra output
108+
* when explicit outputs were declared.
109+
*/
110+
@Test
111+
public void testReturnValueExcluded() throws Exception {
112+
final String script = "" + //
113+
"% @LogService log\n" + //
114+
"% @OUTPUT int value\n";
115+
final ScriptModule scriptModule =
116+
scriptService.run("exclude-return-value.bsizes", script, true).get();
117+
118+
final Map<String, Object> outputs = scriptModule.getOutputs();
119+
assertEquals(1, outputs.size());
120+
assertTrue(outputs.containsKey("value"));
121+
assertFalse(outputs.containsKey(ScriptModule.RETURN_VALUE));
122+
}
123+
124+
87125
/**
88126
* Ensures parameters are parsed correctly from scripts, even in the presence
89127
* of noise like e-mail addresses.
@@ -97,7 +135,7 @@ public void testNoisyParameters() throws Exception {
97135
final ScriptModule scriptModule =
98136
scriptService.run("hello.bsizes", script, true).get();
99137

100-
final Object output = scriptModule.getOutput("result");
138+
final Object output = scriptModule.getReturnValue();
101139

102140
if (output == null) fail("null result");
103141
else if (!(output instanceof Integer)) {
@@ -169,18 +207,14 @@ public void testParameters() {
169207
assertItem("buffer", StringBuilder.class, null, ItemIO.BOTH, true, true,
170208
null, null, null, null, null, null, null, null, noChoices, buffer);
171209

172-
final ModuleItem<?> result = info.getOutput("result");
173-
assertItem("result", Object.class, null, ItemIO.OUTPUT, true, true, null,
174-
null, null, null, null, null, null, null, noChoices, result);
175-
176210
int inputCount = 0;
177211
final ModuleItem<?>[] inputs = { log, sliderValue, animal, buffer };
178212
for (final ModuleItem<?> inItem : info.inputs()) {
179213
assertSame(inputs[inputCount++], inItem);
180214
}
181215

182216
int outputCount = 0;
183-
final ModuleItem<?>[] outputs = { buffer, result };
217+
final ModuleItem<?>[] outputs = { buffer };
184218
for (final ModuleItem<?> outItem : info.outputs()) {
185219
assertSame(outputs[outputCount++], outItem);
186220
}

0 commit comments

Comments
 (0)