diff --git a/docs/environment.yml b/docs/environment.yml index 539f61801..946aa495a 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -1,7 +1,6 @@ name: scijava-docs channels: - conda-forge - - defaults dependencies: - myst-nb - openjdk=11 diff --git a/docs/ops/doc/WritingYourOwnOpPackage.md b/docs/ops/doc/WritingYourOwnOpPackage.md index 757fc6432..98f04db50 100644 --- a/docs/ops/doc/WritingYourOwnOpPackage.md +++ b/docs/ops/doc/WritingYourOwnOpPackage.md @@ -467,6 +467,7 @@ Assuming your project is following Maven's [standard directory layout](https://m ```yaml - op: names: [your.op.name1, your.op.name2, ...] # Array of Strings + hints: [op.hint1, op.hint2, ...] # Array of Strings description: 'your Op description' # String source: yourOpSource # String - see below priority: 0.0 # Number @@ -493,6 +494,17 @@ Assuming your project is following Maven's [standard directory layout](https://m Of particular note are the following sections: +#### Hints + +Each Op can define a set of hints (i.e. flags to the matcher) that can enable/disable particular aspects of the matcher. + +Some of the most useful Op hints are described below: + +| Hint | Use Case | +|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `Adaptation.FORBIDDEN` | Some algorithms like a [Fast Fourier Transform](https://en.wikipedia.org/wiki/Fast_Fourier_transform) require their outputs be
of a particular size (not equivalent to the input size). If they are a `Computer`,
adaptation to `Function`s may cause errors. | +| `Conversion.FORBIDDEN` | `engine.convert` Ops often require this hint to avoid infinite loops in
converted Op matching. | + #### Source For **java objects**, the `source` will start with one of the following prefix, followed by a `:/`, followed by a [percent-encoded](https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding) stringification of the Op (i.e. calling `toString()` on the object). Examples are shown below: diff --git a/scijava-ops-api/src/main/java/org/scijava/ops/api/Hints.java b/scijava-ops-api/src/main/java/org/scijava/ops/api/Hints.java index 487e2ef06..459ddae2a 100644 --- a/scijava-ops-api/src/main/java/org/scijava/ops/api/Hints.java +++ b/scijava-ops-api/src/main/java/org/scijava/ops/api/Hints.java @@ -62,7 +62,7 @@ public Hints(final String... startingHints) { this(Arrays.asList(startingHints)); } - private Hints(final Collection hints) { + public Hints(final Collection hints) { this.hints = new HashSet<>(hints); } diff --git a/scijava-ops-engine/src/main/java/org/scijava/ops/engine/yaml/impl/AbstractYAMLOpInfo.java b/scijava-ops-engine/src/main/java/org/scijava/ops/engine/yaml/impl/AbstractYAMLOpInfo.java index 40c7d04be..5fdefc865 100644 --- a/scijava-ops-engine/src/main/java/org/scijava/ops/engine/yaml/impl/AbstractYAMLOpInfo.java +++ b/scijava-ops-engine/src/main/java/org/scijava/ops/engine/yaml/impl/AbstractYAMLOpInfo.java @@ -35,8 +35,8 @@ import org.scijava.priority.Priority; import org.scijava.struct.Struct; -import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -59,7 +59,10 @@ public AbstractYAMLOpInfo(final Map yaml, this.priority = parsePriority(); this.description = yaml.getOrDefault("description", "").toString(); this.version = (String) yaml.get("version"); - this.hints = new Hints(); + this.hints = new Hints((List) yaml.getOrDefault( // + "hints", // + Collections.emptyList() // + )); } /** diff --git a/scijava-ops-engine/src/test/java/org/scijava/ops/engine/yaml/impl/YAMLOpTest.java b/scijava-ops-engine/src/test/java/org/scijava/ops/engine/yaml/impl/YAMLOpTest.java index a1ed22395..63961b235 100644 --- a/scijava-ops-engine/src/test/java/org/scijava/ops/engine/yaml/impl/YAMLOpTest.java +++ b/scijava-ops-engine/src/test/java/org/scijava/ops/engine/yaml/impl/YAMLOpTest.java @@ -121,4 +121,16 @@ public void testYAMLDescription() { Assertions.assertEquals(expected, actual); } + @Test + public void testYAMLHints() { + var infos = ops.infos("example.xor"); + Assertions.assertEquals(1, infos.size()); + var info = infos.iterator().next(); + var hints = info.declaredHints(); + Assertions.assertTrue(hints.containsAll( // + "Adaptation.FORBIDDEN", // + "Conversion.FORBIDDEN" // + )); + } + } diff --git a/scijava-ops-engine/src/test/java/org/scijava/ops/engine/yaml/impl/ops/YAMLMethodOp.java b/scijava-ops-engine/src/test/java/org/scijava/ops/engine/yaml/impl/ops/YAMLMethodOp.java index e5a15fe90..9852a6744 100644 --- a/scijava-ops-engine/src/test/java/org/scijava/ops/engine/yaml/impl/ops/YAMLMethodOp.java +++ b/scijava-ops-engine/src/test/java/org/scijava/ops/engine/yaml/impl/ops/YAMLMethodOp.java @@ -57,7 +57,7 @@ public static Double subtract(N aDouble, N aDouble2) { /** * Another example Op, implemented by a {@link Method} * - * @implNote op name=example.xor, type=Inplace1 + * @implNote op name=example.xor, type=Inplace1, hints="Adaptation.FORBIDDEN,Conversion.FORBIDDEN" * @param aList the first integer {@link List} * @param aList2 the second integer {@link List} */ diff --git a/scijava-ops-indexer/src/main/java/org/scijava/ops/indexer/OpImplData.java b/scijava-ops-indexer/src/main/java/org/scijava/ops/indexer/OpImplData.java index 816b81ace..0ac2ad176 100644 --- a/scijava-ops-indexer/src/main/java/org/scijava/ops/indexer/OpImplData.java +++ b/scijava-ops-indexer/src/main/java/org/scijava/ops/indexer/OpImplData.java @@ -29,9 +29,6 @@ package org.scijava.ops.indexer; -import static org.scijava.ops.indexer.ProcessingUtils.blockSeparator; -import static org.scijava.ops.indexer.ProcessingUtils.tagElementSeparator; - import java.net.URI; import java.util.*; import java.util.stream.Collectors; @@ -39,6 +36,8 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; +import static org.scijava.ops.indexer.ProcessingUtils.*; + /** * A data structure containing all the metadata needed to define an Op * @@ -89,6 +88,11 @@ abstract class OpImplData { */ protected final List authors = new ArrayList<>(); + /** + * A {@link List} of the hints declared by this Op + */ + protected final List hints = new ArrayList<>(); + protected final ProcessingEnvironment env; /** @@ -186,6 +190,10 @@ private void parseImplNote(String implTag) { else if ("names".equals(kv[0]) || "name".equals(kv[0])) { names.addAll(Arrays.asList(value.split("\\s*,\\s*"))); } + else if ("hints".equals(kv[0])) { + + hints.addAll(Arrays.asList(value.split("\\s*,\\s*"))); + } else { if (value.contains(",")) { tags.put(kv[0], value.split(",")); @@ -216,6 +224,7 @@ public Map dumpData() { map.put("description", description); map.put("priority", priority); map.put("authors", authors.toArray(String[]::new)); + map.put("hints", hints.toArray(String[]::new)); var foo = params.stream() // .map(OpParameter::data) // .collect(Collectors.toList()); diff --git a/scijava-ops-indexer/src/main/java/org/scijava/ops/indexer/ProcessingUtils.java b/scijava-ops-indexer/src/main/java/org/scijava/ops/indexer/ProcessingUtils.java index e585eb3d6..18dc26b18 100644 --- a/scijava-ops-indexer/src/main/java/org/scijava/ops/indexer/ProcessingUtils.java +++ b/scijava-ops-indexer/src/main/java/org/scijava/ops/indexer/ProcessingUtils.java @@ -65,7 +65,7 @@ final class ProcessingUtils { * tags. */ public static final Pattern tagElementSeparator = Pattern.compile( - "\\s*[,\\s]+(?=(?:[^']*'[^']*')*[^']*$)"); + "\\s*[,\\s]+(?=(?:[^'\"]*['\"][^'\"]*['\"])*[^'\"]*$)"); private ProcessingUtils() { throw new AssertionError("not instantiable");