1 /***** BEGIN LICENSE BLOCK *****
2 * Version: CPL 1.0/GPL 2.0/LGPL 2.1
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
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.
14 * Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
16 * Alternatively, the contents of this file may be used under the terms of
17 * either of the GNU General Public License Version 2 or later (the "GPL"),
18 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19 * in which case the provisions of the GPL or the LGPL are applicable instead
20 * of those above. If you wish to allow use of your version of this file only
21 * under the terms of either the GPL or the LGPL, and not to allow others to
22 * use your version of this file under the terms of the CPL, indicate your
23 * decision by deleting the provisions above and replace them with the notice
24 * and other provisions required by the GPL or the LGPL. If you do not delete
25 * the provisions above, a recipient may use your version of this file under
26 * the terms of any one of the CPL, the GPL or the LGPL.
27 ***** END LICENSE BLOCK *****/
30 import java
.io
.ByteArrayInputStream
;
32 import java
.io
.FileInputStream
;
33 import java
.io
.IOException
;
34 import java
.io
.InputStream
;
35 import java
.io
.PrintStream
;
36 import java
.io
.UnsupportedEncodingException
;
37 import java
.util
.ArrayList
;
38 import java
.util
.List
;
40 import org
.jruby
.ast
.executable
.Script
;
41 import org
.jruby
.exceptions
.MainExitException
;
42 import org
.jruby
.runtime
.Constants
;
43 import org
.jruby
.runtime
.load
.LoadService
;
44 import org
.jruby
.util
.ClassCache
;
45 import org
.jruby
.util
.JRubyFile
;
46 import org
.jruby
.util
.KCode
;
47 import org
.jruby
.util
.SafePropertyAccessor
;
49 public class RubyInstanceConfig
{
51 public enum CompileMode
{
54 public boolean shouldPrecompileCLI() {
62 public boolean shouldJIT() {
70 public boolean shouldPrecompileAll() {
74 private InputStream input
= System
.in
;
75 private PrintStream output
= System
.out
;
76 private PrintStream error
= System
.err
;
77 private Profile profile
= Profile
.DEFAULT
;
78 private boolean objectSpaceEnabled
79 = SafePropertyAccessor
.getBoolean("jruby.objectspace.enabled", false);
81 private CompileMode compileMode
= CompileMode
.JIT
;
82 private boolean runRubyInProcess
= true;
83 private String currentDirectory
;
84 private Map environment
;
85 private String
[] argv
= {};
87 private final boolean jitLogging
;
88 private final boolean jitLoggingVerbose
;
89 private final int jitLogEvery
;
90 private final int jitThreshold
;
91 private final int jitMax
;
92 private final boolean samplingEnabled
;
93 private CompatVersion compatVersion
;
95 private ClassLoader loader
= Thread
.currentThread().getContextClassLoader();
97 private ClassCache
<Script
> classCache
;
99 // from CommandlineParser
100 private List
<String
> loadPaths
= new ArrayList
<String
>();
101 private StringBuffer inlineScript
= new StringBuffer();
102 private boolean hasInlineScript
= false;
103 private String scriptFileName
= null;
104 private List
<String
> requiredLibraries
= new ArrayList
<String
>();
105 private boolean benchmarking
= false;
106 private boolean assumeLoop
= false;
107 private boolean assumePrinting
= false;
108 private boolean processLineEnds
= false;
109 private boolean split
= false;
110 // This property is a Boolean, to allow three values, so it can match MRI's nil, false and true
111 private Boolean verbose
= Boolean
.FALSE
;
112 private boolean debug
= false;
113 private boolean showVersion
= false;
114 private boolean showCopyright
= false;
115 private boolean endOfArguments
= false;
116 private boolean shouldRunInterpreter
= true;
117 private boolean shouldPrintUsage
= false;
118 private boolean shouldPrintProperties
=false;
119 private boolean yarv
= false;
120 private boolean rubinius
= false;
121 private boolean yarvCompile
= false;
122 private KCode kcode
= KCode
.NONE
;
123 private String recordSeparator
= "\n";
124 private boolean shouldCheckSyntax
= false;
125 private String inputFieldSeparator
= null;
127 private int safeLevel
= 0;
129 public static final boolean FASTEST_COMPILE_ENABLED
130 = SafePropertyAccessor
.getBoolean("jruby.compile.fastest");
131 public static final boolean BOXED_COMPILE_ENABLED
132 = FASTEST_COMPILE_ENABLED
133 || SafePropertyAccessor
.getBoolean("jruby.compile.boxed");
134 public static final boolean FASTOPS_COMPILE_ENABLED
135 = FASTEST_COMPILE_ENABLED
136 || SafePropertyAccessor
.getBoolean("jruby.compile.fastops");
137 public static final boolean FRAMELESS_COMPILE_ENABLED
138 = FASTEST_COMPILE_ENABLED
139 || SafePropertyAccessor
.getBoolean("jruby.compile.frameless");
140 public static final boolean POSITIONLESS_COMPILE_ENABLED
141 = FASTEST_COMPILE_ENABLED
142 || SafePropertyAccessor
.getBoolean("jruby.compile.positionless");
143 public static final boolean THREADLESS_COMPILE_ENABLED
144 = FASTEST_COMPILE_ENABLED
145 || SafePropertyAccessor
.getBoolean("jruby.compile.threadless");
146 public static final boolean INDEXED_METHODS
147 = SafePropertyAccessor
.getBoolean("jruby.indexed.methods");
148 public static final boolean FORK_ENABLED
149 = SafePropertyAccessor
.getBoolean("jruby.fork.enabled");
150 public static boolean nativeEnabled
= true;
152 public static interface LoadServiceCreator
{
153 LoadService
create(Ruby runtime
);
155 LoadServiceCreator DEFAULT
= new LoadServiceCreator() {
156 public LoadService
create(Ruby runtime
) {
157 return new LoadService(runtime
);
162 private LoadServiceCreator creator
= LoadServiceCreator
.DEFAULT
;
167 if (System
.getProperty("jruby.native.enabled") != null) {
168 nativeEnabled
= Boolean
.getBoolean("jruby.native.enabled");
170 } catch (SecurityException se
) {
171 nativeEnabled
= false;
175 public int characterIndex
= 0;
177 public RubyInstanceConfig() {
178 if (Ruby
.isSecurityRestricted())
179 currentDirectory
= "/";
181 currentDirectory
= JRubyFile
.getFileProperty("user.dir");
184 samplingEnabled
= SafePropertyAccessor
.getBoolean("jruby.sampling.enabled", false);
185 String compatString
= SafePropertyAccessor
.getProperty("jruby.compat.version", "RUBY1_8");
186 if (compatString
.equalsIgnoreCase("RUBY1_8")) {
187 compatVersion
= CompatVersion
.RUBY1_8
;
188 } else if (compatString
.equalsIgnoreCase("RUBY1_9")) {
189 compatVersion
= CompatVersion
.RUBY1_9
;
191 System
.err
.println("Compatibility version `" + compatString
+ "' invalid; use RUBY1_8 or RUBY1_9. Using RUBY1_8.");
192 compatVersion
= CompatVersion
.RUBY1_8
;
195 if (Ruby
.isSecurityRestricted()) {
196 compileMode
= CompileMode
.OFF
;
198 jitLoggingVerbose
= false;
203 String threshold
= SafePropertyAccessor
.getProperty("jruby.jit.threshold");
204 String max
= SafePropertyAccessor
.getProperty("jruby.jit.max");
206 runRubyInProcess
= SafePropertyAccessor
.getBoolean("jruby.launch.inproc", true);
207 boolean jitProperty
= SafePropertyAccessor
.getProperty("jruby.jit.enabled") != null;
209 error
.print("jruby.jit.enabled property is deprecated; use jruby.compile.mode=(OFF|JIT|FORCE) for -C, default, and +C flags");
210 compileMode
= SafePropertyAccessor
.getBoolean("jruby.jit.enabled") ? CompileMode
.JIT
: CompileMode
.OFF
;
212 String jitModeProperty
= SafePropertyAccessor
.getProperty("jruby.compile.mode", "JIT");
214 if (jitModeProperty
.equals("OFF")) {
215 compileMode
= CompileMode
.OFF
;
216 } else if (jitModeProperty
.equals("JIT")) {
217 compileMode
= CompileMode
.JIT
;
218 } else if (jitModeProperty
.equals("FORCE")) {
219 compileMode
= CompileMode
.FORCE
;
221 error
.print("jruby.compile.mode property must be OFF, JIT, FORCE, or unset; defaulting to JIT");
222 compileMode
= CompileMode
.JIT
;
225 jitLogging
= SafePropertyAccessor
.getBoolean("jruby.jit.logging");
226 jitLoggingVerbose
= SafePropertyAccessor
.getBoolean("jruby.jit.logging.verbose");
227 String logEvery
= SafePropertyAccessor
.getProperty("jruby.jit.logEvery");
228 jitLogEvery
= logEvery
== null ?
0 : Integer
.parseInt(logEvery
);
229 jitThreshold
= threshold
== null ?
20 : Integer
.parseInt(threshold
);
230 jitMax
= max
== null ?
2048 : Integer
.parseInt(max
);
233 // default ClassCache using jitMax as a soft upper bound
234 classCache
= new ClassCache
<Script
>(loader
, jitMax
);
237 error
.print("WARNING: fork is highly unlikely to be safe or stable on the JVM. Have fun!\n");
241 public LoadServiceCreator
getLoadServiceCreator() {
245 public void setLoadServiceCreator(LoadServiceCreator creator
) {
246 this.creator
= creator
;
249 public LoadService
createLoadService(Ruby runtime
) {
250 return this.creator
.create(runtime
);
253 public String
getBasicUsageHelp() {
254 StringBuffer sb
= new StringBuffer();
256 .append("Usage: jruby [switches] [--] [programfile] [arguments]\n")
257 .append(" -0[octal] specify record separator (\0, if no argument)\n")
258 .append(" -a autosplit mode with -n or -p (splits $_ into $F)\n")
259 .append(" -b benchmark mode, times the script execution\n")
260 .append(" -c check syntax only\n")
261 .append(" -Cdirectory cd to directory, before executing your script\n")
262 .append(" -d set debugging flags (set $DEBUG to true)\n")
263 .append(" -e 'command' one line of script. Several -e's allowed. Omit [programfile]\n")
264 .append(" -Fpattern split() pattern for autosplit (-a)\n")
265 //.append(" -i[extension] edit ARGV files in place (make backup if extension supplied)\n")
266 .append(" -Idirectory specify $LOAD_PATH directory (may be used more than once)\n")
267 .append(" -J[java option] pass an option on to the JVM (e.g. -J-Xmx512m)\n")
268 .append(" use --properties to list JRuby properties\n")
269 .append(" -Kkcode specifies KANJI (Japanese) code-set\n")
270 .append(" -l enable line ending processing\n")
271 .append(" -n assume 'while gets(); ... end' loop around your script\n")
272 .append(" -p assume loop like -n but print line also like sed\n")
273 .append(" -rlibrary require the library, before executing your script\n")
274 //.append(" -s enable some switch parsing for switches after script name\n")
275 .append(" -S look for the script in bin or using PATH environment variable\n")
276 .append(" -T[level] turn on tainting checks\n")
277 .append(" -v print version number, then turn on verbose mode\n")
278 .append(" -w turn warnings on for your script\n")
279 .append(" -W[level] set warning level; 0=silence, 1=medium, 2=verbose (default)\n")
280 //.append(" -x[directory] strip off text before #!ruby line and perhaps cd to directory\n")
281 .append(" -X[option] enable extended option (omit option to list)\n")
282 .append(" --copyright print the copyright\n")
283 .append(" --properties List all configuration Java properties (pass -J-Dproperty=value)\n")
284 .append(" --version print the version\n");
286 return sb
.toString();
289 public String
getExtendedHelp() {
290 StringBuffer sb
= new StringBuffer();
292 .append("These flags are for extended JRuby options.\n")
293 .append("Specify them by passing -X<option>\n")
294 .append(" -O run with ObjectSpace disabled (default; improves performance)\n")
295 .append(" +O run with ObjectSpace enabled (reduces performance)\n")
296 .append(" -C disable all compilation\n")
297 .append(" +C force compilation of all scripts before they are run (except eval)\n")
298 .append(" -y read a YARV-compiled Ruby script and run that (EXPERIMENTAL)\n")
299 .append(" -Y compile a Ruby script into YARV bytecodes and run this (EXPERIMENTAL)\n")
300 .append(" -R read a Rubinius-compiled Ruby script and run that (EXPERIMENTAL)");
302 return sb
.toString();
305 public String
getPropertyHelp() {
306 StringBuffer sb
= new StringBuffer();
308 .append("These properties can be used to alter runtime behavior for perf or compatibility.\n")
309 .append("Specify them by passing -J-D<property>=<value>\n")
310 .append("\nCOMPILER SETTINGS:\n")
311 .append(" jruby.compile.mode=JIT|FORCE|OFF\n")
312 .append(" Set compilation mode. JIT is default; FORCE compiles all, OFF disables\n")
313 .append(" jruby.compile.fastest=true|false\n")
314 .append(" (EXPERIMENTAL) Turn on all experimental compiler optimizations\n")
315 .append(" jruby.compile.boxed=true|false\n")
316 .append(" (EXPERIMENTAL) Use boxed variables; this can speed up some methods. Default is false\n")
317 .append(" jruby.compile.frameless=true|false\n")
318 .append(" (EXPERIMENTAL) Turn on frameless compilation where possible\n")
319 .append(" jruby.compile.positionless=true|false\n")
320 .append(" (EXPERIMENTAL) Turn on compilation that avoids updating Ruby position info. Default is false\n")
321 .append(" jruby.compile.threadless=true|false\n")
322 .append(" (EXPERIMENTAL) Turn on compilation without polling for \"unsafe\" thread events. Default is false\n")
323 .append(" jruby.compile.fastops=true|false\n")
324 .append(" (EXPERIMENTAL) Turn on fast operators for Fixnum. Default is false\n")
325 .append("\nJIT SETTINGS:\n")
326 .append(" jruby.jit.threshold=<invocation count>\n")
327 .append(" Set the JIT threshold to the specified method invocation count. Default is 20\n")
328 .append(" jruby.jit.max=<method count>\n")
329 .append(" Set the max count of active methods eligible for JIT-compilation.\n")
330 .append(" Default is 2048 per runtime. A value of 0 disables JIT, -1 disables max.\n")
331 .append(" jruby.jit.logging=true|false\n")
332 .append(" Enable JIT logging (reports successful compilation). Default is false\n")
333 .append(" jruby.jit.logging.verbose=true|false\n")
334 .append(" Enable verbose JIT logging (reports failed compilation). Default is false\n")
335 .append(" jruby.jit.logEvery=<method count>\n")
336 .append(" Log a message every n methods JIT compiled. Default is 0 (off).\n")
337 .append("\nNATIVE SUPPORT:\n")
338 .append(" jruby.native.enabled=true|false\n")
339 .append(" Enable/disable native extensions (like JNA for non-Java APIs; Default is true\n")
340 .append(" (This affects all JRuby instances in a given JVM)\n")
341 .append(" jruby.native.verbose=true|false\n")
342 .append(" Enable verbose logging of native extension loading. Default is false.\n")
343 .append(" jruby.fork.enabled=true|false\n")
344 .append(" (EXPERIMENTAL, maybe dangerous) Enable fork(2) on platforms that support it.\n")
345 .append("\nMISCELLANY:\n")
346 .append(" jruby.compat.version=RUBY1_8|RUBY1_9\n")
347 .append(" Specify the major Ruby version to be compatible with; Default is RUBY1_8\n")
348 .append(" jruby.indexed.methods=true|false\n")
349 .append(" Generate \"invokers\" for core classes using a single indexed class\n")
350 .append(" jruby.objectspace.enabled=true|false\n")
351 .append(" Enable or disable ObjectSpace.each_object (default is disabled)\n")
352 .append(" jruby.launch.inproc=true|false\n")
353 .append(" Set in-process launching of e.g. system('ruby ...'). Default is true\n");
355 return sb
.toString();
358 public String
getVersionString() {
359 StringBuffer buf
= new StringBuffer("ruby ");
360 switch (compatVersion
) {
362 buf
.append(Constants
.RUBY_VERSION
);
365 buf
.append(Constants
.RUBY1_9_VERSION
);
370 .append(Constants
.COMPILE_DATE
+ " rev " + Constants
.REVISION
)
372 .append(SafePropertyAccessor
.getProperty("os.arch", "unknown") + "-jruby" + Constants
.VERSION
)
376 return buf
.toString();
379 public String
getCopyrightString() {
380 return "JRuby - Copyright (C) 2001-2008 The JRuby Community (and contribs)\n";
383 public void processArguments(String
[] arguments
) {
384 new ArgumentProcessor(arguments
).processArguments();
387 public CompileMode
getCompileMode() {
391 public void setCompileMode(CompileMode compileMode
) {
392 this.compileMode
= compileMode
;
395 public boolean isJitLogging() {
399 public boolean isJitLoggingVerbose() {
400 return jitLoggingVerbose
;
403 public int getJitLogEvery() {
407 public boolean isSamplingEnabled() {
408 return samplingEnabled
;
411 public int getJitThreshold() {
415 public int getJitMax() {
419 public boolean isRunRubyInProcess() {
420 return runRubyInProcess
;
423 public void setRunRubyInProcess(boolean flag
) {
424 this.runRubyInProcess
= flag
;
427 public void setInput(InputStream newInput
) {
431 public InputStream
getInput() {
435 public CompatVersion
getCompatVersion() {
436 return compatVersion
;
439 public void setOutput(PrintStream newOutput
) {
443 public PrintStream
getOutput() {
447 public void setError(PrintStream newError
) {
451 public PrintStream
getError() {
455 public void setCurrentDirectory(String newCurrentDirectory
) {
456 currentDirectory
= newCurrentDirectory
;
459 public String
getCurrentDirectory() {
460 return currentDirectory
;
463 public void setProfile(Profile newProfile
) {
464 profile
= newProfile
;
467 public Profile
getProfile() {
471 public void setObjectSpaceEnabled(boolean newObjectSpaceEnabled
) {
472 objectSpaceEnabled
= newObjectSpaceEnabled
;
475 public boolean isObjectSpaceEnabled() {
476 return objectSpaceEnabled
;
479 public void setEnvironment(Map newEnvironment
) {
480 environment
= newEnvironment
;
483 public Map
getEnvironment() {
487 public ClassLoader
getLoader() {
491 public void setLoader(ClassLoader loader
) {
492 // Setting the loader needs to reset the class cache
493 if(this.loader
!= loader
) {
494 this.classCache
= new ClassCache
<Script
>(loader
, this.classCache
.getMax());
496 this.loader
= loader
;
499 public String
[] getArgv() {
503 public void setArgv(String
[] argv
) {
507 private class ArgumentProcessor
{
508 private String
[] arguments
;
509 private int argumentIndex
= 0;
511 public ArgumentProcessor(String
[] arguments
) {
512 this.arguments
= arguments
;
515 public void processArguments() {
516 while (argumentIndex
< arguments
.length
&& isInterpreterArgument(arguments
[argumentIndex
])) {
521 if (!hasInlineScript
) {
522 if (argumentIndex
< arguments
.length
) {
523 setScriptFileName(arguments
[argumentIndex
]); //consume the file name
529 // Remaining arguments are for the script itself
530 argv
= new String
[arguments
.length
- argumentIndex
];
531 System
.arraycopy(arguments
, argumentIndex
, argv
, 0, argv
.length
);
534 private boolean isInterpreterArgument(String argument
) {
535 return (argument
.charAt(0) == '-' || argument
.charAt(0) == '+') && !endOfArguments
;
538 private String
getArgumentError(String argument
, String additionalError
) {
539 return "jruby: invalid argument " + argument
+ "\n" + additionalError
+ "\n";
542 private String
getArgumentError(String additionalError
) {
543 return "jruby: invalid argument\n" + additionalError
+ "\n";
546 private void processArgument() {
547 String argument
= arguments
[argumentIndex
];
548 FOR
: for (characterIndex
= 1; characterIndex
< argument
.length(); characterIndex
++) {
549 switch (argument
.charAt(characterIndex
)) {
551 String temp
= grabOptionalValue();
553 recordSeparator
= "\u0000";
554 } else if (temp
.equals("0")) {
555 recordSeparator
= "\n\n";
556 } else if (temp
.equals("777")) {
557 recordSeparator
= "\uFFFF"; // Specify something that can't separate
560 int val
= Integer
.parseInt(temp
, 8);
561 recordSeparator
= "" + (char) val
;
562 } catch (Exception e
) {
563 MainExitException mee
= new MainExitException(1, getArgumentError(" -0 must be followed by either 0, 777, or a valid octal value"));
564 mee
.setUsageError(true);
577 shouldCheckSyntax
= true;
581 String saved
= grabValue(getArgumentError(" -C must be followed by a directory expression"));
582 File base
= new File(currentDirectory
);
583 File newDir
= new File(saved
);
584 if (newDir
.isAbsolute()) {
585 currentDirectory
= newDir
.getCanonicalPath();
587 currentDirectory
= new File(base
, newDir
.getPath()).getCanonicalPath();
589 if (!(new File(currentDirectory
).isDirectory())) {
590 MainExitException mee
= new MainExitException(1, "jruby: Can't chdir to " + saved
+ " (fatal)");
591 mee
.setUsageError(true);
594 } catch (IOException e
) {
595 MainExitException mee
= new MainExitException(1, getArgumentError(" -C must be followed by a valid directory"));
596 mee
.setUsageError(true);
602 verbose
= Boolean
.TRUE
;
605 inlineScript
.append(grabValue(getArgumentError(" -e must be followed by an expression to evaluate")));
606 inlineScript
.append('\n');
607 hasInlineScript
= true;
610 inputFieldSeparator
= grabValue(getArgumentError(" -F must be followed by a pattern for input field separation"));
613 shouldPrintUsage
= true;
614 shouldRunInterpreter
= false;
616 // FIXME: -i flag not supported
620 String s
= grabValue(getArgumentError("-I must be followed by a directory name to add to lib path"));
621 String
[] ls
= s
.split(java
.io
.File
.pathSeparator
);
622 for (int i
= 0; i
< ls
.length
; i
++) {
623 loadPaths
.add(ls
[i
]);
627 // FIXME: No argument seems to work for -K in MRI plus this should not
628 // siphon off additional args 'jruby -K ~/scripts/foo'. Also better error
630 String eArg
= grabValue(getArgumentError("provide a value for -K"));
631 kcode
= KCode
.create(null, eArg
);
634 processLineEnds
= true;
640 assumePrinting
= true;
644 requiredLibraries
.add(grabValue(getArgumentError("-r must be followed by a package to require")));
646 // FIXME: -s flag not supported
653 String temp
= grabOptionalValue();
658 value
= Integer
.parseInt(temp
, 8);
659 } catch(Exception e
) {
669 verbose
= Boolean
.TRUE
;
670 setShowVersion(true);
673 verbose
= Boolean
.TRUE
;
676 String temp
= grabOptionalValue();
679 if (temp
.equals("2")) {
681 } else if (temp
.equals("1")) {
683 } else if (temp
.equals("0")) {
686 MainExitException mee
= new MainExitException(1, getArgumentError(" -W must be followed by either 0, 1, 2 or nothing"));
687 mee
.setUsageError(true);
696 verbose
= Boolean
.FALSE
;
699 verbose
= Boolean
.TRUE
;
706 // FIXME: -x flag not supported
710 String extendedOption
= grabValue("jruby: missing extended option, listing available options\n" + getExtendedHelp());
712 if (extendedOption
.equals("-O")) {
713 objectSpaceEnabled
= false;
714 } else if (extendedOption
.equals("+O")) {
715 objectSpaceEnabled
= true;
716 } else if (extendedOption
.equals("-C")) {
717 compileMode
= CompileMode
.OFF
;
718 } else if (extendedOption
.equals("+C")) {
719 compileMode
= CompileMode
.FORCE
;
720 } else if (extendedOption
.equals("y")) {
722 } else if (extendedOption
.equals("Y")) {
724 } else if (extendedOption
.equals("R")) {
727 MainExitException mee
=
728 new MainExitException(1, "jruby: invalid extended option " + extendedOption
+ " (-X will list valid options)\n");
729 mee
.setUsageError(true);
735 if (argument
.equals("--command") || argument
.equals("--bin")) {
736 characterIndex
= argument
.length();
739 } else if (argument
.equals("--compat")) {
740 characterIndex
= argument
.length();
741 compatVersion
= CompatVersion
.getVersionFromString(grabValue(getArgumentError("--compat must be RUBY1_8 or RUBY1_9")));
742 if (compatVersion
== null) {
743 compatVersion
= CompatVersion
.RUBY1_8
;
746 } else if (argument
.equals("--copyright")) {
747 setShowCopyright(true);
748 shouldRunInterpreter
= false;
750 } else if (argument
.equals("--debug")) {
752 verbose
= Boolean
.TRUE
;
754 } else if (argument
.equals("--help")) {
755 shouldPrintUsage
= true;
756 shouldRunInterpreter
= false;
758 } else if (argument
.equals("--properties")) {
759 shouldPrintProperties
= true;
760 shouldRunInterpreter
= false;
762 } else if (argument
.equals("--version")) {
763 setShowVersion(true);
766 if (argument
.equals("--")) {
767 // ruby interpreter compatibilty
768 // Usage: ruby [switches] [--] [programfile] [arguments])
769 endOfArguments
= true;
774 throw new MainExitException(1, "jruby: unknown option " + argument
);
779 private void runBinScript() {
780 requiredLibraries
.add("jruby/commands");
781 String scriptName
= grabValue("jruby: provide a bin script to execute");
782 if (scriptName
.equals("irb")) {
785 inlineScript
.append("JRuby::Commands." + scriptName
);
786 inlineScript
.append("\n");
787 hasInlineScript
= true;
789 String jrubyHome
= JRubyFile
.create(System
.getProperty("user.dir"), JRubyFile
.getFileProperty("jruby.home")).getCanonicalPath();
790 scriptFileName
= JRubyFile
.create(jrubyHome
+ JRubyFile
.separator
+ "bin", scriptName
).getCanonicalPath();
791 } catch (IOException io
) {
792 MainExitException mee
= new MainExitException(1, "jruby: Can't determine script filename");
793 mee
.setUsageError(true);
796 endOfArguments
= true;
799 private String
grabValue(String errorMessage
) {
801 if (characterIndex
< arguments
[argumentIndex
].length()) {
802 return arguments
[argumentIndex
].substring(characterIndex
);
805 if (argumentIndex
< arguments
.length
) {
806 return arguments
[argumentIndex
];
809 MainExitException mee
= new MainExitException(1, errorMessage
);
810 mee
.setUsageError(true);
815 private String
grabOptionalValue() {
817 if (characterIndex
< arguments
[argumentIndex
].length()) {
818 return arguments
[argumentIndex
].substring(characterIndex
);
824 public byte[] inlineScript() {
826 return inlineScript
.toString().getBytes("UTF-8");
827 } catch (UnsupportedEncodingException e
) {
828 return inlineScript
.toString().getBytes();
832 public List
<String
> requiredLibraries() {
833 return requiredLibraries
;
836 public List
<String
> loadPaths() {
840 public boolean shouldRunInterpreter() {
841 if(isShowVersion() && (hasInlineScript
|| scriptFileName
!= null)) {
844 return isShouldRunInterpreter();
847 public boolean shouldPrintUsage() {
848 return shouldPrintUsage
;
851 public boolean shouldPrintProperties() {
852 return shouldPrintProperties
;
855 private boolean isSourceFromStdin() {
856 return getScriptFileName() == null;
859 public boolean isInlineScript() {
860 return hasInlineScript
;
863 public InputStream
getScriptSource() {
865 // KCode.NONE is used because KCODE does not affect parse in Ruby 1.8
866 // if Ruby 2.0 encoding pragmas are implemented, this will need to change
867 if (hasInlineScript
) {
868 return new ByteArrayInputStream(inlineScript());
869 } else if (isSourceFromStdin()) {
870 // can't use -v and stdin
871 if (isShowVersion()) {
876 File file
= JRubyFile
.create(getCurrentDirectory(), getScriptFileName());
877 return new FileInputStream(file
);
879 } catch (IOException e
) {
880 throw new MainExitException(1, "Error opening script file: " + e
.getMessage());
884 public String
displayedFileName() {
885 if (hasInlineScript
) {
886 if (scriptFileName
!= null) {
887 return scriptFileName
;
891 } else if (isSourceFromStdin()) {
894 return getScriptFileName();
898 private void setScriptFileName(String scriptFileName
) {
899 this.scriptFileName
= scriptFileName
;
902 public String
getScriptFileName() {
903 return scriptFileName
;
906 public boolean isBenchmarking() {
910 public boolean isAssumeLoop() {
914 public boolean isAssumePrinting() {
915 return assumePrinting
;
918 public boolean isProcessLineEnds() {
919 return processLineEnds
;
922 public boolean isSplit() {
926 public boolean isVerbose() {
927 return verbose
== Boolean
.TRUE
;
930 public Boolean
getVerbose() {
934 public boolean isDebug() {
938 public boolean isShowVersion() {
942 public boolean isShowCopyright() {
943 return showCopyright
;
946 protected void setShowVersion(boolean showVersion
) {
947 this.showVersion
= showVersion
;
950 protected void setShowCopyright(boolean showCopyright
) {
951 this.showCopyright
= showCopyright
;
954 public boolean isShouldRunInterpreter() {
955 return shouldRunInterpreter
;
958 public boolean isShouldCheckSyntax() {
959 return shouldCheckSyntax
;
962 public boolean isYARVEnabled() {
966 public String
getInputFieldSeparator() {
967 return inputFieldSeparator
;
970 public boolean isRubiniusEnabled() {
974 public boolean isYARVCompileEnabled() {
978 public KCode
getKCode() {
982 public String
getRecordSeparator() {
983 return recordSeparator
;
986 public int getSafeLevel() {
990 public void setRecordSeparator(String recordSeparator
) {
991 this.recordSeparator
= recordSeparator
;
994 public ClassCache
getClassCache() {
998 public void setClassCache(ClassCache classCache
) {
999 this.classCache
= classCache
;