aboutsummaryrefslogtreecommitdiffhomepage
path: root/ruby/src
diff options
context:
space:
mode:
authorGravatar Adam Greene <adam.greene@gmail.com>2015-05-03 20:42:11 -0700
committerGravatar Adam Greene <adam.greene@gmail.com>2015-05-14 10:38:11 -0700
commitcd7ebbe54f16999b74c2c32a64336bad131ec5f3 (patch)
treead8be4705dbdbc6d88a433948195ee84480969eb /ruby/src
parent5bd8b680bad38ef40b838ce0de05aac5465d04c0 (diff)
make repeated_field quack like an array
Diffstat (limited to 'ruby/src')
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java43
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java136
2 files changed, 107 insertions, 72 deletions
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
index 38226c4e..f3c488bc 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
@@ -73,6 +73,17 @@ public class RubyFieldDescriptor extends RubyObject {
/*
* call-seq:
+ * FieldDescriptor.label
+ *
+ * Return the label of this field.
+ */
+ @JRubyMethod(name = "label")
+ public IRubyObject getLabel(ThreadContext context) {
+ return this.label;
+ }
+
+ /*
+ * call-seq:
* FieldDescriptor.label = label
*
* Sets the label on this field. Cannot be called if field is part of a message
@@ -80,8 +91,10 @@ public class RubyFieldDescriptor extends RubyObject {
*/
@JRubyMethod(name = "label=")
public IRubyObject setLabel(ThreadContext context, IRubyObject value) {
+ String labelName = value.asJavaString();
+ this.label = context.runtime.newSymbol(labelName.toLowerCase());
this.builder.setLabel(
- DescriptorProtos.FieldDescriptorProto.Label.valueOf("LABEL_" + value.asJavaString().toUpperCase()));
+ DescriptorProtos.FieldDescriptorProto.Label.valueOf("LABEL_" + labelName.toUpperCase()));
return context.runtime.getNil();
}
@@ -89,18 +102,13 @@ public class RubyFieldDescriptor extends RubyObject {
* call-seq:
* FieldDescriptor.name => name
*
- * Returns the name of this field.
+ * Returns the name of this field as a Ruby String, or nil if it is not set.
*/
@JRubyMethod(name = "name")
public IRubyObject getName(ThreadContext context) {
return this.name;
}
- @JRubyMethod(name = "subtype")
- public IRubyObject getSubType(ThreadContext context) {
- return subType;
- }
-
/*
* call-seq:
* FieldDescriptor.name = name
@@ -116,6 +124,12 @@ public class RubyFieldDescriptor extends RubyObject {
return context.runtime.getNil();
}
+
+ @JRubyMethod(name = "subtype")
+ public IRubyObject getSubType(ThreadContext context) {
+ return subType;
+ }
+
/*
* call-seq:
* FieldDescriptor.type => type
@@ -146,6 +160,18 @@ public class RubyFieldDescriptor extends RubyObject {
/*
* call-seq:
+ * FieldDescriptor.number => number
+ *
+ * Returns this field's number, as a Ruby Integer, or nil if not yet set.
+ *
+ */
+ @JRubyMethod(name = "number")
+ public IRubyObject getnumber(ThreadContext context) {
+ return this.number;
+ }
+
+ /*
+ * call-seq:
* FieldDescriptor.number = number
*
* Sets the tag number for this field. Cannot be called if field is part of a
@@ -153,6 +179,7 @@ public class RubyFieldDescriptor extends RubyObject {
*/
@JRubyMethod(name = "number=")
public IRubyObject setNumber(ThreadContext context, IRubyObject value) {
+ this.number = value;
this.builder.setNumber(RubyNumeric.num2int(value));
return context.runtime.getNil();
}
@@ -240,6 +267,8 @@ public class RubyFieldDescriptor extends RubyObject {
private DescriptorProtos.FieldDescriptorProto.Builder builder;
private IRubyObject name;
+ private IRubyObject label;
+ private IRubyObject number;
private IRubyObject subType;
private IRubyObject oneofName;
private Descriptors.FieldDescriptor fieldDef;
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
index 84bf8956..946f9e74 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
@@ -40,6 +40,7 @@ import org.jruby.runtime.Block;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
+import java.util.Arrays;
@JRubyClass(name = "RepeatedClass", include = "Enumerable")
public class RubyRepeatedField extends RubyObject {
@@ -110,6 +111,10 @@ public class RubyRepeatedField extends RubyObject {
public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) {
int arrIndex = normalizeArrayIndex(index);
Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+ IRubyObject defaultValue = defaultValue(context);
+ for (int i = this.storage.size(); i < arrIndex; i++) {
+ this.storage.set(i, defaultValue);
+ }
this.storage.set(arrIndex, value);
return context.runtime.getNil();
}
@@ -120,27 +125,35 @@ public class RubyRepeatedField extends RubyObject {
*
* Accesses the element at the given index. Returns nil on out-of-bounds
*/
- @JRubyMethod(name = "[]")
- public IRubyObject index(ThreadContext context, IRubyObject index) {
- int arrIndex = normalizeArrayIndex(index);
- if (arrIndex < 0 || arrIndex >= this.storage.size()) {
- return context.runtime.getNil();
+ @JRubyMethod(required=1, optional=1, name = {"at", "[]"})
+ public IRubyObject index(ThreadContext context, IRubyObject[] args) {
+ if (args.length == 1){
+ IRubyObject arg = args[0];
+ if (Utils.isRubyNum(arg)) {
+ /* standard case */
+ int arrIndex = normalizeArrayIndex(arg);
+ if (arrIndex < 0 || arrIndex >= this.storage.size()) {
+ return context.runtime.getNil();
+ }
+ return this.storage.eltInternal(arrIndex);
+ } else if (arg instanceof RubyRange) {
+ RubyRange range = ((RubyRange) arg);
+ int beg = RubyNumeric.num2int(range.first(context));
+ int to = RubyNumeric.num2int(range.last(context));
+ int len = to - beg + 1;
+ return this.storage.subseq(beg, len);
+ }
}
- return this.storage.eltInternal(arrIndex);
- }
-
- /*
- * call-seq:
- * RepeatedField.insert(*args)
- *
- * Pushes each arg in turn onto the end of the repeated field.
- */
- @JRubyMethod(rest = true)
- public IRubyObject insert(ThreadContext context, IRubyObject[] args) {
- for (int i = 0; i < args.length; i++) {
- push(context, args[i]);
+ /* assume 2 arguments */
+ int beg = RubyNumeric.num2int(args[0]);
+ int len = RubyNumeric.num2int(args[1]);
+ if (beg < 0) {
+ beg += this.storage.size();
}
- return context.runtime.getNil();
+ if (beg >= this.storage.size()) {
+ return context.runtime.getNil();
+ }
+ return this.storage.subseq(beg, len);
}
/*
@@ -151,20 +164,19 @@ public class RubyRepeatedField extends RubyObject {
*/
@JRubyMethod(name = {"push", "<<"})
public IRubyObject push(ThreadContext context, IRubyObject value) {
- Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+ if (!(fieldType == Descriptors.FieldDescriptor.Type.MESSAGE &&
+ value == context.runtime.getNil())) {
+ Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+ }
this.storage.add(value);
- return this;
+ return this.storage;
}
/*
- * call-seq:
- * RepeatedField.pop => value
- *
- * Removes the last element and returns it. Throws an exception if the repeated
- * field is empty.
+ * private Ruby method used by RepeatedField.pop
*/
- @JRubyMethod
- public IRubyObject pop(ThreadContext context) {
+ @JRubyMethod(visibility = org.jruby.runtime.Visibility.PRIVATE)
+ public IRubyObject pop_one(ThreadContext context) {
IRubyObject ret = this.storage.last();
this.storage.remove(ret);
return ret;
@@ -181,7 +193,7 @@ public class RubyRepeatedField extends RubyObject {
RubyArray arr = (RubyArray) list;
checkArrayElementType(context, arr);
this.storage = arr;
- return context.runtime.getNil();
+ return this.storage;
}
/*
@@ -193,7 +205,7 @@ public class RubyRepeatedField extends RubyObject {
@JRubyMethod
public IRubyObject clear(ThreadContext context) {
this.storage.clear();
- return context.runtime.getNil();
+ return this.storage;
}
/*
@@ -202,7 +214,7 @@ public class RubyRepeatedField extends RubyObject {
*
* Returns the length of this repeated field.
*/
- @JRubyMethod(name = {"count", "length"})
+ @JRubyMethod(name = {"length", "size"})
public IRubyObject length(ThreadContext context) {
return context.runtime.newFixnum(this.storage.size());
}
@@ -215,7 +227,7 @@ public class RubyRepeatedField extends RubyObject {
* repeated field's elements and other's elements. The other (second) list may
* be either another repeated field or a Ruby array.
*/
- @JRubyMethod(name = "+")
+ @JRubyMethod(name = {"+"})
public IRubyObject plus(ThreadContext context, IRubyObject list) {
RubyRepeatedField dup = (RubyRepeatedField) dup(context);
if (list instanceof RubyArray) {
@@ -233,13 +245,34 @@ public class RubyRepeatedField extends RubyObject {
/*
* call-seq:
+ * RepeatedField.concat(other) => self
+ *
+ * concats the passed in array to self. Returns a Ruby array.
+ */
+ @JRubyMethod
+ public IRubyObject concat(ThreadContext context, IRubyObject list) {
+ if (list instanceof RubyArray) {
+ checkArrayElementType(context, (RubyArray) list);
+ this.storage.addAll((RubyArray) list);
+ } else {
+ RubyRepeatedField repeatedField = (RubyRepeatedField) list;
+ if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && !
+ typeClass.equals(repeatedField.typeClass)))
+ throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type.");
+ this.storage.addAll((RubyArray) repeatedField.toArray(context));
+ }
+ return this.storage;
+ }
+
+ /*
+ * call-seq:
* RepeatedField.hash => hash_value
*
* Returns a hash value computed from this repeated field's elements.
*/
@JRubyMethod
public IRubyObject hash(ThreadContext context) {
- int hashCode = System.identityHashCode(this.storage);
+ int hashCode = this.storage.hashCode();
return context.runtime.newFixnum(hashCode);
}
@@ -268,17 +301,12 @@ public class RubyRepeatedField extends RubyObject {
@JRubyMethod
public IRubyObject each(ThreadContext context, Block block) {
this.storage.each(context, block);
- return context.runtime.getNil();
+ return this.storage;
}
+
@JRubyMethod(name = {"to_ary", "to_a"})
public IRubyObject toArray(ThreadContext context) {
- for (int i = 0; i < this.storage.size(); i++) {
- IRubyObject defaultValue = defaultValue(context);
- if (storage.eltInternal(i).isNil()) {
- storage.set(i, defaultValue);
- }
- }
return this.storage;
}
@@ -298,31 +326,6 @@ public class RubyRepeatedField extends RubyObject {
return dup;
}
- /*
- * call-seq:
- * RepeatedField.inspect => string
- *
- * Returns a string representing this repeated field's elements. It will be
- * formated as "[<element>, <element>, ...]", with each element's string
- * representation computed by its own #inspect method.
- */
- @JRubyMethod
- public IRubyObject inspect() {
- StringBuilder str = new StringBuilder("[");
- for (int i = 0; i < this.storage.size(); i++) {
- str.append(storage.eltInternal(i).inspect());
- str.append(", ");
- }
-
- if (str.length() > 1) {
- str.replace(str.length() - 2, str.length(), "]");
- } else {
- str.append("]");
- }
-
- return getRuntime().newString(str.toString());
- }
-
// Java API
protected IRubyObject get(int index) {
return this.storage.eltInternal(index);
@@ -376,6 +379,9 @@ public class RubyRepeatedField extends RubyObject {
case STRING:
value = sentinel.getDefaultString();
break;
+ case ENUM:
+ IRubyObject defaultEnumLoc = context.runtime.newFixnum(0);
+ return RubyEnum.lookup(context, typeClass, defaultEnumLoc);
default:
return context.runtime.getNil();
}