KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyHash


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) 2001 Chad Fowler <chadfowler@chadfowler.com>
15  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
16  * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
17  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
18  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
19  * Copyright (C) 2004-2006 Thomas E Enebo <enebo@acm.org>
20  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
21  * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
22  * Copyright (C) 2006 Ola Bini <Ola.Bini@ki.se>
23  * Copyright (C) 2006 Tim Azzopardi <tim@tigerfive.com>
24  * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the CPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the CPL, the GPL or the LGPL.
37  ***** END LICENSE BLOCK *****/

38 package org.jruby;
39
40 import java.io.IOException JavaDoc;
41 import java.util.AbstractCollection JavaDoc;
42 import java.util.AbstractSet JavaDoc;
43 import java.util.ArrayList JavaDoc;
44 import java.util.Collection JavaDoc;
45 import java.util.HashMap JavaDoc;
46 import java.util.Iterator JavaDoc;
47 import java.util.Map JavaDoc;
48 import java.util.Set JavaDoc;
49 import org.jruby.javasupport.JavaUtil;
50 import org.jruby.runtime.Arity;
51 import org.jruby.runtime.Block;
52 import org.jruby.runtime.ClassIndex;
53 import org.jruby.runtime.ThreadContext;
54 import org.jruby.runtime.builtin.IRubyObject;
55 import org.jruby.runtime.callback.Callback;
56 import org.jruby.runtime.marshal.MarshalStream;
57 import org.jruby.runtime.marshal.UnmarshalStream;
58
59 /** Implementation of the Hash class.
60  *
61  * @author jpetersen
62  */

63 public class RubyHash extends RubyObject implements Map JavaDoc {
64     private Map JavaDoc valueMap;
65     // Place we capture any explicitly set proc so we can return it for default_proc
66
private IRubyObject capturedDefaultProc;
67     private static final Callback NIL_DEFAULT_VALUE = new Callback() {
68         public IRubyObject execute(IRubyObject recv, IRubyObject[] args, Block block) {
69             return recv.getRuntime().getNil();
70         }
71     
72         public Arity getArity() {
73             return Arity.optional();
74         }
75     };
76     
77     // Holds either default value or default proc. Executing whatever is here will return the
78
// correct default value.
79
private Callback defaultValueCallback;
80     
81     private boolean isRehashing = false;
82
83     public RubyHash(Ruby runtime) {
84         this(runtime, runtime.getNil());
85     }
86
87     public RubyHash(Ruby runtime, IRubyObject defaultValue) {
88         super(runtime, runtime.getClass("Hash"));
89         this.valueMap = new HashMap JavaDoc();
90         this.capturedDefaultProc = runtime.getNil();
91         setDefaultValue(defaultValue);
92     }
93
94     public RubyHash(Ruby runtime, Map JavaDoc valueMap, IRubyObject defaultValue) {
95         super(runtime, runtime.getClass("Hash"));
96         this.valueMap = new HashMap JavaDoc(valueMap);
97         this.capturedDefaultProc = runtime.getNil();
98         setDefaultValue(defaultValue);
99     }
100     
101     public int getNativeTypeIndex() {
102         return ClassIndex.HASH;
103     }
104     
105     public IRubyObject getDefaultValue(IRubyObject[] args, Block unusedBlock) {
106         if(defaultValueCallback == null || (args.length == 0 && !capturedDefaultProc.isNil())) {
107             return getRuntime().getNil();
108         }
109         return defaultValueCallback.execute(this, args, Block.NULL_BLOCK);
110     }
111
112     public IRubyObject setDefaultValue(final IRubyObject defaultValue) {
113         capturedDefaultProc = getRuntime().getNil();
114         if (defaultValue == getRuntime().getNil()) {
115             defaultValueCallback = NIL_DEFAULT_VALUE;
116         } else {
117             defaultValueCallback = new Callback() {
118                 public IRubyObject execute(IRubyObject recv, IRubyObject[] args, Block unusedBlock) {
119                     return defaultValue;
120                 }
121
122                 public Arity getArity() {
123                     return Arity.optional();
124                 }
125             };
126         }
127         
128         return defaultValue;
129     }
130
131     public void setDefaultProc(final RubyProc newProc) {
132         final IRubyObject self = this;
133         capturedDefaultProc = newProc;
134         defaultValueCallback = new Callback() {
135             public IRubyObject execute(IRubyObject recv, IRubyObject[] args, Block unusedBlock) {
136                 IRubyObject[] nargs = args.length == 0 ? new IRubyObject[] { self } :
137                      new IRubyObject[] { self, args[0] };
138
139                 return newProc.call(nargs);
140             }
141
142             public Arity getArity() {
143                 return Arity.optional();
144             }
145         };
146     }
147     
148     public IRubyObject default_proc(Block unusedBlock) {
149         return capturedDefaultProc;
150     }
151
152     public Map JavaDoc getValueMap() {
153         return valueMap;
154     }
155
156     public void setValueMap(Map JavaDoc valueMap) {
157         this.valueMap = valueMap;
158     }
159
160     /**
161      * gets an iterator on a copy of the keySet.
162      * modifying the iterator will NOT modify the map.
163      * if the map is modified while iterating on this iterator, the iterator
164      * will not be invalidated but the content will be the same as the old one.
165      * @return the iterator
166      **/

167     private Iterator JavaDoc keyIterator() {
168         return new ArrayList JavaDoc(valueMap.keySet()).iterator();
169     }
170
171     private Iterator JavaDoc valueIterator() {
172         return new ArrayList JavaDoc(valueMap.values()).iterator();
173     }
174
175
176     /**
177      * gets an iterator on the entries.
178      * modifying this iterator WILL modify the map.
179      * the iterator will be invalidated if the map is modified.
180      * @return the iterator
181      */

182     private Iterator JavaDoc modifiableEntryIterator() {
183         return valueMap.entrySet().iterator();
184     }
185
186     /**
187      * gets an iterator on a copy of the entries.
188      * modifying this iterator will NOT modify the map.
189      * if the map is modified while iterating on this iterator, the iterator
190      * will not be invalidated but the content will be the same as the old one.
191      * @return the iterator
192      */

193     private Iterator JavaDoc entryIterator() {
194         return new ArrayList JavaDoc(valueMap.entrySet()).iterator(); //in general we either want to modify the map or make sure we don't when we use this, so skip the copy
195
}
196
197     /** rb_hash_modify
198      *
199      */

200     public void modify() {
201         testFrozen("Hash");
202         if (isTaint() && getRuntime().getSafeLevel() >= 4) {
203             throw getRuntime().newSecurityError("Insecure: can't modify hash");
204         }
205     }
206
207     private int length() {
208         return valueMap.size();
209     }
210
211     // Hash methods
212

213     public static RubyHash newHash(Ruby runtime) {
214         return new RubyHash(runtime);
215     }
216
217     public static RubyHash newHash(Ruby runtime, Map JavaDoc valueMap, IRubyObject defaultValue) {
218         assert defaultValue != null;
219         
220         return new RubyHash(runtime, valueMap, defaultValue);
221     }
222
223     public IRubyObject initialize(IRubyObject[] args, Block block) {
224         if (block.isGiven()) {
225             setDefaultProc(getRuntime().newProc(false, block));
226         } else if (args.length > 0) {
227             modify();
228
229             setDefaultValue(args[0]);
230         }
231         return this;
232     }
233     
234     public IRubyObject inspect() {
235         if(!getRuntime().registerInspecting(this)) {
236             return getRuntime().newString("{...}");
237         }
238         try {
239             final String JavaDoc sep = ", ";
240             final String JavaDoc arrow = "=>";
241             final StringBuffer JavaDoc sb = new StringBuffer JavaDoc("{");
242             boolean firstEntry = true;
243         
244             ThreadContext context = getRuntime().getCurrentContext();
245         
246             for (Iterator JavaDoc iter = valueMap.entrySet().iterator(); iter.hasNext(); ) {
247                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
248                 IRubyObject key = (IRubyObject) entry.getKey();
249                 IRubyObject value = (IRubyObject) entry.getValue();
250                 if (!firstEntry) {
251                     sb.append(sep);
252                 }
253             
254                 sb.append(key.callMethod(context, "inspect")).append(arrow);
255                 sb.append(value.callMethod(context, "inspect"));
256                 firstEntry = false;
257             }
258             sb.append("}");
259             return getRuntime().newString(sb.toString());
260         } finally {
261             getRuntime().unregisterInspecting(this);
262         }
263     }
264
265     public RubyFixnum rb_size() {
266         return getRuntime().newFixnum(length());
267     }
268
269     public RubyBoolean empty_p() {
270         return length() == 0 ? getRuntime().getTrue() : getRuntime().getFalse();
271     }
272
273     public RubyArray to_a() {
274         Ruby runtime = getRuntime();
275         RubyArray result = RubyArray.newArray(runtime, length());
276         
277         for(Iterator JavaDoc iter = valueMap.entrySet().iterator(); iter.hasNext();) {
278             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
279             result.append(RubyArray.newArray(runtime, (IRubyObject) entry.getKey(), (IRubyObject) entry.getValue()));
280         }
281         return result;
282     }
283
284     public IRubyObject to_s() {
285         if(!getRuntime().registerInspecting(this)) {
286             return getRuntime().newString("{...}");
287         }
288         try {
289             return to_a().to_s();
290         } finally {
291             getRuntime().unregisterInspecting(this);
292         }
293     }
294
295     public RubyHash rehash() {
296         modify();
297         try {
298             isRehashing = true;
299             valueMap = new HashMap JavaDoc(valueMap);
300         } finally {
301             isRehashing = false;
302         }
303         return this;
304     }
305
306     public RubyHash to_hash() {
307         return this;
308     }
309
310     public IRubyObject aset(IRubyObject key, IRubyObject value) {
311         modify();
312         
313         if (!(key instanceof RubyString) || valueMap.get(key) != null) {
314             valueMap.put(key, value);
315         } else {
316             IRubyObject realKey = key.dup();
317             realKey.setFrozen(true);
318             valueMap.put(realKey, value);
319         }
320         return value;
321     }
322
323     public IRubyObject aref(IRubyObject key) {
324         IRubyObject value = (IRubyObject) valueMap.get(key);
325
326         return value != null ? value : callMethod(getRuntime().getCurrentContext(), "default", new IRubyObject[] {key});
327     }
328
329     public IRubyObject fetch(IRubyObject[] args, Block block) {
330         if (args.length < 1) {
331             throw getRuntime().newArgumentError(args.length, 1);
332         }
333         IRubyObject key = args[0];
334         IRubyObject result = (IRubyObject) valueMap.get(key);
335         if (result == null) {
336             if (args.length > 1) return args[1];
337                 
338             if (block.isGiven()) return getRuntime().getCurrentContext().yield(key, block);
339
340             throw getRuntime().newIndexError("key not found");
341         }
342         return result;
343     }
344
345
346     public RubyBoolean has_key(IRubyObject key) {
347         return getRuntime().newBoolean(valueMap.containsKey(key));
348     }
349
350     public RubyBoolean has_value(IRubyObject value) {
351         return getRuntime().newBoolean(valueMap.containsValue(value));
352     }
353
354     public RubyHash each(Block block) {
355         return eachInternal(false, block);
356     }
357
358     public RubyHash each_pair(Block block) {
359         return eachInternal(true, block);
360     }
361
362     protected RubyHash eachInternal(boolean aValue, Block block) {
363         ThreadContext context = getRuntime().getCurrentContext();
364         for (Iterator JavaDoc iter = entryIterator(); iter.hasNext();) {
365             checkRehashing();
366             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
367             block.yield(context, getRuntime().newArray((IRubyObject)entry.getKey(), (IRubyObject)entry.getValue()), null, null, aValue);
368         }
369         return this;
370     }
371
372     
373
374     private void checkRehashing() {
375         if (isRehashing) {
376             throw getRuntime().newIndexError("rehash occured during iteration");
377         }
378     }
379
380     public RubyHash each_value(Block block) {
381         ThreadContext context = getRuntime().getCurrentContext();
382         for (Iterator JavaDoc iter = valueIterator(); iter.hasNext();) {
383             checkRehashing();
384             IRubyObject value = (IRubyObject) iter.next();
385             context.yield(value, block);
386         }
387         return this;
388     }
389
390     public RubyHash each_key(Block block) {
391         ThreadContext context = getRuntime().getCurrentContext();
392         for (Iterator JavaDoc iter = keyIterator(); iter.hasNext();) {
393             checkRehashing();
394             IRubyObject key = (IRubyObject) iter.next();
395             context.yield(key, block);
396         }
397         return this;
398     }
399
400     public RubyArray sort(Block block) {
401         return (RubyArray) to_a().sort_bang(block);
402     }
403
404     public IRubyObject index(IRubyObject value) {
405         for (Iterator JavaDoc iter = valueMap.keySet().iterator(); iter.hasNext(); ) {
406             Object JavaDoc key = iter.next();
407             if (value.equals(valueMap.get(key))) {
408                 return (IRubyObject) key;
409             }
410         }
411         return getRuntime().getNil();
412     }
413
414     public RubyArray indices(IRubyObject[] indices) {
415         RubyArray values = RubyArray.newArray(getRuntime(), indices.length);
416
417         for (int i = 0; i < indices.length; i++) {
418             values.append(aref(indices[i]));
419         }
420
421         return values;
422     }
423
424     public RubyArray keys() {
425         return RubyArray.newArray(getRuntime(), valueMap.keySet());
426     }
427
428     public RubyArray rb_values() {
429         return RubyArray.newArray(getRuntime(), valueMap.values());
430     }
431
432     public IRubyObject equal(IRubyObject other) {
433         if (this == other) {
434             return getRuntime().getTrue();
435         } else if (!(other instanceof RubyHash)) {
436             return getRuntime().getFalse();
437         } else if (length() != ((RubyHash)other).length()) {
438             return getRuntime().getFalse();
439         }
440
441         for (Iterator JavaDoc iter = modifiableEntryIterator(); iter.hasNext();) {
442             checkRehashing();
443             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
444
445             Object JavaDoc value = ((RubyHash)other).valueMap.get(entry.getKey());
446             if (value == null || !entry.getValue().equals(value)) {
447                 return getRuntime().getFalse();
448             }
449         }
450         return getRuntime().getTrue();
451     }
452
453     public RubyArray shift() {
454         modify();
455         Iterator JavaDoc iter = modifiableEntryIterator();
456         Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
457         iter.remove();
458         return RubyArray.newArray(getRuntime(), (IRubyObject)entry.getKey(), (IRubyObject)entry.getValue());
459     }
460
461     public IRubyObject delete(IRubyObject key, Block block) {
462         modify();
463         IRubyObject result = (IRubyObject) valueMap.remove(key);
464         
465         if (result != null) return result;
466         if (block.isGiven()) return getRuntime().getCurrentContext().yield(key, block);
467
468         return getDefaultValue(new IRubyObject[] {key}, null);
469     }
470
471     public RubyHash delete_if(Block block) {
472         reject_bang(block);
473         return this;
474     }
475
476     public RubyHash reject(Block block) {
477         RubyHash result = (RubyHash) dup();
478         result.reject_bang(block);
479         return result;
480     }
481
482     public IRubyObject reject_bang(Block block) {
483         modify();
484         boolean isModified = false;
485         ThreadContext context = getRuntime().getCurrentContext();
486         for (Iterator JavaDoc iter = keyIterator(); iter.hasNext();) {
487             IRubyObject key = (IRubyObject) iter.next();
488             IRubyObject value = (IRubyObject) valueMap.get(key);
489             IRubyObject shouldDelete = block.yield(context, getRuntime().newArray(key, value), null, null, true);
490             if (shouldDelete.isTrue()) {
491                 valueMap.remove(key);
492                 isModified = true;
493             }
494         }
495
496         return isModified ? this : getRuntime().getNil();
497     }
498
499     public RubyHash rb_clear() {
500         modify();
501         valueMap.clear();
502         return this;
503     }
504
505     public RubyHash invert() {
506         RubyHash result = newHash(getRuntime());
507         
508         for (Iterator JavaDoc iter = modifiableEntryIterator(); iter.hasNext();) {
509             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
510             result.aset((IRubyObject) entry.getValue(),
511                     (IRubyObject) entry.getKey());
512         }
513         return result;
514     }
515
516     public RubyHash update(IRubyObject freshElements, Block block) {
517         modify();
518         RubyHash freshElementsHash =
519             (RubyHash) freshElements.convertType(RubyHash.class, "Hash", "to_hash");
520         ThreadContext ctx = getRuntime().getCurrentContext();
521         if (block.isGiven()) {
522             Map JavaDoc other = freshElementsHash.valueMap;
523             for(Iterator JavaDoc iter = other.keySet().iterator();iter.hasNext();) {
524                 IRubyObject key = (IRubyObject)iter.next();
525                 IRubyObject oval = (IRubyObject)valueMap.get(key);
526                 if(null == oval) {
527                     valueMap.put(key,other.get(key));
528                 } else {
529                     valueMap.put(key,ctx.yield(getRuntime().newArrayNoCopy(new IRubyObject[]{key,oval,(IRubyObject)other.get(key)}), block));
530                 }
531             }
532         } else {
533             valueMap.putAll(freshElementsHash.valueMap);
534         }
535         return this;
536     }
537     
538     public RubyHash merge(IRubyObject freshElements, Block block) {
539         return ((RubyHash) dup()).update(freshElements, block);
540     }
541
542     public RubyHash replace(IRubyObject replacement) {
543         modify();
544         RubyHash replacementHash =
545             (RubyHash) replacement.convertType(RubyHash.class, "Hash", "to_hash");
546         valueMap.clear();
547         valueMap.putAll(replacementHash.valueMap);
548         defaultValueCallback = replacementHash.defaultValueCallback;
549         return this;
550     }
551
552     public RubyArray values_at(IRubyObject[] argv) {
553         RubyArray result = RubyArray.newArray(getRuntime());
554         for (int i = 0; i < argv.length; i++) {
555             result.append(aref(argv[i]));
556         }
557         return result;
558     }
559     
560     public boolean hasNonProcDefault() {
561         return defaultValueCallback != NIL_DEFAULT_VALUE;
562     }
563
564     // FIXME: Total hack to get flash in Rails marshalling/unmarshalling in session ok...We need
565
// to totally change marshalling to work with overridden core classes.
566
public static void marshalTo(RubyHash hash, MarshalStream output) throws IOException JavaDoc {
567         output.writeInt(hash.getValueMap().size());
568
569         for (Iterator JavaDoc iter = hash.entryIterator(); iter.hasNext();) {
570                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
571
572                 output.dumpObject((IRubyObject) entry.getKey());
573                 output.dumpObject((IRubyObject) entry.getValue());
574         }
575         
576         // handle default value
577
if (hash.hasNonProcDefault()) {
578             output.dumpObject(hash.defaultValueCallback.execute(null, NULL_ARRAY, null));
579         }
580     }
581
582     public static RubyHash unmarshalFrom(UnmarshalStream input, boolean defaultValue) throws IOException JavaDoc {
583         RubyHash result = newHash(input.getRuntime());
584         input.registerLinkTarget(result);
585         int size = input.unmarshalInt();
586         for (int i = 0; i < size; i++) {
587             IRubyObject key = input.unmarshalObject();
588             IRubyObject value = input.unmarshalObject();
589             result.aset(key, value);
590         }
591         if (defaultValue) {
592             result.setDefaultValue(input.unmarshalObject());
593         }
594         return result;
595     }
596
597     public Class JavaDoc getJavaClass() {
598         return Map JavaDoc.class;
599     }
600     
601     // Satisfy java.util.Set interface (for Java integration)
602

603     public boolean isEmpty() {
604         return valueMap.isEmpty();
605     }
606
607     public boolean containsKey(Object JavaDoc key) {
608         return keySet().contains(key);
609     }
610
611     public boolean containsValue(Object JavaDoc value) {
612         IRubyObject element = JavaUtil.convertJavaToRuby(getRuntime(), value);
613         
614         for (Iterator JavaDoc iter = valueMap.values().iterator(); iter.hasNext(); ) {
615             if (iter.next().equals(element)) {
616                 return true;
617             }
618         }
619         return false;
620     }
621
622     public Object JavaDoc get(Object JavaDoc key) {
623         return JavaUtil.convertRubyToJava((IRubyObject) valueMap.get(JavaUtil.convertJavaToRuby(getRuntime(), key)));
624     }
625
626     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
627         return valueMap.put(JavaUtil.convertJavaToRuby(getRuntime(), key),
628                 JavaUtil.convertJavaToRuby(getRuntime(), value));
629     }
630
631     public Object JavaDoc remove(Object JavaDoc key) {
632         return valueMap.remove(JavaUtil.convertJavaToRuby(getRuntime(), key));
633     }
634
635     public void putAll(Map JavaDoc map) {
636         for (Iterator JavaDoc iter = map.keySet().iterator(); iter.hasNext();) {
637             Object JavaDoc key = iter.next();
638             
639             put(key, map.get(key));
640         }
641     }
642
643
644     public Set JavaDoc entrySet() {
645         return new ConversionMapEntrySet(getRuntime(), valueMap.entrySet());
646     }
647
648     public int size() {
649         return valueMap.size();
650     }
651
652     public void clear() {
653         valueMap.clear();
654     }
655
656     public Collection JavaDoc values() {
657         return new AbstractCollection JavaDoc() {
658             public Iterator JavaDoc iterator() {
659                 return new IteratorAdapter(entrySet().iterator()) {
660                     public Object JavaDoc next() {
661                         return ((Map.Entry JavaDoc) super.next()).getValue();
662                     }
663                 };
664             }
665
666             public int size() {
667                 return RubyHash.this.size();
668             }
669
670             public boolean contains(Object JavaDoc v) {
671                 return RubyHash.this.containsValue(v);
672             }
673         };
674     }
675     
676     public Set JavaDoc keySet() {
677         return new AbstractSet JavaDoc() {
678             public Iterator JavaDoc iterator() {
679                 return new IteratorAdapter(entrySet().iterator()) {
680                     public Object JavaDoc next() {
681                         return ((Map.Entry JavaDoc) super.next()).getKey();
682                     }
683                 };
684             }
685
686             public int size() {
687                 return RubyHash.this.size();
688             }
689         };
690     }
691
692     /**
693      * Convenience adaptor for delegating to an Iterator.
694      *
695      */

696     private static class IteratorAdapter implements Iterator JavaDoc {
697         private Iterator JavaDoc iterator;
698         
699         public IteratorAdapter(Iterator JavaDoc iterator) {
700             this.iterator = iterator;
701         }
702         public boolean hasNext() {
703             return iterator.hasNext();
704         }
705         public Object JavaDoc next() {
706             return iterator.next();
707         }
708         public void remove() {
709             iterator.remove();
710         }
711     }
712     
713     
714     /**
715      * Wraps a Set of Map.Entry (See #entrySet) such that JRuby types are mapped to Java types and vice verce.
716      *
717      */

718     private static class ConversionMapEntrySet extends AbstractSet JavaDoc {
719         protected Set JavaDoc mapEntrySet;
720         protected Ruby runtime;
721
722         public ConversionMapEntrySet(Ruby runtime, Set JavaDoc mapEntrySet) {
723             this.mapEntrySet = mapEntrySet;
724             this.runtime = runtime;
725         }
726         public Iterator JavaDoc iterator() {
727             return new ConversionMapEntryIterator(runtime, mapEntrySet.iterator());
728         }
729         public boolean contains(Object JavaDoc o) {
730             if (!(o instanceof Map.Entry JavaDoc)) {
731                 return false;
732             }
733             return mapEntrySet.contains(getRubifiedMapEntry((Map.Entry JavaDoc) o));
734         }
735         
736         public boolean remove(Object JavaDoc o) {
737             if (!(o instanceof Map.Entry JavaDoc)) {
738                 return false;
739             }
740             return mapEntrySet.remove(getRubifiedMapEntry((Map.Entry JavaDoc) o));
741         }
742         public int size() {
743             return mapEntrySet.size();
744         }
745         public void clear() {
746             mapEntrySet.clear();
747         }
748         private Entry getRubifiedMapEntry(final Map.Entry JavaDoc mapEntry) {
749             return new Map.Entry JavaDoc(){
750                 public Object JavaDoc getKey() {
751                     return JavaUtil.convertJavaToRuby(runtime, mapEntry.getKey());
752                 }
753                 public Object JavaDoc getValue() {
754                     return JavaUtil.convertJavaToRuby(runtime, mapEntry.getValue());
755                 }
756                 public Object JavaDoc setValue(Object JavaDoc arg0) {
757                     // This should never get called in this context, but if it did...
758
throw new UnsupportedOperationException JavaDoc("unexpected call in this context");
759                 }
760             };
761         }
762     }
763     
764     /**
765      * Wraps a RubyHash#entrySet#iterator such that the Map.Entry returned by next() will have its key and value
766      * mapped from JRuby types to Java types where applicable.
767      */

768     private static class ConversionMapEntryIterator implements Iterator JavaDoc {
769         private Iterator JavaDoc iterator;
770         private Ruby runtime;
771
772         public ConversionMapEntryIterator(Ruby runtime, Iterator JavaDoc iterator) {
773             this.iterator = iterator;
774             this.runtime = runtime;
775         }
776
777         public boolean hasNext() {
778             return iterator.hasNext();
779         }
780
781         public Object JavaDoc next() {
782             return new ConversionMapEntry(runtime, ((Map.Entry JavaDoc) iterator.next()));
783         }
784
785         public void remove() {
786             iterator.remove();
787         }
788     }
789     
790    
791     /**
792      * Wraps a Map.Entry from RubyHash#entrySet#iterator#next such that the the key and value
793      * are mapped from/to JRuby/Java types where applicable.
794      */

795     private static class ConversionMapEntry implements Map.Entry JavaDoc {
796         private Entry entry;
797         private Ruby runtime;
798
799         public ConversionMapEntry(Ruby runtime, Map.Entry JavaDoc entry) {
800             this.entry = entry;
801             this.runtime = runtime;
802         }
803         
804         public Object JavaDoc getKey() {
805             IRubyObject rubyObject = (IRubyObject) entry.getKey();
806             return JavaUtil.convertRubyToJava(rubyObject, Object JavaDoc.class);
807         }
808         
809         public Object JavaDoc getValue() {
810             IRubyObject rubyObject = (IRubyObject) entry.getValue();
811             return JavaUtil.convertRubyToJava(rubyObject, Object JavaDoc.class);
812         }
813         
814         public Object JavaDoc setValue(Object JavaDoc value) {
815             return entry.setValue(JavaUtil.convertJavaToRuby(runtime, value));
816         }
817     }
818     
819 }
820
Popular Tags