Made various GEL functions and the forEach control work with java.util.List and java.util.Collection in addition to just Object[].

Added field columnNames to row object.
Added 1-bounded numeric log facet.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@328 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-03-19 23:04:17 +00:00
parent 6fba7d1e7f
commit a43b2a72c1
14 changed files with 239 additions and 61 deletions

View File

@ -2,7 +2,9 @@ package com.metaweb.gridworks.expr;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import com.metaweb.gridworks.model.Cell;
@ -86,4 +88,14 @@ public class ExpressionUtils {
(Serializable) v :
new EvalError(v.getClass().getSimpleName() + " value not storable");
}
@SuppressWarnings("unchecked")
static public List<Object> toObjectList(Object v) {
return (List<Object>) v;
}
@SuppressWarnings("unchecked")
static public Collection<Object> toObjectCollection(Object v) {
return (Collection<Object>) v;
}
}

View File

@ -1,10 +1,12 @@
package com.metaweb.gridworks.expr.functions;
import java.util.List;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.metaweb.gridworks.expr.ExpressionUtils;
import com.metaweb.gridworks.expr.HasFields;
import com.metaweb.gridworks.gel.Function;
@ -23,31 +25,41 @@ public class Get implements Function {
}
} else {
if (from instanceof Number && (to == null || to instanceof Number)) {
if (v.getClass().isArray()) {
Object[] a = (Object[]) v;
if (v.getClass().isArray() || v instanceof List<?>) {
int length = v.getClass().isArray() ?
((Object[]) v).length :
ExpressionUtils.toObjectList(v).size();
int start = ((Number) from).intValue();
if (start < 0) {
start = a.length + start;
start = length + start;
}
start = Math.min(a.length, Math.max(0, start));
start = Math.min(length, Math.max(0, start));
if (to == null) {
return start < a.length ? a[start] : null;
return start >= length ? null :
(v.getClass().isArray() ?
((Object[]) v)[start] :
ExpressionUtils.toObjectList(v).get(start));
} else {
int end = to != null && to instanceof Number ?
((Number) to).intValue() : a.length;
((Number) to).intValue() : length;
if (end < 0) {
end = a.length + end;
end = length + end;
}
end = Math.min(a.length, Math.max(start, end));
end = Math.min(length, Math.max(start, end));
if (end > start) {
Object[] a2 = new Object[end - start];
System.arraycopy(a, start, a2, 0, end - start);
return a2;
if (v.getClass().isArray()) {
Object[] a2 = new Object[end - start];
System.arraycopy((Object[]) v, start, a2, 0, end - start);
return a2;
} else {
return ExpressionUtils.toObjectList(v).subList(start, end);
}
}
}
} else {

View File

@ -1,5 +1,6 @@
package com.metaweb.gridworks.expr.functions;
import java.util.Collection;
import java.util.Properties;
import org.json.JSONException;
@ -19,6 +20,8 @@ public class Length implements Function {
if (v.getClass().isArray()) {
Object[] a = (Object[]) v;
return a.length;
} else if (v instanceof Collection<?>) {
return ((Collection<?>) v).size();
} else {
String s = (v instanceof String ? (String) v : v.toString());
return s.length();

View File

@ -1,10 +1,12 @@
package com.metaweb.gridworks.expr.functions;
import java.util.List;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.metaweb.gridworks.expr.ExpressionUtils;
import com.metaweb.gridworks.gel.Function;
public class Slice implements Function {
@ -16,26 +18,34 @@ public class Slice implements Function {
Object to = args.length == 3 ? args[2] : null;
if (v != null && from != null && from instanceof Number && (to == null || to instanceof Number)) {
if (v.getClass().isArray()) {
Object[] a = (Object[]) v;
if (v.getClass().isArray() || v instanceof List<?>) {
int length = v.getClass().isArray() ?
((Object[]) v).length :
ExpressionUtils.toObjectList(v).size();
int start = ((Number) from).intValue();
int end = to != null && to instanceof Number ?
((Number) to).intValue() : a.length;
((Number) to).intValue() : length;
if (start < 0) {
start = a.length + start;
start = length + start;
}
start = Math.min(a.length, Math.max(0, start));
start = Math.min(length, Math.max(0, start));
if (end < 0) {
end = a.length + end;
end = length + end;
}
end = Math.min(a.length, Math.max(start, end));
end = Math.min(length, Math.max(start, end));
Object[] a2 = new Object[end - start];
System.arraycopy(a, start, a2, 0, end - start);
return a2;
if (v.getClass().isArray()) {
Object[] a2 = new Object[end - start];
System.arraycopy((Object[]) v, start, a2, 0, end - start);
return a2;
} else {
return ExpressionUtils.toObjectList(v).subList(start, end);
}
} else {
String s = (v instanceof String ? (String) v : v.toString());

View File

@ -1,6 +1,7 @@
package com.metaweb.gridworks.expr.functions;
import java.util.Calendar;
import java.util.List;
import java.util.Properties;
import org.json.JSONException;
@ -23,7 +24,7 @@ public class Type implements Function {
return "date";
} else if (v instanceof Number) {
return "number";
} else if (v.getClass().isArray()) {
} else if (v.getClass().isArray() || v instanceof List<?>) {
return "array";
} else {
return v.getClass().getName();

View File

@ -1,5 +1,6 @@
package com.metaweb.gridworks.expr.functions.arrays;
import java.util.List;
import java.util.Properties;
import org.json.JSONException;
@ -16,20 +17,30 @@ public class Join implements Function {
Object v = args[0];
Object s = args[1];
if (v != null && v.getClass().isArray() &&
if (v != null && (v.getClass().isArray() || v instanceof List<?>) &&
s != null && s instanceof String) {
Object[] a = (Object[]) v;
String separator = (String) s;
StringBuffer sb = new StringBuffer();
for (Object o : a) {
if (o != null) {
if (sb.length() > 0) {
sb.append(separator);
}
sb.append(o.toString());
}
if (v.getClass().isArray()) {
for (Object o : (Object[]) v) {
if (o != null) {
if (sb.length() > 0) {
sb.append(separator);
}
sb.append(o.toString());
}
}
} else {
for (Object o : (List<Object>) v) {
if (o != null) {
if (sb.length() > 0) {
sb.append(separator);
}
sb.append(o.toString());
}
}
}
return sb.toString();

View File

@ -1,11 +1,13 @@
package com.metaweb.gridworks.expr.functions.arrays;
import java.util.List;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.metaweb.gridworks.expr.EvalError;
import com.metaweb.gridworks.expr.ExpressionUtils;
import com.metaweb.gridworks.gel.ControlFunctionRegistry;
import com.metaweb.gridworks.gel.Function;
@ -15,14 +17,23 @@ public class Reverse implements Function {
if (args.length == 1) {
Object v = args[0];
if (v != null && v.getClass().isArray()) {
Object[] a = (Object[]) v;
Object[] r = new Object[a.length];
for (int i = 0; i < a.length; i++) {
r[i] = a[r.length - i - 1];
if (v != null && (v.getClass().isArray() || v instanceof List<?>)) {
int length = v.getClass().isArray() ?
((Object[]) v).length :
ExpressionUtils.toObjectList(v).size();
Object[] r = new Object[length];
if (v.getClass().isArray()) {
Object[] a = (Object[]) v;
for (int i = 0; i < length; i++) {
r[i] = a[r.length - i - 1];
}
} else {
List<Object> a = ExpressionUtils.toObjectList(v);
for (int i = 0; i < length; i++) {
r[i] = a.get(r.length - i - 1);
}
}
return r;
}
}

View File

@ -1,6 +1,8 @@
package com.metaweb.gridworks.expr.functions.arrays;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import org.json.JSONException;
@ -12,18 +14,25 @@ import com.metaweb.gridworks.gel.Function;
public class Sort implements Function {
public Object call(Properties bindings, Object[] args) {
@SuppressWarnings("unchecked")
public Object call(Properties bindings, Object[] args) {
if (args.length == 1) {
Object v = args[0];
if (v != null && v.getClass().isArray()) {
Object[] a = (Object[]) v;
Object[] r = a.clone();
Arrays.sort(r, 0, r.length);
return r;
if (v != null) {
if (v.getClass().isArray()) {
Object[] a = (Object[]) v;
Object[] r = a.clone();
Arrays.sort(r, 0, r.length);
return r;
} else if (v instanceof List<?>) {
List<? extends Comparable> a = (List<? extends Comparable>) v;
Collections.sort(a);
return a;
}
}
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects an array");

View File

@ -0,0 +1,59 @@
package com.metaweb.gridworks.expr.functions.math;
import java.util.List;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.metaweb.gridworks.expr.EvalError;
import com.metaweb.gridworks.expr.ExpressionUtils;
import com.metaweb.gridworks.gel.ControlFunctionRegistry;
import com.metaweb.gridworks.gel.Function;
public class Sum implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1) {
Object v = args[0];
if (v != null && (v.getClass().isArray() || v instanceof List<?>)) {
int length = v.getClass().isArray() ?
((Object[]) v).length :
ExpressionUtils.toObjectList(v).size();
double total = 0;
if (v.getClass().isArray()) {
Object[] a = (Object[]) v;
for (int i = 0; i < length; i++) {
Object n = a[length - i - 1];
if (n instanceof Number) {
total += ((Number) n).doubleValue();
}
}
} else {
List<Object> a = ExpressionUtils.toObjectList(v);
for (int i = 0; i < length; i++) {
Object n = a.get(length - i - 1);
if (n instanceof Number) {
total += ((Number) n).doubleValue();
}
}
}
return total;
}
}
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects an array of numbers");
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("description"); writer.value("Sums numbers in array a");
writer.key("params"); writer.value("array a");
writer.key("returns"); writer.value("number");
writer.endObject();
}
}

View File

@ -30,6 +30,7 @@ import com.metaweb.gridworks.expr.functions.math.Min;
import com.metaweb.gridworks.expr.functions.math.Mod;
import com.metaweb.gridworks.expr.functions.math.Pow;
import com.metaweb.gridworks.expr.functions.math.Round;
import com.metaweb.gridworks.expr.functions.math.Sum;
import com.metaweb.gridworks.expr.functions.strings.Contains;
import com.metaweb.gridworks.expr.functions.strings.Diff;
import com.metaweb.gridworks.expr.functions.strings.EndsWith;
@ -161,6 +162,7 @@ public class ControlFunctionRegistry {
registerFunction("ln", new Ln());
registerFunction("pow", new Pow());
registerFunction("exp", new Exp());
registerFunction("sum", new Sum());
registerFunction("and", new And());
registerFunction("or", new Or());

View File

@ -1,6 +1,8 @@
package com.metaweb.gridworks.gel.controls;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
@ -28,7 +30,7 @@ public class ForEach implements Control {
Object o = args[0].evaluate(bindings);
if (ExpressionUtils.isError(o)) {
return o;
} else if (o == null || !o.getClass().isArray()) {
} else if (o == null || (!o.getClass().isArray() && !(o instanceof Iterable<?>))) {
return new EvalError("First argument to forEach is not an array");
}
@ -36,17 +38,36 @@ public class ForEach implements Control {
Object oldValue = bindings.get(name);
try {
Object[] values = (Object[]) o;
List<Object> results = new ArrayList<Object>(values.length);
for (Object v : values) {
bindings.put(name, v);
Object r = args[2].evaluate(bindings);
results.add(r);
}
List<Object> results = null;
if (o.getClass().isArray()) {
Object[] values = (Object[]) o;
results = new ArrayList<Object>(values.length);
for (Object v : values) {
bindings.put(name, v);
Object r = args[2].evaluate(bindings);
results.add(r);
}
} else {
results = o instanceof Collection<?> ?
new ArrayList<Object>(ExpressionUtils.toObjectCollection(o).size()) :
new ArrayList<Object>();
Iterator<Object> i = ExpressionUtils.toObjectCollection(o).iterator();
while (i.hasNext()) {
Object v = i.next();
bindings.put(name, v);
Object r = args[2].evaluate(bindings);
results.add(r);
}
}
return results.toArray();
} finally {
if (oldValue != null) {

View File

@ -3,6 +3,7 @@ package com.metaweb.gridworks.model;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@ -26,6 +27,7 @@ public class ColumnModel implements Jsonizable {
transient protected Map<String, Column> _nameToColumn;
transient protected Map<Integer, Column> _cellIndexToColumn;
transient protected List<ColumnGroup> _rootColumnGroups;
transient protected List<String> _columnNames;
public ColumnModel() {
internalInitialize();
@ -63,6 +65,10 @@ public class ColumnModel implements Jsonizable {
public Column getColumnByCellIndex(int cellIndex) {
return _cellIndexToColumn.get(cellIndex);
}
public List<String> getColumnNames() {
return _columnNames;
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
@ -171,10 +177,12 @@ public class ColumnModel implements Jsonizable {
protected void generateMaps() {
_nameToColumn = new HashMap<String, Column>();
_cellIndexToColumn = new HashMap<Integer, Column>();
_columnNames = new ArrayList<String>();
for (Column column : columns) {
_nameToColumn.put(column.getName(), column);
_cellIndexToColumn.put(column.getCellIndex(), column);
_columnNames.add(column.getName());
}
}
}

View File

@ -52,6 +52,10 @@ public class Row implements HasFields, Jsonizable {
contextRows.get(0) : rowIndex;
return new Record(recordRowIndex, rowIndex);
} else if ("columnNames".equals(name)) {
Project project = (Project) bindings.get("project");
return project.columnModel.getColumnNames();
}
return null;
}

View File

@ -133,6 +133,21 @@ DataTableColumnHeaderUI.prototype._createMenuForColumnHeader = function(elmt) {
);
}
},
{
label: "1-bounded Numeric Log Facet",
click: function() {
ui.browsingEngine.addFacet(
"range",
{
"name" : self._column.name + ": log(max(1, value))",
"columnName" : self._column.name,
"expression" : "log(max(1, value))",
"mode" : "range"
}
);
}
},
{},
{
label: "Text Length Facet",
click: function() {