KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyModule


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 Thomas E Enebo <enebo@acm.org>
20  * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
21  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
22  * Copyright (C) 2006-2007 Miguel Covarrubias <mlcovarrubias@gmail.com>
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either of the GNU General Public License Version 2 or later (the "GPL"),
26  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the CPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the CPL, the GPL or the LGPL.
35  ***** END LICENSE BLOCK *****/

36 package org.jruby;
37
38 import java.util.ArrayList JavaDoc;
39 import java.util.HashMap JavaDoc;
40 import java.util.Iterator JavaDoc;
41 import java.util.HashSet JavaDoc;
42 import java.util.List JavaDoc;
43 import java.util.Map JavaDoc;
44 import java.util.Set JavaDoc;
45 import org.jruby.internal.runtime.methods.AliasMethod;
46 import org.jruby.internal.runtime.methods.DynamicMethod;
47 import org.jruby.internal.runtime.methods.FullFunctionCallbackMethod;
48 import org.jruby.internal.runtime.methods.SimpleCallbackMethod;
49 import org.jruby.internal.runtime.methods.MethodMethod;
50 import org.jruby.internal.runtime.methods.ProcMethod;
51 import org.jruby.internal.runtime.methods.UndefinedMethod;
52 import org.jruby.internal.runtime.methods.WrapperMethod;
53 import org.jruby.runtime.Arity;
54 import org.jruby.runtime.Block;
55 import org.jruby.runtime.ObjectAllocator;
56 import org.jruby.runtime.ThreadContext;
57 import org.jruby.runtime.Visibility;
58 import org.jruby.runtime.builtin.IRubyObject;
59 import org.jruby.runtime.callback.Callback;
60 import org.jruby.runtime.marshal.MarshalStream;
61 import org.jruby.runtime.marshal.UnmarshalStream;
62 import org.jruby.util.IdUtil;
63 import org.jruby.util.collections.SinglyLinkedList;
64 import org.jruby.exceptions.RaiseException;
65 import org.jruby.runtime.ClassIndex;
66
67 /**
68  *
69  * @author jpetersen
70  */

71 public class RubyModule extends RubyObject {
72     private static final String JavaDoc CVAR_TAINT_ERROR =
73         "Insecure: can't modify class variable";
74     private static final String JavaDoc CVAR_FREEZE_ERROR = "class/module";
75
76     // superClass may be null.
77
private RubyClass superClass;
78
79     public int index;
80
81     public final int id;
82
83     // Containing class...The parent of Object is null. Object should always be last in chain.
84
//public RubyModule parentModule;
85

86     // CRef...to eventually replace parentModule
87
public SinglyLinkedList cref;
88
89     // ClassId is the name of the class/module sans where it is located.
90
// If it is null, then it an anonymous class.
91
private String JavaDoc classId;
92
93     // All methods and all CACHED methods for the module. The cached methods will be removed
94
// when appropriate (e.g. when method is removed by source class or a new method is added
95
// with same name by one of its subclasses).
96
private Map JavaDoc methods = new HashMap JavaDoc();
97
98     protected RubyModule(Ruby runtime, RubyClass metaClass, RubyClass superClass, SinglyLinkedList parentCRef, String JavaDoc name) {
99         super(runtime, metaClass);
100
101         this.superClass = superClass;
102
103         setBaseName(name);
104
105         // If no parent is passed in, it is safe to assume Object.
106
if (parentCRef == null) {
107             if (runtime.getObject() != null) {
108                 parentCRef = runtime.getObject().getCRef();
109             }
110         }
111         this.cref = new SinglyLinkedList(this, parentCRef);
112
113         runtime.moduleLastId++;
114         this.id = runtime.moduleLastId;
115     }
116     
117     public int getNativeTypeIndex() {
118         return ClassIndex.MODULE;
119     }
120
121     /** Getter for property superClass.
122      * @return Value of property superClass.
123      */

124     public RubyClass getSuperClass() {
125         return superClass;
126     }
127
128     protected void setSuperClass(RubyClass superClass) {
129         this.superClass = superClass;
130     }
131
132     public RubyModule getParent() {
133         if (cref.getNext() == null) {
134             return null;
135         }
136
137         return (RubyModule)cref.getNext().getValue();
138     }
139
140     public void setParent(RubyModule p) {
141         cref.setNext(p.getCRef());
142     }
143
144     public Map JavaDoc getMethods() {
145         return methods;
146     }
147
148     public boolean isModule() {
149         return true;
150     }
151
152     public boolean isClass() {
153         return false;
154     }
155
156     public boolean isSingleton() {
157         return false;
158     }
159
160     /**
161      * Is this module one that in an included one (e.g. an IncludedModuleWrapper).
162      */

163     public boolean isIncluded() {
164         return false;
165     }
166
167     public RubyModule getNonIncludedClass() {
168         return this;
169     }
170
171     public String JavaDoc getBaseName() {
172         return classId;
173     }
174
175     public void setBaseName(String JavaDoc name) {
176         classId = name;
177     }
178
179     /**
180      * Generate a fully-qualified class name or a #-style name for anonymous and singleton classes.
181      *
182      * Ruby C equivalent = "classname"
183      *
184      * @return The generated class name
185      */

186     public String JavaDoc getName() {
187         if (getBaseName() == null) {
188             if (isClass()) {
189                 return "#<" + "Class" + ":01x" + Integer.toHexString(System.identityHashCode(this)) + ">";
190             } else {
191                 return "#<" + "Module" + ":01x" + Integer.toHexString(System.identityHashCode(this)) + ">";
192             }
193         }
194
195         StringBuffer JavaDoc result = new StringBuffer JavaDoc(getBaseName());
196         RubyClass objectClass = getRuntime().getObject();
197
198         for (RubyModule p = this.getParent(); p != null && p != objectClass; p = p.getParent()) {
199             result.insert(0, "::").insert(0, p.getBaseName());
200         }
201
202         return result.toString();
203     }
204
205     /**
206      * Create a wrapper to use for including the specified module into this one.
207      *
208      * Ruby C equivalent = "include_class_new"
209      *
210      * @return The module wrapper
211      */

212     public IncludedModuleWrapper newIncludeClass(RubyClass superClazz) {
213         IncludedModuleWrapper includedModule = new IncludedModuleWrapper(getRuntime(), superClazz, this);
214
215         // include its parent (and in turn that module's parents)
216
if (getSuperClass() != null) {
217             includedModule.includeModule(getSuperClass());
218         }
219
220         return includedModule;
221     }
222
223     /**
224      * Search this and parent modules for the named variable.
225      *
226      * @param name The variable to search for
227      * @return The module in which that variable is found, or null if not found
228      */

229     private RubyModule getModuleWithInstanceVar(String JavaDoc name) {
230         for (RubyModule p = this; p != null; p = p.getSuperClass()) {
231             if (p.getInstanceVariable(name) != null) {
232                 return p;
233             }
234         }
235         return null;
236     }
237
238     /**
239      * Set the named class variable to the given value, provided taint and freeze allow setting it.
240      *
241      * Ruby C equivalent = "rb_cvar_set"
242      *
243      * @param name The variable name to set
244      * @param value The value to set it to
245      */

246     public IRubyObject setClassVar(String JavaDoc name, IRubyObject value) {
247         RubyModule module = getModuleWithInstanceVar(name);
248
249         if (module == null) {
250             module = this;
251         }
252
253         return module.setInstanceVariable(name, value, CVAR_TAINT_ERROR, CVAR_FREEZE_ERROR);
254     }
255
256     /**
257      * Retrieve the specified class variable, searching through this module, included modules, and supermodules.
258      *
259      * Ruby C equivalent = "rb_cvar_get"
260      *
261      * @param name The name of the variable to retrieve
262      * @return The variable's value, or throws NameError if not found
263      */

264     public IRubyObject getClassVar(String JavaDoc name) {
265         RubyModule module = getModuleWithInstanceVar(name);
266
267         if (module != null) {
268             IRubyObject variable = module.getInstanceVariable(name);
269
270             return variable == null ? getRuntime().getNil() : variable;
271         }
272
273         throw getRuntime().newNameError("uninitialized class variable " + name + " in " + getName(), name);
274     }
275
276     /**
277      * Is class var defined?
278      *
279      * Ruby C equivalent = "rb_cvar_defined"
280      *
281      * @param name The class var to determine "is defined?"
282      * @return true if true, false if false
283      */

284     public boolean isClassVarDefined(String JavaDoc name) {
285         return getModuleWithInstanceVar(name) != null;
286     }
287
288     /**
289      * Set the named constant on this module. Also, if the value provided is another Module and
290      * that module has not yet been named, assign it the specified name.
291      *
292      * @param name The name to assign
293      * @param value The value to assign to it; if an unnamed Module, also set its basename to name
294      * @return The result of setting the variable.
295      * @see RubyObject#setInstanceVariable(String, IRubyObject, String, String)
296      */

297     public IRubyObject setConstant(String JavaDoc name, IRubyObject value) {
298         if(getConstantAt(name) != null) {
299             getRuntime().getWarnings().warn("already initialized constant " + name);
300         }
301
302         IRubyObject result = setInstanceVariable(name, value, "Insecure: can't set constant",
303                 "class/module");
304
305         // if adding a module under a constant name, set that module's basename to the constant name
306
if (value instanceof RubyModule) {
307             RubyModule module = (RubyModule)value;
308             if (module.getBaseName() == null) {
309                 module.setBaseName(name);
310                 module.setParent(this);
311             }
312             /*
313             module.setParent(this);
314             */

315         }
316         return result;
317     }
318
319     /**
320      * Finds a class that is within the current module (or class).
321      *
322      * @param name to be found in this module (or class)
323      * @return the class or null if no such class
324      */

325     public RubyClass getClass(String JavaDoc name) {
326         IRubyObject module = getConstantAt(name);
327
328         return (module instanceof RubyClass) ? (RubyClass) module : null;
329     }
330
331     /**
332      * Base implementation of Module#const_missing, throws NameError for specific missing constant.
333      *
334      * @param name The constant name which was found to be missing
335      * @return Nothing! Absolutely nothing! (though subclasses might choose to return something)
336      */

337     public IRubyObject const_missing(IRubyObject name, Block block) {
338         /* Uninitialized constant */
339         if (this != getRuntime().getObject()) {
340             throw getRuntime().newNameError("uninitialized constant " + getName() + "::" + name.asSymbol(), "" + getName() + "::" + name.asSymbol());
341         }
342
343         throw getRuntime().newNameError("uninitialized constant " + name.asSymbol(), name.asSymbol());
344     }
345
346     /**
347      * Include a new module in this module or class.
348      *
349      * @param arg The module to include
350      */

351     public synchronized void includeModule(IRubyObject arg) {
352         assert arg != null;
353
354         testFrozen("module");
355         if (!isTaint()) {
356             getRuntime().secure(4);
357         }
358
359         if (!(arg instanceof RubyModule)) {
360             throw getRuntime().newTypeError("Wrong argument type " + arg.getMetaClass().getName() +
361                     " (expected Module).");
362         }
363
364         RubyModule module = (RubyModule) arg;
365
366         // Make sure the module we include does not already exist
367
if (isSame(module)) {
368             return;
369         }
370
371         infectBy(module);
372
373         RubyModule p, c;
374         boolean changed = false;
375         boolean skip = false;
376
377         c = this;
378         while (module != null) {
379             if (getNonIncludedClass() == module.getNonIncludedClass()) {
380                 throw getRuntime().newArgumentError("cyclic include detected");
381             }
382
383             boolean superclassSeen = false;
384             for (p = getSuperClass(); p != null; p = p.getSuperClass()) {
385                 if (p instanceof IncludedModuleWrapper) {
386                     if (p.getNonIncludedClass() == module.getNonIncludedClass()) {
387                         if (!superclassSeen) {
388                             c = p;
389                         }
390                         skip = true;
391                         break;
392                     }
393                 } else {
394                     superclassSeen = true;
395                 }
396             }
397             if (!skip) {
398                 // In the current logic, if we get here we know that module is not an
399
// IncludedModuleWrapper, so there's no need to fish out the delegate. But just
400
// in case the logic should change later, let's do it anyway:
401
c.setSuperClass(new IncludedModuleWrapper(getRuntime(), c.getSuperClass(),
402                         module.getNonIncludedClass()));
403                 c = c.getSuperClass();
404                 changed = true;
405             }
406
407             module = module.getSuperClass();
408             skip = false;
409         }
410
411         if (changed) {
412             // MRI seems to blow away its cache completely after an include; is
413
// what we're doing here really safe?
414
List JavaDoc methodNames = new ArrayList JavaDoc(((RubyModule) arg).getMethods().keySet());
415             for (Iterator JavaDoc iter = methodNames.iterator();
416                  iter.hasNext();) {
417                 String JavaDoc methodName = (String JavaDoc) iter.next();
418                 getRuntime().getCacheMap().remove(methodName, searchMethod(methodName));
419             }
420         }
421
422     }
423
424     public void defineMethod(String JavaDoc name, Callback method) {
425         Visibility visibility = name.equals("initialize") ?
426                 Visibility.PRIVATE : Visibility.PUBLIC;
427         addMethod(name, new FullFunctionCallbackMethod(this, method, visibility));
428     }
429
430     public void defineFastMethod(String JavaDoc name, Callback method) {
431         Visibility visibility = name.equals("initialize") ?
432                 Visibility.PRIVATE : Visibility.PUBLIC;
433         addMethod(name, new SimpleCallbackMethod(this, method, visibility));
434     }
435
436     public void definePrivateMethod(String JavaDoc name, Callback method) {
437         addMethod(name, new FullFunctionCallbackMethod(this, method, Visibility.PRIVATE));
438     }
439
440     public void defineFastPrivateMethod(String JavaDoc name, Callback method) {
441         addMethod(name, new SimpleCallbackMethod(this, method, Visibility.PRIVATE));
442     }
443
444     public void undefineMethod(String JavaDoc name) {
445         addMethod(name, UndefinedMethod.getInstance());
446     }
447
448     /** rb_undef
449      *
450      */

451     public void undef(String JavaDoc name) {
452         Ruby runtime = getRuntime();
453         if (this == runtime.getObject()) {
454             runtime.secure(4);
455         }
456         if (runtime.getSafeLevel() >= 4 && !isTaint()) {
457             throw new SecurityException JavaDoc("Insecure: can't undef");
458         }
459         testFrozen("module");
460         if (name.equals("__id__") || name.equals("__send__")) {
461             getRuntime().getWarnings().warn("undefining `"+ name +"' may cause serious problem");
462         }
463         DynamicMethod method = searchMethod(name);
464         if (method.isUndefined()) {
465             String JavaDoc s0 = " class";
466             RubyModule c = this;
467
468             if (c.isSingleton()) {
469                 IRubyObject obj = getInstanceVariable("__attached__");
470
471                 if (obj != null && obj instanceof RubyModule) {
472                     c = (RubyModule) obj;
473                     s0 = "";
474                 }
475             } else if (c.isModule()) {
476                 s0 = " module";
477             }
478
479             throw getRuntime().newNameError("Undefined method " + name + " for" + s0 + " '" + c.getName() + "'", name);
480         }
481         addMethod(name, UndefinedMethod.getInstance());
482         
483         if(isSingleton()){
484             IRubyObject singleton = getInstanceVariable("__attached__");
485             singleton.callMethod(runtime.getCurrentContext(), "singleton_method_undefined", getRuntime().newSymbol(name));
486         }else{
487             callMethod(runtime.getCurrentContext(), "method_undefined", getRuntime().newSymbol(name));
488     }
489     }
490
491     private void addCachedMethod(String JavaDoc name, DynamicMethod method) {
492         // Included modules modify the original 'included' modules class. Since multiple
493
// classes can include the same module, we cannot cache in the original included module.
494
if (!isIncluded()) {
495             getMethods().put(name, method);
496             getRuntime().getCacheMap().add(method, this);
497         }
498     }
499
500     // TODO: Consider a better way of synchronizing
501
public void addMethod(String JavaDoc name, DynamicMethod method) {
502         if (this == getRuntime().getObject()) {
503             getRuntime().secure(4);
504         }
505
506         if (getRuntime().getSafeLevel() >= 4 && !isTaint()) {
507             throw getRuntime().newSecurityError("Insecure: can't define method");
508         }
509         testFrozen("class/module");
510
511         // We can safely reference methods here instead of doing getMethods() since if we
512
// are adding we are not using a IncludedModuleWrapper.
513
synchronized(getMethods()) {
514             // If we add a method which already is cached in this class, then we should update the
515
// cachemap so it stays up to date.
516
DynamicMethod existingMethod = (DynamicMethod) getMethods().remove(name);
517             if (existingMethod != null) {
518                 getRuntime().getCacheMap().remove(name, existingMethod);
519             }
520
521             getMethods().put(name, method);
522         }
523     }
524
525     public void removeCachedMethod(String JavaDoc name) {
526         getMethods().remove(name);
527     }
528
529     public void removeMethod(String JavaDoc name) {
530         if (this == getRuntime().getObject()) {
531             getRuntime().secure(4);
532         }
533         if (getRuntime().getSafeLevel() >= 4 && !isTaint()) {
534             throw getRuntime().newSecurityError("Insecure: can't remove method");
535         }
536         testFrozen("class/module");
537
538         // We can safely reference methods here instead of doing getMethods() since if we
539
// are adding we are not using a IncludedModuleWrapper.
540
synchronized(getMethods()) {
541             DynamicMethod method = (DynamicMethod) getMethods().remove(name);
542             if (method == null) {
543                 throw getRuntime().newNameError("method '" + name + "' not defined in " + getName(), name);
544             }
545
546             getRuntime().getCacheMap().remove(name, method);
547         }
548         
549         if(isSingleton()){
550             IRubyObject singleton = getInstanceVariable("__attached__");
551             singleton.callMethod(getRuntime().getCurrentContext(), "singleton_method_removed", getRuntime().newSymbol(name));
552         }else{
553             callMethod(getRuntime().getCurrentContext(), "method_removed", getRuntime().newSymbol(name));
554     }
555     }
556
557     /**
558      * Search through this module and supermodules for method definitions. Cache superclass definitions in this class.
559      *
560      * @param name The name of the method to search for
561      * @return The method, or UndefinedMethod if not found
562      */

563     public DynamicMethod searchMethod(String JavaDoc name) {
564         for (RubyModule searchModule = this; searchModule != null; searchModule = searchModule.getSuperClass()) {
565             // included modules use delegates methods for we need to synchronize on result of getMethods
566
synchronized(searchModule.getMethods()) {
567                 // See if current class has method or if it has been cached here already
568
DynamicMethod method = (DynamicMethod) searchModule.getMethods().get(name);
569                 if (method != null) {
570                     if (searchModule != this) {
571                         addCachedMethod(name, method);
572                     }
573
574                     return method;
575                 }
576             }
577         }
578
579         return UndefinedMethod.getInstance();
580     }
581
582     /**
583      * Search through this module and supermodules for method definitions. Cache superclass definitions in this class.
584      *
585      * @param name The name of the method to search for
586      * @return The method, or UndefinedMethod if not found
587      */

588     public DynamicMethod retrieveMethod(String JavaDoc name) {
589         return (DynamicMethod)getMethods().get(name);
590     }
591
592     /**
593      * Search through this module and supermodules for method definitions. Cache superclass definitions in this class.
594      *
595      * @param name The name of the method to search for
596      * @return The method, or UndefinedMethod if not found
597      */

598     public RubyModule findImplementer(RubyModule clazz) {
599         for (RubyModule searchModule = this; searchModule != null; searchModule = searchModule.getSuperClass()) {
600             if (searchModule.isSame(clazz)) {
601                 return searchModule;
602             }
603         }
604
605         return null;
606     }
607
608     public void addModuleFunction(String JavaDoc name, DynamicMethod method) {
609         addMethod(name, method);
610         getSingletonClass().addMethod(name, method);
611     }
612
613     /** rb_define_module_function
614      *
615      */

616     public void defineModuleFunction(String JavaDoc name, Callback method) {
617         definePrivateMethod(name, method);
618         getSingletonClass().defineMethod(name, method);
619     }
620
621     /** rb_define_module_function
622      *
623      */

624     public void definePublicModuleFunction(String JavaDoc name, Callback method) {
625         defineMethod(name, method);
626         getSingletonClass().defineMethod(name, method);
627     }
628
629     /** rb_define_module_function
630      *
631      */

632     public void defineFastModuleFunction(String JavaDoc name, Callback method) {
633         defineFastPrivateMethod(name, method);
634         getSingletonClass().defineFastMethod(name, method);
635     }
636
637     /** rb_define_module_function
638      *
639      */

640     public void defineFastPublicModuleFunction(String JavaDoc name, Callback method) {
641         defineFastMethod(name, method);
642         getSingletonClass().defineFastMethod(name, method);
643     }
644
645     private IRubyObject getConstantInner(String JavaDoc name, boolean exclude) {
646         IRubyObject objectClass = getRuntime().getObject();
647         boolean retryForModule = false;
648         RubyModule p = this;
649
650         retry: while (true) {
651             while (p != null) {
652                 IRubyObject constant = p.getConstantAt(name);
653
654                 if (constant == null) {
655                     if (getRuntime().getLoadService().autoload(p.getName() + "::" + name) != null) {
656                         continue;
657                     }
658                 }
659                 if (constant != null) {
660                     if (exclude && p == objectClass && this != objectClass) {
661                         getRuntime().getWarnings().warn("toplevel constant " + name +
662                                 " referenced by " + getName() + "::" + name);
663                     }
664
665                     return constant;
666                 }
667                 p = p.getSuperClass();
668             }
669
670             if (!exclude && !retryForModule && getClass().equals(RubyModule.class)) {
671                 retryForModule = true;
672                 p = getRuntime().getObject();
673                 continue retry;
674             }
675
676             break;
677         }
678
679         return callMethod(getRuntime().getCurrentContext(), "const_missing", RubySymbol.newSymbol(getRuntime(), name));
680     }
681
682     /**
683      * Retrieve the named constant, invoking 'const_missing' should that be appropriate.
684      *
685      * @param name The constant to retrieve
686      * @return The value for the constant, or null if not found
687      */

688     public IRubyObject getConstant(String JavaDoc name) {
689         return getConstantInner(name, false);
690     }
691
692     public IRubyObject getConstantFrom(String JavaDoc name) {
693         return getConstantInner(name, true);
694     }
695
696     public IRubyObject getConstantAt(String JavaDoc name) {
697         return getInstanceVariable(name);
698     }
699
700     /** rb_alias
701      *
702      */

703     public synchronized void defineAlias(String JavaDoc name, String JavaDoc oldName) {
704         testFrozen("module");
705         if (oldName.equals(name)) {
706             return;
707         }
708         if (this == getRuntime().getObject()) {
709             getRuntime().secure(4);
710         }
711         DynamicMethod method = searchMethod(oldName);
712         if (method.isUndefined()) {
713             if (isModule()) {
714                 method = getRuntime().getObject().searchMethod(oldName);
715             }
716
717             if (method.isUndefined()) {
718                 throw getRuntime().newNameError("undefined method `" + oldName + "' for " +
719                         (isModule() ? "module" : "class") + " `" + getName() + "'", oldName);
720             }
721         }
722         getRuntime().getCacheMap().remove(name, searchMethod(name));
723         getMethods().put(name, new AliasMethod(method, oldName));
724     }
725
726     public RubyClass defineOrGetClassUnder(String JavaDoc name, RubyClass superClazz) {
727         // This method is intended only for defining new classes in Ruby code,
728
// so it uses the allocator of the specified superclass or default to
729
// the Object allocator. It should NOT be used to define classes that require a native allocator.
730
IRubyObject type = getConstantAt(name);
731         ObjectAllocator allocator = superClazz == null ? getRuntime().getObject().getAllocator() : superClazz.getAllocator();
732
733         if (type == null) {
734             return getRuntime().defineClassUnder(name, superClazz, allocator, cref);
735         }
736
737         if (!(type instanceof RubyClass)) {
738             throw getRuntime().newTypeError(name + " is not a class.");
739         } else if (superClazz != null && ((RubyClass) type).getSuperClass().getRealClass() != superClazz) {
740             throw getRuntime().newTypeError("superclass mismatch for class " + name);
741         }
742
743         return (RubyClass) type;
744     }
745
746     /** rb_define_class_under
747      *
748      */

749     public RubyClass defineClassUnder(String JavaDoc name, RubyClass superClazz, ObjectAllocator allocator) {
750         IRubyObject type = getConstantAt(name);
751
752         if (type == null) {
753             return getRuntime().defineClassUnder(name, superClazz, allocator, cref);
754         }
755
756         if (!(type instanceof RubyClass)) {
757             throw getRuntime().newTypeError(name + " is not a class.");
758         } else if (((RubyClass) type).getSuperClass().getRealClass() != superClazz) {
759             throw getRuntime().newNameError(name + " is already defined.", name);
760         }
761
762         return (RubyClass) type;
763     }
764
765     public RubyModule defineModuleUnder(String JavaDoc name) {
766         IRubyObject type = getConstantAt(name);
767
768         if (type == null) {
769             return getRuntime().defineModuleUnder(name, cref);
770         }
771
772         if (!(type instanceof RubyModule)) {
773             throw getRuntime().newTypeError(name + " is not a module.");
774         }
775
776         return (RubyModule) type;
777     }
778
779     /** rb_define_const
780      *
781      */

782     public void defineConstant(String JavaDoc name, IRubyObject value) {
783         assert value != null;
784
785         if (this == getRuntime().getClass("Class")) {
786             getRuntime().secure(4);
787         }
788
789         if (!IdUtil.isConstant(name)) {
790             throw getRuntime().newNameError("bad constant name " + name, name);
791         }
792
793         setConstant(name, value);
794     }
795
796     /** rb_mod_remove_cvar
797      *
798      */

799     public IRubyObject removeCvar(IRubyObject name) { // Wrong Parameter ?
800
if (!IdUtil.isClassVariable(name.asSymbol())) {
801             throw getRuntime().newNameError("wrong class variable name " + name.asSymbol(), name.asSymbol());
802         }
803
804         if (!isTaint() && getRuntime().getSafeLevel() >= 4) {
805             throw getRuntime().newSecurityError("Insecure: can't remove class variable");
806         }
807         testFrozen("class/module");
808
809         IRubyObject value = removeInstanceVariable(name.asSymbol());
810
811         if (value != null) {
812             return value;
813         }
814
815         if (isClassVarDefined(name.asSymbol())) {
816             throw cannotRemoveError(name.asSymbol());
817         }
818
819         throw getRuntime().newNameError("class variable " + name.asSymbol() + " not defined for " + getName(), name.asSymbol());
820     }
821
822     private void addAccessor(String JavaDoc name, boolean readable, boolean writeable) {
823         ThreadContext tc = getRuntime().getCurrentContext();
824
825         // Check the visibility of the previous frame, which will be the frame in which the class is being eval'ed
826
Visibility attributeScope = tc.getCurrentVisibility();
827         if (attributeScope.isPrivate()) {
828             //FIXME warning
829
} else if (attributeScope.isModuleFunction()) {
830             attributeScope = Visibility.PRIVATE;
831             // FIXME warning
832
}
833         final String JavaDoc variableName = "@" + name;
834         final Ruby runtime = getRuntime();
835         ThreadContext context = getRuntime().getCurrentContext();
836         if (readable) {
837             defineMethod(name, new Callback() {
838                 public IRubyObject execute(IRubyObject self, IRubyObject[] args, Block block) {
839                     checkArgumentCount(args, 0, 0);
840
841                     IRubyObject variable = self.getInstanceVariable(variableName);
842
843                     return variable == null ? runtime.getNil() : variable;
844                 }
845
846                 public Arity getArity() {
847                     return Arity.noArguments();
848                 }
849             });
850             callMethod(context, "method_added", RubySymbol.newSymbol(getRuntime(), name));
851         }
852         if (writeable) {
853             name = name + "=";
854             defineMethod(name, new Callback() {
855                 public IRubyObject execute(IRubyObject self, IRubyObject[] args, Block block) {
856                     IRubyObject[] fargs = runtime.getCurrentContext().getFrameArgs();
857
858                     if (fargs.length != 1) {
859                         throw runtime.newArgumentError("wrong # of arguments(" + fargs.length + "for 1)");
860                     }
861
862                     return self.setInstanceVariable(variableName, fargs[0]);
863                 }
864
865                 public Arity getArity() {
866                     return Arity.singleArgument();
867                 }
868             });
869             callMethod(context, "method_added", RubySymbol.newSymbol(getRuntime(), name));
870         }
871     }
872
873     /** set_method_visibility
874      *
875      */

876     public void setMethodVisibility(IRubyObject[] methods, Visibility visibility) {
877         if (getRuntime().getSafeLevel() >= 4 && !isTaint()) {
878             throw getRuntime().newSecurityError("Insecure: can't change method visibility");
879         }
880
881         for (int i = 0; i < methods.length; i++) {
882             exportMethod(methods[i].asSymbol(), visibility);
883         }
884     }
885
886     /** rb_export_method
887      *
888      */

889     public void exportMethod(String JavaDoc name, Visibility visibility) {
890         if (this == getRuntime().getObject()) {
891             getRuntime().secure(4);
892         }
893
894         DynamicMethod method = searchMethod(name);
895
896         if (method.isUndefined()) {
897             throw getRuntime().newNameError("undefined method '" + name + "' for " +
898                                 (isModule() ? "module" : "class") + " '" + getName() + "'", name);
899         }
900
901         if (method.getVisibility() != visibility) {
902             if (this == method.getImplementationClass()) {
903                 method.setVisibility(visibility);
904             } else {
905                 addMethod(name, new FullFunctionCallbackMethod(this, new Callback() {
906                     public IRubyObject execute(IRubyObject self, IRubyObject[] args, Block block) {
907                         ThreadContext tc = self.getRuntime().getCurrentContext();
908                         return tc.callSuper(tc.getFrameArgs(), block);
909                     }
910
911                     public Arity getArity() {
912                         return Arity.optional();
913                     }
914                 }, visibility));
915             }
916         }
917     }
918
919     /**
920      * MRI: rb_method_boundp
921      *
922      */

923     public boolean isMethodBound(String JavaDoc name, boolean checkVisibility) {
924         DynamicMethod method = searchMethod(name);
925         if (!method.isUndefined()) {
926             return !(checkVisibility && method.getVisibility().isPrivate());
927         }
928         return false;
929     }
930
931     public IRubyObject newMethod(IRubyObject receiver, String JavaDoc name, boolean bound) {
932         DynamicMethod method = searchMethod(name);
933         if (method.isUndefined()) {
934             throw getRuntime().newNameError("undefined method `" + name +
935                 "' for class `" + this.getName() + "'", name);
936         }
937
938         RubyMethod newMethod = null;
939         if (bound) {
940             newMethod = RubyMethod.newMethod(method.getImplementationClass(), name, this, name, method, receiver);
941         } else {
942             newMethod = RubyUnboundMethod.newUnboundMethod(method.getImplementationClass(), name, this, name, method);
943         }
944         newMethod.infectBy(this);
945
946         return newMethod;
947     }
948
949     // What is argument 1 for in this method? A Method or Proc object /OB
950
public IRubyObject define_method(IRubyObject[] args, Block block) {
951         if (args.length < 1 || args.length > 2) {
952             throw getRuntime().newArgumentError("wrong # of arguments(" + args.length + " for 1)");
953         }
954
955         IRubyObject body;
956         String JavaDoc name = args[0].asSymbol();
957         DynamicMethod newMethod = null;
958         ThreadContext tc = getRuntime().getCurrentContext();
959         Visibility visibility = tc.getCurrentVisibility();
960
961         if (visibility.isModuleFunction()) visibility = Visibility.PRIVATE;
962
963         if (args.length == 1 || args[1].isKindOf(getRuntime().getClass("Proc"))) {
964             // double-testing args.length here, but it avoids duplicating the proc-setup code in two places
965
RubyProc proc = (args.length == 1) ? getRuntime().newProc(false, block) : (RubyProc)args[1];
966             body = proc;
967
968             proc.getBlock().isLambda = true;
969             proc.getBlock().getFrame().setKlazz(this);
970             proc.getBlock().getFrame().setName(name);
971
972             newMethod = new ProcMethod(this, proc, visibility);
973         } else if (args[1].isKindOf(getRuntime().getClass("Method"))) {
974             RubyMethod method = (RubyMethod)args[1];
975             body = method;
976
977             newMethod = new MethodMethod(this, method.unbind(null), visibility);
978         } else {
979             throw getRuntime().newTypeError("wrong argument type " + args[0].getType().getName() + " (expected Proc/Method)");
980         }
981
982         addMethod(name, newMethod);
983
984         RubySymbol symbol = RubySymbol.newSymbol(getRuntime(), name);
985         ThreadContext context = getRuntime().getCurrentContext();
986
987         if (tc.getPreviousVisibility().isModuleFunction()) {
988             getSingletonClass().addMethod(name, new WrapperMethod(getSingletonClass(), newMethod, Visibility.PUBLIC));
989         }
990
991         if(isSingleton()){
992             IRubyObject singleton = getInstanceVariable("__attached__");
993             singleton.callMethod(context, "singleton_method_added", symbol);
994         }else{
995         callMethod(context, "method_added", symbol);
996         }
997
998         return body;
999     }
1000
1001    public IRubyObject executeUnder(Callback method, IRubyObject[] args, Block block) {
1002        ThreadContext context = getRuntime().getCurrentContext();
1003
1004        context.preExecuteUnder(this, block);
1005
1006        try {
1007            return method.execute(this, args, block);
1008        } finally {
1009            context.postExecuteUnder();
1010        }
1011    }
1012
1013    // Methods of the Module Class (rb_mod_*):
1014

1015    public static RubyModule newModule(Ruby runtime, String JavaDoc name) {
1016        return newModule(runtime, runtime.getClass("Module"), name, null);
1017    }
1018
1019    public static RubyModule newModule(Ruby runtime, RubyClass type, String JavaDoc name) {
1020        return newModule(runtime, type, name, null);
1021    }
1022
1023    public static RubyModule newModule(Ruby runtime, String JavaDoc name, SinglyLinkedList parentCRef) {
1024        return newModule(runtime, runtime.getClass("Module"), name, parentCRef);
1025    }
1026
1027    public static RubyModule newModule(Ruby runtime, RubyClass type, String JavaDoc name, SinglyLinkedList parentCRef) {
1028        RubyModule module = new RubyModule(runtime, type, null, parentCRef, name);
1029        
1030        return module;
1031    }
1032
1033    public RubyString name() {
1034        return getRuntime().newString(getBaseName() == null ? "" : getName());
1035    }
1036
1037    /** rb_mod_class_variables
1038     *
1039     */

1040    public RubyArray class_variables() {
1041        RubyArray ary = getRuntime().newArray();
1042
1043        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
1044            for (Iterator JavaDoc iter = p.instanceVariableNames(); iter.hasNext();) {
1045                String JavaDoc id = (String JavaDoc) iter.next();
1046                if (IdUtil.isClassVariable(id)) {
1047                    RubyString kval = getRuntime().newString(id);
1048                    if (!ary.includes(kval)) {
1049                        ary.append(kval);
1050                    }
1051                }
1052            }
1053        }
1054        return ary;
1055    }
1056
1057    protected IRubyObject cloneMethods(RubyModule clone) {
1058        RubyModule realType = this.getNonIncludedClass();
1059        for (Iterator JavaDoc iter = getMethods().entrySet().iterator(); iter.hasNext(); ) {
1060            Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
1061            DynamicMethod method = (DynamicMethod) entry.getValue();
1062
1063            // Do not clone cached methods
1064
if (method.getImplementationClass() == realType) {
1065                // A cloned method now belongs to a new class. Set it.
1066
// TODO: Make DynamicMethod immutable
1067
DynamicMethod clonedMethod = method.dup();
1068                clonedMethod.setImplementationClass(clone);
1069                clone.getMethods().put(entry.getKey(), clonedMethod);
1070            }
1071        }
1072
1073        return clone;
1074    }
1075
1076    protected IRubyObject doClone() {
1077        return RubyModule.newModule(getRuntime(), null, cref.getNext());
1078    }
1079
1080    /** rb_mod_init_copy
1081     *
1082     */

1083    public IRubyObject initialize_copy(IRubyObject original) {
1084        assert original instanceof RubyModule;
1085        
1086        RubyModule originalModule = (RubyModule)original;
1087        
1088        super.initialize_copy(originalModule);
1089        
1090        if (!getMetaClass().isSingleton()) {
1091            setMetaClass(originalModule.getSingletonClassClone());
1092        }
1093
1094        setSuperClass(originalModule.getSuperClass());
1095        
1096        if (originalModule.instanceVariables != null){
1097            setInstanceVariables(new HashMap JavaDoc(originalModule.getInstanceVariables()));
1098        }
1099        
1100        // no __classpath__ and __classid__ stuff in JRuby here (yet?)
1101

1102        originalModule.cloneMethods(this);
1103        
1104        return this;
1105    }
1106
1107    /** rb_mod_included_modules
1108     *
1109     */

1110    public RubyArray included_modules() {
1111        RubyArray ary = getRuntime().newArray();
1112
1113        for (RubyModule p = getSuperClass(); p != null; p = p.getSuperClass()) {
1114            if (p.isIncluded()) {
1115                ary.append(p.getNonIncludedClass());
1116            }
1117        }
1118
1119        return ary;
1120    }
1121
1122    /** rb_mod_ancestors
1123     *
1124     */

1125    public RubyArray ancestors() {
1126        RubyArray ary = getRuntime().newArray(getAncestorList());
1127
1128        return ary;
1129    }
1130
1131    public List JavaDoc getAncestorList() {
1132        ArrayList JavaDoc list = new ArrayList JavaDoc();
1133
1134        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
1135            if(!p.isSingleton()) {
1136                list.add(p.getNonIncludedClass());
1137            }
1138        }
1139
1140        return list;
1141    }
1142
1143    public boolean hasModuleInHierarchy(RubyModule type) {
1144        // XXX: This check previously used callMethod("==") to check for equality between classes
1145
// when scanning the hierarchy. However the == check may be safe; we should only ever have
1146
// one instance bound to a given type/constant. If it's found to be unsafe, examine ways
1147
// to avoid the == call.
1148
for (RubyModule p = this; p != null; p = p.getSuperClass()) {
1149            if (p.getNonIncludedClass() == type) return true;
1150        }
1151
1152        return false;
1153    }
1154
1155    /** rb_mod_to_s
1156     *
1157     */

1158    public IRubyObject to_s() {
1159        if(isSingleton()){
1160            IRubyObject attached = getInstanceVariable("__attached__");
1161            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("#<Class:");
1162            if(attached instanceof RubyClass || attached instanceof RubyModule){
1163                buffer.append(attached.inspect());
1164            }else{
1165                buffer.append(attached.anyToString());
1166            }
1167            buffer.append(">");
1168            return getRuntime().newString(buffer.toString());
1169        }
1170        return getRuntime().newString(getName());
1171    }
1172
1173    /** rb_mod_eqq
1174     *
1175     */

1176    public RubyBoolean op_eqq(IRubyObject obj) {
1177        return getRuntime().newBoolean(obj.isKindOf(this));
1178    }
1179
1180    /** rb_mod_le
1181    *
1182    */

1183   public IRubyObject op_le(IRubyObject obj) {
1184       if (!(obj instanceof RubyModule)) {
1185           throw getRuntime().newTypeError("compared with non class/module");
1186       }
1187
1188       if (isKindOfModule((RubyModule)obj)) {
1189           return getRuntime().getTrue();
1190       } else if (((RubyModule)obj).isKindOfModule(this)) {
1191           return getRuntime().getFalse();
1192       }
1193
1194       return getRuntime().getNil();
1195   }
1196
1197   /** rb_mod_lt
1198    *
1199    */

1200   public IRubyObject op_lt(IRubyObject obj) {
1201    return obj == this ? getRuntime().getFalse() : op_le(obj);
1202   }
1203
1204   /** rb_mod_ge
1205    *
1206    */

1207   public IRubyObject op_ge(IRubyObject obj) {
1208       if (!(obj instanceof RubyModule)) {
1209           throw getRuntime().newTypeError("compared with non class/module");
1210       }
1211
1212       return ((RubyModule) obj).op_le(this);
1213   }
1214
1215   /** rb_mod_gt
1216    *
1217    */

1218   public IRubyObject op_gt(IRubyObject obj) {
1219       return this == obj ? getRuntime().getFalse() : op_ge(obj);
1220   }
1221
1222   /** rb_mod_cmp
1223    *
1224    */

1225   public IRubyObject op_cmp(IRubyObject obj) {
1226       if (this == obj) {
1227           return getRuntime().newFixnum(0);
1228       }
1229
1230       if (!(obj instanceof RubyModule)) {
1231           throw getRuntime().newTypeError(
1232               "<=> requires Class or Module (" + getMetaClass().getName() + " given)");
1233       }
1234
1235       RubyModule module = (RubyModule)obj;
1236
1237       if (module.isKindOfModule(this)) {
1238           return getRuntime().newFixnum(1);
1239       } else if (this.isKindOfModule(module)) {
1240           return getRuntime().newFixnum(-1);
1241       }
1242
1243       return getRuntime().getNil();
1244   }
1245
1246   public boolean isKindOfModule(RubyModule type) {
1247       for (RubyModule p = this; p != null; p = p.getSuperClass()) {
1248           if (p.isSame(type)) {
1249               return true;
1250           }
1251       }
1252
1253       return false;
1254   }
1255
1256   public boolean isSame(RubyModule module) {
1257       return this == module;
1258   }
1259
1260    /** rb_mod_initialize
1261     *
1262     */

1263    public IRubyObject initialize(IRubyObject[] args, Block block) {
1264        if (block.isGiven()) block.yield(getRuntime().getCurrentContext(), null, this, this, false);
1265        
1266        return getRuntime().getNil();
1267    }
1268
1269    /** rb_mod_attr
1270     *
1271     */

1272    public IRubyObject attr(IRubyObject[] args) {
1273        checkArgumentCount(args, 1, 2);
1274        boolean writeable = args.length > 1 ? args[1].isTrue() : false;
1275
1276        addAccessor(args[0].asSymbol(), true, writeable);
1277
1278        return getRuntime().getNil();
1279    }
1280
1281    /** rb_mod_attr_reader
1282     *
1283     */

1284    public IRubyObject attr_reader(IRubyObject[] args) {
1285        for (int i = 0; i < args.length; i++) {
1286            addAccessor(args[i].asSymbol(), true, false);
1287        }
1288
1289        return getRuntime().getNil();
1290    }
1291
1292    /** rb_mod_attr_writer
1293     *
1294     */

1295    public IRubyObject attr_writer(IRubyObject[] args) {
1296        for (int i = 0; i < args.length; i++) {
1297            addAccessor(args[i].asSymbol(), false, true);
1298        }
1299
1300        return getRuntime().getNil();
1301    }
1302
1303    /** rb_mod_attr_accessor
1304     *
1305     */

1306    public IRubyObject attr_accessor(IRubyObject[] args) {
1307        for (int i = 0; i < args.length; i++) {
1308            addAccessor(args[i].asSymbol(), true, true);
1309        }
1310
1311        return getRuntime().getNil();
1312    }
1313
1314    /** rb_mod_const_get
1315     *
1316     */

1317    public IRubyObject const_get(IRubyObject symbol) {
1318        String JavaDoc name = symbol.asSymbol();
1319
1320        if (!IdUtil.isConstant(name)) {
1321            throw wrongConstantNameError(name);
1322        }
1323
1324        return getConstant(name);
1325    }
1326
1327    /** rb_mod_const_set
1328     *
1329     */

1330    public IRubyObject const_set(IRubyObject symbol, IRubyObject value) {
1331        String JavaDoc name = symbol.asSymbol();
1332
1333        if (!IdUtil.isConstant(name)) {
1334            throw wrongConstantNameError(name);
1335        }
1336
1337        return setConstant(name, value);
1338    }
1339
1340    /** rb_mod_const_defined
1341     *
1342     */

1343    public RubyBoolean const_defined(IRubyObject symbol) {
1344        String JavaDoc name = symbol.asSymbol();
1345
1346        if (!IdUtil.isConstant(name)) {
1347            throw wrongConstantNameError(name);
1348        }
1349
1350        return getRuntime().newBoolean(getConstantAt(name) != null);
1351    }
1352
1353    private RaiseException wrongConstantNameError(String JavaDoc name) {
1354        return getRuntime().newNameError("wrong constant name " + name, name);
1355    }
1356
1357    private RubyArray instance_methods(IRubyObject[] args, final Visibility visibility) {
1358        boolean includeSuper = args.length > 0 ? args[0].isTrue() : true;
1359        RubyArray ary = getRuntime().newArray();
1360        HashMap JavaDoc undefinedMethods = new HashMap JavaDoc();
1361        Set JavaDoc added = new HashSet JavaDoc();
1362
1363        for (RubyModule type = this; type != null; type = type.getSuperClass()) {
1364            RubyModule realType = type.getNonIncludedClass();
1365            for (Iterator JavaDoc iter = type.getMethods().entrySet().iterator(); iter.hasNext();) {
1366                Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
1367                DynamicMethod method = (DynamicMethod) entry.getValue();
1368                String JavaDoc methodName = (String JavaDoc) entry.getKey();
1369
1370                if (method.isUndefined()) {
1371                    undefinedMethods.put(methodName, Boolean.TRUE);
1372                    continue;
1373                }
1374                if (method.getImplementationClass() == realType &&
1375                    method.getVisibility().is(visibility) && undefinedMethods.get(methodName) == null) {
1376
1377                    if (!added.contains(methodName)) {
1378                        ary.append(getRuntime().newString(methodName));
1379                        added.add(methodName);
1380                    }
1381                }
1382            }
1383
1384            if (!includeSuper) {
1385                break;
1386            }
1387        }
1388
1389        return ary;
1390    }
1391
1392    public RubyArray instance_methods(IRubyObject[] args) {
1393        return instance_methods(args, Visibility.PUBLIC_PROTECTED);
1394    }
1395
1396    public RubyArray public_instance_methods(IRubyObject[] args) {
1397        return instance_methods(args, Visibility.PUBLIC);
1398    }
1399
1400    public IRubyObject instance_method(IRubyObject symbol) {
1401        return newMethod(null, symbol.asSymbol(), false);
1402    }
1403
1404    /** rb_class_protected_instance_methods
1405     *
1406     */

1407    public RubyArray protected_instance_methods(IRubyObject[] args) {
1408        return instance_methods(args, Visibility.PROTECTED);
1409    }
1410
1411    /** rb_class_private_instance_methods
1412     *
1413     */

1414    public RubyArray private_instance_methods(IRubyObject[] args) {
1415        return instance_methods(args, Visibility.PRIVATE);
1416    }
1417
1418    /** rb_mod_constants
1419     *
1420     */

1421    public RubyArray constants() {
1422        ArrayList JavaDoc constantNames = new ArrayList JavaDoc();
1423        RubyModule objectClass = getRuntime().getObject();
1424
1425        if (getRuntime().getClass("Module") == this) {
1426            for (Iterator JavaDoc vars = objectClass.instanceVariableNames();
1427                 vars.hasNext();) {
1428                String JavaDoc name = (String JavaDoc) vars.next();
1429                if (IdUtil.isConstant(name)) {
1430                    constantNames.add(getRuntime().newString(name));
1431                }
1432            }
1433
1434            return getRuntime().newArray(constantNames);
1435        } else if (getRuntime().getObject() == this) {
1436            for (Iterator JavaDoc vars = instanceVariableNames(); vars.hasNext();) {
1437                String JavaDoc name = (String JavaDoc) vars.next();
1438                if (IdUtil.isConstant(name)) {
1439                    constantNames.add(getRuntime().newString(name));
1440                }
1441            }
1442
1443            return getRuntime().newArray(constantNames);
1444        }
1445
1446        for (RubyModule p = this; p != null; p = p.getSuperClass()) {
1447            if (objectClass == p) {
1448                continue;
1449            }
1450
1451            for (Iterator JavaDoc vars = p.instanceVariableNames(); vars.hasNext();) {
1452                String JavaDoc name = (String JavaDoc) vars.next();
1453                if (IdUtil.isConstant(name)) {
1454                    constantNames.add(getRuntime().newString(name));
1455                }
1456            }
1457        }
1458
1459        return getRuntime().newArray(constantNames);
1460    }
1461
1462    /** rb_mod_remove_cvar
1463     *
1464     */

1465    public IRubyObject remove_class_variable(IRubyObject name) {
1466        String JavaDoc id = name.asSymbol();
1467
1468        if (!IdUtil.isClassVariable(id)) {
1469            throw getRuntime().newNameError("wrong class variable name " + id, id);
1470        }
1471        if (!isTaint() && getRuntime().getSafeLevel() >= 4) {
1472            throw getRuntime().newSecurityError("Insecure: can't remove class variable");
1473        }
1474        testFrozen("class/module");
1475
1476        IRubyObject variable = removeInstanceVariable(id);
1477        if (variable != null) {
1478            return variable;
1479        }
1480
1481        if (isClassVarDefined(id)) {
1482            throw cannotRemoveError(id);
1483        }
1484        throw getRuntime().newNameError("class variable " + id + " not defined for " + getName(), id);
1485    }
1486
1487    private RaiseException cannotRemoveError(String JavaDoc id) {
1488        return getRuntime().newNameError("cannot remove " + id + " for " + getName(), id);
1489    }
1490
1491    public IRubyObject remove_const(IRubyObject name) {
1492        String JavaDoc id = name.asSymbol();
1493
1494        if (!IdUtil.isConstant(id)) {
1495            throw wrongConstantNameError(id);
1496        }
1497        if (!isTaint() && getRuntime().getSafeLevel() >= 4) {
1498            throw getRuntime().newSecurityError("Insecure: can't remove class variable");
1499        }
1500        testFrozen("class/module");
1501
1502        IRubyObject variable = getInstanceVariable(id);
1503        if (variable != null) {
1504            return removeInstanceVariable(id);
1505        }
1506
1507        if (isClassVarDefined(id)) {
1508            throw cannotRemoveError(id);
1509        }
1510        throw getRuntime().newNameError("constant " + id + " not defined for " + getName(), id);
1511    }
1512
1513    /** rb_mod_append_features
1514     *
1515     */

1516    // TODO: Proper argument check (conversion?)
1517
public RubyModule append_features(IRubyObject module) {
1518        ((RubyModule) module).includeModule(this);
1519        return this;
1520    }
1521
1522    /** rb_mod_extend_object
1523     *
1524     */

1525    public IRubyObject extend_object(IRubyObject obj) {
1526        obj.extendObject(this);
1527        return obj;
1528    }
1529
1530    /** rb_mod_include
1531     *
1532     */

1533    public RubyModule include(IRubyObject[] modules) {
1534        ThreadContext context = getRuntime().getCurrentContext();
1535
1536        for (int i = modules.length - 1; i >= 0; i--) {
1537            modules[i].callMethod(context, "append_features", this);
1538            modules[i].callMethod(context, "included", this);
1539        }
1540
1541        return this;
1542    }
1543
1544    public IRubyObject included(IRubyObject other) {
1545        return getRuntime().getNil();
1546    }
1547
1548    public IRubyObject extended(IRubyObject other, Block block) {
1549        return getRuntime().getNil();
1550    }
1551
1552    private void setVisibility(IRubyObject[] args, Visibility visibility) {
1553        if (getRuntime().getSafeLevel() >= 4 && !isTaint()) {
1554            throw getRuntime().newSecurityError("Insecure: can't change method visibility");
1555        }
1556
1557        if (args.length == 0) {
1558            // Note: we change current frames visibility here because the methods which call
1559
// this method are all "fast" (e.g. they do not created their own frame).
1560
getRuntime().getCurrentContext().setCurrentVisibility(visibility);
1561        } else {
1562            setMethodVisibility(args, visibility);
1563        }
1564    }
1565
1566    /** rb_mod_public
1567     *
1568     */

1569    public RubyModule rbPublic(IRubyObject[] args) {
1570        setVisibility(args, Visibility.PUBLIC);
1571        return this;
1572    }
1573
1574    /** rb_mod_protected
1575     *
1576     */

1577    public RubyModule rbProtected(IRubyObject[] args) {
1578        setVisibility(args, Visibility.PROTECTED);
1579        return this;
1580    }
1581
1582    /** rb_mod_private
1583     *
1584     */

1585    public RubyModule rbPrivate(IRubyObject[] args) {
1586        setVisibility(args, Visibility.PRIVATE);
1587        return this;
1588    }
1589
1590    /** rb_mod_modfunc
1591     *
1592     */

1593    public RubyModule module_function(IRubyObject[] args) {
1594        if (getRuntime().getSafeLevel() >= 4 && !isTaint()) {
1595            throw getRuntime().newSecurityError("Insecure: can't change method visibility");
1596        }
1597
1598        ThreadContext context = getRuntime().getCurrentContext();
1599
1600        if (args.length == 0) {
1601            context.setCurrentVisibility(Visibility.MODULE_FUNCTION);
1602        } else {
1603            setMethodVisibility(args, Visibility.PRIVATE);
1604
1605            for (int i = 0; i < args.length; i++) {
1606                String JavaDoc name = args[i].asSymbol();
1607                DynamicMethod method = searchMethod(name);
1608                assert !method.isUndefined() : "undefined method '" + name + "'";
1609                getSingletonClass().addMethod(name, new WrapperMethod(getSingletonClass(), method, Visibility.PUBLIC));
1610                callMethod(context, "singleton_method_added", RubySymbol.newSymbol(getRuntime(), name));
1611            }
1612        }
1613        return this;
1614    }
1615
1616    public IRubyObject method_added(IRubyObject nothing, Block block) {
1617        return getRuntime().getNil();
1618    }
1619
1620    public IRubyObject method_removed(IRubyObject nothing, Block block) {
1621        return getRuntime().getNil();
1622    }
1623
1624    public IRubyObject method_undefined(IRubyObject nothing, Block block) {
1625        return getRuntime().getNil();
1626    }
1627    
1628    public RubyBoolean method_defined(IRubyObject symbol) {
1629        return isMethodBound(symbol.asSymbol(), true) ? getRuntime().getTrue() : getRuntime().getFalse();
1630    }
1631
1632    public RubyModule public_class_method(IRubyObject[] args) {
1633        getMetaClass().setMethodVisibility(args, Visibility.PUBLIC);
1634        return this;
1635    }
1636
1637    public RubyModule private_class_method(IRubyObject[] args) {
1638        getMetaClass().setMethodVisibility(args, Visibility.PRIVATE);
1639        return this;
1640    }
1641
1642    public RubyModule alias_method(IRubyObject newId, IRubyObject oldId) {
1643        defineAlias(newId.asSymbol(), oldId.asSymbol());
1644        return this;
1645    }
1646
1647    public RubyModule undef_method(IRubyObject name) {
1648        undef(name.asSymbol());
1649        return this;
1650    }
1651
1652    public IRubyObject module_eval(IRubyObject[] args, Block block) {
1653        return specificEval(this, args, block);
1654    }
1655
1656    public RubyModule remove_method(IRubyObject[] args) {
1657        for(int i=0;i<args.length;i++) {
1658            removeMethod(args[i].asSymbol());
1659        }
1660        return this;
1661    }
1662
1663    public static void marshalTo(RubyModule module, MarshalStream output) throws java.io.IOException JavaDoc {
1664        output.writeString(module.name().toString());
1665    }
1666
1667    public static RubyModule unmarshalFrom(UnmarshalStream input) throws java.io.IOException JavaDoc {
1668        String JavaDoc name = RubyString.byteListToString(input.unmarshalString());
1669        Ruby runtime = input.getRuntime();
1670        RubyModule result = runtime.getClassFromPath(name);
1671        if (result == null) {
1672            throw runtime.newNameError("uninitialized constant " + name, name);
1673        }
1674        input.registerLinkTarget(result);
1675        return result;
1676    }
1677
1678    public SinglyLinkedList getCRef() {
1679        return cref;
1680    }
1681}
1682
Popular Tags