Add unshift(), join(), and setLength() methods to JsArray types.

Patch by: bobv

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6398 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/core/client/JsArray.java b/user/src/com/google/gwt/core/client/JsArray.java
index 9fa56f5..5129651 100644
--- a/user/src/com/google/gwt/core/client/JsArray.java
+++ b/user/src/com/google/gwt/core/client/JsArray.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -18,10 +18,10 @@
 /**
  * A simple wrapper around a homogeneous native array of
  * {@link JavaScriptObject} values.
- *
+ * 
  * This class may not be directly instantiated, and can only be returned from a
  * native method. For example,
- *
+ * 
  * <code>
  * native JsArray<JavaScriptObject> getNativeArray() /*-{
  *   return [
@@ -31,7 +31,7 @@
  *   ];
  * }-* /;
  * </code>
- *
+ * 
  * @param <T> the concrete type of object contained in this array
  */
 public class JsArray<T extends JavaScriptObject> extends JavaScriptObject {
@@ -41,18 +41,36 @@
 
   /**
    * Gets the object at a given index.
-   *
+   * 
    * @param index the index to be retrieved
-   * @return the object at the given index, or <code>null</code> if none
-   *         exists
+   * @return the object at the given index, or <code>null</code> if none exists
    */
   public final native T get(int index) /*-{
     return this[index];
   }-*/;
 
   /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final String join() {
+    // As per JS spec
+    return join(",");
+  }
+
+  /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final native String join(String separator) /*-{
+    return this.join(separator);
+  }-*/;
+
+  /**
    * Gets the length of the array.
-   *
+   * 
    * @return the array length
    */
   public final native int length() /*-{
@@ -68,10 +86,10 @@
 
   /**
    * Sets the object value at a given index.
-   *
+   * 
    * If the index is out of bounds, the value will still be set. The array's
    * length will be updated to encompass the bounds implied by the added object.
-   *
+   * 
    * @param index the index to be set
    * @param value the object to be stored
    */
@@ -80,11 +98,29 @@
   }-*/;
 
   /**
+   * Reset the length of the array.
+   * 
+   * @param newLength the new length of the array
+   */
+  public final native void setLength(int newLength) /*-{
+    this.length = newLength;
+  }-*/;
+
+  /**
    * Shifts the first value off the array.
+   * 
    * @return the shifted value
    */
   public final native T shift() /*-{
     return this.shift();
   }-*/;
-  
+
+  /**
+   * Shifts a value onto the beginning of the array.
+   * 
+   * @param value the value to the stored
+   */
+  public final native void unshift(T value) /*-{
+    this.unshift(value);
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/core/client/JsArrayBoolean.java b/user/src/com/google/gwt/core/client/JsArrayBoolean.java
index 27b57b8..6e7d3e3 100644
--- a/user/src/com/google/gwt/core/client/JsArrayBoolean.java
+++ b/user/src/com/google/gwt/core/client/JsArrayBoolean.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -17,10 +17,10 @@
 
 /**
  * A simple wrapper around a homogeneous native array of boolean values.
- *
+ * 
  * This class may not be directly instantiated, and can only be returned from a
  * native method. For example,
- *
+ * 
  * <code>
  * native JsArrayBoolean getNativeArray() /*-{
  *   return [true, false, true];
@@ -34,21 +34,40 @@
 
   /**
    * Gets the value at a given index.
-   *
+   * 
    * If an undefined or non-boolean value exists at the given index, a
    * type-conversion error will occur in hosted mode and unpredictable behavior
    * may occur in web mode.
-   *
+   * 
    * @param index the index to be retrieved
    * @return the value at the given index
    */
   public final native boolean get(int index) /*-{
     return this[index];
   }-*/;
-  
+
+  /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final String join() {
+    // As per JS spec
+    return join(",");
+  }
+
+  /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final native String join(String separator) /*-{
+    return this.join(separator);
+  }-*/;
+
   /**
    * Gets the length of the array.
-   *
+   * 
    * @return the array length
    */
   public final native int length() /*-{
@@ -64,10 +83,10 @@
 
   /**
    * Sets the value value at a given index.
-   *
+   * 
    * If the index is out of bounds, the value will still be set. The array's
    * length will be updated to encompass the bounds implied by the added value.
-   *
+   * 
    * @param index the index to be set
    * @param value the value to be stored
    */
@@ -76,11 +95,29 @@
   }-*/;
 
   /**
+   * Reset the length of the array.
+   * 
+   * @param newLength the new length of the array
+   */
+  public final native void setLength(int newLength) /*-{
+    this.length = newLength;
+  }-*/;
+
+  /**
    * Shifts the first value off the array.
+   * 
    * @return the shifted value
    */
   public final native boolean shift() /*-{
     return this.shift();
   }-*/;
 
+  /**
+   * Shifts a value onto the beginning of the array.
+   * 
+   * @param value the value to the stored
+   */
+  public final native void unshift(boolean value) /*-{
+    this.unshift(value);
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/core/client/JsArrayInteger.java b/user/src/com/google/gwt/core/client/JsArrayInteger.java
index 65b0bb2..c852842 100644
--- a/user/src/com/google/gwt/core/client/JsArrayInteger.java
+++ b/user/src/com/google/gwt/core/client/JsArrayInteger.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -17,10 +17,10 @@
 
 /**
  * A simple wrapper around a homogeneous native array of integer values.
- *
+ * 
  * This class may not be directly instantiated, and can only be returned from a
  * native method. For example,
- *
+ * 
  * <code>
  * native JsArrayInteger getNativeArray() /*-{
  *   return [1, 2, 3];
@@ -34,12 +34,12 @@
 
   /**
    * Gets the value at a given index.
-   *
+   * 
    * If no value exists at the given index, a type-conversion error will occur
    * in hosted mode and unpredictable behavior may occur in web mode. If the
    * numeric value returned is non-integral, it will cause a warning in hosted
    * mode, and may affect the results of mathematical expressions.
-   *
+   * 
    * @param index the index to be retrieved
    * @return the value at the given index
    */
@@ -48,8 +48,27 @@
   }-*/;
 
   /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final String join() {
+    // As per JS spec
+    return join(",");
+  }
+
+  /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final native String join(String separator) /*-{
+    return this.join(separator);
+  }-*/;
+
+  /**
    * Gets the length of the array.
-   *
+   * 
    * @return the array length
    */
   public final native int length() /*-{
@@ -65,10 +84,10 @@
 
   /**
    * Sets the value value at a given index.
-   *
+   * 
    * If the index is out of bounds, the value will still be set. The array's
    * length will be updated to encompass the bounds implied by the added value.
-   *
+   * 
    * @param index the index to be set
    * @param value the value to be stored
    */
@@ -77,10 +96,29 @@
   }-*/;
 
   /**
+   * Reset the length of the array.
+   * 
+   * @param newLength the new length of the array
+   */
+  public final native void setLength(int newLength) /*-{
+    this.length = newLength;
+  }-*/;
+
+  /**
    * Shifts the first value off the array.
+   * 
    * @return the shifted value
    */
   public final native int shift() /*-{
     return this.shift();
   }-*/;
+
+  /**
+   * Shifts a value onto the beginning of the array.
+   * 
+   * @param value the value to the stored
+   */
+  public final native void unshift(int value) /*-{
+    this.unshift(value);
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/core/client/JsArrayNumber.java b/user/src/com/google/gwt/core/client/JsArrayNumber.java
index 6921d6f..21b96dd 100644
--- a/user/src/com/google/gwt/core/client/JsArrayNumber.java
+++ b/user/src/com/google/gwt/core/client/JsArrayNumber.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -17,13 +17,13 @@
 
 /**
  * A simple wrapper around a homogeneous native array of numeric values.
- *
+ * 
  * All native JavaScript numeric values are implicitly double-precision, so only
  * double values may be set and retrieved.
- *
+ * 
  * This class may not be directly instantiated, and can only be returned from a
  * native method. For example,
- *
+ * 
  * <code>
  * native JsArrayNumber getNativeArray() /*-{
  *   return [1.1, 2.2, 3.3];
@@ -31,17 +31,17 @@
  * </code>
  */
 public class JsArrayNumber extends JavaScriptObject {
-  
+
   protected JsArrayNumber() {
   }
 
   /**
    * Gets the value at a given index.
-   *
+   * 
    * If an undefined or non-numeric value exists at the given index, a
    * type-conversion error will occur in hosted mode and unpredictable behavior
    * may occur in web mode.
-   *
+   * 
    * @param index the index to be retrieved
    * @return the value at the given index
    */
@@ -50,8 +50,27 @@
   }-*/;
 
   /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final String join() {
+    // As per JS spec
+    return join(",");
+  }
+
+  /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final native String join(String separator) /*-{
+    return this.join(separator);
+  }-*/;
+
+  /**
    * Gets the length of the array.
-   *
+   * 
    * @return the array length
    */
   public final native int length() /*-{
@@ -67,10 +86,10 @@
 
   /**
    * Sets the value value at a given index.
-   *
+   * 
    * If the index is out of bounds, the value will still be set. The array's
    * length will be updated to encompass the bounds implied by the added value.
-   *
+   * 
    * @param index the index to be set
    * @param value the value to be stored
    */
@@ -79,10 +98,29 @@
   }-*/;
 
   /**
+   * Reset the length of the array.
+   * 
+   * @param newLength the new length of the array
+   */
+  public final native void setLength(int newLength) /*-{
+    this.length = newLength;
+  }-*/;
+
+  /**
    * Shifts the first value off the array.
+   * 
    * @return the shifted value
    */
   public final native double shift() /*-{
     return this.shift();
   }-*/;
+
+  /**
+   * Shifts a value onto the beginning of the array.
+   * 
+   * @param value the value to the stored
+   */
+  public final native void unshift(double value) /*-{
+    this.unshift(value);
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/core/client/JsArrayString.java b/user/src/com/google/gwt/core/client/JsArrayString.java
index 9518c12..3607649 100644
--- a/user/src/com/google/gwt/core/client/JsArrayString.java
+++ b/user/src/com/google/gwt/core/client/JsArrayString.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -17,10 +17,10 @@
 
 /**
  * A simple wrapper around a homogeneous native array of string values.
- *
+ * 
  * This class may not be directly instantiated, and can only be returned from a
  * native method. For example,
- *
+ * 
  * <code>
  * native JsArrayString getNativeArray() /*-{
  *   return ['foo', 'bar', 'baz'];
@@ -34,7 +34,7 @@
 
   /**
    * Gets the value at a given index.
-   *
+   * 
    * @param index the index to be retrieved
    * @return the value at the given index, or <code>null</code> if none exists
    */
@@ -43,8 +43,27 @@
   }-*/;
 
   /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final String join() {
+    // As per JS spec
+    return join(",");
+  }
+
+  /**
+   * Convert each element of the array to a String and join them with a comma
+   * separator. The value returned from this method may vary between browsers
+   * based on how JavaScript values are converted into strings.
+   */
+  public final native String join(String separator) /*-{
+    return this.join(separator);
+  }-*/;
+
+  /**
    * Gets the length of the array.
-   *
+   * 
    * @return the array length
    */
   public final native int length() /*-{
@@ -60,10 +79,10 @@
 
   /**
    * Sets the value value at a given index.
-   *
+   * 
    * If the index is out of bounds, the value will still be set. The array's
    * length will be updated to encompass the bounds implied by the added value.
-   *
+   * 
    * @param index the index to be set
    * @param value the value to be stored
    */
@@ -72,10 +91,29 @@
   }-*/;
 
   /**
+   * Reset the length of the array.
+   * 
+   * @param newLength the new length of the array
+   */
+  public final native void setLength(int newLength) /*-{
+    this.length = newLength;
+  }-*/;
+
+  /**
    * Shifts the first value off the array.
+   * 
    * @return the shifted value
    */
   public final native String shift() /*-{
     return this.shift();
   }-*/;
+
+  /**
+   * Shifts a value onto the beginning of the array.
+   * 
+   * @param value the value to the stored
+   */
+  public final native void unshift(String value) /*-{
+    this.unshift(value);
+  }-*/;
 }
diff --git a/user/test/com/google/gwt/core/client/JsArrayTest.java b/user/test/com/google/gwt/core/client/JsArrayTest.java
index a06bf8e..d20f51c 100644
--- a/user/test/com/google/gwt/core/client/JsArrayTest.java
+++ b/user/test/com/google/gwt/core/client/JsArrayTest.java
@@ -50,6 +50,9 @@
     JsPoint p1 = jsArray.get(1);
     JsPoint p2 = jsArray.get(2);
 
+    assertEquals("JsPoint,JsPoint,JsPoint", jsArray.join());
+    assertEquals("JsPoint:JsPoint:JsPoint", jsArray.join(":"));
+
     assertEquals(0, p0.x());
     assertEquals(1, p0.y());
     assertEquals(2, p1.x());
@@ -77,6 +80,9 @@
       } catch (Throwable e) {
       }
     }
+
+    jsArray.setLength(0);
+    assertEquals(0, jsArray.length());
   }
 
   public void testJsArrayBoolean() {
@@ -89,6 +95,9 @@
     assertEquals(false, jsArray.get(1));
     assertEquals(true, jsArray.get(2));
 
+    assertEquals("true,false,true", jsArray.join());
+    assertEquals("true:false:true", jsArray.join(":"));
+
     // Make sure getting the '3' element throws an exception in hosted mode
     // (this won't happen in web mode).
     if (!GWT.isScript()) {
@@ -114,7 +123,20 @@
         fail("Expected an exception getting an invalid value in hosted mode");
       } catch (Throwable e) {
       }
+    } else {
+      // Keep the length of the array sane for the remainer of the test
+      jsArray.set(4, false);
     }
+
+    // Add an element to the beginning of the array
+    jsArray.unshift(true);
+    assertEquals(6, jsArray.length());
+    assertTrue(jsArray.get(0));
+    assertTrue(jsArray.shift());
+    assertEquals(5, jsArray.length());
+
+    jsArray.setLength(0);
+    assertEquals(0, jsArray.length());
   }
 
   public void testJsArrayInteger() {
@@ -127,6 +149,9 @@
     assertEquals(1, jsArray.get(1));
     assertEquals(2, jsArray.get(2));
 
+    assertEquals("0,1,2", jsArray.join());
+    assertEquals("0:1:2", jsArray.join(":"));
+
     // Make sure getting the '3' element throws an exception in hosted mode
     // (this won't happen in web mode).
     if (!GWT.isScript()) {
@@ -152,7 +177,20 @@
         fail("Expected an exception getting an invalid value in hosted mode");
       } catch (Throwable e) {
       }
+    } else {
+      // Keep the length of the array sane for the remainer of the test
+      jsArray.set(4, 33);
     }
+
+    // Add an element to the beginning of the array
+    jsArray.unshift(42);
+    assertEquals(6, jsArray.length());
+    assertEquals(42, jsArray.get(0));
+    assertEquals(42, jsArray.shift());
+    assertEquals(5, jsArray.length());
+
+    jsArray.setLength(0);
+    assertEquals(0, jsArray.length());
   }
 
   public void testJsArrayNumber() {
@@ -165,6 +203,9 @@
     assertEquals(1.1, jsArray.get(1));
     assertEquals(2.2, jsArray.get(2));
 
+    assertEquals("0,1.1,2.2", jsArray.join());
+    assertEquals("0:1.1:2.2", jsArray.join(":"));
+
     // Make sure getting the '3' element throws an exception in hosted mode
     // (this won't happen in web mode).
     if (!GWT.isScript()) {
@@ -190,7 +231,20 @@
         fail("Expected an exception getting an invalid value in hosted mode");
       } catch (Throwable e) {
       }
+    } else {
+      // Keep the length of the array sane for the remainer of the test
+      jsArray.set(4, 4.4);
     }
+
+    // Add an element to the beginning of the array
+    jsArray.unshift(42.0);
+    assertEquals(6, jsArray.length());
+    assertEquals(42.0, jsArray.get(0));
+    assertEquals(42.0, jsArray.shift());
+    assertEquals(5, jsArray.length());
+
+    jsArray.setLength(0);
+    assertEquals(0, jsArray.length());
   }
 
   public void testJsArrayString() {
@@ -207,6 +261,9 @@
     assertEquals("bar", s1);
     assertEquals("baz", s2);
 
+    assertEquals("foo,bar,baz", jsArray.join());
+    assertEquals("foo:bar:baz", jsArray.join(":"));
+
     // Make sure the '3' element is null.
     assertNull(jsArray.get(3));
 
@@ -225,14 +282,27 @@
         fail("Expected an exception getting an invalid value in hosted mode");
       } catch (Throwable e) {
       }
+    } else {
+      // Keep the length of the array sane for the remainer of the test
+      jsArray.set(4, "quux");
     }
+
+    // Add an element to the beginning of the array
+    jsArray.unshift("42");
+    assertEquals(6, jsArray.length());
+    assertEquals("42", jsArray.get(0));
+    assertEquals("42", jsArray.shift());
+    assertEquals(5, jsArray.length());
+
+    jsArray.setLength(0);
+    assertEquals(0, jsArray.length());
   }
 
   private native JsArray<JsPoint> makeJsArray() /*-{
     return [
-      { x: 0, y: 1},
-      { x: 2, y: 3},
-      { x: 4, y: 5},
+      { x: 0, y: 1, toString: function() { return 'JsPoint';} },
+      { x: 2, y: 3, toString: function() { return 'JsPoint';} },
+      { x: 4, y: 5, toString: function() { return 'JsPoint';} },
     ];
   }-*/;