ruby-protocol-buffers 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -5
- data/.travis.yml +20 -0
- data/Gemfile +5 -1
- data/Gemfile.no_varint +4 -0
- data/README.md +7 -0
- data/Rakefile +3 -18
- data/lib/protocol_buffers.rb +3 -3
- data/lib/protocol_buffers/compiler.rb +7 -0
- data/lib/protocol_buffers/compiler/descriptor.pb.rb +63 -30
- data/lib/protocol_buffers/compiler/descriptor.proto +252 -25
- data/lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb +7 -1
- data/lib/protocol_buffers/runtime/decoder.rb +18 -2
- data/lib/protocol_buffers/runtime/encoder.rb +17 -2
- data/lib/protocol_buffers/runtime/field.rb +14 -3
- data/lib/protocol_buffers/runtime/varint.rb +42 -36
- data/lib/protocol_buffers/version.rb +3 -0
- data/ruby-protocol-buffers.gemspec +22 -21
- data/spec/compiler_spec.rb +22 -0
- data/spec/fields_spec.rb +54 -16
- data/spec/proto_files/featureful.pb.rb +76 -0
- data/spec/proto_files/packed.pb.rb +37 -0
- data/spec/proto_files/packed.proto +30 -0
- data/spec/proto_files/simple.pb.rb +23 -0
- data/spec/runtime_spec.rb +211 -164
- data/spec/spec_helper.rb +24 -7
- data/tasks/rspec.rake +7 -0
- data/tasks/yard.rake +6 -0
- metadata +34 -6
- data/VERSION +0 -1
- data/ext/extconf.disabled.rb +0 -3
- data/ext/varint.c +0 -65
@@ -8,7 +8,7 @@ class FileDescriptorToRuby < Struct.new(:descriptor)
|
|
8
8
|
|
9
9
|
def initialize(descriptor)
|
10
10
|
super
|
11
|
-
@package_modules = descriptor.
|
11
|
+
@package_modules = descriptor.package ? descriptor.package.split('.') : []
|
12
12
|
@ns = []
|
13
13
|
end
|
14
14
|
|
@@ -126,6 +126,12 @@ HEADER
|
|
126
126
|
if field.default_value && field.default_value != ""
|
127
127
|
fieldline << %{, :default => #{default_value(field)}}
|
128
128
|
end
|
129
|
+
|
130
|
+
# Dont need to check for 'repeated' attribute or type, protoc will take care of this.
|
131
|
+
if field.options.packed
|
132
|
+
fieldline << %{, :packed => true }
|
133
|
+
end
|
134
|
+
|
129
135
|
line fieldline
|
130
136
|
end
|
131
137
|
end
|
@@ -14,7 +14,7 @@ module ProtocolBuffers
|
|
14
14
|
wire_type = tag_int & 0b111
|
15
15
|
field = fields[tag]
|
16
16
|
|
17
|
-
if field && wire_type
|
17
|
+
if field && ( !( field.packed? || wire_type == field.wire_type ) || ( field.packed? && wire_type != 2 ) )
|
18
18
|
raise(DecodeError, "incorrect wire type for tag: #{field.tag}, expected #{field.wire_type} but got #{wire_type}\n#{field.inspect}")
|
19
19
|
end
|
20
20
|
|
@@ -39,7 +39,23 @@ module ProtocolBuffers
|
|
39
39
|
|
40
40
|
if field
|
41
41
|
begin
|
42
|
-
|
42
|
+
if field.packed?
|
43
|
+
deserialized = []
|
44
|
+
until value.eof?
|
45
|
+
|
46
|
+
decoded = case field.wire_type
|
47
|
+
when 0 # VARINT
|
48
|
+
Varint.decode(value)
|
49
|
+
when 1 # FIXED64
|
50
|
+
value.read(8)
|
51
|
+
when 5 # FIXED32
|
52
|
+
value.read(4)
|
53
|
+
end
|
54
|
+
deserialized << field.deserialize(decoded)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
deserialized = field.deserialize(value)
|
58
|
+
end
|
43
59
|
# merge_field handles repeated field logic
|
44
60
|
message.merge_field(tag, deserialized, field)
|
45
61
|
rescue ArgumentError
|
@@ -20,8 +20,20 @@ module ProtocolBuffers
|
|
20
20
|
tag = (field.tag << 3) | wire_type
|
21
21
|
|
22
22
|
if field.repeated?
|
23
|
-
value.
|
24
|
-
|
23
|
+
next if value.size == 0
|
24
|
+
|
25
|
+
if field.packed?
|
26
|
+
# encode packed field in a LENGTH_DELIMITED wire
|
27
|
+
wire_type = 2
|
28
|
+
tag = (field.tag << 3) | wire_type
|
29
|
+
buf = StringIO.new
|
30
|
+
value.each { |i| serialize_field_value(buf, field.wire_type, field.serialize(i)) }
|
31
|
+
Varint.encode(io, tag)
|
32
|
+
Varint.encode(io, buf.size)
|
33
|
+
io.write(buf.string)
|
34
|
+
else
|
35
|
+
value.each { |i| serialize_field(io, tag, wire_type, field.serialize(i)) }
|
36
|
+
end
|
25
37
|
else
|
26
38
|
serialize_field(io, tag, wire_type, field.serialize(value))
|
27
39
|
end
|
@@ -36,7 +48,10 @@ module ProtocolBuffers
|
|
36
48
|
def self.serialize_field(io, tag, wire_type, serialized)
|
37
49
|
# write the tag
|
38
50
|
Varint.encode(io, tag)
|
51
|
+
self.serialize_field_value(io, wire_type, serialized)
|
52
|
+
end
|
39
53
|
|
54
|
+
def self.serialize_field_value(io, wire_type, serialized)
|
40
55
|
# see comment in decoder.rb about magic numbers
|
41
56
|
case wire_type
|
42
57
|
when 0 # VARINT
|
@@ -97,6 +97,7 @@ module ProtocolBuffers
|
|
97
97
|
attr_reader :otype, :name, :tag
|
98
98
|
|
99
99
|
def repeated?; otype == :repeated end
|
100
|
+
def packed?; repeated? && @opts[:packed] end
|
100
101
|
|
101
102
|
def self.create(sender, otype, type, name, tag, opts = {})
|
102
103
|
if type.is_a?(Symbol)
|
@@ -294,16 +295,26 @@ module ProtocolBuffers
|
|
294
295
|
|
295
296
|
def check_value(value)
|
296
297
|
if HAS_ENCODING
|
297
|
-
value.valid_encoding? || raise(ArgumentError, "string value is not valid utf-8")
|
298
|
+
value.dup.force_encoding(Encoding::UTF_8).valid_encoding? || raise(ArgumentError, "string value is not valid utf-8")
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def serialize(value)
|
303
|
+
check_value(value)
|
304
|
+
if HAS_ENCODING
|
305
|
+
value.dup.force_encoding(Encoding::UTF_8)
|
306
|
+
else
|
307
|
+
value
|
298
308
|
end
|
299
309
|
end
|
300
310
|
|
301
311
|
def deserialize(value)
|
302
312
|
read_value = value.read.to_s
|
303
313
|
if HAS_ENCODING
|
304
|
-
read_value.force_encoding(
|
314
|
+
read_value.force_encoding(Encoding::UTF_8)
|
315
|
+
else
|
316
|
+
read_value
|
305
317
|
end
|
306
|
-
read_value
|
307
318
|
end
|
308
319
|
end
|
309
320
|
|
@@ -1,41 +1,41 @@
|
|
1
1
|
module ProtocolBuffers
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
break
|
18
|
-
else
|
19
|
-
io << (byte | 0b1000_0000).chr
|
20
|
-
end
|
3
|
+
module VarintPure # :nodoc:
|
4
|
+
def encode(io, int_val)
|
5
|
+
if int_val < 0
|
6
|
+
# negative varints are always encoded with the full 10 bytes
|
7
|
+
int_val = int_val & 0xffffffff_ffffffff
|
8
|
+
end
|
9
|
+
loop do
|
10
|
+
byte = int_val & 0b0111_1111
|
11
|
+
int_val >>= 7
|
12
|
+
if int_val == 0
|
13
|
+
io << byte.chr
|
14
|
+
break
|
15
|
+
else
|
16
|
+
io << (byte | 0b1000_0000).chr
|
21
17
|
end
|
22
18
|
end
|
23
19
|
end
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
21
|
+
def decode(io)
|
22
|
+
int_val = 0
|
23
|
+
shift = 0
|
24
|
+
loop do
|
25
|
+
raise(DecodeError, "too many bytes when decoding varint") if shift >= 64
|
26
|
+
# this works in 1.8.7 and 1.9.x, but for different reasons
|
27
|
+
# in 1.8.7 io.getc returns the int representation of the char, and .ord is a noop. String#ord doesn't exist.
|
28
|
+
# in 1.9.3 io.getc returns a String, and .ord returns the int representation of the first char.
|
29
|
+
# this fails in 1.8.6, which is no longer supported by ruby-protocol-buffers.
|
30
|
+
byte = io.getc.ord
|
31
|
+
int_val |= (byte & 0b0111_1111) << shift
|
32
|
+
shift += 7
|
33
|
+
return int_val if (byte & 0b1000_0000) == 0
|
36
34
|
end
|
37
35
|
end
|
36
|
+
end
|
38
37
|
|
38
|
+
class Varint
|
39
39
|
def self.encodeZigZag32(int_val)
|
40
40
|
(int_val << 1) ^ (int_val >> 31)
|
41
41
|
end
|
@@ -47,16 +47,22 @@ module ProtocolBuffers
|
|
47
47
|
def self.decodeZigZag32(int_val)
|
48
48
|
(int_val >> 1) ^ -(int_val & 1)
|
49
49
|
end
|
50
|
-
class << self; alias_method :decodeZigZag64, :decodeZigZag32 end
|
51
50
|
|
51
|
+
class << self
|
52
|
+
alias_method :decodeZigZag64, :decodeZigZag32
|
53
|
+
end
|
52
54
|
end
|
53
55
|
|
54
56
|
end
|
55
57
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
# optionally load C extension
|
59
|
+
begin
|
60
|
+
require 'varint/varint'
|
61
|
+
class ProtocolBuffers::Varint
|
62
|
+
extend ::Varint
|
63
|
+
end
|
64
|
+
rescue LoadError
|
65
|
+
class ProtocolBuffers::Varint
|
66
|
+
extend ::ProtocolBuffers::VarintPure
|
67
|
+
end
|
62
68
|
end
|
@@ -1,27 +1,28 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "protocol_buffers/version"
|
4
5
|
|
5
|
-
Gem::Specification.new do |
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
s.summary = %{Ruby compiler and runtime for the google protocol buffers library.}
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "ruby-protocol-buffers"
|
8
|
+
gem.version = ProtocolBuffers::VERSION
|
9
|
+
gem.authors = ["Brian Palmer", "Benedikt Böhm", "Rob Marable", "Paulo Luis Franchini Casaretto"]
|
10
|
+
gem.email = ["brian@codekitchen.net", "bb@xnull.de"]
|
11
|
+
gem.summary = %{Ruby compiler and runtime for the google protocol buffers library.}
|
12
|
+
gem.homepage = "https://github.com/mozy/ruby-protocol-buffers"
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
18
|
|
19
|
-
|
19
|
+
gem.extra_rdoc_files << "Changelog.md"
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
gem.add_development_dependency "autotest-standalone"
|
22
|
+
gem.add_development_dependency "autotest-growl"
|
23
|
+
gem.add_development_dependency "rake"
|
24
|
+
gem.add_development_dependency "rake-compiler"
|
25
|
+
gem.add_development_dependency "simplecov"
|
26
|
+
gem.add_development_dependency "rspec", "~> 2.5"
|
27
|
+
gem.add_development_dependency "yard"
|
27
28
|
end
|
data/spec/compiler_spec.rb
CHANGED
@@ -8,6 +8,10 @@ describe ProtocolBuffers, "compiler" do
|
|
8
8
|
|
9
9
|
test_files = Dir[File.join(File.dirname(__FILE__), "proto_files", "*.proto")]
|
10
10
|
|
11
|
+
before do
|
12
|
+
pending "need protoc installed" unless has_compiler?
|
13
|
+
end
|
14
|
+
|
11
15
|
test_files.each do |file|
|
12
16
|
it "can compile #{File.basename(file)}" do
|
13
17
|
proc do
|
@@ -16,4 +20,22 @@ describe ProtocolBuffers, "compiler" do
|
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
23
|
+
it "can compile and instantiate a message in a package with under_scores" do
|
24
|
+
Object.send(:remove_const, :UnderScore) if defined?(UnderScore)
|
25
|
+
|
26
|
+
ProtocolBuffers::Compiler.compile_and_load(
|
27
|
+
File.join(File.dirname(__FILE__), "proto_files", "under_score_package.proto"))
|
28
|
+
|
29
|
+
proc do
|
30
|
+
under_test = UnderScore::UnderTest.new
|
31
|
+
end.should_not raise_error()
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should compile and correctly translate" do
|
35
|
+
ProtocolBuffers::Compiler.compile_and_load(
|
36
|
+
File.join(File.dirname(__FILE__), "proto_files", "simple.proto"))
|
37
|
+
ProtocolBuffers::Compiler.compile_and_load(
|
38
|
+
File.join(File.dirname(__FILE__), "proto_files", "featureful.proto"))
|
39
|
+
end
|
40
|
+
|
19
41
|
end
|
data/spec/fields_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
|
1
3
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
4
|
|
3
5
|
require 'stringio'
|
@@ -36,25 +38,61 @@ describe ProtocolBuffers, "fields" do
|
|
36
38
|
proc { int64.check_value(int64.deserialize(val2)) }.should_not raise_error
|
37
39
|
end
|
38
40
|
|
39
|
-
|
41
|
+
context "UTF-8 encoding of length-delimited fields" do
|
40
42
|
if RUBY_VERSION < "1.9"
|
41
43
|
pending "UTF-8 validation only happens in ruby 1.9+"
|
42
44
|
else
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
45
|
+
|
46
|
+
before :each do
|
47
|
+
@good_utf = "\xc2\xa1hola\x21"
|
48
|
+
@bad_utf = "\xc2"
|
49
|
+
@good_ascii = "!hola!".force_encoding("us-ascii")
|
50
|
+
|
51
|
+
@good_utf_io = proc { StringIO.new(@good_utf) }
|
52
|
+
@bad_utf_io = proc { StringIO.new(@bad_utf) }
|
53
|
+
@good_ascii_io = proc { StringIO.new(@good_ascii) }
|
54
|
+
|
55
|
+
@s = mkfield(:StringField)
|
56
|
+
@b = mkfield(:BytesField)
|
57
|
+
end
|
58
|
+
|
59
|
+
context "string fields" do
|
60
|
+
|
61
|
+
it "forces UTF-8 on serializing" do
|
62
|
+
@s.serialize(@good_utf).encoding.should == Encoding::UTF_8
|
63
|
+
proc { @s.check_valid(@s.serialize(@good_utf)) }.should_not raise_error()
|
64
|
+
|
65
|
+
@s.serialize(@good_ascii).encoding.should == Encoding::UTF_8
|
66
|
+
proc { @s.check_valid(@s.serialize(@good_ascii)) }.should_not raise_error()
|
67
|
+
|
68
|
+
proc { @s.serialize(@bad_utf) }.should raise_error(ArgumentError)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "forces UTF-8 on deserializing" do
|
72
|
+
@s.deserialize(@good_utf_io[]).encoding.should == Encoding::UTF_8
|
73
|
+
proc { @s.check_valid(@s.deserialize(@good_utf_io[])) }.should_not raise_error()
|
74
|
+
|
75
|
+
@s.deserialize(@good_ascii_io[]).encoding.should == Encoding::UTF_8
|
76
|
+
proc { @s.check_valid(@s.deserialize(@good_ascii_io[])) }.should_not raise_error()
|
77
|
+
|
78
|
+
@s.deserialize(@bad_utf_io[]).encoding.should == Encoding::UTF_8
|
79
|
+
proc { @s.check_valid(@s.deserialize(@bad_utf_io[])) }.should raise_error(ArgumentError)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "byte fields" do
|
84
|
+
|
85
|
+
it "does not force UTF-8 on deserializing" do
|
86
|
+
@b.deserialize(@good_utf_io[]).encoding.should == Encoding::BINARY
|
87
|
+
proc { @b.check_valid(@b.deserialize(@good_utf_io[])) }.should_not raise_error()
|
88
|
+
|
89
|
+
@b.deserialize(@good_ascii_io[]).encoding.should == Encoding.find("us-ascii")
|
90
|
+
proc { @b.check_valid(@b.deserialize(@good_ascii_io[])) }.should_not raise_error()
|
91
|
+
|
92
|
+
@b.deserialize(@bad_utf_io[]).encoding.should == Encoding::BINARY
|
93
|
+
proc { @b.check_valid(@b.deserialize(@bad_utf_io[])) }.should_not raise_error()
|
94
|
+
end
|
95
|
+
end
|
58
96
|
end
|
59
97
|
end
|
60
98
|
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
3
|
+
|
4
|
+
require 'protocol_buffers'
|
5
|
+
|
6
|
+
module Featureful
|
7
|
+
# forward declarations
|
8
|
+
class A < ::ProtocolBuffers::Message; end
|
9
|
+
class B < ::ProtocolBuffers::Message; end
|
10
|
+
class ABitOfEverything < ::ProtocolBuffers::Message; end
|
11
|
+
|
12
|
+
# enums
|
13
|
+
module MainPayloads
|
14
|
+
include ::ProtocolBuffers::Enum
|
15
|
+
P1 = 2
|
16
|
+
P2 = 3
|
17
|
+
P3 = 4
|
18
|
+
end
|
19
|
+
|
20
|
+
class A < ::ProtocolBuffers::Message
|
21
|
+
# forward declarations
|
22
|
+
class Sub < ::ProtocolBuffers::Message; end
|
23
|
+
|
24
|
+
# nested messages
|
25
|
+
class Sub < ::ProtocolBuffers::Message
|
26
|
+
# forward declarations
|
27
|
+
class SubSub < ::ProtocolBuffers::Message; end
|
28
|
+
|
29
|
+
# enums
|
30
|
+
module Payloads
|
31
|
+
include ::ProtocolBuffers::Enum
|
32
|
+
P1 = 0
|
33
|
+
P2 = 1
|
34
|
+
end
|
35
|
+
|
36
|
+
# nested messages
|
37
|
+
class SubSub < ::ProtocolBuffers::Message
|
38
|
+
optional :string, :subsub_payload, 1
|
39
|
+
end
|
40
|
+
|
41
|
+
optional :string, :payload, 1
|
42
|
+
required ::Featureful::A::Sub::Payloads, :payload_type, 2, :default => ::Featureful::A::Sub::Payloads::P1
|
43
|
+
optional ::Featureful::A::Sub::SubSub, :subsub1, 3
|
44
|
+
end
|
45
|
+
|
46
|
+
repeated :int32, :i1, 1
|
47
|
+
optional :int32, :i2, 2
|
48
|
+
required :int32, :i3, 3
|
49
|
+
repeated ::Featureful::A::Sub, :sub1, 4
|
50
|
+
optional ::Featureful::A::Sub, :sub2, 5
|
51
|
+
required ::Featureful::A::Sub, :sub3, 6
|
52
|
+
end
|
53
|
+
|
54
|
+
class B < ::ProtocolBuffers::Message
|
55
|
+
repeated ::Featureful::A, :a, 1
|
56
|
+
end
|
57
|
+
|
58
|
+
class ABitOfEverything < ::ProtocolBuffers::Message
|
59
|
+
optional :double, :double_field, 1
|
60
|
+
optional :float, :float_field, 2
|
61
|
+
optional :int32, :int32_field, 3
|
62
|
+
optional :int64, :int64_field, 4, :default => 15
|
63
|
+
optional :uint32, :uint32_field, 5
|
64
|
+
optional :uint64, :uint64_field, 6
|
65
|
+
optional :sint32, :sint32_field, 7
|
66
|
+
optional :sint64, :sint64_field, 8
|
67
|
+
optional :fixed32, :fixed32_field, 9
|
68
|
+
optional :fixed64, :fixed64_field, 10
|
69
|
+
optional :sfixed32, :sfixed32_field, 11
|
70
|
+
optional :sfixed64, :sfixed64_field, 12
|
71
|
+
optional :bool, :bool_field, 13, :default => false
|
72
|
+
optional :string, :string_field, 14, :default => "zomgkittenz"
|
73
|
+
optional :bytes, :bytes_field, 15
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|