parent
b6993a9060
commit
3581d85ced
21 changed files with 264 additions and 1832 deletions
@ -1,147 +0,0 @@ |
|||||||
/* |
|
||||||
* Protocol Buffers - Google's data interchange format |
|
||||||
* Copyright 2014 Google Inc. All rights reserved. |
|
||||||
* https://developers.google.com/protocol-buffers/
|
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or without |
|
||||||
* modification, are permitted provided that the following conditions are |
|
||||||
* met: |
|
||||||
* |
|
||||||
* * Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* * Redistributions in binary form must reproduce the above |
|
||||||
* copyright notice, this list of conditions and the following disclaimer |
|
||||||
* in the documentation and/or other materials provided with the |
|
||||||
* distribution. |
|
||||||
* * Neither the name of Google Inc. nor the names of its |
|
||||||
* contributors may be used to endorse or promote products derived from |
|
||||||
* this software without specific prior written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
*/ |
|
||||||
|
|
||||||
package com.google.protobuf.jruby; |
|
||||||
|
|
||||||
import org.jruby.*; |
|
||||||
import org.jruby.anno.JRubyClass; |
|
||||||
import org.jruby.anno.JRubyMethod; |
|
||||||
import org.jruby.runtime.*; |
|
||||||
import org.jruby.runtime.builtin.IRubyObject; |
|
||||||
|
|
||||||
@JRubyClass(name = "Builder") |
|
||||||
public class RubyBuilder extends RubyObject { |
|
||||||
public static void createRubyBuilder(Ruby runtime) { |
|
||||||
RubyModule internal = runtime.getClassFromPath("Google::Protobuf::Internal"); |
|
||||||
RubyClass cBuilder = internal.defineClassUnder("Builder", runtime.getObject(), new ObjectAllocator() { |
|
||||||
@Override |
|
||||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
|
||||||
return new RubyBuilder(runtime, klazz); |
|
||||||
} |
|
||||||
}); |
|
||||||
cBuilder.defineAnnotatedMethods(RubyBuilder.class); |
|
||||||
} |
|
||||||
|
|
||||||
public RubyBuilder(Ruby runtime, RubyClass metaClass) { |
|
||||||
super(runtime, metaClass); |
|
||||||
this.cFileBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Internal::FileBuilderContext"); |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* Builder.new => builder |
|
||||||
* |
|
||||||
* Creates a new Builder. A Builder can accumulate a set of new message and enum |
|
||||||
* descriptors and atomically register them into a pool in a way that allows for |
|
||||||
* (co)recursive type references. |
|
||||||
*/ |
|
||||||
@JRubyMethod |
|
||||||
public IRubyObject initialize(ThreadContext context, IRubyObject descriptorPool) { |
|
||||||
this.descriptorPool = (RubyDescriptorPool) descriptorPool; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* Builder.add_message(name, &block) |
|
||||||
* |
|
||||||
* Old and deprecated way to create a new descriptor. |
|
||||||
* See FileBuilderContext.add_message for the recommended way. |
|
||||||
* |
|
||||||
* Exists for backwards compatibility to allow building descriptor pool for |
|
||||||
* files generated by protoc which don't add messages within "add_file" block. |
|
||||||
* Descriptors created this way get assigned to a default empty FileDescriptor. |
|
||||||
*/ |
|
||||||
@JRubyMethod(name = "add_message") |
|
||||||
public IRubyObject addMessage(ThreadContext context, IRubyObject name, Block block) { |
|
||||||
ensureDefaultFileBuilder(context); |
|
||||||
defaultFileBuilder.addMessage(context, name, block); |
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* Builder.add_enum(name, &block) |
|
||||||
* |
|
||||||
* Old and deprecated way to create a new enum descriptor. |
|
||||||
* See FileBuilderContext.add_enum for the recommended way. |
|
||||||
* |
|
||||||
* Exists for backwards compatibility to allow building descriptor pool for |
|
||||||
* files generated by protoc which don't add enums within "add_file" block. |
|
||||||
* Enum descriptors created this way get assigned to a default empty |
|
||||||
* FileDescriptor. |
|
||||||
*/ |
|
||||||
@JRubyMethod(name = "add_enum") |
|
||||||
public IRubyObject addEnum(ThreadContext context, IRubyObject name, Block block) { |
|
||||||
ensureDefaultFileBuilder(context); |
|
||||||
defaultFileBuilder.addEnum(context, name, block); |
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* Builder.add_file(name, options = nil, &block) |
|
||||||
* |
|
||||||
* Creates a new, file descriptor with the given name and options and invokes |
|
||||||
* the block in the context of a FileBuilderContext on that descriptor. The |
|
||||||
* block can then call FileBuilderContext#add_message or |
|
||||||
* FileBuilderContext#add_enum to define new messages or enums, respectively. |
|
||||||
* |
|
||||||
* This is the recommended, idiomatic way to build file descriptors. |
|
||||||
*/ |
|
||||||
@JRubyMethod(name = "add_file") |
|
||||||
public IRubyObject addFile(ThreadContext context, IRubyObject name, IRubyObject options, Block block) { |
|
||||||
RubyFileBuilderContext ctx = (RubyFileBuilderContext) cFileBuilderContext.newInstance(context, descriptorPool, name, options, Block.NULL_BLOCK); |
|
||||||
ctx.instance_eval(context, block); |
|
||||||
ctx.build(context); |
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* Used to trigger the build when using the deprecated syntax |
|
||||||
*/ |
|
||||||
protected void build(ThreadContext context) { |
|
||||||
if (defaultFileBuilder != null) { |
|
||||||
defaultFileBuilder.build(context); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void ensureDefaultFileBuilder(ThreadContext context) { |
|
||||||
if (defaultFileBuilder == null) { |
|
||||||
this.defaultFileBuilder = (RubyFileBuilderContext) cFileBuilderContext.newInstance(context, descriptorPool, context.runtime.newString("ruby_default_file.proto"), Block.NULL_BLOCK); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private RubyClass cFileBuilderContext; |
|
||||||
private RubyDescriptorPool descriptorPool; |
|
||||||
private RubyFileBuilderContext defaultFileBuilder; |
|
||||||
} |
|
@ -1,91 +0,0 @@ |
|||||||
/* |
|
||||||
* Protocol Buffers - Google's data interchange format |
|
||||||
* Copyright 2014 Google Inc. All rights reserved. |
|
||||||
* https://developers.google.com/protocol-buffers/
|
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or without |
|
||||||
* modification, are permitted provided that the following conditions are |
|
||||||
* met: |
|
||||||
* |
|
||||||
* * Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* * Redistributions in binary form must reproduce the above |
|
||||||
* copyright notice, this list of conditions and the following disclaimer |
|
||||||
* in the documentation and/or other materials provided with the |
|
||||||
* distribution. |
|
||||||
* * Neither the name of Google Inc. nor the names of its |
|
||||||
* contributors may be used to endorse or promote products derived from |
|
||||||
* this software without specific prior written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
*/ |
|
||||||
|
|
||||||
package com.google.protobuf.jruby; |
|
||||||
|
|
||||||
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto; |
|
||||||
import org.jruby.Ruby; |
|
||||||
import org.jruby.RubyClass; |
|
||||||
import org.jruby.RubyModule; |
|
||||||
import org.jruby.RubyNumeric; |
|
||||||
import org.jruby.RubyObject; |
|
||||||
import org.jruby.anno.JRubyClass; |
|
||||||
import org.jruby.anno.JRubyMethod; |
|
||||||
import org.jruby.runtime.ObjectAllocator; |
|
||||||
import org.jruby.runtime.ThreadContext; |
|
||||||
import org.jruby.runtime.builtin.IRubyObject; |
|
||||||
|
|
||||||
@JRubyClass(name = "EnumBuilderContext") |
|
||||||
public class RubyEnumBuilderContext extends RubyObject { |
|
||||||
public static void createRubyEnumBuilderContext(Ruby runtime) { |
|
||||||
RubyModule internal = runtime.getClassFromPath("Google::Protobuf::Internal"); |
|
||||||
RubyClass cEnumBuilderContext = internal.defineClassUnder("EnumBuilderContext", runtime.getObject(), new ObjectAllocator() { |
|
||||||
@Override |
|
||||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
|
||||||
return new RubyEnumBuilderContext(runtime, klazz); |
|
||||||
} |
|
||||||
}); |
|
||||||
cEnumBuilderContext.defineAnnotatedMethods(RubyEnumBuilderContext.class); |
|
||||||
} |
|
||||||
|
|
||||||
public RubyEnumBuilderContext(Ruby ruby, RubyClass klazz) { |
|
||||||
super(ruby, klazz); |
|
||||||
} |
|
||||||
|
|
||||||
@JRubyMethod |
|
||||||
public IRubyObject initialize(ThreadContext context, IRubyObject fileBuilderContext, IRubyObject name) { |
|
||||||
this.fileBuilderContext = (RubyFileBuilderContext) fileBuilderContext; |
|
||||||
this.builder = this.fileBuilderContext.getNewEnumBuilder(); |
|
||||||
this.builder.setName(name.asJavaString()); |
|
||||||
this.builder.getOptionsBuilder().setAllowAlias(true); |
|
||||||
|
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* EnumBuilder.add_value(name, number) |
|
||||||
* |
|
||||||
* Adds the given name => number mapping to the enum type. Name must be a Ruby |
|
||||||
* symbol. |
|
||||||
*/ |
|
||||||
@JRubyMethod |
|
||||||
public IRubyObject value(ThreadContext context, IRubyObject name, IRubyObject number) { |
|
||||||
this.builder.addValueBuilder() |
|
||||||
.setName(name.asJavaString()) |
|
||||||
.setNumber(RubyNumeric.num2int(number)); |
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
private EnumDescriptorProto.Builder builder; |
|
||||||
private RubyFileBuilderContext fileBuilderContext; |
|
||||||
} |
|
@ -1,348 +0,0 @@ |
|||||||
/* |
|
||||||
* Protocol Buffers - Google's data interchange format |
|
||||||
* Copyright 2014 Google Inc. All rights reserved. |
|
||||||
* https://developers.google.com/protocol-buffers/
|
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or without |
|
||||||
* modification, are permitted provided that the following conditions are |
|
||||||
* met: |
|
||||||
* |
|
||||||
* * Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* * Redistributions in binary form must reproduce the above |
|
||||||
* copyright notice, this list of conditions and the following disclaimer |
|
||||||
* in the documentation and/or other materials provided with the |
|
||||||
* distribution. |
|
||||||
* * Neither the name of Google Inc. nor the names of its |
|
||||||
* contributors may be used to endorse or promote products derived from |
|
||||||
* this software without specific prior written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
*/ |
|
||||||
|
|
||||||
package com.google.protobuf.jruby; |
|
||||||
|
|
||||||
import com.google.protobuf.DescriptorProtos.DescriptorProto; |
|
||||||
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto; |
|
||||||
import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProtoOrBuilder; |
|
||||||
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; |
|
||||||
import com.google.protobuf.DescriptorProtos.FileDescriptorProto; |
|
||||||
import com.google.protobuf.Descriptors.FieldDescriptor; |
|
||||||
import org.jruby.Ruby; |
|
||||||
import org.jruby.RubyClass; |
|
||||||
import org.jruby.RubyHash; |
|
||||||
import org.jruby.RubyModule; |
|
||||||
import org.jruby.RubyObject; |
|
||||||
import org.jruby.anno.JRubyClass; |
|
||||||
import org.jruby.anno.JRubyMethod; |
|
||||||
import org.jruby.runtime.Block; |
|
||||||
import org.jruby.runtime.ObjectAllocator; |
|
||||||
import org.jruby.runtime.ThreadContext; |
|
||||||
import org.jruby.runtime.builtin.IRubyObject; |
|
||||||
|
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.TreeMap; |
|
||||||
|
|
||||||
@JRubyClass(name = "FileBuilderContext") |
|
||||||
public class RubyFileBuilderContext extends RubyObject { |
|
||||||
public static void createRubyFileBuilderContext(Ruby runtime) { |
|
||||||
RubyModule internal = runtime.getClassFromPath("Google::Protobuf::Internal"); |
|
||||||
RubyClass cFileBuilderContext = internal.defineClassUnder("FileBuilderContext", runtime.getObject(), new ObjectAllocator() { |
|
||||||
@Override |
|
||||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
|
||||||
return new RubyFileBuilderContext(runtime, klazz); |
|
||||||
} |
|
||||||
}); |
|
||||||
cFileBuilderContext.defineAnnotatedMethods(RubyFileBuilderContext.class); |
|
||||||
|
|
||||||
cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor"); |
|
||||||
cEnumBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Internal::EnumBuilderContext"); |
|
||||||
cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor"); |
|
||||||
cMessageBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Internal::MessageBuilderContext"); |
|
||||||
} |
|
||||||
|
|
||||||
public RubyFileBuilderContext(Ruby runtime, RubyClass klazz) { |
|
||||||
super(runtime, klazz); |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* FileBuilderContext.new(descriptor_pool, name, options = nil) => context |
|
||||||
* |
|
||||||
* Create a new file builder context for the given file descriptor and |
|
||||||
* builder context. This class is intended to serve as a DSL context to be used |
|
||||||
* with #instance_eval. |
|
||||||
*/ |
|
||||||
@JRubyMethod(required = 2, optional = 1) |
|
||||||
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) { |
|
||||||
this.descriptorPool = (RubyDescriptorPool) args[0]; |
|
||||||
this.builder = FileDescriptorProto.newBuilder(); |
|
||||||
this.builder.setName(args[1].asJavaString()); |
|
||||||
this.builder.setSyntax("proto3"); |
|
||||||
|
|
||||||
if (args.length > 2) { |
|
||||||
RubyHash options = (RubyHash) args[2]; |
|
||||||
IRubyObject syntax = options.fastARef(context.runtime.newSymbol("syntax")); |
|
||||||
|
|
||||||
if (syntax != null) { |
|
||||||
String syntaxStr = syntax.asJavaString(); |
|
||||||
this.builder.setSyntax(syntaxStr); |
|
||||||
this.proto3 = syntaxStr.equals("proto3"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* FileBuilderContext.add_enum(name, &block) |
|
||||||
* |
|
||||||
* Creates a new, empty enum descriptor with the given name, and invokes the |
|
||||||
* block in the context of an EnumBuilderContext on that descriptor. The block |
|
||||||
* can then call EnumBuilderContext#add_value to define the enum values. |
|
||||||
* |
|
||||||
* This is the recommended, idiomatic way to build enum definitions. |
|
||||||
*/ |
|
||||||
@JRubyMethod(name = "add_enum") |
|
||||||
public IRubyObject addEnum(ThreadContext context, IRubyObject name, Block block) { |
|
||||||
RubyObject ctx = (RubyObject) cEnumBuilderContext.newInstance(context, this, name, Block.NULL_BLOCK); |
|
||||||
ctx.instance_eval(context, block); |
|
||||||
|
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* FileBuilderContext.add_message(name, &block) |
|
||||||
* |
|
||||||
* Creates a new, empty descriptor with the given name, and invokes the block in |
|
||||||
* the context of a MessageBuilderContext on that descriptor. The block can then |
|
||||||
* call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated |
|
||||||
* methods to define the message fields. |
|
||||||
* |
|
||||||
* This is the recommended, idiomatic way to build message definitions. |
|
||||||
*/ |
|
||||||
@JRubyMethod(name = "add_message") |
|
||||||
public IRubyObject addMessage(ThreadContext context, IRubyObject name, Block block) { |
|
||||||
RubyObject ctx = (RubyObject) cMessageBuilderContext.newInstance(context, this, name, Block.NULL_BLOCK); |
|
||||||
ctx.instance_eval(context, block); |
|
||||||
|
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
protected void build(ThreadContext context) { |
|
||||||
Ruby runtime = context.runtime; |
|
||||||
List<DescriptorProto.Builder> messageBuilderList = builder.getMessageTypeBuilderList(); |
|
||||||
List<EnumDescriptorProto.Builder> enumBuilderList = builder.getEnumTypeBuilderList(); |
|
||||||
|
|
||||||
// Get the package name from defined names
|
|
||||||
String packageName = getPackageName(messageBuilderList, enumBuilderList); |
|
||||||
|
|
||||||
if (!packageName.isEmpty()) { |
|
||||||
builder.setPackage(packageName); |
|
||||||
} |
|
||||||
|
|
||||||
// Make an index of the message builders so we can easily nest them
|
|
||||||
TreeMap<String, DescriptorProto.Builder> messageBuilderMap = new TreeMap(); |
|
||||||
for (DescriptorProto.Builder messageBuilder : messageBuilderList) { |
|
||||||
messageBuilderMap.put(messageBuilder.getName(), messageBuilder); |
|
||||||
} |
|
||||||
|
|
||||||
// Make an index of the enum builders so we can easily nest them
|
|
||||||
HashMap<String, EnumDescriptorProto.Builder> enumBuilderMap = new HashMap(); |
|
||||||
for (EnumDescriptorProto.Builder enumBuilder : enumBuilderList) { |
|
||||||
enumBuilderMap.put("." + enumBuilder.getName(), enumBuilder); |
|
||||||
} |
|
||||||
|
|
||||||
// Rename and properly nest messages and create associated ruby objects
|
|
||||||
int packageNameLength = packageName.length(); |
|
||||||
int currentMessageIndex = 0; |
|
||||||
int currentEnumIndex = 0; |
|
||||||
|
|
||||||
// Need to get a static list because we are potentially deleting some of them from the collection
|
|
||||||
DescriptorProto.Builder[] messageBuilders = new DescriptorProto.Builder[messageBuilderList.size()]; |
|
||||||
messageBuilderList.toArray(messageBuilders); |
|
||||||
EnumDescriptorProto.Builder[] enumBuilders = new EnumDescriptorProto.Builder[enumBuilderList.size()]; |
|
||||||
enumBuilderList.toArray(enumBuilders); |
|
||||||
|
|
||||||
for (EnumDescriptorProto.Builder enumBuilder : enumBuilders) { |
|
||||||
String name = enumBuilder.getName(); |
|
||||||
int lastDot = name.lastIndexOf('.'); |
|
||||||
|
|
||||||
if (lastDot > packageNameLength) { |
|
||||||
String parentName = name.substring(0, lastDot); |
|
||||||
String shortName = name.substring(lastDot + 1); |
|
||||||
|
|
||||||
enumBuilder.setName(shortName); |
|
||||||
messageBuilderMap.get(parentName).addEnumType(enumBuilder); |
|
||||||
|
|
||||||
builder.removeEnumType(currentEnumIndex); |
|
||||||
|
|
||||||
} else { |
|
||||||
if (packageNameLength > 0) { |
|
||||||
// Remove the package name
|
|
||||||
String shortName = name.substring(packageNameLength + 1); |
|
||||||
enumBuilder.setName(shortName); |
|
||||||
} |
|
||||||
|
|
||||||
currentEnumIndex++; |
|
||||||
} |
|
||||||
|
|
||||||
// Ensure we have a default value if using proto3 syntax
|
|
||||||
if (proto3) { |
|
||||||
boolean foundDefault = false; |
|
||||||
for (EnumValueDescriptorProtoOrBuilder enumValue : enumBuilder.getValueOrBuilderList()) { |
|
||||||
if (enumValue.getNumber() == 0) { |
|
||||||
foundDefault = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (!foundDefault) { |
|
||||||
throw Utils.createTypeError(context, "Enum definition " + enumBuilder.getName() + " does not contain a value for '0'"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Wipe out top level message builders so we can insert only the ones that should be there
|
|
||||||
builder.clearMessageType(); |
|
||||||
|
|
||||||
/* |
|
||||||
* This block is done in this order because calling |
|
||||||
* `addNestedType` and `addMessageType` makes a copy of the builder |
|
||||||
* so the objects that our maps point to are no longer the objects |
|
||||||
* that are being used to build the descriptions. |
|
||||||
*/ |
|
||||||
for (HashMap.Entry<String, DescriptorProto.Builder> entry : messageBuilderMap.descendingMap().entrySet()) { |
|
||||||
DescriptorProto.Builder messageBuilder = entry.getValue(); |
|
||||||
|
|
||||||
// Rewrite any enum defaults needed
|
|
||||||
for(FieldDescriptorProto.Builder field : messageBuilder.getFieldBuilderList()) { |
|
||||||
String typeName = field.getTypeName(); |
|
||||||
|
|
||||||
if (typeName == null || !field.hasDefaultValue()) continue; |
|
||||||
|
|
||||||
EnumDescriptorProto.Builder enumBuilder = enumBuilderMap.get(typeName); |
|
||||||
|
|
||||||
if (enumBuilder == null) continue; |
|
||||||
|
|
||||||
int defaultValue = Integer.parseInt(field.getDefaultValue()); |
|
||||||
|
|
||||||
for (EnumValueDescriptorProtoOrBuilder enumValue : enumBuilder.getValueOrBuilderList()) { |
|
||||||
if (enumValue.getNumber() == defaultValue) { |
|
||||||
field.setDefaultValue(enumValue.getName()); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Turn Foo.Bar.Baz into a correctly nested structure with the correct name
|
|
||||||
String name = messageBuilder.getName(); |
|
||||||
int lastDot = name.lastIndexOf('.'); |
|
||||||
|
|
||||||
if (lastDot > packageNameLength) { |
|
||||||
String parentName = name.substring(0, lastDot); |
|
||||||
String shortName = name.substring(lastDot + 1); |
|
||||||
messageBuilder.setName(shortName); |
|
||||||
messageBuilderMap.get(parentName).addNestedType(messageBuilder); |
|
||||||
|
|
||||||
} else { |
|
||||||
if (packageNameLength > 0) { |
|
||||||
// Remove the package name
|
|
||||||
messageBuilder.setName(name.substring(packageNameLength + 1)); |
|
||||||
} |
|
||||||
|
|
||||||
// Add back in top level message definitions
|
|
||||||
builder.addMessageType(messageBuilder); |
|
||||||
|
|
||||||
currentMessageIndex++; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
descriptorPool.registerFileDescriptor(context, builder); |
|
||||||
} |
|
||||||
|
|
||||||
protected EnumDescriptorProto.Builder getNewEnumBuilder() { |
|
||||||
return builder.addEnumTypeBuilder(); |
|
||||||
} |
|
||||||
|
|
||||||
protected DescriptorProto.Builder getNewMessageBuilder() { |
|
||||||
return builder.addMessageTypeBuilder(); |
|
||||||
} |
|
||||||
|
|
||||||
protected boolean isProto3() { |
|
||||||
return proto3; |
|
||||||
} |
|
||||||
|
|
||||||
private String getPackageName(List<DescriptorProto.Builder> messages, List<EnumDescriptorProto.Builder> enums) { |
|
||||||
String shortest = null; |
|
||||||
String longest = null; |
|
||||||
|
|
||||||
/* |
|
||||||
* The >= in the longest string comparisons below makes it so we replace |
|
||||||
* the name in case all the names are the same length. This makes it so |
|
||||||
* that the shortest and longest aren't the same name to prevent |
|
||||||
* finding a "package" that isn't correct |
|
||||||
*/ |
|
||||||
|
|
||||||
for (DescriptorProto.Builder message : messages) { |
|
||||||
String name = message.getName(); |
|
||||||
int nameLength = name.length(); |
|
||||||
if (shortest == null) { |
|
||||||
shortest = name; |
|
||||||
longest = name; |
|
||||||
} else if (nameLength < shortest.length()) { |
|
||||||
shortest = name; |
|
||||||
} else if (nameLength >= longest.length()) { |
|
||||||
longest = name; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (EnumDescriptorProto.Builder item : enums) { |
|
||||||
String name = item.getName(); |
|
||||||
int nameLength = name.length(); |
|
||||||
if (shortest == null) { |
|
||||||
shortest = name; |
|
||||||
longest = name; |
|
||||||
} else if (nameLength < shortest.length()) { |
|
||||||
shortest = name; |
|
||||||
} else if (nameLength >= longest.length()) { |
|
||||||
longest = name; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (shortest == null) { |
|
||||||
return ""; |
|
||||||
} |
|
||||||
|
|
||||||
int lastCommonDot = 0; |
|
||||||
for (int i = 0; i < shortest.length(); i++) { |
|
||||||
char nextChar = shortest.charAt(i); |
|
||||||
if (nextChar != longest.charAt(i)) break; |
|
||||||
if (nextChar == '.') lastCommonDot = i; |
|
||||||
} |
|
||||||
|
|
||||||
return shortest.substring(0, lastCommonDot); |
|
||||||
} |
|
||||||
|
|
||||||
private static RubyClass cDescriptor; |
|
||||||
private static RubyClass cEnumBuilderContext; |
|
||||||
private static RubyClass cEnumDescriptor; |
|
||||||
private static RubyClass cMessageBuilderContext; |
|
||||||
|
|
||||||
private FileDescriptorProto.Builder builder; |
|
||||||
private RubyDescriptorPool descriptorPool; |
|
||||||
private boolean proto3 = true; |
|
||||||
} |
|
@ -1,255 +0,0 @@ |
|||||||
/* |
|
||||||
* Protocol Buffers - Google's data interchange format |
|
||||||
* Copyright 2014 Google Inc. All rights reserved. |
|
||||||
* https://developers.google.com/protocol-buffers/
|
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or without |
|
||||||
* modification, are permitted provided that the following conditions are |
|
||||||
* met: |
|
||||||
* |
|
||||||
* * Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* * Redistributions in binary form must reproduce the above |
|
||||||
* copyright notice, this list of conditions and the following disclaimer |
|
||||||
* in the documentation and/or other materials provided with the |
|
||||||
* distribution. |
|
||||||
* * Neither the name of Google Inc. nor the names of its |
|
||||||
* contributors may be used to endorse or promote products derived from |
|
||||||
* this software without specific prior written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
*/ |
|
||||||
|
|
||||||
package com.google.protobuf.jruby; |
|
||||||
|
|
||||||
import com.google.protobuf.DescriptorProtos.DescriptorProto; |
|
||||||
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; |
|
||||||
import com.google.protobuf.DescriptorProtos.OneofDescriptorProto; |
|
||||||
import org.jruby.*; |
|
||||||
import org.jruby.anno.JRubyClass; |
|
||||||
import org.jruby.anno.JRubyMethod; |
|
||||||
import org.jruby.runtime.Binding; |
|
||||||
import org.jruby.runtime.Block; |
|
||||||
import org.jruby.runtime.ObjectAllocator; |
|
||||||
import org.jruby.runtime.ThreadContext; |
|
||||||
import org.jruby.runtime.builtin.IRubyObject; |
|
||||||
|
|
||||||
@JRubyClass(name = "MessageBuilderContext") |
|
||||||
public class RubyMessageBuilderContext extends RubyObject { |
|
||||||
public static void createRubyMessageBuilderContext(Ruby runtime) { |
|
||||||
RubyModule internal = runtime.getClassFromPath("Google::Protobuf::Internal"); |
|
||||||
RubyClass cMessageBuilderContext = internal.defineClassUnder("MessageBuilderContext", runtime.getObject(), new ObjectAllocator() { |
|
||||||
@Override |
|
||||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
|
||||||
return new RubyMessageBuilderContext(runtime, klazz); |
|
||||||
} |
|
||||||
}); |
|
||||||
cMessageBuilderContext.defineAnnotatedMethods(RubyMessageBuilderContext.class); |
|
||||||
|
|
||||||
cFieldDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::FieldDescriptor"); |
|
||||||
cOneofBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Internal::OneofBuilderContext"); |
|
||||||
} |
|
||||||
|
|
||||||
public RubyMessageBuilderContext(Ruby runtime, RubyClass klazz) { |
|
||||||
super(runtime, klazz); |
|
||||||
} |
|
||||||
|
|
||||||
@JRubyMethod |
|
||||||
public IRubyObject initialize(ThreadContext context, IRubyObject fileBuilderContext, IRubyObject name) { |
|
||||||
this.fileBuilderContext = (RubyFileBuilderContext) fileBuilderContext; |
|
||||||
this.builder = this.fileBuilderContext.getNewMessageBuilder(); |
|
||||||
this.builder.setName(name.asJavaString()); |
|
||||||
|
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* MessageBuilderContext.optional(name, type, number, type_class = nil, |
|
||||||
* options = nil) |
|
||||||
* |
|
||||||
* Defines a new optional field on this message type with the given type, tag |
|
||||||
* number, and type class (for message and enum fields). The type must be a Ruby |
|
||||||
* symbol (as accepted by FieldDescriptor#type=) and the type_class must be a |
|
||||||
* string, if present (as accepted by FieldDescriptor#submsg_name=). |
|
||||||
*/ |
|
||||||
@JRubyMethod(required = 3, optional = 2) |
|
||||||
public IRubyObject optional(ThreadContext context, IRubyObject[] args) { |
|
||||||
addField(context, OPTIONAL, args, false); |
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
@JRubyMethod(required = 3, optional = 2) |
|
||||||
public IRubyObject proto3_optional(ThreadContext context, IRubyObject[] args) { |
|
||||||
addField(context, OPTIONAL, args, true); |
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* MessageBuilderContext.required(name, type, number, type_class = nil, |
|
||||||
* options = nil) |
|
||||||
* |
|
||||||
* Defines a new required field on this message type with the given type, tag |
|
||||||
* number, and type class (for message and enum fields). The type must be a Ruby |
|
||||||
* symbol (as accepted by FieldDescriptor#type=) and the type_class must be a |
|
||||||
* string, if present (as accepted by FieldDescriptor#submsg_name=). |
|
||||||
* |
|
||||||
* Proto3 does not have required fields, but this method exists for |
|
||||||
* completeness. Any attempt to add a message type with required fields to a |
|
||||||
* pool will currently result in an error. |
|
||||||
*/ |
|
||||||
@JRubyMethod(required = 3, optional = 2) |
|
||||||
public IRubyObject required(ThreadContext context, IRubyObject[] args) { |
|
||||||
if (fileBuilderContext.isProto3()) throw Utils.createTypeError(context, "Required fields are unsupported in proto3"); |
|
||||||
addField(context, "required", args, false); |
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* MessageBuilderContext.repeated(name, type, number, type_class = nil) |
|
||||||
* |
|
||||||
* Defines a new repeated field on this message type with the given type, tag |
|
||||||
* number, and type class (for message and enum fields). The type must be a Ruby |
|
||||||
* symbol (as accepted by FieldDescriptor#type=) and the type_class must be a |
|
||||||
* string, if present (as accepted by FieldDescriptor#submsg_name=). |
|
||||||
*/ |
|
||||||
@JRubyMethod(required = 3, optional = 1) |
|
||||||
public IRubyObject repeated(ThreadContext context, IRubyObject[] args) { |
|
||||||
addField(context, "repeated", args, false); |
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* MessageBuilderContext.map(name, key_type, value_type, number, |
|
||||||
* value_type_class = nil) |
|
||||||
* |
|
||||||
* Defines a new map field on this message type with the given key and value |
|
||||||
* types, tag number, and type class (for message and enum value types). The key |
|
||||||
* type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type |
|
||||||
* type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the |
|
||||||
* type_class must be a string, if present (as accepted by |
|
||||||
* FieldDescriptor#submsg_name=). |
|
||||||
*/ |
|
||||||
@JRubyMethod(required = 4, optional = 1) |
|
||||||
public IRubyObject map(ThreadContext context, IRubyObject[] args) { |
|
||||||
Ruby runtime = context.runtime; |
|
||||||
if (!fileBuilderContext.isProto3()) throw runtime.newArgumentError("Cannot add a native map field using proto2 syntax."); |
|
||||||
|
|
||||||
RubySymbol messageSym = runtime.newSymbol("message"); |
|
||||||
|
|
||||||
IRubyObject name = args[0]; |
|
||||||
IRubyObject keyType = args[1]; |
|
||||||
IRubyObject valueType = args[2]; |
|
||||||
IRubyObject number = args[3]; |
|
||||||
IRubyObject typeClass = args.length > 4 ? args[4] : context.nil; |
|
||||||
|
|
||||||
// Validate the key type. We can't accept enums, messages, or floats/doubles
|
|
||||||
// as map keys. (We exclude these explicitly, and the field-descriptor setter
|
|
||||||
// below then ensures that the type is one of the remaining valid options.)
|
|
||||||
if (keyType.equals(runtime.newSymbol("float")) || |
|
||||||
keyType.equals(runtime.newSymbol("double")) || |
|
||||||
keyType.equals(runtime.newSymbol("enum")) || |
|
||||||
keyType.equals(messageSym)) |
|
||||||
throw runtime.newArgumentError("Cannot add a map field with a float, double, enum, or message type."); |
|
||||||
|
|
||||||
DescriptorProto.Builder mapEntryBuilder = fileBuilderContext.getNewMessageBuilder(); |
|
||||||
mapEntryBuilder.setName(builder.getName() + "_MapEntry_" + name.asJavaString()); |
|
||||||
mapEntryBuilder.getOptionsBuilder().setMapEntry(true); |
|
||||||
|
|
||||||
mapEntryBuilder.addField( |
|
||||||
Utils.createFieldBuilder( |
|
||||||
context, |
|
||||||
OPTIONAL, |
|
||||||
new IRubyObject[] { |
|
||||||
runtime.newString("key"), |
|
||||||
keyType, |
|
||||||
runtime.newFixnum(1) |
|
||||||
} |
|
||||||
) |
|
||||||
); |
|
||||||
|
|
||||||
mapEntryBuilder.addField( |
|
||||||
Utils.createFieldBuilder( |
|
||||||
context, |
|
||||||
OPTIONAL, |
|
||||||
new IRubyObject[] { |
|
||||||
runtime.newString("value"), |
|
||||||
valueType, |
|
||||||
runtime.newFixnum(2), |
|
||||||
typeClass |
|
||||||
} |
|
||||||
) |
|
||||||
); |
|
||||||
|
|
||||||
IRubyObject[] addFieldArgs = { |
|
||||||
name, messageSym, number, runtime.newString(mapEntryBuilder.getName()) |
|
||||||
}; |
|
||||||
|
|
||||||
repeated(context, addFieldArgs); |
|
||||||
|
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* MessageBuilderContext.oneof(name, &block) => nil |
|
||||||
* |
|
||||||
* Creates a new OneofDescriptor with the given name, creates a |
|
||||||
* OneofBuilderContext attached to that OneofDescriptor, evaluates the given |
|
||||||
* block in the context of that OneofBuilderContext with #instance_eval, and |
|
||||||
* then adds the oneof to the message. |
|
||||||
* |
|
||||||
* This is the recommended, idiomatic way to build oneof definitions. |
|
||||||
*/ |
|
||||||
@JRubyMethod |
|
||||||
public IRubyObject oneof(ThreadContext context, IRubyObject name, Block block) { |
|
||||||
RubyOneofBuilderContext ctx = (RubyOneofBuilderContext) |
|
||||||
cOneofBuilderContext.newInstance( |
|
||||||
context, |
|
||||||
context.runtime.newFixnum(builder.getOneofDeclCount()), |
|
||||||
this, |
|
||||||
Block.NULL_BLOCK |
|
||||||
); |
|
||||||
|
|
||||||
builder.addOneofDeclBuilder().setName(name.asJavaString()); |
|
||||||
ctx.instance_eval(context, block); |
|
||||||
|
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
protected void addFieldBuilder(FieldDescriptorProto.Builder fieldBuilder) { |
|
||||||
builder.addField(fieldBuilder); |
|
||||||
} |
|
||||||
|
|
||||||
private FieldDescriptorProto.Builder addField(ThreadContext context, String label, IRubyObject[] args, boolean proto3Optional) { |
|
||||||
FieldDescriptorProto.Builder fieldBuilder = |
|
||||||
Utils.createFieldBuilder(context, label, args); |
|
||||||
|
|
||||||
fieldBuilder.setProto3Optional(proto3Optional); |
|
||||||
builder.addField(fieldBuilder); |
|
||||||
|
|
||||||
return fieldBuilder; |
|
||||||
} |
|
||||||
|
|
||||||
private static RubyClass cFieldDescriptor; |
|
||||||
private static RubyClass cOneofBuilderContext; |
|
||||||
|
|
||||||
private static final String OPTIONAL = "optional"; |
|
||||||
|
|
||||||
private DescriptorProto.Builder builder; |
|
||||||
private RubyClass cDescriptor; |
|
||||||
private RubyFileBuilderContext fileBuilderContext; |
|
||||||
} |
|
@ -1,103 +0,0 @@ |
|||||||
/* |
|
||||||
* Protocol Buffers - Google's data interchange format |
|
||||||
* Copyright 2014 Google Inc. All rights reserved. |
|
||||||
* https://developers.google.com/protocol-buffers/
|
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or without |
|
||||||
* modification, are permitted provided that the following conditions are |
|
||||||
* met: |
|
||||||
* |
|
||||||
* * Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* * Redistributions in binary form must reproduce the above |
|
||||||
* copyright notice, this list of conditions and the following disclaimer |
|
||||||
* in the documentation and/or other materials provided with the |
|
||||||
* distribution. |
|
||||||
* * Neither the name of Google Inc. nor the names of its |
|
||||||
* contributors may be used to endorse or promote products derived from |
|
||||||
* this software without specific prior written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
*/ |
|
||||||
|
|
||||||
package com.google.protobuf.jruby; |
|
||||||
|
|
||||||
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; |
|
||||||
import org.jruby.Ruby; |
|
||||||
import org.jruby.RubyClass; |
|
||||||
import org.jruby.RubyHash; |
|
||||||
import org.jruby.RubyModule; |
|
||||||
import org.jruby.RubyNumeric; |
|
||||||
import org.jruby.RubyObject; |
|
||||||
import org.jruby.anno.JRubyClass; |
|
||||||
import org.jruby.anno.JRubyMethod; |
|
||||||
import org.jruby.runtime.ObjectAllocator; |
|
||||||
import org.jruby.runtime.ThreadContext; |
|
||||||
import org.jruby.runtime.builtin.IRubyObject; |
|
||||||
|
|
||||||
@JRubyClass(name = "OneofBuilderContext") |
|
||||||
public class RubyOneofBuilderContext extends RubyObject { |
|
||||||
public static void createRubyOneofBuilderContext(Ruby runtime) { |
|
||||||
RubyModule internal = runtime.getClassFromPath("Google::Protobuf::Internal"); |
|
||||||
RubyClass cRubyOneofBuidlerContext = internal.defineClassUnder("OneofBuilderContext", runtime.getObject(), new ObjectAllocator() { |
|
||||||
@Override |
|
||||||
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) { |
|
||||||
return new RubyOneofBuilderContext(ruby, rubyClass); |
|
||||||
} |
|
||||||
}); |
|
||||||
cRubyOneofBuidlerContext.defineAnnotatedMethods(RubyOneofBuilderContext.class); |
|
||||||
} |
|
||||||
|
|
||||||
public RubyOneofBuilderContext(Ruby ruby, RubyClass rubyClass) { |
|
||||||
super(ruby, rubyClass); |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* OneofBuilderContext.new(oneof_index, message_builder) => context |
|
||||||
* |
|
||||||
* Create a new oneof builder context around the given oneof descriptor and |
|
||||||
* builder context. This class is intended to serve as a DSL context to be used |
|
||||||
* with #instance_eval. |
|
||||||
*/ |
|
||||||
@JRubyMethod |
|
||||||
public IRubyObject initialize(ThreadContext context, IRubyObject index, IRubyObject messageBuilder) { |
|
||||||
this.builder = (RubyMessageBuilderContext) messageBuilder; |
|
||||||
this.index = RubyNumeric.num2int(index); |
|
||||||
|
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* call-seq: |
|
||||||
* OneofBuilderContext.optional(name, type, number, type_class = nil, |
|
||||||
* options = nil) |
|
||||||
* |
|
||||||
* Defines a new optional field in this oneof with the given type, tag number, |
|
||||||
* and type class (for message and enum fields). The type must be a Ruby symbol |
|
||||||
* (as accepted by FieldDescriptor#type=) and the type_class must be a string, |
|
||||||
* if present (as accepted by FieldDescriptor#submsg_name=). |
|
||||||
*/ |
|
||||||
@JRubyMethod(required = 3, optional = 2) |
|
||||||
public IRubyObject optional(ThreadContext context, IRubyObject[] args) { |
|
||||||
FieldDescriptorProto.Builder fieldBuilder = |
|
||||||
Utils.createFieldBuilder(context, "optional", args); |
|
||||||
fieldBuilder.setOneofIndex(index); |
|
||||||
builder.addFieldBuilder(fieldBuilder); |
|
||||||
|
|
||||||
return context.nil; |
|
||||||
} |
|
||||||
|
|
||||||
private RubyMessageBuilderContext builder; |
|
||||||
private int index; |
|
||||||
} |
|
Loading…
Reference in new issue