1 41 package org.jruby; 42 43 import java.io.ByteArrayOutputStream ; 44 import java.io.File ; 45 import java.io.IOException ; 46 import java.io.InputStream ; 47 import java.io.OutputStream ; 48 import java.io.PrintStream ; 49 import java.util.Calendar ; 50 import java.util.Iterator ; 51 import java.util.List ; 52 import java.util.HashMap ; 53 import java.util.Map ; 54 import java.util.StringTokenizer ; 55 import java.util.regex.Pattern ; 56 57 import org.jruby.ast.util.ArgsUtil; 58 import org.jruby.exceptions.JumpException; 59 import org.jruby.exceptions.RaiseException; 60 import org.jruby.exceptions.MainExitException; 61 import org.jruby.internal.runtime.methods.DynamicMethod; 62 import org.jruby.runtime.Block; 63 import org.jruby.runtime.CallType; 64 import org.jruby.runtime.CallbackFactory; 65 import org.jruby.runtime.ThreadContext; 66 import org.jruby.runtime.Visibility; 67 import org.jruby.runtime.builtin.IRubyObject; 68 import org.jruby.runtime.builtin.meta.FileMetaClass; 69 import org.jruby.runtime.builtin.meta.IOMetaClass; 70 import org.jruby.runtime.load.IAutoloadMethod; 71 import org.jruby.runtime.load.LoadService; 72 import org.jruby.util.PrintfFormat; 73 import org.jruby.util.UnsynchronizedStack; 74 75 80 public class RubyKernel { 81 public final static Class IRUBY_OBJECT = IRubyObject.class; 82 83 public static RubyModule createKernelModule(Ruby runtime) { 84 RubyModule module = runtime.defineModule("Kernel"); 85 CallbackFactory callbackFactory = runtime.callbackFactory(RubyKernel.class); 86 CallbackFactory objectCallbackFactory = runtime.callbackFactory(RubyObject.class); 87 88 module.defineFastModuleFunction("Array", callbackFactory.getFastSingletonMethod("new_array", IRUBY_OBJECT)); 89 module.defineFastModuleFunction("Float", callbackFactory.getFastSingletonMethod("new_float", IRUBY_OBJECT)); 90 module.defineFastModuleFunction("Integer", callbackFactory.getFastSingletonMethod("new_integer", IRUBY_OBJECT)); 91 module.defineFastModuleFunction("String", callbackFactory.getFastSingletonMethod("new_string", IRUBY_OBJECT)); 92 module.defineFastModuleFunction("`", callbackFactory.getFastSingletonMethod("backquote", IRUBY_OBJECT)); 93 module.defineFastModuleFunction("abort", callbackFactory.getFastOptSingletonMethod("abort")); 94 module.defineModuleFunction("at_exit", callbackFactory.getSingletonMethod("at_exit")); 95 module.defineFastModuleFunction("autoload", callbackFactory.getFastSingletonMethod("autoload", IRUBY_OBJECT, IRUBY_OBJECT)); 96 module.defineFastPublicModuleFunction("autoload?", callbackFactory.getFastSingletonMethod("autoload_p", IRUBY_OBJECT)); 97 module.defineModuleFunction("binding", callbackFactory.getSingletonMethod("binding")); 98 module.defineModuleFunction("block_given?", callbackFactory.getSingletonMethod("block_given")); 99 module.defineModuleFunction("caller", callbackFactory.getOptSingletonMethod("caller")); 101 module.defineModuleFunction("catch", callbackFactory.getSingletonMethod("rbCatch", IRUBY_OBJECT)); 102 module.defineFastModuleFunction("chomp", callbackFactory.getFastOptSingletonMethod("chomp")); 103 module.defineFastModuleFunction("chomp!", callbackFactory.getFastOptSingletonMethod("chomp_bang")); 104 module.defineFastModuleFunction("chop", callbackFactory.getFastSingletonMethod("chop")); 105 module.defineFastModuleFunction("chop!", callbackFactory.getFastSingletonMethod("chop_bang")); 106 module.defineModuleFunction("eval", callbackFactory.getOptSingletonMethod("eval")); 107 module.defineFastModuleFunction("exit", callbackFactory.getFastOptSingletonMethod("exit")); 108 module.defineFastModuleFunction("exit!", callbackFactory.getFastOptSingletonMethod("exit_bang")); 109 module.defineModuleFunction("fail", callbackFactory.getOptSingletonMethod("raise")); 110 module.defineFastModuleFunction("format", callbackFactory.getFastOptSingletonMethod("sprintf")); 112 module.defineFastModuleFunction("gets", callbackFactory.getFastOptSingletonMethod("gets")); 113 module.defineFastModuleFunction("global_variables", callbackFactory.getFastSingletonMethod("global_variables")); 114 module.defineModuleFunction("gsub", callbackFactory.getOptSingletonMethod("gsub")); 115 module.defineModuleFunction("gsub!", callbackFactory.getOptSingletonMethod("gsub_bang")); 116 module.defineModuleFunction("iterator?", callbackFactory.getSingletonMethod("block_given")); 118 module.defineModuleFunction("lambda", callbackFactory.getSingletonMethod("proc")); 119 module.defineModuleFunction("load", callbackFactory.getOptSingletonMethod("load")); 120 module.defineFastModuleFunction("local_variables", callbackFactory.getFastSingletonMethod("local_variables")); 121 module.defineModuleFunction("loop", callbackFactory.getSingletonMethod("loop")); 122 module.defineModuleFunction("method_missing", callbackFactory.getOptSingletonMethod("method_missing")); 124 module.defineModuleFunction("open", callbackFactory.getOptSingletonMethod("open")); 125 module.defineFastModuleFunction("p", callbackFactory.getFastOptSingletonMethod("p")); 126 module.defineFastModuleFunction("print", callbackFactory.getFastOptSingletonMethod("print")); 127 module.defineFastModuleFunction("printf", callbackFactory.getFastOptSingletonMethod("printf")); 128 module.defineModuleFunction("proc", callbackFactory.getSingletonMethod("proc")); 129 module.defineFastModuleFunction("puts", callbackFactory.getFastOptSingletonMethod("puts")); 131 module.defineModuleFunction("raise", callbackFactory.getOptSingletonMethod("raise")); 132 module.defineFastModuleFunction("rand", callbackFactory.getFastOptSingletonMethod("rand")); 133 module.defineFastModuleFunction("readline", callbackFactory.getFastOptSingletonMethod("readline")); 134 module.defineFastModuleFunction("readlines", callbackFactory.getFastOptSingletonMethod("readlines")); 135 module.defineModuleFunction("require", callbackFactory.getSingletonMethod("require", IRUBY_OBJECT)); 136 module.defineModuleFunction("scan", callbackFactory.getSingletonMethod("scan", IRUBY_OBJECT)); 137 module.defineFastModuleFunction("select", callbackFactory.getFastOptSingletonMethod("select")); 138 module.defineModuleFunction("set_trace_func", callbackFactory.getSingletonMethod("set_trace_func", IRUBY_OBJECT)); 139 module.defineFastModuleFunction("sleep", callbackFactory.getFastSingletonMethod("sleep", IRUBY_OBJECT)); 140 module.defineFastModuleFunction("split", callbackFactory.getFastOptSingletonMethod("split")); 141 module.defineFastModuleFunction("sprintf", callbackFactory.getFastOptSingletonMethod("sprintf")); 142 module.defineFastModuleFunction("srand", callbackFactory.getFastOptSingletonMethod("srand")); 143 module.defineModuleFunction("sub", callbackFactory.getOptSingletonMethod("sub")); 144 module.defineModuleFunction("sub!", callbackFactory.getOptSingletonMethod("sub_bang")); 145 module.defineFastModuleFunction("system", callbackFactory.getFastOptSingletonMethod("system")); 147 module.defineFastModuleFunction("exec", callbackFactory.getFastOptSingletonMethod("system")); 149 module.defineFastModuleFunction("test", callbackFactory.getFastOptSingletonMethod("test")); 150 module.defineModuleFunction("throw", callbackFactory.getOptSingletonMethod("rbThrow")); 151 module.defineModuleFunction("trap", callbackFactory.getOptSingletonMethod("trap")); 153 module.defineFastModuleFunction("warn", callbackFactory.getFastSingletonMethod("warn", IRUBY_OBJECT)); 155 156 module.defineModuleFunction("singleton_method_added", callbackFactory.getSingletonMethod("singleton_method_added", IRUBY_OBJECT)); 158 module.defineModuleFunction("singleton_method_removed", callbackFactory.getSingletonMethod("singleton_method_removed", IRUBY_OBJECT)); 159 module.defineModuleFunction("singleton_method_undefined", callbackFactory.getSingletonMethod("singleton_method_undefined", IRUBY_OBJECT)); 160 161 module.defineFastPublicModuleFunction("==", objectCallbackFactory.getFastMethod("obj_equal", IRUBY_OBJECT)); 163 module.defineFastPublicModuleFunction("===", objectCallbackFactory.getFastMethod("equal", IRUBY_OBJECT)); 164 165 module.defineAlias("eql?", "=="); 166 module.defineFastPublicModuleFunction("to_s", objectCallbackFactory.getFastMethod("to_s")); 167 module.defineFastPublicModuleFunction("nil?", objectCallbackFactory.getFastMethod("nil_p")); 168 module.defineFastPublicModuleFunction("to_a", callbackFactory.getFastSingletonMethod("to_a")); 169 module.defineFastPublicModuleFunction("hash", objectCallbackFactory.getFastMethod("hash")); 170 module.defineFastPublicModuleFunction("id", objectCallbackFactory.getFastMethod("id_deprecated")); 171 module.defineFastPublicModuleFunction("object_id", objectCallbackFactory.getFastMethod("id")); 172 module.defineAlias("__id__", "object_id"); 173 module.defineFastPublicModuleFunction("is_a?", objectCallbackFactory.getFastMethod("kind_of", IRUBY_OBJECT)); 174 module.defineAlias("kind_of?", "is_a?"); 175 module.defineFastPublicModuleFunction("dup", objectCallbackFactory.getFastMethod("dup")); 176 module.defineFastPublicModuleFunction("equal?", objectCallbackFactory.getFastMethod("same", IRUBY_OBJECT)); 177 module.defineFastPublicModuleFunction("type", objectCallbackFactory.getFastMethod("type_deprecated")); 178 module.defineFastPublicModuleFunction("class", objectCallbackFactory.getFastMethod("type")); 179 module.defineFastPublicModuleFunction("inspect", objectCallbackFactory.getFastMethod("inspect")); 180 module.defineFastPublicModuleFunction("=~", objectCallbackFactory.getFastMethod("match", IRUBY_OBJECT)); 181 module.defineFastPublicModuleFunction("clone", objectCallbackFactory.getFastMethod("rbClone")); 182 module.defineFastPublicModuleFunction("display", objectCallbackFactory.getFastOptMethod("display")); 183 module.defineFastPublicModuleFunction("extend", objectCallbackFactory.getFastOptMethod("extend")); 184 module.defineFastPublicModuleFunction("freeze", objectCallbackFactory.getFastMethod("freeze")); 185 module.defineFastPublicModuleFunction("frozen?", objectCallbackFactory.getFastMethod("frozen")); 186 module.defineFastModuleFunction("initialize_copy", objectCallbackFactory.getFastMethod("initialize_copy", IRUBY_OBJECT)); 187 module.definePublicModuleFunction("instance_eval", objectCallbackFactory.getOptMethod("instance_eval")); 188 module.defineFastPublicModuleFunction("instance_of?", objectCallbackFactory.getFastMethod("instance_of", IRUBY_OBJECT)); 189 module.defineFastPublicModuleFunction("instance_variables", objectCallbackFactory.getFastMethod("instance_variables")); 190 module.defineFastPublicModuleFunction("instance_variable_get", objectCallbackFactory.getFastMethod("instance_variable_get", IRUBY_OBJECT)); 191 module.defineFastPublicModuleFunction("instance_variable_set", objectCallbackFactory.getFastMethod("instance_variable_set", IRUBY_OBJECT, IRUBY_OBJECT)); 192 module.defineFastPublicModuleFunction("method", objectCallbackFactory.getFastMethod("method", IRUBY_OBJECT)); 193 module.defineFastPublicModuleFunction("methods", objectCallbackFactory.getFastOptMethod("methods")); 194 module.defineFastPublicModuleFunction("private_methods", objectCallbackFactory.getFastMethod("private_methods")); 195 module.defineFastPublicModuleFunction("protected_methods", objectCallbackFactory.getFastMethod("protected_methods")); 196 module.defineFastPublicModuleFunction("public_methods", objectCallbackFactory.getFastOptMethod("public_methods")); 197 module.defineFastModuleFunction("remove_instance_variable", objectCallbackFactory.getMethod("remove_instance_variable", IRUBY_OBJECT)); 198 module.defineFastPublicModuleFunction("respond_to?", objectCallbackFactory.getFastOptMethod("respond_to")); 199 module.definePublicModuleFunction("send", objectCallbackFactory.getOptMethod("send")); 200 module.defineAlias("__send__", "send"); 201 module.defineFastPublicModuleFunction("singleton_methods", objectCallbackFactory.getFastOptMethod("singleton_methods")); 202 module.defineFastPublicModuleFunction("taint", objectCallbackFactory.getFastMethod("taint")); 203 module.defineFastPublicModuleFunction("tainted?", objectCallbackFactory.getFastMethod("tainted")); 204 module.defineFastPublicModuleFunction("untaint", objectCallbackFactory.getFastMethod("untaint")); 205 206 return module; 207 } 208 209 public static IRubyObject at_exit(IRubyObject recv, Block block) { 210 return recv.getRuntime().pushExitBlock(recv.getRuntime().newProc(false, block)); 211 } 212 213 public static IRubyObject autoload_p(final IRubyObject recv, IRubyObject symbol) { 214 String name = symbol.asSymbol(); 215 if (recv instanceof RubyModule) { 216 name = ((RubyModule)recv).getName() + "::" + name; 217 } 218 219 IAutoloadMethod autoloadMethod = recv.getRuntime().getLoadService().autoloadFor(name); 220 if(autoloadMethod == null) return recv.getRuntime().getNil(); 221 222 return recv.getRuntime().newString(autoloadMethod.file()); 223 } 224 225 public static IRubyObject autoload(final IRubyObject recv, IRubyObject symbol, final IRubyObject file) { 226 final LoadService loadService = recv.getRuntime().getLoadService(); 227 final String baseName = symbol.asSymbol(); 228 String nm = baseName; 229 if(recv instanceof RubyModule) { 230 nm = ((RubyModule)recv).getName() + "::" + nm; 231 } 232 loadService.addAutoload(nm, new IAutoloadMethod() { 233 public String file() { 234 return file.toString(); 235 } 236 239 public IRubyObject load(Ruby runtime, String name) { 240 loadService.require(file.toString()); 241 if(recv instanceof RubyModule) { 242 return ((RubyModule)recv).getConstant(baseName); 243 } 244 return runtime.getObject().getConstant(baseName); 245 } 246 }); 247 return recv; 248 } 249 250 public static IRubyObject method_missing(IRubyObject recv, IRubyObject[] args, Block block) { 251 Ruby runtime = recv.getRuntime(); 252 if (args.length == 0) { 253 throw recv.getRuntime().newArgumentError("no id given"); 254 } 255 256 String name = args[0].asSymbol(); 257 String description = null; 258 if("inspect".equals(name) || "to_s".equals(name)) { 259 description = recv.anyToString().toString(); 260 } else { 261 description = recv.inspect().toString(); 262 } 263 boolean noClass = description.length() > 0 && description.charAt(0) == '#'; 264 ThreadContext tc = runtime.getCurrentContext(); 265 Visibility lastVis = tc.getLastVisibility(); 266 if(null == lastVis) { 267 lastVis = Visibility.PUBLIC; 268 } 269 CallType lastCallType = tc.getLastCallType(); 270 String format = lastVis.errorMessageFormat(lastCallType, name); 271 String msg = new PrintfFormat(format).sprintf(new Object [] { name, description, 272 noClass ? "" : ":", noClass ? "" : recv.getType().getName()}, null); 273 274 throw lastCallType == CallType.VARIABLE ? runtime.newNameError(msg, name) : runtime.newNoMethodError(msg, name); 275 } 276 277 public static IRubyObject open(IRubyObject recv, IRubyObject[] args, Block block) { 278 recv.checkArgumentCount(args,1,3); 279 String arg = args[0].convertToString().toString(); 280 281 if (arg.startsWith("|")) { 283 String command = arg.substring(1); 284 try { 286 Process p = Runtime.getRuntime().exec(command,getCurrentEnv(recv.getRuntime())); 288 RubyIO io = new RubyIO(recv.getRuntime(), p); 289 290 if (block.isGiven()) { 291 try { 292 recv.getRuntime().getCurrentContext().yield(io, block); 293 294 return recv.getRuntime().getNil(); 295 } finally { 296 io.close(); 297 } 298 } 299 300 return io; 301 } catch (IOException ioe) { 302 throw recv.getRuntime().newIOErrorFromException(ioe); 303 } 304 } 305 306 return ((FileMetaClass) recv.getRuntime().getClass("File")).open(args, block); 307 } 308 309 public static IRubyObject gets(IRubyObject recv, IRubyObject[] args) { 310 return ((RubyArgsFile) recv.getRuntime().getGlobalVariables().get("$<")).gets(args); 311 } 312 313 public static IRubyObject abort(IRubyObject recv, IRubyObject[] args) { 314 if(recv.checkArgumentCount(args,0,1) == 1) { 315 recv.getRuntime().getGlobalVariables().get("$stderr").callMethod(recv.getRuntime().getCurrentContext(),"puts",args[0]); 316 } 317 throw new MainExitException(1,true); 318 } 319 320 public static IRubyObject new_array(IRubyObject recv, IRubyObject object) { 321 IRubyObject value = object.convertToTypeWithCheck("Array", "to_ary"); 322 323 if (value.isNil()) { 324 DynamicMethod method = object.getMetaClass().searchMethod("to_a"); 325 326 if (method.getImplementationClass() == recv.getRuntime().getKernel()) { 327 return recv.getRuntime().newArray(object); 328 } 329 330 value = object.callMethod(recv.getRuntime().getCurrentContext(), "to_a"); 332 if (value.getMetaClass() != recv.getRuntime().getClass("Array")) { 333 throw recv.getRuntime().newTypeError("`to_a' did not return Array"); 334 335 } 336 } 337 338 return value; 339 } 340 341 public static IRubyObject new_float(IRubyObject recv, IRubyObject object) { 342 if(object instanceof RubyFixnum){ 343 return RubyFloat.newFloat(object.getRuntime(), ((RubyFixnum)object).getDoubleValue()); 344 }else if(object instanceof RubyFloat){ 345 return object; 346 }else if(object instanceof RubyBignum){ 347 return RubyFloat.newFloat(object.getRuntime(), RubyBignum.big2dbl((RubyBignum)object)); 348 }else if(object instanceof RubyString){ 349 if(((RubyString)object).getValue().length() == 0){ throw recv.getRuntime().newArgumentError("invalid value for Float(): " + object.inspect()); 351 } 352 return RubyNumeric.str2fnum(recv.getRuntime(),(RubyString)object,true); 353 }else if(object.isNil()){ 354 throw recv.getRuntime().newTypeError("can't convert nil into Float"); 355 } else { 356 RubyFloat rFloat = object.convertToFloat(); 357 if(Double.isNaN(rFloat.getDoubleValue())){ 358 recv.getRuntime().newArgumentError("invalid value for Float()"); 359 } 360 return rFloat; 361 } 362 } 363 364 public static IRubyObject new_integer(IRubyObject recv, IRubyObject object) { 365 ThreadContext context = recv.getRuntime().getCurrentContext(); 366 367 if(object instanceof RubyString) { 368 return RubyNumeric.str2inum(recv.getRuntime(),(RubyString)object,0,true); 369 } 370 return object.callMethod(context,"to_i"); 371 } 372 373 public static IRubyObject new_string(IRubyObject recv, IRubyObject object) { 374 return object.callMethod(recv.getRuntime().getCurrentContext(), "to_s"); 375 } 376 377 378 public static IRubyObject p(IRubyObject recv, IRubyObject[] args) { 379 IRubyObject defout = recv.getRuntime().getGlobalVariables().get("$>"); 380 ThreadContext context = recv.getRuntime().getCurrentContext(); 381 382 for (int i = 0; i < args.length; i++) { 383 if (args[i] != null) { 384 defout.callMethod(context, "write", args[i].callMethod(context, "inspect")); 385 defout.callMethod(context, "write", recv.getRuntime().newString("\n")); 386 } 387 } 388 return recv.getRuntime().getNil(); 389 } 390 391 public static IRubyObject puts(IRubyObject recv, IRubyObject[] args) { 392 IRubyObject defout = recv.getRuntime().getGlobalVariables().get("$>"); 393 ThreadContext context = recv.getRuntime().getCurrentContext(); 394 395 defout.callMethod(context, "puts", args); 396 397 return recv.getRuntime().getNil(); 398 } 399 400 public static IRubyObject print(IRubyObject recv, IRubyObject[] args) { 401 IRubyObject defout = recv.getRuntime().getGlobalVariables().get("$>"); 402 ThreadContext context = recv.getRuntime().getCurrentContext(); 403 404 defout.callMethod(context, "print", args); 405 406 return recv.getRuntime().getNil(); 407 } 408 409 public static IRubyObject printf(IRubyObject recv, IRubyObject[] args) { 410 if (args.length != 0) { 411 IRubyObject defout = recv.getRuntime().getGlobalVariables().get("$>"); 412 413 if (!(args[0] instanceof RubyString)) { 414 defout = args[0]; 415 args = ArgsUtil.popArray(args); 416 } 417 418 ThreadContext context = recv.getRuntime().getCurrentContext(); 419 420 defout.callMethod(context, "write", RubyKernel.sprintf(recv, args)); 421 } 422 423 return recv.getRuntime().getNil(); 424 } 425 426 public static IRubyObject readline(IRubyObject recv, IRubyObject[] args) { 427 IRubyObject line = gets(recv, args); 428 429 if (line.isNil()) { 430 throw recv.getRuntime().newEOFError(); 431 } 432 433 return line; 434 } 435 436 public static RubyArray readlines(IRubyObject recv, IRubyObject[] args) { 437 return ((RubyArgsFile) recv.getRuntime().getGlobalVariables().get("$<")).readlines(args); 438 } 439 440 445 private static RubyString getLastlineString(Ruby runtime) { 446 IRubyObject line = runtime.getCurrentContext().getLastline(); 447 448 if (line.isNil()) { 449 throw runtime.newTypeError("$_ value need to be String (nil given)."); 450 } else if (!(line instanceof RubyString)) { 451 throw runtime.newTypeError("$_ value need to be String (" + line.getMetaClass().getName() + " given)."); 452 } else { 453 return (RubyString) line; 454 } 455 } 456 457 public static IRubyObject sub_bang(IRubyObject recv, IRubyObject[] args, Block block) { 458 return getLastlineString(recv.getRuntime()).sub_bang(args, block); 459 } 460 461 public static IRubyObject sub(IRubyObject recv, IRubyObject[] args, Block block) { 462 RubyString str = (RubyString) getLastlineString(recv.getRuntime()).dup(); 463 464 if (!str.sub_bang(args, block).isNil()) { 465 recv.getRuntime().getCurrentContext().setLastline(str); 466 } 467 468 return str; 469 } 470 471 public static IRubyObject gsub_bang(IRubyObject recv, IRubyObject[] args, Block block) { 472 return getLastlineString(recv.getRuntime()).gsub_bang(args, block); 473 } 474 475 public static IRubyObject gsub(IRubyObject recv, IRubyObject[] args, Block block) { 476 RubyString str = (RubyString) getLastlineString(recv.getRuntime()).dup(); 477 478 if (!str.gsub_bang(args, block).isNil()) { 479 recv.getRuntime().getCurrentContext().setLastline(str); 480 } 481 482 return str; 483 } 484 485 public static IRubyObject chop_bang(IRubyObject recv) { 486 return getLastlineString(recv.getRuntime()).chop_bang(); 487 } 488 489 public static IRubyObject chop(IRubyObject recv) { 490 RubyString str = getLastlineString(recv.getRuntime()); 491 492 if (str.getValue().length() > 0) { 493 str = (RubyString) str.dup(); 494 str.chop_bang(); 495 recv.getRuntime().getCurrentContext().setLastline(str); 496 } 497 498 return str; 499 } 500 501 public static IRubyObject chomp_bang(IRubyObject recv, IRubyObject[] args) { 502 return getLastlineString(recv.getRuntime()).chomp_bang(args); 503 } 504 505 public static IRubyObject chomp(IRubyObject recv, IRubyObject[] args) { 506 RubyString str = getLastlineString(recv.getRuntime()); 507 RubyString dup = (RubyString) str.dup(); 508 509 if (dup.chomp_bang(args).isNil()) { 510 return str; 511 } 512 513 recv.getRuntime().getCurrentContext().setLastline(dup); 514 return dup; 515 } 516 517 public static IRubyObject split(IRubyObject recv, IRubyObject[] args) { 518 return getLastlineString(recv.getRuntime()).split(args); 519 } 520 521 public static IRubyObject scan(IRubyObject recv, IRubyObject pattern, Block block) { 522 return getLastlineString(recv.getRuntime()).scan(pattern, block); 523 } 524 525 public static IRubyObject select(IRubyObject recv, IRubyObject[] args) { 526 return IOMetaClass.select_static(recv.getRuntime(), args); 527 } 528 529 public static IRubyObject sleep(IRubyObject recv, IRubyObject seconds) { 530 long milliseconds = (long) (seconds.convertToFloat().getDoubleValue() * 1000); 531 long startTime = System.currentTimeMillis(); 532 533 RubyThread rubyThread = recv.getRuntime().getThreadService().getCurrentContext().getThread(); 534 try { 535 rubyThread.sleep(milliseconds); 536 } catch (InterruptedException iExcptn) { 537 } 538 539 return recv.getRuntime().newFixnum( 540 Math.round((System.currentTimeMillis() - startTime) / 1000.0)); 541 } 542 543 public static IRubyObject exit(IRubyObject recv, IRubyObject[] args) { 545 recv.getRuntime().secure(4); 546 547 int status = 1; 548 if (args.length > 0) { 549 RubyObject argument = (RubyObject)args[0]; 550 if (argument instanceof RubyFixnum) { 551 status = RubyNumeric.fix2int(argument); 552 } else { 553 status = argument.isFalse() ? 1 : 0; 554 } 555 } 556 557 throw recv.getRuntime().newSystemExit(status); 558 } 559 560 public static IRubyObject exit_bang(IRubyObject recv, IRubyObject[] args) { 561 return exit(recv, args); 562 } 563 564 565 568 public static RubyArray global_variables(IRubyObject recv) { 569 RubyArray globalVariables = recv.getRuntime().newArray(); 570 571 Iterator iter = recv.getRuntime().getGlobalVariables().getNames(); 572 while (iter.hasNext()) { 573 String globalVariableName = (String ) iter.next(); 574 575 globalVariables.append(recv.getRuntime().newString(globalVariableName)); 576 } 577 578 return globalVariables; 579 } 580 581 584 public static RubyArray local_variables(IRubyObject recv) { 585 final Ruby runtime = recv.getRuntime(); 586 RubyArray localVariables = runtime.newArray(); 587 588 String [] names = runtime.getCurrentContext().getCurrentScope().getAllNamesInScope(); 589 for (int i = 0; i < names.length; i++) { 590 localVariables.append(runtime.newString(names[i])); 591 } 592 593 return localVariables; 594 } 595 596 public static RubyBinding binding(IRubyObject recv, Block block) { 597 return recv.getRuntime().newBinding(); 599 } 600 601 public static RubyBoolean block_given(IRubyObject recv, Block block) { 602 return recv.getRuntime().newBoolean(recv.getRuntime().getCurrentContext().getPreviousFrame().getBlock().isGiven()); 603 } 604 605 public static IRubyObject sprintf(IRubyObject recv, IRubyObject[] args) { 606 if (args.length == 0) { 607 throw recv.getRuntime().newArgumentError("sprintf must have at least one argument"); 608 } 609 610 RubyString str = RubyString.stringValue(args[0]); 611 612 RubyArray newArgs = recv.getRuntime().newArrayNoCopy(args); 613 newArgs.shift(); 614 615 return str.format(newArgs); 616 } 617 618 public static IRubyObject raise(IRubyObject recv, IRubyObject[] args, Block block) { 619 recv.checkArgumentCount(args, 0, 3); 621 Ruby runtime = recv.getRuntime(); 622 623 if (args.length == 0) { 624 IRubyObject lastException = runtime.getGlobalVariables().get("$!"); 625 if (lastException.isNil()) { 626 throw new RaiseException(runtime, runtime.getClass("RuntimeError"), "", false); 627 } 628 throw new RaiseException((RubyException) lastException); 629 } 630 631 IRubyObject exception; 632 ThreadContext context = recv.getRuntime().getCurrentContext(); 633 634 if (args.length == 1) { 635 if (args[0] instanceof RubyString) { 636 throw new RaiseException((RubyException)runtime.getClass("RuntimeError").newInstance(args, block)); 637 } 638 639 if (!args[0].respondsTo("exception")) { 640 throw runtime.newTypeError("exception class/object expected"); 641 } 642 exception = args[0].callMethod(context, "exception"); 643 } else { 644 if (!args[0].respondsTo("exception")) { 645 throw runtime.newTypeError("exception class/object expected"); 646 } 647 648 exception = args[0].callMethod(context, "exception", args[1]); 649 } 650 651 if (!exception.isKindOf(runtime.getClass("Exception"))) { 652 throw runtime.newTypeError("exception object expected"); 653 } 654 655 if (args.length == 3) { 656 ((RubyException) exception).set_backtrace(args[2]); 657 } 658 659 throw new RaiseException((RubyException) exception); 660 } 661 662 669 public static IRubyObject require(IRubyObject recv, IRubyObject name, Block block) { 670 if (recv.getRuntime().getLoadService().require(name.toString())) { 671 return recv.getRuntime().getTrue(); 672 } 673 return recv.getRuntime().getFalse(); 674 } 675 676 public static IRubyObject load(IRubyObject recv, IRubyObject[] args, Block block) { 677 RubyString file = args[0].convertToString(); 678 recv.getRuntime().getLoadService().load(file.toString()); 679 return recv.getRuntime().getTrue(); 680 } 681 682 public static IRubyObject eval(IRubyObject recv, IRubyObject[] args, Block block) { 683 if (args == null || args.length == 0) { 684 throw recv.getRuntime().newArgumentError(args.length, 1); 685 } 686 687 RubyString src = args[0].convertToString(); 688 IRubyObject scope = null; 689 String file = "(eval)"; 690 691 if (args.length > 1) { 692 if (!args[1].isNil()) { 693 scope = args[1]; 694 } 695 696 if (args.length > 2) { 697 file = args[2].toString(); 698 } 699 } 700 703 src.checkSafeString(); 704 ThreadContext context = recv.getRuntime().getCurrentContext(); 705 706 if (scope == null) { 707 scope = recv.getRuntime().newBinding(); 708 } 709 710 return recv.evalWithBinding(context, src, scope, file); 711 } 712 713 public static IRubyObject caller(IRubyObject recv, IRubyObject[] args, Block block) { 714 int level = args.length > 0 ? RubyNumeric.fix2int(args[0]) : 1; 715 716 if (level < 0) { 717 throw recv.getRuntime().newArgumentError("negative level(" + level + ')'); 718 } 719 720 return recv.getRuntime().getCurrentContext().createBacktrace(level, false); 721 } 722 723 public static IRubyObject rbCatch(IRubyObject recv, IRubyObject tag, Block block) { 724 ThreadContext context = recv.getRuntime().getCurrentContext(); 725 try { 726 context.pushCatch(tag.asSymbol()); 727 return context.yield(tag, block); 728 } catch (JumpException je) { 729 if (je.getJumpType() == JumpException.JumpType.ThrowJump && 730 je.getTarget().equals(tag.asSymbol())) { 731 return (IRubyObject) je.getValue(); 732 } 733 throw je; 734 } finally { 735 context.popCatch(); 736 } 737 } 738 739 public static IRubyObject rbThrow(IRubyObject recv, IRubyObject[] args, Block block) { 740 Ruby runtime = recv.getRuntime(); 741 742 String tag = args[0].asSymbol(); 743 String [] catches = runtime.getCurrentContext().getActiveCatches(); 744 745 String message = "uncaught throw '" + tag + '\''; 746 747 for (int i = catches.length - 1 ; i >= 0 ; i--) { 749 if (tag.equals(catches[i])) { 750 JumpException je = new JumpException(JumpException.JumpType.ThrowJump); 752 753 je.setTarget(tag); 754 je.setValue(args.length > 1 ? args[1] : runtime.getNil()); 755 throw je; 756 } 757 } 758 759 throw runtime.newNameError(message, tag); 761 } 762 763 public static IRubyObject trap(IRubyObject recv, IRubyObject[] args, Block block) { 764 return recv.getRuntime().getNil(); 766 } 767 768 public static IRubyObject warn(IRubyObject recv, IRubyObject message) { 769 IRubyObject out = recv.getRuntime().getObject().getConstant("STDERR"); 770 RubyIO io = (RubyIO) out.convertToType("IO", "to_io", true); 771 772 io.puts(new IRubyObject[] { message }); 773 return recv.getRuntime().getNil(); 774 } 775 776 public static IRubyObject set_trace_func(IRubyObject recv, IRubyObject trace_func, Block block) { 777 if (trace_func.isNil()) { 778 recv.getRuntime().setTraceFunction(null); 779 } else if (!(trace_func instanceof RubyProc)) { 780 throw recv.getRuntime().newTypeError("trace_func needs to be Proc."); 781 } else { 782 recv.getRuntime().setTraceFunction((RubyProc) trace_func); 783 } 784 return trace_func; 785 } 786 787 public static IRubyObject singleton_method_added(IRubyObject recv, IRubyObject symbolId, Block block) { 788 return recv.getRuntime().getNil(); 789 } 790 791 public static IRubyObject singleton_method_removed(IRubyObject recv, IRubyObject symbolId, Block block) { 792 return recv.getRuntime().getNil(); 793 } 794 795 public static IRubyObject singleton_method_undefined(IRubyObject recv, IRubyObject symbolId, Block block) { 796 return recv.getRuntime().getNil(); 797 } 798 799 800 public static RubyProc proc(IRubyObject recv, Block block) { 801 return recv.getRuntime().newProc(true, block); 802 } 803 804 public static IRubyObject loop(IRubyObject recv, Block block) { 805 ThreadContext context = recv.getRuntime().getCurrentContext(); 806 while (true) { 807 try { 808 context.yield(recv.getRuntime().getNil(), block); 809 810 Thread.yield(); 811 } catch (JumpException je) { 812 if (je.getJumpType() == JumpException.JumpType.BreakJump) { 819 if (je.getTarget() != null && je.getTarget() != block) { 820 je.setBreakInKernelLoop(true); 821 } 822 } 823 824 throw je; 825 } 826 } 827 } 828 public static IRubyObject test(IRubyObject recv, IRubyObject[] args) { 829 int cmd = (int) args[0].convertToInteger().getLongValue(); 830 Ruby runtime = recv.getRuntime(); 831 File pwd = new File (recv.getRuntime().getCurrentDirectory()); 832 File file1 = new File (pwd, args[1].toString()); 833 Calendar calendar; 834 switch (cmd) { 835 case 'f': 843 return RubyBoolean.newBoolean(runtime, file1.isFile()); 844 case 'M': 852 calendar = Calendar.getInstance(); 853 calendar.setTimeInMillis(file1.lastModified()); 854 return RubyTime.newTime(runtime, calendar); 855 } 888 throw RaiseException.createNativeRaiseException(runtime, 889 new UnsupportedOperationException ("test flag " + ((char) cmd) + " is not implemented")); 890 } 891 892 public static IRubyObject backquote(IRubyObject recv, IRubyObject aString) { 893 Ruby runtime = recv.getRuntime(); 894 ByteArrayOutputStream output = new ByteArrayOutputStream (); 895 896 int resultCode = runInShell(runtime, new IRubyObject[] {aString}, output); 897 898 recv.getRuntime().getGlobalVariables().set("$?", RubyProcess.RubyStatus.newProcessStatus(runtime, resultCode)); 899 900 return recv.getRuntime().newString(output.toString()); 901 } 902 903 private static final Pattern PATH_SEPARATORS = Pattern.compile("[/\\\\]"); 904 905 913 private static String repairDirSeps(String command) { 914 String executable = "", remainder = ""; 915 command = command.trim(); 916 if (command.startsWith("'")) { 917 String [] tokens = command.split("'", 3); 918 executable = "'"+tokens[1]+"'"; 919 if (tokens.length > 2) 920 remainder = tokens[2]; 921 } else if (command.startsWith("\"")) { 922 String [] tokens = command.split("\"", 3); 923 executable = "\""+tokens[1]+"\""; 924 if (tokens.length > 2) 925 remainder = tokens[2]; 926 } else { 927 String [] tokens = command.split(" ", 2); 928 executable = tokens[0]; 929 if (tokens.length > 1) 930 remainder = " "+tokens[1]; 931 } 932 933 String replacement = File.separator; 935 if (File.separatorChar == '\\') 936 replacement = "\\\\"; 937 938 return PATH_SEPARATORS.matcher(executable).replaceAll(replacement) + remainder; 939 } 940 941 private static List parseCommandLine(IRubyObject[] rawArgs) { 942 String command = rawArgs[0].toString(); 945 UnsynchronizedStack args = new UnsynchronizedStack(); 946 StringTokenizer st = new StringTokenizer (command, " "); 947 String quoteChar = null; 948 949 while (st.hasMoreTokens()) { 950 String token = st.nextToken(); 951 if (quoteChar == null) { 952 if (token.startsWith("'") || token.startsWith("\"")) { 954 quoteChar = token.substring(0, 1); 956 token = token.substring(1); 957 } 958 if (quoteChar!=null && token.endsWith(quoteChar)) { 959 token = token.substring(0, token.length()-1); 961 quoteChar = null; 962 } 963 args.push(token); 965 } else { 966 if (token.endsWith(quoteChar)) { 968 token = token.substring(0, token.length()-1); 970 quoteChar = null; 971 } 972 token = args.pop() + " " + token; 974 args.push(token); 975 } 976 } 977 978 for (int i=1;i<rawArgs.length;i++) { 980 args.push(rawArgs[i].toString()); 981 } 982 983 return args; 984 } 985 986 989 private static boolean shouldRunInProcess(Ruby runtime, String command) { 990 command = command.trim(); 991 String [] spaceDelimitedTokens = command.split(" ", 2); 992 String [] slashDelimitedTokens = spaceDelimitedTokens[0].split("/"); 993 String finalToken = slashDelimitedTokens[slashDelimitedTokens.length-1]; 994 return (finalToken.indexOf("ruby") != -1 || finalToken.endsWith(".rb") || finalToken.endsWith("irb")); 995 } 996 997 private static class InProcessScript extends Thread { 998 private String [] argArray; 999 private int result; 1000 private RubyInstanceConfig config; 1001 1002 public InProcessScript(final String [] argArray, final InputStream in, 1003 final OutputStream out, final OutputStream err, final String [] env, final File dir) { 1004 this.argArray = argArray; 1005 this.config = new RubyInstanceConfig() {{ 1006 setInput(in); 1007 setOutput(new PrintStream (out)); 1008 setError(new PrintStream (err)); 1009 setEnvironment(environmentMap(env)); 1010 setCurrentDirectory(dir.toString()); 1011 }}; 1012 } 1013 1014 public int getResult() { 1015 return result; 1016 } 1017 1018 public void setResult(int result) { 1019 this.result = result; 1020 } 1021 1022 public void run() { 1023 result = new Main(config).run(argArray); 1024 } 1025 1026 private Map environmentMap(String [] env) { 1027 Map m = new HashMap (); 1028 for (int i = 0; i < env.length; i++) { 1029 String [] kv = env[i].split("=", 2); 1030 m.put(kv[0], kv[1]); 1031 } 1032 return m; 1033 } 1034 } 1035 1036 public static int runInShell(Ruby runtime, IRubyObject[] rawArgs) { 1037 return runInShell(runtime,rawArgs,runtime.getOutputStream()); 1038 } 1039 1040 private static String [] getCurrentEnv(Ruby runtime) { 1041 Map h = ((RubyHash)runtime.getObject().getConstant("ENV")).getValueMap(); 1042 String [] ret = new String [h.size()]; 1043 int i=0; 1044 for(Iterator iter = h.entrySet().iterator();iter.hasNext();i++) { 1045 Map.Entry e = (Map.Entry )iter.next(); 1046 ret[i] = e.getKey().toString() + "=" + e.getValue().toString(); 1047 } 1048 return ret; 1049 } 1050 1051 public static int runInShell(Ruby runtime, IRubyObject[] rawArgs, OutputStream output) { 1052 OutputStream error = runtime.getErrorStream(); 1053 InputStream input = runtime.getInputStream(); 1054 try { 1055 String shell = runtime.evalScript("require 'rbconfig'; Config::CONFIG['SHELL']").toString(); 1056 rawArgs[0] = runtime.newString(repairDirSeps(rawArgs[0].toString())); 1057 Process aProcess = null; 1058 InProcessScript ipScript = null; 1059 File pwd = new File (runtime.getCurrentDirectory()); 1060 1061 if (shouldRunInProcess(runtime, rawArgs[0].toString())) { 1062 List args = parseCommandLine(rawArgs); 1063 String command = (String )args.get(0); 1064 1065 int startIndex = command.endsWith(".rb") ? 0 : 1; 1068 if(command.trim().endsWith("irb")) { 1069 startIndex = 0; 1070 args.set(0,runtime.getJRubyHome() + File.separator + "bin" + File.separator + "jirb"); 1071 } 1072 String [] argArray = (String [])args.subList(startIndex,args.size()).toArray(new String [0]); 1073 ipScript = new InProcessScript(argArray, input, output, error, getCurrentEnv(runtime), pwd); 1074 1075 ipScript.start(); 1077 ipScript.join(); 1078 } else if (shell != null && rawArgs.length == 1) { 1079 String shellSwitch = shell.endsWith("sh") ? "-c" : "/c"; 1082 String [] argArray = new String [3]; 1083 argArray[0] = shell; 1084 argArray[1] = shellSwitch; 1085 argArray[2] = rawArgs[0].toString(); 1086 aProcess = Runtime.getRuntime().exec(argArray, getCurrentEnv(runtime), pwd); 1087 } else { 1088 if (rawArgs.length > 1) { 1090 String [] argArray = new String [rawArgs.length]; 1091 for (int i=0;i<rawArgs.length;i++) { 1092 argArray[i] = rawArgs[i].toString(); 1093 } 1094 aProcess = Runtime.getRuntime().exec(argArray,getCurrentEnv(runtime), pwd); 1095 } else { 1096 aProcess = Runtime.getRuntime().exec(rawArgs[0].toString(), getCurrentEnv(runtime), pwd); 1097 } 1098 } 1099 1100 if (aProcess != null) { 1101 handleStreams(aProcess,input,output,error); 1102 return aProcess.waitFor(); 1103 } else if (ipScript != null) { 1104 return ipScript.getResult(); 1105 } else { 1106 return 0; 1107 } 1108 } catch (IOException e) { 1109 throw runtime.newIOErrorFromException(e); 1110 } catch (InterruptedException e) { 1111 throw runtime.newThreadError("unexpected interrupt"); 1112 } 1113 } 1114 1115 private static void handleStreams(Process p, InputStream in, OutputStream out, OutputStream err) throws IOException { 1116 InputStream pOut = p.getInputStream(); 1117 InputStream pErr = p.getErrorStream(); 1118 OutputStream pIn = p.getOutputStream(); 1119 1120 boolean done = false; 1121 int b; 1122 boolean proc = false; 1123 while(!done) { 1124 if(pOut.available() > 0) { 1125 byte[] input = new byte[pOut.available()]; 1126 if((b = pOut.read(input)) == -1) { 1127 done = true; 1128 } else { 1129 out.write(input); 1130 } 1131 proc = true; 1132 } 1133 if(pErr.available() > 0) { 1134 byte[] input = new byte[pErr.available()]; 1135 if((b = pErr.read(input)) != -1) { 1136 err.write(input); 1137 } 1138 proc = true; 1139 } 1140 if(in.available() > 0) { 1141 byte[] input = new byte[in.available()]; 1142 if((b = in.read(input)) != -1) { 1143 pIn.write(input); 1144 } 1145 proc = true; 1146 } 1147 if(!proc) { 1148 if((b = pOut.read()) == -1) { 1149 if((b = pErr.read()) == -1) { 1150 done = true; 1151 } else { 1152 err.write(b); 1153 } 1154 } else { 1155 out.write(b); 1156 } 1157 } 1158 proc = false; 1159 } 1160 pOut.close(); 1161 pErr.close(); 1162 pIn.close(); 1163 } 1164 1165 public static RubyInteger srand(IRubyObject recv, IRubyObject[] args) { 1166 Ruby runtime = recv.getRuntime(); 1167 long oldRandomSeed = runtime.getRandomSeed(); 1168 1169 if (args.length > 0) { 1170 RubyInteger integerSeed = 1171 (RubyInteger) args[0].convertToType("Integer", "to_i", true); 1172 runtime.setRandomSeed(integerSeed.getLongValue()); 1173 } else { 1174 runtime.setRandomSeed(System.currentTimeMillis() ^ 1177 recv.hashCode() ^ runtime.incrementRandomSeedSequence() ^ 1178 runtime.getRandom().nextInt(Math.abs((int)runtime.getRandomSeed()))); 1179 } 1180 runtime.getRandom().setSeed(runtime.getRandomSeed()); 1181 return runtime.newFixnum(oldRandomSeed); 1182 } 1183 1184 public static RubyNumeric rand(IRubyObject recv, IRubyObject[] args) { 1185 long ceil; 1186 if (args.length == 0) { 1187 ceil = 0; 1188 } else if (args.length == 1) { 1189 RubyInteger integerCeil = (RubyInteger) args[0].convertToType("Integer", "to_i", true); 1190 ceil = integerCeil.getLongValue(); 1191 ceil = Math.abs(ceil); 1192 if (ceil > Integer.MAX_VALUE) { 1193 throw recv.getRuntime().newNotImplementedError("Random values larger than Integer.MAX_VALUE not supported"); 1194 } 1195 } else { 1196 throw recv.getRuntime().newArgumentError("wrong # of arguments(" + args.length + " for 1)"); 1197 } 1198 1199 if (ceil == 0) { 1200 double result = recv.getRuntime().getRandom().nextDouble(); 1201 return RubyFloat.newFloat(recv.getRuntime(), result); 1202 } 1203 return recv.getRuntime().newFixnum(recv.getRuntime().getRandom().nextInt((int) ceil)); 1204 } 1205 1206 public static RubyBoolean system(IRubyObject recv, IRubyObject[] args) { 1207 Ruby runtime = recv.getRuntime(); 1208 int resultCode = runInShell(runtime, args); 1209 recv.getRuntime().getGlobalVariables().set("$?", RubyProcess.RubyStatus.newProcessStatus(runtime, resultCode)); 1210 return runtime.newBoolean(resultCode == 0); 1211 } 1212 1213 public static RubyArray to_a(IRubyObject recv) { 1214 recv.getRuntime().getWarnings().warn("default 'to_a' will be obsolete"); 1215 return recv.getRuntime().newArray(recv); 1216 } 1217} 1218 | Popular Tags |