KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyEnumerable


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2006 Ola Bini <ola@ologix.com>
15  *
16  * Alternatively, the contents of this file may be used under the terms of
17  * either of the GNU General Public License Version 2 or later (the "GPL"),
18  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19  * in which case the provisions of the GPL or the LGPL are applicable instead
20  * of those above. If you wish to allow use of your version of this file only
21  * under the terms of either the GPL or the LGPL, and not to allow others to
22  * use your version of this file under the terms of the CPL, indicate your
23  * decision by deleting the provisions above and replace them with the notice
24  * and other provisions required by the GPL or the LGPL. If you do not delete
25  * the provisions above, a recipient may use your version of this file under
26  * the terms of any one of the CPL, the GPL or the LGPL.
27  ***** END LICENSE BLOCK *****/

28 package org.jruby;
29
30 import java.util.Comparator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.Arrays JavaDoc;
37 import java.util.Collections JavaDoc;
38
39 import org.jruby.runtime.Arity;
40 import org.jruby.runtime.Block;
41 import org.jruby.runtime.CallBlock;
42 import org.jruby.runtime.BlockCallback;
43 import org.jruby.runtime.ThreadContext;
44 import org.jruby.runtime.Visibility;
45 import org.jruby.runtime.builtin.IRubyObject;
46
47 import org.jruby.internal.runtime.methods.MultiStub;
48 import org.jruby.internal.runtime.methods.MultiStubMethod;
49
50 /**
51  * The implementation of Ruby's Enumerable module.
52  */

53 public class RubyEnumerable {
54     private static class ListAddBlockCallback implements BlockCallback {
55         private final List JavaDoc arr = new ArrayList JavaDoc();
56         private final Ruby runtime;
57         public ListAddBlockCallback(Ruby runtime) {
58             this.runtime = runtime;
59         }
60         public IRubyObject call(ThreadContext context, IRubyObject[] iargs, IRubyObject iself, Block block) {
61             if(iargs.length > 1) {
62                 arr.add(runtime.newArrayNoCopy(iargs));
63             } else {
64                 arr.add(iargs[0]);
65             }
66
67             return runtime.getNil();
68         }
69         public List JavaDoc getList() {
70             return arr;
71         }
72     }
73
74     private static class RubyFirstArrayComparator implements Comparator JavaDoc {
75         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
76             IRubyObject obj1 = ((IRubyObject[])o1)[0];
77             return RubyFixnum.fix2int((((IRubyObject[])o1)[0].callMethod(obj1.getRuntime().getCurrentContext(),"<=>", ((IRubyObject[])o2)[0])));
78         }
79     }
80     private static class RubyYieldComparator implements Comparator JavaDoc {
81         private final ThreadContext context;
82         private final Ruby runtime;
83         private final Block block;
84         public RubyYieldComparator(ThreadContext context, Block block) {
85             this.context = context;
86             this.runtime = context.getRuntime();
87             this.block = block;
88         }
89         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
90             return RubyFixnum.fix2int(context.yield(runtime.newArray((IRubyObject)o1,(IRubyObject)o2), block));
91         }
92     }
93
94     public static IRubyObject callEach(ThreadContext context, IRubyObject self, RubyModule module, BlockCallback bc) {
95         return self.callMethod(context, "each", new CallBlock(self,module,Arity.noArguments(),bc,context));
96     }
97
98     public static List JavaDoc eachToList(ThreadContext context, IRubyObject self, RubyModule module) {
99         ListAddBlockCallback ladc = new ListAddBlockCallback(context.getRuntime());
100         callEach(context,self,module,ladc);
101         return ladc.getList();
102     }
103
104
105
106     public static class RubyEnumerableStub0 implements MultiStub {
107         public static RubyEnumerableStub0 createStub(final RubyModule recv) {
108             return new RubyEnumerableStub0(recv);
109         }
110         public final MultiStubMethod to_a;
111         public final MultiStubMethod sort;
112         public final MultiStubMethod sort_by;
113         public final MultiStubMethod grep;
114         public final MultiStubMethod detect;
115         public final MultiStubMethod select;
116         public final MultiStubMethod reject;
117         public final MultiStubMethod collect;
118         public final MultiStubMethod inject;
119         public final MultiStubMethod partition;
120
121         private final RubyModule module;
122
123         private RubyEnumerableStub0(final RubyModule recv) {
124             this.module = recv;
125             this.to_a = new MultiStubMethod(RubyEnumerableStub0.this,0,recv,Arity.noArguments(), Visibility.PUBLIC);
126             this.sort = new MultiStubMethod(RubyEnumerableStub0.this,1,recv,Arity.noArguments(), Visibility.PUBLIC);
127             this.sort_by = new MultiStubMethod(RubyEnumerableStub0.this,2,recv,Arity.noArguments(), Visibility.PUBLIC);
128             this.grep = new MultiStubMethod(RubyEnumerableStub0.this,3,recv,Arity.noArguments(), Visibility.PUBLIC);
129             this.detect = new MultiStubMethod(RubyEnumerableStub0.this,4,recv,Arity.noArguments(), Visibility.PUBLIC);
130             this.select = new MultiStubMethod(RubyEnumerableStub0.this,5,recv,Arity.noArguments(), Visibility.PUBLIC);
131             this.reject = new MultiStubMethod(RubyEnumerableStub0.this,6,recv,Arity.noArguments(), Visibility.PUBLIC);
132             this.collect = new MultiStubMethod(RubyEnumerableStub0.this,7,recv,Arity.noArguments(), Visibility.PUBLIC);
133             this.inject = new MultiStubMethod(RubyEnumerableStub0.this,8,recv,Arity.noArguments(), Visibility.PUBLIC);
134             this.partition = new MultiStubMethod(RubyEnumerableStub0.this,9,recv,Arity.noArguments(), Visibility.PUBLIC);
135         }
136
137         public IRubyObject method0(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
138             //TO_A
139
return context.getRuntime().newArray(eachToList(context,self,module));
140         }
141         public IRubyObject method1(final ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
142             //SORT
143
if (!block.isGiven()) return self.callMethod(context, "to_a").callMethod(context, "sort");
144                 
145             final List JavaDoc arr = eachToList(context, self, module);
146             Collections.sort(arr, new RubyYieldComparator(context, block));
147             
148             return context.getRuntime().newArray(arr);
149         }
150         public IRubyObject method2(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
151             //SORT_BY
152
List JavaDoc result = eachToList(context,self,module);
153             IRubyObject[][] secResult = new IRubyObject[result.size()][2];
154             int ix = 0;
155             for(Iterator JavaDoc iter = result.iterator();iter.hasNext();ix++) {
156                 IRubyObject iro = (IRubyObject)iter.next();
157                 secResult[ix][0] = context.yield(iro, block);
158                 secResult[ix][1] = iro;
159             }
160             Arrays.sort(secResult, new RubyFirstArrayComparator());
161             IRubyObject[] result2 = new IRubyObject[secResult.length];
162             for(int i=0,j=result2.length;i<j;i++) {
163                 result2[i] = secResult[i][1];
164             }
165             return context.getRuntime().newArrayNoCopy(result2);
166         }
167         public IRubyObject method3(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
168             //GREP
169
self.checkArgumentCount(args,1,1);
170             List JavaDoc arr = eachToList(context,self,module);
171             List JavaDoc result = new ArrayList JavaDoc();
172             IRubyObject pattern = args[0];
173             if (!block.isGiven()) {
174                 for (Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
175                     IRubyObject item = (IRubyObject)iter.next();
176                     if (pattern.callMethod(context,"===", item).isTrue()) {
177                         result.add(item);
178                     }
179                 }
180             } else {
181                 for (Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
182                     IRubyObject item = (IRubyObject)iter.next();
183                     if (pattern.callMethod(context,"===", item).isTrue()) {
184                         result.add(context.yield(item, block));
185                     }
186                 }
187             }
188             return context.getRuntime().newArray(result);
189         }
190         public IRubyObject method4(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
191             //DETECT
192
List JavaDoc arr = eachToList(context,self,module);
193             for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
194                 IRubyObject element = (IRubyObject)iter.next();
195                 if(context.yield(element, block).isTrue()) {
196                     return element;
197                 }
198             }
199             if(args.length > 0 && args[0] instanceof RubyProc) {
200                 return ((RubyProc)args[0]).call(new IRubyObject[0]);
201             }
202             return context.getRuntime().getNil();
203         }
204         public IRubyObject method5(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
205             //SELECT
206
List JavaDoc arr = eachToList(context,self,module);
207             List JavaDoc result = new ArrayList JavaDoc(arr.size());
208             for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
209                 IRubyObject element = (IRubyObject)iter.next();
210                 if(context.yield(element, block).isTrue()) {
211                     result.add(element);
212                 }
213             }
214             return context.getRuntime().newArray(result);
215         }
216         public IRubyObject method6(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
217             //REJECT
218
List JavaDoc arr = eachToList(context,self,module);
219             List JavaDoc result = new ArrayList JavaDoc(arr.size());
220             for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
221                 IRubyObject element = (IRubyObject)iter.next();
222                 if(!context.yield(element, block).isTrue()) {
223                     result.add(element);
224                 }
225             }
226             return context.getRuntime().newArray(result);
227         }
228         public IRubyObject method7(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
229             //COLLECT
230
List JavaDoc arr = eachToList(context,self,module);
231             IRubyObject[] result = new IRubyObject[arr.size()];
232             if (block.isGiven()) {
233                 int i=0;
234                 for (Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
235                     result[i++] = context.yield((IRubyObject)iter.next(), block);
236                 }
237             } else {
238                 int i=0;
239                 for (Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
240                     result[i++] = (IRubyObject)iter.next();
241                 }
242             }
243             return context.getRuntime().newArrayNoCopy(result);
244         }
245         public IRubyObject method8(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
246             //INJECT
247
IRubyObject result = null;
248             if(args.length > 0) {
249                 result = args[0];
250             }
251             List JavaDoc arr = eachToList(context,self,module);
252             for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
253                 IRubyObject item = (IRubyObject)iter.next();
254                 if(result == null) {
255                     result = item;
256                 } else {
257                     result = context.yield(context.getRuntime().newArray(result,item), block);
258                 }
259             }
260             if(null == result) {
261                 return context.getRuntime().getNil();
262             }
263             return result;
264         }
265         public IRubyObject method9(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
266             //PARTITION
267
List JavaDoc arr = eachToList(context,self,module);
268             List JavaDoc arr_true = new ArrayList JavaDoc(arr.size()/2);
269             List JavaDoc arr_false = new ArrayList JavaDoc(arr.size()/2);
270             for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
271                 IRubyObject item = (IRubyObject)iter.next();
272                 if(context.yield(item, block).isTrue()) {
273                     arr_true.add(item);
274                 } else {
275                     arr_false.add(item);
276                 }
277             }
278             return context.getRuntime().newArray(context.getRuntime().newArray(arr_true),context.getRuntime().newArray(arr_false));
279         }
280     }
281
282     public static class RubyEnumerableStub1 implements MultiStub {
283         public static RubyEnumerableStub1 createStub(final RubyModule recv) {
284             return new RubyEnumerableStub1(recv);
285         }
286         public final MultiStubMethod each_with_index;
287         public final MultiStubMethod include_p;
288         public final MultiStubMethod max;
289         public final MultiStubMethod min;
290         public final MultiStubMethod all_p;
291         public final MultiStubMethod any_p;
292         public final MultiStubMethod zip;
293         public final MultiStubMethod group_by;
294
295         private final RubyModule module;
296
297         private RubyEnumerableStub1(final RubyModule recv) {
298             this.module = recv;
299             this.each_with_index = new MultiStubMethod(RubyEnumerableStub1.this,0,recv,Arity.noArguments(), Visibility.PUBLIC);
300             this.include_p = new MultiStubMethod(RubyEnumerableStub1.this,1,recv,Arity.noArguments(), Visibility.PUBLIC);
301             this.max = new MultiStubMethod(RubyEnumerableStub1.this,2,recv,Arity.noArguments(), Visibility.PUBLIC);
302             this.min = new MultiStubMethod(RubyEnumerableStub1.this,3,recv,Arity.noArguments(), Visibility.PUBLIC);
303             this.all_p = new MultiStubMethod(RubyEnumerableStub1.this,4,recv,Arity.noArguments(), Visibility.PUBLIC);
304             this.any_p = new MultiStubMethod(RubyEnumerableStub1.this,5,recv,Arity.noArguments(), Visibility.PUBLIC);
305             this.zip = new MultiStubMethod(RubyEnumerableStub1.this,6,recv,Arity.noArguments(), Visibility.PUBLIC);
306             this.group_by = new MultiStubMethod(RubyEnumerableStub1.this,7,recv,Arity.noArguments(), Visibility.PUBLIC);
307         }
308
309         public IRubyObject method0(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
310             //EACH_WITH_INDEX
311
int index = 0;
312             List JavaDoc arr = eachToList(context,self,module);
313             Ruby rt = context.getRuntime();
314             for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
315                 context.yield(rt.newArray((IRubyObject)iter.next(),rt.newFixnum(index++)), block);
316             }
317             return self;
318         }
319         public IRubyObject method1(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
320             //INCLUDE?
321
List JavaDoc arr = eachToList(context,self,module);
322             for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
323                 if(args[0].callMethod(context,"==", (IRubyObject)iter.next()).isTrue()) {
324                     return context.getRuntime().getTrue();
325                 }
326             }
327             return context.getRuntime().getFalse();
328         }
329         public IRubyObject method2(final ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
330             //MAX
331
IRubyObject result = null;
332             List JavaDoc arr = eachToList(context,self,module);
333
334             if(block.isGiven()) {
335                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
336                     IRubyObject item = (IRubyObject)iter.next();
337                     if(result == null || (context.yield(context.getRuntime().newArray(item,result), block).callMethod(context, ">", RubyFixnum.zero(context.getRuntime()))).isTrue()) {
338                         result = item;
339                     }
340                 }
341             } else {
342                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
343                     IRubyObject item = (IRubyObject)iter.next();
344                     if(result == null || item.callMethod(context,"<=>", result).callMethod(context, ">", RubyFixnum.zero(context.getRuntime())).isTrue()) {
345                         result = item;
346                     }
347                 }
348             }
349             if(null == result) {
350                 return context.getRuntime().getNil();
351             }
352             return result;
353         }
354         public IRubyObject method3(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
355             //MIN
356
IRubyObject result = null;
357             List JavaDoc arr = eachToList(context,self,module);
358
359             if(block.isGiven()) {
360                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
361                     IRubyObject item = (IRubyObject)iter.next();
362                     if(result == null || (context.yield(context.getRuntime().newArray(item,result), block).callMethod(context, "<", RubyFixnum.zero(context.getRuntime()))).isTrue()) {
363                         result = item;
364                     }
365                 }
366             } else {
367                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
368                     IRubyObject item = (IRubyObject)iter.next();
369                     if(result == null || item.callMethod(context,"<=>", result).callMethod(context, "<", RubyFixnum.zero(context.getRuntime())).isTrue()) {
370                         result = item;
371                     }
372                 }
373             }
374             if(null == result) {
375                 return context.getRuntime().getNil();
376             }
377             return result;
378         }
379         public IRubyObject method4(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
380             //ALL?
381
boolean all = true;
382             List JavaDoc arr = eachToList(context,self,module);
383
384             if (block.isGiven()) {
385                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
386                     if(!context.yield((IRubyObject)iter.next(), block).isTrue()) {
387                         all = false;
388                         break;
389                     }
390                 }
391             } else {
392                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
393                     if(!((IRubyObject)iter.next()).isTrue()) {
394                         all = false;
395                         break;
396                     }
397                 }
398             }
399             return all ? context.getRuntime().getTrue() : context.getRuntime().getFalse();
400         }
401         public IRubyObject method5(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
402             //ANY?
403
boolean any = false;
404             List JavaDoc arr = eachToList(context,self,module);
405
406             if (block.isGiven()) {
407                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
408                     if(context.yield((IRubyObject)iter.next(), block).isTrue()) {
409                         any = true;
410                         break;
411                     }
412                 }
413             } else {
414                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
415                     if(((IRubyObject)iter.next()).isTrue()) {
416                         any = true;
417                         break;
418                     }
419                 }
420             }
421             return any ? context.getRuntime().getTrue() : context.getRuntime().getFalse();
422         }
423         public IRubyObject method6(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
424             //ZIP
425
List JavaDoc arr = eachToList(context,self,module);
426             int ix = 0;
427             List JavaDoc zip = new ArrayList JavaDoc(arr.size());
428             int aLen = args.length+1;
429             if(block.isGiven()) {
430                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
431                     IRubyObject elem = (IRubyObject)iter.next();
432                     List JavaDoc array = new ArrayList JavaDoc(aLen);
433                     array.add(elem);
434                     for(int i=0,j=args.length;i<j;i++) {
435                         array.add(args[i].callMethod(context,"[]", context.getRuntime().newFixnum(ix)));
436                     }
437                     context.yield(context.getRuntime().newArray(array), block);
438                     ix++;
439                 }
440                 return context.getRuntime().getNil();
441             } else {
442                 for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
443                     IRubyObject elem = (IRubyObject)iter.next();
444                     List JavaDoc array = new ArrayList JavaDoc(aLen);
445                     array.add(elem);
446                     for(int i=0,j=args.length;i<j;i++) {
447                         array.add(args[i].callMethod(context,"[]", context.getRuntime().newFixnum(ix)));
448                     }
449                     zip.add(context.getRuntime().newArray(array));
450                     ix++;
451                 }
452             }
453             return context.getRuntime().newArray(zip);
454         }
455         public IRubyObject method7(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
456             //GROUP_BY
457
List JavaDoc arr = eachToList(context,self,module);
458             Map JavaDoc results = new HashMap JavaDoc(arr.size());
459             for(Iterator JavaDoc iter = arr.iterator();iter.hasNext();) {
460                 IRubyObject item = (IRubyObject)iter.next();
461                 IRubyObject key = context.yield(item, block);
462                 IRubyObject curr = (IRubyObject)results.get(key);
463                 if(curr == null) {
464                     curr = context.getRuntime().newArray();
465                     results.put(key,curr);
466                 }
467                 curr.callMethod(context,"<<", item);
468             }
469             return new RubyHash(context.getRuntime(),results,context.getRuntime().getNil());
470         }
471         public IRubyObject method8(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
472             return null;
473         }
474         public IRubyObject method9(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
475             return null;
476         }
477     }
478
479     public static RubyModule createEnumerableModule(Ruby runtime) {
480         RubyModule enm = runtime.defineModule("Enumerable");
481         RubyEnumerableStub0 stub0 = RubyEnumerableStub0.createStub(enm);
482         RubyEnumerableStub1 stub1 = RubyEnumerableStub1.createStub(enm);
483
484         enm.addModuleFunction("to_a", stub0.to_a);
485         enm.addModuleFunction("entries", stub0.to_a);
486         enm.addModuleFunction("sort", stub0.sort);
487         enm.addModuleFunction("sort_by", stub0.sort_by);
488         enm.addModuleFunction("grep", stub0.grep);
489         enm.addModuleFunction("detect", stub0.detect);
490         enm.addModuleFunction("find", stub0.detect);
491         enm.addModuleFunction("select", stub0.select);
492         enm.addModuleFunction("find_all", stub0.select);
493         enm.addModuleFunction("reject", stub0.reject);
494         enm.addModuleFunction("collect", stub0.collect);
495         enm.addModuleFunction("map", stub0.collect);
496         enm.addModuleFunction("inject", stub0.inject);
497         enm.addModuleFunction("partition", stub0.partition);
498
499         enm.addModuleFunction("each_with_index", stub1.each_with_index);
500         enm.addModuleFunction("include?", stub1.include_p);
501         enm.addModuleFunction("member?", stub1.include_p);
502         enm.addModuleFunction("max", stub1.max);
503         enm.addModuleFunction("min", stub1.min);
504         enm.addModuleFunction("all?", stub1.all_p);
505         enm.addModuleFunction("any?", stub1.any_p);
506         enm.addModuleFunction("zip", stub1.zip);
507         enm.addModuleFunction("group_by", stub1.group_by);
508
509         return enm;
510     }
511 }
512
Popular Tags