msgpack 1.3.3 → 1.7.2

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 (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