ruby-protocol-buffers 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/.document +3 -0
  2. data/.gitignore +11 -0
  3. data/LICENSE +22 -0
  4. data/README +82 -0
  5. data/Rakefile +56 -0
  6. data/VERSION +1 -0
  7. data/bin/ruby-protoc +55 -0
  8. data/debian/changelog +105 -0
  9. data/debian/compatability +1 -0
  10. data/debian/control +12 -0
  11. data/debian/libprotobuf-ruby1.8.install +7 -0
  12. data/debian/protocol_buffers.rb +3 -0
  13. data/debian/rules +13 -0
  14. data/examples/json_protobuf.rb +90 -0
  15. data/ext/extconf.disabled.rb +3 -0
  16. data/ext/varint.c +65 -0
  17. data/lib/protocol_buffers.rb +5 -0
  18. data/lib/protocol_buffers/compiler.rb +48 -0
  19. data/lib/protocol_buffers/compiler/descriptor.pb.rb +236 -0
  20. data/lib/protocol_buffers/compiler/descriptor.proto +393 -0
  21. data/lib/protocol_buffers/compiler/file_descriptor_to_d.rb +195 -0
  22. data/lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb +173 -0
  23. data/lib/protocol_buffers/limited_io.rb +33 -0
  24. data/lib/protocol_buffers/runtime/decoder.rb +65 -0
  25. data/lib/protocol_buffers/runtime/encoder.rb +53 -0
  26. data/lib/protocol_buffers/runtime/enum.rb +4 -0
  27. data/lib/protocol_buffers/runtime/extend.rb +1 -0
  28. data/lib/protocol_buffers/runtime/field.rb +550 -0
  29. data/lib/protocol_buffers/runtime/message.rb +494 -0
  30. data/lib/protocol_buffers/runtime/service.rb +1 -0
  31. data/lib/protocol_buffers/runtime/varint.rb +62 -0
  32. data/spec/compiler_spec.rb +19 -0
  33. data/spec/fields_spec.rb +49 -0
  34. data/spec/proto_files/depends.proto +5 -0
  35. data/spec/proto_files/featureful.proto +54 -0
  36. data/spec/proto_files/no_package.proto +10 -0
  37. data/spec/proto_files/simple.proto +5 -0
  38. data/spec/runtime_spec.rb +430 -0
  39. data/spec/spec.opts +1 -0
  40. data/spec/spec_helper.rb +8 -0
  41. metadata +128 -0
@@ -0,0 +1 @@
1
+ # TODO
@@ -0,0 +1,62 @@
1
+ module ProtocolBuffers
2
+
3
+ module Varint # :nodoc:
4
+ # encode/decode methods defined in ext/varint.c
5
+
6
+ unless self.respond_to?(:encode)
7
+ def self.encode(io, int_val)
8
+ if int_val < 0
9
+ # negative varints are always encoded with the full 10 bytes
10
+ int_val = int_val & 0xffffffff_ffffffff
11
+ end
12
+ loop do
13
+ byte = int_val & 0b0111_1111
14
+ int_val >>= 7
15
+ if int_val == 0
16
+ io << byte.chr
17
+ break
18
+ else
19
+ io << (byte | 0b1000_0000).chr
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ unless self.respond_to?(:decode)
26
+ def self.decode(io)
27
+ int_val = 0
28
+ shift = 0
29
+ loop do
30
+ raise(DecodeError, "too many bytes when decoding varint") if shift >= 64
31
+ byte = io.getc.ord
32
+ int_val |= (byte & 0b0111_1111) << shift
33
+ shift += 7
34
+ return int_val if (byte & 0b1000_0000) == 0
35
+ end
36
+ end
37
+ end
38
+
39
+ def self.encodeZigZag32(int_val)
40
+ (int_val << 1) ^ (int_val >> 31)
41
+ end
42
+
43
+ def self.encodeZigZag64(int_val)
44
+ (int_val << 1) ^ (int_val >> 63)
45
+ end
46
+
47
+ def self.decodeZigZag32(int_val)
48
+ (int_val >> 1) ^ -(int_val & 1)
49
+ end
50
+ class << self; alias_method :decodeZigZag64, :decodeZigZag32 end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ # fix for 1.8 <-> 1.9 compat
57
+ unless 'a'.respond_to?(:ord)
58
+ class String; def ord; self[0]; end; end
59
+ end
60
+ unless (1).respond_to?(:ord)
61
+ class Fixnum; def ord; self; end; end
62
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
4
+ require 'protocol_buffers'
5
+ require 'protocol_buffers/compiler'
6
+
7
+ describe ProtocolBuffers, "compiler" do
8
+
9
+ test_files = Dir[File.join(File.dirname(__FILE__), "proto_files", "*.proto")]
10
+
11
+ test_files.each do |file|
12
+ it "can compile #{File.basename(file)}" do
13
+ proc do
14
+ ProtocolBuffers::Compiler.compile_and_load(file)
15
+ end.should_not raise_error()
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ require 'stringio'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
6
+ require 'protocol_buffers/runtime/field'
7
+
8
+ describe ProtocolBuffers, "fields" do
9
+
10
+ def mkfield(ftype)
11
+ ProtocolBuffers::Field.const_get(ftype).new(:optional, "test", 1)
12
+ end
13
+
14
+ it "checks bounds on varint field types" do
15
+ u32 = mkfield(:Uint32Field)
16
+ proc { u32.check_valid(0xFFFFFFFF) }.should_not raise_error()
17
+ proc { u32.check_valid(0x100000000) }.should raise_error(ArgumentError)
18
+ proc { u32.check_valid(-1) }.should raise_error(ArgumentError)
19
+
20
+ u64 = mkfield(:Uint64Field)
21
+ proc { u64.check_valid(0xFFFFFFFF_FFFFFFFF) }.should_not raise_error()
22
+ proc { u64.check_valid(0x100000000_00000000) }.should raise_error(ArgumentError)
23
+ proc { u64.check_valid(-1) }.should raise_error(ArgumentError)
24
+ end
25
+
26
+ it "properly encodes and decodes negative varints" do
27
+ val = -2082844800000000
28
+ str = "\200\300\313\274\236\265\246\374\377\001"
29
+ sio = StringIO.new
30
+ ProtocolBuffers::Varint.encode(sio, val)
31
+ sio.string.should == str
32
+ sio.rewind
33
+ val2 = ProtocolBuffers::Varint.decode(sio)
34
+ int64 = mkfield(:Int64Field)
35
+ int64.deserialize(val2).should == val
36
+ proc { int64.check_value(int64.deserialize(val2)) }.should_not raise_error
37
+ end
38
+
39
+ it "verifies UTF-8 for string fields" do
40
+ pending("do UTF-8 validation") do
41
+ s1 = mkfield(:StringField)
42
+ proc { s1.check_valid("hello") }.should_not raise_error()
43
+ proc { s1.check_valid("\xff\xff") }.should raise_error(ArgumentError)
44
+ b1 = mkfield(:BytesField)
45
+ proc { b1.check_valid("\xff\xff") }.should_not raise_error()
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,5 @@
1
+ package depends;
2
+
3
+ import "simple.proto";
4
+
5
+ message Depends {}
@@ -0,0 +1,54 @@
1
+ package featureful;
2
+
3
+ message A {
4
+ message Sub {
5
+ enum Payloads {
6
+ P1 = 0;
7
+ P2 = 1;
8
+ };
9
+
10
+ optional string payload = 1;
11
+ required Payloads payload_type = 2 [default = P1];
12
+
13
+ message SubSub {
14
+ optional string subsub_payload = 1;
15
+ };
16
+ optional SubSub subsub1 = 3;
17
+ };
18
+
19
+ repeated int32 i1 = 1;
20
+ optional int32 i2 = 2;
21
+ required int32 i3 = 3;
22
+
23
+ repeated Sub sub1 = 4;
24
+ optional Sub sub2 = 5;
25
+ required Sub sub3 = 6;
26
+ };
27
+
28
+ message B {
29
+ repeated A a = 1;
30
+ };
31
+
32
+ enum MainPayloads {
33
+ P1 = 2;
34
+ P2 = 3;
35
+ P3 = 4;
36
+ };
37
+
38
+ message ABitOfEverything {
39
+ optional double double_field = 1;
40
+ optional float float_field = 2;
41
+ optional int32 int32_field = 3;
42
+ optional int64 int64_field = 4 [default = 15];
43
+ optional uint32 uint32_field = 5;
44
+ optional uint64 uint64_field = 6;
45
+ optional sint32 sint32_field = 7;
46
+ optional sint64 sint64_field = 8;
47
+ optional fixed32 fixed32_field = 9;
48
+ optional fixed64 fixed64_field = 10;
49
+ optional sfixed32 sfixed32_field = 11;
50
+ optional sfixed64 sfixed64_field = 12;
51
+ optional bool bool_field = 13 [default = false];
52
+ optional string string_field = 14 [default = "zomgkittenz"];
53
+ optional bytes bytes_field = 15;
54
+ };
@@ -0,0 +1,10 @@
1
+ message A {
2
+ message B {
3
+ };
4
+
5
+ optional B b = 1;
6
+ };
7
+
8
+ message C {
9
+ optional A.B b = 1;
10
+ };
@@ -0,0 +1,5 @@
1
+ package simple;
2
+
3
+ message Test1 {
4
+ optional string test_field = 1;
5
+ };
@@ -0,0 +1,430 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ require 'stringio'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
6
+ require 'protocol_buffers'
7
+ require 'protocol_buffers/compiler'
8
+
9
+ ProtocolBuffers::Compiler.compile_and_load(
10
+ File.join(File.dirname(__FILE__), "proto_files", "simple.proto"))
11
+ ProtocolBuffers::Compiler.compile_and_load(
12
+ File.join(File.dirname(__FILE__), "proto_files", "featureful.proto"))
13
+
14
+ describe ProtocolBuffers, "runtime" do
15
+
16
+ it "can handle basic operations" do
17
+
18
+ msg1 = Simple::Test1.new
19
+ msg1.test_field.should == ""
20
+
21
+ msg1.test_field = "zomgkittenz"
22
+
23
+ ser = StringIO.new(msg1.to_s)
24
+ msg2 = Simple::Test1.parse(ser)
25
+ msg2.test_field.should == "zomgkittenz"
26
+ msg2.should == msg1
27
+ end
28
+
29
+ it "doesn't serialize unset fields" do
30
+ msg1 = Simple::Test1.new
31
+ msg1.test_field.should == ""
32
+ msg1.to_s.should == ""
33
+
34
+ msg1.test_field = "zomgkittenz"
35
+ msg1.to_s.should_not == ""
36
+ end
37
+
38
+ it "flags values that have been set" do
39
+ a1 = Featureful::A.new
40
+ a1.has_i2?.should == false
41
+ a1.i2 = 5
42
+ a1.has_i2?.should == true
43
+ end
44
+
45
+ it "flags sub-messages that have been set" do
46
+ a1 = Featureful::A.new
47
+ a1.value_for_tag?(a1.class.field_for_name(:sub1).tag).should == true
48
+ a1.value_for_tag?(a1.class.field_for_name(:sub2).tag).should == false
49
+ a1.value_for_tag?(a1.class.field_for_name(:sub3).tag).should == false
50
+
51
+ a1.has_sub1?.should == true
52
+ a1.has_sub2?.should == false
53
+ a1.has_sub3?.should == false
54
+
55
+ a1.sub2 = Featureful::A::Sub.new(:payload => "ohai")
56
+ a1.has_sub2?.should == true
57
+ end
58
+
59
+ it "detects changes to a sub-message and flags it as set if it wasn't" do
60
+ a1 = Featureful::A.new
61
+ a1.has_sub2?.should == false
62
+ a1.sub2.payload = "ohai"
63
+ a1.has_sub2?.should == true
64
+ end
65
+
66
+ it "detects changes to a sub-sub-message and flags up the chain" do
67
+ a1 = Featureful::A.new
68
+ a1.sub2.has_subsub1?.should == false
69
+ a1.has_sub2?.should == false
70
+ a1.sub2.subsub1.subsub_payload = "ohai"
71
+ a1.has_sub2?.should == true
72
+ a1.sub2.has_subsub1?.should == true
73
+ end
74
+
75
+ it "pretends that repeated fields are arrays" do
76
+ # make sure our RepeatedField class acts like a normal Array
77
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
78
+ package foo;
79
+ message Foo {
80
+ repeated int32 nums = 1;
81
+ }
82
+ EOS
83
+
84
+ foo = Foo::Foo.new
85
+ foo2 = Foo::Foo.new(:nums => [1,2,3])
86
+ proc do
87
+ foo.nums << 1
88
+ foo.nums.class.should == ProtocolBuffers::RepeatedField
89
+ foo.nums.to_a.class.should == Array
90
+ (foo.nums & foo2.nums).should == [1]
91
+ (foo.nums + foo2.nums).should == [1,1,2,3]
92
+ foo2.nums.map! { |i| i + 1 }
93
+ foo2.nums.to_a.should == [2,3,4]
94
+ foo2.nums.class.should == ProtocolBuffers::RepeatedField
95
+ end.should_not raise_error
96
+ end
97
+
98
+ it "does type checking of repeated fields" do
99
+ a1 = Featureful::A.new
100
+ proc do
101
+ a1.sub1 << Featureful::A::Sub.new
102
+ end.should_not raise_error(TypeError)
103
+
104
+ a1 = Featureful::A.new
105
+ proc do
106
+ a1.sub1 << Featureful::A::Sub.new << "dummy string"
107
+ end.should raise_error(TypeError)
108
+ a1.sub1.should == [Featureful::A::Sub.new]
109
+
110
+ a1 = Featureful::A.new
111
+ proc do
112
+ a1.sub1 = [Featureful::A::Sub.new, Featureful::A::Sub.new, 5, Featureful::A::Sub.new]
113
+ end.should raise_error(TypeError)
114
+ end
115
+
116
+ it "does value checking of repeated fields" do
117
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
118
+ package foo;
119
+ message Foo {
120
+ repeated int32 nums = 1;
121
+ }
122
+ EOS
123
+
124
+ foo = Foo::Foo.new
125
+ proc do
126
+ foo.nums << 5 << 3 << (1 << 32) # value too large for int32
127
+ end.should raise_error(ArgumentError)
128
+ end
129
+
130
+ # sort of redundant test, but let's check the example in the docs for
131
+ # correctness
132
+ it "handles singular message fields exactly as in the documentation" do
133
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
134
+ package foo;
135
+ message Foo {
136
+ optional Bar bar = 1;
137
+ }
138
+ message Bar {
139
+ optional int32 i = 1;
140
+ }
141
+ EOS
142
+
143
+ foo = Foo::Foo.new
144
+ foo.has_bar?.should == false
145
+ foo.bar = Foo::Bar.new
146
+ foo.has_bar?.should == true
147
+
148
+ foo = Foo::Foo.new
149
+ foo.has_bar?.should == false
150
+ foo.bar.i = 1
151
+ foo.has_bar?.should == true
152
+
153
+ foo = Foo::Foo.new
154
+ foo.has_bar?.should == false
155
+ local_i = foo.bar.i
156
+ foo.has_bar?.should == false
157
+ end
158
+
159
+ # another example from the docs
160
+ it "handles repeated field logic" do
161
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
162
+ package foo;
163
+ message Foo {
164
+ repeated int32 nums = 1;
165
+ }
166
+ EOS
167
+
168
+ foo = Foo::Foo.new
169
+ foo.has_nums?.should == true
170
+ foo.nums << 15
171
+ foo.has_nums?.should == true
172
+ foo.nums.push(32)
173
+ foo.nums.length.should == 2
174
+ foo.nums[0].should == 15
175
+ foo.nums[1].should == 32
176
+ foo.nums[1] = 56
177
+ foo.nums[1].should == 56
178
+
179
+ foo = Foo::Foo.new
180
+ foo.nums << 15
181
+ foo.nums.push(32)
182
+ foo.nums.length.should == 2
183
+ foo.nums.clear
184
+ foo.nums.length.should == 0
185
+ foo.nums << 15
186
+ foo.nums.length.should == 1
187
+ foo.nums = nil
188
+ foo.nums.length.should == 0
189
+
190
+ foo = Foo::Foo.new
191
+ foo.nums << 15
192
+ foo.nums = [1, 3, 5]
193
+ foo.nums.length.should == 3
194
+ foo.nums.to_a.should == [1,3,5]
195
+
196
+ foo.merge_from_string(foo.to_s)
197
+ foo.nums.length.should == 6
198
+ foo.nums.to_a.should == [1,3,5,1,3,5]
199
+ end
200
+
201
+ it "can assign any object with an each method to a repeated field" do
202
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
203
+ package foo;
204
+ message Foo {
205
+ repeated Bar nums = 1;
206
+ }
207
+ message Bar {
208
+ optional int32 i = 1;
209
+ }
210
+ EOS
211
+
212
+ class Blah
213
+ def each
214
+ yield Foo::Bar.new(:i => 1)
215
+ yield Foo::Bar.new(:i => 3)
216
+ end
217
+ end
218
+
219
+ foo = Foo::Foo.new
220
+ foo.nums = Blah.new
221
+ foo.nums.to_a.should == [Foo::Bar.new(:i => 1), Foo::Bar.new(:i => 3)]
222
+ end
223
+
224
+ it "shouldn't modify the default Message instance like this" do
225
+ a1 = Featureful::A.new
226
+ a1.sub2.payload = "ohai"
227
+ a2 = Featureful::A.new
228
+ a2.sub2.payload.should == ""
229
+ sub = Featureful::A::Sub.new
230
+ sub.payload.should == ""
231
+ end
232
+
233
+ it "doesn't allow defining fields after gen_methods is called" do
234
+ proc do
235
+ A.define_field(:optional, :string, "newfield", 15)
236
+ end.should raise_error()
237
+ end
238
+
239
+ def filled_in_bit
240
+ bit = Featureful::ABitOfEverything.new
241
+ bit.int64_field.should == 15
242
+ bit.bool_field.should == false
243
+ bit.string_field.should == "zomgkittenz"
244
+ bit.double_field = 1.0
245
+ bit.float_field = 2.0
246
+ bit.int32_field = 3
247
+ bit.int64_field = 4
248
+ bit.uint32_field = 5
249
+ bit.uint64_field = 6
250
+ bit.sint32_field = 7
251
+ bit.sint64_field = 8
252
+ bit.fixed32_field = 9
253
+ bit.fixed64_field = 10
254
+ bit.sfixed32_field = 11
255
+ bit.sfixed64_field = 12
256
+ bit.bool_field = true
257
+ bit.string_field = "14"
258
+ bit.bytes_field = "15"
259
+ bit
260
+ end
261
+
262
+ it "can serialize and de-serialize all basic field types" do
263
+ bit = filled_in_bit
264
+
265
+ bit2 = Featureful::ABitOfEverything.parse(bit.to_s)
266
+ bit.should == bit2
267
+ bit.fields.each do |tag, field|
268
+ bit.value_for_tag(tag).should == bit2.value_for_tag(tag)
269
+ end
270
+ end
271
+
272
+ it "does type checking" do
273
+ bit = filled_in_bit
274
+
275
+ proc do
276
+ bit.fixed32_field = 1.0
277
+ end.should raise_error(TypeError)
278
+
279
+ proc do
280
+ bit.double_field = 15
281
+ end.should_not raise_error()
282
+ bit2 = Featureful::ABitOfEverything.parse(bit.to_s)
283
+ bit2.double_field.should == 15
284
+ bit2.double_field.should == 15.0
285
+ bit2.double_field.is_a?(Float).should == true
286
+
287
+ proc do
288
+ bit.bool_field = 1.0
289
+ end.should raise_error(TypeError)
290
+
291
+ proc do
292
+ bit.string_field = 1.0
293
+ end.should raise_error(TypeError)
294
+
295
+ a1 = Featureful::A.new
296
+ proc do
297
+ a1.sub2 = "zomgkittenz"
298
+ end.should raise_error(TypeError)
299
+ end
300
+
301
+ it "doesn't allow invalid enum values" do
302
+ sub = Featureful::A::Sub.new
303
+
304
+ proc do
305
+ sub.payload_type.should == 0
306
+ sub.payload_type = Featureful::A::Sub::Payloads::P2
307
+ sub.payload_type.should == 1
308
+ end.should_not raise_error()
309
+
310
+ proc do
311
+ sub.payload_type = 2
312
+ end.should raise_error(ArgumentError)
313
+ end
314
+
315
+ it "enforces required fields on serialization" do
316
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
317
+ package tehUnknown;
318
+ message MyResult {
319
+ required string field_1 = 1;
320
+ optional string field_2 = 2;
321
+ }
322
+ EOS
323
+
324
+ res1 = TehUnknown::MyResult.new(:field_2 => 'b')
325
+
326
+ proc { res1.to_s }.should raise_error(ProtocolBuffers::EncodeError)
327
+ end
328
+
329
+ it "enforces required fields on deserialization" do
330
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
331
+ package tehUnknown;
332
+ message MyResult {
333
+ optional string field_1 = 1;
334
+ optional string field_2 = 2;
335
+ }
336
+ EOS
337
+
338
+ res1 = TehUnknown::MyResult.new(:field_2 => 'b')
339
+ buf = res1.to_s
340
+
341
+ # now make field_1 required
342
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
343
+ package tehUnknown;
344
+ message MyResult {
345
+ required string field_1 = 1;
346
+ optional string field_2 = 2;
347
+ }
348
+ EOS
349
+
350
+ proc { TehUnknown::MyResult.parse(buf) }.should raise_error(ProtocolBuffers::DecodeError)
351
+ end
352
+
353
+ it "enforces valid values on deserialization" do
354
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
355
+ package tehUnknown;
356
+ message MyResult {
357
+ optional int32 field_1 = 1;
358
+ }
359
+ EOS
360
+
361
+ res1 = TehUnknown::MyResult.new(:field_1 => 5)
362
+ buf = res1.to_s
363
+
364
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
365
+ package tehUnknown;
366
+ message MyResult {
367
+ enum E { A = 1; }
368
+ optional E field_1 = 1;
369
+ }
370
+ EOS
371
+
372
+ proc { TehUnknown::MyResult.parse(buf) }.should raise_error(ProtocolBuffers::DecodeError)
373
+ end
374
+
375
+ it "ignores and passes on unknown fields" do
376
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
377
+ package tehUnknown;
378
+ message MyResult {
379
+ optional int32 field_1 = 1;
380
+ optional int32 field_2 = 2;
381
+ optional int32 field_3 = 3;
382
+ optional int32 field_4 = 4;
383
+ }
384
+ EOS
385
+
386
+ res1 = TehUnknown::MyResult.new(:field_1 => 0xffff, :field_2 => 0xfffe,
387
+ :field_3 => 0xfffd, :field_4 => 0xfffc)
388
+ serialized = res1.to_s
389
+
390
+ # remove field_2 to pretend we never knew about it
391
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
392
+ package tehUnknown;
393
+ message MyResult {
394
+ optional int32 field_1 = 1;
395
+ optional int32 field_3 = 3;
396
+ }
397
+ EOS
398
+
399
+ res2 = nil
400
+ proc do
401
+ res2 = TehUnknown::MyResult.parse(serialized)
402
+ end.should_not raise_error()
403
+
404
+ res2.field_1.should == 0xffff
405
+ res2.field_3.should == 0xfffd
406
+
407
+ proc do
408
+ res2.field_2.should == 0xfffe
409
+ end.should raise_error(NoMethodError)
410
+
411
+ serialized2 = res2.to_s
412
+
413
+ # now we know about field_2 again
414
+ ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
415
+ package tehUnknown;
416
+ message MyResult {
417
+ optional int32 field_1 = 1;
418
+ optional int32 field_2 = 2;
419
+ optional int32 field_4 = 4;
420
+ }
421
+ EOS
422
+
423
+ res3 = TehUnknown::MyResult.parse(serialized2)
424
+ res3.field_1.should == 0xffff
425
+
426
+ res3.field_2.should == 0xfffe
427
+ res3.field_4.should == 0xfffc
428
+ end
429
+
430
+ end