You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/12/20 00:56:39 UTC
[42/49] groovy git commit: Move source files to proper packages
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/inspect/Inspector.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/inspect/Inspector.java b/src/main/groovy/groovy/inspect/Inspector.java
new file mode 100644
index 0000000..f0c94a7
--- /dev/null
+++ b/src/main/groovy/groovy/inspect/Inspector.java
@@ -0,0 +1,348 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.inspect;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaMethod;
+import groovy.lang.PropertyValue;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * The Inspector provides a unified access to an object's
+ * information that can be determined by introspection.
+ *
+ * @author Dierk Koenig
+ */
+public class Inspector {
+ protected Object objectUnderInspection;
+
+ // Indexes to retrieve Class Property information
+ public static final int CLASS_PACKAGE_IDX = 0;
+ public static final int CLASS_CLASS_IDX = 1;
+ public static final int CLASS_INTERFACE_IDX = 2;
+ public static final int CLASS_SUPERCLASS_IDX = 3;
+ public static final int CLASS_OTHER_IDX = 4;
+
+ // Indexes to retrieve field and method information
+ public static final int MEMBER_ORIGIN_IDX = 0;
+ public static final int MEMBER_MODIFIER_IDX = 1;
+ public static final int MEMBER_DECLARER_IDX = 2;
+ public static final int MEMBER_TYPE_IDX = 3;
+ public static final int MEMBER_NAME_IDX = 4;
+ public static final int MEMBER_PARAMS_IDX = 5;
+ public static final int MEMBER_VALUE_IDX = 5;
+ public static final int MEMBER_EXCEPTIONS_IDX = 6;
+
+ public static final String NOT_APPLICABLE = "n/a";
+ public static final String GROOVY = "GROOVY";
+ public static final String JAVA = "JAVA";
+
+ /**
+ * @param objectUnderInspection must not be null
+ */
+ public Inspector(Object objectUnderInspection) {
+ if (null == objectUnderInspection) {
+ throw new IllegalArgumentException("argument must not be null");
+ }
+ this.objectUnderInspection = objectUnderInspection;
+ }
+
+ /**
+ * Get the Class Properties of the object under inspection.
+ *
+ * @return String array to be indexed by the CLASS_xxx_IDX constants
+ */
+ public String[] getClassProps() {
+ String[] result = new String[CLASS_OTHER_IDX + 1];
+ Package pack = getClassUnderInspection().getPackage();
+ result[CLASS_PACKAGE_IDX] = "package " + ((pack == null) ? NOT_APPLICABLE : pack.getName());
+ String modifiers = Modifier.toString(getClassUnderInspection().getModifiers());
+ result[CLASS_CLASS_IDX] = modifiers + " class " + shortName(getClassUnderInspection());
+ result[CLASS_INTERFACE_IDX] = "implements ";
+ Class[] interfaces = getClassUnderInspection().getInterfaces();
+ for (Class anInterface : interfaces) {
+ result[CLASS_INTERFACE_IDX] += shortName(anInterface) + " ";
+ }
+ result[CLASS_SUPERCLASS_IDX] = "extends " + shortName(getClassUnderInspection().getSuperclass());
+ result[CLASS_OTHER_IDX] = "is Primitive: " + getClassUnderInspection().isPrimitive()
+ + ", is Array: " + getClassUnderInspection().isArray()
+ + ", is Groovy: " + isGroovy();
+ return result;
+ }
+
+ public boolean isGroovy() {
+ return GroovyObject.class.isAssignableFrom(getClassUnderInspection());
+ }
+
+ /**
+ * Gets the object being inspected.
+ *
+ * @return the object
+ */
+ public Object getObject() {
+ return objectUnderInspection;
+ }
+
+ /**
+ * Get info about usual Java instance and class Methods as well as Constructors.
+ *
+ * @return Array of StringArrays that can be indexed with the MEMBER_xxx_IDX constants
+ */
+ public Object[] getMethods() {
+ Method[] methods = getClassUnderInspection().getMethods();
+ Constructor[] ctors = getClassUnderInspection().getConstructors();
+ Object[] result = new Object[methods.length + ctors.length];
+ int resultIndex = 0;
+ for (; resultIndex < methods.length; resultIndex++) {
+ Method method = methods[resultIndex];
+ result[resultIndex] = methodInfo(method);
+ }
+ for (int i = 0; i < ctors.length; i++, resultIndex++) {
+ Constructor ctor = ctors[i];
+ result[resultIndex] = methodInfo(ctor);
+ }
+ return result;
+ }
+
+ /**
+ * Get info about instance and class Methods that are dynamically added through Groovy.
+ *
+ * @return Array of StringArrays that can be indexed with the MEMBER_xxx_IDX constants
+ */
+ public Object[] getMetaMethods() {
+ MetaClass metaClass = InvokerHelper.getMetaClass(objectUnderInspection);
+ List metaMethods = metaClass.getMetaMethods();
+ Object[] result = new Object[metaMethods.size()];
+ int i = 0;
+ for (Iterator iter = metaMethods.iterator(); iter.hasNext(); i++) {
+ MetaMethod metaMethod = (MetaMethod) iter.next();
+ result[i] = methodInfo(metaMethod);
+ }
+ return result;
+ }
+
+ /**
+ * Get info about usual Java public fields incl. constants.
+ *
+ * @return Array of StringArrays that can be indexed with the MEMBER_xxx_IDX constants
+ */
+ public Object[] getPublicFields() {
+ Field[] fields = getClassUnderInspection().getFields();
+ Object[] result = new Object[fields.length];
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ result[i] = fieldInfo(field);
+ }
+ return result;
+ }
+
+ /**
+ * Get info about Properties (Java and Groovy alike).
+ *
+ * @return Array of StringArrays that can be indexed with the MEMBER_xxx_IDX constants
+ */
+ public Object[] getPropertyInfo() {
+ List props = DefaultGroovyMethods.getMetaPropertyValues(objectUnderInspection);
+ Object[] result = new Object[props.size()];
+ int i = 0;
+ for (Iterator iter = props.iterator(); iter.hasNext(); i++) {
+ PropertyValue pv = (PropertyValue) iter.next();
+ result[i] = fieldInfo(pv);
+ }
+ return result;
+ }
+
+ protected String[] fieldInfo(Field field) {
+ String[] result = new String[MEMBER_VALUE_IDX + 1];
+ result[MEMBER_ORIGIN_IDX] = JAVA;
+ result[MEMBER_MODIFIER_IDX] = Modifier.toString(field.getModifiers());
+ result[MEMBER_DECLARER_IDX] = shortName(field.getDeclaringClass());
+ result[MEMBER_TYPE_IDX] = shortName(field.getType());
+ result[MEMBER_NAME_IDX] = field.getName();
+ try {
+ result[MEMBER_VALUE_IDX] = InvokerHelper.inspect(field.get(objectUnderInspection));
+ } catch (IllegalAccessException e) {
+ result[MEMBER_VALUE_IDX] = NOT_APPLICABLE;
+ }
+ return withoutNulls(result);
+ }
+
+ protected String[] fieldInfo(PropertyValue pv) {
+ String[] result = new String[MEMBER_VALUE_IDX + 1];
+ result[MEMBER_ORIGIN_IDX] = GROOVY;
+ result[MEMBER_MODIFIER_IDX] = "public";
+ result[MEMBER_DECLARER_IDX] = NOT_APPLICABLE;
+ result[MEMBER_TYPE_IDX] = shortName(pv.getType());
+ result[MEMBER_NAME_IDX] = pv.getName();
+ try {
+ result[MEMBER_VALUE_IDX] = InvokerHelper.inspect(pv.getValue());
+ } catch (Exception e) {
+ result[MEMBER_VALUE_IDX] = NOT_APPLICABLE;
+ }
+ return withoutNulls(result);
+ }
+
+ protected Class getClassUnderInspection() {
+ return objectUnderInspection.getClass();
+ }
+
+ public static String shortName(Class clazz) {
+ if (null == clazz) return NOT_APPLICABLE;
+ String className = clazz.getName();
+ if (null == clazz.getPackage()) return className;
+ String packageName = clazz.getPackage().getName();
+ int offset = packageName.length();
+ if (offset > 0) offset++;
+ className = className.substring(offset);
+ return className;
+ }
+
+ protected String[] methodInfo(Method method) {
+ String[] result = new String[MEMBER_EXCEPTIONS_IDX + 1];
+ int mod = method.getModifiers();
+ result[MEMBER_ORIGIN_IDX] = JAVA;
+ result[MEMBER_DECLARER_IDX] = shortName(method.getDeclaringClass());
+ result[MEMBER_MODIFIER_IDX] = Modifier.toString(mod);
+ result[MEMBER_NAME_IDX] = method.getName();
+ result[MEMBER_TYPE_IDX] = shortName(method.getReturnType());
+ Class[] params = method.getParameterTypes();
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < params.length; j++) {
+ sb.append(shortName(params[j]));
+ if (j < (params.length - 1)) sb.append(", ");
+ }
+ result[MEMBER_PARAMS_IDX] = sb.toString();
+ sb.setLength(0);
+ Class[] exceptions = method.getExceptionTypes();
+ for (int k = 0; k < exceptions.length; k++) {
+ sb.append(shortName(exceptions[k]));
+ if (k < (exceptions.length - 1)) sb.append(", ");
+ }
+ result[MEMBER_EXCEPTIONS_IDX] = sb.toString();
+ return withoutNulls(result);
+ }
+
+ protected String[] methodInfo(Constructor ctor) {
+ String[] result = new String[MEMBER_EXCEPTIONS_IDX + 1];
+ int mod = ctor.getModifiers();
+ result[MEMBER_ORIGIN_IDX] = JAVA;
+ result[MEMBER_MODIFIER_IDX] = Modifier.toString(mod);
+ result[MEMBER_DECLARER_IDX] = shortName(ctor.getDeclaringClass());
+ result[MEMBER_TYPE_IDX] = shortName(ctor.getDeclaringClass());
+ result[MEMBER_NAME_IDX] = ctor.getName();
+ Class[] params = ctor.getParameterTypes();
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < params.length; j++) {
+ sb.append(shortName(params[j]));
+ if (j < (params.length - 1)) sb.append(", ");
+ }
+ result[MEMBER_PARAMS_IDX] = sb.toString();
+ sb.setLength(0);
+ Class[] exceptions = ctor.getExceptionTypes();
+ for (int k = 0; k < exceptions.length; k++) {
+ sb.append(shortName(exceptions[k]));
+ if (k < (exceptions.length - 1)) sb.append(", ");
+ }
+ result[MEMBER_EXCEPTIONS_IDX] = sb.toString();
+ return withoutNulls(result);
+ }
+
+ protected String[] methodInfo(MetaMethod method) {
+ String[] result = new String[MEMBER_EXCEPTIONS_IDX + 1];
+ int mod = method.getModifiers();
+ result[MEMBER_ORIGIN_IDX] = GROOVY;
+ result[MEMBER_MODIFIER_IDX] = Modifier.toString(mod);
+ result[MEMBER_DECLARER_IDX] = shortName(method.getDeclaringClass().getTheClass());
+ result[MEMBER_TYPE_IDX] = shortName(method.getReturnType());
+ result[MEMBER_NAME_IDX] = method.getName();
+ CachedClass[] params = method.getParameterTypes();
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < params.length; j++) {
+ sb.append(shortName(params[j].getTheClass()));
+ if (j < (params.length - 1)) sb.append(", ");
+ }
+ result[MEMBER_PARAMS_IDX] = sb.toString();
+ result[MEMBER_EXCEPTIONS_IDX] = NOT_APPLICABLE; // no exception info for Groovy MetaMethods
+ return withoutNulls(result);
+ }
+
+ protected String[] withoutNulls(String[] toNormalize) {
+ for (int i = 0; i < toNormalize.length; i++) {
+ String s = toNormalize[i];
+ if (null == s) toNormalize[i] = NOT_APPLICABLE;
+ }
+ return toNormalize;
+ }
+
+ public static void print(Object[] memberInfo) {
+ print(System.out, memberInfo);
+ }
+
+ static void print(final PrintStream out, Object[] memberInfo) {
+ for (int i = 0; i < memberInfo.length; i++) {
+ String[] metaMethod = (String[]) memberInfo[i];
+ out.print(i + ":\t");
+ for (String s : metaMethod) {
+ out.print(s + " ");
+ }
+ out.println("");
+ }
+ }
+
+ public static Collection sort(List<Object> memberInfo) {
+ Collections.sort(memberInfo, new MemberComparator());
+ return memberInfo;
+ }
+
+ public static class MemberComparator implements Comparator<Object>, Serializable {
+ private static final long serialVersionUID = -7691851726606749541L;
+
+ public int compare(Object a, Object b) {
+ String[] aStr = (String[]) a;
+ String[] bStr = (String[]) b;
+ int result = aStr[Inspector.MEMBER_NAME_IDX].compareTo(bStr[Inspector.MEMBER_NAME_IDX]);
+ if (0 != result) return result;
+ result = aStr[Inspector.MEMBER_TYPE_IDX].compareTo(bStr[Inspector.MEMBER_TYPE_IDX]);
+ if (0 != result) return result;
+ result = aStr[Inspector.MEMBER_PARAMS_IDX].compareTo(bStr[Inspector.MEMBER_PARAMS_IDX]);
+ if (0 != result) return result;
+ result = aStr[Inspector.MEMBER_DECLARER_IDX].compareTo(bStr[Inspector.MEMBER_DECLARER_IDX]);
+ if (0 != result) return result;
+ result = aStr[Inspector.MEMBER_MODIFIER_IDX].compareTo(bStr[Inspector.MEMBER_MODIFIER_IDX]);
+ if (0 != result) return result;
+ result = aStr[Inspector.MEMBER_ORIGIN_IDX].compareTo(bStr[Inspector.MEMBER_ORIGIN_IDX]);
+ return result;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/inspect/package.html
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/inspect/package.html b/src/main/groovy/groovy/inspect/package.html
new file mode 100644
index 0000000..6d80c2b
--- /dev/null
+++ b/src/main/groovy/groovy/inspect/package.html
@@ -0,0 +1,28 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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 License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<html>
+ <head>
+ <title>package groovy.inspect.*</title>
+ </head>
+ <body>
+ <p>Classes for inspecting object properties through introspection.</p>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/io/EncodingAwareBufferedWriter.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/io/EncodingAwareBufferedWriter.java b/src/main/groovy/groovy/io/EncodingAwareBufferedWriter.java
new file mode 100644
index 0000000..2faaaeb
--- /dev/null
+++ b/src/main/groovy/groovy/io/EncodingAwareBufferedWriter.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.io;
+
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+
+/**
+ * A buffered writer only for OutputStreamWriter that is aware of
+ * the encoding of the OutputStreamWriter.
+ *
+ * @author Paul King
+ */
+
+public class EncodingAwareBufferedWriter extends BufferedWriter {
+ private final OutputStreamWriter out;
+ public EncodingAwareBufferedWriter(OutputStreamWriter out) {
+ super(out);
+ this.out = out;
+ }
+
+ /**
+ * The encoding as returned by the underlying OutputStreamWriter. Can be the historical name.
+ *
+ * @return the encoding
+ * @see java.io.OutputStreamWriter#getEncoding()
+ */
+ public String getEncoding() {
+ return out.getEncoding();
+ }
+
+ /**
+ * The encoding as returned by the underlying OutputStreamWriter. Will be the preferred name.
+ *
+ * @return the encoding
+ * @see java.io.OutputStreamWriter#getEncoding()
+ */
+ public String getNormalizedEncoding() {
+ return Charset.forName(getEncoding()).name();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/io/FileType.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/io/FileType.java b/src/main/groovy/groovy/io/FileType.java
new file mode 100644
index 0000000..945b9ae
--- /dev/null
+++ b/src/main/groovy/groovy/io/FileType.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.io;
+
+/**
+ * Represents particular files of interest.
+ */
+public enum FileType {
+ /** Represents normal files */
+ FILES,
+ /** Represents directories */
+ DIRECTORIES,
+ /** Represents both normal files and directories */
+ ANY
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/io/FileVisitResult.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/io/FileVisitResult.java b/src/main/groovy/groovy/io/FileVisitResult.java
new file mode 100644
index 0000000..55ecb4a
--- /dev/null
+++ b/src/main/groovy/groovy/io/FileVisitResult.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.io;
+
+/**
+ * Represents special return values for the 'preDir', 'postDir' and 'visit'/supplied Closures used with
+ * {@link org.codehaus.groovy.runtime.DefaultGroovyMethods#traverse(java.io.File, java.util.Map, groovy.lang.Closure)}
+ * and related methods to control subsequent traversal behavior.
+ */
+public enum FileVisitResult {
+ /** Continue processing; the default */
+ CONTINUE,
+ /** Skip processing sibling files/directories within the current directory being processed */
+ SKIP_SIBLINGS,
+ /** Do not process the child files/subdirectories within the current directory being processed */
+ SKIP_SUBTREE,
+ /** Do not process any more files */
+ TERMINATE
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/io/GroovyPrintStream.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/io/GroovyPrintStream.java b/src/main/groovy/groovy/io/GroovyPrintStream.java
new file mode 100644
index 0000000..d77c5aa
--- /dev/null
+++ b/src/main/groovy/groovy/io/GroovyPrintStream.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.io;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * A PrintStream that outputs objects in Groovy style.
+ * That means print(Object) uses InvokerHelper.toString(Object)
+ * to produce the same results as Writer.print(Object).
+ *
+ * @author Jim White
+ * @since 1.6
+ */
+public class GroovyPrintStream extends PrintStream
+{
+ /**
+ * Creates a new print stream. This stream will not flush automatically.
+ *
+ * @see java.io.PrintStream#PrintStream(java.io.OutputStream)
+ */
+ public GroovyPrintStream(OutputStream out) {
+ super(out, false);
+ }
+
+ /**
+ * Creates a new print stream.
+ *
+ * @see java.io.PrintStream#PrintStream(java.io.OutputStream, boolean)
+ */
+ public GroovyPrintStream(OutputStream out, boolean autoFlush) {
+ super(out, autoFlush);
+ }
+
+ /**
+ * Creates a new print stream.
+ *
+ * @see java.io.PrintStream#PrintStream(java.io.OutputStream, boolean, String)
+ */
+ public GroovyPrintStream(OutputStream out, boolean autoFlush, String encoding)
+ throws UnsupportedEncodingException
+ {
+ super(out, autoFlush, encoding);
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file name.
+ *
+ * @see java.io.PrintStream#PrintStream(String)
+ */
+ public GroovyPrintStream(String fileName) throws FileNotFoundException {
+ super(fileName);
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file name and charset.
+ *
+ * @see java.io.PrintStream#PrintStream(String, String)
+ */
+ public GroovyPrintStream(String fileName, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ super(fileName, csn);
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file.
+ *
+ * @see java.io.PrintStream#PrintStream(File)
+ */
+ public GroovyPrintStream(File file) throws FileNotFoundException {
+ super(file);
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file and charset.
+ *
+ * @see java.io.PrintStream#PrintStream(File, String)
+ */
+ public GroovyPrintStream(File file, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ super(file, csn);
+ }
+
+ /**
+ * Prints an object Groovy style.
+ *
+ * @param obj The <code>Object</code> to be printed
+ */
+ public void print(Object obj) {
+ print(InvokerHelper.toString(obj));
+ }
+
+ /**
+ * Prints an object Groovy style followed by a newline.
+ *
+ * @param obj The <code>Object</code> to be printed
+ */
+ public void println(Object obj) {
+ println(InvokerHelper.toString(obj));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/io/GroovyPrintWriter.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/io/GroovyPrintWriter.java b/src/main/groovy/groovy/io/GroovyPrintWriter.java
new file mode 100644
index 0000000..0a076b9
--- /dev/null
+++ b/src/main/groovy/groovy/io/GroovyPrintWriter.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.io;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+/**
+ * A PrintWriter that outputs objects in Groovy style.
+ * That means print(Object) uses InvokerHelper.toString(Object)
+ * to produce the same results as Writer.print(Object).
+ *
+ * @author Jim White
+ * @since 1.6
+ */
+public class GroovyPrintWriter extends PrintWriter
+{
+ public GroovyPrintWriter(File file) throws FileNotFoundException
+ {
+ super(file);
+ }
+
+ public GroovyPrintWriter(File file, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ super(file, csn);
+ }
+
+ public GroovyPrintWriter(Writer out)
+ {
+ super(out);
+ }
+
+ public GroovyPrintWriter(Writer out, boolean autoflush)
+ {
+ super(out, autoflush);
+ }
+
+ public GroovyPrintWriter(OutputStream out)
+ {
+ super(out);
+ }
+
+ public GroovyPrintWriter(OutputStream out, boolean autoflush)
+ {
+ super(out, autoflush);
+ }
+
+ public GroovyPrintWriter(String filename) throws FileNotFoundException
+ {
+ super(filename);
+ }
+
+ public GroovyPrintWriter(String filename, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ super(filename, csn);
+ }
+
+// Don't need to do this if Groovy is going to print char[] like a string.
+// public void print(char[] x)
+// {
+// write(InvokerHelper.toString(x));
+// }
+
+ public void print(Object x)
+ {
+ write(InvokerHelper.toString(x));
+ }
+
+ public void println(Object x)
+ {
+ // JDK 1.6 has changed the implementation to do a
+ // String.valueOf(x) rather than call print(x).
+ // Probably to improve performance by doing the conversion outside the lock.
+ // This will do the same thing for us, and we don't have to have access to the lock.
+ println(InvokerHelper.toString(x));
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/io/LineColumnReader.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/io/LineColumnReader.java b/src/main/groovy/groovy/io/LineColumnReader.java
new file mode 100644
index 0000000..49b7c94
--- /dev/null
+++ b/src/main/groovy/groovy/io/LineColumnReader.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.io;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.CharBuffer;
+
+/**
+ * The <code>LineColumnReader</code> is an extension to <code>BufferedReader</code>
+ * that keeps track of the line and column information of where the cursor is.
+ *
+ * @author Guillaume Laforge
+ * @since 1.8.0
+ */
+public class LineColumnReader extends BufferedReader {
+
+ /**
+ * The current line position
+ */
+ private long line = 1;
+
+ /**
+ * The current column position
+ */
+ private long column = 1;
+
+ /**
+ * The latest marked line position
+ */
+ private long lineMark = 1;
+
+ /**
+ * The latest marked line position
+ */
+ private long columnMark = 1;
+
+ private boolean newLineWasRead = false;
+
+ /**
+ * Constructor wrapping a <code>Reader</code>
+ * (<code>FileReader</code>, <code>FileReader</code>, <code>InputStreamReader</code>, etc.)
+ *
+ * @param reader the reader to wrap
+ */
+ public LineColumnReader(Reader reader) {
+ super(reader);
+ }
+
+ /**
+ * Marks the present position in the stream. Subsequent calls to reset() will attempt to reposition the stream to this point.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be read while still preserving the mark.
+ * An attempt to reset the stream after reading characters up to this limit or beyond may fail.
+ * A limit value larger than the size of the input buffer will cause a new buffer to be allocated whose size is no smaller than limit.
+ * Therefore large values should be used with care.
+ */
+ @Override
+ public void mark(int readAheadLimit) throws IOException {
+ lineMark = line;
+ columnMark = column;
+ super.mark(readAheadLimit);
+ }
+
+ /**
+ * Resets the stream to the most recent mark.
+ */
+ @Override
+ public void reset() throws IOException {
+ line = lineMark;
+ column = columnMark;
+ super.reset();
+ }
+
+ /**
+ * Reads a single character.
+ *
+ * @return The character read, as an integer in the range 0 to 65535 (0x00-0xffff),
+ * or -1 if the end of the stream has been reached
+ */
+ @Override
+ public int read() throws IOException {
+ if (newLineWasRead) {
+ line += 1;
+ column = 1;
+ newLineWasRead = false;
+ }
+
+ int charRead = super.read();
+ if (charRead > -1) {
+ char c = (char)charRead;
+ // found a \r or \n, like on Mac or Unix
+ // could also be Windows' \r\n
+ if (c == '\r' || c == '\n') {
+ newLineWasRead = true;
+ if (c == '\r') {
+ mark(1);
+ c = (char)super.read();
+ // check if we have \r\n like on Windows
+ // if it's not \r\n we reset, otherwise, the \n is just consummed
+ if (c != '\n') {
+ reset();
+ }
+ }
+ } else {
+ column += 1;
+ }
+ }
+
+ return charRead;
+ }
+
+ /**
+ * Reads characters into a portion of an array.
+ *
+ * @param chars Destination array of char
+ * @param startOffset Offset at which to start storing characters
+ * @param length Maximum number of characters to read
+ * @return an exception if an error occurs
+ */
+ @Override
+ public int read(char[] chars, int startOffset, int length) throws IOException {
+ for (int i = startOffset; i <= startOffset + length; i++) {
+ int readInt = read();
+ if (readInt == -1) return i - startOffset;
+ chars[i] = (char)readInt;
+ }
+ return length;
+ }
+
+ /**
+ * Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'),
+ * a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
+ *
+ * @return A String containing the contents of the line, not including any line-termination characters,
+ * or null if the end of the stream has been reached
+ */
+ @Override
+ public String readLine() throws IOException {
+ StringBuilder result = new StringBuilder();
+ for (;;) {
+ int intRead = read();
+ if (intRead == -1) {
+ return result.length() == 0 ? null : result.toString();
+ }
+
+ char c = (char)intRead;
+ if (c == '\n' || c == '\r') break;
+ result.append(c);
+ }
+ return result.toString();
+ }
+
+ /**
+ * Skips characters.
+ *
+ * @param toSkip the number of characters to skip
+ * @return The number of characters actually skipped
+ */
+ @Override
+ public long skip(long toSkip) throws IOException {
+ for (long i = 0; i < toSkip; i++) {
+ int intRead = read();
+ if (intRead == -1) return i;
+ }
+ return toSkip;
+ }
+
+ /**
+ * Reads characters into an array.
+ * This method will block until some input is available, an I/O error occurs,
+ * or the end of the stream is reached.
+ *
+ * @param chars Destination buffer
+ * @return The number of characters read, or -1 if the end of the stream has been reached
+ */
+ @Override
+ public int read(char[] chars) throws IOException {
+ return read(chars, 0, chars.length - 1);
+ }
+
+ /**
+ * Not implemented.
+ *
+ * @param buffer Destination buffer
+ * @return The number of characters read, or -1 if the end of the stream has been reached
+ * @throws UnsupportedOperationException as the method is not implemented
+ */
+ @Override
+ public int read(CharBuffer buffer) {
+ throw new UnsupportedOperationException("read(CharBuffer) not yet implemented");
+ }
+
+ /**
+ * Closes the stream and releases any system resources associated with it.
+ * Once the stream has been closed, further read(), ready(), mark(), reset(), or skip() invocations
+ * will throw an IOException. Closing a previously closed stream has no effect.
+ */
+ @Override
+ public void close() throws IOException {
+ super.close();
+ }
+
+ public long getColumn() {
+ return column;
+ }
+
+ public void setColumn(long column) {
+ this.column = column;
+ }
+
+ public long getColumnMark() {
+ return columnMark;
+ }
+
+ public void setColumnMark(long columnMark) {
+ this.columnMark = columnMark;
+ }
+
+ public long getLine() {
+ return line;
+ }
+
+ public void setLine(long line) {
+ this.line = line;
+ }
+
+ public long getLineMark() {
+ return lineMark;
+ }
+
+ public void setLineMark(long lineMark) {
+ this.lineMark = lineMark;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/io/PlatformLineWriter.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/io/PlatformLineWriter.java b/src/main/groovy/groovy/io/PlatformLineWriter.java
new file mode 100644
index 0000000..0071e0f
--- /dev/null
+++ b/src/main/groovy/groovy/io/PlatformLineWriter.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.io;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * A buffered writer that gobbles any \r characters
+ * and replaces every \n with a platform specific newline.
+ * In many places Groovy normalises streams to only have \n
+ * characters but when creating files that must be used
+ * by other platform-aware tools, you sometimes want the
+ * newlines to match what the platform expects.
+ *
+ * @author Paul King
+ */
+public class PlatformLineWriter extends Writer {
+ private final BufferedWriter writer;
+
+ public PlatformLineWriter(Writer out) {
+ writer = new BufferedWriter(out);
+ }
+
+ public PlatformLineWriter(Writer out, int sz) {
+ writer = new BufferedWriter(out, sz);
+ }
+
+ public void write(char cbuf[], int off, int len) throws IOException {
+ for (; len > 0; len--) {
+ char c = cbuf[off++];
+ if (c == '\n') {
+ writer.newLine();
+ } else if (c != '\r') {
+ writer.write(c);
+ }
+ }
+ }
+
+ public void flush() throws IOException {
+ writer.flush();
+ }
+
+ public void close() throws IOException {
+ writer.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/io/package.html
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/io/package.html b/src/main/groovy/groovy/io/package.html
new file mode 100644
index 0000000..fef0d09
--- /dev/null
+++ b/src/main/groovy/groovy/io/package.html
@@ -0,0 +1,28 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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 License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<html>
+ <head>
+ <title>package groovy.io.*</title>
+ </head>
+ <body>
+ <p>Classes for Groovier Input/Output.</p>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/AdaptingMetaClass.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/AdaptingMetaClass.java b/src/main/groovy/groovy/lang/AdaptingMetaClass.java
new file mode 100644
index 0000000..81afc26
--- /dev/null
+++ b/src/main/groovy/groovy/lang/AdaptingMetaClass.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+/**
+ * An interface for MetaClass instances that "adapt" other MetaClass instances such as a proxy or
+ * delegating MetaClass.
+ *
+ * @author Graeme Rocher
+ * @since 1.5
+ */
+public interface AdaptingMetaClass extends MetaClass {
+
+ /**
+ * Returns the MetaClass that this adapter adapts
+ *
+ * @return The MetaClass instance
+ */
+ MetaClass getAdaptee();
+
+ /**
+ * Sets the MetaClass adapted by this MetaClass
+ *
+ * @param metaClass The MetaClass to adapt
+ */
+ void setAdaptee(MetaClass metaClass);
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/BenchmarkInterceptor.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/BenchmarkInterceptor.java b/src/main/groovy/groovy/lang/BenchmarkInterceptor.java
new file mode 100644
index 0000000..77bcb64
--- /dev/null
+++ b/src/main/groovy/groovy/lang/BenchmarkInterceptor.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Interceptor that registers the timestamp of each method call
+ * before and after invocation. The timestamps are stored internally
+ * and can be retrieved through the with the <pre>getCalls()</pre>
+ * and <pre>statistic()</pre> API.
+ * <p>
+ * Example usage:
+ * <pre>
+ * def proxy = ProxyMetaClass.getInstance(ArrayList.class)
+ * proxy.interceptor = new BenchmarkInterceptor()
+ * proxy.use {
+ * def list = (0..10000).collect{ it }
+ * 4.times { list.size() }
+ * 4000.times { list.set(it, it+1) }
+ * }
+ * proxy.interceptor.statistic()
+ * </pre>
+ * Which produces the following output:
+ * <pre>
+ * [[size, 4, 0], [set, 4000, 21]]
+ * </pre>
+ */
+public class BenchmarkInterceptor implements Interceptor {
+
+ protected Map calls = new LinkedHashMap(); // keys to list of invocation times and before and after
+
+ /**
+ * Returns the raw data associated with the current benchmark run.
+ */
+ public Map getCalls() {
+ return calls;
+ }
+
+ /**
+ * Resets all the benchmark data on this object.
+ */
+ public void reset() {
+ calls = new HashMap();
+ }
+ /**
+ * This code is executed before the method is called.
+ * @param object receiver object for the method call
+ * @param methodName name of the method to call
+ * @param arguments arguments to the method call
+ * @return null
+ * relays this result.
+ */
+ public Object beforeInvoke(Object object, String methodName, Object[] arguments) {
+ if (!calls.containsKey(methodName)) calls.put(methodName, new LinkedList());
+ ((List) calls.get(methodName)).add(Long.valueOf(System.currentTimeMillis()));
+
+ return null;
+ }
+ /**
+ * This code is executed after the method is called.
+ * @param object receiver object for the called method
+ * @param methodName name of the called method
+ * @param arguments arguments to the called method
+ * @param result result of the executed method call or result of beforeInvoke if method was not called
+ * @return result
+ */
+ public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
+ ((List) calls.get(methodName)).add(Long.valueOf(System.currentTimeMillis()));
+ return result;
+ }
+
+ /**
+ * The call should be invoked separately
+ * @return true
+ */
+ public boolean doInvoke() {
+ return true;
+ }
+
+ /**
+ * Returns benchmark statistics as a List<Object[]>.
+ * AccumulateTime is measured in milliseconds and is as accurate as
+ * System.currentTimeMillis() allows it to be.
+ * @return a list of lines, each item is [methodname, numberOfCalls, accumulatedTime]
+ */
+ public List statistic() {
+ List result = new LinkedList();
+ for (Iterator iter = calls.keySet().iterator(); iter.hasNext();) {
+ Object[] line = new Object[3];
+ result.add(line);
+ line[0] = iter.next();
+ List times = (List) calls.get(line[0]);
+ line[1] = Integer.valueOf(times.size() / 2);
+ int accTime = 0;
+ for (Iterator it = times.iterator(); it.hasNext();) {
+ Long start = (Long) it.next();
+ Long end = (Long) it.next();
+ accTime += end.longValue() - start.longValue();
+ }
+ line[2] = Long.valueOf(accTime);
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Binding.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Binding.java b/src/main/groovy/groovy/lang/Binding.java
new file mode 100644
index 0000000..6505ea5
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Binding.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Represents the variable bindings of a script which can be altered
+ * from outside the script object or created outside of a script and passed
+ * into it.
+ * <p> Binding instances are not supposed to be used in a multi-threaded context.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class Binding extends GroovyObjectSupport {
+ private Map variables;
+
+ public Binding() {
+ }
+
+ public Binding(Map variables) {
+ this.variables = variables;
+ }
+
+ /**
+ * A helper constructor used in main(String[]) method calls
+ *
+ * @param args are the command line arguments from a main()
+ */
+ public Binding(String[] args) {
+ this();
+ setVariable("args", args);
+ }
+
+ /**
+ * @param name the name of the variable to lookup
+ * @return the variable value
+ */
+ public Object getVariable(String name) {
+ if (variables == null)
+ throw new MissingPropertyException(name, this.getClass());
+
+ Object result = variables.get(name);
+
+ if (result == null && !variables.containsKey(name)) {
+ throw new MissingPropertyException(name, this.getClass());
+ }
+
+ return result;
+ }
+
+ /**
+ * Sets the value of the given variable
+ *
+ * @param name the name of the variable to set
+ * @param value the new value for the given variable
+ */
+ public void setVariable(String name, Object value) {
+ if (variables == null)
+ variables = new LinkedHashMap();
+ variables.put(name, value);
+ }
+
+ /**
+ * Simple check for whether the binding contains a particular variable or not.
+ *
+ * @param name the name of the variable to check for
+ */
+ public boolean hasVariable(String name) {
+ return variables != null && variables.containsKey(name);
+ }
+
+ public Map getVariables() {
+ if (variables == null)
+ variables = new LinkedHashMap();
+ return variables;
+ }
+
+ /**
+ * Overloaded to make variables appear as bean properties or via the subscript operator
+ */
+ public Object getProperty(String property) {
+ /** @todo we should check if we have the property with the metaClass instead of try/catch */
+ try {
+ return super.getProperty(property);
+ }
+ catch (MissingPropertyException e) {
+ return getVariable(property);
+ }
+ }
+
+ /**
+ * Overloaded to make variables appear as bean properties or via the subscript operator
+ */
+ public void setProperty(String property, Object newValue) {
+ /** @todo we should check if we have the property with the metaClass instead of try/catch */
+ try {
+ super.setProperty(property, newValue);
+ }
+ catch (MissingPropertyException e) {
+ setVariable(property, newValue);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Buildable.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Buildable.java b/src/main/groovy/groovy/lang/Buildable.java
new file mode 100644
index 0000000..af22958
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Buildable.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+
+public interface Buildable {
+ void build(GroovyObject builder);
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Category.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Category.java b/src/main/groovy/groovy/lang/Category.java
new file mode 100644
index 0000000..a7d3336
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Category.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.transform.GroovyASTTransformationClass;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Transforms an instance-style Groovy class or interface to become a static-style
+ * conventional Groovy category.
+ * <p>
+ * Groovy categories are the original mechanism used
+ * by Groovy when augmenting classes with new methods. Writing categories required
+ * using a class writing style where all methods were static and an additional
+ * self parameter was defined. The self parameter and static nature of the methods
+ * disappeared once applied by Groovy's metaclass framework but some regarded
+ * the writing style as a little noisy. This transformation allows you to write
+ * your categories without the "apparent noise" but adds it back in during
+ * compilation so that the classes appear as normal categories.
+ * <p>
+ * It might seem strange writing your class/object enhancements using a succinct
+ * notation, then having "noise" added, then having the noise removed during
+ * category application. If this worries you, then you may also like to consider
+ * using Groovy's {@code ExpandoMetaClass} mechanism which avoids
+ * the category definition altogether. If you already have an investment in
+ * categories or like some of the other features which categories currently give you,
+ * then read on.
+ * <p>
+ * The mechanics: during compilation, all methods are transformed to static ones with an additional
+ * self parameter of the type you supply as the annotation parameter (the default type
+ * for the self parameters is {@code Object} which might be more broad reaching than
+ * you like so it is usually wise to specify a type).
+ * Properties invoked using 'this' references are transformed so that
+ * they are instead invoked on the additional self parameter and not on
+ * the Category instance. (Remember that once the category is applied, the reverse
+ * will occur and we will be back to conceptually having methods on the {@code this}
+ * references again!)
+ * <p>
+ * Classes conforming to the conventional Groovy category conventions can be used
+ * within {@code use} statements or mixed in at runtime with the {@code mixin} method on classes.
+ * <p>
+ * An example showing a {@code use} statement (allowing fine-grained application of
+ * the category methods):
+ * <pre class="groovyTestCase">
+ * {@code @Category}(Integer)
+ * class IntegerOps {
+ * def triple() {
+ * this * 3
+ * }
+ * }
+ *
+ * use (IntegerOps) {
+ * assert 25.triple() == 75
+ * }
+ * </pre>
+ * Or, "mixing in" your methods at runtime:
+ * <pre class="groovyTestCase">
+ * {@code @Category}(List)
+ * class Shuffler {
+ * def shuffle() {
+ * def result = new ArrayList(this)
+ * Collections.shuffle(result)
+ * result
+ * }
+ * }
+ *
+ * class Sentence extends ArrayList {
+ * Sentence(Collection initial) { super(initial) }
+ * }
+ * Sentence.mixin Shuffler
+ *
+ * def words = ["The", "quick", "brown", "fox"]
+ * println new Sentence(words).shuffle()
+ * // => [quick, fox, The, brown] (order will vary)
+ * </pre>
+ *
+ * @author Alex Tkachman
+ */
+@java.lang.annotation.Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.TYPE)
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.CategoryASTTransformation")
+public @interface Category {
+ Class value () default Object.class;
+}