1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package groovy.lang;
35
36 import java.io.IOException;
37 import java.io.StringWriter;
38 import java.io.Writer;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42 import java.util.regex.Pattern;
43
44 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
45 import org.codehaus.groovy.runtime.InvokerHelper;
46
47 /***
48 * Represents a String which contains embedded values such as "hello there
49 * ${user} how are you?" which can be evaluated lazily. Advanced users can
50 * iterate over the text and values to perform special processing, such as for
51 * performing SQL operations, the values can be substituted for ? and the
52 * actual value objects can be bound to a JDBC statement. The lovely name of
53 * this class was suggested by Jules Gosnell and was such a good idea, I
54 * couldn't resist :)
55 *
56 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
57 * @version $Revision: 4098 $
58 */
59 public abstract class GString extends GroovyObjectSupport implements Comparable, CharSequence, Writable, Buildable {
60
61 private Object[] values;
62
63 public GString(Object values) {
64 this.values = (Object[]) values;
65 }
66
67 public GString(Object[] values) {
68 this.values = values;
69 }
70
71
72 public abstract String[] getStrings();
73
74 /***
75 * Overloaded to implement duck typing for Strings
76 * so that any method that can't be evaluated on this
77 * object will be forwarded to the toString() object instead.
78 */
79 public Object invokeMethod(String name, Object args) {
80 try {
81 return super.invokeMethod(name, args);
82 }
83 catch (MissingMethodException e) {
84
85 return InvokerHelper.invokeMethod(toString(), name, args);
86 }
87 }
88
89 public Object[] getValues() {
90 return values;
91 }
92
93 public GString plus(GString that) {
94 List stringList = new ArrayList();
95 List valueList = new ArrayList();
96
97 stringList.addAll(Arrays.asList(getStrings()));
98 valueList.addAll(Arrays.asList(getValues()));
99
100 if (stringList.size() > valueList.size()) {
101 valueList.add("");
102 }
103
104 stringList.addAll(Arrays.asList(that.getStrings()));
105 valueList.addAll(Arrays.asList(that.getValues()));
106
107 final String[] newStrings = new String[stringList.size()];
108 stringList.toArray(newStrings);
109 Object[] newValues = valueList.toArray();
110
111 return new GString(newValues) {
112 public String[] getStrings() {
113 return newStrings;
114 }
115 };
116 }
117
118 public GString plus(String that) {
119 String[] currentStrings = getStrings();
120 String[] newStrings = null;
121 Object[] newValues = null;
122
123 newStrings = new String[currentStrings.length + 1];
124 newValues = new Object[getValues().length + 1];
125 int lastIndex = currentStrings.length;
126 System.arraycopy(currentStrings, 0, newStrings, 0, lastIndex);
127 System.arraycopy(getValues(), 0, newValues, 0, getValues().length);
128 newStrings[lastIndex] = that;
129 newValues[getValues().length] = "";
130
131 final String[] finalStrings = newStrings;
132 return new GString(newValues) {
133
134 public String[] getStrings() {
135 return finalStrings;
136 }
137 };
138 }
139
140 public int getValueCount() {
141 return values.length;
142 }
143
144 public Object getValue(int idx) {
145 return values[idx];
146 }
147
148 public String toString() {
149 StringWriter buffer = new StringWriter();
150 try {
151 writeTo(buffer);
152 }
153 catch (IOException e) {
154 throw new StringWriterIOException(e);
155 }
156 return buffer.toString();
157 }
158
159 public Writer writeTo(Writer out) throws IOException {
160 String[] s = getStrings();
161 int numberOfValues = values.length;
162 for (int i = 0, size = s.length; i < size; i++) {
163 out.write(s[i]);
164 if (i < numberOfValues) {
165 InvokerHelper.write(out, values[i]);
166 }
167 }
168 return out;
169 }
170
171
172
173
174 public void build(final GroovyObject builder) {
175 final String[] s = getStrings();
176 final int numberOfValues = values.length;
177
178 for (int i = 0, size = s.length; i < size; i++) {
179 builder.getProperty("mkp");
180 builder.invokeMethod("yield", new Object[]{s[i]});
181 if (i < numberOfValues) {
182 builder.getProperty("mkp");
183 builder.invokeMethod("yield", new Object[]{values[i]});
184 }
185 }
186 }
187
188 public boolean equals(Object that) {
189 if (that instanceof GString) {
190 return equals((GString) that);
191 }
192 return false;
193 }
194
195 public boolean equals(GString that) {
196 return toString().equals(that.toString());
197 }
198
199 public int hashCode() {
200 return 37 + toString().hashCode();
201 }
202
203 public int compareTo(Object that) {
204 return toString().compareTo(that.toString());
205 }
206
207 public char charAt(int index) {
208 return toString().charAt(index);
209 }
210
211 public int length() {
212 return toString().length();
213 }
214
215 public CharSequence subSequence(int start, int end) {
216 return toString().subSequence(start, end);
217 }
218
219 /***
220 * Turns a String into a regular expression pattern
221 *
222 * @return the regular expression pattern
223 */
224 public Pattern negate() {
225 return DefaultGroovyMethods.negate(toString());
226 }
227 }