1 36 package org.jruby; 37 38 import java.util.ArrayList ; 39 import java.util.HashMap ; 40 import java.util.Iterator ; 41 import java.util.HashSet ; 42 import java.util.List ; 43 import java.util.Map ; 44 import java.util.Set ; 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 71 public class RubyModule extends RubyObject { 72 private static final String CVAR_TAINT_ERROR = 73 "Insecure: can't modify class variable"; 74 private static final String CVAR_FREEZE_ERROR = "class/module"; 75 76 private RubyClass superClass; 78 79 public int index; 80 81 public final int id; 82 83 86 public SinglyLinkedList cref; 88 89 private String classId; 92 93 private Map methods = new HashMap (); 97 98 protected RubyModule(Ruby runtime, RubyClass metaClass, RubyClass superClass, SinglyLinkedList parentCRef, String name) { 99 super(runtime, metaClass); 100 101 this.superClass = superClass; 102 103 setBaseName(name); 104 105 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 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 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 163 public boolean isIncluded() { 164 return false; 165 } 166 167 public RubyModule getNonIncludedClass() { 168 return this; 169 } 170 171 public String getBaseName() { 172 return classId; 173 } 174 175 public void setBaseName(String name) { 176 classId = name; 177 } 178 179 186 public String 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 result = new StringBuffer (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 212 public IncludedModuleWrapper newIncludeClass(RubyClass superClazz) { 213 IncludedModuleWrapper includedModule = new IncludedModuleWrapper(getRuntime(), superClazz, this); 214 215 if (getSuperClass() != null) { 217 includedModule.includeModule(getSuperClass()); 218 } 219 220 return includedModule; 221 } 222 223 229 private RubyModule getModuleWithInstanceVar(String 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 246 public IRubyObject setClassVar(String 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 264 public IRubyObject getClassVar(String 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 284 public boolean isClassVarDefined(String name) { 285 return getModuleWithInstanceVar(name) != null; 286 } 287 288 297 public IRubyObject setConstant(String 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 (value instanceof RubyModule) { 307 RubyModule module = (RubyModule)value; 308 if (module.getBaseName() == null) { 309 module.setBaseName(name); 310 module.setParent(this); 311 } 312 315 } 316 return result; 317 } 318 319 325 public RubyClass getClass(String name) { 326 IRubyObject module = getConstantAt(name); 327 328 return (module instanceof RubyClass) ? (RubyClass) module : null; 329 } 330 331 337 public IRubyObject const_missing(IRubyObject name, Block block) { 338 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 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 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 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 List methodNames = new ArrayList (((RubyModule) arg).getMethods().keySet()); 415 for (Iterator iter = methodNames.iterator(); 416 iter.hasNext();) { 417 String methodName = (String ) iter.next(); 418 getRuntime().getCacheMap().remove(methodName, searchMethod(methodName)); 419 } 420 } 421 422 } 423 424 public void defineMethod(String 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 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 name, Callback method) { 437 addMethod(name, new FullFunctionCallbackMethod(this, method, Visibility.PRIVATE)); 438 } 439 440 public void defineFastPrivateMethod(String name, Callback method) { 441 addMethod(name, new SimpleCallbackMethod(this, method, Visibility.PRIVATE)); 442 } 443 444 public void undefineMethod(String name) { 445 addMethod(name, UndefinedMethod.getInstance()); 446 } 447 448 451 public void undef(String 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 ("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 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 name, DynamicMethod method) { 492 if (!isIncluded()) { 495 getMethods().put(name, method); 496 getRuntime().getCacheMap().add(method, this); 497 } 498 } 499 500 public void addMethod(String 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 synchronized(getMethods()) { 514 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 name) { 526 getMethods().remove(name); 527 } 528 529 public void removeMethod(String 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 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 563 public DynamicMethod searchMethod(String name) { 564 for (RubyModule searchModule = this; searchModule != null; searchModule = searchModule.getSuperClass()) { 565 synchronized(searchModule.getMethods()) { 567 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 588 public DynamicMethod retrieveMethod(String name) { 589 return (DynamicMethod)getMethods().get(name); 590 } 591 592 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 name, DynamicMethod method) { 609 addMethod(name, method); 610 getSingletonClass().addMethod(name, method); 611 } 612 613 616 public void defineModuleFunction(String name, Callback method) { 617 definePrivateMethod(name, method); 618 getSingletonClass().defineMethod(name, method); 619 } 620 621 624 public void definePublicModuleFunction(String name, Callback method) { 625 defineMethod(name, method); 626 getSingletonClass().defineMethod(name, method); 627 } 628 629 632 public void defineFastModuleFunction(String name, Callback method) { 633 defineFastPrivateMethod(name, method); 634 getSingletonClass().defineFastMethod(name, method); 635 } 636 637 640 public void defineFastPublicModuleFunction(String name, Callback method) { 641 defineFastMethod(name, method); 642 getSingletonClass().defineFastMethod(name, method); 643 } 644 645 private IRubyObject getConstantInner(String 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 688 public IRubyObject getConstant(String name) { 689 return getConstantInner(name, false); 690 } 691 692 public IRubyObject getConstantFrom(String name) { 693 return getConstantInner(name, true); 694 } 695 696 public IRubyObject getConstantAt(String name) { 697 return getInstanceVariable(name); 698 } 699 700 703 public synchronized void defineAlias(String name, String 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 name, RubyClass superClazz) { 727 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 749 public RubyClass defineClassUnder(String 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 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 782 public void defineConstant(String 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 799 public IRubyObject removeCvar(IRubyObject name) { 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 name, boolean readable, boolean writeable) { 823 ThreadContext tc = getRuntime().getCurrentContext(); 824 825 Visibility attributeScope = tc.getCurrentVisibility(); 827 if (attributeScope.isPrivate()) { 828 } else if (attributeScope.isModuleFunction()) { 830 attributeScope = Visibility.PRIVATE; 831 } 833 final String 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 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 889 public void exportMethod(String 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 923 public boolean isMethodBound(String 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 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 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 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 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 1015 public static RubyModule newModule(Ruby runtime, String name) { 1016 return newModule(runtime, runtime.getClass("Module"), name, null); 1017 } 1018 1019 public static RubyModule newModule(Ruby runtime, RubyClass type, String name) { 1020 return newModule(runtime, type, name, null); 1021 } 1022 1023 public static RubyModule newModule(Ruby runtime, String name, SinglyLinkedList parentCRef) { 1024 return newModule(runtime, runtime.getClass("Module"), name, parentCRef); 1025 } 1026 1027 public static RubyModule newModule(Ruby runtime, RubyClass type, String 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 1040 public RubyArray class_variables() { 1041 RubyArray ary = getRuntime().newArray(); 1042 1043 for (RubyModule p = this; p != null; p = p.getSuperClass()) { 1044 for (Iterator iter = p.instanceVariableNames(); iter.hasNext();) { 1045 String id = (String ) 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 iter = getMethods().entrySet().iterator(); iter.hasNext(); ) { 1060 Map.Entry entry = (Map.Entry ) iter.next(); 1061 DynamicMethod method = (DynamicMethod) entry.getValue(); 1062 1063 if (method.getImplementationClass() == realType) { 1065 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 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 (originalModule.getInstanceVariables())); 1098 } 1099 1100 1102 originalModule.cloneMethods(this); 1103 1104 return this; 1105 } 1106 1107 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 1125 public RubyArray ancestors() { 1126 RubyArray ary = getRuntime().newArray(getAncestorList()); 1127 1128 return ary; 1129 } 1130 1131 public List getAncestorList() { 1132 ArrayList list = new ArrayList (); 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 for (RubyModule p = this; p != null; p = p.getSuperClass()) { 1149 if (p.getNonIncludedClass() == type) return true; 1150 } 1151 1152 return false; 1153 } 1154 1155 1158 public IRubyObject to_s() { 1159 if(isSingleton()){ 1160 IRubyObject attached = getInstanceVariable("__attached__"); 1161 StringBuffer buffer = new StringBuffer ("#<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 1176 public RubyBoolean op_eqq(IRubyObject obj) { 1177 return getRuntime().newBoolean(obj.isKindOf(this)); 1178 } 1179 1180 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 1200 public IRubyObject op_lt(IRubyObject obj) { 1201 return obj == this ? getRuntime().getFalse() : op_le(obj); 1202 } 1203 1204 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 1218 public IRubyObject op_gt(IRubyObject obj) { 1219 return this == obj ? getRuntime().getFalse() : op_ge(obj); 1220 } 1221 1222 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 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 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 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 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 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 1317 public IRubyObject const_get(IRubyObject symbol) { 1318 String name = symbol.asSymbol(); 1319 1320 if (!IdUtil.isConstant(name)) { 1321 throw wrongConstantNameError(name); 1322 } 1323 1324 return getConstant(name); 1325 } 1326 1327 1330 public IRubyObject const_set(IRubyObject symbol, IRubyObject value) { 1331 String name = symbol.asSymbol(); 1332 1333 if (!IdUtil.isConstant(name)) { 1334 throw wrongConstantNameError(name); 1335 } 1336 1337 return setConstant(name, value); 1338 } 1339 1340 1343 public RubyBoolean const_defined(IRubyObject symbol) { 1344 String 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 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 undefinedMethods = new HashMap (); 1361 Set added = new HashSet (); 1362 1363 for (RubyModule type = this; type != null; type = type.getSuperClass()) { 1364 RubyModule realType = type.getNonIncludedClass(); 1365 for (Iterator iter = type.getMethods().entrySet().iterator(); iter.hasNext();) { 1366 Map.Entry entry = (Map.Entry ) iter.next(); 1367 DynamicMethod method = (DynamicMethod) entry.getValue(); 1368 String methodName = (String ) 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 1407 public RubyArray protected_instance_methods(IRubyObject[] args) { 1408 return instance_methods(args, Visibility.PROTECTED); 1409 } 1410 1411 1414 public RubyArray private_instance_methods(IRubyObject[] args) { 1415 return instance_methods(args, Visibility.PRIVATE); 1416 } 1417 1418 1421 public RubyArray constants() { 1422 ArrayList constantNames = new ArrayList (); 1423 RubyModule objectClass = getRuntime().getObject(); 1424 1425 if (getRuntime().getClass("Module") == this) { 1426 for (Iterator vars = objectClass.instanceVariableNames(); 1427 vars.hasNext();) { 1428 String name = (String ) 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 vars = instanceVariableNames(); vars.hasNext();) { 1437 String name = (String ) 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 vars = p.instanceVariableNames(); vars.hasNext();) { 1452 String name = (String ) 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 1465 public IRubyObject remove_class_variable(IRubyObject name) { 1466 String 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 id) { 1488 return getRuntime().newNameError("cannot remove " + id + " for " + getName(), id); 1489 } 1490 1491 public IRubyObject remove_const(IRubyObject name) { 1492 String 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 1516 public RubyModule append_features(IRubyObject module) { 1518 ((RubyModule) module).includeModule(this); 1519 return this; 1520 } 1521 1522 1525 public IRubyObject extend_object(IRubyObject obj) { 1526 obj.extendObject(this); 1527 return obj; 1528 } 1529 1530 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 getRuntime().getCurrentContext().setCurrentVisibility(visibility); 1561 } else { 1562 setMethodVisibility(args, visibility); 1563 } 1564 } 1565 1566 1569 public RubyModule rbPublic(IRubyObject[] args) { 1570 setVisibility(args, Visibility.PUBLIC); 1571 return this; 1572 } 1573 1574 1577 public RubyModule rbProtected(IRubyObject[] args) { 1578 setVisibility(args, Visibility.PROTECTED); 1579 return this; 1580 } 1581 1582 1585 public RubyModule rbPrivate(IRubyObject[] args) { 1586 setVisibility(args, Visibility.PRIVATE); 1587 return this; 1588 } 1589 1590 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 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 { 1664 output.writeString(module.name().toString()); 1665 } 1666 1667 public static RubyModule unmarshalFrom(UnmarshalStream input) throws java.io.IOException { 1668 String 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 |