Beispiel #1
0
  /** 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);
  }
Beispiel #2
0
  /**
   * 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;
  }
Beispiel #3
0
  /**
   * 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);
      }
    }
  }
Beispiel #4
0
  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;
  }
Beispiel #5
0
  @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);
    }
  }
Beispiel #8
0
  @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;
  }
Beispiel #9
0
  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;
  }
Beispiel #10
0
  /**
   * 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);
      }
    }
  }