google-protobuf 3.0.0.alpha.2.0 → 3.0.0.alpha.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

@@ -28,4 +28,36 @@
28
28
  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
29
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
30
 
31
- require 'google/protobuf_c'
31
+ # require mixins before we hook them into the java & c code
32
+ require 'google/protobuf/message_exts'
33
+
34
+ if RUBY_PLATFORM == "java"
35
+ require 'json'
36
+ require 'google/protobuf_java'
37
+ else
38
+ require 'google/protobuf_c'
39
+ end
40
+
41
+ require 'google/protobuf/repeated_field'
42
+
43
+ module Google
44
+ module Protobuf
45
+
46
+ def self.encode(msg)
47
+ msg.to_proto
48
+ end
49
+
50
+ def self.encode_json(msg)
51
+ msg.to_json
52
+ end
53
+
54
+ def self.decode(klass, proto)
55
+ klass.decode(proto)
56
+ end
57
+
58
+ def self.decode_json(klass, json)
59
+ klass.decode_json(json)
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,53 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2008 Google Inc. All rights reserved.
3
+ # https://developers.google.com/protocol-buffers/
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are
7
+ # met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ # * Redistributions in binary form must reproduce the above
12
+ # copyright notice, this list of conditions and the following disclaimer
13
+ # in the documentation and/or other materials provided with the
14
+ # distribution.
15
+ # * Neither the name of Google Inc. nor the names of its
16
+ # contributors may be used to endorse or promote products derived from
17
+ # this software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ module Google
32
+ module Protobuf
33
+ module MessageExts
34
+
35
+ #this is only called in jruby; mri loades the ClassMethods differently
36
+ def self.included(klass)
37
+ klass.extend(ClassMethods)
38
+ end
39
+
40
+ module ClassMethods
41
+ end
42
+
43
+ def to_json
44
+ self.class.encode_json(self)
45
+ end
46
+
47
+ def to_proto
48
+ self.class.encode(self)
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,188 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2008 Google Inc. All rights reserved.
3
+ # https://developers.google.com/protocol-buffers/
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are
7
+ # met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ # * Redistributions in binary form must reproduce the above
12
+ # copyright notice, this list of conditions and the following disclaimer
13
+ # in the documentation and/or other materials provided with the
14
+ # distribution.
15
+ # * Neither the name of Google Inc. nor the names of its
16
+ # contributors may be used to endorse or promote products derived from
17
+ # this software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ require 'forwardable'
32
+
33
+ #
34
+ # This class makes RepeatedField act (almost-) like a Ruby Array.
35
+ # It has convenience methods that extend the core C or Java based
36
+ # methods.
37
+ #
38
+ # This is a best-effort to mirror Array behavior. Two comments:
39
+ # 1) patches always welcome :)
40
+ # 2) if performance is an issue, feel free to rewrite the method
41
+ # in jruby and C. The source code has plenty of examples
42
+ #
43
+ # KNOWN ISSUES
44
+ # - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'`
45
+ # - #concat should return the orig array
46
+ # - #push should accept multiple arguments and push them all at the same time
47
+ #
48
+ module Google
49
+ module Protobuf
50
+ class RepeatedField
51
+ extend Forwardable
52
+
53
+ # methods defined in C or Java:
54
+ # +
55
+ # [], at
56
+ # []=
57
+ # concat
58
+ # clear
59
+ # dup, clone
60
+ # each
61
+ # push, <<
62
+ # replace
63
+ # length, size
64
+ # ==
65
+ # to_ary, to_a
66
+ # also all enumerable
67
+ #
68
+ # NOTE: using delegators rather than method_missing to make the
69
+ # relationship explicit instead of implicit
70
+ def_delegators :to_ary,
71
+ :&, :*, :-, :'<=>',
72
+ :assoc, :bsearch, :combination, :compact, :count, :cycle,
73
+ :drop, :drop_while, :eql?, :fetch, :find_index, :flatten,
74
+ :include?, :index, :inspect, :join,
75
+ :pack, :permutation, :product, :pretty_print, :pretty_print_cycle,
76
+ :rassoc, :repeated_combination, :repeated_permutation, :reverse,
77
+ :rindex, :rotate, :sample, :shuffle, :shelljoin, :slice,
78
+ :to_s, :transpose, :uniq, :|
79
+
80
+
81
+ def first(n=nil)
82
+ n ? self[0..n] : self[0]
83
+ end
84
+
85
+
86
+ def last(n=nil)
87
+ n ? self[(self.size-n-1)..-1] : self[-1]
88
+ end
89
+
90
+
91
+ def pop(n=nil)
92
+ if n
93
+ results = []
94
+ n.times{ results << pop_one }
95
+ return results
96
+ else
97
+ return pop_one
98
+ end
99
+ end
100
+
101
+
102
+ def empty?
103
+ self.size == 0
104
+ end
105
+
106
+ # array aliases into enumerable
107
+ alias_method :each_index, :each_with_index
108
+ alias_method :slice, :[]
109
+ alias_method :values_at, :select
110
+ alias_method :map, :collect
111
+
112
+
113
+ class << self
114
+ def define_array_wrapper_method(method_name)
115
+ define_method(method_name) do |*args, &block|
116
+ arr = self.to_a
117
+ result = arr.send(method_name, *args)
118
+ self.replace(arr)
119
+ return result if result
120
+ return block ? block.call : result
121
+ end
122
+ end
123
+ private :define_array_wrapper_method
124
+
125
+
126
+ def define_array_wrapper_with_result_method(method_name)
127
+ define_method(method_name) do |*args, &block|
128
+ # result can be an Enumerator, Array, or nil
129
+ # Enumerator can sometimes be returned if a block is an optional argument and it is not passed in
130
+ # nil usually specifies that no change was made
131
+ result = self.to_a.send(method_name, *args, &block)
132
+ if result
133
+ new_arr = result.to_a
134
+ self.replace(new_arr)
135
+ if result.is_a?(Enumerator)
136
+ # generate a fresh enum; rewinding the exiting one, in Ruby 2.2, will
137
+ # reset the enum with the same length, but all the #next calls will
138
+ # return nil
139
+ result = new_arr.to_enum
140
+ # generate a wrapper enum so any changes which occur by a chained
141
+ # enum can be captured
142
+ ie = ProxyingEnumerator.new(self, result)
143
+ result = ie.to_enum
144
+ end
145
+ end
146
+ result
147
+ end
148
+ end
149
+ private :define_array_wrapper_with_result_method
150
+ end
151
+
152
+
153
+ %w(delete delete_at delete_if shift slice! unshift).each do |method_name|
154
+ define_array_wrapper_method(method_name)
155
+ end
156
+
157
+
158
+ %w(collect! compact! fill flatten! insert reverse!
159
+ rotate! select! shuffle! sort! sort_by! uniq!).each do |method_name|
160
+ define_array_wrapper_with_result_method(method_name)
161
+ end
162
+ alias_method :keep_if, :select!
163
+ alias_method :map!, :collect!
164
+ alias_method :reject!, :delete_if
165
+
166
+
167
+ # propagates changes made by user of enumerator back to the original repeated field.
168
+ # This only applies in cases where the calling function which created the enumerator,
169
+ # such as #sort!, modifies itself rather than a new array, such as #sort
170
+ class ProxyingEnumerator < Struct.new(:repeated_field, :external_enumerator)
171
+ def each(*args, &block)
172
+ results = []
173
+ external_enumerator.each_with_index do |val, i|
174
+ result = yield(val)
175
+ results << result
176
+ #nil means no change occured from yield; usually occurs when #to_a is called
177
+ if result
178
+ repeated_field[i] = result if result != val
179
+ end
180
+ end
181
+ results
182
+ end
183
+ end
184
+
185
+
186
+ end
187
+ end
188
+ end
data/tests/basic.rb CHANGED
@@ -8,6 +8,19 @@ require 'test/unit'
8
8
  module BasicTest
9
9
  pool = Google::Protobuf::DescriptorPool.new
10
10
  pool.build do
11
+ add_message "Foo" do
12
+ optional :bar, :message, 1, "Bar"
13
+ repeated :baz, :message, 2, "Baz"
14
+ end
15
+
16
+ add_message "Bar" do
17
+ optional :msg, :string, 1
18
+ end
19
+
20
+ add_message "Baz" do
21
+ optional :msg, :string, 1
22
+ end
23
+
11
24
  add_message "TestMessage" do
12
25
  optional :optional_int32, :int32, 1
13
26
  optional :optional_int64, :int64, 2
@@ -84,6 +97,9 @@ module BasicTest
84
97
  end
85
98
  end
86
99
 
100
+ Foo = pool.lookup("Foo").msgclass
101
+ Bar = pool.lookup("Bar").msgclass
102
+ Baz = pool.lookup("Baz").msgclass
87
103
  TestMessage = pool.lookup("TestMessage").msgclass
88
104
  TestMessage2 = pool.lookup("TestMessage2").msgclass
89
105
  Recursive1 = pool.lookup("Recursive1").msgclass
@@ -138,6 +154,8 @@ module BasicTest
138
154
  assert m.optional_bytes == "world"
139
155
  m.optional_msg = TestMessage2.new(:foo => 42)
140
156
  assert m.optional_msg == TestMessage2.new(:foo => 42)
157
+ m.optional_msg = nil
158
+ assert m.optional_msg == nil
141
159
  end
142
160
 
143
161
  def test_ctor_args
@@ -160,7 +178,7 @@ module BasicTest
160
178
  :optional_msg => TestMessage2.new,
161
179
  :repeated_string => ["hello", "there", "world"])
162
180
  expected = '<BasicTest::TestMessage: optional_int32: -42, optional_int64: 0, optional_uint32: 0, optional_uint64: 0, optional_bool: false, optional_float: 0.0, optional_double: 0.0, optional_string: "", optional_bytes: "", optional_msg: <BasicTest::TestMessage2: foo: 0>, optional_enum: :A, repeated_int32: [], repeated_int64: [], repeated_uint32: [], repeated_uint64: [], repeated_bool: [], repeated_float: [], repeated_double: [], repeated_string: ["hello", "there", "world"], repeated_bytes: [], repeated_msg: [], repeated_enum: []>'
163
- assert m.inspect == expected
181
+ assert_equal expected, m.inspect
164
182
  end
165
183
 
166
184
  def test_hash
@@ -258,7 +276,7 @@ module BasicTest
258
276
 
259
277
  assert l.inspect == '[5, 2, 3, 4]'
260
278
 
261
- l.insert(7, 8, 9)
279
+ l.concat([7, 8, 9])
262
280
  assert l == [5, 2, 3, 4, 7, 8, 9]
263
281
  assert l.pop == 9
264
282
  assert l == [5, 2, 3, 4, 7, 8]
@@ -298,6 +316,17 @@ module BasicTest
298
316
  assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102]
299
317
  end
300
318
 
319
+ def test_parent_rptfield
320
+ #make sure we set the RepeatedField and can add to it
321
+ m = TestMessage.new
322
+ assert m.repeated_string == []
323
+ m.repeated_string << 'ok'
324
+ m.repeated_string.push('ok2')
325
+ assert m.repeated_string == ['ok', 'ok2']
326
+ m.repeated_string += ['ok3']
327
+ assert m.repeated_string == ['ok', 'ok2', 'ok3']
328
+ end
329
+
301
330
  def test_rptfield_msg
302
331
  l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
303
332
  l.push TestMessage.new
@@ -361,6 +390,39 @@ module BasicTest
361
390
  end
362
391
  end
363
392
 
393
+ def test_rptfield_array_ducktyping
394
+ l = Google::Protobuf::RepeatedField.new(:int32)
395
+ length_methods = %w(count length size)
396
+ length_methods.each do |lm|
397
+ assert l.send(lm) == 0
398
+ end
399
+ # out of bounds returns a nil
400
+ assert l[0] == nil
401
+ assert l[1] == nil
402
+ assert l[-1] == nil
403
+ l.push 4
404
+ length_methods.each do |lm|
405
+ assert l.send(lm) == 1
406
+ end
407
+ assert l[0] == 4
408
+ assert l[1] == nil
409
+ assert l[-1] == 4
410
+ assert l[-2] == nil
411
+
412
+ l.push 2
413
+ length_methods.each do |lm|
414
+ assert l.send(lm) == 2
415
+ end
416
+ assert l[0] == 4
417
+ assert l[1] == 2
418
+ assert l[2] == nil
419
+ assert l[-1] == 2
420
+ assert l[-2] == 4
421
+ assert l[-3] == nil
422
+
423
+ #adding out of scope will backfill with empty objects
424
+ end
425
+
364
426
  def test_map_basic
365
427
  # allowed key types:
366
428
  # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.
@@ -696,9 +758,12 @@ module BasicTest
696
758
  m = TestMessage.new
697
759
  m.optional_string = "hello"
698
760
  m.optional_int32 = 42
699
- m.repeated_msg.push TestMessage2.new(:foo => 100)
700
- m.repeated_msg.push TestMessage2.new(:foo => 200)
701
-
761
+ tm1 = TestMessage2.new(:foo => 100)
762
+ tm2 = TestMessage2.new(:foo => 200)
763
+ m.repeated_msg.push tm1
764
+ assert m.repeated_msg[-1] == tm1
765
+ m.repeated_msg.push tm2
766
+ assert m.repeated_msg[-1] == tm2
702
767
  m2 = m.dup
703
768
  assert m == m2
704
769
  m.optional_int32 += 1
@@ -757,6 +822,67 @@ module BasicTest
757
822
  assert m == m2
758
823
  end
759
824
 
825
+ def test_encode_decode_helpers
826
+ m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
827
+ json = m.to_json
828
+ m2 = TestMessage.decode_json(json)
829
+ assert m2.optional_string == 'foo'
830
+ assert m2.repeated_string == ['bar1', 'bar2']
831
+
832
+ proto = m.to_proto
833
+ m2 = TestMessage.decode(proto)
834
+ assert m2.optional_string == 'foo'
835
+ assert m2.repeated_string == ['bar1', 'bar2']
836
+ end
837
+
838
+ def test_protobuf_encode_decode_helpers
839
+ m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
840
+ encoded_msg = Google::Protobuf.encode(m)
841
+ assert_equal m.to_proto, encoded_msg
842
+
843
+ decoded_msg = Google::Protobuf.decode(TestMessage, encoded_msg)
844
+ assert_equal TestMessage.decode(m.to_proto), decoded_msg
845
+ end
846
+
847
+ def test_protobuf_encode_decode_json_helpers
848
+ m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
849
+ encoded_msg = Google::Protobuf.encode_json(m)
850
+ assert_equal m.to_json, encoded_msg
851
+
852
+ decoded_msg = Google::Protobuf.decode_json(TestMessage, encoded_msg)
853
+ assert_equal TestMessage.decode_json(m.to_json), decoded_msg
854
+ end
855
+
856
+ def test_to_h
857
+ m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
858
+ expected_result = {
859
+ :optional_bool=>true,
860
+ :optional_bytes=>"",
861
+ :optional_double=>-10.100001,
862
+ :optional_enum=>:Default,
863
+ :optional_float=>0.0,
864
+ :optional_int32=>0,
865
+ :optional_int64=>0,
866
+ :optional_msg=>nil,
867
+ :optional_string=>"foo",
868
+ :optional_uint32=>0,
869
+ :optional_uint64=>0,
870
+ :repeated_bool=>[],
871
+ :repeated_bytes=>[],
872
+ :repeated_double=>[],
873
+ :repeated_enum=>[],
874
+ :repeated_float=>[],
875
+ :repeated_int32=>[],
876
+ :repeated_int64=>[],
877
+ :repeated_msg=>[],
878
+ :repeated_string=>["bar1", "bar2"],
879
+ :repeated_uint32=>[],
880
+ :repeated_uint64=>[]
881
+ }
882
+ assert_equal expected_result, m.to_h
883
+ end
884
+
885
+
760
886
  def test_def_errors
761
887
  s = Google::Protobuf::DescriptorPool.new
762
888
  assert_raise TypeError do
@@ -811,7 +937,6 @@ module BasicTest
811
937
  assert m['a.b'] == 4
812
938
  end
813
939
 
814
-
815
940
  def test_int_ranges
816
941
  m = TestMessage.new
817
942
 
@@ -917,7 +1042,6 @@ module BasicTest
917
1042
  assert_raise RangeError do
918
1043
  m.optional_uint64 = 1.5
919
1044
  end
920
-
921
1045
  end
922
1046
 
923
1047
  def test_stress_test
@@ -972,6 +1096,8 @@ module BasicTest
972
1096
  end
973
1097
 
974
1098
  def test_json
1099
+ # TODO: Fix JSON in JRuby version.
1100
+ return if RUBY_PLATFORM == "java"
975
1101
  m = TestMessage.new(:optional_int32 => 1234,
976
1102
  :optional_int64 => -0x1_0000_0000,
977
1103
  :optional_uint32 => 0x8000_0000,
@@ -991,9 +1117,19 @@ module BasicTest
991
1117
  json_text = TestMessage.encode_json(m)
992
1118
  m2 = TestMessage.decode_json(json_text)
993
1119
  assert m == m2
1120
+
1121
+ # Crash case from GitHub issue 283.
1122
+ bar = Bar.new(msg: "bar")
1123
+ baz1 = Baz.new(msg: "baz")
1124
+ baz2 = Baz.new(msg: "quux")
1125
+ Foo.encode_json(Foo.new)
1126
+ Foo.encode_json(Foo.new(bar: bar))
1127
+ Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2]))
994
1128
  end
995
1129
 
996
1130
  def test_json_maps
1131
+ # TODO: Fix JSON in JRuby version.
1132
+ return if RUBY_PLATFORM == "java"
997
1133
  m = MapMessage.new(:map_string_int32 => {"a" => 1})
998
1134
  expected = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
999
1135
  assert MapMessage.encode_json(m) == expected