/** Compatibility with Tempfile#make_tmpname(basename, n) in MRI */ @JRubyMethod(visibility = PRIVATE) public IRubyObject make_tmpname( ThreadContext context, IRubyObject basename, IRubyObject n, Block block) { Ruby runtime = context.getRuntime(); IRubyObject[] newargs = new IRubyObject[5]; IRubyObject base, suffix; if (basename instanceof RubyArray) { RubyArray array = (RubyArray) basename; int length = array.getLength(); base = length > 0 ? array.eltInternal(0) : runtime.getNil(); suffix = length > 0 ? array.eltInternal(1) : runtime.getNil(); } else { base = basename; suffix = runtime.newString(""); } newargs[0] = runtime.newString("%s.%d.%d%s"); newargs[1] = base; newargs[2] = runtime.getGlobalVariables().get("$$"); // PID newargs[3] = n; newargs[4] = suffix; return callMethod(context, "sprintf", newargs); }
/** * this method uses the appropriate lookup strategy to find a file. It is used by Kernel#require. * * @mri rb_find_file * @param name the file to find, this is a path name * @return the correct file */ protected LoadServiceResource findFileInClasspath(String name) { // Look in classpath next (we do not use File as a test since UNC names will match) // Note: Jar resources must NEVER begin with an '/'. (previous code said "always begin with a // /") ClassLoader classLoader = runtime.getJRubyClassLoader(); // handle security-sensitive case if (Ruby.isSecurityRestricted() && classLoader == null) { classLoader = runtime.getInstanceConfig().getLoader(); } // absolute classpath URI, no need to iterate over loadpaths if (name.startsWith("classpath:/")) { LoadServiceResource foundResource = getClassPathResource(classLoader, name); if (foundResource != null) { return foundResource; } } else if (name.startsWith("classpath:")) { // "relative" classpath URI name = name.substring("classpath:".length()); } for (int i = 0; i < loadPath.size(); i++) { // TODO this is really inefficient, and potentially a problem everytime anyone require's // something. // we should try to make LoadPath a special array object. RubyString entryString = loadPath.eltInternal(i).convertToString(); String entry = entryString.asJavaString(); // if entry is an empty string, skip it if (entry.length() == 0) continue; // if entry starts with a slash, skip it since classloader resources never start with a / if (entry.charAt(0) == '/' || (entry.length() > 1 && entry.charAt(1) == ':')) continue; if (entry.startsWith("classpath:/")) { entry = entry.substring("classpath:/".length()); } else if (entry.startsWith("classpath:")) { entry = entry.substring("classpath:".length()); } // otherwise, try to load from classpath (Note: Jar resources always uses '/') LoadServiceResource foundResource = getClassPathResource(classLoader, entry + "/" + name); if (foundResource != null) { return foundResource; } } // if name starts with a / we're done (classloader resources won't load with an initial /) if (name.charAt(0) == '/' || (name.length() > 1 && name.charAt(1) == ':')) return null; // Try to load from classpath without prefix. "A/b.rb" will not load as // "./A/b.rb" in a jar file. LoadServiceResource foundResource = getClassPathResource(classLoader, name); if (foundResource != null) { return foundResource; } return null; }
/** * Assist with setting the parameter values on a PreparedStatement * * @param ps the PreparedStatement for which parameters should be set * @param recv * @param args an array of parameter values */ private static void prepareStatementFromArgs( PreparedStatement ps, IRubyObject recv, IRubyObject[] args) { int index = 1; try { for (IRubyObject arg : args) { // Handle multiple valued arguments, i.e. arrays + ranges if (arg instanceof RubyArray) { // Handle a RubyArray passed into a query // // NOTE: This should not call ps.setArray(i,v) as this is // designed to work with the SQL Array type, and in most cases // is not what we want. // Instead, this functionality is for breaking down a Ruby // array of ["a","b","c"] into SQL "('a','b','c')": // // So, in this case, we actually want to augment the number of // ? params in the PreparedStatement query appropriately. RubyArray array_value = arg.convertToArray(); for (int j = 0; j < array_value.getLength(); j++) { setPreparedStatementParam(ps, recv, array_value.eltInternal(j), index++); } } else if (arg instanceof RubyRange) { // Handle a RubyRange passed into a query // // NOTE: see above - need to augment the number of ? params // in the PreparedStatement: (? AND ?) RubyRange range_value = (RubyRange) arg; setPreparedStatementParam(ps, recv, range_value.first(), index++); setPreparedStatementParam(ps, recv, range_value.last(), index++); } else { // Otherwise, handle each argument setPreparedStatementParam(ps, recv, arg, index++); } } } catch (SQLException sqle) { // TODO: log sqle.printStackTrace(); // TODO: possibly move this exception string parsing somewhere else Pattern pattern = Pattern.compile( "Parameter index out of bounds. (\\d+) is not between valid values of (\\d+) and (\\d+)"); Matcher matcher = pattern.matcher(sqle.getMessage()); if (matcher.matches()) { throw recv.getRuntime() .newArgumentError( String.format( "Binding mismatch: %1$d for %2$d", Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)))); } else { throw DataObjectsUtils.newDriverError(recv.getRuntime(), errorName, sqle); } } }
private Object[] convertArguments(final RubyArray arguments) { final int argsSize = arguments.size(); final Object[] args = new Object[argsSize]; final Class<?>[] parameterTypes = getParameterTypes(); for (int i = 0; i < argsSize; i++) { args[i] = arguments.eltInternal(i).toJava(parameterTypes[i]); } return args; }
@JRubyMethod(backtrace = true) public IRubyObject java_send( ThreadContext context, IRubyObject rubyName, IRubyObject argTypes, IRubyObject arg0) { String name = rubyName.asJavaString(); RubyArray argTypesAry = argTypes.convertToArray(); Ruby runtime = context.getRuntime(); if (argTypesAry.size() != 1) { Class[] argTypesClasses = (Class[]) argTypesAry.toArray(new Class[argTypesAry.size()]); throw JavaMethod.newArgSizeMismatchError(runtime, argTypesClasses); } Class argTypeClass = (Class) argTypesAry.eltInternal(0).toJava(Class.class); JavaMethod method = new JavaMethod(runtime, getMethod(name, argTypeClass)); return method.invokeDirect(getObject(), arg0.toJava(argTypeClass)); }
@Override public IRubyObject replace(IRubyObject orig) { if (!packed()) return super.replace(orig); modifyCheck(); RubyArray origArr = orig.convertToArray(); if (this == orig) return this; if (origArr.size() == 1) { value = origArr.eltInternal(0); return this; } unpack(); return super.replace(origArr); }
@Override public void assignArray( Ruby runtime, ThreadContext context, IRubyObject self, IRubyObject arg, Block block) { RubyArray values = (RubyArray) arg; int valueLength = values.getLength(); switch (valueLength) { case 0: assign(runtime, context, self, block); break; case 1: assign(runtime, context, self, values.eltInternal(0), block); break; case 2: assign(runtime, context, self, values.eltInternal(0), values.eltInternal(1), block); break; case 3: assign( runtime, context, self, values.eltInternal(0), values.eltInternal(1), values.eltInternal(2), block); break; } // Populate up to shorter of calling arguments or local parameters in the block for (int i = 0; i < preLength && i < valueLength; i++) { pre.get(i).assign(runtime, context, self, values.eltInternal(i), block, false); } // nil pad since we provided less values than block parms if (valueLength < preLength) { assignNilTo(runtime, context, self, block, valueLength); } else if (valueLength == preLength) { // no extra args for rest rest.assign( runtime, context, self, runtime.newArrayNoCopyLight(IRubyObject.NULL_ARRAY), block, true); } else { // extra args for rest rest.assign( runtime, context, self, values.subseqLight(preLength, valueLength - preLength), block, true); } }
@Override public Object interpret( ThreadContext context, IRubyObject self, IRubyObject[] args, Block block, Object exception, Object[] temp) { IRubyObject receiver = (IRubyObject) arg1.retrieve(context, self, temp); IRubyObject value = (IRubyObject) arg2.retrieve(context, self, temp); if (value == UndefinedValue.UNDEFINED) { result.store(context, self, temp, receiver); } else if (receiver instanceof RubyArray) { RubyArray testVals = (RubyArray) receiver; for (int i = 0, n = testVals.getLength(); i < n; i++) { IRubyObject excType = (IRubyObject) testVals.eltInternal(i); if (!(excType instanceof RubyModule)) { throw context .getRuntime() .newTypeError("class or module required for rescue clause. Found: " + excType); } IRubyObject eqqVal = excType.callMethod(context, "===", value); if (eqqVal.isTrue()) { result.store(context, self, temp, eqqVal); return null; } } result.store(context, self, temp, context.getRuntime().newBoolean(false)); } else { if (!(receiver instanceof RubyModule)) { throw context .getRuntime() .newTypeError("class or module required for rescue clause. Found: " + receiver); } result.store(context, self, temp, receiver.callMethod(context, "===", value)); } return null; }
protected LoadServiceResource tryResourceFromLoadPathOrURL( SearchState state, String baseName, SuffixType suffixType) { LoadServiceResource foundResource = null; // if it's a ./ baseName, use CWD logic if (baseName.startsWith("./")) { foundResource = tryResourceFromCWD(state, baseName, suffixType); if (foundResource != null) { state.loadName = resolveLoadName(foundResource, foundResource.getName()); return foundResource; } } // if it's a ~/ baseName use HOME logic if (baseName.startsWith("~/")) { foundResource = tryResourceFromHome(state, baseName, suffixType); if (foundResource != null) { state.loadName = resolveLoadName(foundResource, foundResource.getName()); return foundResource; } } // if given path is absolute, just try it as-is (with extensions) and no load path if (new File(baseName).isAbsolute() || baseName.startsWith("../")) { for (String suffix : suffixType.getSuffixes()) { String namePlusSuffix = baseName + suffix; foundResource = tryResourceAsIs(namePlusSuffix); if (foundResource != null) { state.loadName = resolveLoadName(foundResource, namePlusSuffix); return foundResource; } } return null; } Outer: for (int i = 0; i < loadPath.size(); i++) { // TODO this is really inefficient, and potentially a problem everytime anyone require's // something. // we should try to make LoadPath a special array object. RubyString entryString = loadPath.eltInternal(i).convertToString(); String loadPathEntry = entryString.asJavaString(); if (loadPathEntry.equals(".") || loadPathEntry.equals("")) { foundResource = tryResourceFromCWD(state, baseName, suffixType); if (foundResource != null) { String ss = foundResource.getName(); if (ss.startsWith("./")) { ss = ss.substring(2); } state.loadName = resolveLoadName(foundResource, ss); break Outer; } } else { boolean looksLikeJarURL = loadPathLooksLikeJarURL(loadPathEntry); for (String suffix : suffixType.getSuffixes()) { String namePlusSuffix = baseName + suffix; if (looksLikeJarURL) { foundResource = tryResourceFromJarURLWithLoadPath(namePlusSuffix, loadPathEntry); } else if (namePlusSuffix.startsWith("./")) { throw runtime.newLoadError(""); } else { foundResource = tryResourceFromLoadPath(namePlusSuffix, loadPathEntry); } if (foundResource != null) { String ss = namePlusSuffix; if (ss.startsWith("./")) { ss = ss.substring(2); } state.loadName = resolveLoadName(foundResource, ss); break Outer; // end suffix iteration } } } } return foundResource; }
/** * Assist with setting the parameter values on a PreparedStatement * * @param sqlText * @param ps the PreparedStatement for which parameters should be set * @param args an array of parameter values * @return true if there is return parameter, false if there is not */ private boolean prepareStatementFromArgs( String sqlText, PreparedStatement ps, IRubyObject[] args) { int index = 1; boolean hasReturnParam = false; try { int psCount = ps.getParameterMetaData().getParameterCount(); // fail fast if (args.length > psCount) { throw getRuntime().newArgumentError("Binding mismatch: " + args.length + " for " + psCount); } for (IRubyObject arg : args) { // Handle multiple valued arguments, i.e. arrays + ranges if (arg instanceof RubyArray) { // Handle a RubyArray passed into a query // // NOTE: This should not call ps.setArray(i,v) as this is // designed to work with the SQL Array type, and in most cases // is not what we want. // Instead, this functionality is for breaking down a Ruby // array of ["a","b","c"] into SQL "('a','b','c')": // // So, in this case, we actually want to augment the number of // ? params in the PreparedStatement query appropriately. RubyArray arrayValues = arg.convertToArray(); for (int j = 0; j < arrayValues.getLength(); j++) { driver.setPreparedStatementParam(ps, arrayValues.eltInternal(j), index++); } } else if (arg instanceof RubyRange) { // Handle a RubyRange passed into a query // // NOTE: see above - need to augment the number of ? params // in the PreparedStatement: (? AND ?) RubyRange range_value = (RubyRange) arg; driver.setPreparedStatementParam(ps, range_value.first(), index++); driver.setPreparedStatementParam(ps, range_value.last(), index++); } else { // Otherwise, handle each argument driver.setPreparedStatementParam(ps, arg, index++); } } // callback for binding RETURN ... INTO ... output parameter if (driver.registerPreparedStatementReturnParam(sqlText, ps, index)) { index++; hasReturnParam = true; } if ((index - 1) < psCount) { throw getRuntime().newArgumentError("Binding mismatch: " + (index - 1) + " for " + psCount); } return hasReturnParam; } catch (SQLException sqle) { // TODO: possibly move this exception string parsing somewhere else Pattern pattern = Pattern.compile( "Parameter index out of bounds. (\\d+) is not between valid values of (\\d+) and (\\d+)"); // POSTGRES: The column index is out of range: 2, number of columns: 1. // POSTGRES SQL STATE: 22023 (22023 "INVALID PARAMETER VALUE" invalid_parameter_value) // SQLITE3: Does not throw a SQLException! // H2: Invalid value 2 for parameter parameterIndex [90008-63] // HSQLDB: Invalid argument in JDBC call: parameter index out of range: 2 // DERBY: The parameter position '2' is out of range. The number of parameters for this // prepared statement is '1' // DERbY SQL CODE: XCL13 Matcher matcher = pattern.matcher(sqle.getMessage()); if (matcher.matches()) { throw getRuntime() .newArgumentError( String.format( "Binding mismatch: %1$d for %2$d", Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)))); } else { throw Errors.newSqlError(getRuntime(), driver, sqle); } } }