Author: johnh
Date: Thu Jul 28 21:12:45 2011
New Revision: 1152002
URL: http://svn.apache.org/viewvc?rev=1152002&view=rev
Log:
Improve exportJs() in the face of potentially nonexistent symbols.
When exportJs(...) is used in deferred-binding mode, its namespaces usually
don't already exist. Example for fictional API foo.bar.baz:
exportJs("foo.bar", [foo,foo.bar], {baz:"baz"}, 1);
This is problematic because the namespaced vars, when interpreted by the
browser, do not yet exist and thus throw an error. To get around this with the
root namespace, we prepended "window.", but this simply supports one-layer NS.
This CL changes the pattern to:
exportJs("foo.bar", { foo: "foo", bar: "bar" }, { baz: "baz" }, 1);
The export method uses the second argument's symbol map to generate/upsert
namespaces based on the possibly-obfuscated symbol expansions. Support in the
JS is provided for both new- and old-style (array and Object) for a time to
prevent version skew issues. The Array-based approach will be removed later.
Modified:
shindig/trunk/features/src/main/javascript/features/exportjs/exportjs.js
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java
Modified:
shindig/trunk/features/src/main/javascript/features/exportjs/exportjs.js
URL:
http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/exportjs/exportjs.js?rev=1152002&r1=1152001&r2=1152002&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/exportjs/exportjs.js
(original)
+++ shindig/trunk/features/src/main/javascript/features/exportjs/exportjs.js
Thu Jul 28 21:12:45 2011
@@ -65,8 +65,20 @@ function exportJs(namespace, components,
// Set up defer function queue.
var deferMap = ((window[JSL] = window[JSL] || {})[DEFER_KEY] =
window[JSL][DEFER_KEY] || {});
+ // TODO: Remove support for arrayStyle after a reasonable amount of time.
+ var arrayStyle = components.constructor === Array;
+
+ // New-style: object mapping. Doesn't require symbols be pre-defined.
+ // array/old-style supported only for transition; will be removed.
+ var rmap = {};
+ for (var rkey in components) {
+ if (components.hasOwnProperty(rkey)) {
+ rmap[components[rkey]] = rkey;
+ }
+ }
+
for (var i = 0, part; part = nsParts.shift(); i++) {
- base[part] = base[part] || components[i] || {};
+ base[part] = base[part] || (arrayStyle ? components[i] : base[rmap[part]])
|| {};
prevBase = base;
base = base[part];
}
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java?rev=1152002&r1=1152001&r2=1152002&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java
Thu Jul 28 21:12:45 2011
@@ -18,7 +18,6 @@
package org.apache.shindig.gadgets.js;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -36,7 +35,9 @@ import org.apache.shindig.gadgets.featur
import org.apache.shindig.gadgets.features.FeatureResource;
import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -135,74 +136,39 @@ public class ExportJsProcessor implement
private static class Input {
String namespace;
- List<String> components;
List<String> properties;
- private Input(String namespace, List<String> components) {
+ private Input(String namespace) {
this.namespace = namespace;
- this.components = components;
this.properties = Lists.newArrayList();
}
- static Input newGlobal() {
- return new Input(null, ImmutableList.<String>of());
- }
-
- static Input newLocal(String namespace, List<String> components) {
- return new Input(namespace, components);
- }
-
public String toExportStatement(boolean isJsload) {
StringBuilder result = new StringBuilder();
-
- // Local namespace.
- if (namespace != null) {
-
result.append(FUNCTION_NAME).append("('").append(namespace).append("',[");
- result.append(isJsload ? "window." : "");
- result.append(Joiner.on(',').join(components));
- result.append("],{");
- for (int i = 0; i < properties.size(); i++) {
- String prop = properties.get(i);
- if (i > 0) result.append(",");
- result.append(prop).append(":'").append(prop).append("'");
- }
- result.append("}");
- if (isJsload) {
- result.append(",1");
- }
- result.append(");");
-
- // Global/window namespace.
- } else {
- for (String prop : properties) {
- result.append(FUNCTION_NAME).append("(");
- result.append("'").append(prop).append("',[");
- result.append(isJsload ? "window." : "");
- result.append(prop);
- result.append("]");
- if (isJsload) {
- result.append(",{},1");
- }
- result.append(");");
- }
+ result.append(FUNCTION_NAME).append("('").append(namespace).append("',");
+ appendPropMap(result, Arrays.asList(namespace.split("\\.")));
+ result.append(',');
+ appendPropMap(result, properties);
+ if (isJsload) {
+ result.append(",1");
}
+ result.append(");");
return result.toString();
}
- }
-
- private List<String> expandNamespace(String namespace) {
- List<String> result = Lists.newArrayList();
- for (int from = 0; ;) {
- int idx = namespace.indexOf('.', from);
- if (idx >= 0) {
- result.add(namespace.substring(0, idx));
- from = idx + 1;
- } else {
- result.add(namespace);
- break;
+
+ private void appendPropMap(StringBuilder result, Iterable<String>
properties) {
+ result.append("{");
+ boolean first = true;
+ Iterator<String> propIterator = properties.iterator();
+ while (propIterator.hasNext()) {
+ String prop = propIterator.next();
+ if ("prototype".equals(prop)) continue;
+ if (!first) result.append(",");
+ first = false;
+ result.append(prop).append(":'").append(prop).append("'");
}
+ result.append("}");
}
- return result;
}
private Collection<Input> generateInputs(List<String> symbols) {
@@ -211,11 +177,13 @@ public class ExportJsProcessor implement
String ns = getNamespace(symbol);
Input input = result.get(ns);
if (input == null) {
- input = (ns != null) ? Input.newLocal(ns, expandNamespace(ns)) :
Input.newGlobal();
+ input = new Input(ns);
result.put(ns, input);
}
- String property = (ns != null) ? getProperty(symbol) : symbol;
- input.properties.add(property);
+ String property = getProperty(symbol);
+ if (property != null) {
+ input.properties.add(property);
+ }
}
return result.values();
}
@@ -226,7 +194,7 @@ public class ExportJsProcessor implement
*/
private String getNamespace(String symbol) {
int idx = symbol.lastIndexOf('.');
- return (idx >= 0) ? symbol.substring(0, idx) : null;
+ return (idx >= 0) ? symbol.substring(0, idx) : symbol;
}
/**
@@ -235,7 +203,7 @@ public class ExportJsProcessor implement
*/
private String getProperty(String symbol) {
int idx = symbol.lastIndexOf('.');
- return (idx >= 0) ? symbol.substring(idx + 1) : symbol;
+ return (idx >= 0) ? symbol.substring(idx + 1) : null;
}
}
Modified:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java?rev=1152002&r1=1152001&r2=1152002&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java
(original)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java
Thu Jul 28 21:12:45 2011
@@ -66,20 +66,18 @@ public class ExportJsProcessorTest {
private final List<String> EXPORTS_3 = ImmutableList.<String>of();
private final String EXPORT_STRING_1 =
- "exportJs('gadgets',[gadgets]);" +
- "exportJs('shindig',[shindig]);" +
- "exportJs('gadgets.rpc',[gadgets,gadgets.rpc],{call:'call'});" +
- "exportJs('shindig',[shindig],{random:'random'});";
+ "exportJs('gadgets',{gadgets:'gadgets'},{});" +
+ "exportJs('gadgets.rpc',{gadgets:'gadgets',rpc:'rpc'},{call:'call'});" +
+ "exportJs('shindig',{shindig:'shindig'},{random:'random'});";
private final String EXPORT_STRING_1_DEFER =
- "exportJs('gadgets',[window.gadgets],{},1);" +
- "exportJs('shindig',[window.shindig],{},1);" +
- "exportJs('gadgets.rpc',[window.gadgets,gadgets.rpc],{call:'call'},1);" +
- "exportJs('shindig',[window.shindig],{random:'random'},1);";
+ "exportJs('gadgets',{gadgets:'gadgets'},{},1);" +
+ "exportJs('gadgets.rpc',{gadgets:'gadgets',rpc:'rpc'},{call:'call'},1);" +
+ "exportJs('shindig',{shindig:'shindig'},{random:'random'},1);";
private final String EXPORT_STRING_2 =
- "exportJs('foo',[foo]);" +
- "exportJs('foo.prototype',[foo,foo.prototype],{bar:'bar'});";
+ "exportJs('foo',{foo:'foo'},{});" +
+ "exportJs('foo.prototype',{foo:'foo'},{bar:'bar'});";
private final String EXPORT_STRING_3 = "";