Example #1
0
 private static final long longValue(RubyString parameter) {
   CharSequence cs = parameter.asJavaString();
   if (cs.length() == 1) {
     return cs.charAt(0);
   }
   throw parameter.getRuntime().newRangeError("Value " + parameter + " is not an integer");
 }
Example #2
0
  /**
   * Evaluate the given string.
   *
   * @param context the current thread's context
   * @param self the self to evaluate under
   * @param src The string containing the text to be evaluated
   * @param file The filename to use when reporting errors during the evaluation
   * @param lineNumber that the eval supposedly starts from
   * @return An IRubyObject result from the evaluation
   */
  public static IRubyObject evalSimple(
      ThreadContext context, IRubyObject self, RubyString src, String file, int lineNumber) {
    // this is ensured by the callers
    assert file != null;

    Ruby runtime = src.getRuntime();

    // no binding, just eval in "current" frame (caller's frame)
    RubyString source = src.convertToString();

    DynamicScope evalScope = context.getCurrentScope().getEvalScope(runtime);
    evalScope.getStaticScope().determineModule();

    try {
      Node node = runtime.parseEval(source.getByteList(), file, evalScope, lineNumber);

      if (runtime.getInstanceConfig().getCompileMode() == CompileMode.OFFIR) {
        // SSS FIXME: AST interpreter passed both a runtime (which comes from the source string)
        // and the thread-context rather than fetch one from the other.  Why is that?
        return Interpreter.interpretSimpleEval(runtime, file, lineNumber, "(eval)", node, self);
      } else {
        return INTERPRET_EVAL(
            runtime, context, file, lineNumber, node, "(eval)", self, Block.NULL_BLOCK);
      }
    } catch (JumpException.BreakJump bj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.BREAK, (IRubyObject) bj.getValue(), "unexpected break");
    } catch (StackOverflowError soe) {
      throw runtime.newSystemStackError("stack level too deep", soe);
    }
  }
Example #3
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;
  }
Example #4
0
  private static void addBackTraceElement(
      Ruby runtime, RubyArray backtrace, Frame frame, Frame previousFrame) {
    if (frame != previousFrame
        && // happens with native exceptions, should not filter those out
        frame.getLine() == previousFrame.getLine()
        && frame.getName() != null
        && frame.getName().equals(previousFrame.getName())
        && frame.getFile().equals(previousFrame.getFile())) {
      return;
    }

    RubyString traceLine;
    if (previousFrame.getName() != null) {
      traceLine =
          RubyString.newString(
              runtime,
              frame.getFile()
                  + ':'
                  + (frame.getLine() + 1)
                  + ":in `"
                  + previousFrame.getName()
                  + '\'');
    } else if (runtime.is1_9()) {
      // TODO: This probably isn't the best hack, but it works until we can have different
      // root frame setup for 1.9 easily.
      traceLine =
          RubyString.newString(
              runtime, frame.getFile() + ':' + (frame.getLine() + 1) + ":in `<main>'");
    } else {
      traceLine = RubyString.newString(runtime, frame.getFile() + ':' + (frame.getLine() + 1));
    }

    backtrace.append(traceLine);
  }
Example #5
0
  private static void addBackTraceElement(
      Ruby runtime,
      RubyArray backtrace,
      RubyStackTraceElement frame,
      RubyStackTraceElement previousFrame) {
    if (frame != previousFrame
        && // happens with native exceptions, should not filter those out
        frame.getLineNumber() == previousFrame.getLineNumber()
        && frame.getMethodName() != null
        && frame.getMethodName().equals(previousFrame.getMethodName())
        && frame.getFileName() != null
        && frame.getFileName().equals(previousFrame.getFileName())) {
      return;
    }

    RubyString traceLine;
    String fileName = frame.getFileName();
    if (fileName == null) fileName = "";
    if (previousFrame.getMethodName() == UNKNOWN_NAME) {
      traceLine = RubyString.newString(runtime, fileName + ':' + (frame.getLineNumber()));
    } else {
      traceLine =
          RubyString.newString(
              runtime,
              fileName
                  + ':'
                  + (frame.getLineNumber())
                  + ":in `"
                  + previousFrame.getMethodName()
                  + '\'');
    }

    backtrace.append(traceLine);
  }
 /**
  * Take the boolean value and convert it to its bytes.
  *
  * @param bool The Ruby boolean value.
  * @return The byte array.
  * @since 2.0.0
  */
 private static RubyString toBsonBoolean(final IRubyObject bool) {
   final Ruby runtime = bool.getRuntime();
   if (bool == runtime.getTrue()) {
     return RubyString.newString(runtime, TRUE_BYTES);
   } else {
     return RubyString.newString(runtime, FALSE_BYTES);
   }
 }
  // Make string based on internal data encoding (which ironically is its
  // external encoding.  This seems messy and we should consider a more
  // uniform method for makeing strings (we have a slightly different variant
  // of this in RubyIO.
  private RubyString makeString(Ruby runtime, ByteList buf) {
    if (runtime.is1_9()) buf.setEncoding(data.internal.getEncoding());

    RubyString str = RubyString.newString(runtime, buf);
    str.setTaint(true);

    return str;
  }
Example #8
0
  // Make string based on internal data encoding (which ironically is its
  // external encoding.  This seems messy and we should consider a more
  // uniform method for makeing strings (we have a slightly different variant
  // of this in RubyIO.
  private RubyString makeString(Ruby runtime, ByteList buf, boolean setEncoding) {
    if (runtime.is1_9() && setEncoding) buf.setEncoding(ptr.string.getEncoding());

    RubyString str = RubyString.newString(runtime, buf);
    str.setTaint(true);

    return str;
  }
Example #9
0
 public final RubyRegexp cacheRegexp(int index, RubyString pattern, int options) {
   RubyRegexp regexp = regexps[index];
   Ruby runtime = pattern.getRuntime();
   if (regexp == null || runtime.getKCode() != regexp.getKCode()) {
     regexp = RubyRegexp.newRegexp(runtime, pattern.getByteList(), options);
     regexps[index] = regexp;
   }
   return regexp;
 }
Example #10
0
 @JRubyMethod(name = "string=", required = 1)
 public IRubyObject set_string(IRubyObject arg) {
   checkFrozen();
   ptr.flags &= ~OpenFile.READWRITE;
   RubyString str = arg.convertToString();
   ptr.flags = str.isFrozen() ? OpenFile.READABLE : OpenFile.READWRITE;
   ptr.pos = 0;
   ptr.lineno = 0;
   return ptr.string = str;
 }
Example #11
0
 @JRubyMethod(
     name = {"push", "<<"},
     rest = true)
 public static IRubyObject s_push(IRubyObject recv, IRubyObject[] lines) throws Exception {
   ConsoleHolder holder = getHolder(recv.getRuntime());
   for (int i = 0; i < lines.length; i++) {
     RubyString line = lines[i].convertToString();
     holder.history.addToHistory(line.getUnicodeValue());
   }
   return recv.getRuntime().getNil();
 }
Example #12
0
 @JRubyMethod(name = "ruby=", required = 1)
 public IRubyObject ruby_set(final ThreadContext ctx, IRubyObject arg) {
   RubyString string;
   try {
     string = arg.convertToString();
   } catch (RaiseException re) {
     throw newTypeError(ctx.runtime, arg.getMetaClass(), "String");
   }
   ByteList bytes = string.getByteList();
   value.set(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getRealSize());
   return arg;
 }
Example #13
0
 public void testStrConvEncThatGrows() throws Exception {
   String javaStr = "--- こんにちは!";
   RubyString rubyStr = RubyString.newString(runtime, javaStr);
   rubyStr =
       EncodingUtils.strConvEnc(
           runtime.getCurrentContext(), rubyStr, rubyStr.getEncoding(), SJISEncoding.INSTANCE);
   assertEquals(rubyStr.getEncoding(), SJISEncoding.INSTANCE);
   rubyStr =
       EncodingUtils.strConvEnc(
           runtime.getCurrentContext(), rubyStr, SJISEncoding.INSTANCE, UTF8Encoding.INSTANCE);
   assertEquals(rubyStr.getEncoding(), UTF8Encoding.INSTANCE);
 }
Example #14
0
  /**
   * Evaluate the given string under the specified binding object. If the binding is not a Proc or
   * Binding object (RubyProc or RubyBinding) throw an appropriate type error.
   *
   * @param context the thread context for the current thread
   * @param self the self against which eval was called; used as self in the eval in 1.9 mode
   * @param src The string containing the text to be evaluated
   * @param binding The binding object under which to perform the evaluation
   * @return An IRubyObject result from the evaluation
   */
  public static IRubyObject evalWithBinding(
      ThreadContext context, IRubyObject self, IRubyObject src, Binding binding) {
    Ruby runtime = src.getRuntime();
    DynamicScope evalScope;

    if (runtime.is1_9()) {
      // in 1.9, eval scopes are local to the binding
      evalScope = binding.getEvalScope(runtime);
    } else {
      // in 1.8, eval scopes are local to the parent scope
      evalScope = binding.getDynamicScope().getEvalScope(runtime);
    }

    // FIXME:  This determine module is in a strange location and should somehow be in block
    evalScope.getStaticScope().determineModule();

    Frame lastFrame = context.preEvalWithBinding(binding);
    try {
      // Binding provided for scope, use it
      RubyString source = src.convertToString();
      Node node =
          runtime.parseEval(source.getByteList(), binding.getFile(), evalScope, binding.getLine());
      Block block = binding.getFrame().getBlock();

      if (runtime.getInstanceConfig().getCompileMode() == CompileMode.OFFIR) {
        // SSS FIXME: AST interpreter passed both a runtime (which comes from the source string)
        // and the thread-context rather than fetch one from the other.  Why is that?
        return Interpreter.interpretBindingEval(
            runtime, binding.getFile(), binding.getLine(), binding.getMethod(), node, self, block);
      } else {
        return INTERPRET_EVAL(
            runtime,
            context,
            binding.getFile(),
            binding.getLine(),
            node,
            binding.getMethod(),
            self,
            block);
      }
    } catch (JumpException.BreakJump bj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.BREAK, (IRubyObject) bj.getValue(), "unexpected break");
    } catch (JumpException.RedoJump rj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.REDO, (IRubyObject) rj.getValue(), "unexpected redo");
    } catch (StackOverflowError soe) {
      throw runtime.newSystemStackError("stack level too deep", soe);
    } finally {
      context.postEvalWithBinding(binding, lastFrame);
    }
  }
Example #15
0
 public static final void checkStringSafety(Ruby runtime, IRubyObject value) {
   RubyString s = value.asString();
   if (runtime.getSafeLevel() > 0 && s.isTaint()) {
     throw runtime.newSecurityError("Unsafe string parameter");
   }
   ByteList bl = s.getByteList();
   final byte[] array = bl.unsafeBytes();
   final int end = bl.length();
   for (int i = bl.begin(); i < end; ++i) {
     if (array[i] == (byte) 0) {
       throw runtime.newSecurityError("string contains null byte");
     }
   }
 }
Example #16
0
  @JRubyMethod(name = "sign")
  public IRubyObject sign(IRubyObject digest, IRubyObject data) {
    if (!this.callMethod(getRuntime().getCurrentContext(), "private?").isTrue()) {
      throw getRuntime().newArgumentError("Private key is needed.");
    }
    String digAlg = ((Digest) digest).getShortAlgorithm();
    try {
      Signature signature = SecurityHelper.getSignature(digAlg + "WITH" + getAlgorithm());
      signature.initSign(getPrivateKey());
      byte[] inp = data.convertToString().getBytes();
      signature.update(inp);
      byte[] sigge = signature.sign();
      return RubyString.newString(getRuntime(), sigge);
    } catch (GeneralSecurityException gse) {
      throw newPKeyError(getRuntime(), gse.getMessage());
    }
    /*
    GetPKey(self, pkey);
    EVP_SignInit(&ctx, GetDigestPtr(digest));
    StringValue(data);
    EVP_SignUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len);
    str = rb_str_new(0, EVP_PKEY_size(pkey)+16);
    if (!EVP_SignFinal(&ctx, RSTRING(str)->ptr, &buf_len, pkey))
    ossl_raise(ePKeyError, NULL);
    assert(buf_len <= RSTRING(str)->len);
    RSTRING(str)->len = buf_len;
    RSTRING(str)->ptr[buf_len] = 0;

    return str;
         */
  }
Example #17
0
    public final IRubyObject invoke(Ruby runtime, Function function, HeapInvocationBuffer args) {
      long address = invoker.invokeAddress(function, args);
      if (address == 0) {
        return runtime.getNil();
      }
      int len = (int) IO.getStringLength(address);
      if (len == 0) {
        return RubyString.newEmptyString(runtime);
      }
      byte[] bytes = new byte[len];
      IO.getByteArray(address, bytes, 0, len);

      RubyString s = RubyString.newStringShared(runtime, bytes);
      s.setTaint(true);
      return s;
    }
Example #18
0
  protected boolean tryLoadingLibraryOrScript(Ruby runtime, SearchState state) {
    // attempt to load the found library
    RubyString loadNameRubyString = RubyString.newString(runtime, state.loadName);
    try {
      synchronized (loadedFeaturesInternal) {
        if (loadedFeaturesInternal.contains(loadNameRubyString)) {
          return false;
        } else {
          addLoadedFeature(loadNameRubyString);
        }
      }

      // otherwise load the library we've found
      state.library.load(runtime, false);
      return true;
    } catch (MainExitException mee) {
      // allow MainExitException to propagate out for exec and friends
      throw mee;
    } catch (Throwable e) {
      if (isJarfileLibrary(state, state.searchFile)) {
        return true;
      }

      removeLoadedFeature(loadNameRubyString);
      reraiseRaiseExceptions(e);

      if (runtime.getDebug().isTrue()) e.printStackTrace(runtime.getErr());

      RaiseException re = newLoadErrorFromThrowable(runtime, state.searchFile, e);
      re.initCause(e);
      throw re;
    }
  }
Example #19
0
  public void testUnicodeChars() throws Exception {
    File file = new File("unicodeáéíóú");
    if (file.exists()) {
      if (!file.delete()) {
        fail("Unable to delete file: " + file);
      }
    }
    try {
      if (!file.mkdirs()) {
        fail("Unable to create directory: " + file);
      }
      Ruby runtime;
      RubyInstanceConfig.nativeEnabled = false;
      runtime = Ruby.newInstance();

      JRubyFile rubyFile = RubyFile.file(RubyString.newString(runtime, file.getAbsolutePath()));
      assertTrue(rubyFile.exists());
      assertTrue(file.exists());
      assertTrue(file.isDirectory());
      try {
        assertTrue(runtime.getPosix().stat(rubyFile.getAbsolutePath()).isDirectory());
      } catch (Exception e) {
        throw new RuntimeException("Expecting posix layer to work properly", e);
      }
    } finally {
      if (file.exists()) {
        file.delete();
      }
    }
  }
    @JRubyMethod
    public static IRubyObject rbuf_fill(IRubyObject recv) {
      RubyString buf = (RubyString) recv.getInstanceVariables().getInstanceVariable("@rbuf");
      RubyIO io = (RubyIO) recv.getInstanceVariables().getInstanceVariable("@io");

      int timeout =
          RubyNumeric.fix2int(recv.getInstanceVariables().getInstanceVariable("@read_timeout"))
              * 1000;
      NativeImpl nim = (NativeImpl) recv.dataGetStruct();

      Selector selector = null;
      synchronized (nim.channel.blockingLock()) {
        boolean oldBlocking = nim.channel.isBlocking();

        try {
          selector =
              SelectorFactory.openWithRetryFrom(recv.getRuntime(), SelectorProvider.provider());
          nim.channel.configureBlocking(false);
          SelectionKey key = nim.channel.register(selector, SelectionKey.OP_READ);
          int n = selector.select(timeout);

          if (n > 0) {
            IRubyObject readItems =
                io.read(new IRubyObject[] {recv.getRuntime().newFixnum(1024 * 16)});
            return buf.concat(readItems);
          } else {
            RubyClass exc =
                (RubyClass) (recv.getRuntime().getModule("Timeout").getConstant("Error"));
            throw new RaiseException(
                RubyException.newException(recv.getRuntime(), exc, "execution expired"), false);
          }
        } catch (IOException exception) {
          throw recv.getRuntime().newIOErrorFromException(exception);
        } finally {
          if (selector != null) {
            try {
              selector.close();
            } catch (Exception e) {
            }
          }
          try {
            nim.channel.configureBlocking(oldBlocking);
          } catch (IOException ioe) {
          }
        }
      }
    }
Example #21
0
 @JRubyMethod(name = "ruby=")
 public IRubyObject ruby_set(final ThreadContext ctx, IRubyObject arg) {
   RubyString string;
   try {
     string = arg.convertToString();
   } catch (RaiseException re) {
     throw newTypeError(ctx.runtime, arg.getMetaClass(), "String");
   }
   if (string.getEncoding() == UTF8Encoding.INSTANCE
       || string.getEncoding() == USASCIIEncoding.INSTANCE) {
     ByteList bytes = string.getByteList();
     value.set(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getRealSize());
   } else {
     value.set(string.toString());
   }
   return arg;
 }
Example #22
0
 @JRubyMethod
 public IRubyObject to_der() {
   try {
     return RubyString.newString(getRuntime(), crl_v.getEncoded());
   } catch (IOException ioe) {
     throw newX509CRLError(getRuntime(), ioe.getMessage());
   }
 }
  @JRubyMethod(name = "puts", rest = true)
  @Override
  public IRubyObject puts(ThreadContext context, IRubyObject[] args) {
    checkWritable();

    // FIXME: the code below is a copy of RubyIO.puts,
    // and we should avoid copy-paste.

    if (args.length == 0) {
      callMethod(context, "write", RubyString.newStringShared(getRuntime(), NEWLINE));
      return getRuntime().getNil();
    }

    for (int i = 0; i < args.length; i++) {
      RubyString line;

      if (args[i].isNil()) {
        line = getRuntime().newString("nil");
      } else {
        IRubyObject tmp = args[i].checkArrayType();
        if (!tmp.isNil()) {
          RubyArray arr = (RubyArray) tmp;
          if (getRuntime().isInspecting(arr)) {
            line = getRuntime().newString("[...]");
          } else {
            inspectPuts(context, arr);
            continue;
          }
        } else {
          if (args[i] instanceof RubyString) {
            line = (RubyString) args[i];
          } else {
            line = args[i].asString();
          }
        }
      }

      callMethod(context, "write", line);

      if (!line.getByteList().endsWith(NEWLINE)) {
        callMethod(context, "write", RubyString.newStringShared(getRuntime(), NEWLINE));
      }
    }
    return getRuntime().getNil();
  }
Example #24
0
 @JRubyMethod(name = "close")
 public IRubyObject close() {
   if (toEncoding == null && fromEncoding == null) {
     return getRuntime().getNil();
   }
   toEncoding = null;
   fromEncoding = null;
   return RubyString.newEmptyString(getRuntime());
 }
Example #25
0
  private IRubyObject iconv(IRubyObject str, int start, int end) {
    if (str.isNil()) {
      fromEncoding.reset();
      toEncoding.reset();
      return RubyString.newEmptyString(getRuntime());
    }

    return _iconv(str.convertToString(), start, end);
  }
Example #26
0
    public IRubyObject get(
        ThreadContext context, StructLayout.Storage cache, Member m, IRubyObject ptr) {
      MemoryIO io = m.getMemoryIO(ptr).getMemoryIO(m.getOffset(ptr));
      if (io == null || io.isNull()) {
        return context.getRuntime().getNil();
      }

      return RubyString.newStringNoCopy(context.getRuntime(), io.getZeroTerminatedByteArray(0));
    }
Example #27
0
 public void trySearch(SearchState state) throws AlreadyLoaded {
   for (String suffix : state.suffixType.getSuffixes()) {
     String searchName = state.searchFile + suffix;
     RubyString searchNameString = RubyString.newString(runtime, searchName);
     if (featureAlreadyLoaded(searchNameString)) {
       throw new AlreadyLoaded(searchNameString);
     }
   }
 }
Example #28
0
  private void strioInit(ThreadContext context, IRubyObject[] args) {
    Ruby runtime = context.runtime;
    RubyString string;
    IRubyObject mode;
    boolean trunc = false;

    switch (args.length) {
      case 2:
        mode = args[1];
        if (mode instanceof RubyFixnum) {
          int flags = RubyFixnum.fix2int(mode);
          ptr.flags = ModeFlags.getOpenFileFlagsFor(flags);
          trunc = (flags & ModeFlags.TRUNC) != 0;
        } else {
          String m = args[1].convertToString().toString();
          ptr.flags = OpenFile.ioModestrFmode(runtime, m);
          trunc = m.charAt(0) == 'w';
        }
        string = args[0].convertToString();
        if ((ptr.flags & OpenFile.WRITABLE) != 0 && string.isFrozen()) {
          throw runtime.newErrnoEACCESError("Permission denied");
        }
        if (trunc) {
          string.resize(0);
        }
        break;
      case 1:
        string = args[0].convertToString();
        ptr.flags = string.isFrozen() ? OpenFile.READABLE : OpenFile.READWRITE;
        break;
      case 0:
        string = RubyString.newEmptyString(runtime, runtime.getDefaultExternalEncoding());
        ptr.flags = OpenFile.READWRITE;
        break;
      default:
        throw runtime.newArgumentError(args.length, 2);
    }

    ptr.string = string;
    ptr.pos = 0;
    ptr.lineno = 0;
    // funky way of shifting readwrite flags into object flags
    flags |= (ptr.flags & OpenFile.READWRITE) * (STRIO_READABLE / OpenFile.READABLE);
  }
  @JRubyMethod
  public IRubyObject recv(ThreadContext context, IRubyObject _length) {
    Ruby runtime = context.runtime;

    ByteList bytes = doReceive(context, RubyNumeric.fix2int(_length));

    if (bytes == null) return context.nil;

    return RubyString.newString(runtime, bytes);
  }
Example #30
0
 @JRubyMethod(meta = true)
 public static IRubyObject encode(ThreadContext ctx, IRubyObject recv, IRubyObject data) {
   try {
     byte[] bytes = data.convertToString().getBytes();
     byte[] encoded = Hex.encode(bytes);
     return RubyString.newUsAsciiStringNoCopy(ctx.getRuntime(), new ByteList(encoded, false));
   } catch (RuntimeException ex) {
     throw Errors.newHexError(ctx.getRuntime(), ex.getMessage());
   }
 }