View Javadoc

1   /*
2    * $Id: DefaultGroovyMethods.java 4598 2006-12-22 20:21:21Z blackdrag $
3    *
4    * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5    *
6    * Redistribution and use of this software and associated documentation
7    * ("Software"), with or without modification, are permitted provided that the
8    * following conditions are met:
9    *  1. Redistributions of source code must retain copyright statements and
10   * notices. Redistributions must also contain a copy of this document.
11   *  2. Redistributions in binary form must reproduce the above copyright
12   * notice, this list of conditions and the following disclaimer in the
13   * documentation and/or other materials provided with the distribution.
14   *  3. The name "groovy" must not be used to endorse or promote products
15   * derived from this Software without prior written permission of The Codehaus.
16   * For written permission, please contact info@codehaus.org.
17   *  4. Products derived from this Software may not be called "groovy" nor may
18   * "groovy" appear in their names without prior written permission of The
19   * Codehaus. "groovy" is a registered trademark of The Codehaus.
20   *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
23   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
26   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32   * DAMAGE.
33   *
34   */
35  package org.codehaus.groovy.runtime;
36  
37  import groovy.lang.*;
38  import groovy.util.CharsetToolkit;
39  import groovy.util.ClosureComparator;
40  import groovy.util.OrderBy;
41  
42  import java.io.*;
43  import java.lang.reflect.Array;
44  import java.lang.reflect.Field;
45  import java.lang.reflect.Modifier;
46  import java.lang.reflect.Proxy;
47  import java.math.BigDecimal;
48  import java.math.BigInteger;
49  import java.net.MalformedURLException;
50  import java.net.ServerSocket;
51  import java.net.Socket;
52  import java.net.URI;
53  import java.net.URISyntaxException;
54  import java.net.URL;
55  import java.security.AccessController;
56  import java.security.PrivilegedAction;
57  import java.util.*;
58  import java.util.logging.Logger;
59  import java.util.regex.Matcher;
60  import java.util.regex.Pattern;
61  
62  import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
63  import org.codehaus.groovy.runtime.typehandling.NumberMath;
64  import org.codehaus.groovy.tools.RootLoader;
65  import org.w3c.dom.NodeList;
66  
67  /***
68   * This class defines all the new groovy methods which appear on normal JDK
69   * classes inside the Groovy environment. Static methods are used with the
70   * first parameter the destination class.
71   *
72   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
73   * @author Jeremy Rayner
74   * @author Sam Pullara
75   * @author Rod Cope
76   * @author Guillaume Laforge
77   * @author John Wilson
78   * @author Hein Meling
79   * @author Dierk Koenig
80   * @author Pilho Kim
81   * @author Marc Guillemot
82   * @author Russel Winder
83   * @author bing ran
84   * @author Jochen Theodorou
85   * @version $Revision: 4598 $
86   */
87  public class DefaultGroovyMethods {
88  
89      private static final Logger LOG = Logger.getLogger(DefaultGroovyMethods.class.getName());
90      private static final Integer ONE = new Integer(1);
91  
92      /***
93       * Identity check. Since == is overridden in Groovy with the meaning of equality
94       * we need some fallback to check for object identity.
95       *
96       * @param self
97       * @param other
98       * @return true if self and other are identical, false otherwise
99       */
100     public static boolean is(Object self, Object other) {
101         return self == other;
102     }
103 
104     /***
105      * Allows the closure to be called for the object reference self
106      *
107      * @param self    the object to have a closure act upon
108      * @param closure the closure to call on the object
109      * @return result of calling the closure
110      */
111     public static Object identity(Object self, Closure closure) {
112         final Closure clonedClosure = (Closure) closure.clone();
113         clonedClosure.setDelegate(self);
114         return clonedClosure.call(self);
115     }
116 
117     /***
118      * Allows the subscript operator to be used to lookup dynamic property values.
119      * <code>bean[somePropertyNameExpression]</code>. The normal property notation
120      * of groovy is neater and more concise but only works with compile-time known
121      * property names.
122      *
123      * @param self the object to act upon
124      */
125     public static Object getAt(Object self, String property) {
126         return InvokerHelper.getProperty(self, property);
127     }
128 
129     /***
130      * Allows the subscript operator to be used to set dynamically named property values.
131      * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
132      * of groovy is neater and more concise but only works with property names which
133      * are known at compile time.
134      *
135      * @param self     the object to act upon
136      * @param property the name of the property to set
137      * @param newValue the value to set
138      */
139     public static void putAt(Object self, String property, Object newValue) {
140         InvokerHelper.setProperty(self, property, newValue);
141     }
142 
143     /***
144      * Generates a detailed dump string of an object showing its class,
145      * hashCode and fields
146      */
147     public static String dump(Object self) {
148         if (self == null) {
149             return "null";
150         }
151         StringBuffer buffer = new StringBuffer("<");
152         Class klass = self.getClass();
153         buffer.append(klass.getName());
154         buffer.append("@");
155         buffer.append(Integer.toHexString(self.hashCode()));
156         boolean groovyObject = self instanceof GroovyObject;
157 
158         /*jes this may be rewritten to use the new getProperties() stuff
159          * but the original pulls out private variables, whereas getProperties()
160          * does not. What's the real use of dump() here?
161          */
162         while (klass != null) {
163             Field[] fields = klass.getDeclaredFields();
164             for (int i = 0; i < fields.length; i++) {
165                 final Field field = fields[i];
166                 if ((field.getModifiers() & Modifier.STATIC) == 0) {
167                     if (groovyObject && field.getName().equals("metaClass")) {
168                         continue;
169                     }
170                     AccessController.doPrivileged(new PrivilegedAction() {
171                         public Object run() {
172                             field.setAccessible(true);
173                             return null;
174                         }
175                     });
176                     buffer.append(" ");
177                     buffer.append(field.getName());
178                     buffer.append("=");
179                     try {
180                         buffer.append(InvokerHelper.toString(field.get(self)));
181                     } catch (Exception e) {
182                         buffer.append(e);
183                     }
184                 }
185             }
186 
187             klass = klass.getSuperclass();
188         }
189 
190         /* here is a different implementation that uses getProperties(). I have left
191          * it commented out because it returns a slightly different list of properties;
192          * ie it does not return privates. I don't know what dump() really should be doing,
193          * although IMO showing private fields is a no-no
194          */
195         /*
196         List props = getProperties(self);
197             for(Iterator itr = props.keySet().iterator(); itr.hasNext(); ) {
198             String propName = itr.next().toString();
199 
200             // the original skipped this, so I will too
201             if(pv.getName().equals("metaClass")) continue;
202             if(pv.getName().equals("class")) continue;
203 
204             buffer.append(" ");
205             buffer.append(propName);
206             buffer.append("=");
207             try {
208                 buffer.append(InvokerHelper.toString(props.get(propName)));
209             }
210             catch (Exception e) {
211                 buffer.append(e);
212             }
213         }
214         */
215 
216         buffer.append(">");
217         return buffer.toString();
218     }
219 
220     /***
221      * Retrieves the list of {@link MetaProperty} objects for 'self' and wraps it
222      * in a list of {@link PropertyValue} objects that additionally provide
223      * the value for each property of 'self'.
224      *
225      * @param self the receiver object
226      * @return list of {@link PropertyValue} objects
227      * @see groovy.util.Expando#getMetaPropertyValues()
228      */
229     public static List getMetaPropertyValues(Object self) {
230         MetaClass metaClass = InvokerHelper.getMetaClass(self);
231         List mps = metaClass.getProperties();
232         List props = new ArrayList(mps.size());
233         for (Iterator itr = mps.iterator(); itr.hasNext();) {
234             MetaProperty mp = (MetaProperty) itr.next();
235             PropertyValue pv = new PropertyValue(self, mp);
236             props.add(pv);
237         }
238         return props;
239     }
240 
241     /***
242      * Convenience method that calls {@link #getMetaPropertyValues(Object)}(self)
243      * and provides the data in form of simple key/value pairs, i.e. without
244      * type() information.
245      *
246      * @param self the receiver object
247      * @return meta properties as Map of key/value pairs
248      */
249     public static Map getProperties(Object self) {
250         List metaProps = getMetaPropertyValues(self);
251         Map props = new HashMap(metaProps.size());
252 
253         for (Iterator itr = metaProps.iterator(); itr.hasNext();) {
254             PropertyValue pv = (PropertyValue) itr.next();
255             try {
256                 props.put(pv.getName(), pv.getValue());
257             } catch (Exception e) {
258                 LOG.throwing(self.getClass().getName(), "getProperty(" + pv.getName() + ")", e);
259             }
260         }
261         return props;
262     }
263 
264     /***
265      * Scoped use method
266      */
267     public static void use(Object self, Class categoryClass, Closure closure) {
268         GroovyCategorySupport.use(categoryClass, closure);
269     }
270 
271     /***
272      * Scoped use method with list of categories
273      */
274     public static void use(Object self, List categoryClassList, Closure closure) {
275         GroovyCategorySupport.use(categoryClassList, closure);
276     }
277 
278 
279     /***
280      * use() a list of categories, specifying the list as varargs:<br>
281      * use(CategoryClass1, CategoryClass2) { ... }<br>
282      * This method prevents the error of forgetting to wrap the the category
283      * classes in a list.
284      *
285      * @param self
286      * @param array
287      */
288     public static void use(Object self, Object[] array) {
289         if (array.length < 2)
290             throw new IllegalArgumentException(
291                     "Expecting at least 2 arguments, a category class and a Closure");
292         Closure closure;
293         try {
294             closure = (Closure) array[array.length - 1];
295         } catch (ClassCastException e) {
296             throw new IllegalArgumentException("Expecting a Closure to be the last argument");
297         }
298         List list = new ArrayList(array.length - 1);
299         for (int i = 0; i < array.length - 1; ++i)
300             list.add(array[i]);
301         GroovyCategorySupport.use(list, closure);
302     }
303 
304     /***
305      * Print to a console in interactive format
306      */
307     public static void print(Object self, Object value) {
308         System.out.print(InvokerHelper.toString(value));
309     }
310 
311     /***
312      * Print a linebreak to the standard out.
313      */
314     public static void println(Object self) {
315         System.out.println();
316     }
317 
318     /***
319      * Print to a console in interactive format along with a newline
320      */
321     public static void println(Object self, Object value) {
322         System.out.println(InvokerHelper.toString(value));
323     }
324 
325     /***
326      * Printf to a console.  Only works with JDK1.5 or later.
327      */
328     public static void printf(Object self, String format, Object[] values) {
329         if (System.getProperty("java.version").charAt(2) == '5') {
330             //
331             //  Cannot just do:
332             //
333             //        System.out.printf(format, values) ;
334             //
335             //  because this fails to compile on JDK1.4.x and earlier.  So until the entire world is using
336             //  JDK1.5 or later then we have to do things by reflection so as to hide the use of printf
337             //  from the compiler.  In JDK1.5 you might try:
338             //
339             //        System.out.getClass().getMethod("printf", String.class, Object[].class).invoke(System.out, format, values) ;
340             //
341             //  but of course this doesn't work on JDK1.4 as it relies on varargs.  argh.  So we are
342             //  forced into:
343             //
344             try {
345                 System.out.getClass().getMethod("printf", new Class[]{String.class, Object[].class}).invoke(System.out, new Object[]{format, values});
346             } catch (NoSuchMethodException nsme) {
347                 throw new RuntimeException("getMethod threw a NoSuchMethodException.  This is impossible.");
348             } catch (IllegalAccessException iae) {
349                 throw new RuntimeException("invoke threw a IllegalAccessException.  This is impossible.");
350             } catch (java.lang.reflect.InvocationTargetException ite) {
351                 throw new RuntimeException("invoke threw a InvocationTargetException.  This is impossible.");
352             }
353         } else {
354             throw new RuntimeException("printf requires JDK1.5 or later.");
355         }
356     }
357 
358     /***
359      * Returns a formatted string using the specified format string and
360      * arguments.
361      * <p/>
362      * <p/>
363      * For examples, <pre>
364      *     printf ( "Hello, %s!\n" , [ "world" ] as String[] )
365      *     printf ( "Hello, %s!\n" , [ "Groovy" ])
366      *     printf ( "%d + %d = %d\n" , [ 1 , 2 , 1+2 ] as Integer[] )
367      *     printf ( "%d + %d = %d\n" , [ 3 , 3 , 3+3 ])
368      * <p/>
369      *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as Integer[] ) }
370      *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as int[] ) }
371      *     ( 0x41..0x45 ).each { printf ( "-- %c\n" , [ it ] as char[] ) }
372      *     ( 07..011 ).each { printf ( "-- %d\n" , [ it ] as byte[] ) }
373      *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as short[] ) }
374      *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as long[] ) }
375      *     ( 7..11 ).each { printf ( "-- %5.2f\n" , [ it ] as float[] ) }
376      *     ( 7..11 ).each { printf ( "-- %5.2g\n" , [ it ] as double[] ) }
377      * </pre>
378      * <p/>
379      *
380      * @param format A format string
381      * @param arg    Argument which is referenced by the format specifiers in the format
382      *               string.  The type of <code>arg</code> should be one of Object[], List,
383      *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
384      * @since JDK 1.5
385      */
386     public static void printf(Object self, String format, Object arg) {
387         if (arg instanceof Object[]) {
388             printf(self, format, (Object[]) arg);
389             return;
390         } else if (arg instanceof List) {
391             printf(self, format, ((List) arg).toArray());
392             return;
393         } else if (!arg.getClass().isArray()) {
394             Object[] o = (Object[]) java.lang.reflect.Array.newInstance(arg.getClass(), 1);
395             o[0] = arg;
396             printf(self, format, o);
397             return;
398         }
399 
400         Object[] ans = null;
401         String elemType = arg.getClass().getName();
402         if (elemType.equals("[I")) {
403             int[] ia = (int[]) arg;
404             ans = new Integer[ia.length];
405             for (int i = 0; i < ia.length; i++) {
406                 ans[i] = new Integer(ia[i]);
407             }
408         } else if (elemType.equals("[C")) {
409             char[] ia = (char[]) arg;
410             ans = new Character[ia.length];
411             for (int i = 0; i < ia.length; i++) {
412                 ans[i] = new Character(ia[i]);
413             }
414         } else if (elemType.equals("[Z")) {
415             boolean[] ia = (boolean[]) arg;
416             ans = new Boolean[ia.length];
417             for (int i = 0; i < ia.length; i++) {
418                 ans[i] = new Boolean(ia[i]);
419             }
420         } else if (elemType.equals("[B")) {
421             byte[] ia = (byte[]) arg;
422             ans = new Byte[ia.length];
423             for (int i = 0; i < ia.length; i++) {
424                 ans[i] = new Byte(ia[i]);
425             }
426         } else if (elemType.equals("[S")) {
427             short[] ia = (short[]) arg;
428             ans = new Short[ia.length];
429             for (int i = 0; i < ia.length; i++) {
430                 ans[i] = new Short(ia[i]);
431             }
432         } else if (elemType.equals("[F")) {
433             float[] ia = (float[]) arg;
434             ans = new Float[ia.length];
435             for (int i = 0; i < ia.length; i++) {
436                 ans[i] = new Float(ia[i]);
437             }
438         } else if (elemType.equals("[J")) {
439             long[] ia = (long[]) arg;
440             ans = new Long[ia.length];
441             for (int i = 0; i < ia.length; i++) {
442                 ans[i] = new Long(ia[i]);
443             }
444         } else if (elemType.equals("[D")) {
445             double[] ia = (double[]) arg;
446             ans = new Double[ia.length];
447             for (int i = 0; i < ia.length; i++) {
448                 ans[i] = new Double(ia[i]);
449             }
450         } else {
451             throw new RuntimeException("printf(String," + arg + ")");
452         }
453         printf(self, format, (Object[]) ans);
454     }
455 
456 
457     /***
458      * @return a String that matches what would be typed into a terminal to
459      *         create this object. e.g. [1, 'hello'].inspect() -> [1, "hello"]
460      */
461     public static String inspect(Object self) {
462         return InvokerHelper.inspect(self);
463     }
464 
465     /***
466      * Print to a console in interactive format
467      */
468     public static void print(Object self, PrintWriter out) {
469         if (out == null) {
470             out = new PrintWriter(System.out);
471         }
472         out.print(InvokerHelper.toString(self));
473     }
474 
475     /***
476      * Print to a console in interactive format
477      *
478      * @param out the PrintWriter used for printing
479      */
480     public static void println(Object self, PrintWriter out) {
481         if (out == null) {
482             out = new PrintWriter(System.out);
483         }
484         InvokerHelper.invokeMethod(self, "print", out);
485         out.println();
486     }
487 
488     /***
489      * Provide a dynamic method invocation method which can be overloaded in
490      * classes to implement dynamic proxies easily.
491      */
492     public static Object invokeMethod(Object object, String method, Object arguments) {
493         return InvokerHelper.invokeMethod(object, method, arguments);
494     }
495 
496     // isCase methods
497     //-------------------------------------------------------------------------
498     public static boolean isCase(Object caseValue, Object switchValue) {
499         return caseValue.equals(switchValue);
500     }
501 
502     public static boolean isCase(String caseValue, Object switchValue) {
503         if (switchValue == null) {
504             return caseValue == null;
505         }
506         return caseValue.equals(switchValue.toString());
507     }
508 
509     public static boolean isCase(Class caseValue, Object switchValue) {
510         if (switchValue instanceof Class) {
511             Class val = (Class) switchValue;
512             return caseValue.isAssignableFrom(val);
513         }
514         return caseValue.isInstance(switchValue);
515     }
516 
517     public static boolean isCase(Collection caseValue, Object switchValue) {
518         return caseValue.contains(switchValue);
519     }
520 
521     public static boolean isCase(Pattern caseValue, Object switchValue) {
522         if (switchValue == null) {
523             return caseValue == null;
524         }
525         final Matcher matcher = caseValue.matcher(switchValue.toString());
526         if (matcher.matches()) {
527             RegexSupport.setLastMatcher(matcher);
528             return true;
529         } else {
530             return false;
531         }
532     }
533 
534     // Collection based methods
535     //-------------------------------------------------------------------------
536 
537     public static Collection unique(Collection self) {
538         if (self instanceof Set)
539             return self;
540         List answer = new ArrayList();
541         NumberComparator comparator = new NumberComparator();
542         for (Iterator it = self.iterator(); it.hasNext();) {
543             Object o = it.next();
544             boolean duplicated = false;
545             for (Iterator it2 = answer.iterator(); it2.hasNext();) {
546                 Object o2 = it2.next();
547                 if (comparator.compare(o, o2) == 0) {
548                     duplicated = true;
549                     break;
550                 }
551             }
552             if (!duplicated)
553                 answer.add(o);
554         }
555         self.clear();
556         self.addAll(answer);
557         return self;
558     }
559 
560     /***
561      * A convenience method for making a collection unique using a closure as a comparator
562      * (by Michael Baehr)
563      *
564      * @param self    a Collection
565      * @param closure a Closure used as a comparator
566      * @return self   without any duplicates
567      */
568     public static Collection unique(Collection self, Closure closure) {
569         if (self instanceof Set)
570             return self;
571         // use a comparator of one item or two
572         int params = closure.getMaximumNumberOfParameters();
573         if (params == 1) {
574             unique(self, new OrderBy(closure));
575         } else {
576             unique(self, new ClosureComparator(closure));
577         }
578         return self;
579     }
580 
581     /***
582      * Remove all duplicates from a given Collection.
583      * Works on the receiver object and returns it.
584      * The order of members in the Collection are compared by the given Comparator.
585      * For each duplicate, the first member which is returned
586      * by the given Collection's iterator is retained, but all other ones are removed.
587      * The given Collection's original order is preserved.
588      * <p/>
589      * <code><pre>
590      *     class Person {
591      *         @Property fname, lname
592      *         public String toString() {
593      *             return fname + " " + lname
594      *         }
595      *     }
596      * <p/>
597      *     class PersonComparator implements Comparator {
598      *         public int compare(Object o1, Object o2) {
599      *             Person p1 = (Person) o1
600      *             Person p2 = (Person) o2
601      *             if (p1.lname != p2.lname)
602      *                 return p1.lname.compareTo(p2.lname)
603      *             else
604      *                 return p1.fname.compareTo(p2.fname)
605      *         }
606      * <p/>
607      *         public boolean equals(Object obj) {
608      *             return this.equals(obj)
609      *         }
610      *     }
611      * <p/>
612      *     Person a = new Person(fname:"John", lname:"Taylor")
613      *     Person b = new Person(fname:"Clark", lname:"Taylor")
614      *     Person c = new Person(fname:"Tom", lname:"Cruz")
615      *     Person d = new Person(fname:"Clark", lname:"Taylor")
616      * <p/>
617      *     def list = [a, b, c, d]
618      *     List list2 = list.unique(new PersonComparator())
619      *     assert( list2 == list && list == [a, b, c] )
620      * <p/>
621      * </pre></code>
622      *
623      * @param self       a Collection
624      * @param comparator a Comparator.
625      * @return self       without duplicates
626      */
627     public static Collection unique(Collection self, Comparator comparator) {
628         if (self instanceof Set)
629             return self;
630         List answer = new ArrayList();
631         for (Iterator it = self.iterator(); it.hasNext();) {
632             Object o = it.next();
633             boolean duplicated = false;
634             for (Iterator it2 = answer.iterator(); it2.hasNext();) {
635                 Object o2 = it2.next();
636                 if (comparator.compare(o, o2) == 0) {
637                     duplicated = true;
638                     break;
639                 }
640             }
641             if (!duplicated)
642                 answer.add(o);
643         }
644         self.clear();
645         self.addAll(answer);
646         return self;
647     }
648 
649     /***
650      * Allows objects to be iterated through using a closure
651      *
652      * @param self    the object over which we iterate
653      * @param closure the closure applied on each element found
654      */
655     public static void each(Object self, Closure closure) {
656         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
657             closure.call(iter.next());
658         }
659     }
660 
661     /***
662      * Allows object to be iterated through a closure with a counter
663      *
664      * @param self    an Object
665      * @param closure a Closure
666      */
667     public static void eachWithIndex(Object self, Closure closure) {
668         int counter = 0;
669         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
670             closure.call(new Object[]{iter.next(), new Integer(counter++)});
671         }
672     }
673 
674     /***
675      * Allows objects to be iterated through using a closure
676      *
677      * @param self    the collection over which we iterate
678      * @param closure the closure applied on each element of the collection
679      */
680     public static void each(Collection self, Closure closure) {
681         for (Iterator iter = self.iterator(); iter.hasNext();) {
682             closure.call(iter.next());
683         }
684     }
685 
686     /***
687      * Allows a Map to be iterated through using a closure. If the
688      * closure takes one parameter then it will be passed the Map.Entry
689      * otherwise if the closure takes two parameters then it will be
690      * passed the key and the value.
691      *
692      * @param self    the map over which we iterate
693      * @param closure the closure applied on each entry of the map
694      */
695     public static void each(Map self, Closure closure) {
696         for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
697             Map.Entry entry = (Map.Entry) iter.next();
698             callClosureForMapEntry(closure, entry);
699         }
700     }
701 
702 
703     /***
704      * Iterates over every element of a collection, and check whether a predicate is valid for all elements.
705      *
706      * @param self    the object over which we iterate
707      * @param closure the closure predicate used for matching
708      * @return true if every item in the collection matches the closure
709      *         predicate
710      */
711     public static boolean every(Object self, Closure closure) {
712         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
713             if (!DefaultTypeTransformation.castToBoolean(closure.call(iter.next()))) {
714                 return false;
715             }
716         }
717         return true;
718     }
719 
720     /***
721      * Iterates over every element of a collection, and check whether a predicate is valid for at least one element
722      *
723      * @param self    the object over which we iterate
724      * @param closure the closure predicate used for matching
725      * @return true if any item in the collection matches the closure predicate
726      */
727     public static boolean any(Object self, Closure closure) {
728         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
729             if (DefaultTypeTransformation.castToBoolean(closure.call(iter.next()))) {
730                 return true;
731             }
732         }
733         return false;
734     }
735 
736     /***
737      * Iterates over every element of the collection and return each object that matches
738      * the given filter - calling the isCase() method used by switch statements.
739      * This method can be used with different kinds of filters like regular expresions, classes, ranges etc.
740      *
741      * @param self   the object over which we iterate
742      * @param filter the filter to perform on the collection (using the isCase(object) method)
743      * @return a list of objects which match the filter
744      */
745     public static List grep(Object self, Object filter) {
746         List answer = new ArrayList();
747         MetaClass metaClass = InvokerHelper.getMetaClass(filter);
748         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
749             Object object = iter.next();
750             if (DefaultTypeTransformation.castToBoolean(metaClass.invokeMethod(filter, "isCase", object))) {
751                 answer.add(object);
752             }
753         }
754         return answer;
755     }
756 
757     /***
758      * Counts the number of occurencies of the given value inside this collection
759      *
760      * @param self  the collection within which we count the number of occurencies
761      * @param value the value
762      * @return the number of occurrencies
763      */
764     public static int count(Collection self, Object value) {
765         int answer = 0;
766         for (Iterator iter = self.iterator(); iter.hasNext();) {
767             if (DefaultTypeTransformation.compareEqual(iter.next(), value)) {
768                 ++answer;
769             }
770         }
771         return answer;
772     }
773 
774     /***
775      * Convert a collection to a List.
776      *
777      * @param self a collection
778      * @return a List
779      */
780     public static List toList(Collection self) {
781         List answer = new ArrayList(self.size());
782         answer.addAll(self);
783         return answer;
784     }
785 
786     /***
787      * Iterates through this object transforming each object into a new value using the closure
788      * as a transformer, returning a list of transformed values.
789      *
790      * @param self    the values of the object to map
791      * @param closure the closure used to map each element of the collection
792      * @return a List of the mapped values
793      */
794     public static List collect(Object self, Closure closure) {
795         return (List) collect(self, new ArrayList(), closure);
796     }
797 
798     /***
799      * Iterates through this object transforming each object into a new value using the closure
800      * as a transformer and adding it to the collection, returning the resulting collection.
801      *
802      * @param self       the values of the object to map
803      * @param collection the Collection to which the mapped values are added
804      * @param closure    the closure used to map each element of the collection
805      * @return the resultant collection
806      */
807     public static Collection collect(Object self, Collection collection, Closure closure) {
808         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
809             collection.add(closure.call(iter.next()));
810         }
811         return collection;
812     }
813 
814     /***
815      * Iterates through this collection transforming each entry into a new value using the closure
816      * as a transformer, returning a list of transformed values.
817      *
818      * @param self    a collection
819      * @param closure the closure used for mapping
820      * @return a List of the mapped values
821      */
822     public static List collect(Collection self, Closure closure) {
823         return (List) collect(self, new ArrayList(self.size()), closure);
824     }
825 
826     /***
827      * Iterates through this collection transforming each entry into a new value using the closure
828      * as a transformer, returning a list of transformed values.
829      *
830      * @param self       a collection
831      * @param collection the Collection to which the mapped values are added
832      * @param closure    the closure used to map each element of the collection
833      * @return the resultant collection
834      */
835     public static Collection collect(Collection self, Collection collection, Closure closure) {
836         for (Iterator iter = self.iterator(); iter.hasNext();) {
837             collection.add(closure.call(iter.next()));
838             if (closure.getDirective() == Closure.DONE) {
839                 break;
840             }
841         }
842         return collection;
843     }
844 
845     /***
846      * Iterates through this Map transforming each entry into a new value using the closure
847      * as a transformer, returning a list of transformed values.
848      *
849      * @param self       a Map
850      * @param collection the Collection to which the mapped values are added
851      * @param closure    the closure used for mapping, which can be with one(Map.Entry) or two(key, value) parameters
852      * @return a List of the mapped values
853      */
854     public static Collection collect(Map self, Collection collection, Closure closure) {
855         boolean isTwoParams = (closure.getParameterTypes().length == 2);
856         for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
857             if (isTwoParams) {
858                 Map.Entry entry = (Map.Entry) iter.next();
859                 collection.add(closure.call(new Object[]{entry.getKey(), entry.getValue()}));
860             } else {
861                 collection.add(closure.call(iter.next()));
862             }
863         }
864         return collection;
865     }
866 
867     /***
868      * Iterates through this Map transforming each entry into a new value using the closure
869      * as a transformer, returning a list of transformed values.
870      *
871      * @param self    a Map
872      * @param closure the closure used to map each element of the collection
873      * @return the resultant collection
874      */
875     public static List collect(Map self, Closure closure) {
876         return (List) collect(self, new ArrayList(self.size()), closure);
877     }
878 
879     /***
880      * Finds the first value matching the closure condition
881      *
882      * @param self    an Object with an iterator returning its values
883      * @param closure a closure condition
884      * @return the first Object found
885      */
886     public static Object find(Object self, Closure closure) {
887         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
888             Object value = iter.next();
889             if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
890                 return value;
891             }
892         }
893         return null;
894     }
895 
896     /***
897      * Finds the first value matching the closure condition
898      *
899      * @param self    a Collection
900      * @param closure a closure condition
901      * @return the first Object found
902      */
903     public static Object find(Collection self, Closure closure) {
904         for (Iterator iter = self.iterator(); iter.hasNext();) {
905             Object value = iter.next();
906             if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
907                 return value;
908             }
909         }
910         return null;
911     }
912 
913     /***
914      * Finds the first value matching the closure condition
915      *
916      * @param self    a Map
917      * @param closure a closure condition
918      * @return the first Object found
919      */
920     public static Object find(Map self, Closure closure) {
921         for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
922             Object value = iter.next();
923             if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
924                 return value;
925             }
926         }
927         return null;
928     }
929 
930     /***
931      * Finds all values matching the closure condition
932      *
933      * @param self    an Object with an Iterator returning its values
934      * @param closure a closure condition
935      * @return a List of the values found
936      */
937     public static List findAll(Object self, Closure closure) {
938         List answer = new ArrayList();
939         for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
940             Object value = iter.next();
941             if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
942                 answer.add(value);
943             }
944         }
945         return answer;
946     }
947 
948     /***
949      * Finds all values matching the closure condition
950      *
951      * @param self    a Collection
952      * @param closure a closure condition
953      * @return a List of the values found
954      */
955     public static List findAll(Collection self, Closure closure) {
956         List answer = new ArrayList(self.size());
957         for (Iterator iter = self.iterator(); iter.hasNext();) {
958             Object value = iter.next();
959             if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
960                 answer.add(value);
961             }
962         }
963         return answer;
964     }
965 
966     /***
967      * Finds all entries matching the closure condition. If the
968      * closure takes one parameter then it will be passed the Map.Entry
969      * otherwise if the closure takes two parameters then it will be
970      * passed the key and the value.
971      *
972      * @param self    a Map
973      * @param closure a closure condition applying on the entries
974      * @return a new subMap
975      */
976     public static Map findAll(Map self, Closure closure) {
977         Map answer = new HashMap(self.size());
978         for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
979             Map.Entry entry = (Map.Entry) iter.next();
980             if (DefaultTypeTransformation.castToBoolean(callClosureForMapEntry(closure, entry))) {
981                 answer.put(entry.getKey(), entry.getValue());
982             }
983         }
984         return answer;
985     }
986 
987     /***
988      * Groups all collection members into groups determined by the
989      * supplied mapping closure.
990      *
991      * @param self    a collection to group (no map)
992      * @param closure a closure mapping entries on keys
993      * @return a new Map grouped by keys
994      */
995     public static Map groupBy(Collection self, Closure closure) {
996         Map answer = new HashMap();
997         for (Iterator iter = self.iterator(); iter.hasNext();) {
998             groupCurrentElement(closure, answer, iter);
999         }
1000         return answer;
1001     }
1002 
1003     /***
1004      * Groups all map members into groups determined by the
1005      * supplied mapping closure.
1006      * 
1007      * @param self     a map to group
1008      * @param closure  a closure mapping entries on keys
1009      * @return         a new Map grouped by keys
1010      */
1011     /* Removed for 1.0, to be discussed for 1.1
1012     public static Map groupBy(Map self, Closure closure) {
1013         final Map answer = new HashMap();
1014         for (final Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
1015             groupCurrentElement(closure, answer, iter);
1016         }
1017         return answer;
1018     }
1019     */
1020     
1021     /***
1022      * Groups the current element of the iterator as determined
1023      * by the mapping closure.
1024      * 
1025      * @param closure  a closure mapping the current entry on a key
1026      * @param answer   the map containing the results
1027      * @param iter     the iterator from which the current element stems
1028      */   
1029     private static void groupCurrentElement(Closure closure, Map answer, Iterator iter) {
1030 	Object element = iter.next();
1031 	Object value = closure.call(element);
1032 	if (answer.containsKey(value)) {
1033 	    ((List) answer.get(value)).add(element);
1034 	} else {
1035 	    ArrayList groupedElements = new ArrayList();
1036 	    groupedElements.add(element);
1037 	    answer.put(value, groupedElements);
1038 	}
1039     }
1040     
1041     // internal helper method
1042     protected static Object callClosureForMapEntry(Closure closure, Map.Entry entry) {
1043         if (closure.getMaximumNumberOfParameters() == 2) {
1044             return closure.call(new Object[]{entry.getKey(), entry.getValue()});
1045         }
1046         return closure.call(entry);
1047     }
1048 
1049 
1050     /***
1051      * Iterates through the given collection, passing in the initial value to
1052      * the closure along with the current iterated item then passing into the
1053      * next iteration the value of the previous closure.
1054      *
1055      * @param self    a Collection
1056      * @param value   a value
1057      * @param closure a closure
1058      * @return the last value of the last iteration
1059      */
1060     public static Object inject(Collection self, Object value, Closure closure) {
1061         Object[] params = new Object[2];
1062         for (Iterator iter = self.iterator(); iter.hasNext();) {
1063             Object item = iter.next();
1064             params[0] = value;
1065             params[1] = item;
1066             value = closure.call(params);
1067         }
1068         return value;
1069     }
1070 
1071     /***
1072      * Iterates through the given array of objects, passing in the initial value to
1073      * the closure along with the current iterated item then passing into the
1074      * next iteration the value of the previous closure.
1075      *
1076      * @param self    an Object[]
1077      * @param value   a value
1078      * @param closure a closure
1079      * @return the last value of the last iteration
1080      */
1081     public static Object inject(Object[] self, Object value, Closure closure) {
1082         Object[] params = new Object[2];
1083         for (int i = 0; i < self.length; i++) {
1084             params[0] = value;
1085             params[1] = self[i];
1086             value = closure.call(params);
1087         }
1088         return value;
1089     }
1090 
1091     /***
1092      * Sums a collection of numeric values. <code>coll.sum()</code> is equivalent to:
1093      * <code>coll.inject(0) {value, item -> value + item}</code>.
1094      *
1095      * @param self Collection of values to add together.
1096      * @return The sum of all of the list itmems.
1097      */
1098     public static Object sum(Collection self) {
1099         Object result = null;
1100 
1101         if (self.size() == 0) return result;
1102 
1103         boolean isNumber = true;
1104 
1105         Class classref = null;
1106         try {
1107             classref = Class.forName("java.lang.Number");
1108         } catch (Exception ex) {
1109         }
1110 
1111         for (Iterator iter = self.iterator(); iter.hasNext();) {
1112             if (!classref.isInstance(iter.next())) {
1113                 isNumber = false;
1114                 break;
1115             }
1116         }
1117 
1118         if (isNumber) {
1119             result = new Integer(0);
1120         } else {
1121             result = new String();
1122         }
1123 
1124         Object[] param = new Object[1];
1125         for (Iterator iter = self.iterator(); iter.hasNext();) {
1126             param[0] = iter.next();
1127             MetaClass metaClass = InvokerHelper.getMetaClass(result);
1128             result = metaClass.invokeMethod(result, "plus", param);
1129         }
1130         return result;
1131     }
1132 
1133     /***
1134      * Sums the result of apply a closure to each item of a collection.
1135      * <code>coll.sum(closure)</code> is equivalent to:
1136      * <code>coll.collect(closure).sum()</code>.
1137      *
1138      * @param self    a Collection
1139      * @param closure a single parameter closure that returns a numeric value.
1140      * @return The sum of the values returned by applying the closure to each
1141      *         item of the list.
1142      */
1143     public static Object sum(Collection self, Closure closure) {
1144         Object result = new Integer(0);
1145         Object[] closureParam = new Object[1];
1146         Object[] plusParam = new Object[1];
1147         for (Iterator iter = self.iterator(); iter.hasNext();) {
1148             closureParam[0] = iter.next();
1149             plusParam[0] = closure.call(closureParam);
1150             MetaClass metaClass = InvokerHelper.getMetaClass(result);
1151             result = metaClass.invokeMethod(result, "plus", plusParam);
1152         }
1153         return result;
1154     }
1155 
1156     /***
1157      * Concatenates all of the items of the collection together with the given String as a separator
1158      *
1159      * @param self      a Collection of objects
1160      * @param separator a String separator
1161      * @return the joined String
1162      */
1163     public static String join(Collection self, String separator) {
1164         StringBuffer buffer = new StringBuffer();
1165         boolean first = true;
1166 
1167         if (separator == null) separator = "";
1168 
1169         for (Iterator iter = self.iterator(); iter.hasNext();) {
1170             Object value = iter.next();
1171             if (first) {
1172                 first = false;
1173             } else {
1174                 buffer.append(separator);
1175             }
1176             buffer.append(InvokerHelper.toString(value));
1177         }
1178         return buffer.toString();
1179     }
1180 
1181     /***
1182      * Concatenates all of the elements of the array together with the given String as a separator
1183      *
1184      * @param self      an array of Object
1185      * @param separator a String separator
1186      * @return the joined String
1187      */
1188     public static String join(Object[] self, String separator) {
1189         StringBuffer buffer = new StringBuffer();
1190         boolean first = true;
1191 
1192         if (separator == null) separator = "";
1193 
1194         for (int i = 0; i < self.length; i++) {
1195             String value = InvokerHelper.toString(self[i]);
1196             if (first) {
1197                 first = false;
1198             } else {
1199                 buffer.append(separator);
1200             }
1201             buffer.append(value);
1202         }
1203         return buffer.toString();
1204     }
1205 
1206     /***
1207      * Selects the maximum value found in the collection
1208      *
1209      * @param self a Collection
1210      * @return the maximum value
1211      */
1212     public static Object max(Collection self) {
1213         Object answer = null;
1214         for (Iterator iter = self.iterator(); iter.hasNext();) {
1215             Object value = iter.next();
1216             if (value != null) {
1217                 if (answer == null || ScriptBytecodeAdapter.compareGreaterThan(value, answer)) {
1218                     answer = value;
1219                 }
1220             }
1221         }
1222         return answer;
1223     }
1224 
1225     /***
1226      * Selects the maximum value found in the collection using the given comparator
1227      *
1228      * @param self       a Collection
1229      * @param comparator a Comparator
1230      * @return the maximum value
1231      */
1232     public static Object max(Collection self, Comparator comparator) {
1233         Object answer = null;
1234         for (Iterator iter = self.iterator(); iter.hasNext();) {
1235             Object value = iter.next();
1236             if (answer == null || comparator.compare(value, answer) > 0) {
1237                 answer = value;
1238             }
1239         }
1240         return answer;
1241     }
1242 
1243     /***
1244      * Selects the minimum value found in the collection
1245      *
1246      * @param self a Collection
1247      * @return the minimum value
1248      */
1249     public static Object min(Collection self) {
1250         Object answer = null;
1251         for (Iterator iter = self.iterator(); iter.hasNext();) {
1252             Object value = iter.next();
1253             if (value != null) {
1254                 if (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer)) {
1255                     answer = value;
1256                 }
1257             }
1258         }
1259         return answer;
1260     }
1261 
1262     /***
1263      * Selects the minimum value found in the collection using the given comparator
1264      *
1265      * @param self       a Collection
1266      * @param comparator a Comparator
1267      * @return the minimum value
1268      */
1269     public static Object min(Collection self, Comparator comparator) {
1270         Object answer = null;
1271         for (Iterator iter = self.iterator(); iter.hasNext();) {
1272             Object value = iter.next();
1273             if (answer == null || comparator.compare(value, answer) < 0) {
1274                 answer = value;
1275             }
1276         }
1277         return answer;
1278     }
1279 
1280     /***
1281      * Selects the minimum value found in the collection using the given closure as a comparator
1282      *
1283      * @param self    a Collection
1284      * @param closure a closure used as a comparator
1285      * @return the minimum value
1286      */
1287     public static Object min(Collection self, Closure closure) {
1288         int params = closure.getMaximumNumberOfParameters();
1289         if (params == 1) {
1290             Object answer = null;
1291             Object answer_value = null;
1292             for (Iterator iter = self.iterator(); iter.hasNext();) {
1293                 Object item = iter.next();
1294                 Object value = closure.call(item);
1295                 if (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer_value)) {
1296                     answer = item;
1297                     answer_value = value;
1298                 }
1299             }
1300             return answer;
1301         } else {
1302             return min(self, new ClosureComparator(closure));
1303         }
1304     }
1305 
1306     /***
1307      * Selects the maximum value found in the collection using the given closure as a comparator
1308      *
1309      * @param self    a Collection
1310      * @param closure a closure used as a comparator
1311      * @return the maximum value
1312      */
1313     public static Object max(Collection self, Closure closure) {
1314         int params = closure.getMaximumNumberOfParameters();
1315         if (params == 1) {
1316             Object answer = null;
1317             Object answer_value = null;
1318             for (Iterator iter = self.iterator(); iter.hasNext();) {
1319                 Object item = iter.next();
1320                 Object value = closure.call(item);
1321                 if (answer == null || ScriptBytecodeAdapter.compareLessThan(answer_value, value)) {
1322                     answer = item;
1323                     answer_value = value;
1324                 }
1325             }
1326             return answer;
1327         } else {
1328             return max(self, new ClosureComparator(closure));
1329         }
1330     }
1331 
1332     /***
1333      * Makes a String look like a Collection by adding support for the size() method
1334      *
1335      * @param text a String
1336      * @return the length of the String
1337      */
1338     public static int size(String text) {
1339         return text.length();
1340     }
1341 
1342     /***
1343      * Provide standard Groovy size() method for StringBuffers
1344      *
1345      * @param buffer a StringBuffer
1346      * @return the length of the StringBuffer
1347      */
1348     public static int size(StringBuffer buffer) {
1349         return buffer.length();
1350     }
1351 
1352     /***
1353      * Provide the standard Groovy size method
1354      */
1355     public static long size(File file) {
1356         return file.length();
1357     }
1358 
1359 
1360     /***
1361      * Provide the standard Groovy size method
1362      */
1363     public static long size(Matcher matcher) {
1364         return getCount(matcher);
1365     }
1366 
1367     /***
1368      * Makes an Array look like a Collection by adding support for the size() method
1369      *
1370      * @param self an Array of Object
1371      * @return the size of the Array
1372      */
1373     public static int size(Object[] self) {
1374         return self.length;
1375     }
1376 
1377     /***
1378      * Support the subscript operator for String.
1379      *
1380      * @param text  a String
1381      * @param index the index of the Character to get
1382      * @return the Character at the given index
1383      */
1384     public static CharSequence getAt(CharSequence text, int index) {
1385         index = normaliseIndex(index, text.length());
1386         return text.subSequence(index, index + 1);
1387     }
1388 
1389     /***
1390      * Support the subscript operator for String
1391      *
1392      * @param text a String
1393      * @return the Character object at the given index
1394      */
1395     public static String getAt(String text, int index) {
1396         index = normaliseIndex(index, text.length());
1397         return text.substring(index, index + 1);
1398     }
1399 
1400     /***
1401      * Support the range subscript operator for CharSequence
1402      *
1403      * @param text  a CharSequence
1404      * @param range a Range
1405      * @return the subsequence CharSequence
1406      */
1407     public static CharSequence getAt(CharSequence text, Range range) {
1408         int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), text.length());
1409         int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), text.length());
1410 
1411         // If this is a backwards range, reverse the arguments to substring.
1412         if (from > to) {
1413             int tmp = from;
1414             from = to;
1415             to = tmp;
1416         }
1417 
1418         return text.subSequence(from, to + 1);
1419     }
1420 
1421     /***
1422      * Support the range subscript operator for CharSequence or StringBuffer with IntRange
1423      *
1424      * @param text  a CharSequence
1425      * @param range an IntRange
1426      * @return the subsequence CharSequence
1427      */
1428     public static CharSequence getAt(CharSequence text, IntRange range) {
1429         return getAt(text, (Range) range);
1430     }
1431 
1432     /***
1433      * Support the range subscript operator for String with IntRange
1434      *
1435      * @param text  a String
1436      * @param range an IntRange
1437      * @return the resulting String
1438      */
1439     public static String getAt(String text, IntRange range) {
1440         return getAt(text, (Range) range);
1441     }
1442 
1443     /***
1444      * Support the range subscript operator for String
1445      *
1446      * @param text  a String
1447      * @param range a Range
1448      * @return a substring corresponding to the Range
1449      */
1450     public static String getAt(String text, Range range) {
1451         int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), text.length());
1452         int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), text.length());
1453 
1454         // If this is a backwards range, reverse the arguments to substring.
1455         boolean reverse = range.isReverse();
1456         if (from > to) {
1457             int tmp = to;
1458             to = from;
1459             from = tmp;
1460             reverse = !reverse;
1461         }
1462 
1463         String answer = text.substring(from, to + 1);
1464         if (reverse) {
1465             answer = reverse(answer);
1466         }
1467         return answer;
1468     }
1469 
1470     /***
1471      * Creates a new string which is the reverse (backwards) of this string
1472      *
1473      * @param self a String
1474      * @return a new string with all the characters reversed.
1475      */
1476     public static String reverse(String self) {
1477         int size = self.length();
1478         StringBuffer buffer = new StringBuffer(size);
1479         for (int i = size - 1; i >= 0; i--) {
1480             buffer.append(self.charAt(i));
1481         }
1482         return buffer.toString();
1483     }
1484 
1485     /***
1486      * Transforms a String representing a URL into a URL object.
1487      *
1488      * @param self the String representing a URL
1489      * @return a URL
1490      * @throws MalformedURLException is thrown if the URL is not well formed.
1491      */
1492     public static URL toURL(String self) throws MalformedURLException {
1493         return new URL(self);
1494     }
1495 
1496     /***
1497      * Transforms a String representing a URI into a URI object.
1498      *
1499      * @param self the String representing a URI
1500      * @return a URI
1501      * @throws URISyntaxException is thrown if the URI is not well formed.
1502      */
1503     public static URI toURI(String self) throws URISyntaxException {
1504         return new URI(self);
1505     }
1506 
1507     /***
1508      * Turns a String into a regular expression pattern
1509      *
1510      * @param self a String to convert into a regular expression
1511      * @return the regular expression pattern
1512      */
1513     public static Pattern negate(String self) {
1514         return Pattern.compile(self);
1515     }
1516 
1517     /***
1518      * Replaces all occurrencies of a captured group by the result of a closure on that text.
1519      * <p/>
1520      * <p> For examples,
1521      * <pre>
1522