Commit 9861c0d7 authored by Chris Fallin's avatar Chris Fallin

Merge pull request #146 from isaiah/jruby

protobuf support for jruby
parents a5f7bb8e 27e2b578
*.bundle
tags
.idea/
lib/google/protobuf_java.jar
protobuf-jruby.iml
target/
source 'https://rubygems.org'
gemspec
PATH
remote: .
specs:
google-protobuf (3.0.0.alpha.2)
GEM
remote: https://rubygems.org/
specs:
power_assert (0.2.2)
rake (10.4.2)
rake-compiler (0.9.5)
rake
rubygems-tasks (0.2.4)
test-unit (3.0.9)
power_assert
PLATFORMS
java
ruby
DEPENDENCIES
google-protobuf!
rake-compiler
rubygems-tasks
test-unit
......@@ -60,15 +60,28 @@ To build this Ruby extension, you will need:
* Ruby development headers
* a C compiler
First, install the required Ruby gems:
To Build the JRuby extension, you will need:
$ sudo gem install bundler rake rake-compiler rspec rubygems-tasks
* Maven
* The latest version of the protobuf java library
* Install JRuby via rbenv or RVM
First switch to the desired platform with rbenv or RVM.
Then install the required Ruby gems:
$ gem install bundler
$ bundle
Then build the Gem:
$ rake gem
$ gem install pkg/protobuf-$VERSION.gem
To run the specs:
$ rake test
This gem includes the upb parsing and serialization library as a single-file
amalgamation. It is up-to-date with upb git commit
`535bc2fe2f2b467f59347ffc9449e11e47791257`.
......
require "rake/extensiontask"
require "rubygems"
require "rubygems/package_task"
require "rake/extensiontask" unless RUBY_PLATFORM == "java"
require "rake/testtask"
spec = Gem::Specification.load("google-protobuf.gemspec")
Rake::ExtensionTask.new("protobuf_c", spec) do |ext|
ext.ext_dir = "ext/google/protobuf_c"
ext.lib_dir = "lib/google"
end
if RUBY_PLATFORM == "java"
task :clean do
system("mvn clean")
end
Rake::TestTask.new(:test => :build) do |t|
t.test_files = FileList["tests/*.rb"]
task :compile do
system("mvn package")
end
else
Rake::ExtensionTask.new("protobuf_c", spec) do |ext|
ext.ext_dir = "ext/google/protobuf_c"
ext.lib_dir = "lib/google"
end
end
Gem::PackageTask.new(spec) do |pkg|
end
Rake::TestTask.new(:test => :build) do |t|
t.test_files = FileList["tests/*.rb"]
end
task :build => [:clean, :compile]
task :default => [:build]
......
class << Gem::Specification
def find_c_source(dir)
`cd #{dir}; git ls-files "*.c" "*.h" extconf.rb Makefile`.split
.map{|f| "#{dir}/#{f}"}
end
end
Gem::Specification.new do |s|
s.name = "google-protobuf"
s.version = "3.0.0.alpha.3.0.pre"
......@@ -14,11 +7,17 @@ Gem::Specification.new do |s|
s.authors = ["Protobuf Authors"]
s.email = "protobuf@googlegroups.com"
s.require_paths = ["lib"]
s.extensions = ["ext/google/protobuf_c/extconf.rb"]
s.files = ["lib/google/protobuf.rb"] +
# extension C source
find_c_source("ext/google/protobuf_c")
s.test_files = ["tests/basic.rb",
"tests/stress.rb",
"tests/generated_code_test.rb"]
s.files = ["lib/google/protobuf.rb"]
unless RUBY_PLATFORM == "java"
s.files += `git ls-files "*.c" "*.h" extconf.rb Makefile`.split
s.extensions= ["ext/google/protobuf_c/extconf.rb"]
else
s.files += ["lib/google/protobuf_java.jar"]
end
s.test_files = ["tests/basic.rb",
"tests/stress.rb",
"tests/generated_code_test.rb"]
s.add_development_dependency "rake-compiler"
s.add_development_dependency "test-unit"
s.add_development_dependency "rubygems-tasks"
end
......@@ -28,4 +28,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'google/protobuf_c'
if RUBY_PLATFORM == "java"
require 'json'
require 'google/protobuf_java'
else
require 'google/protobuf_c'
end
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.google</groupId>
<artifactId>google</artifactId>
<version>1</version>
</parent>
<groupId>com.google.protobuf.jruby</groupId>
<artifactId>protobuf-jruby</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Protocol Buffer JRuby native extension</name>
<description>
Protocol Buffers are a way of encoding structured data in an efficient yet
extensible format.
</description>
<inceptionYear>2014</inceptionYear>
<url>https://developers.google.com/protocol-buffers/</url>
<licenses>
<license>
<name>New BSD license</name>
<url>http://www.opensource.org/licenses/bsd-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>https://github.com/google/protobuf</url>
<connection>
scm:git:https://github.com/google/protobuf.git
</connection>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<ruby.sources>lib/google</ruby.sources>
<jar.finalName>protobuf_java</jar.finalName>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>${jar.finalName}</finalName>
<outputDirectory>${ruby.sources}</outputDirectory>
<appendAssemblyId>false</appendAssemblyId>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>1.7.13</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.0.0-pre</version>
</dependency>
</dependencies>
</project>
/*
* 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 protobuf = runtime.getClassFromPath("Google::Protobuf");
RubyClass cBuilder = protobuf.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.cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor");
this.cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor");
this.cMessageBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::MessageBuilderContext");
this.cEnumBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumBuilderContext");
}
/*
* 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) {
Ruby runtime = context.runtime;
this.pendingList = runtime.newArray();
return this;
}
/*
* call-seq:
* Builder.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) {
RubyDescriptor msgdef = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK);
IRubyObject ctx = cMessageBuilderContext.newInstance(context, msgdef, this, Block.NULL_BLOCK);
msgdef.setName(context, name);
if (block.isGiven()) {
if (block.arity() == Arity.ONE_ARGUMENT) {
block.yield(context, ctx);
} else {
Binding binding = block.getBinding();
binding.setSelf(ctx);
block.yieldSpecific(context);
}
}
this.pendingList.add(msgdef);
return context.runtime.getNil();
}
/*
* call-seq:
* Builder.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) {
RubyEnumDescriptor enumDef = (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK);
IRubyObject ctx = cEnumBuilderContext.newInstance(context, enumDef, Block.NULL_BLOCK);
enumDef.setName(context, name);
if (block.isGiven()) {
if (block.arity() == Arity.ONE_ARGUMENT) {
block.yield(context, ctx);
} else {
Binding binding = block.getBinding();
binding.setSelf(ctx);
block.yieldSpecific(context);
}
}
this.pendingList.add(enumDef);
return context.runtime.getNil();
}
/*
* call-seq:
* Builder.finalize_to_pool(pool)
*
* Adds all accumulated message and enum descriptors created in this builder
* context to the given pool. The operation occurs atomically, and all
* descriptors can refer to each other (including in cycles). This is the only
* way to build (co)recursive message definitions.
*
* This method is usually called automatically by DescriptorPool#build after it
* invokes the given user block in the context of the builder. The user should
* not normally need to call this manually because a Builder is not normally
* created manually.
*/
@JRubyMethod(name = "finalize_to_pool")
public IRubyObject finalizeToPool(ThreadContext context, IRubyObject rbPool) {
RubyDescriptorPool pool = (RubyDescriptorPool) rbPool;
for (int i = 0; i < this.pendingList.size(); i++) {
IRubyObject defRb = this.pendingList.entry(i);
if (defRb instanceof RubyDescriptor) {
pool.addToSymtab(context, (RubyDescriptor) defRb);
} else {
pool.addToSymtab(context, (RubyEnumDescriptor) defRb);
}
}
this.pendingList = context.runtime.newArray();
return context.runtime.getNil();
}
protected RubyArray pendingList;
private RubyClass cDescriptor, cEnumDescriptor, cMessageBuilderContext, cEnumBuilderContext;
}
/*
* 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;
import com.google.protobuf.Descriptors;
import org.jruby.*;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.*;
import org.jruby.runtime.builtin.IRubyObject;
import java.util.HashMap;
import java.util.Map;
@JRubyClass(name = "DescriptorPool")
public class RubyDescriptorPool extends RubyObject {
public static void createRubyDescriptorPool(Ruby runtime) {
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
RubyClass cDescriptorPool = protobuf.defineClassUnder("DescriptorPool", runtime.getObject(), new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new RubyDescriptorPool(runtime, klazz);
}
});
cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class);
descriptorPool = (RubyDescriptorPool) cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK);
}
public RubyDescriptorPool(Ruby ruby, RubyClass klazz) {
super(ruby, klazz);
}
@JRubyMethod
public IRubyObject initialize(ThreadContext context) {
this.symtab = new HashMap<IRubyObject, IRubyObject>();
this.cBuilder = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Builder");
this.builder = DescriptorProtos.FileDescriptorProto.newBuilder();
return this;
}
@JRubyMethod
public IRubyObject build(ThreadContext context, Block block) {
RubyBuilder ctx = (RubyBuilder) cBuilder.newInstance(context, Block.NULL_BLOCK);
if (block.arity() == Arity.ONE_ARGUMENT) {
block.yield(context, ctx);
} else {
Binding binding = block.getBinding();
binding.setSelf(ctx);
block.yieldSpecific(context);
}
ctx.finalizeToPool(context, this);
buildFileDescriptor(context);
return context.runtime.getNil();
}
@JRubyMethod
public IRubyObject lookup(ThreadContext context, IRubyObject name) {
IRubyObject descriptor = this.symtab.get(name);
if (descriptor == null) {
return context.runtime.getNil();
}
return descriptor;
}
/*
* call-seq:
* DescriptorPool.generated_pool => descriptor_pool
*
* Class method that returns the global DescriptorPool. This is a singleton into
* which generated-code message and enum types are registered. The user may also
* register types in this pool for convenience so that they do not have to hold
* a reference to a private pool instance.
*/
@JRubyMethod(meta = true, name = "generated_pool")
public static IRubyObject generatedPool(ThreadContext context, IRubyObject recv) {
return descriptorPool;
}
protected void addToSymtab(ThreadContext context, RubyDescriptor def) {
symtab.put(def.getName(context), def);
this.builder.addMessageType(def.getBuilder());
}
protected void addToSymtab(ThreadContext context, RubyEnumDescriptor def) {
symtab.put(def.getName(context), def);
this.builder.addEnumType(def.getBuilder());
}
private void buildFileDescriptor(ThreadContext context) {
Ruby runtime = context.runtime;
try {
this.builder.setSyntax("proto3");
final Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor.buildFrom(
this.builder.build(), new Descriptors.FileDescriptor[]{});
for (Descriptors.EnumDescriptor enumDescriptor : fileDescriptor.getEnumTypes()) {
String enumName = Utils.unescapeIdentifier(enumDescriptor.getName());
if (enumDescriptor.findValueByNumber(0) == null) {
throw runtime.newTypeError("Enum definition " + enumName
+ " does not contain a value for '0'");
}
((RubyEnumDescriptor) symtab.get(runtime.newString(enumName)))
.setDescriptor(enumDescriptor);
}
for (Descriptors.Descriptor descriptor : fileDescriptor.getMessageTypes()) {
RubyDescriptor rubyDescriptor = ((RubyDescriptor)
symtab.get(runtime.newString(Utils.unescapeIdentifier(descriptor.getName()))));
for (Descriptors.FieldDescriptor fieldDescriptor : descriptor.getFields()) {
if (fieldDescriptor.isRequired()) {
throw runtime.newTypeError("Required fields are unsupported in proto3");
}
RubyFieldDescriptor rubyFieldDescriptor = rubyDescriptor.lookup(fieldDescriptor.getName());
rubyFieldDescriptor.setFieldDef(fieldDescriptor);
if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) {
RubyDescriptor subType = (RubyDescriptor) lookup(context,
runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getMessageType().getName())));
rubyFieldDescriptor.setSubType(subType);
}
if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.ENUM) {
RubyEnumDescriptor subType = (RubyEnumDescriptor) lookup(context,
runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getEnumType().getName())));
rubyFieldDescriptor.setSubType(subType);
}
}
rubyDescriptor.setDescriptor(descriptor);
}
} catch (Descriptors.DescriptorValidationException e) {
throw runtime.newRuntimeError(e.getMessage());
}
}
private static RubyDescriptorPool descriptorPool;
private RubyClass cBuilder;
private Map<IRubyObject, IRubyObject> symtab;
private DescriptorProtos.FileDescriptorProto.Builder builder;
}
/*
* 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.Descriptors;
import org.jruby.RubyModule;
import org.jruby.RubyNumeric;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
public class RubyEnum {
/*
* call-seq:
* Enum.lookup(number) => name
*
* This module method, provided on each generated enum module, looks up an enum
* value by number and returns its name as a Ruby symbol, or nil if not found.
*/
@JRubyMethod(meta = true)
public static IRubyObject lookup(ThreadContext context, IRubyObject recv, IRubyObject number) {
RubyEnumDescriptor rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor();
Descriptors.EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number));
if (value == null) return context.runtime.getNil();
return context.runtime.newSymbol(value.getName());
}
/*
* call-seq:
* Enum.resolve(name) => number
*
* This module method, provided on each generated enum module, looks up an enum
* value by name (as a Ruby symbol) and returns its name, or nil if not found.
*/
@JRubyMethod(meta = true)
public static IRubyObject resolve(ThreadContext context, IRubyObject recv, IRubyObject name) {
RubyEnumDescriptor rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor();
Descriptors.EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString());
if (value == null) return context.runtime.getNil();
return context.runtime.newFixnum(value.getNumber());
}
/*
* call-seq:
* Enum.descriptor
*
* This module method, provided on each generated enum module, returns the
* EnumDescriptor corresponding to this enum type.
*/
@JRubyMethod(meta = true, name = "descriptor")
public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
return ((RubyModule) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
}
}
/*
* 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.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
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 protobuf = runtime.getClassFromPath("Google::Protobuf");
RubyClass cMessageBuilderContext = protobuf.defineClassUnder("EnumBuilderContext", runtime.getObject(), new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new RubyEnumBuilderContext(runtime, klazz);
}
});
cMessageBuilderContext.defineAnnotatedMethods(RubyEnumBuilderContext.class);
}
public RubyEnumBuilderContext(Ruby ruby, RubyClass klazz) {
super(ruby, klazz);
}
@JRubyMethod
public IRubyObject initialize(ThreadContext context, IRubyObject enumDescriptor) {
this.enumDescriptor = (RubyEnumDescriptor) enumDescriptor;
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.enumDescriptor.addValue(context, name, number);
return context.runtime.getNil();
}
private RubyEnumDescriptor enumDescriptor;
}
/*
* 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;
import com.google.protobuf.Descriptors;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.RubyNumeric;
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;
@JRubyClass(name = "EnumDescriptor", include = "Enumerable")
public class RubyEnumDescriptor extends RubyObject {
public static void createRubyEnumDescriptor(Ruby runtime) {
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
RubyClass cEnumDescriptor = mProtobuf.defineClassUnder("EnumDescriptor", runtime.getObject(), new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new RubyEnumDescriptor(runtime, klazz);
}
});
cEnumDescriptor.includeModule(runtime.getEnumerable());
cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class);
}
public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) {
super(runtime, klazz);
}
/*
* call-seq:
* EnumDescriptor.new => enum_descriptor
*
* Creates a new, empty, enum descriptor. Must be added to a pool before the
* enum type can be used. The enum type may only be modified prior to adding to
* a pool.
*/
@JRubyMethod
public IRubyObject initialize(ThreadContext context) {
this.builder = DescriptorProtos.EnumDescriptorProto.newBuilder();
return this;
}
/*
* call-seq:
* EnumDescriptor.name => name
*
* Returns the name of this enum type.
*/
@JRubyMethod(name = "name")
public IRubyObject getName(ThreadContext context) {
return this.name;
}
/*
* call-seq:
* EnumDescriptor.name = name
*
* Sets the name of this enum type. Cannot be called if the enum type has
* already been added to a pool.
*/
@JRubyMethod(name = "name=")
public IRubyObject setName(ThreadContext context, IRubyObject name) {
this.name = name;
this.builder.setName(Utils.escapeIdentifier(name.asJavaString()));
return context.runtime.getNil();
}
/*
* call-seq:
* EnumDescriptor.add_value(key, value)
*
* Adds a new key => value mapping to this enum type. Key must be given as a
* Ruby symbol. Cannot be called if the enum type has already been added to a
* pool. Will raise an exception if the key or value is already in use.
*/
@JRubyMethod(name = "add_value")
public IRubyObject addValue(ThreadContext context, IRubyObject name, IRubyObject number) {
DescriptorProtos.EnumValueDescriptorProto.Builder valueBuilder = DescriptorProtos.EnumValueDescriptorProto.newBuilder();
valueBuilder.setName(name.asJavaString());
valueBuilder.setNumber(RubyNumeric.num2int(number));
this.builder.addValue(valueBuilder);
return context.runtime.getNil();
}
/*
* call-seq:
* EnumDescriptor.each(&block)
*
* Iterates over key => value mappings in this enum's definition, yielding to
* the block with (key, value) arguments for each one.
*/
@JRubyMethod
public IRubyObject each(ThreadContext context, Block block) {
Ruby runtime = context.runtime;
for (Descriptors.EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) {
block.yield(context, runtime.newArray(runtime.newSymbol(enumValueDescriptor.getName()),
runtime.newFixnum(enumValueDescriptor.getNumber())));
}
return runtime.getNil();
}
/*
* call-seq:
* EnumDescriptor.enummodule => module
*
* Returns the Ruby module corresponding to this enum type. Cannot be called
* until the enum descriptor has been added to a pool.
*/
@JRubyMethod
public IRubyObject enummodule(ThreadContext context) {
if (this.klazz == null) {
this.klazz = buildModuleFromDescriptor(context);
}
return this.klazz;
}
public void setDescriptor(Descriptors.EnumDescriptor descriptor) {
this.descriptor = descriptor;
}
public Descriptors.EnumDescriptor getDescriptor() {
return this.descriptor;
}
public DescriptorProtos.EnumDescriptorProto.Builder getBuilder() {
return this.builder;
}
private RubyModule buildModuleFromDescriptor(ThreadContext context) {
Ruby runtime = context.runtime;
Utils.checkNameAvailability(context, name.asJavaString());
RubyModule enumModule = RubyModule.newModule(runtime);
for (Descriptors.EnumValueDescriptor value : descriptor.getValues()) {
enumModule.defineConstant(value.getName(), runtime.newFixnum(value.getNumber()));
}
enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
enumModule.defineAnnotatedMethods(RubyEnum.class);
return enumModule;
}
private IRubyObject name;
private RubyModule klazz;
private Descriptors.EnumDescriptor descriptor;
private DescriptorProtos.EnumDescriptorProto.Builder builder;
}
/*
* 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;
import com.google.protobuf.Descriptors;
import org.jruby.*;
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 = "FieldDescriptor")
public class RubyFieldDescriptor extends RubyObject {
public static void createRubyFileDescriptor(Ruby runtime) {
RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
RubyClass cFieldDescriptor = mProtobuf.defineClassUnder("FieldDescriptor", runtime.getObject(), new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new RubyFieldDescriptor(runtime, klazz);
}
});
cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class);
}
public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) {
super(runtime, klazz);
}
/*
* call-seq:
* FieldDescriptor.new => field
*
* Returns a new field descriptor. Its name, type, etc. must be set before it is
* added to a message type.
*/
@JRubyMethod
public IRubyObject initialize(ThreadContext context) {
builder = DescriptorProtos.FieldDescriptorProto.newBuilder();
return this;
}
/*
* call-seq:
* FieldDescriptor.label = label
*
* Sets the label on this field. Cannot be called if field is part of a message
* type already in a pool.
*/
@JRubyMethod(name = "label=")
public IRubyObject setLabel(ThreadContext context, IRubyObject value) {
this.builder.setLabel(
DescriptorProtos.FieldDescriptorProto.Label.valueOf("LABEL_" + value.asJavaString().toUpperCase()));
return context.runtime.getNil();
}
/*
* call-seq:
* FieldDescriptor.name => name
*
* Returns the name of this field.
*/
@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
*
* Sets the name of this field. Cannot be called once the containing message
* type, if any, is added to a pool.
*/
@JRubyMethod(name = "name=")
public IRubyObject setName(ThreadContext context, IRubyObject value) {
String nameStr = value.asJavaString();
this.name = context.runtime.newString(nameStr);
this.builder.setName(Utils.escapeIdentifier(nameStr));
return context.runtime.getNil();
}
/*
* call-seq:
* FieldDescriptor.type => type
*
* Returns this field's type, as a Ruby symbol, or nil if not yet set.
*
* Valid field types are:
* :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
* :bytes, :message.
*/
@JRubyMethod(name = "type")
public IRubyObject getType(ThreadContext context) {
return Utils.fieldTypeToRuby(context, this.builder.getType());
}
/*
* call-seq:
* FieldDescriptor.type = type
*
* Sets this field's type. Cannot be called if field is part of a message type
* already in a pool.
*/
@JRubyMethod(name = "type=")
public IRubyObject setType(ThreadContext context, IRubyObject value) {
this.builder.setType(DescriptorProtos.FieldDescriptorProto.Type.valueOf("TYPE_" + value.asJavaString().toUpperCase()));
return context.runtime.getNil();
}
/*
* call-seq:
* FieldDescriptor.number = number
*
* Sets the tag number for this field. Cannot be called if field is part of a
* message type already in a pool.
*/
@JRubyMethod(name = "number=")
public IRubyObject setNumber(ThreadContext context, IRubyObject value) {
this.builder.setNumber(RubyNumeric.num2int(value));
return context.runtime.getNil();
}
/*
* call-seq:
* FieldDescriptor.submsg_name = submsg_name
*
* Sets the name of the message or enum type corresponding to this field, if it
* is a message or enum field (respectively). This type name will be resolved
* within the context of the pool to which the containing message type is added.
* Cannot be called on field that are not of message or enum type, or on fields
* that are part of a message type already added to a pool.
*/
@JRubyMethod(name = "submsg_name=")
public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) {
this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString()));
return context.runtime.getNil();
}
/*
* call-seq:
* FieldDescriptor.get(message) => value
*
* Returns the value set for this field on the given message. Raises an
* exception if message is of the wrong type.
*/
@JRubyMethod(name = "get")
public IRubyObject getValue(ThreadContext context, IRubyObject msgRb) {
RubyMessage message = (RubyMessage) msgRb;
if (message.getDescriptor() != fieldDef.getContainingType()) {
throw context.runtime.newTypeError("set method called on wrong message type");
}
return message.getField(context, fieldDef);
}
/*
* call-seq:
* FieldDescriptor.set(message, value)
*
* Sets the value corresponding to this field to the given value on the given
* message. Raises an exception if message is of the wrong type. Performs the
* ordinary type-checks for field setting.
*/
@JRubyMethod(name = "set")
public IRubyObject setValue(ThreadContext context, IRubyObject msgRb, IRubyObject value) {
RubyMessage message = (RubyMessage) msgRb;
if (message.getDescriptor() != fieldDef.getContainingType()) {
throw context.runtime.newTypeError("set method called on wrong message type");
}
message.setField(context, fieldDef, value);
return context.runtime.getNil();
}
protected void setSubType(IRubyObject rubyDescriptor) {
this.subType = rubyDescriptor;
}
protected void setFieldDef(Descriptors.FieldDescriptor fieldDescriptor) {
this.fieldDef = fieldDescriptor;
}
protected void setOneofName(IRubyObject name) {
oneofName = name;
}
protected void setOneofIndex(int index) {
hasOneofIndex = true;
oneofIndex = index;
}
protected IRubyObject getOneofName() {
return oneofName;
}
protected Descriptors.FieldDescriptor getFieldDef() {
return fieldDef;
}
protected DescriptorProtos.FieldDescriptorProto build() {
if (hasOneofIndex)
builder.setOneofIndex(oneofIndex);
return this.builder.build();
}
private DescriptorProtos.FieldDescriptorProto.Builder builder;
private IRubyObject name;
private IRubyObject subType;
private IRubyObject oneofName;
private Descriptors.FieldDescriptor fieldDef;
private int oneofIndex;
private boolean hasOneofIndex = false;
}
This diff is collapsed.
This diff is collapsed.
/*
* 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.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
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 protobuf = runtime.getClassFromPath("Google::Protobuf");
RubyModule internal = protobuf.defineModuleUnder("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);
}
@JRubyMethod
public IRubyObject initialize(ThreadContext context, IRubyObject oneofdef) {
this.descriptor = (RubyOneofDescriptor) oneofdef;
this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor");
return this;
}
@JRubyMethod(required = 3, optional = 1)
public IRubyObject optional(ThreadContext context, IRubyObject[] args) {
IRubyObject name = args[0];
IRubyObject type = args[1];
IRubyObject number = args[2];
IRubyObject typeClass = args.length > 3 ? args[3] : context.runtime.getNil();
RubyFieldDescriptor fieldDescriptor = Utils.msgdefCreateField(context, "optional",
name, type, number, typeClass, cFieldDescriptor);
descriptor.addField(context, fieldDescriptor);
return this;
}
private RubyOneofDescriptor descriptor;
private RubyClass cFieldDescriptor;
}
package com.google.protobuf.jruby;
import com.google.protobuf.DescriptorProtos;
import com.google.protobuf.Descriptors;
import org.jruby.Ruby;
import org.jruby.RubyClass;
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.*;
@JRubyClass(name = "OneofDescriptor", include = "Enumerable")
public class RubyOneofDescriptor extends RubyObject {
public static void createRubyOneofDescriptor(Ruby runtime) {
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
RubyClass cRubyOneofDescriptor = protobuf.defineClassUnder("OneofDescriptor", runtime.getObject(), new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
return new RubyOneofDescriptor(ruby, rubyClass);
}
});
cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class);
cRubyOneofDescriptor.includeModule(runtime.getEnumerable());
}
public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) {
super(ruby, rubyClass);
}
@JRubyMethod
public IRubyObject initialize(ThreadContext context) {
builder = DescriptorProtos.OneofDescriptorProto.newBuilder();
fields = new ArrayList<RubyFieldDescriptor>();
return this;
}
/*
* call-seq:
* OneofDescriptor.name => name
*
* Returns the name of this oneof.
*/
@JRubyMethod(name = "name")
public IRubyObject getName(ThreadContext context) {
return name;
}
/*
* call-seq:
* OneofDescriptor.name = name
*
* Sets a new name for this oneof. The oneof must not have been added to a
* message descriptor yet.
*/
@JRubyMethod(name = "name=")
public IRubyObject setName(ThreadContext context, IRubyObject name) {
this.name = context.runtime.newString(name.asJavaString());
this.builder.setName(name.asJavaString());
return context.runtime.getNil();
}
/*
* call-seq:
* OneofDescriptor.add_field(field) => nil
*
* Adds a field to this oneof. The field may have been added to this oneof in
* the past, or the message to which this oneof belongs (if any), but may not
* have already been added to any other oneof or message. Otherwise, an
* exception is raised.
*
* All fields added to the oneof via this method will be automatically added to
* the message to which this oneof belongs, if it belongs to one currently, or
* else will be added to any message to which the oneof is later added at the
* time that it is added.
*/
@JRubyMethod(name = "add_field")
public IRubyObject addField(ThreadContext context, IRubyObject obj) {
RubyFieldDescriptor fieldDescriptor = (RubyFieldDescriptor) obj;
fieldDescriptor.setOneofName(this.name);
fields.add(fieldDescriptor);
return context.runtime.getNil();
}
/*
* call-seq:
* OneofDescriptor.each(&block) => nil
*
* Iterates through fields in this oneof, yielding to the block on each one.
*/
@JRubyMethod
public IRubyObject each(ThreadContext context, Block block) {
for (RubyFieldDescriptor field : fields) {
block.yieldSpecific(context, field);
}
return context.runtime.getNil();
}
public DescriptorProtos.OneofDescriptorProto build(int index) {
for (RubyFieldDescriptor field: fields) {
field.setOneofIndex(index);
}
return this.builder.build();
}
protected Collection<RubyFieldDescriptor> getFields() {
return fields;
}
protected Descriptors.OneofDescriptor getOneofDescriptor() {
RubyFieldDescriptor fieldDescriptor = fields.get(0);
return fieldDescriptor.getFieldDef().getContainingOneof();
}
private IRubyObject name;
private DescriptorProtos.OneofDescriptorProto.Builder builder;
private List<RubyFieldDescriptor> fields;
}
/*
* 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.Ruby;
import org.jruby.RubyModule;
import org.jruby.anno.JRubyMethod;
import org.jruby.anno.JRubyModule;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
@JRubyModule(name = "Protobuf")
public class RubyProtobuf {
public static void createProtobuf(Ruby runtime) {
RubyModule mGoogle = runtime.getModule("Google");
RubyModule mProtobuf = mGoogle.defineModuleUnder("Protobuf");
mProtobuf.defineAnnotatedMethods(RubyProtobuf.class);
}
/*
* call-seq:
* Google::Protobuf.encode(msg) => bytes
*
* Encodes the given message object to protocol buffers wire format. This is an
* alternative to the #encode method on msg's class.
*/
@JRubyMethod(meta = true)
public static IRubyObject encode(ThreadContext context, IRubyObject self, IRubyObject message) {
return RubyMessage.encode(context, message.getMetaClass(), message);
}
/*
* call-seq:
* Google::Protobuf.decode(class, bytes) => msg
*
* Decodes the given bytes as protocol buffers wire format under the
* interpretation given by the given class's message definition. This is an
* alternative to the #decode method on the given class.
*/
@JRubyMethod(meta = true)
public static IRubyObject decode(ThreadContext context, IRubyObject self, IRubyObject klazz, IRubyObject message) {
return RubyMessage.decode(context, klazz, message);
}
/*
* call-seq:
* Google::Protobuf.encode_json(msg) => json_string
*
* Encodes the given message object to its JSON representation. This is an
* alternative to the #encode_json method on msg's class.
*/
@JRubyMethod(name = "encode_json", meta = true)
public static IRubyObject encodeJson(ThreadContext context, IRubyObject self, IRubyObject message) {
return RubyMessage.encodeJson(context, message.getMetaClass(), message);
}
/*
* call-seq:
* Google::Protobuf.decode_json(class, json_string) => msg
*
* Decodes the given JSON string under the interpretation given by the given
* class's message definition. This is an alternative to the #decode_json method
* on the given class.
*/
@JRubyMethod(name = "decode_json", meta = true)
public static IRubyObject decodeJson(ThreadContext context, IRubyObject self, IRubyObject klazz, IRubyObject message) {
return RubyMessage.decodeJson(context, klazz, message);
}
/*
* call-seq:
* Google::Protobuf.deep_copy(obj) => copy_of_obj
*
* Performs a deep copy of either a RepeatedField instance or a message object,
* recursively copying its members.
*/
@JRubyMethod(name = "deep_copy", meta = true)
public static IRubyObject deepCopy(ThreadContext context, IRubyObject self, IRubyObject message) {
if (message instanceof RubyMessage) {
return ((RubyMessage) message).deepCopy(context);
} else if (message instanceof RubyRepeatedField) {
return ((RubyRepeatedField) message).deepCopy(context);
} else {
return ((RubyMap) message).deepCopy(context);
}
}
}
This diff is collapsed.
/*
* 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 google;
import com.google.protobuf.jruby.*;
import org.jruby.Ruby;
import org.jruby.runtime.load.BasicLibraryService;
import java.io.IOException;
public class ProtobufJavaService implements BasicLibraryService {
@Override
public boolean basicLoad(Ruby ruby) throws IOException {
ruby.defineModule("Google");
RubyProtobuf.createProtobuf(ruby);
RubyDescriptor.createRubyDescriptor(ruby);
RubyBuilder.createRubyBuilder(ruby);
RubyFieldDescriptor.createRubyFileDescriptor(ruby);
RubyMessageBuilderContext.createRubyMessageBuilderContext(ruby);
RubyEnumDescriptor.createRubyEnumDescriptor(ruby);
RubyEnumBuilderContext.createRubyEnumBuilderContext(ruby);
RubyDescriptorPool.createRubyDescriptorPool(ruby);
RubyRepeatedField.createRubyRepeatedField(ruby);
RubyFieldDescriptor.createRubyFileDescriptor(ruby);
RubyMap.createRubyMap(ruby);
RubyOneofDescriptor.createRubyOneofDescriptor(ruby);
RubyOneofBuilderContext.createRubyOneofBuilderContext(ruby);
return true;
}
}
syntax = "proto3";
package com.google.protobuf.jruby;
option optimize_for = CODE_SIZE;
message Sentinel {
optional int32 default_int32 = 1;
optional int64 default_int64 = 2;
optional uint32 default_unit32 = 3;
optional uint64 default_uint64 = 4;
optional string default_string = 5;
optional bool default_bool = 6;
optional float default_float = 7;
optional double default_double = 8;
optional bytes default_bytes = 9;
}
......@@ -972,6 +972,7 @@ module BasicTest
end
def test_json
skip("Unimplemented") if RUBY_PLATFORM == "java"
m = TestMessage.new(:optional_int32 => 1234,
:optional_int64 => -0x1_0000_0000,
:optional_uint32 => 0x8000_0000,
......@@ -994,6 +995,7 @@ module BasicTest
end
def test_json_maps
skip("Unimplemented") if RUBY_PLATFORM == "java"
m = MapMessage.new(:map_string_int32 => {"a" => 1})
expected = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
assert MapMessage.encode_json(m) == expected
......
......@@ -30,7 +30,7 @@ module StressTest
100_000.times do
mnew = TestMessage.decode(data)
mnew = mnew.dup
assert mnew.inspect == m.inspect
assert_equal mnew.inspect, m.inspect
assert TestMessage.encode(mnew) == data
end
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment