Skip to content

Commit

Permalink
Merge branch 'groovy-time'
Browse files Browse the repository at this point in the history
This uses Groovy to parse template values.
Much cleaner, much slicker, much more powerful.

For details, see b5d3778.
  • Loading branch information
ctrueden committed Jan 30, 2015
2 parents 1569a78 + d371bd7 commit c51ce63
Show file tree
Hide file tree
Showing 76 changed files with 4,155 additions and 845 deletions.
148 changes: 18 additions & 130 deletions src/main/groovy/generate.groovy
Expand Up @@ -54,135 +54,15 @@ def processTemplate(engine, context, templateFile, outFilename) {
out.close();
}

/* Parses a string to a string, list or map. */
def parseValue(str) {
symbols = new Stack<Character>();
parsed = new Stack<Object>();

buffer = "";

for (char c : str.toCharArray()) {
try {
// top symbol determines what kind of structure we're
// currently working on TODO: Speedup?
top = symbols.peek();

if (top == '\\') { // escaped
symbols.pop();
}
else {
if (top == '{') {
// parse a map
if (c == ':') {
// key is complete, push the key to parsed
if (!buffer.isEmpty()) {
parsed.push(new String(buffer));
buffer = "";
} // else
// buffer has probably already been pushed,
// therefore must have been enclosed in '"'
continue;
}
if (c == ',' || c == '}') {
if (buffer.isEmpty()) {
value = parsed.pop();
}
else {
value = new String(buffer);
buffer = "";
}

key = parsed.pop();

parsed.peek().put(key.trim(), value);

if (c == '}') {
// finish up this map.
symbols.pop();
}

continue;
}
}
else if (top == '[') {
// parse a list
if (c == ',' || c == ']') {
if (buffer.isEmpty()) {
value = parsed.pop();
}
else {
value = new String(buffer);
buffer = "";
}

parsed.peek().add(value);

if (c == ']') {
// finish up this map.
symbols.pop();
}

continue;
}
}
else if (top == '"') {
if (c == '"') {
parsed.push(new String(buffer));
buffer = "";
symbols.pop();
continue;
}
}

if (c == '[') {
symbols.push(c);
parsed.push(new ArrayList<Object>());
continue;
}
if (c == '{') {
symbols.push(c);
parsed.push(new HashMap<Object, Object>());
continue;
}
if (c == '"') {
symbols.push(c);
continue;
// uses buffer
}
}

// no special meaning to this char.
if (buffer.isEmpty() && isWhitespace(c)) {
// skip leading whitespaces
continue;
}
buffer += c;
}
catch (EmptyStackException e) {
if (isWhitespace(c)) {
// skip leading whitespaces
}
else if (c == '{') {
symbols.push(c);
parsed.push(new HashMap<Object, Object>());
}
else if (c == '[') {
symbols.push(c);
parsed.push(new ArrayList<Object>());
}
else {
// this is a simple string value, we're done.
parsed.push(new String(str.trim()));
break;
}
}
/* Parses a string to a scalar, list or map. */
def parseValue(sh, translationsFile, key, expression) {
try {
return sh.evaluate(expression);
}
catch (groovy.lang.GroovyRuntimeException e) {
print("[WARNING] $translationsFile: " +
"key '$key' has unparseable value: " + e.getMessage());
}

return parsed.pop();
}

def isWhitespace(c) {
return c == ' ' || c == '\t' || c == '\n';
}

/*
Expand All @@ -202,6 +82,9 @@ def translate(templateSubdirectory, templateFile, translationsFile) {
// initialize the Velocity engine
engine = new org.apache.velocity.app.VelocityEngine();
p = new java.util.Properties();
// fail if template uses an invalid expression; e.g., an undefined variable
p.setProperty("runtime.references.strict", "true");
// tell Velocity where the templates are located
p.setProperty("file.resource.loader.path", "$templateSubdirectory");
// tell Velocity to log to stderr rather than to a velocity.log file
p.setProperty(org.apache.velocity.runtime.RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
Expand All @@ -217,6 +100,7 @@ def translate(templateSubdirectory, templateFile, translationsFile) {
timestamp(templateSubdirectory, translationsFile),
timestamp(templateSubdirectory, templateFile));

sh = new groovy.lang.GroovyShell();
for (;;) {
// read the line
line = reader.readLine();
Expand All @@ -240,7 +124,11 @@ def translate(templateSubdirectory, templateFile, translationsFile) {
}

// ignore blank lines
if (line.trim().isEmpty()) continue;
trimmedLine = line.trim();
if (trimmedLine.isEmpty()) continue;

// ignore comments
if (trimmedLine.startsWith("#")) continue;

// parse key/value pair lines separate by equals
if (!line.contains('=')) {
Expand Down Expand Up @@ -273,7 +161,7 @@ def translate(templateSubdirectory, templateFile, translationsFile) {

//For debugging: System.out.println("<" + key + ">: " + parseValue(value).toString());

context.put(key, parseValue(value));
context.put(key, parseValue(sh, translationsFile, key, value));
}
reader.close();

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/net/imagej/ops/OpRef.java
@@ -1,9 +1,9 @@
/*
* #%L
* ImageJ OPS: a framework for reusable algorithms.
* ImageJ software for multidimensional image processing and analysis.
* %%
* Copyright (C) 2014 - 2015 Board of Regents of the University of
* Wisconsin-Madison and University of Konstanz.
* Wisconsin-Madison, University of Konstanz and Brian Northan.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
Expand Down
58 changes: 58 additions & 0 deletions src/main/java/net/imagej/ops/arithmetic/real/RealAbs.java
@@ -0,0 +1,58 @@

/*
* #%L
* ImageJ software for multidimensional image processing and analysis.
* %%
* Copyright (C) 2014 - 2015 Board of Regents of the University of
* Wisconsin-Madison, University of Konstanz and Brian Northan.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package net.imagej.ops.arithmetic.real;

import net.imagej.ops.AbstractStrictFunction;
import net.imagej.ops.MathOps;
import net.imagej.ops.Op;
import net.imglib2.type.numeric.RealType;

import org.scijava.plugin.Plugin;

/**
* Sets the real component of an output real number to the absolute value of the
* real component of an input real number.
*
* @author Barry DeZonia
* @author Jonathan Hale
*/
@Plugin(type = Op.class, name = MathOps.Abs.NAME)
public class RealAbs<I extends RealType<I>, O extends RealType<O>> extends
AbstractStrictFunction<I, O> implements MathOps.Abs
{

@Override
public O compute(final I input, final O output) {
output.setReal(Math.abs(input.getRealDouble()));
return output;
}
}
62 changes: 62 additions & 0 deletions src/main/java/net/imagej/ops/arithmetic/real/RealAdd.java
@@ -0,0 +1,62 @@

/*
* #%L
* ImageJ software for multidimensional image processing and analysis.
* %%
* Copyright (C) 2014 - 2015 Board of Regents of the University of
* Wisconsin-Madison, University of Konstanz and Brian Northan.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package net.imagej.ops.arithmetic.real;

import net.imagej.ops.AbstractStrictFunction;
import net.imagej.ops.MathOps;
import net.imagej.ops.Op;
import net.imglib2.type.numeric.RealType;

import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;

/**
* Sets the real component of an output real number to the addition of the real
* component of an input real number with a constant value.
*
* @author Barry DeZonia
* @author Jonathan Hale
*/
@Plugin(type = Op.class, name = MathOps.Add.NAME)
public class RealAdd<I extends RealType<I>, O extends RealType<O>> extends
AbstractStrictFunction<I, O> implements MathOps.Add
{

@Parameter
private double constant;

@Override
public O compute(final I input, final O output) {
output.setReal(input.getRealDouble() + constant);
return output;
}
}

0 comments on commit c51ce63

Please sign in to comment.