Coverage Report - org.as3collections.TypedCollection
 
Classes in this File Line Coverage Branch Coverage Complexity
TypedCollection
100%
47/47
N/A
0
 
 1  
 /*
 2  
  * Licensed under the MIT License
 3  
  * 
 4  
  * Copyright 2010 (c) Flávio Silva, http://flsilva.com
 5  
  *
 6  
  * Permission is hereby granted, free of charge, to any person
 7  
  * obtaining a copy of this software and associated documentation
 8  
  * files (the "Software"), to deal in the Software without
 9  
  * restriction, including without limitation the rights to use,
 10  
  * copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  
  * copies of the Software, and to permit persons to whom the
 12  
  * Software is furnished to do so, subject to the following
 13  
  * conditions:
 14  
  *
 15  
  * The above copyright notice and this permission notice shall be
 16  
  * included in all copies or substantial portions of the Software.
 17  
  *
 18  
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 19  
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 20  
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 21  
  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 22  
  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 23  
  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 24  
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 25  
  * OTHER DEALINGS IN THE SOFTWARE.
 26  
  * 
 27  
  * http://www.opensource.org/licenses/mit-license.php
 28  
  */
 29  
 
 30  1
 package org.as3collections 
 31  
 {
 32  
         import org.as3collections.utils.CollectionUtil;
 33  
         import org.as3coreaddendum.errors.ClassCastError;
 34  
         import org.as3coreaddendum.errors.UnsupportedOperationError;
 35  
         import org.as3coreaddendum.system.ITypeable;
 36  
         import org.as3utils.ReflectionUtil;
 37  
 
 38  
         /**
 39  
          * <p><code>TypedCollection</code> works as a wrapper for a collection.</p>
 40  
          * <p>Since ActionScript 3.0 does not support typed arrays, <code>TypedCollection</code> is a way to create typed collections.</p>
 41  
          * <p>It stores the <code>wrapCollection</code> constructor's argument internally.
 42  
          * So every method call to this class is forwarded to the <code>wrappedCollection</code> object.
 43  
          * The methods that need to be checked for the type of the elements are previously validated with the <code>validateType</code> or <code>validateCollection</code> method before forward the call.
 44  
          * If the type of an element requested to be added to this collection is incompatible with the type of the collection a <code>org.as3coreaddendum.errors.ClassCastError</code> is thrown.
 45  
          * The calls that are forwarded to the <code>wrappedCollection</code> returns the return of the <code>wrappedCollection</code> call.</p>
 46  
          * <p>The <code>TypedCollection.type</code> setter is not supported and will thrown an <code>UnsupportedOperationError</code> if used.</p>
 47  
          * 
 48  
          * @author Flávio Silva
 49  
          */
 50  
         public class TypedCollection implements ICollection, ITypeable
 51  
         {
 52  
                 private var _wrappedCollection: ICollection;
 53  
                 private var _type: *;
 54  
 
 55  
                 /**
 56  
                  * @inheritDoc
 57  
                  */
 58  
                 public function get allEquatable(): Boolean { return _wrappedCollection.allEquatable; }
 59  
 
 60  
                 /**
 61  
                  * Defines the acceptable type of the elements by this collection.
 62  
                  * <p>The setter is not supported and will thrown an <code>UnsupportedOperationError</code> if used.</p>
 63  
                  */
 64  
                 public function get type(): * { return _type; }
 65  
 
 66  
                 public function set type(value:*): void { throw new UnsupportedOperationError("Cannot change the collection type."); }
 67  
 
 68  
                 /**
 69  
                  * @private
 70  
                  */
 71  
                 protected function get wrappedCollection(): ICollection { return _wrappedCollection; }
 72  
 
 73  
                 /**
 74  
                  * Constructor, creates a new <code>TypedCollection</code> object.
 75  
                  * 
 76  
                  * @param         wrapCollection         the target collection to wrap.
 77  
                  * @param         type                         the type of the elements allowed by this collection.
 78  
                  * @throws         ArgumentError          if the <code>wrapCollection</code> argument is <code>null</code>.
 79  
                  * @throws         ArgumentError          if the <code>type</code> argument is <code>null</code>.
 80  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the types of one or more elements in the <code>wrapCollection</code> argument are incompatible with the <code>type</code> argument.
 81  
                  */
 82  
                 public function TypedCollection(wrapCollection:ICollection, type:*)
 83  1
                 {
 84  1
                         if (!wrapCollection) throw new ArgumentError("The 'wrapCollection' argument must not be 'null'.");
 85  1
                         if (type == null) throw new ArgumentError("The 'type' argument must not be 'null'.");
 86  
                         
 87  1
                         _type = type;
 88  1
                         validateCollection(wrapCollection);
 89  1
                         _wrappedCollection = wrapCollection;
 90  1
                 }
 91  
 
 92  
                 /**
 93  
                  * The element is validated with the <code>validateType</code> method to be forwarded to <code>wrappedCollection.add</code>.
 94  
                  * 
 95  
                  * @param          element         the element to forward to <code>wrappedCollection.add</code>.
 96  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the type of the element is incompatible with the type of this collection.
 97  
                  * @return         the return of the call <code>wrappedCollection.add</code>.
 98  
                  */
 99  
                 public function add(element:*): Boolean
 100  
                 {
 101  1
                         validateElement(element);
 102  1
                         return _wrappedCollection.add(element);
 103  
                 }
 104  
 
 105  
                 /**
 106  
                  * The collection is validated with the <code>validateCollection</code> method to be forwarded to <code>wrappedCollection.addAll</code>.
 107  
                  * 
 108  
                  * @param          collection         the collection to forward to <code>wrappedCollection.addAll</code>.
 109  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the types of one or more elements in the <code>collection</code> argument are incompatible with the type of this collection.
 110  
                  * @return         the return of the call <code>wrappedCollection.addAll</code>.
 111  
                  */
 112  
                 public function addAll(collection:ICollection): Boolean
 113  
                 {
 114  1
                         validateCollection(collection);
 115  1
                         return _wrappedCollection.addAll(collection);
 116  
                 }
 117  
 
 118  
                 /**
 119  
                  * Forwards the call to <code>wrappedCollection.clear</code>.
 120  
                  */
 121  
                 public function clear(): void
 122  
                 {
 123  1
                         _wrappedCollection.clear();
 124  1
                 }
 125  
 
 126  
                 /**
 127  
                  * Creates and return a new <code>TypedCollection</code> object with the clone of the <code>wrappedCollection</code> object.
 128  
                  * 
 129  
                  * @return         a new <code>TypedCollection</code> object with the clone of the <code>wrappedCollection</code> object.
 130  
                   */
 131  
                 public function clone(): *
 132  
                 {
 133  1
                         return new TypedCollection(_wrappedCollection.clone(), _type);
 134  
                 }
 135  
 
 136  
                 /**
 137  
                  * Forwards the call to <code>wrappedCollection.contains</code>.
 138  
                  * 
 139  
                  * @param          o
 140  
                  * @return         the return of the call <code>wrappedCollection.contains</code>.
 141  
                  */
 142  
                 public function contains(o:*): Boolean
 143  
                 {
 144  1
                         return _wrappedCollection.contains(o);
 145  
                 }
 146  
 
 147  
                 /**
 148  
                  * Forwards the call to <code>wrappedCollection.containsAll</code>.
 149  
                  * 
 150  
                  * @param collection
 151  
                  * @return         the return of the call <code>wrappedCollection.containsAll</code>.
 152  
                  */
 153  
                 public function containsAll(collection:ICollection): Boolean
 154  
                 {
 155  1
                         return _wrappedCollection.containsAll(collection);
 156  
                 }
 157  
 
 158  
                 /**
 159  
                  * This method first checks if <code>other</code> argument is a <code>TypedCollection</code>.
 160  
                  * If not it returns <code>false</code>. If <code>true</code> it checks the <code>type</code> property of both lists.
 161  
                  * If they are different it returns <code>false</code>.
 162  
                  * Otherwise it uses <code>CollectionUtil.equalNotConsideringOrder</code> method to perform equality, sending this list and <code>other</code> argument.
 163  
                  * 
 164  
                  * @param          other         the object to be compared for equality.
 165  
                  * @return         <code>true</code> if the arbitrary evaluation considers the objects equal.
 166  
                  * @see         org.as3collections.utils.CollectionUtil#equalNotConsideringOrder() CollectionUtil.equalNotConsideringOrder()
 167  
                  */
 168  
                 public function equals(other:*): Boolean
 169  
                 {
 170  1
                         if (this == other) return true;
 171  1
                         if (!ReflectionUtil.classPathEquals(this, other)) return false;
 172  
                         
 173  1
                         var otherList:TypedCollection = other as TypedCollection;
 174  1
                         if (type != otherList.type) return false;
 175  
                         
 176  1
                         return CollectionUtil.equalNotConsideringOrder(this, other);
 177  
                 }
 178  
 
 179  
                 /**
 180  
                  * Forwards the call to <code>wrappedCollection.isEmpty</code>.
 181  
                  * 
 182  
                  * @return         the return of the call <code>wrappedCollection.isEmpty</code>.
 183  
                   */
 184  
                 public function isEmpty(): Boolean
 185  
                 {
 186  1
                         return _wrappedCollection.isEmpty();
 187  
                 }
 188  
 
 189  
                 /**
 190  
                  * Forwards the call to <code>wrappedCollection.iterator</code>.
 191  
                  * 
 192  
                  * @return         the return of the call <code>wrappedCollection.iterator</code>.
 193  
                   */
 194  
                 public function iterator(): IIterator
 195  
                 {
 196  1
                         return _wrappedCollection.iterator();
 197  
                 }
 198  
 
 199  
                 /**
 200  
                  * Forwards the call to <code>wrappedCollection.remove</code>.
 201  
                  * 
 202  
                  * @param o
 203  
                  * @return         the return of the call <code>wrappedCollection.remove</code>.
 204  
                  */
 205  
                 public function remove(o:*): Boolean
 206  
                 {
 207  1
                         return _wrappedCollection.remove(o);
 208  
                 }
 209  
 
 210  
                 /**
 211  
                  * Forwards the call to <code>wrappedCollection.removeAll</code>.
 212  
                  * 
 213  
                  * @param collection
 214  
                  * @return         the return of the call <code>wrappedCollection.removeAll</code>.
 215  
                  */
 216  
                 public function removeAll(collection:ICollection): Boolean
 217  
                 {
 218  1
                         return _wrappedCollection.removeAll(collection);
 219  
                 }
 220  
 
 221  
                 /**
 222  
                  * Forwards the call to <code>wrappedCollection.retainAll</code>.
 223  
                  * 
 224  
                  * @param collection
 225  
                  * @return         the return of the call <code>wrappedCollection.retainAll</code>.
 226  
                  */
 227  
                 public function retainAll(collection:ICollection): Boolean
 228  
                 {
 229  1
                         return _wrappedCollection.retainAll(collection);
 230  
                 }
 231  
 
 232  
                 /**
 233  
                  * Forwards the call to <code>wrappedCollection.size</code>.
 234  
                  * 
 235  
                  * @return         the return of the call <code>wrappedCollection.size</code>.
 236  
                   */
 237  
                 public function size(): int
 238  
                 {
 239  1
                         return _wrappedCollection.size();
 240  
                 }
 241  
 
 242  
                 /**
 243  
                  * Forwards the call to <code>wrappedCollection.toArray</code>.
 244  
                  * 
 245  
                  * @return         the return of the call <code>wrappedCollection.toArray</code>.
 246  
                   */
 247  
                 public function toArray(): Array
 248  
                 {
 249  1
                         return _wrappedCollection.toArray();
 250  
                 }
 251  
 
 252  
                 /**
 253  
                  * Returns the string representation of this instance.
 254  
                  * <p>This method uses <code>CollectionUtil.toString</code> method.</p>
 255  
                  * 
 256  
                  * @return the string representation of this instance.
 257  
                   */
 258  
                 public function toString():String 
 259  
                 {
 260  1
                         return CollectionUtil.toString(this);
 261  
                 }
 262  
                 
 263  
                 /**
 264  
                  * @private
 265  
                  */
 266  
                 protected function isValidElement(element:*): Boolean
 267  
                 {
 268  1
                         return element is _type;
 269  
                 }
 270  
                 
 271  
                 /**
 272  
                  * @private
 273  
                  */
 274  
                 protected function validateCollection(collection:ICollection): void
 275  
                 {
 276  1
                         if (!collection || collection.isEmpty()) return;
 277  
                         
 278  1
                         var containsOnlyType:Boolean = CollectionUtil.containsOnlyType(collection, type, false);
 279  1
                         if (containsOnlyType) return;
 280  
                         
 281  1
                         var it:IIterator = collection.iterator();
 282  
                         var element:*;
 283  
                         
 284  1
                         while (it.hasNext())
 285  
                         {
 286  1
                                 element = it.next();
 287  1
                                 if (!isValidElement(element)) break;
 288  
                         }
 289  
                         
 290  1
                         var error:ClassCastError = getInvalidElementError(element);
 291  1
                         throw error;
 292  
                 }
 293  
                 
 294  
                 /**
 295  
                  * @private
 296  
                  */
 297  
                 protected function validateElement(element:*): void
 298  
                 {
 299  1
                         if (isValidElement(element)) return;
 300  
                         
 301  1
                         var error:ClassCastError = getInvalidElementError(element);
 302  1
                         throw error;
 303  
                 }
 304  
                 
 305  
                 /**
 306  
                  * @private
 307  
                  */
 308  
                 private function getInvalidElementError(element:*): ClassCastError
 309  
                 {
 310  1
                         var message:String = "Invalid element type. element: <" + element + ">\n";
 311  1
                         message += "element type: <" + ReflectionUtil.getClassPath(element) + ">\n";
 312  1
                         message += "expected type: <" + ReflectionUtil.getClassPath(_type) + ">";
 313  
                         
 314  1
                         return new ClassCastError(message);
 315  
                 }
 316  
 
 317  
         }
 318  
 
 319  
 }