msgpack 1.4.0.pre1 → 1.4.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.
data/ext/msgpack/buffer.h CHANGED
@@ -49,11 +49,11 @@
49
49
 
50
50
  #define NO_MAPPED_STRING ((VALUE)0)
51
51
 
52
- #ifdef COMPAT_HAVE_ENCODING /* see compat.h*/
53
52
  extern int msgpack_rb_encindex_utf8;
54
53
  extern int msgpack_rb_encindex_usascii;
55
54
  extern int msgpack_rb_encindex_ascii8bit;
56
- #endif
55
+
56
+ extern ID s_uminus;
57
57
 
58
58
  struct msgpack_buffer_chunk_t;
59
59
  typedef struct msgpack_buffer_chunk_t msgpack_buffer_chunk_t;
@@ -438,7 +438,7 @@ static inline VALUE _msgpack_buffer_refer_head_mapped_string(msgpack_buffer_t* b
438
438
  return rb_str_substr(b->head->mapped_string, offset, length);
439
439
  }
440
440
 
441
- static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen)
441
+ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen, bool utf8)
442
442
  {
443
443
  #ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE
444
444
  /* optimize */
@@ -446,16 +446,52 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
446
446
  b->head->mapped_string != NO_MAPPED_STRING &&
447
447
  length >= b->read_reference_threshold) {
448
448
  VALUE result = _msgpack_buffer_refer_head_mapped_string(b, length);
449
+ if (utf8) ENCODING_SET(result, msgpack_rb_encindex_utf8);
449
450
  _msgpack_buffer_consumed(b, length);
450
451
  return result;
451
452
  }
452
453
  #endif
453
454
 
454
- VALUE result = rb_str_new(b->read_buffer, length);
455
+ VALUE result;
456
+
457
+ #ifdef HAVE_RB_ENC_INTERNED_STR
458
+ if (will_be_frozen) {
459
+ result = rb_enc_interned_str(b->read_buffer, length, utf8 ? rb_utf8_encoding() : rb_ascii8bit_encoding());
460
+ } else {
461
+ if (utf8) {
462
+ result = rb_utf8_str_new(b->read_buffer, length);
463
+ } else {
464
+ result = rb_str_new(b->read_buffer, length);
465
+ }
466
+ }
455
467
  _msgpack_buffer_consumed(b, length);
456
468
  return result;
457
- }
458
469
 
470
+ #else
459
471
 
460
- #endif
472
+ if (utf8) {
473
+ result = rb_utf8_str_new(b->read_buffer, length);
474
+ } else {
475
+ result = rb_str_new(b->read_buffer, length);
476
+ }
477
+
478
+ #if STR_UMINUS_DEDUPE
479
+ if (will_be_frozen) {
480
+ #if STR_UMINUS_DEDUPE_FROZEN
481
+ // Starting from MRI 2.8 it is preferable to freeze the string
482
+ // before deduplication so that it can be interned directly
483
+ // otherwise it would be duplicated first which is wasteful.
484
+ rb_str_freeze(result);
485
+ #endif //STR_UMINUS_DEDUPE_FROZEN
486
+ // MRI 2.5 and older do not deduplicate strings that are already
487
+ // frozen.
488
+ result = rb_funcall(result, s_uminus, 0);
489
+ }
490
+ #endif // STR_UMINUS_DEDUPE
491
+ _msgpack_buffer_consumed(b, length);
492
+ return result;
493
+
494
+ #endif // HAVE_RB_ENC_INTERNED_STR
495
+ }
461
496
 
497
+ #endif
data/ext/msgpack/compat.h CHANGED
@@ -20,6 +20,7 @@
20
20
 
21
21
  #include <stdbool.h>
22
22
  #include "ruby.h"
23
+ #include "ruby/encoding.h"
23
24
 
24
25
  #if defined(HAVE_RUBY_ST_H)
25
26
  # include "ruby/st.h" /* ruby hash on Ruby 1.9 */
@@ -38,18 +39,6 @@
38
39
  # define ZALLOC_N(type,n) RB_ZALLOC_N(type,n)
39
40
  #endif
40
41
 
41
- /*
42
- * COMPAT_HAVE_ENCODING
43
- */
44
- #ifdef HAVE_RUBY_ENCODING_H
45
- # include "ruby/encoding.h"
46
- # define COMPAT_HAVE_ENCODING
47
- #endif
48
-
49
- #if defined(__MACRUBY__) /* MacRuby */
50
- # undef COMPAT_HAVE_ENCODING
51
- #endif
52
-
53
42
 
54
43
  /*
55
44
  * define STR_DUP_LIKELY_DOES_COPY
@@ -4,6 +4,7 @@ have_header("ruby/st.h")
4
4
  have_header("st.h")
5
5
  have_func("rb_str_replace", ["ruby.h"])
6
6
  have_func("rb_intern_str", ["ruby.h"])
7
+ have_func("rb_enc_interned_str", "ruby.h")
7
8
  have_func("rb_sym2str", ["ruby.h"])
8
9
  have_func("rb_str_intern", ["ruby.h"])
9
10
  have_func("rb_block_lambda", ["ruby.h"])
@@ -37,6 +38,32 @@ else
37
38
  $CFLAGS << ' -DHASH_ASET_DEDUPE=0 '
38
39
  end
39
40
 
41
+
42
+ # checking if String#-@ (str_uminus) dedupes... '
43
+ begin
44
+ a = -(%w(t e s t).join)
45
+ b = -(%w(t e s t).join)
46
+ if a.equal?(b)
47
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
48
+ else
49
+ $CFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
50
+ end
51
+ rescue NoMethodError
52
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
53
+ end
54
+
55
+ # checking if String#-@ (str_uminus) directly interns frozen strings... '
56
+ begin
57
+ s = rand.to_s.freeze
58
+ if (-s).equal?(s) && (-s.dup).equal?(s)
59
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
60
+ else
61
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
62
+ end
63
+ rescue NoMethodError
64
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
65
+ end
66
+
40
67
  if warnflags = CONFIG['warnflags']
41
68
  warnflags.slice!(/ -Wdeclaration-after-statement/)
42
69
  end
data/ext/msgpack/packer.h CHANGED
@@ -396,7 +396,6 @@ static inline void msgpack_packer_write_ext(msgpack_packer_t* pk, int ext_type,
396
396
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), payload);
397
397
  }
398
398
 
399
- #ifdef COMPAT_HAVE_ENCODING
400
399
  static inline bool msgpack_packer_is_binary(VALUE v, int encindex)
401
400
  {
402
401
  return encindex == msgpack_rb_encindex_ascii8bit;
@@ -414,7 +413,6 @@ static inline bool msgpack_packer_is_utf8_compat_string(VALUE v, int encindex)
414
413
  #endif
415
414
  ;
416
415
  }
417
- #endif
418
416
 
419
417
  static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE v)
420
418
  {
@@ -425,7 +423,6 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
425
423
  rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %lu", len, 0xffffffffUL);
426
424
  }
427
425
 
428
- #ifdef COMPAT_HAVE_ENCODING
429
426
  int encindex = ENCODING_GET(v);
430
427
  if(msgpack_packer_is_binary(v, encindex) && !pk->compatibility_mode) {
431
428
  /* write ASCII-8BIT string using Binary type */
@@ -443,10 +440,6 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
443
440
  msgpack_packer_write_raw_header(pk, (unsigned int)len);
444
441
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
445
442
  }
446
- #else
447
- msgpack_packer_write_raw_header(pk, (unsigned int)len);
448
- msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
449
- #endif
450
443
  }
451
444
 
452
445
  static inline void msgpack_packer_write_symbol_string_value(msgpack_packer_t* pk, VALUE v)
@@ -142,33 +142,17 @@ static inline void reset_head_byte(msgpack_unpacker_t* uk)
142
142
 
143
143
  static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
144
144
  {
145
+ if(uk->freeze) {
146
+ rb_obj_freeze(object);
147
+ }
148
+
145
149
  uk->last_object = object;
146
150
  reset_head_byte(uk);
147
151
  return PRIMITIVE_OBJECT_COMPLETE;
148
152
  }
149
153
 
150
- static inline int object_complete_string(msgpack_unpacker_t* uk, VALUE str)
151
- {
152
- #ifdef COMPAT_HAVE_ENCODING
153
- ENCODING_SET(str, msgpack_rb_encindex_utf8);
154
- #endif
155
- return object_complete(uk, str);
156
- }
157
-
158
- static inline int object_complete_binary(msgpack_unpacker_t* uk, VALUE str)
159
- {
160
- #ifdef COMPAT_HAVE_ENCODING
161
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
162
- #endif
163
- return object_complete(uk, str);
164
- }
165
-
166
154
  static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
167
155
  {
168
- #ifdef COMPAT_HAVE_ENCODING
169
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
170
- #endif
171
-
172
156
  VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type);
173
157
  if(proc != Qnil) {
174
158
  VALUE obj = rb_funcall(proc, s_call, 1, str);
@@ -271,9 +255,10 @@ static int read_raw_body_cont(msgpack_unpacker_t* uk)
271
255
 
272
256
  int ret;
273
257
  if(uk->reading_raw_type == RAW_TYPE_STRING) {
274
- ret = object_complete_string(uk, uk->reading_raw);
275
- } else if(uk->reading_raw_type == RAW_TYPE_BINARY) {
276
- ret = object_complete_binary(uk, uk->reading_raw);
258
+ ENCODING_SET(uk->reading_raw, msgpack_rb_encindex_utf8);
259
+ ret = object_complete(uk, uk->reading_raw);
260
+ } else if (uk->reading_raw_type == RAW_TYPE_BINARY) {
261
+ ret = object_complete(uk, uk->reading_raw);
277
262
  } else {
278
263
  ret = object_complete_ext(uk, uk->reading_raw_type, uk->reading_raw);
279
264
  }
@@ -290,13 +275,11 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
290
275
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
291
276
  /* don't use zerocopy for hash keys but get a frozen string directly
292
277
  * because rb_hash_aset freezes keys and it causes copying */
293
- bool will_freeze = is_reading_map_key(uk);
294
- VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze);
278
+ bool will_freeze = uk->freeze || is_reading_map_key(uk);
279
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
295
280
  int ret;
296
- if(raw_type == RAW_TYPE_STRING) {
297
- ret = object_complete_string(uk, string);
298
- } else if(raw_type == RAW_TYPE_BINARY) {
299
- ret = object_complete_binary(uk, string);
281
+ if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
282
+ ret = object_complete(uk, string);
300
283
  } else {
301
284
  ret = object_complete_ext(uk, raw_type, string);
302
285
  }
@@ -335,7 +318,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
335
318
  SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr
336
319
  int count = b & 0x1f;
337
320
  if(count == 0) {
338
- return object_complete_string(uk, rb_str_buf_new(0));
321
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
339
322
  }
340
323
  /* read_raw_body_begin sets uk->reading_raw */
341
324
  uk->reading_raw_remaining = count;
@@ -520,7 +503,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
520
503
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
521
504
  uint8_t count = cb->u8;
522
505
  if(count == 0) {
523
- return object_complete_string(uk, rb_str_buf_new(0));
506
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
524
507
  }
525
508
  /* read_raw_body_begin sets uk->reading_raw */
526
509
  uk->reading_raw_remaining = count;
@@ -532,7 +515,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
532
515
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
533
516
  uint16_t count = _msgpack_be16(cb->u16);
534
517
  if(count == 0) {
535
- return object_complete_string(uk, rb_str_buf_new(0));
518
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
536
519
  }
537
520
  /* read_raw_body_begin sets uk->reading_raw */
538
521
  uk->reading_raw_remaining = count;
@@ -544,7 +527,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
544
527
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
545
528
  uint32_t count = _msgpack_be32(cb->u32);
546
529
  if(count == 0) {
547
- return object_complete_string(uk, rb_str_buf_new(0));
530
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
548
531
  }
549
532
  /* read_raw_body_begin sets uk->reading_raw */
550
533
  uk->reading_raw_remaining = count;
@@ -556,7 +539,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
556
539
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
557
540
  uint8_t count = cb->u8;
558
541
  if(count == 0) {
559
- return object_complete_binary(uk, rb_str_buf_new(0));
542
+ return object_complete(uk, rb_str_new_static("", 0));
560
543
  }
561
544
  /* read_raw_body_begin sets uk->reading_raw */
562
545
  uk->reading_raw_remaining = count;
@@ -568,7 +551,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
568
551
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
569
552
  uint16_t count = _msgpack_be16(cb->u16);
570
553
  if(count == 0) {
571
- return object_complete_binary(uk, rb_str_buf_new(0));
554
+ return object_complete(uk, rb_str_new_static("", 0));
572
555
  }
573
556
  /* read_raw_body_begin sets uk->reading_raw */
574
557
  uk->reading_raw_remaining = count;
@@ -580,7 +563,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
580
563
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
581
564
  uint32_t count = _msgpack_be32(cb->u32);
582
565
  if(count == 0) {
583
- return object_complete_binary(uk, rb_str_buf_new(0));
566
+ return object_complete(uk, rb_str_new_static("", 0));
584
567
  }
585
568
  /* read_raw_body_begin sets uk->reading_raw */
586
569
  uk->reading_raw_remaining = count;
@@ -64,6 +64,7 @@ struct msgpack_unpacker_t {
64
64
 
65
65
  /* options */
66
66
  bool symbolize_keys;
67
+ bool freeze;
67
68
  bool allow_unknown_ext;
68
69
  };
69
70
 
@@ -96,6 +97,11 @@ static inline void msgpack_unpacker_set_symbolized_keys(msgpack_unpacker_t* uk,
96
97
  uk->symbolize_keys = enable;
97
98
  }
98
99
 
100
+ static inline void msgpack_unpacker_set_freeze(msgpack_unpacker_t* uk, bool enable)
101
+ {
102
+ uk->freeze = enable;
103
+ }
104
+
99
105
  static inline void msgpack_unpacker_set_allow_unknown_ext(msgpack_unpacker_t* uk, bool enable)
100
106
  {
101
107
  uk->allow_unknown_ext = enable;
@@ -105,6 +105,9 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
105
105
  v = rb_hash_aref(options, ID2SYM(rb_intern("symbolize_keys")));
106
106
  msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
107
107
 
108
+ v = rb_hash_aref(options, ID2SYM(rb_intern("freeze")));
109
+ msgpack_unpacker_set_freeze(uk, RTEST(v));
110
+
108
111
  v = rb_hash_aref(options, ID2SYM(rb_intern("allow_unknown_ext")));
109
112
  msgpack_unpacker_set_allow_unknown_ext(uk, RTEST(v));
110
113
  }
@@ -118,6 +121,12 @@ static VALUE Unpacker_symbolized_keys_p(VALUE self)
118
121
  return uk->symbolize_keys ? Qtrue : Qfalse;
119
122
  }
120
123
 
124
+ static VALUE Unpacker_freeze_p(VALUE self)
125
+ {
126
+ UNPACKER(self, uk);
127
+ return uk->freeze ? Qtrue : Qfalse;
128
+ }
129
+
121
130
  static VALUE Unpacker_allow_unknown_ext_p(VALUE self)
122
131
  {
123
132
  UNPACKER(self, uk);
@@ -438,6 +447,7 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
438
447
 
439
448
  rb_define_method(cMessagePack_Unpacker, "initialize", MessagePack_Unpacker_initialize, -1);
440
449
  rb_define_method(cMessagePack_Unpacker, "symbolize_keys?", Unpacker_symbolized_keys_p, 0);
450
+ rb_define_method(cMessagePack_Unpacker, "freeze?", Unpacker_freeze_p, 0);
441
451
  rb_define_method(cMessagePack_Unpacker, "allow_unknown_ext?", Unpacker_allow_unknown_ext_p, 0);
442
452
  rb_define_method(cMessagePack_Unpacker, "buffer", Unpacker_buffer, 0);
443
453
  rb_define_method(cMessagePack_Unpacker, "read", Unpacker_read, 0);
@@ -1,10 +1,6 @@
1
1
  module MessagePack
2
- VERSION = "1.4.0.pre1"
3
-
4
- # NOTE for msgpack-ruby maintainer:
5
- # Check these things to release new binaryes for new Ruby versions (especially for Windows):
6
- # * versions/supports of rake-compiler & rake-compiler-dock
7
- # https://github.com/rake-compiler/rake-compiler-dock/blob/master/History.md
8
- # * update RUBY_CC_VERSION in Rakefile
9
- # * check Ruby dependency of released mswin gem details
2
+ VERSION = "1.4.2"
3
+ # Note for maintainers:
4
+ # Don't miss building/releasing the JRuby version (rake buld:java)
5
+ # See "How to build -java rubygems" in README for more details.
10
6
  end
data/msgpack.gemspec CHANGED
@@ -20,13 +20,11 @@ Gem::Specification.new do |s|
20
20
  end
21
21
  s.test_files = `git ls-files -- {test,spec}/*`.split("\n")
22
22
 
23
+ s.required_ruby_version = ">= 2.4"
24
+
23
25
  s.add_development_dependency 'bundler'
24
26
  s.add_development_dependency 'rake'
25
- s.add_development_dependency 'rake-compiler', ['~> 1.0']
26
- if /java/ !~ RUBY_PLATFORM
27
- # NOTE: rake-compiler-dock SHOULD be updated for new Ruby versions
28
- s.add_development_dependency 'rake-compiler-dock', ['~> 1.0']
29
- end
27
+ s.add_development_dependency 'rake-compiler'
30
28
  s.add_development_dependency 'rspec', ['~> 3.3']
31
29
  s.add_development_dependency 'yard'
32
30
  s.add_development_dependency 'json'
data/spec/spec_helper.rb CHANGED
@@ -30,6 +30,12 @@ def automatic_string_keys_deduplication?
30
30
  x.keys[0].equal?(h.keys[0])
31
31
  end
32
32
 
33
+ def string_deduplication?
34
+ r1 = rand.to_s
35
+ r2 = r1.dup
36
+ (-r1).equal?(-r2)
37
+ end
38
+
33
39
  if java?
34
40
  RSpec.configure do |c|
35
41
  c.treat_symbols_as_metadata_keys_with_true_values = true
@@ -18,10 +18,12 @@ describe MessagePack::Unpacker do
18
18
  it 'gets options to specify how to unpack values' do
19
19
  u1 = MessagePack::Unpacker.new
20
20
  u1.symbolize_keys?.should == false
21
+ u1.freeze?.should == false
21
22
  u1.allow_unknown_ext?.should == false
22
23
 
23
- u2 = MessagePack::Unpacker.new(symbolize_keys: true, allow_unknown_ext: true)
24
+ u2 = MessagePack::Unpacker.new(symbolize_keys: true, freeze: true, allow_unknown_ext: true)
24
25
  u2.symbolize_keys?.should == true
26
+ u2.freeze?.should == true
25
27
  u2.allow_unknown_ext?.should == true
26
28
  end
27
29
 
@@ -632,6 +634,14 @@ describe MessagePack::Unpacker do
632
634
  array = ['foo'] * 10_000
633
635
  MessagePack.unpack(MessagePack.pack(array)).size.should == 10_000
634
636
  end
637
+
638
+ it 'preserve string encoding (issue #200)' do
639
+ string = 'a'.force_encoding(Encoding::UTF_8)
640
+ MessagePack.unpack(MessagePack.pack(string)).encoding.should == string.encoding
641
+
642
+ string *= 256
643
+ MessagePack.unpack(MessagePack.pack(string)).encoding.should == string.encoding
644
+ end
635
645
  end
636
646
 
637
647
  context 'extensions' do
@@ -662,6 +672,88 @@ describe MessagePack::Unpacker do
662
672
  end
663
673
  end
664
674
 
675
+ context 'freeze' do
676
+ let :struct do
677
+ {'hello' => 'world', 'nested' => ['object', {'structure' => true}]}
678
+ end
679
+
680
+ let :buffer do
681
+ MessagePack.pack(struct)
682
+ end
683
+
684
+ let :unpacker do
685
+ described_class.new(:freeze => true)
686
+ end
687
+
688
+ it 'can freeze objects when using .unpack' do
689
+ parsed_struct = MessagePack.unpack(buffer, freeze: true)
690
+ parsed_struct.should == struct
691
+
692
+ parsed_struct.should be_frozen
693
+ parsed_struct['hello'].should be_frozen
694
+ parsed_struct['nested'].should be_frozen
695
+ parsed_struct['nested'][0].should be_frozen
696
+ parsed_struct['nested'][1].should be_frozen
697
+
698
+ if string_deduplication?
699
+ parsed_struct.keys[0].should be_equal('hello'.freeze)
700
+ parsed_struct.keys[1].should be_equal('nested'.freeze)
701
+ parsed_struct.values[0].should be_equal('world'.freeze)
702
+ parsed_struct.values[1][0].should be_equal('object'.freeze)
703
+ parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze)
704
+ end
705
+ end
706
+
707
+ it 'can freeze objects when using #each' do
708
+ objs = []
709
+ unpacker.feed(buffer)
710
+ unpacker.each do |obj|
711
+ objs << obj
712
+ end
713
+
714
+ parsed_struct = objs.first
715
+ parsed_struct.should == struct
716
+
717
+ parsed_struct.should be_frozen
718
+ parsed_struct['hello'].should be_frozen
719
+ parsed_struct['nested'].should be_frozen
720
+ parsed_struct['nested'][0].should be_frozen
721
+ parsed_struct['nested'][1].should be_frozen
722
+
723
+ if string_deduplication?
724
+ parsed_struct.keys[0].should be_equal('hello'.freeze)
725
+ parsed_struct.keys[1].should be_equal('nested'.freeze)
726
+ parsed_struct.values[0].should be_equal('world'.freeze)
727
+ parsed_struct.values[1][0].should be_equal('object'.freeze)
728
+ parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze)
729
+ end
730
+ end
731
+
732
+ it 'can freeze objects when using #feed_each' do
733
+ objs = []
734
+ unpacker.feed_each(buffer) do |obj|
735
+ objs << obj
736
+ end
737
+
738
+ parsed_struct = objs.first
739
+ parsed_struct.should == struct
740
+
741
+ parsed_struct.should be_frozen
742
+ parsed_struct['hello'].should be_frozen
743
+ parsed_struct['nested'].should be_frozen
744
+ parsed_struct['nested'][0].should be_frozen
745
+ parsed_struct['nested'][1].should be_frozen
746
+
747
+ if string_deduplication?
748
+ parsed_struct.keys[0].should be_equal('hello'.freeze)
749
+ parsed_struct.keys[1].should be_equal('nested'.freeze)
750
+ parsed_struct.values[0].should be_equal('world'.freeze)
751
+ parsed_struct.values[1][0].should be_equal('object'.freeze)
752
+ parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze)
753
+ end
754
+ end
755
+ end
756
+
665
757
  context 'binary encoding', :encodings do
666
758
  let :buffer do
667
759
  MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})