msgpack 1.3.3 → 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +99 -0
  3. data/README.md +293 -0
  4. data/ext/java/org/msgpack/jruby/Buffer.java +26 -19
  5. data/ext/java/org/msgpack/jruby/Decoder.java +46 -23
  6. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  7. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +43 -64
  8. data/ext/java/org/msgpack/jruby/ExtensionValue.java +6 -9
  9. data/ext/java/org/msgpack/jruby/Factory.java +43 -42
  10. data/ext/java/org/msgpack/jruby/Packer.java +37 -40
  11. data/ext/java/org/msgpack/jruby/Unpacker.java +86 -68
  12. data/ext/msgpack/buffer.c +58 -85
  13. data/ext/msgpack/buffer.h +59 -20
  14. data/ext/msgpack/buffer_class.c +161 -52
  15. data/ext/msgpack/buffer_class.h +1 -0
  16. data/ext/msgpack/compat.h +1 -111
  17. data/ext/msgpack/extconf.rb +41 -23
  18. data/ext/msgpack/factory_class.c +143 -87
  19. data/ext/msgpack/packer.c +66 -43
  20. data/ext/msgpack/packer.h +25 -27
  21. data/ext/msgpack/packer_class.c +102 -130
  22. data/ext/msgpack/packer_class.h +11 -0
  23. data/ext/msgpack/packer_ext_registry.c +35 -40
  24. data/ext/msgpack/packer_ext_registry.h +41 -38
  25. data/ext/msgpack/rbinit.c +1 -1
  26. data/ext/msgpack/rmem.c +3 -4
  27. data/ext/msgpack/sysdep.h +5 -2
  28. data/ext/msgpack/unpacker.c +130 -126
  29. data/ext/msgpack/unpacker.h +22 -13
  30. data/ext/msgpack/unpacker_class.c +94 -124
  31. data/ext/msgpack/unpacker_class.h +11 -0
  32. data/ext/msgpack/unpacker_ext_registry.c +40 -28
  33. data/ext/msgpack/unpacker_ext_registry.h +21 -18
  34. data/lib/msgpack/bigint.rb +69 -0
  35. data/lib/msgpack/buffer.rb +9 -0
  36. data/lib/msgpack/factory.rb +140 -10
  37. data/lib/msgpack/packer.rb +10 -1
  38. data/lib/msgpack/symbol.rb +21 -4
  39. data/lib/msgpack/time.rb +1 -1
  40. data/lib/msgpack/unpacker.rb +14 -1
  41. data/lib/msgpack/version.rb +4 -8
  42. data/lib/msgpack.rb +7 -12
  43. data/msgpack.gemspec +9 -8
  44. metadata +37 -96
  45. data/.gitignore +0 -23
  46. data/.rubocop.yml +0 -36
  47. data/.travis.yml +0 -43
  48. data/Gemfile +0 -9
  49. data/README.rdoc +0 -225
  50. data/Rakefile +0 -78
  51. data/appveyor.yml +0 -18
  52. data/bench/pack.rb +0 -23
  53. data/bench/pack_log.rb +0 -33
  54. data/bench/pack_log_long.rb +0 -65
  55. data/bench/pack_symbols.rb +0 -28
  56. data/bench/run.sh +0 -14
  57. data/bench/run_long.sh +0 -35
  58. data/bench/run_symbols.sh +0 -26
  59. data/bench/unpack.rb +0 -21
  60. data/bench/unpack_log.rb +0 -34
  61. data/bench/unpack_log_long.rb +0 -67
  62. data/doclib/msgpack/buffer.rb +0 -193
  63. data/doclib/msgpack/core_ext.rb +0 -101
  64. data/doclib/msgpack/error.rb +0 -19
  65. data/doclib/msgpack/extension_value.rb +0 -9
  66. data/doclib/msgpack/factory.rb +0 -101
  67. data/doclib/msgpack/packer.rb +0 -208
  68. data/doclib/msgpack/time.rb +0 -22
  69. data/doclib/msgpack/timestamp.rb +0 -44
  70. data/doclib/msgpack/unpacker.rb +0 -183
  71. data/doclib/msgpack.rb +0 -87
  72. data/msgpack.org.md +0 -46
  73. data/spec/cases.json +0 -1
  74. data/spec/cases.msg +0 -0
  75. data/spec/cases_compact.msg +0 -0
  76. data/spec/cases_spec.rb +0 -39
  77. data/spec/cruby/buffer_io_spec.rb +0 -255
  78. data/spec/cruby/buffer_packer.rb +0 -29
  79. data/spec/cruby/buffer_spec.rb +0 -575
  80. data/spec/cruby/buffer_unpacker.rb +0 -19
  81. data/spec/cruby/unpacker_spec.rb +0 -70
  82. data/spec/ext_value_spec.rb +0 -99
  83. data/spec/exttypes.rb +0 -51
  84. data/spec/factory_spec.rb +0 -367
  85. data/spec/format_spec.rb +0 -301
  86. data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
  87. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
  88. data/spec/jruby/unpacker_spec.rb +0 -186
  89. data/spec/msgpack_spec.rb +0 -214
  90. data/spec/pack_spec.rb +0 -61
  91. data/spec/packer_spec.rb +0 -557
  92. data/spec/random_compat.rb +0 -24
  93. data/spec/spec_helper.rb +0 -38
  94. data/spec/timestamp_spec.rb +0 -121
  95. data/spec/unpack_spec.rb +0 -57
  96. data/spec/unpacker_spec.rb +0 -716
@@ -1,716 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- require 'stringio'
4
- require 'tempfile'
5
- require 'zlib'
6
-
7
- require 'spec_helper'
8
-
9
- describe MessagePack::Unpacker do
10
- let :unpacker do
11
- MessagePack::Unpacker.new
12
- end
13
-
14
- let :packer do
15
- MessagePack::Packer.new
16
- end
17
-
18
- it 'gets options to specify how to unpack values' do
19
- u1 = MessagePack::Unpacker.new
20
- u1.symbolize_keys?.should == false
21
- u1.allow_unknown_ext?.should == false
22
-
23
- u2 = MessagePack::Unpacker.new(symbolize_keys: true, allow_unknown_ext: true)
24
- u2.symbolize_keys?.should == true
25
- u2.allow_unknown_ext?.should == true
26
- end
27
-
28
- it 'gets IO or object which has #read to read data from it' do
29
- sample_data = {"message" => "morning!", "num" => 1}
30
- sample_packed = MessagePack.pack(sample_data).force_encoding('ASCII-8BIT')
31
-
32
- Tempfile.open("for_io") do |file|
33
- file.sync = true
34
- file.write sample_packed
35
- file.rewind
36
-
37
- u1 = MessagePack::Unpacker.new(file)
38
- u1.each do |obj|
39
- expect(obj).to eql(sample_data)
40
- end
41
- file.unlink
42
- end
43
-
44
- sio = StringIO.new(sample_packed)
45
- u2 = MessagePack::Unpacker.new(sio)
46
- u2.each do |obj|
47
- expect(obj).to eql(sample_data)
48
- end
49
-
50
- dio = StringIO.new
51
- Zlib::GzipWriter.wrap(dio){|gz| gz.write sample_packed }
52
- reader = Zlib::GzipReader.new(StringIO.new(dio.string))
53
- u3 = MessagePack::Unpacker.new(reader)
54
- u3.each do |obj|
55
- expect(obj).to eql(sample_data)
56
- end
57
-
58
- class DummyIO
59
- def initialize
60
- @buf = "".force_encoding('ASCII-8BIT')
61
- @pos = 0
62
- end
63
- def write(val)
64
- @buf << val.to_s
65
- end
66
- def read(length=nil,outbuf="")
67
- if @pos == @buf.size
68
- nil
69
- elsif length.nil?
70
- val = @buf[@pos..(@buf.size)]
71
- @pos = @buf.size
72
- outbuf << val
73
- outbuf
74
- else
75
- val = @buf[@pos..(@pos + length)]
76
- @pos += val.size
77
- @pos = @buf.size if @pos > @buf.size
78
- outbuf << val
79
- outbuf
80
- end
81
- end
82
- def flush
83
- # nop
84
- end
85
- end
86
-
87
- dio = DummyIO.new
88
- dio.write sample_packed
89
- u4 = MessagePack::Unpacker.new(dio)
90
- u4.each do |obj|
91
- expect(obj).to eql(sample_data)
92
- end
93
- end
94
-
95
- it 'read_array_header succeeds' do
96
- unpacker.feed("\x91")
97
- unpacker.read_array_header.should == 1
98
- end
99
-
100
- it 'read_array_header fails' do
101
- unpacker.feed("\x81")
102
- lambda {
103
- unpacker.read_array_header
104
- }.should raise_error(MessagePack::TypeError) # TypeError is included in UnexpectedTypeError
105
- lambda {
106
- unpacker.read_array_header
107
- }.should raise_error(MessagePack::UnexpectedTypeError)
108
- end
109
-
110
- it 'read_map_header converts an map to key-value sequence' do
111
- packer.write_array_header(2)
112
- packer.write("e")
113
- packer.write(1)
114
- unpacker = MessagePack::Unpacker.new
115
- unpacker.feed(packer.to_s)
116
- unpacker.read_array_header.should == 2
117
- unpacker.read.should == "e"
118
- unpacker.read.should == 1
119
- end
120
-
121
- it 'read_map_header succeeds' do
122
- unpacker.feed("\x81")
123
- unpacker.read_map_header.should == 1
124
- end
125
-
126
- it 'read_map_header converts an map to key-value sequence' do
127
- packer.write_map_header(1)
128
- packer.write("k")
129
- packer.write("v")
130
- unpacker = MessagePack::Unpacker.new
131
- unpacker.feed(packer.to_s)
132
- unpacker.read_map_header.should == 1
133
- unpacker.read.should == "k"
134
- unpacker.read.should == "v"
135
- end
136
-
137
- it 'read_map_header fails' do
138
- unpacker.feed("\x91")
139
- lambda {
140
- unpacker.read_map_header
141
- }.should raise_error(MessagePack::TypeError) # TypeError is included in UnexpectedTypeError
142
- lambda {
143
- unpacker.read_map_header
144
- }.should raise_error(MessagePack::UnexpectedTypeError)
145
- end
146
-
147
- it 'read raises EOFError before feeding' do
148
- lambda {
149
- unpacker.read
150
- }.should raise_error(EOFError)
151
- end
152
-
153
- let :sample_object do
154
- [1024, {["a","b"]=>["c","d"]}, ["e","f"], "d", 70000, 4.12, 1.5, 1.5, 1.5]
155
- end
156
-
157
- it 'feed and each continue internal state' do
158
- raw = sample_object.to_msgpack.to_s * 4
159
- objects = []
160
-
161
- raw.split(//).each do |b|
162
- unpacker.feed(b)
163
- unpacker.each {|c|
164
- objects << c
165
- }
166
- end
167
-
168
- objects.should == [sample_object] * 4
169
- end
170
-
171
- it 'feed_each continues internal state' do
172
- raw = sample_object.to_msgpack.to_s * 4
173
- objects = []
174
-
175
- raw.split(//).each do |b|
176
- unpacker.feed_each(b) {|c|
177
- objects << c
178
- }
179
- end
180
-
181
- objects.should == [sample_object] * 4
182
- end
183
-
184
- it 'feed_each enumerator' do
185
- raw = sample_object.to_msgpack.to_s * 4
186
-
187
- enum = unpacker.feed_each(raw)
188
- enum.should be_instance_of(Enumerator)
189
- enum.to_a.should == [sample_object] * 4
190
- end
191
-
192
- it 'reset clears internal buffer' do
193
- # 1-element array
194
- unpacker.feed("\x91")
195
- unpacker.reset
196
- unpacker.feed("\x01")
197
-
198
- unpacker.each.map {|x| x }.should == [1]
199
- end
200
-
201
- it 'reset clears internal state' do
202
- # 1-element array
203
- unpacker.feed("\x91")
204
- unpacker.each.map {|x| x }.should == []
205
-
206
- unpacker.reset
207
-
208
- unpacker.feed("\x01")
209
- unpacker.each.map {|x| x }.should == [1]
210
- end
211
-
212
- it 'frozen short strings' do
213
- raw = sample_object.to_msgpack.to_s.force_encoding('UTF-8')
214
- lambda {
215
- unpacker.feed_each(raw.freeze) { }
216
- }.should_not raise_error
217
- end
218
-
219
- it 'frozen long strings' do
220
- raw = (sample_object.to_msgpack.to_s * 10240).force_encoding('UTF-8')
221
- lambda {
222
- unpacker.feed_each(raw.freeze) { }
223
- }.should_not raise_error
224
- end
225
-
226
- it 'read raises invalid byte error' do
227
- unpacker.feed("\xc1")
228
- lambda {
229
- unpacker.read
230
- }.should raise_error(MessagePack::MalformedFormatError)
231
- end
232
-
233
- it "gc mark" do
234
- raw = sample_object.to_msgpack.to_s * 4
235
-
236
- n = 0
237
- raw.split(//).each do |b|
238
- GC.start
239
- unpacker.feed_each(b) {|o|
240
- GC.start
241
- o.should == sample_object
242
- n += 1
243
- }
244
- GC.start
245
- end
246
-
247
- n.should == 4
248
- end
249
-
250
- it "buffer" do
251
- orig = "a"*32*1024*4
252
- raw = orig.to_msgpack.to_s
253
-
254
- n = 655
255
- times = raw.size / n
256
- times += 1 unless raw.size % n == 0
257
-
258
- off = 0
259
- parsed = false
260
-
261
- times.times do
262
- parsed.should == false
263
-
264
- seg = raw[off, n]
265
- off += seg.length
266
-
267
- unpacker.feed_each(seg) {|obj|
268
- parsed.should == false
269
- obj.should == orig
270
- parsed = true
271
- }
272
- end
273
-
274
- parsed.should == true
275
- end
276
-
277
- it 'MessagePack.unpack symbolize_keys' do
278
- symbolized_hash = {:a => 'b', :c => 'd'}
279
- MessagePack.load(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash
280
- MessagePack.unpack(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash
281
- end
282
-
283
- it 'Unpacker#unpack symbolize_keys' do
284
- unpacker = MessagePack::Unpacker.new(:symbolize_keys => true)
285
- symbolized_hash = {:a => 'b', :c => 'd'}
286
- unpacker.feed(MessagePack.pack(symbolized_hash)).read.should == symbolized_hash
287
- end
288
-
289
- it "msgpack str 8 type" do
290
- MessagePack.unpack([0xd9, 0x00].pack('C*')).should == ""
291
- MessagePack.unpack([0xd9, 0x00].pack('C*')).encoding.should == Encoding::UTF_8
292
- MessagePack.unpack([0xd9, 0x01].pack('C*') + 'a').should == "a"
293
- MessagePack.unpack([0xd9, 0x02].pack('C*') + 'aa').should == "aa"
294
- end
295
-
296
- it "msgpack str 16 type" do
297
- MessagePack.unpack([0xda, 0x00, 0x00].pack('C*')).should == ""
298
- MessagePack.unpack([0xda, 0x00, 0x00].pack('C*')).encoding.should == Encoding::UTF_8
299
- MessagePack.unpack([0xda, 0x00, 0x01].pack('C*') + 'a').should == "a"
300
- MessagePack.unpack([0xda, 0x00, 0x02].pack('C*') + 'aa').should == "aa"
301
- end
302
-
303
- it "msgpack str 32 type" do
304
- MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x00].pack('C*')).should == ""
305
- MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x00].pack('C*')).encoding.should == Encoding::UTF_8
306
- MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x01].pack('C*') + 'a').should == "a"
307
- MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x02].pack('C*') + 'aa').should == "aa"
308
- end
309
-
310
- it "msgpack bin 8 type" do
311
- MessagePack.unpack([0xc4, 0x00].pack('C*')).should == ""
312
- MessagePack.unpack([0xc4, 0x00].pack('C*')).encoding.should == Encoding::ASCII_8BIT
313
- MessagePack.unpack([0xc4, 0x01].pack('C*') + 'a').should == "a"
314
- MessagePack.unpack([0xc4, 0x02].pack('C*') + 'aa').should == "aa"
315
- end
316
-
317
- it "msgpack bin 16 type" do
318
- MessagePack.unpack([0xc5, 0x00, 0x00].pack('C*')).should == ""
319
- MessagePack.unpack([0xc5, 0x00, 0x00].pack('C*')).encoding.should == Encoding::ASCII_8BIT
320
- MessagePack.unpack([0xc5, 0x00, 0x01].pack('C*') + 'a').should == "a"
321
- MessagePack.unpack([0xc5, 0x00, 0x02].pack('C*') + 'aa').should == "aa"
322
- end
323
-
324
- it "msgpack bin 32 type" do
325
- MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x00].pack('C*')).should == ""
326
- MessagePack.unpack([0xc6, 0x0, 0x00, 0x00, 0x000].pack('C*')).encoding.should == Encoding::ASCII_8BIT
327
- MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x01].pack('C*') + 'a').should == "a"
328
- MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x02].pack('C*') + 'aa').should == "aa"
329
- end
330
-
331
- describe "ext formats" do
332
- let(:unpacker) { MessagePack::Unpacker.new(allow_unknown_ext: true) }
333
-
334
- [1, 2, 4, 8, 16].zip([0xd4, 0xd5, 0xd6, 0xd7, 0xd8]).each do |n,b|
335
- it "msgpack fixext #{n} format" do
336
- unpacker.feed([b, 1].pack('CC') + "a"*n).unpack.should == MessagePack::ExtensionValue.new(1, "a"*n)
337
- unpacker.feed([b, -1].pack('CC') + "a"*n).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*n)
338
- end
339
- end
340
-
341
- it "msgpack ext 8 format" do
342
- unpacker.feed([0xc7, 0, 1].pack('CCC')).unpack.should == MessagePack::ExtensionValue.new(1, "")
343
- unpacker.feed([0xc7, 255, -1].pack('CCC') + "a"*255).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*255)
344
- end
345
-
346
- it "msgpack ext 16 format" do
347
- unpacker.feed([0xc8, 0, 1].pack('CnC')).unpack.should == MessagePack::ExtensionValue.new(1, "")
348
- unpacker.feed([0xc8, 256, -1].pack('CnC') + "a"*256).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*256)
349
- end
350
-
351
- it "msgpack ext 32 format" do
352
- unpacker.feed([0xc9, 0, 1].pack('CNC')).unpack.should == MessagePack::ExtensionValue.new(1, "")
353
- unpacker.feed([0xc9, 256, -1].pack('CNC') + "a"*256).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*256)
354
- unpacker.feed([0xc9, 65536, -1].pack('CNC') + "a"*65536).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*65536)
355
- end
356
- end
357
-
358
- class ValueOne
359
- attr_reader :num
360
- def initialize(num)
361
- @num = num
362
- end
363
- def ==(obj)
364
- self.num == obj.num
365
- end
366
- def num
367
- @num
368
- end
369
- def to_msgpack_ext
370
- @num.to_msgpack
371
- end
372
- def self.from_msgpack_ext(data)
373
- self.new(MessagePack.unpack(data))
374
- end
375
- end
376
-
377
- class ValueTwo
378
- attr_reader :num_s
379
- def initialize(num)
380
- @num_s = num.to_s
381
- end
382
- def ==(obj)
383
- self.num_s == obj.num_s
384
- end
385
- def num
386
- @num_s.to_i
387
- end
388
- def to_msgpack_ext
389
- @num_s.to_msgpack
390
- end
391
- def self.from_msgpack_ext(data)
392
- self.new(MessagePack.unpack(data))
393
- end
394
- end
395
-
396
- describe '#type_registered?' do
397
- it 'receive Class or Integer, and return bool' do
398
- expect(subject.type_registered?(0x00)).to be_falsy
399
- expect(subject.type_registered?(0x01)).to be_falsy
400
- expect(subject.type_registered?(::ValueOne)).to be_falsy
401
- end
402
-
403
- it 'returns true if specified type or class is already registered' do
404
- subject.register_type(0x30, ::ValueOne, :from_msgpack_ext)
405
- subject.register_type(0x31, ::ValueTwo, :from_msgpack_ext)
406
-
407
- expect(subject.type_registered?(0x00)).to be_falsy
408
- expect(subject.type_registered?(0x01)).to be_falsy
409
-
410
- expect(subject.type_registered?(0x30)).to be_truthy
411
- expect(subject.type_registered?(0x31)).to be_truthy
412
- expect(subject.type_registered?(::ValueOne)).to be_truthy
413
- expect(subject.type_registered?(::ValueTwo)).to be_truthy
414
- end
415
-
416
- it 'cannot detect unpack rule with block, not method' do
417
- subject.register_type(0x40){|data| ValueOne.from_msgpack_ext(data) }
418
-
419
- expect(subject.type_registered?(0x40)).to be_truthy
420
- expect(subject.type_registered?(ValueOne)).to be_falsy
421
- end
422
- end
423
-
424
- context 'with ext definitions' do
425
- it 'get type and class mapping for packing' do
426
- unpacker = MessagePack::Unpacker.new
427
- unpacker.register_type(0x01){|data| ValueOne.from_msgpack_ext }
428
- unpacker.register_type(0x02){|data| ValueTwo.from_msgpack_ext(data) }
429
-
430
- unpacker = MessagePack::Unpacker.new
431
- unpacker.register_type(0x01, ValueOne, :from_msgpack_ext)
432
- unpacker.register_type(0x02, ValueTwo, :from_msgpack_ext)
433
- end
434
-
435
- it 'returns a Array of Hash which contains :type, :class and :unpacker' do
436
- unpacker = MessagePack::Unpacker.new
437
- unpacker.register_type(0x02, ValueTwo, :from_msgpack_ext)
438
- unpacker.register_type(0x01, ValueOne, :from_msgpack_ext)
439
-
440
- list = unpacker.registered_types
441
-
442
- expect(list).to be_a(Array)
443
- expect(list.size).to eq(2)
444
-
445
- one = list[0]
446
- expect(one.keys.sort).to eq([:type, :class, :unpacker].sort)
447
- expect(one[:type]).to eq(0x01)
448
- expect(one[:class]).to eq(ValueOne)
449
- expect(one[:unpacker]).to eq(:from_msgpack_ext)
450
-
451
- two = list[1]
452
- expect(two.keys.sort).to eq([:type, :class, :unpacker].sort)
453
- expect(two[:type]).to eq(0x02)
454
- expect(two[:class]).to eq(ValueTwo)
455
- expect(two[:unpacker]).to eq(:from_msgpack_ext)
456
- end
457
-
458
- it 'returns a Array of Hash, which contains nil for class if block unpacker specified' do
459
- unpacker = MessagePack::Unpacker.new
460
- unpacker.register_type(0x01){|data| ValueOne.from_msgpack_ext }
461
- unpacker.register_type(0x02, &ValueTwo.method(:from_msgpack_ext))
462
-
463
- list = unpacker.registered_types
464
-
465
- expect(list).to be_a(Array)
466
- expect(list.size).to eq(2)
467
-
468
- one = list[0]
469
- expect(one.keys.sort).to eq([:type, :class, :unpacker].sort)
470
- expect(one[:type]).to eq(0x01)
471
- expect(one[:class]).to be_nil
472
- expect(one[:unpacker]).to be_instance_of(Proc)
473
-
474
- two = list[1]
475
- expect(two.keys.sort).to eq([:type, :class, :unpacker].sort)
476
- expect(two[:type]).to eq(0x02)
477
- expect(two[:class]).to be_nil
478
- expect(two[:unpacker]).to be_instance_of(Proc)
479
- end
480
-
481
- describe "registering an ext type for a module" do
482
- subject { unpacker.feed("\xc7\x06\x00module").unpack }
483
-
484
- let(:unpacker) { MessagePack::Unpacker.new }
485
-
486
- before do
487
- mod = Module.new do
488
- def self.from_msgpack_ext(data)
489
- "unpacked #{data}"
490
- end
491
- end
492
- stub_const('Mod', mod)
493
- end
494
-
495
- before { unpacker.register_type(0x00, Mod, :from_msgpack_ext) }
496
- it { is_expected.to eq "unpacked module" }
497
- end
498
- end
499
-
500
- def flatten(struct, results = [])
501
- case struct
502
- when Array
503
- struct.each { |v| flatten(v, results) }
504
- when Hash
505
- struct.each { |k, v| flatten(v, flatten(k, results)) }
506
- else
507
- results << struct
508
- end
509
- results
510
- end
511
-
512
- subject do
513
- described_class.new
514
- end
515
-
516
- let :buffer1 do
517
- MessagePack.pack(:foo => 'bar')
518
- end
519
-
520
- let :buffer2 do
521
- MessagePack.pack(:hello => {:world => [1, 2, 3]})
522
- end
523
-
524
- let :buffer3 do
525
- MessagePack.pack(:x => 'y')
526
- end
527
-
528
- describe '#read' do
529
- context 'with a buffer' do
530
- it 'reads objects' do
531
- objects = []
532
- subject.feed(buffer1)
533
- subject.feed(buffer2)
534
- subject.feed(buffer3)
535
- objects << subject.read
536
- objects << subject.read
537
- objects << subject.read
538
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
539
- end
540
-
541
- it 'reads map header' do
542
- subject.feed({}.to_msgpack)
543
- subject.read_map_header.should == 0
544
- end
545
-
546
- it 'reads array header' do
547
- subject.feed([].to_msgpack)
548
- subject.read_array_header.should == 0
549
- end
550
- end
551
- end
552
-
553
- describe '#each' do
554
- context 'with a buffer' do
555
- it 'yields each object in the buffer' do
556
- objects = []
557
- subject.feed(buffer1)
558
- subject.feed(buffer2)
559
- subject.feed(buffer3)
560
- subject.each do |obj|
561
- objects << obj
562
- end
563
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
564
- end
565
-
566
- it 'returns an enumerator when no block is given' do
567
- subject.feed(buffer1)
568
- subject.feed(buffer2)
569
- subject.feed(buffer3)
570
- enum = subject.each
571
- enum.map { |obj| obj.keys.first }.should == %w[foo hello x]
572
- end
573
- end
574
-
575
- context 'with a stream passed to the constructor' do
576
- it 'yields each object in the stream' do
577
- objects = []
578
- unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3))
579
- unpacker.each do |obj|
580
- objects << obj
581
- end
582
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
583
- end
584
- end
585
-
586
- context 'with a stream and symbolize_keys passed to the constructor' do
587
- it 'yields each object in the stream, with symbolized keys' do
588
- objects = []
589
- unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3), symbolize_keys: true)
590
- unpacker.each do |obj|
591
- objects << obj
592
- end
593
- objects.should == [{:foo => 'bar'}, {:hello => {:world => [1, 2, 3]}}, {:x => 'y'}]
594
- end
595
- end
596
- end
597
-
598
- describe '#feed_each' do
599
- it 'feeds the buffer then runs #each' do
600
- objects = []
601
- subject.feed_each(buffer1 + buffer2 + buffer3) do |obj|
602
- objects << obj
603
- end
604
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
605
- end
606
-
607
- it 'handles chunked data' do
608
- objects = []
609
- buffer = buffer1 + buffer2 + buffer3
610
- buffer.chars.each do |ch|
611
- subject.feed_each(ch) do |obj|
612
- objects << obj
613
- end
614
- end
615
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
616
- end
617
- end
618
-
619
- context 'regressions' do
620
- it 'handles massive arrays (issue #2)' do
621
- array = ['foo'] * 10_000
622
- MessagePack.unpack(MessagePack.pack(array)).size.should == 10_000
623
- end
624
- end
625
-
626
- context 'extensions' do
627
- context 'symbolized keys' do
628
- let :buffer do
629
- MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
630
- end
631
-
632
- let :unpacker do
633
- described_class.new(:symbolize_keys => true)
634
- end
635
-
636
- it 'can symbolize keys when using #each' do
637
- objs = []
638
- unpacker.feed(buffer)
639
- unpacker.each do |obj|
640
- objs << obj
641
- end
642
- objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}]
643
- end
644
-
645
- it 'can symbolize keys when using #feed_each' do
646
- objs = []
647
- unpacker.feed_each(buffer) do |obj|
648
- objs << obj
649
- end
650
- objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}]
651
- end
652
- end
653
-
654
- context 'binary encoding', :encodings do
655
- let :buffer do
656
- MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
657
- end
658
-
659
- let :unpacker do
660
- described_class.new()
661
- end
662
-
663
- it 'decodes binary as ascii-8bit when using #feed' do
664
- objs = []
665
- unpacker.feed(buffer)
666
- unpacker.each do |obj|
667
- objs << obj
668
- end
669
- strings = flatten(objs).grep(String)
670
- strings.should == %w[hello world nested object structure]
671
- strings.map(&:encoding).uniq.should == [Encoding::ASCII_8BIT]
672
- end
673
-
674
- it 'decodes binary as ascii-8bit when using #feed_each' do
675
- objs = []
676
- unpacker.feed_each(buffer) do |obj|
677
- objs << obj
678
- end
679
- strings = flatten(objs).grep(String)
680
- strings.should == %w[hello world nested object structure]
681
- strings.map(&:encoding).uniq.should == [Encoding::ASCII_8BIT]
682
- end
683
- end
684
-
685
- context 'string encoding', :encodings do
686
- let :buffer do
687
- MessagePack.pack({'hello'.force_encoding(Encoding::UTF_8) => 'world'.force_encoding(Encoding::UTF_8), 'nested'.force_encoding(Encoding::UTF_8) => ['object'.force_encoding(Encoding::UTF_8), {'structure'.force_encoding(Encoding::UTF_8) => true}]})
688
- end
689
-
690
- let :unpacker do
691
- described_class.new()
692
- end
693
-
694
- it 'decodes string as utf-8 when using #feed' do
695
- objs = []
696
- unpacker.feed(buffer)
697
- unpacker.each do |obj|
698
- objs << obj
699
- end
700
- strings = flatten(objs).grep(String)
701
- strings.should == %w[hello world nested object structure]
702
- strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
703
- end
704
-
705
- it 'decodes binary as ascii-8bit when using #feed_each' do
706
- objs = []
707
- unpacker.feed_each(buffer) do |obj|
708
- objs << obj
709
- end
710
- strings = flatten(objs).grep(String)
711
- strings.should == %w[hello world nested object structure]
712
- strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
713
- end
714
- end
715
- end
716
- end