Merge branch 'jruby-1_7'

* jruby-1_7: (54 commits)
  [travis-ci] re-try sudo: false
  dry out the two (Java helper) respond_to_p19 methods
  respondsTo JRuby API under 1.9.3 does not do respond_to_missing? like MRI does
  sleep should convert it's "time interval" argument the same way as MRI
  respond_to_missing? should always get a symbol name passed (fixes #2946)
  add a respond_to_missing unit test (on 1.9)
  introduce and use conversion( just like MRI does) on #timeout's sec argument
  add missing ' ' (space) in exception message ... TypeError from `sleep('invalid')`
  DateTime.iso8601 fails with an error if a second fraction is present
  [build] switch to 1.7.21-SNAPSHOT for test-jruby-jars
  refactor Timeout's scheduled tasks to an inner class (for easier identification)
  further hand drying of the Timeout module impl
  less (int) casting noiz
  add some (internal) generics for an improved readability xp
  inner class' Finalizer fields id and finalized can be final
  generix-ize the environment field (at least internally) + use a StringBuilder
  unnecessary (int) cast
  missing throw statement in RubyString's concat
  tune timeout to work when scheduling or argument convenrsion throws (see #2940)
  return empty Ruby array for empty dir list
  ...

Conflicts:
	.gitignore
	.travis.yml
	VERSION
	core/pom.xml
	core/src/main/java/org/jruby/RubyArray.java
	core/src/main/java/org/jruby/RubyBasicObject.java
	core/src/main/java/org/jruby/RubyDir.java
	core/src/main/java/org/jruby/RubyEnumerable.java
	core/src/main/java/org/jruby/RubyFile.java
	core/src/main/java/org/jruby/RubyGlobal.java
	core/src/main/java/org/jruby/RubyIO.java
	core/src/main/java/org/jruby/RubyKernel.java
	core/src/main/java/org/jruby/RubyModule.java
	core/src/main/java/org/jruby/RubyString.java
	core/src/main/java/org/jruby/RubyTime.java
	core/src/main/java/org/jruby/ext/timeout/Timeout.java
	core/src/main/java/org/jruby/java/proxies/JavaProxy.java
	core/src/main/java/org/jruby/util/Dir.java
	core/src/main/java/org/jruby/util/encoding/CharsetTranscoder.java
	docs/man/pom.xml
	docs/pom.xml
	ext/pom.xml
	ext/readline/pom.xml
	ext/ripper/pom.xml
	lib/pom.xml
	lib/ruby/1.9/date/format.rb
	lib/ruby/1.9/io/linux_console.rb
	lib/ruby/shared/gauntlet_rubygems.rb
	lib/ruby/shared/rubygems.rb
	lib/ruby/shared/rubygems/available_set.rb
	lib/ruby/shared/rubygems/basic_specification.rb
	lib/ruby/shared/rubygems/command.rb
	lib/ruby/shared/rubygems/command_manager.rb
	lib/ruby/shared/rubygems/commands/cert_command.rb
	lib/ruby/shared/rubygems/commands/cleanup_command.rb
	lib/ruby/shared/rubygems/commands/contents_command.rb
	lib/ruby/shared/rubygems/commands/dependency_command.rb
	lib/ruby/shared/rubygems/commands/environment_command.rb
	lib/ruby/shared/rubygems/commands/generate_index_command.rb
	lib/ruby/shared/rubygems/commands/help_command.rb
	lib/ruby/shared/rubygems/commands/install_command.rb
	lib/ruby/shared/rubygems/commands/list_command.rb
	lib/ruby/shared/rubygems/commands/mirror_command.rb
	lib/ruby/shared/rubygems/commands/outdated_command.rb
	lib/ruby/shared/rubygems/commands/owner_command.rb
	lib/ruby/shared/rubygems/commands/pristine_command.rb
	lib/ruby/shared/rubygems/commands/push_command.rb
	lib/ruby/shared/rubygems/commands/query_command.rb
	lib/ruby/shared/rubygems/commands/search_command.rb
	lib/ruby/shared/rubygems/commands/setup_command.rb
	lib/ruby/shared/rubygems/commands/specification_command.rb
	lib/ruby/shared/rubygems/commands/uninstall_command.rb
	lib/ruby/shared/rubygems/commands/unpack_command.rb
	lib/ruby/shared/rubygems/commands/update_command.rb
	lib/ruby/shared/rubygems/commands/which_command.rb
	lib/ruby/shared/rubygems/commands/yank_command.rb
	lib/ruby/shared/rubygems/compatibility.rb
	lib/ruby/shared/rubygems/config_file.rb
	lib/ruby/shared/rubygems/core_ext/kernel_gem.rb
	lib/ruby/shared/rubygems/core_ext/kernel_require.rb
	lib/ruby/shared/rubygems/defaults.rb
	lib/ruby/shared/rubygems/dependency.rb
	lib/ruby/shared/rubygems/dependency_installer.rb
	lib/ruby/shared/rubygems/dependency_list.rb
	lib/ruby/shared/rubygems/deprecate.rb
	lib/ruby/shared/rubygems/doctor.rb
	lib/ruby/shared/rubygems/errors.rb
	lib/ruby/shared/rubygems/exceptions.rb
	lib/ruby/shared/rubygems/ext.rb
	lib/ruby/shared/rubygems/ext/builder.rb
	lib/ruby/shared/rubygems/ext/cmake_builder.rb
	lib/ruby/shared/rubygems/ext/configure_builder.rb
	lib/ruby/shared/rubygems/ext/ext_conf_builder.rb
	lib/ruby/shared/rubygems/ext/rake_builder.rb
	lib/ruby/shared/rubygems/gemcutter_utilities.rb
	lib/ruby/shared/rubygems/indexer.rb
	lib/ruby/shared/rubygems/install_update_options.rb
	lib/ruby/shared/rubygems/installer.rb
	lib/ruby/shared/rubygems/installer_test_case.rb
	lib/ruby/shared/rubygems/local_remote_options.rb
	lib/ruby/shared/rubygems/name_tuple.rb
	lib/ruby/shared/rubygems/package.rb
	lib/ruby/shared/rubygems/package/old.rb
	lib/ruby/shared/rubygems/package/tar_header.rb
	lib/ruby/shared/rubygems/package/tar_reader/entry.rb
	lib/ruby/shared/rubygems/package/tar_writer.rb
	lib/ruby/shared/rubygems/path_support.rb
	lib/ruby/shared/rubygems/platform.rb
	lib/ruby/shared/rubygems/psych_additions.rb
	lib/ruby/shared/rubygems/rdoc.rb
	lib/ruby/shared/rubygems/remote_fetcher.rb
	lib/ruby/shared/rubygems/request.rb
	lib/ruby/shared/rubygems/request_set.rb
	lib/ruby/shared/rubygems/request_set/gem_dependency_api.rb
	lib/ruby/shared/rubygems/requirement.rb
	lib/ruby/shared/rubygems/resolver/current_set.rb
	lib/ruby/shared/rubygems/security.rb
	lib/ruby/shared/rubygems/security/policy.rb
	lib/ruby/shared/rubygems/security/signer.rb
	lib/ruby/shared/rubygems/security/trust_dir.rb
	lib/ruby/shared/rubygems/server.rb
	lib/ruby/shared/rubygems/source.rb
	lib/ruby/shared/rubygems/source/installed.rb
	lib/ruby/shared/rubygems/source/local.rb
	lib/ruby/shared/rubygems/source/specific_file.rb
	lib/ruby/shared/rubygems/source_list.rb
	lib/ruby/shared/rubygems/spec_fetcher.rb
	lib/ruby/shared/rubygems/specification.rb
	lib/ruby/shared/rubygems/ssl_certs/AddTrustExternalCARoot.pem
	lib/ruby/shared/rubygems/stub_specification.rb
	lib/ruby/shared/rubygems/syck_hack.rb
	lib/ruby/shared/rubygems/test_case.rb
	lib/ruby/shared/rubygems/test_utilities.rb
	lib/ruby/shared/rubygems/text.rb
	lib/ruby/shared/rubygems/uninstaller.rb
	lib/ruby/shared/rubygems/uri_formatter.rb
	lib/ruby/shared/rubygems/user_interaction.rb
	lib/ruby/shared/rubygems/util/list.rb
	lib/ruby/shared/rubygems/validator.rb
	lib/ruby/shared/rubygems/version.rb
	maven/jruby-complete/pom.xml
	maven/jruby-dist/pom.xml
	maven/jruby-jars/pom.xml
	maven/jruby-noasm/pom.xml
	maven/jruby-rake-plugin/pom.xml
	maven/jruby-stdlib/pom.xml
	maven/jruby/pom.xml
	maven/pom.xml
	pom.xml
	test/pom.xml
	test/test_dir.rb
	test/test_kernel.rb
	test/test_respond_to.rb
	test/test_timeout.rb
This commit is contained in:
kares 2015-05-25 16:54:09 +02:00
commit 40beb472cb
29 changed files with 1263 additions and 979 deletions

2
.gitignore vendored
View File

@ -48,7 +48,7 @@ lib/ruby/stdlib/jar*
lib/ruby/stdlib/jline
lib/ruby/stdlib/jopenssl*
lib/ruby/stdlib/krypt*
lib/ruby/stdlib/openssl
lib/ruby/stdlib/openssl*
lib/ruby/stdlib/org/
lib/ruby/stdlib/readline/*readline*.jar
lib/ruby/stdlib/ripper.jar

View File

@ -25,7 +25,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-1.7.20-SNAPSHOT.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-1.7.21-SNAPSHOT.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
@ -136,7 +136,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-1.7.20-SNAPSHOT.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-1.7.21-SNAPSHOT.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
@ -152,7 +152,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-1.7.20-SNAPSHOT.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-1.7.21-SNAPSHOT.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
@ -168,7 +168,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-1.7.20-SNAPSHOT.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-1.7.21-SNAPSHOT.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
@ -460,7 +460,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-1.7.20-SNAPSHOT.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-1.7.21-SNAPSHOT.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>

View File

@ -91,6 +91,7 @@
<groupId>com.github.jnr</groupId>
<artifactId>jnr-enxio</artifactId>
<version>0.9</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
@ -101,6 +102,7 @@
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
<version>0.8</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
@ -116,6 +118,7 @@
<groupId>com.github.jnr</groupId>
<artifactId>jnr-ffi</artifactId>
<version>2.0.3</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>

View File

@ -1288,7 +1288,7 @@ public final class Ruby implements Constantizable {
// attempt to enable unlimited-strength crypto on OpenJDK
try {
Class jceSecurity = Class.forName("javax.crypto.JceSecurity");
Field isRestricted = jceSecurity.getField("isRestricted");
Field isRestricted = jceSecurity.getDeclaredField("isRestricted");
isRestricted.setAccessible(true);
isRestricted.set(null, false);
isRestricted.setAccessible(false);

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,6 @@ package org.jruby;
import org.jcodings.Encoding;
import org.jruby.ir.interpreter.Interpreter;
import org.jruby.runtime.Arity;
import org.jruby.runtime.ivars.VariableAccessor;
import java.io.IOException;
import java.io.ObjectInputStream;
@ -59,6 +58,7 @@ import org.jruby.runtime.Visibility;
import static org.jruby.anno.FrameField.*;
import static org.jruby.runtime.Visibility.*;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Arity;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.builtin.InstanceVariables;
import org.jruby.runtime.builtin.InternalVariables;
@ -588,40 +588,43 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co
*/
@Override
public final boolean respondsTo(String name) {
Ruby runtime = getRuntime();
final Ruby runtime = getRuntime();
DynamicMethod respondTo = getMetaClass().searchMethod("respond_to?");
DynamicMethod respondToMissing = getMetaClass().searchMethod("respond_to_missing?");
final DynamicMethod respondTo = getMetaClass().searchMethod("respond_to?");
final DynamicMethod respondToMissing = getMetaClass().searchMethod("respond_to_missing?");
if(respondTo.equals(runtime.getRespondToMethod()) && respondToMissing.equals(runtime.getRespondToMissingMethod())) {
if ( respondTo.equals(runtime.getRespondToMethod()) &&
respondToMissing.equals(runtime.getRespondToMissingMethod()) ) {
// fastest path; builtin respond_to? which just does isMethodBound
return getMetaClass().isMethodBound(name, false);
} else if (!(respondTo.isUndefined() && respondToMissing.isUndefined())) {
// medium path, invoke user's respond_to?/respond_to_missing? if defined
DynamicMethod method;
String methodName;
if (respondTo.isUndefined()) {
method = respondToMissing;
methodName = "respond_to_missing?";
} else {
method = respondTo;
methodName = "respond_to?";
}
// We have to check and enforce arity
Arity arity = method.getArity();
ThreadContext context = runtime.getCurrentContext();
if (arity.isFixed() && arity.required() == 1) {
return method.call(context, this, metaClass, methodName, runtime.newSymbol(name)).isTrue();
} else if (arity.isFixed() && arity.required() != 2) {
throw runtime.newArgumentError(methodName + " must accept 1 or 2 arguments (requires " + arity.getValue() + ")");
}
return method.call(context, this, metaClass, methodName, runtime.newSymbol(name), runtime.newBoolean(true)).isTrue();
} else {
// slowest path, full callMethod to hit method_missing if present, or produce error
return callMethod(runtime.getCurrentContext(), "respond_to?", runtime.newSymbol(name)).isTrue();
}
final ThreadContext context = runtime.getCurrentContext();
final RubySymbol mname = runtime.newSymbol(name);
final boolean respondToUndefined = respondTo.isUndefined();
if ( ! ( respondToUndefined && respondToMissing.isUndefined() ) ) {
// medium path, invoke user's respond_to?/respond_to_missing? if defined
final DynamicMethod method; final String respondName;
if ( respondToUndefined ) {
method = respondToMissing; respondName = "respond_to_missing?";
} else {
method = respondTo; respondName = "respond_to?";
}
// We have to check and enforce arity
final Arity arity = method.getArity();
if ( arity.isFixed() ) {
if ( arity.required() == 1 ) {
return method.call(context, this, metaClass, respondName, mname).isTrue();
}
if ( arity.required() != 2 ) {
throw runtime.newArgumentError(respondName + " must accept 1 or 2 arguments (requires " + arity.getValue() + ")");
}
}
return method.call(context, this, metaClass, respondName, mname, runtime.getTrue()).isTrue();
}
// slowest path, full callMethod to hit method_missing if present, or produce error
return callMethod(context, "respond_to?", mname).isTrue();
}
/**
@ -636,20 +639,14 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co
* Does this object respond to the specified message via "method_missing?"
*/
@Override
public final boolean respondsToMissing(String name, boolean priv) {
public final boolean respondsToMissing(String name, boolean incPrivate) {
DynamicMethod method = getMetaClass().searchMethod("respond_to_missing?");
// perhaps should try a smart version as for respondsTo above?
if(method.isUndefined()) {
return false;
} else {
return method.call(
getRuntime().getCurrentContext(),
this,
metaClass,
"respond_to_missing?",
getRuntime().newSymbol(name),
getRuntime().newBoolean(priv)).isTrue();
}
if ( method.isUndefined() ) return false;
final Ruby runtime = getRuntime();
return method.call(runtime.getCurrentContext(), this, getMetaClass(),
"respond_to_missing?", runtime.newSymbol(name), runtime.newBoolean(incPrivate)
).isTrue();
}
/**
@ -1553,7 +1550,7 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co
public final int getNativeTypeIndex() {
return getNativeClassIndex().ordinal();
}
@Override
public ClassIndex getNativeClassIndex() {
return ClassIndex.BASICOBJECT;
@ -1877,10 +1874,10 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co
* operation.
*/
public static class Finalizer implements Finalizable {
private RubyFixnum id;
private final RubyFixnum id;
private final AtomicBoolean finalized;
private IRubyObject firstFinalizer;
private List<IRubyObject> finalizers;
private AtomicBoolean finalized;
public Finalizer(RubyFixnum id) {
this.id = id;
@ -1995,51 +1992,32 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co
* in both the compiler and the interpreter, the performance
* benefit is important for this method.
*/
public RubyBoolean respond_to_p(IRubyObject mname) {
String name = mname.asJavaString();
public final RubyBoolean respond_to_p(IRubyObject mname) {
final String name = mname.asJavaString();
return getRuntime().newBoolean(getMetaClass().isMethodBound(name, true));
}
public IRubyObject respond_to_p19(IRubyObject mname) {
String name = mname.asJavaString();
IRubyObject respond = getRuntime().newBoolean(getMetaClass().isMethodBound(name, true, true));
if (!respond.isTrue()) {
respond = Helpers.invoke(getRuntime().getCurrentContext(), this, "respond_to_missing?", mname, getRuntime().getFalse());
respond = getRuntime().newBoolean(respond.isTrue());
}
return respond;
public final RubyBoolean respond_to_p19(IRubyObject mname) {
return respond_to_p19(mname, false);
}
/** obj_respond_to
*
* respond_to?( aSymbol, includePriv=false ) -> true or false
*
* Returns true if this object responds to the given method. Private
* methods are included in the search only if the optional second
* parameter evaluates to true.
*
* @return true if this responds to the given method
*
* !!! For some reason MRI shows the arity of respond_to? as -1, when it should be -2; that's why this is rest instead of required, optional = 1
*
* Going back to splitting according to method arity. MRI is wrong
* about most of these anyway, and since we have arity splitting
* in both the compiler and the interpreter, the performance
* benefit is important for this method.
*/
public RubyBoolean respond_to_p(IRubyObject mname, IRubyObject includePrivate) {
public final RubyBoolean respond_to_p(IRubyObject mname, IRubyObject includePrivate) {
String name = mname.asJavaString();
return getRuntime().newBoolean(getMetaClass().isMethodBound(name, !includePrivate.isTrue()));
}
public IRubyObject respond_to_p19(IRubyObject mname, IRubyObject includePrivate) {
String name = mname.asJavaString();
IRubyObject respond = getRuntime().newBoolean(getMetaClass().isMethodBound(name, !includePrivate.isTrue()));
if (!respond.isTrue()) {
respond = Helpers.invoke(getRuntime().getCurrentContext(), this, "respond_to_missing?", mname, includePrivate);
respond = getRuntime().newBoolean(respond.isTrue());
}
return respond;
public final RubyBoolean respond_to_p19(IRubyObject mname, IRubyObject includePrivate) {
return respond_to_p19(mname, includePrivate.isTrue());
}
private RubyBoolean respond_to_p19(IRubyObject mname, final boolean includePrivate) {
final Ruby runtime = getRuntime();
final String name = mname.asJavaString();
if ( getMetaClass().isMethodBound(name, !includePrivate, true) ) return runtime.getTrue();
// MRI (1.9) always passes down a symbol when calling respond_to_missing?
if ( ! (mname instanceof RubySymbol) ) mname = runtime.newSymbol(name);
IRubyObject respond = Helpers.invoke(runtime.getCurrentContext(), this, "respond_to_missing?", mname, runtime.newBoolean(includePrivate));
return runtime.newBoolean( respond.isTrue() );
}
/** rb_obj_id

View File

@ -151,31 +151,30 @@ public class RubyDir extends RubyObject {
// ----- Ruby Class Methods ----------------------------------------------------
private static List<ByteList> dirGlobs(ThreadContext context, String cwd, IRubyObject[] args, int flags) {
List<ByteList> dirs = new ArrayList<ByteList>();
private static ArrayList<ByteList> dirGlobs(ThreadContext context, String cwd, IRubyObject[] args, int flags) {
ArrayList<ByteList> dirs = new ArrayList<ByteList>();
for (int i = 0; i < args.length; i++) {
for ( int i = 0; i < args.length; i++ ) {
dirs.addAll(Dir.push_glob(context.runtime, cwd, globArgumentAsByteList(context, args[i]), flags));
}
return dirs;
}
private static IRubyObject asRubyStringList(Ruby runtime, List<ByteList> dirs) {
List<RubyString> allFiles = new ArrayList<RubyString>();
private static RubyArray asRubyStringList(Ruby runtime, List<ByteList> dirs) {
final int size = dirs.size();
if ( size == 0 ) return RubyArray.newEmptyArray(runtime);
Encoding enc = runtime.getDefaultExternalEncoding();
if (enc == null) {
enc = UTF8;
}
for (ByteList dir : dirs) {
allFiles.add(RubyString.newString(runtime, dir, enc));
IRubyObject[] dirStrings = new IRubyObject[ size ];
for ( int i = 0; i < size; i++ ) {
dirStrings[i] = RubyString.newString(runtime, dirs.get(i), enc);
}
IRubyObject[] tempFileList = new IRubyObject[allFiles.size()];
allFiles.toArray(tempFileList);
return runtime.newArrayNoCopy(tempFileList);
return RubyArray.newArrayNoCopy(runtime, dirStrings);
}
private static String getCWD(Ruby runtime) {
@ -459,12 +458,12 @@ public class RubyDir extends RubyObject {
private static IRubyObject mkdirCommon(Ruby runtime, String path, IRubyObject[] args) {
File newDir = getDir(runtime, path, false);
String name = path.replace('\\', '/');
boolean startsWithDriveLetterOnWindows = RubyFile.startsWithDriveLetterOnWindows(name);
// don't attempt to create a dir for drive letters
if (startsWithDriveLetterOnWindows) {
// path is just drive letter plus :
@ -507,7 +506,7 @@ public class RubyDir extends RubyObject {
return block.yield(context, directory);
} finally {
directory.close();
}
}
}
// ----- Ruby Instance Methods -------------------------------------------------
@ -603,11 +602,11 @@ public class RubyDir extends RubyObject {
public IRubyObject path(ThreadContext context) {
return path == null ? context.runtime.getNil() : path.strDup(context.runtime);
}
@JRubyMethod
public IRubyObject to_path(ThreadContext context) {
return path(context);
}
}
/** Returns the next entry from this directory. */
@JRubyMethod(name = "read")
@ -636,7 +635,7 @@ public class RubyDir extends RubyObject {
// Capture previous exception if any.
IRubyObject exception = runtime.getGlobalVariables().get("$!");
RubyString path = StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, arg));
try {
return runtime.newFileStat(path.asJavaString(), false).directory_p();
} catch (Exception e) {

View File

@ -20,7 +20,7 @@
* Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
* Copyright (C) 2006 Evan Buswell <ebuswell@gmail.com>
* Copyright (C) 2007 Miguel Covarrubias <mlcovarrubias@gmail.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@ -105,7 +105,7 @@ import org.jruby.util.ShellLauncher.POpenProcess;
import org.jruby.util.io.IOEncodable;
/**
*
*
* @author jpetersen
*/
@JRubyClass(name="IO", include="Enumerable")
@ -120,37 +120,37 @@ public class RubyIO extends RubyObject implements IOEncodable {
public RubyIO(Ruby runtime, RubyClass type) {
super(runtime, type);
}
public RubyIO(Ruby runtime, OutputStream outputStream) {
this(runtime, outputStream, true);
}
public RubyIO(Ruby runtime, OutputStream outputStream, boolean autoclose) {
super(runtime, runtime.getIO());
// We only want IO objects with valid streams (better to error now).
// We only want IO objects with valid streams (better to error now).
if (outputStream == null) {
throw runtime.newRuntimeError("Opening null stream");
}
openFile = MakeOpenFile();
openFile.setFD(new ChannelFD(Channels.newChannel(outputStream), runtime.getPosix(), runtime.getFilenoUtil()));
openFile.setMode(OpenFile.WRITABLE | OpenFile.APPEND);
openFile.setAutoclose(autoclose);
}
public RubyIO(Ruby runtime, InputStream inputStream) {
super(runtime, runtime.getIO());
if (inputStream == null) {
throw runtime.newRuntimeError("Opening null stream");
}
openFile = MakeOpenFile();
openFile.setFD(new ChannelFD(Channels.newChannel(inputStream), runtime.getPosix(), runtime.getFilenoUtil()));
openFile.setMode(OpenFile.READABLE);
}
public RubyIO(Ruby runtime, Channel channel) {
this(runtime, runtime.getIO(), channel);
}
@ -261,20 +261,20 @@ public class RubyIO extends RubyObject implements IOEncodable {
return io;
}
public static RubyIO newIO(Ruby runtime, Channel channel) {
return new RubyIO(runtime, channel);
}
public OpenFile getOpenFile() {
return openFile;
}
public OpenFile getOpenFileChecked() {
openFile.checkClosed();
return openFile;
}
private static ObjectAllocator IO_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
@ -299,7 +299,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
ioClass.kindOf = new RubyModule.JavaClassKindOf(RubyIO.class);
ioClass.includeModule(runtime.getEnumerable());
ioClass.defineAnnotatedMethods(RubyIO.class);
// Constants for seek
@ -680,7 +680,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
private IRubyObject getline(ThreadContext context, IRubyObject separator, long limit, ByteListCache cache) {
return getlineInner(context, separator, (int)limit, cache);
}
/**
* getline using logic of gets. If limit is -1 then read unlimited amount.
* mri: rb_io_getline_1 (mostly)
@ -690,7 +690,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
IRubyObject str = context.nil;
boolean noLimit = false;
Encoding enc;
OpenFile fptr = getOpenFileChecked();
boolean locked = fptr.lock();
@ -821,17 +821,17 @@ public class RubyIO extends RubyObject implements IOEncodable {
public Encoding getEnc() {
return openFile.encs.enc;
}
// mri: io_read_encoding
public Encoding getReadEncoding() {
return openFile.readEncoding(getRuntime());
}
// fptr->enc2 and codeconv->enc2
public Encoding getEnc2() {
return openFile.encs.enc2;
}
// mri: io_input_encoding
public Encoding getInputEncoding() {
return openFile.inputEncoding(getRuntime());
@ -851,14 +851,14 @@ public class RubyIO extends RubyObject implements IOEncodable {
@JRubyMethod(name = "new", rest = true, meta = true)
public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
RubyClass klass = (RubyClass)recv;
if (block.isGiven()) {
String className = klass.getName();
context.runtime.getWarnings().warn(
ID.BLOCK_NOT_ACCEPTED,
className + "::new() does not take block; use " + className + "::open() instead");
}
return klass.newInstance(context, args, block);
}
@ -966,7 +966,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
public IRubyObject initialize(ThreadContext context, IRubyObject fileNumber, Block unused) {
return initializeCommon(context, RubyNumeric.fix2int(fileNumber), null, context.nil);
}
@JRubyMethod(name = "initialize", visibility = PRIVATE)
public IRubyObject initialize(ThreadContext context, IRubyObject fileNumber, IRubyObject second, Block unused) {
int fileno = RubyNumeric.fix2int(fileNumber);
@ -1007,20 +1007,20 @@ public class RubyIO extends RubyObject implements IOEncodable {
@JRubyMethod
public IRubyObject external_encoding(ThreadContext context) {
EncodingService encodingService = context.runtime.getEncodingService();
if (openFile.encs.enc2 != null) return encodingService.getEncoding(openFile.encs.enc2);
if (openFile.isWritable()) {
return openFile.encs.enc == null ? context.runtime.getNil() : encodingService.getEncoding(openFile.encs.enc);
}
return encodingService.getEncoding(getReadEncoding());
}
@JRubyMethod
public IRubyObject internal_encoding(ThreadContext context) {
if (openFile.encs.enc2 == null) return context.nil;
return context.runtime.getEncodingService().getEncoding(getReadEncoding());
}
@ -1049,21 +1049,21 @@ public class RubyIO extends RubyObject implements IOEncodable {
return context.nil;
}
// mri: io_encoding_set
public void setEncoding(ThreadContext context, IRubyObject v1, IRubyObject v2, IRubyObject opt) {
IOEncodable.ConvConfig holder = new IOEncodable.ConvConfig();
int ecflags = openFile.encs.ecflags;
IRubyObject[] ecopts_p = {context.nil};
IRubyObject tmp;
if (!v2.isNil()) {
holder.enc2 = EncodingUtils.rbToEncoding(context, v1);
tmp = v2.checkStringType19();
if (!tmp.isNil()) {
RubyString internalAsString = (RubyString)tmp;
// No encoding '-'
if (internalAsString.size() == 1 && internalAsString.asJavaString().equals("-")) {
/* Special case - "-" => no transcoding */
@ -1072,14 +1072,14 @@ public class RubyIO extends RubyObject implements IOEncodable {
} else {
holder.enc = EncodingUtils.rbToEncoding(context, internalAsString);
}
if (holder.enc == holder.enc2) {
/* Special case - "-" => no transcoding */
holder.enc2 = null;
}
} else {
holder.enc = EncodingUtils.rbToEncoding(context, v2);
if (holder.enc == holder.enc2) {
/* Special case - "-" => no transcoding */
holder.enc2 = null;
@ -1402,9 +1402,9 @@ public class RubyIO extends RubyObject implements IOEncodable {
throw getRuntime().newIOError("uninitialized stream");
}
}
/** io_write_m
*
*
*/
@JRubyMethod(name = "write", required = 1)
public IRubyObject write(ThreadContext context, IRubyObject str) {
@ -1446,13 +1446,13 @@ public class RubyIO extends RubyObject implements IOEncodable {
}
/** rb_io_addstr
*
*
*/
@JRubyMethod(name = "<<", required = 1)
public IRubyObject op_append(ThreadContext context, IRubyObject anObject) {
// Claims conversion is done via 'to_s' in docs.
callMethod(context, "write", anObject);
return this;
}
@ -1460,9 +1460,9 @@ public class RubyIO extends RubyObject implements IOEncodable {
public RubyFixnum fileno(ThreadContext context) {
return context.runtime.newFixnum(getOpenFileChecked().getFileno());
}
/** Returns the current line number.
*
*
* @return the current line number.
*/
@JRubyMethod(name = "lineno")
@ -1471,7 +1471,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
}
/** Sets the current line number.
*
*
* @param newLineNumber The new line number.
*/
@JRubyMethod(name = "lineno=", required = 1)
@ -1484,7 +1484,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
/** Returns the current sync mode.
*
* MRI: rb_io_sync
*
*
* @return the current sync mode.
*/
@JRubyMethod
@ -1501,23 +1501,23 @@ public class RubyIO extends RubyObject implements IOEncodable {
fptr.unlock();
}
}
/**
* <p>Return the process id (pid) of the process this IO object
* spawned. If no process exists (popen was not called), then
* nil is returned. This is not how it appears to be defined
* but ruby 1.8 works this way.</p>
*
*
* @return the pid or nil
*/
@JRubyMethod
public IRubyObject pid(ThreadContext context) {
OpenFile myOpenFile = getOpenFileChecked();
if (myOpenFile.getProcess() == null) {
return context.runtime.getNil();
}
// Of course this isn't particularly useful.
long pid = myOpenFile.getPid();
@ -1559,9 +1559,9 @@ public class RubyIO extends RubyObject implements IOEncodable {
return context.runtime.newFixnum(pos);
}
/** Print some objects to the stream.
*
*
*/
@JRubyMethod(rest = true, reads = FrameField.LASTLINE)
public IRubyObject print(ThreadContext context, IRubyObject[] args) {
@ -1634,25 +1634,25 @@ public class RubyIO extends RubyObject implements IOEncodable {
public RubyFixnum seek(ThreadContext context, IRubyObject[] args) {
int whence = PosixShim.SEEK_SET;
if (args.length > 1) {
whence = interpretSeekWhence(args[1]);
}
return doSeek(context, args[0], whence);
}
@JRubyMethod
public RubyFixnum seek(ThreadContext context, IRubyObject arg0) {
int whence = PosixShim.SEEK_SET;
return doSeek(context, arg0, whence);
}
@JRubyMethod
public RubyFixnum seek(ThreadContext context, IRubyObject arg0, IRubyObject arg1) {
int whence = interpretSeekWhence(arg1);
return doSeek(context, arg0, whence);
}
@ -1674,7 +1674,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
return RubyFixnum.zero(context.runtime);
}
// This was a getOpt with one mandatory arg, but it did not work
// so I am parsing it for now.
@JRubyMethod(required = 1, optional = 1)
@ -1774,7 +1774,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
/** Sets the current sync mode.
*
* MRI: rb_io_set_sync
*
*
* @param sync The new sync mode.
*/
@JRubyMethod(name = "sync=", required = 1)
@ -1909,7 +1909,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
return dest;
}
@JRubyMethod(name = "closed?")
public RubyBoolean closed_p(ThreadContext context) {
return context.runtime.newBoolean(isClosed());
@ -1919,7 +1919,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
* Is this IO closed
*
* MRI: rb_io_closed
*
*
* @return true if closed
*/
public boolean isClosed() {
@ -1940,10 +1940,10 @@ public class RubyIO extends RubyObject implements IOEncodable {
return fptr.fd() != null ? false : true;
}
/**
/**
* <p>Closes all open resources for the IO. It also removes
* it from our magical all open file descriptor pool.</p>
*
*
* @return The IO.
*
* MRI: rb_io_close_m
@ -1974,8 +1974,8 @@ public class RubyIO extends RubyObject implements IOEncodable {
}
}
}
// rb_io_close
// rb_io_close
protected IRubyObject rbIoClose(Ruby runtime) {
ThreadContext context = runtime.getCurrentContext();
OpenFile fptr;
@ -2193,7 +2193,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
}
/** Read a line.
*
*
*/
// rb_io_gets_m
@ -2351,7 +2351,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
public IRubyObject ioctl(ThreadContext context, IRubyObject[] args) {
IRubyObject cmd = args[0];
IRubyObject arg;
if (args.length == 2) {
arg = args[1];
} else {
@ -2369,8 +2369,8 @@ public class RubyIO extends RubyObject implements IOEncodable {
OpenFile myOpenFile = getOpenFileChecked();
return runtime.newFixnum(OpenFile.ioFmodeOflags(myOpenFile.getMode()));
}
// FIXME: Arg may also be true, false, and nil and still be valid. Strangely enough,
// FIXME: Arg may also be true, false, and nil and still be valid. Strangely enough,
// protocol conversion is not happening in Ruby on this arg?
if (arg == null || arg.isNil() || arg == runtime.getFalse()) {
nArg = 0;
@ -2381,7 +2381,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
} else {
throw runtime.newNotImplementedError("JRuby does not support string for second fcntl/ioctl argument yet");
}
OpenFile fptr = getOpenFileChecked();
// Fixme: Only F_SETFL and F_GETFL is current supported
@ -2407,7 +2407,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
} else {
throw runtime.newNotImplementedError("JRuby only supports F_SETFL and F_GETFL with NONBLOCK for fcntl/ioctl");
}
return runtime.newFixnum(0);
}
@ -2547,17 +2547,17 @@ public class RubyIO extends RubyObject implements IOEncodable {
public static IRubyObject write(ThreadContext context, IRubyObject maybeIO, IRubyObject str) {
return maybeIO.callMethod(context, "write", str);
}
@Override
public IRubyObject inspect() {
Ruby runtime = getRuntime();
if (openFile == null) return super.inspect();
String className = getMetaClass().getRealClass().getName();
String path = openFile.getPath();
String status = "";
if (path == null) {
if (openFile.fd() == null) {
path = "";
@ -2568,14 +2568,14 @@ public class RubyIO extends RubyObject implements IOEncodable {
} else if (!openFile.isOpen()) {
status = " (closed)";
}
String inspectStr = "#<" + className + ":" + path + status + ">";
return runtime.newString(inspectStr);
}
/** Read a line.
*
*
*/
@JRubyMethod(name = "readline", writes = FrameField.LASTLINE)
public IRubyObject readline(ThreadContext context) {
@ -2584,7 +2584,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
if (line.isNil()) {
throw context.runtime.newEOFError();
}
return line;
}
@ -2600,7 +2600,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
}
/** Read a byte. On EOF returns nil.
*
*
*/
public IRubyObject getc() {
return getbyte(getRuntime().getCurrentContext());
@ -2610,7 +2610,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
@JRubyMethod
public IRubyObject readchar(ThreadContext context) {
IRubyObject c = getc19(context);
if (c.isNil()) {
throw context.runtime.newEOFError();
}
@ -2950,7 +2950,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
// io_read
public IRubyObject read(IRubyObject[] args) {
ThreadContext context = getRuntime().getCurrentContext();
switch (args.length) {
case 0: return read(context);
case 1: return read(context, args[0]);
@ -2977,7 +2977,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
Ruby runtime = context.runtime;
OpenFile fptr;
int n, len;
if (length.isNil()) {
fptr = getOpenFileChecked();
@ -2989,7 +2989,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
if (locked) fptr.unlock();
}
}
len = RubyNumeric.num2int(length);
if (len < 0) {
throw runtime.newArgumentError("negative length " + len + " given");
@ -3027,14 +3027,14 @@ public class RubyIO extends RubyObject implements IOEncodable {
return str;
}
/** Read a byte. On EOF throw EOFError.
*
*
*/
public IRubyObject readchar() {
return readchar(getRuntime().getCurrentContext());
}
@JRubyMethod
public IRubyObject stat(ThreadContext context) {
Ruby runtime = context.runtime;
@ -3055,7 +3055,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
}
}
/**
/**
* <p>Invoke a block for each byte.</p>
*
* MRI: rb_io_each_byte
@ -3221,7 +3221,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
return this;
}
/**
/**
* <p>Invoke a block for each line.</p>
*
* MRI: rb_io_each_line
@ -3237,7 +3237,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
line = getline(context, separator, -1, cache)) {
block.yield(context, line);
}
return this;
}
@ -3264,7 +3264,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
private RubyArray readlinesCommon(ThreadContext context, IRubyObject[] args) {
Ruby runtime = context.runtime;
long limit = prepareGetsLimit(context, args);
IRubyObject separator = prepareGetsSeparator(context, args);
RubyArray result = runtime.newArray();
@ -3285,13 +3285,13 @@ public class RubyIO extends RubyObject implements IOEncodable {
public String toString() {
return inspect().toString();
}
/* class methods for IO */
// rb_io_s_foreach
private static IRubyObject foreachInternal19(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
Ruby runtime = context.runtime;
IRubyObject opt = ArgsUtil.getOptionsArg(context.runtime, args);
IRubyObject io = openKeyArgs(context, recv, args, opt);
if (io.isNil()) return io;
@ -3323,7 +3323,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
public static RubyIO convertToIO(ThreadContext context, IRubyObject obj) {
return (RubyIO)TypeConverter.ioGetIO(context.runtime, obj);
}
@JRubyMethod(name = "select", required = 1, optional = 3, meta = true)
public static IRubyObject select(ThreadContext context, IRubyObject recv, IRubyObject[] argv) {
IRubyObject read, write, except, _timeout;
@ -3411,7 +3411,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
// ok
}
}
public static IRubyObject read(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
return read19(context, recv, args, Block.NULL_BLOCK);
}
@ -3430,40 +3430,40 @@ public class RubyIO extends RubyObject implements IOEncodable {
private static IRubyObject openKeyArgs(ThreadContext context, IRubyObject recv, IRubyObject[] argv, IRubyObject opt) {
Ruby runtime = context.runtime;
IRubyObject path, v;
path = StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, argv[0]));
failIfDirectory(runtime, (RubyString) path); // only in JRuby
// MRI increments args past 0 now, so remaining uses of args only see non-path args
if (opt.isNil()) {
return ioOpen(context, path, runtime.newFixnum(ModeFlags.RDONLY), runtime.newFixnum(0666), opt);
}
v = ((RubyHash)opt).op_aref(context, runtime.newSymbol("open_args"));
if (!v.isNil()) {
IRubyObject args;
int n;
v = v.convertToArray();
n = ((RubyArray)v).size() + 1;
args = runtime.newArray(n);
((RubyArray)args).push_m19(new IRubyObject[]{path});
((RubyArray)args).concat19(v);
return RubyKernel.open19(context, recv, ((RubyArray)args).toJavaArray(), Block.NULL_BLOCK);
}
return ioOpen(context, path, context.nil, context.nil, opt);
}
// rb_io_open
public static IRubyObject ioOpen(ThreadContext context, IRubyObject filename, IRubyObject vmode, IRubyObject vperm, IRubyObject opt) {
Ruby runtime = context.runtime;
int[] oflags_p = {0}, fmode_p = {0};
int perm;
IRubyObject cmd;
if ((filename instanceof RubyString) && ((RubyString) filename).isEmpty()) {
throw context.getRuntime().newErrnoENOENTError();
}
@ -3506,7 +3506,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
file = (RubyIO) Helpers.invoke(context, runtime.getFile(), "new", path, RubyFixnum.newFixnum(runtime, mode));
} else if (!options.containsKey(runtime.newSymbol("mode"))) {
mode |= ModeFlags.WRONLY;
file = (RubyIO) Helpers.invoke(context, runtime.getFile(), "new", path, RubyFixnum.newFixnum(runtime, mode), options);
file = (RubyIO) Helpers.invoke(context, runtime.getFile(), "new", path, RubyFixnum.newFixnum(runtime, mode), options);
} else {
file = (RubyIO) Helpers.invoke(context, runtime.getFile(), "new", path, options);
}
@ -3686,7 +3686,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
IRubyObject opt = ArgsUtil.getOptionsArg(context.runtime, args);
IRubyObject io = openKeyArgs(context, recv, args, opt);
if (io.isNil()) return io;
IRubyObject[] methodArguments = processReadlinesMethodArguments(args);
return readlinesCommon19(context, (RubyIO)io, methodArguments);
@ -3695,18 +3695,18 @@ public class RubyIO extends RubyObject implements IOEncodable {
private static IRubyObject[] processReadlinesMethodArguments(IRubyObject[] args) {
int count = args.length;
IRubyObject[] methodArguments = IRubyObject.NULL_ARRAY;
if(count >= 3 && (args[2] instanceof RubyFixnum || args[2].respondsTo("to_int"))) {
methodArguments = new IRubyObject[]{args[1], args[2]};
methodArguments = new IRubyObject[]{args[1], args[2]};
} else if (count >= 2 && (args[1] instanceof RubyFixnum || args[1].respondsTo("to_int"))) {
methodArguments = new IRubyObject[]{args[1]};
methodArguments = new IRubyObject[]{args[1]};
} else if (count >= 2 && !(args[1] instanceof RubyHash)) {
methodArguments = new IRubyObject[]{args[1]};
methodArguments = new IRubyObject[]{args[1]};
}
return methodArguments;
}
private static RubyArray readlinesCommon19(ThreadContext context, RubyIO file, IRubyObject[] newArguments) {
try {
return file.readlines(context, newArguments);
@ -3759,7 +3759,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
public final RubyString cmd;
public final IRubyObject[] cmdPlusArgs;
public final RubyHash env;
public Ruby19POpen(Ruby runtime, IRubyObject[] args) {
IRubyObject[] _cmdPlusArgs = null;
IRubyObject _env = null;
@ -3782,7 +3782,8 @@ public class RubyIO extends RubyObject implements IOEncodable {
if ((arg0 = TypeConverter.checkStringType(runtime, args[firstArg])).isNil()) {
throw runtime.newTypeError(args[firstArg], runtime.getString());
}
_cmdPlusArgs = new IRubyObject[]{arg0};
_cmdPlusArgs = null;
_cmd = arg0;
} else {
RubyArray arg0Ary = (RubyArray) arg0;
if (arg0Ary.isEmpty()) throw runtime.newArgumentError("wrong number of arguments");
@ -3796,15 +3797,17 @@ public class RubyIO extends RubyObject implements IOEncodable {
_env = arg0Ary.eltOk(arg0Ary.size() - 1);
}
_cmdPlusArgs = arg0Ary.toJavaArray();
_cmd = _cmdPlusArgs[0];
}
if (Platform.IS_WINDOWS) {
String commandString = _cmdPlusArgs[0].convertToString().toString().replace('/', '\\');
_cmdPlusArgs[0] = runtime.newString(commandString);
String commandString = _cmd.convertToString().toString().replace('/', '\\');
_cmd = runtime.newString(commandString);
if (_cmdPlusArgs != null) _cmdPlusArgs[0] = _cmd;
} else {
_cmdPlusArgs[0] = _cmdPlusArgs[0].convertToString();
_cmd = _cmd.convertToString();
if (_cmdPlusArgs != null) _cmdPlusArgs[0] = _cmd;
}
_cmd = _cmdPlusArgs[0];
this.cmd = (RubyString)_cmd;
this.cmdPlusArgs = _cmdPlusArgs;
@ -3842,16 +3845,16 @@ public class RubyIO extends RubyObject implements IOEncodable {
if (argc > 1) {
pmode = args[firstArg + 1];
}
RubyIO io = new RubyIO(runtime, (RubyClass) recv);
io.MakeOpenFile();
Object pm = vmodeVperm(pmode, runtime.newFixnum(0));
int[] oflags_p = {0}, fmode_p = {0};
EncodingUtils.extractModeEncoding(context, io, pm, options, oflags_p, fmode_p);
ModeFlags modes = ModeFlags.createModeFlags(oflags_p[0]);
// FIXME: Reprocessing logic twice for now...
// for 1.9 mode, strip off the trailing options hash, if there
if (args.length > 1 && args[args.length - 1] instanceof RubyHash) {
@ -3860,9 +3863,9 @@ public class RubyIO extends RubyObject implements IOEncodable {
System.arraycopy(args, 0, newArgs, 0, args.length - 1);
args = newArgs;
}
Ruby19POpen r19Popen = new Ruby19POpen(runtime, args);
if ("-".equals(r19Popen.cmd.toString())) {
throw runtime.newNotImplementedError("popen(\"-\") is unimplemented");
}
@ -4205,7 +4208,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
if (n == 0) {
break;
}
position += n;
remaining -= n;
transferred += n;
@ -4263,26 +4266,26 @@ public class RubyIO extends RubyObject implements IOEncodable {
private static ByteList getNilByteList(Ruby runtime) {
return ByteList.EMPTY_BYTELIST;
}
/**
* Add a thread to the list of blocking threads for this IO.
*
*
* @param thread A thread blocking on this IO
*/
public void addBlockingThread(RubyThread thread) {
OpenFile fptr = openFile;
if (openFile != null) openFile.addBlockingThread(thread);
}
/**
* Remove a thread from the list of blocking threads for this IO.
*
*
* @param thread A thread blocking on this IO
*/
public void removeBlockingThread(RubyThread thread) {
if (openFile != null) openFile.removeBlockingThread(thread);
}
/**
* Fire an IOError in all threads blocking on this IO object
*/
@ -4347,19 +4350,19 @@ public class RubyIO extends RubyObject implements IOEncodable {
ioOptions = newIOOptions(runtime, ioOptions, ModeFlags.TEXT);
}
// TODO: Waaaay different than MRI. They uniformly have all opening logic
// do a scan of args before anything opens. We do this logic in a less
// consistent way. We should consider re-impling all IO/File construction
// logic.
if (options.containsKey(runtime.newSymbol("open_args"))) {
IRubyObject args = options.fastARef(runtime.newSymbol("open_args"));
RubyArray openArgs = args.convertToArray();
for (int i = 0; i < openArgs.size(); i++) {
IRubyObject arg = openArgs.eltInternal(i);
if (arg instanceof RubyString) { // Overrides all?
ioOptions = newIOOptions(runtime, arg.asJavaString());
} else if (arg instanceof RubyFixnum) {
@ -4472,7 +4475,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
public static RubyArray checkExecEnv(ThreadContext context, RubyHash hash) {
return PopenExecutor.checkExecEnv(context, hash);
}
/**
* Try for around 1s to destroy the child process. This is to work around
* issues on some JVMs where if you try to destroy the process too quickly
@ -4497,7 +4500,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
// attempt to destroy (SIGTERM on UNIX, TerminateProcess on Windows)
process.destroy();
try {
// get the exit value; succeeds if it has terminated, throws
// IllegalThreadStateException if not.
@ -4532,7 +4535,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
return new ModeFlags(mode);
} catch (InvalidValueException ive) {
// This is used by File and StringIO, which seem to want an ArgumentError instead of EINVAL
throw runtime.newArgumentError("illegal access mode " + mode);
throw runtime.newArgumentError("illegal access mode " + mode);
}
}
@ -4579,37 +4582,37 @@ public class RubyIO extends RubyObject implements IOEncodable {
public void setEnc2(Encoding enc2) {
openFile.encs.enc2 = enc2;
}
@Override
public void setEnc(Encoding enc) {
openFile.encs.enc = enc;
}
@Override
public void setEcflags(int ecflags) {
openFile.encs.ecflags = ecflags;
}
@Override
public int getEcflags() {
return openFile.encs.ecflags;
}
@Override
public void setEcopts(IRubyObject ecopts) {
openFile.encs.ecopts = ecopts;
}
@Override
public IRubyObject getEcopts() {
return openFile.encs.ecopts;
}
@Override
public void setBOM(boolean bom) {
openFile.setBOM(bom);
}
@Override
public boolean getBOM() {
return openFile.isBOM();
@ -4625,7 +4628,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
return this;
}
public OpenFile MakeOpenFile() {
Ruby runtime = getRuntime();
if (openFile != null) {
@ -4660,7 +4663,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
public IRubyObject getline(Ruby runtime, ByteList separator) {
return getline(runtime.getCurrentContext(), runtime.newString(separator), -1, null);
}
@Deprecated
public IRubyObject getline(Ruby runtime, ByteList separator, long limit) {
return getline(runtime.getCurrentContext(), runtime.newString(separator), limit, null);
@ -4940,7 +4943,7 @@ public class RubyIO extends RubyObject implements IOEncodable {
public static IRubyObject select_static(ThreadContext context, Ruby runtime, IRubyObject[] args) {
return select(context, runtime.getIO(), args);
}
protected OpenFile openFile;
/**

View File

@ -116,7 +116,7 @@ public class RubyInstanceConfig {
try {
environment = System.getenv();
} catch (SecurityException se) {
environment = new HashMap();
environment = new HashMap<String,String>();
}
}
@ -387,8 +387,8 @@ public class RubyInstanceConfig {
}
return getInput();
} else {
String script = getScriptFileName();
InputStream stream = null;
final String script = getScriptFileName();
final InputStream stream;
if (script.startsWith("file:") && script.indexOf(".jar!/") != -1) {
stream = new URL("jar:" + script).openStream();
} else if (script.startsWith("classpath:")) {
@ -424,7 +424,7 @@ public class RubyInstanceConfig {
}
private static InputStream findScript(File file) throws IOException {
StringBuffer buf = new StringBuffer();
StringBuilder buf = new StringBuilder();
BufferedReader br = new BufferedReader(new FileReader(file));
String currentLine = br.readLine();
while (currentLine != null && !isRubyShebangLine(currentLine)) {
@ -437,8 +437,8 @@ public class RubyInstanceConfig {
do {
currentLine = br.readLine();
if (currentLine != null) {
buf.append(currentLine);
buf.append("\n");
buf.append(currentLine);
buf.append("\n");
}
} while (!(currentLine == null || currentLine.contains("__END__") || currentLine.contains("\026")));
return new BufferedInputStream(new ByteArrayInputStream(buf.toString().getBytes()), 8192);
@ -691,8 +691,10 @@ public class RubyInstanceConfig {
}
public void setEnvironment(Map newEnvironment) {
if (newEnvironment == null) newEnvironment = new HashMap();
environment = newEnvironment;
if (newEnvironment == null) {
newEnvironment = new HashMap<String, String>();
}
this.environment = newEnvironment;
}
public Map getEnvironment() {
@ -1448,7 +1450,7 @@ public class RubyInstanceConfig {
private String currentDirectory;
/** Environment variables; defaults to System.getenv() in constructor */
private Map environment;
private Map<String, String> environment;
private String[] argv = {};
private final boolean jitLogging;

View File

@ -19,7 +19,7 @@
* Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
* Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
* Copyright (C) 2005 Charles O Nutter <headius@headius.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@ -62,7 +62,7 @@ import static org.jruby.RubyEnumerator.SizeFn;
* @author jpetersen
*/
@JRubyClass(name="Integer", parent="Numeric", include="Precision")
public abstract class RubyInteger extends RubyNumeric {
public abstract class RubyInteger extends RubyNumeric {
public static RubyClass createIntegerClass(Ruby runtime) {
RubyClass integer = runtime.defineClass("Integer", runtime.getNumeric(),
@ -71,13 +71,13 @@ public abstract class RubyInteger extends RubyNumeric {
integer.setClassIndex(ClassIndex.INTEGER);
integer.setReifiedClass(RubyInteger.class);
integer.kindOf = new RubyModule.JavaClassKindOf(RubyInteger.class);
integer.getSingletonClass().undefineMethod("new");
integer.defineAnnotatedMethods(RubyInteger.class);
return integer;
}
@ -88,15 +88,15 @@ public abstract class RubyInteger extends RubyNumeric {
public RubyInteger(RubyClass rubyClass) {
super(rubyClass);
}
public RubyInteger(Ruby runtime, RubyClass rubyClass, boolean useObjectSpace) {
super(runtime, rubyClass, useObjectSpace);
}
}
@Deprecated
public RubyInteger(Ruby runtime, RubyClass rubyClass, boolean useObjectSpace, boolean canBeTainted) {
super(runtime, rubyClass, useObjectSpace, canBeTainted);
}
}
@Override
public RubyInteger convertToInteger() {
@ -110,11 +110,11 @@ public abstract class RubyInteger extends RubyNumeric {
/* ================
* Instance Methods
* ================
* ================
*/
/** int_int_p
*
*
*/
@Override
@JRubyMethod(name = "integer?")
@ -123,7 +123,7 @@ public abstract class RubyInteger extends RubyNumeric {
}
/** int_upto
*
*
*/
@JRubyMethod
public IRubyObject upto(ThreadContext context, IRubyObject to, Block block) {
@ -185,7 +185,7 @@ public abstract class RubyInteger extends RubyNumeric {
}
/** int_downto
*
*
*/
// TODO: Make callCoerced work in block context...then fix downto, step, and upto.
@JRubyMethod
@ -283,7 +283,7 @@ public abstract class RubyInteger extends RubyNumeric {
}
/** int_succ
*
*
*/
@JRubyMethod(name = {"succ", "next"})
public IRubyObject succ(ThreadContext context) {
@ -312,7 +312,7 @@ public abstract class RubyInteger extends RubyNumeric {
}
/** int_chr
*
*
*/
public RubyString chr(ThreadContext context) {
return chr19(context);
@ -331,7 +331,7 @@ public abstract class RubyInteger extends RubyNumeric {
throw runtime.newRangeError(this.toString() + " out of char range");
} else {
if (enc == null) enc = USASCIIEncoding.INSTANCE;
return RubyString.newStringNoCopy(runtime, fromEncodedBytes(runtime, enc, (int)value), enc, 0);
return RubyString.newStringNoCopy(runtime, fromEncodedBytes(runtime, enc, value), enc, 0);
}
}
}
@ -361,7 +361,7 @@ public abstract class RubyInteger extends RubyNumeric {
}
if (n <= 0) throw runtime.newRangeError(this.toString() + " out of char range");
ByteList bytes = new ByteList(n);
boolean ok = false;
@ -381,7 +381,7 @@ public abstract class RubyInteger extends RubyNumeric {
}
/** int_ord
*
*
*/
@JRubyMethod(name = "ord")
public IRubyObject ord(ThreadContext context) {
@ -389,7 +389,7 @@ public abstract class RubyInteger extends RubyNumeric {
}
/** int_to_i
*
*
*/
@JRubyMethod(name = {"to_i", "to_int", "floor", "ceil", "truncate"})
public IRubyObject to_i() {
@ -412,14 +412,14 @@ public abstract class RubyInteger extends RubyNumeric {
if (ndigits > 0) return RubyKernel.new_float(this, this);
if (ndigits == 0) return this;
Ruby runtime = context.runtime;
long bytes = (this instanceof RubyFixnum) ? 8 : RubyFixnum.fix2long(callMethod("size"));
/* If 10**N/2 > this, return 0 */
/* We have log_256(10) > 0.415241 and log_256(1/2)=-0.125 */
if (-0.415241 * ndigits - 0.125 > bytes) {
return RubyFixnum.zero(runtime);
}
IRubyObject f = Numeric.int_pow(context, 10, -ndigits);
if (this instanceof RubyFixnum && f instanceof RubyFixnum) {
@ -443,7 +443,7 @@ public abstract class RubyInteger extends RubyNumeric {
}
/** integer_to_r
*
*
*/
@JRubyMethod(name = "to_r")
public IRubyObject to_r(ThreadContext context) {
@ -457,7 +457,7 @@ public abstract class RubyInteger extends RubyNumeric {
public IRubyObject rationalize(ThreadContext context, IRubyObject[] args) {
return to_r(context);
}
@JRubyMethod(name = "odd?")
public RubyBoolean odd_p(ThreadContext context) {
@ -483,25 +483,25 @@ public abstract class RubyInteger extends RubyNumeric {
}
/** rb_gcd
*
*
*/
@JRubyMethod(name = "gcd")
public IRubyObject gcd(ThreadContext context, IRubyObject other) {
checkInteger(context, other);
return f_gcd(context, this, RubyRational.intValue(context, other));
}
}
/** rb_lcm
*
*
*/
@JRubyMethod(name = "lcm")
public IRubyObject lcm(ThreadContext context, IRubyObject other) {
checkInteger(context, other);
return f_lcm(context, this, RubyRational.intValue(context, other));
}
}
/** rb_gcdlcm
*
*
*/
@JRubyMethod(name = "gcdlcm")
public IRubyObject gcdlcm(ThreadContext context, IRubyObject other) {
@ -524,11 +524,11 @@ public abstract class RubyInteger extends RubyNumeric {
/* ================
* Singleton Methods
* ================
* ================
*/
/** rb_int_induced_from
*
*
*/
@Deprecated
public static IRubyObject induced_from(ThreadContext context, IRubyObject recv, IRubyObject other) {

View File

@ -27,7 +27,7 @@
* Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
* Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
* Copyright (C) 2008 Joseph LaFata <joe@quibb.org>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@ -121,7 +121,7 @@ public class RubyKernel {
runtime.setKernel(module);
module.defineAnnotatedMethods(RubyKernel.class);
module.setFlag(RubyObject.USER7_F, false); //Kernel is the only normal Module that doesn't need an implementor
runtime.setPrivateMethodMissing(new MethodMissingMethod(module, PRIVATE, CallType.NORMAL));
@ -158,29 +158,29 @@ public class RubyKernel {
Ruby runtime = context.runtime;
final RubyModule module = getModuleForAutoload(runtime, recv);
String name = symbol.asJavaString();
String file = module.getAutoloadFile(name);
return (file == null) ? runtime.getNil() : runtime.newString(file);
}
@JRubyMethod(required = 2, module = true, visibility = PRIVATE)
public static IRubyObject autoload(final IRubyObject recv, IRubyObject symbol, IRubyObject file) {
Ruby runtime = recv.getRuntime();
Ruby runtime = recv.getRuntime();
String nonInternedName = symbol.asJavaString();
final RubyString fileString = StringSupport.checkEmbeddedNulls(runtime,
RubyFile.get_path(runtime.getCurrentContext(), file));
if (!IdUtil.isValidConstantName(nonInternedName)) {
throw runtime.newNameError("autoload must be constant name", nonInternedName);
}
if (fileString.isEmpty()) throw runtime.newArgumentError("empty file name");
final String baseName = symbol.asJavaString().intern(); // interned, OK for "fast" methods
final RubyModule module = getModuleForAutoload(runtime, recv);
IRubyObject existingValue = module.fetchConstant(baseName);
IRubyObject existingValue = module.fetchConstant(baseName);
if (existingValue != null && existingValue != RubyObject.UNDEF) return runtime.getNil();
module.defineAutoload(baseName, new IAutoloadMethod() {
@ -192,7 +192,7 @@ public class RubyKernel {
@Override
public void load(Ruby runtime) {
if (runtime.getLoadService().autoloadRequire(file())) {
// Do not finish autoloading by cyclic autoload
// Do not finish autoloading by cyclic autoload
module.finishAutoload(baseName);
}
}
@ -222,7 +222,7 @@ public class RubyKernel {
protected static IRubyObject methodMissingDirect(ThreadContext context, IRubyObject recv, RubySymbol symbol, Visibility lastVis, CallType lastCallType, IRubyObject[] args, Block block) {
Ruby runtime = context.runtime;
// create a lightweight thunk
IRubyObject msg = new RubyNameError.RubyNameErrorMessage(runtime,
recv,
@ -264,7 +264,7 @@ public class RubyKernel {
throw new RaiseException((RubyException)exc.newInstance(context, exArgs, Block.NULL_BLOCK));
}
private static IRubyObject[] popenArgs(Ruby runtime, String pipedArg, IRubyObject[] args) {
IRubyObject command = runtime.newString(pipedArg.substring(1));
@ -273,7 +273,7 @@ public class RubyKernel {
return new IRubyObject[] { command };
}
public static IRubyObject open(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
return open19(context, recv, args, block);
}
@ -332,7 +332,7 @@ public class RubyKernel {
message = args[0].convertToString();
runtime.getGlobalVariables().get("$stderr").callMethod(context, "puts", message);
}
exit(runtime, new IRubyObject[] { runtime.getFalse(), message }, false);
return runtime.getNil(); // not reached
}
@ -355,7 +355,7 @@ public class RubyKernel {
public static IRubyObject new_complex(ThreadContext context, IRubyObject recv, IRubyObject arg0, IRubyObject arg1) {
return Helpers.invoke(context, context.runtime.getComplex(), "convert", arg0, arg1);
}
@JRubyMethod(name = "Rational", module = true, visibility = PRIVATE)
public static IRubyObject new_rational(ThreadContext context, IRubyObject recv) {
return Helpers.invoke(context, context.runtime.getRational(), "convert");
@ -397,7 +397,7 @@ public class RubyKernel {
return (RubyFloat)TypeConverter.convertToType19(object, runtime.getFloat(), "to_f");
}
}
@JRubyMethod(name = "Hash", required = 1, module = true, visibility = PRIVATE)
public static IRubyObject new_hash(ThreadContext context, IRubyObject recv, IRubyObject arg) {
IRubyObject tmp;
@ -411,7 +411,7 @@ public class RubyKernel {
throw runtime.newTypeError("can't convert " + arg.getMetaClass() + " into Hash");
}
return tmp;
}
}
public static IRubyObject new_integer(ThreadContext context, IRubyObject recv, IRubyObject object) {
return new_integer19(context, recv, object);
@ -633,32 +633,25 @@ public class RubyKernel {
if (args.length == 0) {
// Zero sleeps forever
milliseconds = 0;
} else {
if (!(args[0] instanceof RubyNumeric)) {
throw context.runtime.newTypeError("can't convert " + args[0].getMetaClass().getName() + "into time interval");
}
milliseconds = (long) (args[0].convertToFloat().getDoubleValue() * 1000);
if (milliseconds < 0) {
throw context.runtime.newArgumentError("time interval must be positive");
} else if (milliseconds == 0) {
// Explicit zero in MRI returns immediately
return context.runtime.newFixnum(0);
}
}
long startTime = System.currentTimeMillis();
RubyThread rubyThread = context.getThread();
else {
milliseconds = (long) ( RubyTime.convertTimeInterval(context, args[0]) * 1000 );
// Explicit zero in MRI returns immediately
if ( milliseconds == 0 ) return context.runtime.newFixnum(0);
}
final long startTime = System.currentTimeMillis();
final RubyThread rubyThread = context.getThread();
// Spurious wakeup-loop
do {
long loopStartTime = System.currentTimeMillis();
try {
// We break if we know this sleep was explicitly woken up/interrupted
if (!rubyThread.sleep(milliseconds)) break;
} catch (InterruptedException iExcptn) {
}
if ( ! rubyThread.sleep(milliseconds) ) break;
} catch (InterruptedException ex) { /* no-op */ }
milliseconds -= (System.currentTimeMillis() - loopStartTime);
} while (milliseconds > 0);
}
while (milliseconds > 0);
return context.runtime.newFixnum(Math.round((System.currentTimeMillis() - startTime) / 1000.0));
}
@ -757,11 +750,11 @@ public class RubyKernel {
return allLocalVariables;
}
public static RubyBinding binding(ThreadContext context, IRubyObject recv, Block block) {
return binding19(context, recv, block);
}
@JRubyMethod(name = "binding", module = true, visibility = PRIVATE,
reads = {LASTLINE, BACKREF, VISIBILITY, BLOCK, SELF, METHODNAME, LINE, JUMPTARGET, CLASS, FILENAME, SCOPE},
writes = {LASTLINE, BACKREF, VISIBILITY, BLOCK, SELF, METHODNAME, LINE, JUMPTARGET, CLASS, FILENAME, SCOPE})
@ -937,7 +930,7 @@ public class RubyKernel {
public static IRubyObject require19(ThreadContext context, IRubyObject recv, IRubyObject name, Block block) {
Ruby runtime = context.runtime;
IRubyObject tmp = name.checkStringType();
if (!tmp.isNil()) return requireCommon(runtime, recv, tmp, block);
return requireCommon(runtime, recv, RubyFile.get_path(context, name), block);
@ -1031,7 +1024,7 @@ public class RubyKernel {
public static IRubyObject caller(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
return caller20(context, recv, args, block);
}
public static IRubyObject caller19(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
return caller20(context, recv, args, block);
}
@ -1044,16 +1037,16 @@ public class RubyKernel {
return context.createCallerBacktrace(level, length, Thread.currentThread().getStackTrace());
}
@JRubyMethod(optional = 2, module = true, visibility = PRIVATE, omit = true)
public static IRubyObject caller_locations(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
Integer[] ll = levelAndLengthFromArgs(runtime, args, 1);
Integer level = ll[0], length = ll[1];
return context.createCallerLocations(level, length, Thread.currentThread().getStackTrace());
}
static Integer[] levelAndLengthFromArgs(Ruby runtime, IRubyObject[] args, int defaultLevel) {
int level;
Integer length = null;
@ -1081,7 +1074,7 @@ public class RubyKernel {
if (length != null && length < 0) {
throw runtime.newArgumentError("negative size (" + length + ')');
}
return new Integer[] {level, length};
}
@ -1166,11 +1159,11 @@ public class RubyKernel {
return runtime.newArgumentError(message);
}
};
@JRubyMethod(module = true, visibility = PRIVATE)
public static IRubyObject warn(ThreadContext context, IRubyObject recv, IRubyObject message) {
Ruby runtime = context.runtime;
if (runtime.warningsEnabled()) {
IRubyObject out = runtime.getGlobalVariables().get("$stderr");
Helpers.invoke(context, out, "write", message);
@ -1222,7 +1215,7 @@ public class RubyKernel {
if (var.charAt(0) != '$') {
return context.runtime.getNil();
}
if (args.length > 1) {
ArrayList<IRubyObject> success = new ArrayList<IRubyObject>();
for (int i = 1; i < args.length; i++) {
@ -1273,7 +1266,7 @@ public class RubyKernel {
return context.runtime.newProc(type, block);
}
@JRubyMethod(name = "proc", module = true, visibility = PRIVATE)
public static RubyProc proc_1_9(ThreadContext context, IRubyObject recv, Block block) {
return context.runtime.newProc(Block.Type.PROC, block);
@ -1329,11 +1322,11 @@ public class RubyKernel {
} else {
cmd = (int) args[0].convertToInteger().getLongValue();
}
// MRI behavior: raise ArgumentError for 'unknown command' before
// checking number of args.
switch(cmd) {
case 'A': case 'b': case 'c': case 'C': case 'd': case 'e': case 'f': case 'g': case 'G':
case 'A': case 'b': case 'c': case 'C': case 'd': case 'e': case 'f': case 'g': case 'G':
case 'k': case 'M': case 'l': case 'o': case 'O': case 'p': case 'r': case 'R': case 's':
case 'S': case 'u': case 'w': case 'W': case 'x': case 'X': case 'z': case '=': case '<':
case '>': case '-':
@ -1356,7 +1349,7 @@ public class RubyKernel {
}
break;
}
switch (cmd) {
case 'A': // ?A | Time | Last access time for file1
return context.runtime.newFileStat(args[1].convertToString().toString(), false).atime();
@ -1384,7 +1377,7 @@ public class RubyKernel {
return RubyFileTest.symlink_p(recv, args[1]);
case 'o': // ?o | boolean | True if file1 exists and is owned by the caller's effective uid
return RubyFileTest.owned_p(recv, args[1]);
case 'O': // ?O | boolean | True if file1 exists and is owned by the caller's real uid
case 'O': // ?O | boolean | True if file1 exists and is owned by the caller's real uid
return RubyFileTest.rowned_p(recv, args[1]);
case 'p': // ?p | boolean | True if file1 exists and is a fifo
return RubyFileTest.pipe_p(recv, args[1]);
@ -1483,7 +1476,7 @@ public class RubyKernel {
}
ByteList buf = new ByteList(out, 0, length, runtime.getDefaultExternalEncoding(), false);
RubyString newString = RubyString.newString(runtime, buf);
return newString;
}
@ -1603,20 +1596,20 @@ public class RubyKernel {
context.setLastExitStatus(RubyProcess.RubyStatus.newProcessStatus(runtime, tuple[0] << 8, tuple[1]));
return (int)tuple[0];
}
public static IRubyObject exec(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
return execCommon(runtime, null, args[0], null, args);
}
/* Actual exec definition which calls this internal version is specified
/* Actual exec definition which calls this internal version is specified
* in /core/src/main/ruby/jruby/kernel/kernel.rb.
*/
@JRubyMethod(required = 4, visibility = PRIVATE)
public static IRubyObject _exec_internal(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
IRubyObject env = args[0];
IRubyObject prog = args[1];
IRubyObject options = args[2];
@ -1626,7 +1619,7 @@ public class RubyKernel {
return execCommon(runtime, env, prog, options, cmdArgs.toJavaArray());
}
private static IRubyObject execCommon(Ruby runtime, IRubyObject env, IRubyObject prog, IRubyObject options, IRubyObject[] args) {
// This is a fairly specific hack for empty string, but it does the job
if (args.length == 1) {
@ -1649,7 +1642,7 @@ public class RubyKernel {
runtime.getENV().merge_bang(context, envMap, Block.NULL_BLOCK);
}
}
boolean nativeFailed = false;
boolean nativeExec = Options.NATIVE_EXEC.load();
boolean jmxStopped = false;
@ -1676,7 +1669,7 @@ public class RubyKernel {
jmxStopped = runtime.getBeanManager().tryShutdownAgent();
runtime.getPosix().chdir(System.getProperty("user.dir"));
if (Platform.IS_WINDOWS) {
// Windows exec logic is much more elaborate; exec() in jnr-posix attempts to duplicate it
runtime.getPosix().exec(progStr, argv);
@ -1707,7 +1700,7 @@ public class RubyKernel {
}
throw runtime.newErrnoFromLastPOSIXErrno();
}
// Fall back onto our existing code if native not available
// FIXME: Make jnr-posix Pure-Java backend do this as well
int resultCode = ShellLauncher.execAndWait(runtime, args);
@ -1755,7 +1748,7 @@ public class RubyKernel {
block.yield(context, recv);
return recv;
}
@JRubyMethod(name = {"to_enum", "enum_for"}, optional = 1, rest = true)
public static IRubyObject obj_to_enum(final ThreadContext context, IRubyObject self, IRubyObject[] args, final Block block) {
String method = "each";
@ -1786,7 +1779,7 @@ public class RubyKernel {
}
return context.runtime.newSymbol(frameName);
}
@JRubyMethod(name = "__dir__", module = true, visibility = PRIVATE, reads = FILENAME)
public static IRubyObject __dir__(ThreadContext context, IRubyObject recv) {
String dir = RubyFile.dirname(context, new File(context.gatherCallerBacktrace()[1].getFileName()).getAbsolutePath());
@ -1861,14 +1854,22 @@ public class RubyKernel {
return self.callMethod(context, "initialize_copy", original);
}
public static RubyBoolean respond_to_p(IRubyObject self, IRubyObject mname) {
return ((RubyBasicObject) self).respond_to_p(mname);
}
@JRubyMethod(name = "respond_to?")
public static IRubyObject respond_to_p19(IRubyObject self, IRubyObject mname) {
return ((RubyBasicObject)self).respond_to_p19(mname);
return ((RubyBasicObject) self).respond_to_p19(mname);
}
public static RubyBoolean respond_to_p(IRubyObject self, IRubyObject mname, IRubyObject includePrivate) {
return ((RubyBasicObject) self).respond_to_p(mname, includePrivate);
}
@JRubyMethod(name = "respond_to?")
public static IRubyObject respond_to_p19(IRubyObject self, IRubyObject mname, IRubyObject includePrivate) {
return ((RubyBasicObject)self).respond_to_p19(mname, includePrivate);
return ((RubyBasicObject) self).respond_to_p19(mname, includePrivate);
}
@JRubyMethod

View File

@ -254,11 +254,14 @@ public class RubyModule extends RubyObject {
return autoloads == Collections.EMPTY_MAP ? autoloads = new ConcurrentHashMap<String, Autoload>(4, 0.9f, 1) : autoloads;
}
@SuppressWarnings("unchecked")
public void addIncludingHierarchy(IncludedModule hierarchy) {
synchronized (getRuntime().getHierarchyLock()) {
Set<RubyClass> oldIncludingHierarchies = includingHierarchies;
if (oldIncludingHierarchies == Collections.EMPTY_SET) includingHierarchies = oldIncludingHierarchies = new WeakHashSet(4);
oldIncludingHierarchies.add(hierarchy);
Set<RubyClass> including = this.includingHierarchies;
if (including == Collections.EMPTY_SET) {
including = this.includingHierarchies = new WeakHashSet(4);
}
including.add(hierarchy);
}
}
@ -500,6 +503,9 @@ public class RubyModule extends RubyObject {
// First, we count the parents
int parentCount = 0;
for (RubyModule p = getParent() ; p != null && p != objectClass ; p = p.getParent()) {
// Break out of cyclic namespaces like C::A = C2; C2::A = C (jruby/jruby#2314)
if (p == this) break;
parentCount++;
}
@ -508,6 +514,9 @@ public class RubyModule extends RubyObject {
int i = parentCount - 1;
int totalLength = name.length() + parentCount * 2; // name length + enough :: for all parents
for (RubyModule p = getParent() ; p != null && p != objectClass ; p = p.getParent(), i--) {
// Break out of cyclic namespaces like C::A = C2; C2::A = C (jruby/jruby#2314)
if (p == this) break;
String pName = p.getBaseName();
// This is needed when the enclosing class or module is a singleton.
@ -3736,9 +3745,8 @@ public class RubyModule extends RubyObject {
protected Map<String, IRubyObject> getClassVariables() {
if (CLASSVARS_UPDATER == null) {
return getClassVariablesForWriteSynchronized();
} else {
return getClassVariablesForWriteAtomic();
}
return getClassVariablesForWriteAtomic();
}
/**
@ -3748,19 +3756,17 @@ public class RubyModule extends RubyObject {
* @return the class vars map, ready for assignment
*/
private Map<String,IRubyObject> getClassVariablesForWriteSynchronized() {
Map myClassVars = classVariables;
if (myClassVars == Collections.EMPTY_MAP) {
Map<String, IRubyObject> myClassVars = classVariables;
if ( myClassVars == Collections.EMPTY_MAP ) {
synchronized (this) {
myClassVars = classVariables;
if (myClassVars == Collections.EMPTY_MAP) {
if ( myClassVars == Collections.EMPTY_MAP ) {
return classVariables = new ConcurrentHashMap<String, IRubyObject>(4, 0.75f, 2);
} else {
return myClassVars;
}
return myClassVars;
}
}
return myClassVars;
}
@ -3773,14 +3779,12 @@ public class RubyModule extends RubyObject {
*/
private Map<String,IRubyObject> getClassVariablesForWriteAtomic() {
while (true) {
Map myClassVars = classVariables;
Map newClassVars;
Map<String, IRubyObject> myClassVars = classVariables;
if (myClassVars == Collections.EMPTY_MAP) {
newClassVars = new ConcurrentHashMap<String, IRubyObject>(4, 0.75f, 2);
} else {
return myClassVars;
}
if ( myClassVars != Collections.EMPTY_MAP ) return myClassVars;
Map<String, IRubyObject> newClassVars;
newClassVars = new ConcurrentHashMap<String, IRubyObject>(4, 0.75f, 2);
// proceed with atomic update of table, or retry
if (CLASSVARS_UPDATER.compareAndSet(this, myClassVars, newClassVars)) {
@ -4311,6 +4315,17 @@ public class RubyModule extends RubyObject {
setFlag(USER0_F, cacheProxy);
}
@Override
public Object toJava(Class target) {
if (target == Class.class) { // try java_class for proxy modules
if ( respondsTo("java_class") ) {
return callMethod("java_class").toJava(target);
}
}
return super.toJava(target);
}
public Set<String> discoverInstanceVariables() {
HashSet<String> set = new HashSet();
RubyModule cls = this;
@ -4409,17 +4424,19 @@ public class RubyModule extends RubyObject {
/** The moduel where this refinement was defined */
private volatile RubyModule definedAt = null;
private static final AtomicReferenceFieldUpdater CLASSVARS_UPDATER;
private static final AtomicReferenceFieldUpdater<RubyModule, Map> CLASSVARS_UPDATER;
static {
AtomicReferenceFieldUpdater updater = null;
AtomicReferenceFieldUpdater<RubyModule, Map> updater = null;
try {
updater = AtomicReferenceFieldUpdater.newUpdater(RubyModule.class, Map.class, "classVariables");
} catch (RuntimeException re) {
if (re.getCause() instanceof AccessControlException) {
}
catch (final RuntimeException ex) {
if (ex.getCause() instanceof AccessControlException) {
// security prevented creation; fall back on synchronized assignment
} else {
throw re;
}
else {
throw ex;
}
}
CLASSVARS_UPDATER = updater;

View File

@ -1975,8 +1975,6 @@ public class RubyString extends RubyObject implements EncodingCapable, MarshalEn
}
while (p < end) {
int cc = 0;
int n = StringSupport.preciseLength(enc, bytes, p, end);
if (!MBCLEN_CHARFOUND_P(n)) {
if (p > prev) result.cat(bytes, prev, p - prev);
@ -1990,7 +1988,8 @@ public class RubyString extends RubyObject implements EncodingCapable, MarshalEn
continue;
}
n = MBCLEN_CHARFOUND_LEN(n);
int c = enc.mbcToCode(bytes, p, end);
final int c = enc.mbcToCode(bytes, p, end); int cc = 0;
p += n;
if ((asciiCompat || isUnicode) &&
(c == '"' || c == '\\' ||
@ -2161,7 +2160,7 @@ public class RubyString extends RubyObject implements EncodingCapable, MarshalEn
modify19(value.getRealSize() + cl);
if (enc == USASCIIEncoding.INSTANCE) {
if (c > 0xff) runtime.newRangeError(c + " out of char range");
if (c > 0xff) throw runtime.newRangeError(c + " out of char range");
if (c > 0x79) {
value.setEncoding(ASCIIEncoding.INSTANCE);
enc = value.getEncoding();

View File

@ -22,7 +22,7 @@
* Copyright (C) 2006 Ola Bini <ola.bini@ki.se>
* Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
* Copyright (C) 2009 Joseph LaFata <joe@quibb.org>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@ -73,7 +73,7 @@ import static org.jruby.runtime.Helpers.invokedynamic;
import static org.jruby.runtime.invokedynamic.MethodNames.OP_CMP;
/** The Time class.
*
*
* @author chadfowler, jpetersen
*/
@JRubyClass(name="Time", include="Comparable")
@ -81,7 +81,7 @@ public class RubyTime extends RubyObject {
public static final String UTC = "UTC";
private DateTime dt;
private long nsec;
private final static DateTimeFormatter ONE_DAY_CTIME_FORMATTER = DateTimeFormat.forPattern("EEE MMM d HH:mm:ss yyyy").withLocale(Locale.ENGLISH);
private final static DateTimeFormatter TWO_DAY_CTIME_FORMATTER = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss yyyy").withLocale(Locale.ENGLISH);
@ -96,14 +96,14 @@ public class RubyTime extends RubyObject {
// understood by Java API.
private static final Pattern TZ_PATTERN
= Pattern.compile("([^-\\+\\d]+)?([\\+-]?)(\\d+)(?::(\\d+))?(?::(\\d+))?");
private static final Pattern TIME_OFFSET_PATTERN
= Pattern.compile("([\\+-])(\\d\\d):(\\d\\d)(?::(\\d\\d))?");
private static final ByteList TZ_STRING = ByteList.create("TZ");
private boolean isTzRelative = false; // true if and only if #new is called with a numeric offset (e.g., "+03:00")
/* JRUBY-3560
* joda-time disallows use of three-letter time zone IDs.
* Since MRI accepts these values, we need to translate them.
@ -113,7 +113,7 @@ public class RubyTime extends RubyObject {
"ROC", "Asia/Taipei", // Republic of China
"WET", "Europe/Lisbon" // Western European Time
);
/* Some TZ values need to be overriden for Time#zone
*/
private static final Map<String, String> SHORT_STD_TZNAME = Helpers.map(
@ -127,7 +127,7 @@ public class RubyTime extends RubyObject {
"MET", "MEST", // needs to be overriden
"UCT", "UCT"
);
private void setIsTzRelative(boolean tzRelative) {
isTzRelative = tzRelative;
}
@ -136,7 +136,7 @@ public class RubyTime extends RubyObject {
public ClassIndex getNativeClassIndex() {
return ClassIndex.TIME;
}
private static IRubyObject getEnvTimeZone(Ruby runtime) {
RubyString tzVar = (RubyString)runtime.getTime().getInternalVariable("tz_string");
if (tzVar == null) {
@ -339,7 +339,7 @@ public class RubyTime extends RubyObject {
public RubyTime(Ruby runtime, RubyClass rubyClass) {
super(runtime, rubyClass);
}
public RubyTime(Ruby runtime, RubyClass rubyClass, DateTime dt) {
super(runtime, rubyClass);
this.dt = dt;
@ -362,16 +362,16 @@ public class RubyTime extends RubyObject {
timeClass.setClassIndex(ClassIndex.TIME);
timeClass.setReifiedClass(RubyTime.class);
runtime.setTime(timeClass);
timeClass.includeModule(runtime.getComparable());
timeClass.defineAnnotatedMethods(RubyTime.class);
return timeClass;
}
public void setNSec(long nsec) {
this.nsec = nsec;
}
@ -383,33 +383,33 @@ public class RubyTime extends RubyObject {
public void setUSec(long usec) {
this.nsec = 1000 * usec;
}
public long getUSec() {
return nsec / 1000;
}
public void updateCal(DateTime dt) {
this.dt = dt;
}
protected long getTimeInMillis() {
return dt.getMillis();
}
public static RubyTime newTime(Ruby runtime, long milliseconds) {
return newTime(runtime, new DateTime(milliseconds));
}
public static RubyTime newTime(Ruby runtime, DateTime dt) {
return new RubyTime(runtime, runtime.getTime(), dt);
}
public static RubyTime newTime(Ruby runtime, DateTime dt, long nsec) {
RubyTime t = new RubyTime(runtime, runtime.getTime(), dt);
t.setNSec(nsec);
return t;
}
@Override
public Class<?> getJavaClass() {
return Date.class;
@ -421,13 +421,13 @@ public class RubyTime extends RubyObject {
if (!(original instanceof RubyTime)) {
throw getRuntime().newTypeError("Expecting an instance of class Time");
}
RubyTime originalTime = (RubyTime) original;
// We can just use dt, since it is immutable
dt = originalTime.dt;
nsec = originalTime.nsec;
return this;
}
@ -445,7 +445,7 @@ public class RubyTime extends RubyObject {
public RubyTime localtime() {
return localtime19(getRuntime().getCurrentContext(), NULL_ARRAY);
}
@JRubyMethod(name = "localtime", optional = 1)
public RubyTime localtime19(ThreadContext context, IRubyObject[] args) {
DateTimeZone newDtz;
@ -457,12 +457,12 @@ public class RubyTime extends RubyObject {
dt = dt.withZone(newDtz);
return this;
}
@JRubyMethod(name = {"gmt?", "utc?", "gmtime?"})
public RubyBoolean gmt() {
return getRuntime().newBoolean(dt.getZone().getID().equals("UTC"));
}
@JRubyMethod(name = {"getgm", "getutc"})
public RubyTime getgm() {
return newTime(getRuntime(), dt.withZone(DateTimeZone.UTC), nsec);
@ -499,43 +499,43 @@ public class RubyTime extends RubyObject {
return RubyComparable.op_equal19(context, this, other);
}
@JRubyMethod(name = ">=", required = 1)
public IRubyObject op_ge(ThreadContext context, IRubyObject other) {
if (other instanceof RubyTime) {
return getRuntime().newBoolean(cmp((RubyTime) other) >= 0);
}
return RubyComparable.op_ge(context, this, other);
}
@JRubyMethod(name = ">", required = 1)
public IRubyObject op_gt(ThreadContext context, IRubyObject other) {
if (other instanceof RubyTime) {
return getRuntime().newBoolean(cmp((RubyTime) other) > 0);
}
return RubyComparable.op_gt(context, this, other);
}
@JRubyMethod(name = "<=", required = 1)
public IRubyObject op_le(ThreadContext context, IRubyObject other) {
if (other instanceof RubyTime) {
return getRuntime().newBoolean(cmp((RubyTime) other) <= 0);
}
return RubyComparable.op_le(context, this, other);
}
@JRubyMethod(name = "<", required = 1)
public IRubyObject op_lt(ThreadContext context, IRubyObject other) {
if (other instanceof RubyTime) {
return getRuntime().newBoolean(cmp((RubyTime) other) < 0);
}
return RubyComparable.op_lt(context, this, other);
}
private int cmp(RubyTime other) {
Ruby runtime = getRuntime();
@ -572,10 +572,10 @@ public class RubyTime extends RubyObject {
private IRubyObject opPlusNanos(long adjustNanos) {
long currentMillis = getTimeInMillis();
long adjustMillis = adjustNanos/1000000;
long adjustNanosLeft = adjustNanos - (adjustMillis*1000000);
long newMillisPart = currentMillis + adjustMillis;
long newNanosPart = nsec + adjustNanosLeft;
@ -604,7 +604,7 @@ public class RubyTime extends RubyObject {
private IRubyObject opMinus(RubyTime other) {
long timeInMillis = (getTimeInMillis() - other.getTimeInMillis());
double timeInSeconds = timeInMillis/1000.0 + (getNSec() - other.getNSec())/1000000000.0;
return RubyFloat.newFloat(getRuntime(), timeInSeconds); // float number of seconds
}
@ -623,9 +623,9 @@ public class RubyTime extends RubyObject {
long adjustmentInNanos = (long)(RubyNumeric.num2dbl(other)*1000000000);
long adjustmentInMillis = adjustmentInNanos/1000000;
long adjustmentInNanosLeft = adjustmentInNanos%1000000;
long time = getTimeInMillis() - adjustmentInMillis;
long nano;
if (nsec < adjustmentInNanosLeft) {
time--;
@ -657,7 +657,7 @@ public class RubyTime extends RubyObject {
if (other instanceof RubyTime) {
return context.runtime.newFixnum(cmp((RubyTime) other));
}
return invcmp(context, this, other);
}
@ -665,7 +665,7 @@ public class RubyTime extends RubyObject {
@Override
public IRubyObject eql_p(IRubyObject other) {
if (other instanceof RubyTime) {
RubyTime otherTime = (RubyTime)other;
RubyTime otherTime = (RubyTime)other;
return (nsec == otherTime.nsec && getTimeInMillis() == otherTime.getTimeInMillis()) ? getRuntime().getTrue() : getRuntime().getFalse();
}
return getRuntime().getFalse();
@ -762,7 +762,7 @@ public class RubyTime extends RubyObject {
dt = dt.withMillis(withoutMillis);
nsec = (mic % 1000) * 1000;
}
public long microseconds() {
return getTimeInMillis() % 1000 * 1000 + getUSec();
}
@ -844,19 +844,19 @@ public class RubyTime extends RubyObject {
if (SHORT_STD_TZNAME.containsKey(envTZ) && ! dt.getZone().toTimeZone().inDaylightTime(dt.toDate())) {
return SHORT_STD_TZNAME.get(envTZ);
}
if (SHORT_DL_TZNAME.containsKey(envTZ) && dt.getZone().toTimeZone().inDaylightTime(dt.toDate())) {
return SHORT_DL_TZNAME.get(envTZ);
}
String zone = dt.getZone().getShortName(dt.getMillis());
Matcher offsetMatcher = TIME_OFFSET_PATTERN.matcher(zone);
if (offsetMatcher.matches()) {
boolean minus_p = offsetMatcher.group(1).toString().equals("-");
int hourOffset = Integer.valueOf(offsetMatcher.group(2));
if (zone.equals("+00:00")) {
zone = "GMT";
} else {
@ -868,7 +868,7 @@ public class RubyTime extends RubyObject {
}
}
}
return zone;
}
@ -889,14 +889,14 @@ public class RubyTime extends RubyObject {
public RubyFixnum hash() {
// modified to match how hash is calculated in 1.8.2
return getRuntime().newFixnum((int)(((dt.getMillis() / 1000) ^ microseconds()) << 1) >> 1);
}
}
@JRubyMethod(name = "_dump", optional = 1)
public RubyString dump(IRubyObject[] args, Block unusedBlock) {
RubyString str = (RubyString) mdump();
str.syncVariables(this);
return str;
}
}
public RubyObject mdump() {
Ruby runtime = getRuntime();
@ -906,8 +906,8 @@ public class RubyTime extends RubyObject {
long nanos = this.nsec;
long usec = this.nsec / 1000;
long nanosec = this.nsec % 1000;
int pe =
int pe =
0x1 << 31 |
((obj.gmt().isTrue())? 0x1 : 0x0) << 30 |
(dateTime.getYear()-1900) << 14 |
@ -968,7 +968,7 @@ public class RubyTime extends RubyObject {
public IRubyObject initialize(Block block) {
return this;
}
@JRubyMethod(optional = 1)
public RubyTime round(ThreadContext context, IRubyObject[] args) {
int ndigits = args.length == 0 ? 0 : RubyNumeric.num2int(args[0]);
@ -988,7 +988,7 @@ public class RubyTime extends RubyObject {
}
/* Time class methods */
public static IRubyObject s_new(IRubyObject recv, IRubyObject[] args, Block block) {
Ruby runtime = recv.getRuntime();
RubyTime time = new RubyTime(runtime, (RubyClass) recv, new DateTime(getLocalTimeZone(runtime)));
@ -1148,25 +1148,58 @@ public class RubyTime extends RubyObject {
public Object toJava(Class target) {
if (target.equals(Date.class)) {
return getJavaDate();
} else if (target.equals(Calendar.class)) {
}
if (target.equals(Calendar.class)) {
Calendar cal = GregorianCalendar.getInstance();
cal.setTime(getJavaDate());
return cal;
} else if (target.equals(DateTime.class)) {
return this.dt;
} else if (target.equals(java.sql.Date.class)) {
return new java.sql.Date(dt.getMillis());
} else if (target.equals(java.sql.Time.class)) {
return new java.sql.Time(dt.getMillis());
} else if (target.equals(java.sql.Timestamp.class)) {
return new java.sql.Timestamp(dt.getMillis());
} else if (target.isAssignableFrom(Date.class)) {
return getJavaDate();
} else {
return super.toJava(target);
}
if (target.equals(DateTime.class)) {
return this.dt;
}
if (target.equals(java.sql.Date.class)) {
return new java.sql.Date(dt.getMillis());
}
if (target.equals(java.sql.Time.class)) {
return new java.sql.Time(dt.getMillis());
}
if (target.equals(java.sql.Timestamp.class)) {
return new java.sql.Timestamp(dt.getMillis());
}
if (target.isAssignableFrom(Date.class)) {
return getJavaDate();
}
return super.toJava(target);
}
// MRI: time.c ~ rb_time_interval 1.9 ... invokes time_timespec(VALUE num, TRUE)
public static double convertTimeInterval(ThreadContext context, IRubyObject sec) {
double seconds;
if ( sec instanceof RubyNumeric ) {
seconds = ((RubyNumeric) sec).getDoubleValue();
}
// NOTE: we can probably do better here, but we're matching MRI behavior
// this is for converting custom objects such as ActiveSupport::Duration
else if ( sec.respondsTo("divmod") ) {
final Ruby runtime = context.runtime;
IRubyObject result = sec.callMethod(context, "divmod", RubyFixnum.newFixnum(runtime, 1));
if ( result instanceof RubyArray ) {
seconds = ((RubyNumeric) ((RubyArray) result).eltOk(0) ).getDoubleValue(); // div
seconds += ((RubyNumeric) ((RubyArray) result).eltOk(1) ).getDoubleValue(); // mod
}
else {
throw runtime.newTypeError("unexpected divmod result: into %s" + result.getMetaClass().getName());
}
}
else {
throw context.runtime.newTypeError("can't convert " + sec.getMetaClass().getName() + " into time interval");
}
if ( seconds < 0 ) throw context.runtime.newArgumentError("time interval must be positive");
return seconds;
}
protected static RubyTime s_mload(IRubyObject recv, RubyTime time, IRubyObject from) {
Ruby runtime = recv.getRuntime();
@ -1258,7 +1291,7 @@ public class RubyTime extends RubyObject {
Ruby runtime = recv.getRuntime();
int len = ARG_SIZE;
boolean isDst = false;
boolean setTzRelative = false;
boolean setTzRelative = false;
long nanos = 0;
DateTimeZone dtz;
@ -1277,7 +1310,7 @@ public class RubyTime extends RubyObject {
} else {
dtz = getLocalTimeZone(runtime);
}
if (args.length == 10) {
if (args[8] instanceof RubyBoolean) isDst = args[8].isTrue();

View File

@ -10,7 +10,7 @@
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@ -35,12 +35,14 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyException;
import org.jruby.RubyFixnum;
import org.jruby.RubyKernel;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.RubyRegexp;
import org.jruby.RubyThread;
import org.jruby.RubyTime;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Helpers;
@ -63,8 +65,8 @@ public class Timeout implements Library {
// Here we create an "anonymous" exception type used for unrolling the stack.
// MRI creates a new one for *every call* to timeout, which can be costly.
// We opt to use a single exception type for all cases to avoid this overhead.
RubyClass anonEx = runtime.defineClassUnder("AnonymousException", runtime.getException(), runtime.getException().getAllocator(), timeout);
anonEx.setBaseName(null); // clear basename so it's anonymous when raising
RubyClass anonException = runtime.defineClassUnder("AnonymousException", runtime.getException(), runtime.getException().getAllocator(), timeout);
anonException.setBaseName(null); // clear basename so it's anonymous when raising
// These are not really used by timeout, but exposed for compatibility
timeout.defineConstant("THIS_FILE", RubyRegexp.newRegexp(runtime, "timeout\\.rb", new RegexpOptions()));
@ -83,8 +85,8 @@ public class Timeout implements Library {
public static class TimeoutToplevel {
@JRubyMethod(required = 1, optional = 1, visibility = PRIVATE)
public static IRubyObject timeout(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
RubyModule timeout = context.runtime.getModule("Timeout");
final RubyModule timeout = context.runtime.getModule("Timeout");
switch (args.length) {
case 1:
return Timeout.timeout(context, timeout, args[0], block);
@ -100,7 +102,7 @@ public class Timeout implements Library {
@JRubyMethod(module = true)
public static IRubyObject timeout(final ThreadContext context, IRubyObject timeout, IRubyObject seconds, Block block) {
// No seconds, just yield
if (seconds.isNil() || Helpers.invoke(context, seconds, "zero?").isTrue()) {
if ( nilOrZeroSeconds(context, seconds) ) {
return block.yieldSpecific(context);
}
@ -115,31 +117,21 @@ public class Timeout implements Library {
final AtomicBoolean latch = new AtomicBoolean(false);
IRubyObject id = new RubyObject(runtime, runtime.getObject());
Runnable timeoutRunnable = prepareRunnable(currentThread, runtime, latch, id);
Future timeoutFuture = null;
Runnable timeoutRunnable = TimeoutTask.newAnnonymousTask(currentThread, timeout, latch, id);
try {
try {
timeoutFuture = timeoutExecutor.schedule(timeoutRunnable,
(long)(seconds.convertToFloat().getDoubleValue() * 1000000), TimeUnit.MICROSECONDS);
return block.yield(context, seconds);
} finally {
killTimeoutThread(context, timeoutFuture, latch);
}
} catch (RaiseException re) {
if (re.getException().getInternalVariable("__identifier__") == id) {
return raiseTimeoutError(context, re);
} else {
throw re;
}
return yieldWithTimeout(context, seconds, block, timeoutRunnable, latch);
}
catch (RaiseException re) {
raiseTimeoutErrorIfMatches(context, timeout, re, id);
throw re;
}
}
@JRubyMethod(module = true)
public static IRubyObject timeout(final ThreadContext context, IRubyObject timeout, IRubyObject seconds, IRubyObject exceptionType, Block block) {
// No seconds, just yield
if (seconds.isNil() || Helpers.invoke(context, seconds, "zero?").isTrue()) {
if ( nilOrZeroSeconds(context, seconds) ) {
return block.yieldSpecific(context);
}
@ -154,30 +146,19 @@ public class Timeout implements Library {
final AtomicBoolean latch = new AtomicBoolean(false);
IRubyObject id = new RubyObject(runtime, runtime.getObject());
RubyClass anonException = (RubyClass)runtime.getClassFromPath("Timeout::AnonymousException");
Runnable timeoutRunnable = exceptionType.isNil() ?
prepareRunnable(currentThread, runtime, latch, id) :
prepareRunnableWithException(currentThread, exceptionType, runtime, latch);
Future timeoutFuture = null;
TimeoutTask.newAnnonymousTask(currentThread, timeout, latch, id) :
TimeoutTask.newTaskWithException(currentThread, timeout, latch, exceptionType);
try {
try {
timeoutFuture = timeoutExecutor.schedule(timeoutRunnable,
(long)(seconds.convertToFloat().getDoubleValue() * 1000000), TimeUnit.MICROSECONDS);
return block.yield(context, seconds);
} finally {
killTimeoutThread(context, timeoutFuture, latch);
}
} catch (RaiseException re) {
return yieldWithTimeout(context, seconds, block, timeoutRunnable, latch);
}
catch (RaiseException re) {
// if it's the exception we're expecting
if (re.getException().getMetaClass() == anonException) {
if (re.getException().getMetaClass() == getAnonymousException(timeout)) {
// and we were not given a specific exception
if (exceptionType.isNil()) {
// and it's the exception intended for us
if (re.getException().getInternalVariable("__identifier__") == id) {
return raiseTimeoutError(context, re);
}
if ( exceptionType.isNil() ) {
raiseTimeoutErrorIfMatches(context, timeout, re, id);
}
}
@ -186,36 +167,80 @@ public class Timeout implements Library {
}
}
private static Runnable prepareRunnable(final RubyThread currentThread, final Ruby runtime, final AtomicBoolean latch, final IRubyObject id) {
Runnable timeoutRunnable = new Runnable() {
public void run() {
if (latch.compareAndSet(false, true)) {
if (currentThread.isAlive()) {
RubyClass anonException = (RubyClass)runtime.getClassFromPath("Timeout::AnonymousException");
IRubyObject anonExceptionObj = anonException.newInstance(runtime.getCurrentContext(), runtime.newString("execution expired"), Block.NULL_BLOCK);
anonExceptionObj.getInternalVariables().setInternalVariable("__identifier__", id);
currentThread.raise(anonExceptionObj);
}
}
}
};
return timeoutRunnable;
private static boolean nilOrZeroSeconds(final ThreadContext context, final IRubyObject seconds) {
return seconds.isNil() || Helpers.invoke(context, seconds, "zero?").isTrue();
}
private static Runnable prepareRunnableWithException(final RubyThread currentThread, final IRubyObject exception, final Ruby runtime, final AtomicBoolean latch) {
Runnable timeoutRunnable = new Runnable() {
public void run() {
if (latch.compareAndSet(false, true)) {
if (currentThread.isAlive()) {
currentThread.genericRaise(runtime, new IRubyObject[]{exception, runtime.newString("execution expired")}, null);
}
}
}
};
return timeoutRunnable;
private static IRubyObject yieldWithTimeout(ThreadContext context,
final IRubyObject seconds, final Block block,
final Runnable runnable, final AtomicBoolean latch) throws RaiseException {
final long micros = (long) ( RubyTime.convertTimeInterval(context, seconds) * 1000000 );
Future timeoutFuture = null;
try {
timeoutFuture = timeoutExecutor.schedule(runnable, micros, TimeUnit.MICROSECONDS);
return block.yield(context, seconds);
}
finally {
if ( timeoutFuture != null ) killTimeoutThread(context, timeoutFuture, latch);
// ... when timeoutFuture == null there's likely an error thrown from schedule
}
}
private static void killTimeoutThread(ThreadContext context, Future timeoutFuture, AtomicBoolean latch) {
private static class TimeoutTask implements Runnable {
final RubyThread currentThread;
final AtomicBoolean latch;
final IRubyObject timeout; // Timeout module
final IRubyObject id; // needed for 'anonymous' timeout (no exception passed)
final IRubyObject exception; // if there's exception (type) passed to timeout
private TimeoutTask(final RubyThread currentThread, final IRubyObject timeout,
final AtomicBoolean latch, final IRubyObject id, final IRubyObject exception) {
this.currentThread = currentThread;
this.timeout = timeout;
this.latch = latch;
this.id = id;
this.exception = exception;
}
static TimeoutTask newAnnonymousTask(final RubyThread currentThread, final IRubyObject timeout,
final AtomicBoolean latch, final IRubyObject id) {
return new TimeoutTask(currentThread, timeout, latch, id, null);
}
static TimeoutTask newTaskWithException(final RubyThread currentThread, final IRubyObject timeout,
final AtomicBoolean latch, final IRubyObject exception) {
return new TimeoutTask(currentThread, timeout, latch, null, exception);
}
public void run() {
if ( latch.compareAndSet(false, true) ) {
if ( exception == null ) {
raiseAnnonymous();
}
else {
raiseException();
}
}
}
private void raiseAnnonymous() {
final Ruby runtime = timeout.getRuntime();
IRubyObject anonException = getAnonymousException(timeout).newInstance(runtime.getCurrentContext(), runtime.newString("execution expired"), Block.NULL_BLOCK);
anonException.getInternalVariables().setInternalVariable("__identifier__", id);
currentThread.internalRaise(new IRubyObject[] { anonException });
}
private void raiseException() {
final Ruby runtime = timeout.getRuntime();
currentThread.internalRaise(new IRubyObject[]{ exception, runtime.newString("execution expired") });
}
}
private static void killTimeoutThread(ThreadContext context, final Future timeoutFuture, final AtomicBoolean latch) {
if (latch.compareAndSet(false, true) && timeoutFuture.cancel(false)) {
// ok, exception will not fire
if (timeoutExecutor instanceof ScheduledThreadPoolExecutor && timeoutFuture instanceof Runnable) {
@ -225,10 +250,9 @@ public class Timeout implements Library {
// future is not cancellable, wait for it to run and then poll
try {
timeoutFuture.get();
} catch (ExecutionException ex) {
} catch (InterruptedException ex) {
}
catch (ExecutionException ex) {}
catch (InterruptedException ex) {}
// poll to propagate exception from child thread
context.pollThreadEvents();
}
@ -237,19 +261,42 @@ public class Timeout implements Library {
private static IRubyObject raiseBecauseCritical(ThreadContext context) {
Ruby runtime = context.runtime;
return RubyKernel.raise(context, runtime.getKernel(), new IRubyObject[]{runtime.getThreadError(), runtime.newString("timeout within critical section")}, Block.NULL_BLOCK);
}
private static IRubyObject raiseTimeoutError(ThreadContext context, RaiseException re) {
Ruby runtime = context.runtime;
return RubyKernel.raise(
context,
runtime.getKernel(),
new IRubyObject[]{
runtime.getClassFromPath("Timeout::Error"),
re.getException().callMethod(context, "message"),
re.getException().callMethod(context, "backtrace")},
new IRubyObject[] {
runtime.getThreadError(),
runtime.newString("timeout within critical section")
},
Block.NULL_BLOCK);
}
private static IRubyObject raiseTimeoutErrorIfMatches(ThreadContext context,
final IRubyObject timeout, final RaiseException ex, final IRubyObject id) {
// check if it's the exception intended for us (@see prepareRunnable):
if ( ex.getException().getInternalVariable("__identifier__") == id ) {
final RubyException rubyException = ex.getException();
return RubyKernel.raise( // throws
context,
context.runtime.getKernel(),
new IRubyObject[] {
getClassFrom(timeout, "Error"), // Timeout::Error
rubyException.callMethod(context, "message"),
rubyException.callMethod(context, "backtrace")
},
Block.NULL_BLOCK);
}
return null;
}
// Timeout::AnonymousException (@see above)
private static RubyClass getAnonymousException(final IRubyObject timeout) {
return getClassFrom(timeout, "AnonymousException");
}
private static RubyClass getClassFrom(final IRubyObject timeout, final String name) {
return ((RubyModule) timeout).getClass(name); // Timeout::[name]
}
}

View File

@ -313,10 +313,7 @@ public class JavaProxy extends RubyObject {
RubyArray argTypesAry = argTypes.convertToArray();
Ruby runtime = context.runtime;
if (argTypesAry.size() != 0) {
Class[] argTypesClasses = (Class[])argTypesAry.toArray(new Class[argTypesAry.size()]);
throw JavaMethod.newArgSizeMismatchError(runtime, argTypesClasses);
}
checkArgSizeMismatch(runtime, 0, argTypesAry);
JavaMethod method = new JavaMethod(runtime, getMethod(context, name));
return method.invokeDirect(context, getObject());
@ -328,12 +325,9 @@ public class JavaProxy extends RubyObject {
RubyArray argTypesAry = argTypes.convertToArray();
Ruby runtime = context.runtime;
if (argTypesAry.size() != 1) {
Class[] argTypesClasses = (Class[])argTypesAry.toArray(new Class[argTypesAry.size()]);
throw JavaMethod.newArgSizeMismatchError(runtime, argTypesClasses);
}
checkArgSizeMismatch(runtime, 1, argTypesAry);
Class argTypeClass = (Class)argTypesAry.eltInternal(0).toJava(Class.class);
Class argTypeClass = (Class) argTypesAry.eltInternal(0).toJava(Class.class);
JavaMethod method = new JavaMethod(runtime, getMethod(context, name, argTypeClass));
return method.invokeDirect(context, getObject(), arg0.toJava(argTypeClass));
@ -345,22 +339,26 @@ public class JavaProxy extends RubyObject {
String name = args[0].asJavaString();
RubyArray argTypesAry = args[1].convertToArray();
int argsLen = args.length - 2;
final int argsLen = args.length - 2;
if (argTypesAry.size() != argsLen) {
Class[] argTypesClasses = (Class[])argTypesAry.toArray(new Class[argTypesAry.size()]);
throw JavaMethod.newArgSizeMismatchError(runtime, argTypesClasses);
}
checkArgSizeMismatch(runtime, argsLen, argTypesAry);
Class[] argTypesClasses = (Class[])argTypesAry.toArray(new Class[argsLen]);
Class[] argTypesClasses = (Class[]) argTypesAry.toArray(new Class[argsLen]);
Object[] argsAry = new Object[argsLen];
for (int i = 0; i < argsLen; i++) {
argsAry[i] = args[i + 2].toJava(argTypesClasses[i]);
Object[] javaArgs = new Object[argsLen];
for ( int i = 0; i < argsLen; i++ ) {
javaArgs[i] = args[i + 2].toJava( argTypesClasses[i] );
}
JavaMethod method = new JavaMethod(runtime, getMethod(context, name, argTypesClasses));
return method.invokeDirect(context, getObject(), argsAry);
return method.invokeDirect(context, getObject(), javaArgs);
}
private static void checkArgSizeMismatch(final Ruby runtime, final int expected, final RubyArray argTypes) {
if ( argTypes.size() != expected ) {
Class[] argTypesClasses = (Class[]) argTypes.toArray(new Class[argTypes.size()]);
throw JavaMethod.newArgSizeMismatchError(runtime, argTypesClasses);
}
}
@JRubyMethod
@ -374,7 +372,7 @@ public class JavaProxy extends RubyObject {
public IRubyObject java_method(ThreadContext context, IRubyObject rubyName, IRubyObject argTypes) {
String name = rubyName.asJavaString();
RubyArray argTypesAry = argTypes.convertToArray();
Class[] argTypesClasses = (Class[])argTypesAry.toArray(new Class[argTypesAry.size()]);
Class[] argTypesClasses = (Class[]) argTypesAry.toArray(new Class[argTypesAry.size()]);
return getRubyMethod(context, name, argTypesClasses);
}

View File

@ -9,7 +9,7 @@ public enum Priority {
RESERVED(0), METHOD(1), FIELD(2), PROTECTED_METHOD(3),
WEAKLY_RESERVED(4), ALIAS(5), PROTECTED_FIELD(6);
private int value;
private final int value;
Priority(int value) {
this.value = value;

View File

@ -12,7 +12,7 @@
* rights and limitations under the License.
*
* Copyright (C) 2007, 2008 Ola Bini <ola@ologix.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@ -29,6 +29,7 @@ package org.jruby.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import jnr.posix.POSIX;
@ -38,8 +39,8 @@ import org.jruby.RubyEncoding;
import org.jruby.platform.Platform;
/**
* This class exists as a counterpart to the dir.c file in
* MRI source. It contains many methods useful for
* This class exists as a counterpart to the dir.c file in
* MRI source. It contains many methods useful for
* File matching and Globbing.
*
* @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
@ -87,7 +88,7 @@ public class Dir {
byte c = bytes[pat++];
switch(c) {
case '?':
if(s >= send || (pathname && isdirsep(string[s])) ||
if(s >= send || (pathname && isdirsep(string[s])) ||
(period && string[s] == '.' && (s == 0 || (pathname && isdirsep(string[s-1]))))) {
return FNM_NOMATCH;
}
@ -126,7 +127,7 @@ public class Dir {
}
return FNM_NOMATCH;
case '[':
if(s >= send || (pathname && isdirsep(string[s]) ||
if(s >= send || (pathname && isdirsep(string[s]) ||
(period && string[s] == '.' && (s == 0 || (pathname && isdirsep(string[s-1])))))) {
return FNM_NOMATCH;
}
@ -154,13 +155,13 @@ public class Dir {
if(Character.toLowerCase((char)c) != Character.toLowerCase((char)string[s])) {
return FNM_NOMATCH;
}
} else {
if(c != (char)string[s]) {
return FNM_NOMATCH;
}
}
}
s++;
break;
@ -172,7 +173,7 @@ public class Dir {
public static int fnmatch(
byte[] bytes, int pstart, int pend,
byte[] string, int sstart, int send, int flags) {
// This method handles '**/' patterns and delegates to
// fnmatch_helper for the main work.
@ -296,122 +297,122 @@ public class Dir {
}
public static List<ByteList> push_glob(Ruby runtime, String cwd, ByteList globByteList, int flags) {
List<ByteList> result = new ArrayList<ByteList>();
if (globByteList.length() > 0) {
final ArrayList<ByteList> result = new ArrayList<ByteList>();
push_braces(runtime, cwd, result, new GlobPattern(globByteList, flags));
return result;
}
return result;
return Collections.emptyList();
}
private static class GlobPattern {
final byte[] bytes;
final byte[] bytes;
final int begin;
final int end;
int flags;
int index;
public GlobPattern(ByteList bytelist, int flags) {
this(bytelist.getUnsafeBytes(), bytelist.getBegin(), bytelist.getBegin() + bytelist.getRealSize(), flags);
private int index;
private final int flags;
GlobPattern(ByteList bytes, int flags) {
this(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getBegin() + bytes.getRealSize(), flags);
}
public GlobPattern(byte[] bytes, int index, int end, int flags) {
GlobPattern(byte[] bytes, int index, int end, int flags) {
this.bytes = bytes;
this.index = index;
this.begin = index;
this.end = end;
this.flags = flags;
}
public int findClosingIndexOf(int leftTokenIndex) {
if (leftTokenIndex == -1 || leftTokenIndex > end) return -1;
byte leftToken = bytes[leftTokenIndex];
byte rightToken;
switch (leftToken) {
case '{': rightToken = '}'; break;
case '[': rightToken = ']'; break;
default: return -1;
}
int nest = 1; // leftToken made us start as nest 1
index = leftTokenIndex + 1;
while (hasNext()) {
byte c = next();
if (c == leftToken) {
nest++;
} else if (c == rightToken && --nest == 0) {
return index();
}
}
return -1;
}
public boolean hasNext() {
return index < end;
}
public void reset() {
index = begin;
}
public void setIndex(int value) {
index = value;
}
// Get index of last read byte
public int index() {
return index - 1;
}
public int indexOf(byte c) {
while (hasNext()) if (next() == c) return index();
return -1;
}
public byte next() {
return bytes[index++];
}
}
public static interface GlobFunc {
int call(byte[] ptr, int p, int len, Object ary);
public static interface GlobFunc<T> {
int call(byte[] ptr, int p, int len, T ary);
}
private static class GlobArgs {
GlobFunc func;
int c = -1;
List<ByteList> v;
public GlobArgs(GlobFunc func, List<ByteList> arg) {
final GlobFunc<List<ByteList>> func;
final List<ByteList> arg;
private int c = -1;
GlobArgs(GlobFunc<List<ByteList>> func, List<ByteList> arg) {
this.func = func;
this.v = arg;
this.arg = arg;
}
}
public final static GlobFunc push_pattern = new GlobFunc() {
@SuppressWarnings("unchecked")
public int call(byte[] ptr, int p, int len, Object ary) {
((List) ary).add(new ByteList(ptr, p, len));
return 0;
}
};
public final static GlobFunc glob_caller = new GlobFunc() {
public int call(byte[] ptr, int p, int len, Object ary) {
GlobArgs args = (GlobArgs)ary;
final static GlobFunc<List<ByteList>> push_pattern = new GlobFunc<List<ByteList>>() {
public int call(byte[] ptr, int p, int len, List<ByteList> ary) {
ary.add(new ByteList(ptr, p, len));
return 0;
}
};
private final static GlobFunc<GlobArgs> glob_caller = new GlobFunc<GlobArgs>() {
public int call(byte[] ptr, int p, int len, GlobArgs args) {
args.c = p;
return args.func.call(ptr, args.c, len, args.v);
return args.func.call(ptr, args.c, len, args.arg);
}
};
/*
* Process {}'s (example: Dir.glob("{jruby,jython}/README*")
* Process {}'s (example: Dir.glob("{jruby,jython}/README*")
*/
private static int push_braces(Ruby runtime, String cwd, List<ByteList> result, GlobPattern pattern) {
pattern.reset();
@ -419,10 +420,10 @@ public class Dir {
int rbrace = pattern.findClosingIndexOf(lbrace);// index of right-most brace
// No, mismatched or escaped braces..Move along..nothing to see here
if (lbrace == -1 || rbrace == -1 ||
lbrace > 0 && pattern.bytes[lbrace-1] == '\\' ||
if (lbrace == -1 || rbrace == -1 ||
lbrace > 0 && pattern.bytes[lbrace-1] == '\\' ||
rbrace > 0 && pattern.bytes[rbrace-1] == '\\') {
ByteList unescaped = new ByteList(pattern.bytes.length-1);
ByteList unescaped = new ByteList(pattern.bytes.length - 1);
for (int i = pattern.begin; i < pattern.end; i++) {
byte b = pattern.bytes[i];
if (b == '\\' && i < pattern.bytes.length - 1) {
@ -434,12 +435,12 @@ public class Dir {
unescaped.append(b);
}
}
return push_globs(runtime, cwd, result, unescaped.getUnsafeBytes(), unescaped.begin(), unescaped.length(), pattern.flags);
return push_globs(runtime, cwd, result, unescaped, pattern.flags);
}
// Peel onion...make subpatterns out of outer layer of glob and recall with each subpattern
// Peel onion...make subpatterns out of outer layer of glob and recall with each subpattern
// Example: foo{a{c},b}bar -> fooa{c}bar, foobbar
ByteList buf = new ByteList(20);
final ByteList bytes = new ByteList(20);
int middleRegionIndex;
int i = lbrace;
while (pattern.bytes[i] != '}') {
@ -448,20 +449,20 @@ public class Dir {
if (pattern.bytes[i] == '{') i = pattern.findClosingIndexOf(i); // skip inner braces
}
buf.length(0);
buf.append(pattern.bytes, pattern.begin, lbrace - pattern.begin);
buf.append(pattern.bytes, middleRegionIndex, i - middleRegionIndex);
buf.append(pattern.bytes, rbrace + 1, pattern.end - (rbrace + 1));
int status = push_braces(runtime, cwd, result, new GlobPattern(buf.getUnsafeBytes(), buf.getBegin(), buf.getRealSize(),pattern.flags));
if(status != 0) return status;
bytes.length(0);
bytes.append(pattern.bytes, pattern.begin, lbrace - pattern.begin);
bytes.append(pattern.bytes, middleRegionIndex, i - middleRegionIndex);
bytes.append(pattern.bytes, rbrace + 1, pattern.end - (rbrace + 1));
int status = push_braces(runtime, cwd, result, new GlobPattern(bytes, pattern.flags));
if (status != 0) return status;
}
return 0; // All braces pushed..
}
private static int push_globs(Ruby runtime, String cwd, List<ByteList> ary, byte[] pattern, int pbegin, int pend, int pflags) {
pflags |= FNM_SYSCASE;
return glob_helper(runtime, cwd, pattern, pbegin, pend, -1, pflags, glob_caller, new GlobArgs(push_pattern, ary));
private static int push_globs(Ruby runtime, String cwd, List<ByteList> ary, ByteList pattern, int flags) {
flags |= FNM_SYSCASE;
return glob_helper(runtime, cwd, pattern, -1, flags, glob_caller, new GlobArgs(push_pattern, ary));
}
public static ArrayList<String> braces(String pattern, int flags, ArrayList<String> patterns) {
@ -548,7 +549,7 @@ public class Dir {
int open = 0;
for (int i = begin; i < end; i++) {
switch(bytes[i]) {
switch (bytes[i]) {
case '?':
case '*':
return true;
@ -564,36 +565,34 @@ public class Dir {
break;
default:
if (FNM_SYSCASE == 0 && nocase && Character.isLetter((char)(bytes[i]&0xFF))) return true;
if (FNM_SYSCASE == 0 && nocase && Character.isLetter((char)(bytes[i] & 0xFF))) return true;
}
}
return false;
}
private static int remove_backslashes(byte[] bytes, int index, int len) {
int t = index;
for (; index < len; index++, t++) {
if (bytes[index] == '\\' && ++index == len) break;
bytes[t] = bytes[index];
private static int remove_backslashes(byte[] bytes, int index, int end) {
int i = index;
for ( ; index < end; index++, i++ ) {
if (bytes[index] == '\\' && ++index == end) break;
bytes[i] = bytes[index];
}
return t;
return i;
}
private static int strchr(byte[] bytes, int begin, int end, byte ch) {
for (int i = begin; i < end; i++) {
if (bytes[i] == ch) return i;
private static int indexOf(byte[] bytes, int begin, int end, final byte ch) {
for ( int i = begin; i < end; i++ ) {
if ( bytes[i] == ch ) return i;
}
return -1;
}
private static byte[] extract_path(byte[] bytes, int begin, int end) {
int len = end - begin;
if (len > 1 && bytes[end-1] == '/' && (!DOSISH || (len < 2 || bytes[end-2] != ':'))) len--;
byte[] alloc = new byte[len];
@ -602,51 +601,44 @@ public class Dir {
}
private static byte[] extract_elem(byte[] bytes, int begin, int end) {
int elementEnd = strchr(bytes, begin, end, (byte)'/');
int elementEnd = indexOf(bytes, begin, end, (byte)'/');
if (elementEnd == -1) elementEnd = end;
return extract_path(bytes, begin, elementEnd);
}
// Win drive letter X:/
private static boolean beginsWithDriveLetter(byte[] path, int begin, int end) {
return DOSISH && begin + 2 < end && path[begin + 1] == ':' && isdirsep(path[begin + 2]);
return DOSISH && begin + 2 < end && path[begin + 1] == ':' && isdirsep(path[begin + 2]);
}
// Is this nothing or literally root directory for the OS.
private static boolean isRoot(byte[] base) {
int length = base.length;
return length == 0 || // empty
length == 1 && isdirsep(base[0]) || // Just '/'
length == 3 && beginsWithDriveLetter(base, 0, length); // Just X:/
length == 3 && beginsWithDriveLetter(base, 0, length); // Just X:/
}
private static boolean isAbsolutePath(byte[] path, int begin, int length) {
return isdirsep(path[begin]) || beginsWithDriveLetter(path, begin, length);
}
private static String[] files(FileResource directory) {
String[] files = directory.list();
if (files != null) {
return files;
} else {
return new String[0];
}
private static String[] files(final FileResource directory) {
final String[] files = directory.list();
return files == null ? new String[0] : files;
}
private static final class DirGlobber {
public final ByteList link;
public DirGlobber(ByteList link) {
this.link = link;
}
DirGlobber(ByteList link) { this.link = link; }
}
private static boolean isSpecialFile(String name) {
int length = name.length();
if (length < 1 || length > 3 || name.charAt(0) != '.') return false;
if (length == 1) return true;
char c = name.charAt(1);
@ -654,8 +646,8 @@ public class Dir {
return c == '.' && name.charAt(2) == '/';
}
private static int addToResultIfExists(Ruby runtime, String cwd, byte[] bytes, int begin, int end, int flags, GlobFunc func, GlobArgs arg) {
String fileName = newStringFromUTF8(bytes, begin, end - begin);
private static int addToResultIfExists(Ruby runtime, String cwd, byte[] bytes, int begin, int end, int flags, GlobFunc<GlobArgs> func, GlobArgs arg) {
final String fileName = newStringFromUTF8(bytes, begin, end - begin);
// FIXME: Ultimately JRubyFile.createResource should do this but all 1.7.x is only selectively honoring raw
// paths and using system drive make it absolute. MRI does this on many methods we don't.
@ -673,7 +665,7 @@ public class Dir {
// On case-insenstive file systems any case string will 'exists',
// but what does it display as if you ls/dir it?
/* No idea what this is doing =/
if ((flags & FNM_CASEFOLD) != 0 && !isSpecialFile(fileName)) {
try {
String realName = file.getCanonicalFile().getName();
@ -694,155 +686,155 @@ public class Dir {
end = bytes.length;
} catch (Exception e) {} // Failure will just use what we pass in
}*/
return func.call(bytes, begin, end - begin, arg);
}
return 0;
}
private static int glob_helper(Ruby runtime, String cwd, byte[] bytes, int begin, int end, int sub, int flags, GlobFunc func, GlobArgs arg) {
int p,m;
int status = 0;
byte[] newpath = null;
FileResource st;
p = sub != -1 ? sub : begin;
private static int glob_helper(Ruby runtime, String cwd, ByteList path, int sub, int flags, GlobFunc<GlobArgs> func, GlobArgs arg) {
final int begin = path.getBegin();
final int end = begin + path.getRealSize();
return glob_helper(runtime, cwd, path.getUnsafeBytes(), begin, end, sub, flags, func, arg);
}
if (!has_magic(bytes, p, end, flags)) {
if (DOSISH || (flags & FNM_NOESCAPE) == 0) {
newpath = new byte[end];
System.arraycopy(bytes,0,newpath,0,end);
if (sub != -1) {
p = (sub - begin);
end = remove_backslashes(newpath, p, end);
sub = p;
} else {
end = remove_backslashes(newpath, 0, end);
bytes = newpath;
private static int glob_helper(Ruby runtime, String cwd,
byte[] path, int begin, int end, int sub,
final int flags, GlobFunc<GlobArgs> func, GlobArgs arg) {
int status = 0;
int p = sub != -1 ? sub : begin;
if ( ! has_magic(path, p, end, flags) ) {
if ( DOSISH || (flags & FNM_NOESCAPE) == 0 ) {
if ( sub != -1 ) { // can modify path (our internal buf[])
end = remove_backslashes(path, sub, end);
}
else {
final int len = end - begin;
final byte[] newPath = new byte[len];
System.arraycopy(path, begin, newPath, 0, len);
begin = 0; end = remove_backslashes(newPath, 0, len);
path = newPath;
}
}
if (isAbsolutePath(bytes, begin, end)) {
status = addToResultIfExists(runtime, null, bytes, begin, end, flags, func, arg);
} else if ((end - begin) > 0) { // Length check is a hack. We should not be reeiving "" as a filename ever.
status = addToResultIfExists(runtime, cwd, bytes, begin, end, flags, func, arg);
if ( (end - begin) > 0 ) {
if ( isAbsolutePath(path, begin, end) ) {
status = addToResultIfExists(runtime, null, path, begin, end, flags, func, arg);
} else {
status = addToResultIfExists(runtime, cwd, path, begin, end, flags, func, arg);
}
}
return status;
}
ByteList buf = new ByteList(20);
List<DirGlobber> link = new ArrayList<DirGlobber>();
mainLoop: while(p != -1 && status == 0) {
if (bytes[p] == '/') p++;
m = strchr(bytes, p, end, (byte)'/');
if(has_magic(bytes, p, m == -1 ? end : m, flags)) {
final ArrayList<DirGlobber> links = new ArrayList<DirGlobber>();
ByteList buf = new ByteList(20); FileResource resource;
mainLoop: while(p != -1 && status == 0) {
if ( path[p] == '/' ) p++;
final int s = indexOf(path, p, end, (byte) '/');
if ( has_magic(path, p, s == -1 ? end : s, flags) ) {
finalize: do {
byte[] base = extract_path(bytes, begin, p);
byte[] dir = begin == p ? new byte[]{'.'} : base;
byte[] magic = extract_elem(bytes,p,end);
byte[] base = extract_path(path, begin, p);
byte[] dir = begin == p ? new byte[] { '.' } : base;
byte[] magic = extract_elem(path, p, end);
boolean recursive = false;
st = JRubyFile.createResource(runtime, cwd, newStringFromUTF8(dir));
resource = JRubyFile.createResource(runtime, cwd, newStringFromUTF8(dir, 0, dir.length));
if (st.isDirectory()) {
if(m != -1 && Arrays.equals(magic, DOUBLE_STAR)) {
int n = base.length;
if ( resource.isDirectory() ) {
if ( s != -1 && Arrays.equals(magic, DOUBLE_STAR) ) {
final int n = base.length;
recursive = true;
buf.length(0);
buf.append(base);
buf.append(bytes, (base.length > 0 ? m : m + 1), end - (base.length > 0 ? m : m + 1));
status = glob_helper(runtime, cwd, buf.getUnsafeBytes(), buf.getBegin(), buf.getRealSize(), n, flags, func, arg);
if(status != 0) {
break finalize;
}
buf.append(path, (n > 0 ? s : s + 1), end - (n > 0 ? s : s + 1));
status = glob_helper(runtime, cwd, buf, n, flags, func, arg);
if ( status != 0 ) break finalize;
}
} else {
break mainLoop;
}
String[] dirp = files(st);
final String[] files = files(resource);
for(int i=0;i<dirp.length;i++) {
if(recursive) {
byte[] bs = getBytesInUTF8(dirp[i]);
if (fnmatch(STAR,0,1,bs,0,bs.length,flags) != 0) {
for ( int i = 0; i < files.length; i++ ) {
final String file = files[i];
final byte[] fileBytes = getBytesInUTF8(file);
if (recursive) {
if ( fnmatch(STAR, 0, 1, fileBytes, 0, fileBytes.length, flags) != 0) {
continue;
}
buf.length(0);
buf.append(base);
buf.append(isRoot(base) ? EMPTY : SLASH );
buf.append(getBytesInUTF8(dirp[i]));
st = JRubyFile.createResource(runtime, cwd, newStringFromUTF8(buf.getUnsafeBytes(), buf.getBegin(), buf.getRealSize()));
if(!st.isSymLink() && st.isDirectory() && !".".equals(dirp[i]) && !"..".equals(dirp[i])) {
int t = buf.getRealSize();
buf.append( isRoot(base) ? EMPTY : SLASH );
buf.append( getBytesInUTF8(file) );
resource = JRubyFile.createResource(runtime, cwd, newStringFromUTF8(buf));
if ( !resource.isSymLink() && resource.isDirectory() && !".".equals(file) && !"..".equals(file) ) {
final int len = buf.getRealSize();
buf.append(SLASH);
buf.append(DOUBLE_STAR);
buf.append(bytes, m, end - m);
status = glob_helper(runtime, cwd, buf.getUnsafeBytes(), buf.getBegin(), buf.getRealSize(), t, flags, func, arg);
if(status != 0) {
break;
}
buf.append(path, s, end - s);
status = glob_helper(runtime, cwd, buf, buf.getBegin() + len, flags, func, arg);
if ( status != 0 ) break;
}
continue;
}
byte[] bs = getBytesInUTF8(dirp[i]);
if(fnmatch(magic,0,magic.length,bs,0, bs.length,flags) == 0) {
if ( fnmatch(magic, 0, magic.length, fileBytes, 0, fileBytes.length, flags) == 0 ) {
buf.length(0);
buf.append(base);
buf.append(isRoot(base) ? EMPTY : SLASH );
buf.append(getBytesInUTF8(dirp[i]));
if(m == -1) {
status = func.call(buf.getUnsafeBytes(),0, buf.getRealSize(),arg);
if(status != 0) {
break;
}
buf.append( isRoot(base) ? EMPTY : SLASH );
buf.append( getBytesInUTF8(file) );
if ( s == -1 ) {
status = func.call(buf.getUnsafeBytes(), 0, buf.getRealSize(), arg);
if ( status != 0 ) break;
continue;
}
link.add(new DirGlobber(buf));
links.add(new DirGlobber(buf));
buf = new ByteList(20);
}
}
} while(false);
if (link.size() > 0) {
for (DirGlobber globber : link) {
ByteList b = globber.link;
if (status == 0) {
st = JRubyFile.createResource(runtime, cwd, newStringFromUTF8(b.getUnsafeBytes(), 0, b.getRealSize()));
if(st.isDirectory()) {
int len = b.getRealSize();
if ( links.size() > 0 ) {
for ( DirGlobber globber : links ) {
final ByteList link = globber.link;
if ( status == 0 ) {
resource = JRubyFile.createResource(runtime, cwd, newStringFromUTF8(link));
if ( resource.isDirectory() ) {
final int len = link.getRealSize();
buf.length(0);
buf.append(b);
buf.append(bytes, m, end - m);
status = glob_helper(runtime, cwd, buf.getUnsafeBytes(),0, buf.getRealSize(),len,flags,func,arg);
buf.append(link);
buf.append(path, s, end - s);
status = glob_helper(runtime, cwd, buf, buf.getBegin() + len, flags, func, arg);
}
}
}
break mainLoop;
}
}
p = m;
p = s;
}
return status;
}
private static ByteList fixBytesForJarInUTF8(byte[] buf, int offset, int len) {
String path = newStringFromUTF8(buf, offset, len);
path = path.replace(".jar/", ".jar!");
return new ByteList(path.getBytes());
private static byte[] getBytesInUTF8(final String str) {
return RubyEncoding.encodeUTF8(str);
}
private static byte[] getBytesInUTF8(String s) {
return RubyEncoding.encodeUTF8(s);
private static String newStringFromUTF8(final ByteList bytes) {
final int offset = bytes.getBegin();
final int length = bytes.getRealSize();
return RubyEncoding.decodeUTF8(bytes.getUnsafeBytes(), offset, length);
}
private static String newStringFromUTF8(byte[] buf, int offset, int len) {
return RubyEncoding.decodeUTF8(buf, offset, len);
private static String newStringFromUTF8(final byte[] bytes, int offset, int len) {
return RubyEncoding.decodeUTF8(bytes, offset, len);
}
private static String newStringFromUTF8(byte[] buf) {
return RubyEncoding.decodeUTF8(buf);
}
}

View File

@ -162,10 +162,10 @@ public class ShellLauncher {
public void start() throws IOException {
config = new RubyInstanceConfig(parentRuntime.getInstanceConfig());
config.setEnvironment(environmentMap(env));
config.setCurrentDirectory(pwd.toString());
if (pipedStreams) {
config.setInput(new PipedInputStream(processInput));
config.setOutput(new PrintStream(new PipedOutputStream(processOutput)));
@ -294,7 +294,7 @@ public class ShellLauncher {
}
}
}
ary = new String[i];
System.arraycopy(ret, 0, ary, 0, i);
return ary;
@ -479,13 +479,13 @@ public class ShellLauncher {
if (env.isNil() || !(env instanceof Map)) {
env = null;
}
IRubyObject[] rawArgs = args.convertToArray().toJavaArray();
OutputStream output = runtime.getOutputStream();
OutputStream error = runtime.getErrorStream();
InputStream input = runtime.getInputStream();
try {
Process aProcess = null;
File pwd = new File(runtime.getCurrentDirectory());
@ -506,7 +506,7 @@ public class ShellLauncher {
} catch (SecurityException se) {
throw runtime.newSecurityError(se.getLocalizedMessage());
}
if (wait) {
handleStreams(runtime, aProcess, input, output, error);
try {
@ -616,14 +616,14 @@ public class ShellLauncher {
return reflectPidFromProcess(process);
}
}
private static final Class UNIXProcess;
private static final Field UNIXProcess_pid;
private static final Class ProcessImpl;
private static final Field ProcessImpl_handle;
private interface PidGetter { public long getPid(Process process); }
private static final PidGetter PID_GETTER;
static {
// default PidGetter
PidGetter pg = new PidGetter() {
@ -631,7 +631,7 @@ public class ShellLauncher {
return process.hashCode();
}
};
Class up = null;
Field pid = null;
try {
@ -731,7 +731,11 @@ public class ShellLauncher {
public static POpenProcess popen(Ruby runtime, IRubyObject[] strings, Map env, ModeFlags modes) throws IOException {
return new POpenProcess(popenShared(runtime, strings, env), runtime, modes);
}
public static POpenProcess popen(Ruby runtime, IRubyObject string, Map env, ModeFlags modes) throws IOException {
return new POpenProcess(popenShared(runtime, new IRubyObject[] {string}, env, true), runtime, modes);
}
@Deprecated
public static POpenProcess popen(Ruby runtime, IRubyObject string, IOOptions modes) throws IOException {
return new POpenProcess(popenShared(runtime, new IRubyObject[] {string}, null, true), runtime, modes);
@ -757,7 +761,7 @@ public class ShellLauncher {
}
private static Process popenShared(Ruby runtime, IRubyObject[] strings, Map env) throws IOException {
return popenShared(runtime, strings, env, true);
return popenShared(runtime, strings, env, false);
}
private static Process popenShared(Ruby runtime, IRubyObject[] strings, Map env, boolean addShell) throws IOException {
@ -840,7 +844,7 @@ public class ShellLauncher {
*/
public static InputStream unwrapBufferedStream(InputStream filteredStream) {
if (RubyInstanceConfig.NO_UNWRAP_PROCESS_STREAMS) return filteredStream;
// Java 7+ uses a stream that drains the child on exit, which when
// unwrapped breaks because the channel gets drained prematurely.
// System.out.println("class is :" + filteredStream.getClass().getName());
@ -927,7 +931,7 @@ public class ShellLauncher {
public POpenProcess(Process child, Ruby runtime, IOOptions modes) {
this(child, runtime, modes.getModeFlags());
}
public POpenProcess(Process child, Ruby runtime, ModeFlags modes) {
this.child = child;
@ -948,7 +952,7 @@ public class ShellLauncher {
pumpInput(child, runtime);
}
pumpInerr(child, runtime);
pumpInerr(child, runtime);
}
public POpenProcess(Process child) {
@ -1434,7 +1438,7 @@ public class ShellLauncher {
} catch (SecurityException se) {
throw runtime.newSecurityError(se.getLocalizedMessage());
}
return aProcess;
}
@ -1682,7 +1686,7 @@ public class ShellLauncher {
return RbConfigLibrary.jrubyShell();
}
private static boolean shouldUseShell(String command) {
public static boolean shouldUseShell(String command) {
boolean useShell = false;
for (char c : command.toCharArray()) {
if (c != ' ' && !Character.isLetter(c) && "*?{}[]<>()~&|\\$;'`\"\n".indexOf(c) != -1) {

View File

@ -8,6 +8,7 @@ module JRuby
java_import org.jruby.util.ShellLauncher
java_import java.lang.ProcessBuilder
java_import org.jruby.runtime.builtin.IRubyObject
java_import org.jruby.platform.Platform
Redirect = ProcessBuilder::Redirect
LaunchConfig = ShellLauncher::LaunchConfig
@ -18,7 +19,10 @@ module JRuby
config = LaunchConfig.new(JRuby.runtime, [command].to_java(IRubyObject), false)
if config.should_run_in_shell?
use_shell = Platform::IS_WINDOWS ? config.should_run_in_shell : false
use_shell |= ShellLauncher.should_use_shell(command)
if use_shell
config.verify_executable_for_shell
else
config.verify_executable_for_direct
@ -26,6 +30,7 @@ module JRuby
pb = ProcessBuilder.new(config.exec_args)
pb.redirect_input(Redirect::INHERIT)
pb.redirect_error(Redirect::INHERIT)
pb.environment(ShellLauncher.get_current_env(JRuby.runtime))
pb.directory(JFile.new(JRuby.runtime.current_directory))
process = pb.start

View File

@ -939,7 +939,7 @@ class Date
h[:sec] = i sec if sec
end
h[:sec_fraction] = sec_fraction if sec_fraction
h[:sec_fraction] = Rational(sec_fraction.to_i, 10**sec_fraction.size) if sec_fraction
set_zone(h, zone)
elsif /\A\s*
@ -981,7 +981,7 @@ class Date
h[:sec] = i sec if sec
end
h[:sec_fraction] = sec_fraction if sec_fraction
h[:sec_fraction] = Rational(sec_fraction.to_i, 10**sec_fraction.size) if sec_fraction
set_zone(h, zone)
elsif /\A\s*
@ -1004,7 +1004,7 @@ class Date
h[:hour] = i hour
h[:min] = i min
h[:sec] = i sec if sec
h[:sec_fraction] = i sec_fraction if sec_fraction
h[:sec_fraction] = Rational(sec_fraction.to_i, 10**sec_fraction.size) if sec_fraction
set_zone(h, zone)
end
h

View File

@ -96,7 +96,7 @@ project 'JRuby Complete' do
plugin 'org.codehaus.mojo:build-helper-maven-plugin' do
execute_goals( 'attach-artifact',
:id => 'attach javadocs and sources artifacts',
:id => 'attach-artifacts',
'artifacts' => [ { 'file' => '${project.build.directory}/jruby-core-${project.version}-sources.jar',
'classifier' => 'sources' },
{ 'file' => '${project.build.directory}/jruby-core-${project.version}-javadoc.jar',

View File

@ -5,7 +5,7 @@ describe "A Java object's java_send method" do
@list = java.util.ArrayList.new
@integer = java.lang.Integer.new(1)
end
it "works with name only for no-arg methods" do
@list.java_send(:toString).should == "[]"
java.lang.System.java_send(:currentTimeMillis).class.should == Fixnum
@ -15,19 +15,56 @@ describe "A Java object's java_send method" do
@list.java_send(:toString, []).should == "[]"
java.lang.System.java_send(:currentTimeMillis, []).class.should == Fixnum
end
it "works with a signature" do
@list.java_send :add, [Java::int, java.lang.Object], 0, 'foo'
@list.to_s.should == "[foo]"
java_home = java.lang.System.java_send(:getProperty, [java.lang.String], 'java.home')
java_home.should == java.lang.System.getProperty('java.home')
str = java.lang.StringBuilder.new
str.java_send :append, [Java::long], 1234567890
str.to_s.should == '1234567890'
str.java_send :append, [java.lang.String], " str1"
str.to_s.should == '1234567890 str1'
str.java_send :append, [java.lang.CharSequence], " str2"
str.to_s.should == '1234567890 str1 str2'
str.java_send :append, [Java::char[], Java::int, Java::int], " str3".to_java.to_char_array, 0, 4
str.to_s.should == '1234567890 str1 str2 str'
end
it "works with package-level classes" do
array = Java::int[16].new
array[1] = 10; array[2] = 20
buffer = java.nio.IntBuffer.wrap array # returns a Java::JavaNio::HeapIntBuffer
buffer.java_send(:get, [ Java::int ], 1).should == 10
buffer.java_send(:get).should == 0
buffer.java_send(:get).should == 10
buffer.java_send(:get, []).should == 20
end
it "works with private classes" do
array = Java::int[16].new
array[1] = 10; array[2] = 20
map = java.util.HashMap.new
key_type = java.lang.String.java_class
val_type = java.lang.Number.java_class
map = java.util.Collections.checkedMap(map, key_type, val_type) # returns a private CheckedMap instance
map.java_send(:clear)
map.java_send(:put, [ Java::JavaLang::Object, Java::JavaLang::Object ], '1', 1.to_java)
map.java_send(:get, [ Java::JavaLang::Object ], '').should == nil
map.java_send(:get, [ Java::JavaLang::Object ], '1').should == 1
end
it "raises NameError if the method can't be found" do
lambda do
@list.java_send :foobar
end.should raise_error(NameError)
lambda do
@list.java_send :add, [Java::long, java.lang.Object], 0, 'foo'
end.should raise_error(NameError)
@ -40,7 +77,7 @@ describe "A Java object's java_send method" do
java.lang.System.java_send :getProperty, [Java::long, Java::long], 0, 0
end.should raise_error(NameError)
end
it "raises ArgumentError if type count doesn't match arg count" do
lambda do
@list.java_send :add, [Java::int, java.lang.Object], 0, 'foo', 'bar'

View File

@ -0,0 +1,15 @@
require 'base64'
describe "A badly-encoded UTF-8 String reencoded with replacements as UTF-16 " do
it "completes for all inputs" do
random = Random.new
# We obviously can't test all valid inputs, but we use the script from #2856 to try
10_000.times do
data = random.bytes(1000)
data.force_encoding("UTF-8")
data = data.encode("UTF-16", :undef => :replace, :invalid => :replace, :replace => '')
expect(data).to_not eq(nil)
end
end
end unless RUBY_VERSION.index('1.8') == 0

View File

@ -0,0 +1,14 @@
require 'rspec'
require 'date'
# https://github.com/jruby/jruby/issues/2883
if RUBY_VERSION > '1.9'
describe 'DateTime.iso8601' do
it 'correctly parses fraction of a second' do
date = DateTime.iso8601('2014-07-08T17:51:36.013Z')
date.sec_fraction.should == Rational(13, 1000)
date.second_fraction.should == Rational(13, 1000)
end
end
end

View File

@ -24,13 +24,13 @@ class TestDir < Test::Unit::TestCase
# JRUBY-2519
def test_dir_instance_should_not_cache_dir_contents
require 'fileutils'
require 'tmpdir'
testdir = File.join(Dir.tmpdir, Process.pid.to_s)
FileUtils.mkdir_p testdir
FileUtils.touch File.join(testdir, 'fileA.txt')
dir = Dir.new(testdir)
FileUtils.touch File.join(testdir, 'fileB.txt')
@ -38,8 +38,8 @@ class TestDir < Test::Unit::TestCase
assert_equal 'fileA.txt', dir.find {|item| item == 'fileA.txt' }
assert_equal 'fileB.txt', dir.find {|item| item == 'fileB.txt' }
end
end
def test_pwd_and_getwd_equivalent
assert_equal(Dir.pwd, Dir.getwd)
end
@ -72,7 +72,7 @@ class TestDir < Test::Unit::TestCase
end
def test_bogus_glob
# Test unescaped special char that is meant to be used with another
# Test unescaped special char that is meant to be used with another
# (i.e. bogus glob pattern)
assert_equal([], Dir.glob("{"))
end
@ -83,7 +83,7 @@ class TestDir < Test::Unit::TestCase
end
def test_glob_double_star
# Test that glob expansion of ** works ok with non-patterns as path
# Test that glob expansion of ** works ok with non-patterns as path
# elements. This used to throw NPE.
Dir.mkdir("testDir_2")
open("testDir_2/testDir_tmp1", "w").close
@ -114,6 +114,10 @@ class TestDir < Test::Unit::TestCase
Dir["blahtest/test_argf.rb"[4..-1]]
end
def test_glob_empty_parens
assert_equal [], Dir['{}'] # #2922 throwing AIOoBE is <= 1.7.20
end
# http://jira.codehaus.org/browse/JRUBY-300
def test_chdir_and_pwd
java_test_classes = File.expand_path(File.dirname(__FILE__) + '/../target/test-classes')
@ -124,7 +128,7 @@ class TestDir < Test::Unit::TestCase
pwd.gsub! '\\', '/'
assert_equal("testDir_4", pwd.split("/")[-1].strip)
if (ENV_JAVA['jruby.home'] and not
if (ENV_JAVA['jruby.home'] and not
ENV_JAVA['jruby.home'].match( /!\// ) and not
ENV_JAVA['jruby.home'].match( /:\// ))
pwd = `#{ENV_JAVA['jruby.home']}/bin/jruby -e "puts Dir.pwd"`
@ -218,7 +222,7 @@ class TestDir < Test::Unit::TestCase
# JRUBY-4983
def test_entries_unicode
utf8_dir = "testDir_1/glk\u00a9"
Dir.mkdir("./testDir_1")
Dir.mkdir(utf8_dir)
@ -270,7 +274,7 @@ class TestDir < Test::Unit::TestCase
def test_chdir_exceptions_windows
orig_pwd = Dir.pwd
assert_raise(Errno::EINVAL) {
Dir.chdir('//') # '//' is not a valid thing on Windows
Dir.chdir('//') # '//' is not a valid thing on Windows
}
assert_raise(Errno::ENOENT) {
Dir.chdir('//blah-blah-blah') # doesn't exist
@ -290,7 +294,7 @@ class TestDir < Test::Unit::TestCase
ensure
Dir.chdir(orig_pwd)
end
def test_new_windows
slashes = ['/', '\\']
slashes.each { |slash|
@ -307,7 +311,7 @@ class TestDir < Test::Unit::TestCase
assert_equal(drive_root_entries, slash_entries, "slash - #{slash}")
}
end
def test_new_with_drive_letter
current_drive_letter = Dir.pwd[0..2]
@ -319,7 +323,7 @@ class TestDir < Test::Unit::TestCase
Dir.new(current_drive_letter + "\\").entries,
Dir.new(current_drive_letter).entries)
end
def test_entries_with_drive_letter
current_drive_letter = Dir.pwd[0..2]
@ -331,7 +335,7 @@ class TestDir < Test::Unit::TestCase
Dir.entries(current_drive_letter + "\\"),
Dir.entries(current_drive_letter))
end
def test_open_windows
slashes = ['/', '\\']
slashes.each { |slash|
@ -348,13 +352,13 @@ class TestDir < Test::Unit::TestCase
assert_equal(drive_root_entries, slash_entries, "slash - #{slash}")
}
end
def test_dir_new_exceptions_windows
assert_raise(Errno::ENOENT) {
Dir.new('')
}
assert_raise(Errno::EINVAL) {
Dir.new('//') # '//' is not a valid thing on Windows
Dir.new('//') # '//' is not a valid thing on Windows
}
assert_raise(Errno::ENOENT) {
Dir.new('//blah-blah-blah') # doesn't exist
@ -372,7 +376,7 @@ class TestDir < Test::Unit::TestCase
Dir.new('\\\\\\') # doesn't exist
}
end
def test_entries_windows
slashes = ['/', '\\']
slashes.each { |slash|
@ -388,7 +392,7 @@ class TestDir < Test::Unit::TestCase
Dir.entries('')
}
assert_raise(Errno::EINVAL) {
Dir.entries('//') # '//' is not a valid thing on Windows
Dir.entries('//') # '//' is not a valid thing on Windows
}
assert_raise(Errno::ENOENT) {
Dir.entries('//blah-blah-blah') # doesn't exist
@ -447,11 +451,11 @@ class TestDir < Test::Unit::TestCase
require 'pathname'
win_dir = nil
if FileTest.exist?('C:/windows')
win_dir = "windows"
win_dir = "windows"
elsif FileTest.exist?('C:/winnt')
win_dir = "winnt"
win_dir = "winnt"
end
if (win_dir != nil)
Pathname.new("C:\\#{win_dir}").realpath.to_s
Pathname.new("C:\\#{win_dir}\\..\\#{win_dir}").realpath.to_s

View File

@ -57,7 +57,7 @@ class TestKernel < Test::Unit::TestCase
def test_Array_should_use_to_ary_and_make_sure_that_it_returns_either_array_or_nil
assert_equal [1], Kernel.Array(ToAryReturnsAnArray.new)
assert_raises(TypeError) { Kernel.Array(ToAryReturnsAnInteger.new) }
assert_raises(TypeError) { Kernel.Array(ToAryReturnsAnInteger.new) }
end
class BothToAryAndToADefined; def to_ary() [3] end; def to_a() raise "to_a() should not be called" end; end
@ -71,7 +71,7 @@ class TestKernel < Test::Unit::TestCase
def test_Array_should_return_array_containing_argument_if_the_argument_has_neither_to_ary_nor_to_a
assert_equal [1], Kernel.Array(1)
assert_equal [:foo], Kernel.Array(:foo)
obj = NeitherToANorToAryDefined.new
obj = NeitherToANorToAryDefined.new
assert_equal [obj], Kernel.Array(obj)
end
@ -142,7 +142,7 @@ class TestKernel < Test::Unit::TestCase
end
been_at_fred2 = true
end
assert been_at_fred2
assert been_at_fred2
end
def test_invalid_throw_after_inner_catch_should_unwind_the_stack_all_the_way_to_the_top
@ -200,8 +200,8 @@ class TestKernel < Test::Unit::TestCase
Kernel.eval("new_variable = another_variable = existing_variable")
assert_equal 0, existing_variable
assert_equal 0, another_variable
assert_equal 0, existing_variable
assert_equal 0, another_variable
assert !(defined? new_variable)
end
@ -214,7 +214,7 @@ class TestKernel < Test::Unit::TestCase
# fork
def test_format
assert_equal "Hello, world", Kernel.format("Hello, %s", "world")
assert_equal "Hello, world", Kernel.format("Hello, %s", "world")
assert_raises(TypeError) { Kernel.format("%01.3f", nil) }
end
@ -360,8 +360,8 @@ class TestKernel < Test::Unit::TestCase
def test_sleep
assert_raises(ArgumentError) { sleep(-10) }
# FIXME: below is true for MRI, but not for JRuby
# assert_raises(TypeError) { sleep "foo" }
assert_raises(TypeError) { sleep "foo" }
assert_equal 0, sleep(0)
t1 = Time.now
sleep(0.1)
@ -370,6 +370,63 @@ class TestKernel < Test::Unit::TestCase
assert t2 >= t1 + 0.08
end
class SecDuration
def initialize(value); @value = value end
def respond_to?(name)
@value.respond_to?(name)
end
private
def method_missing(method, *args, &block)
@value.send(method, *args, &block)
end
end
def test_sleep_arg
sleep SecDuration.new(0.01)
begin
sleep SecDuration.new(-0.01)
rescue ArgumentError => e
assert_equal "time interval must be positive", e.message
else
fail 'argument error expected'
end
begin
sleep []
rescue TypeError => e
assert_equal "can't convert Array into time interval", e.message
else
fail 'type error expected'
end
end
class SecDuration19
def initialize(value); @value = value end
def respond_to_missing?(name, include_private = false)
@value.respond_to?(name)
end
private
def method_missing(method, *args, &block)
@value.send(method, *args, &block)
end
end
def test_sleep_arg19
sleep(SecDuration19.new(0.10))
assert_raises(ArgumentError) { sleep(SecDuration19.new(-0.01)) }
end
def test_sprintf
assert_equal 'Hello', Kernel.sprintf('Hello')
end
@ -497,20 +554,19 @@ class TestKernel < Test::Unit::TestCase
end
# JRUBY-4834
# GH #2047 backquote fails with null byte ArgumentError
# def test_backquote_with_changed_path
# orig_env = ENV['PATH']
def test_backquote_with_changed_path
orig_env = ENV['PATH']
# # Append a directory where testapp resides to the PATH
# paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR)
# paths.unshift TESTAPP_DIR
# ENV["PATH"] = paths.uniq.join(File::PATH_SEPARATOR)
# Append a directory where testapp resides to the PATH
paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR)
paths.unshift TESTAPP_DIR
ENV["PATH"] = paths.uniq.join(File::PATH_SEPARATOR)
# res = `testapp`.chomp
# assert_equal("NO_ARGS", res)
# ensure
# ENV['PATH'] = orig_env
# end
res = `testapp`.chomp
assert_equal("NO_ARGS", res)
ensure
ENV['PATH'] = orig_env
end
# JRUBY-4127
def test_backquote_with_quotes
@ -545,20 +601,19 @@ class TestKernel < Test::Unit::TestCase
assert_equal(expected, result)
end
# GH #2047 backquote fails with null byte ArgumentError
# def test_backquote2
# TESTAPPS.each { |app|
# if (app =~ /\/.*\.bat/ && Pathname.new(app).relative?)
# # MRI can't launch relative BAT files with / in their paths
# log "-- skipping #{app}"
# next
# end
# log "testing #{app}"
def test_backquote2
TESTAPPS.each { |app|
if (app =~ /\/.*\.bat/ && Pathname.new(app).relative?)
# MRI can't launch relative BAT files with / in their paths
log "-- skipping #{app}"
next
end
log "testing #{app}"
# result = `#{app}`.strip
# assert_equal('NO_ARGS', result, "Can't properly launch '#{app}'")
# }
# end
result = `#{app}`.strip
assert_equal('NO_ARGS', result, "Can't properly launch '#{app}'")
}
end
def test_backquote2_1
TESTAPPS.each { |app|
@ -683,7 +738,7 @@ class TestKernel < Test::Unit::TestCase
next
end
log "testing #{app}"
if (TESTAPP_DIR =~ /\s/) # spaces in paths, quote!
app = '"' + app + '"'
end

View File

@ -23,7 +23,7 @@ class TestRespondToConcurrency < Test::Unit::TestCase
attr_reader :hashable_methods
def method_added(method_name)
@hashable_methods ||= []
@hashable_methods << {:method_name => method_name, :key => method_name.to_s }
@hashable_methods << {:method_name => method_name, :key => method_name.to_s }
end
end
end
@ -85,7 +85,7 @@ class TestRespondToViaMethodMissing < Test::Unit::TestCase
instance_methods.each do |m|
undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
end
attr_accessor :respond_to_called
def method_missing(name, *args)
@ -127,4 +127,42 @@ class TestRespondToMissingFastPath < Test::Unit::TestCase
obj = Duration.new
assert(10 * obj == 100)
end
end
class TestRespondToMissing < Test::Unit::TestCase
class Foo
def respond_to_missing?(method, private = false)
return true if method.to_s == 'foo'
super(method, private)
end
def method_missing(method, *args)
return method if method.to_s == 'foo'
super
end
end
def test_respond_to_missing
obj = Foo.new
assert obj.respond_to?(:to_s)
assert ! obj.respond_to?(:fo)
assert obj.respond_to?(:foo)
assert_equal :foo, obj.foo
end
class Bar
def respond_to_missing?(method, private = false)
method.eql? :bar
end
end
def test_respond_to_missing_gets_a_symbol_name
obj = Bar.new
assert obj.respond_to?(:bar)
assert ! obj.respond_to?(:ba)
assert obj.respond_to?('bar')
end
end

View File

@ -4,6 +4,7 @@ require 'socket'
require 'net/http'
class TestTimeout < Test::Unit::TestCase
def test_timeout_for_loop
n = 10000000
assert_raises(Timeout::Error) do
@ -13,7 +14,7 @@ class TestTimeout < Test::Unit::TestCase
def do_timeout(time, count, pass_expected, timeout_expected = 0, &block)
pass = timeout = error = 0
count.times do |i|
count.times do
begin
Timeout::timeout(time, &block)
pass += 1
@ -70,7 +71,7 @@ class TestTimeout < Test::Unit::TestCase
assert_raises Net::OpenTimeout do
http = Net::HTTP.new('8.8.8.8')
http.open_timeout = 0.001
response = http.start do |h|
http.start do |h|
h.request_get '/index.html'
# ensure we timeout even if we're fast
sleep(0.01)
@ -145,4 +146,42 @@ class TestTimeout < Test::Unit::TestCase
assert_equal expected, result
end
class Seconds
attr_reader :value
def initialize(value); @value = value end
def self.===(other); other.is_a?(Seconds) end
def ==(other)
if Seconds === other
other.value == value
else
other == value
end
end
def eql?(other); other.is_a?(Seconds) && self == other end
def divmod(divisor)
value.divmod(divisor)
end
private
def method_missing(method, *args, &block)
value.send(method, *args, &block)
end
end
def test_timeout_interval_argument
assert_equal 42, Timeout::timeout(Seconds.new(2)) { 42 }
assert_raises(Timeout::Error) do
Timeout::timeout(Seconds.new(0.3)) { sleep(0.5) }
end
end
end