@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 void assign(Ruby runtime, ThreadContext context, IRubyObject self, Block block) {
    assignNilTo(runtime, context, self, block, 0);

    rest.assign(
        runtime, context, self, runtime.newArrayNoCopyLight(IRubyObject.NULL_ARRAY), block, true);
  }
  @Override
  public void assign(
      Ruby runtime, ThreadContext context, IRubyObject self, IRubyObject value1, Block block) {
    pre.get(0).assign(runtime, context, self, value1, block, false);

    assignNilTo(runtime, context, self, block, 1);

    rest.assign(
        runtime, context, self, runtime.newArrayNoCopyLight(IRubyObject.NULL_ARRAY), block, true);
  }
  @Override
  public void assign(
      Ruby runtime, ThreadContext context, IRubyObject self, IRubyObject values[], Block block) {
    int valueLength = values == null ? 0 : values.length;

    switch (valueLength) {
      case 0:
        assign(runtime, context, self, block);
        return;
      case 1:
        assign(runtime, context, self, values[0], block);
        return;
      case 2:
        assign(runtime, context, self, values[0], values[1], block);
        return;
      case 3:
        assign(runtime, context, self, values[0], values[1], values[2], block);
        return;
    }

    // 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[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,
          runtime.newArrayNoCopyLight(shiftedArray(values, valueLength - preLength)),
          block,
          true);
    }
  }