marshal-structure 1.1.1 → 2.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ef879e59c6e30f4e9a9794f4b712dbff947c508f
4
+ data.tar.gz: 7639105aa9aba80c6c7a8ea2293ed783ca3e22e2
5
+ SHA512:
6
+ metadata.gz: 905840c1775e2787f813ccbc1396b22434b5b41c36eb05136f4d21e3c478f8f3fb676b777c243446712f9fd362b8088c88f115f824e1efcf1b3d0797b656269d
7
+ data.tar.gz: c95e398a52ac662f5de25770e56077c58dbdf1803b9f79f4364f5e13ab73f611f41312362ef6efefea09e77093a9e0dd6fa0fbe97651e450e6179905762d4188
Binary file
data.tar.gz.sig CHANGED
@@ -1 +1,2 @@
1
- 7s5�^MD ��-47ܒ�εɯc��]��T@�nxg���I��cqSWt��� ��`�`B��C� �<�T��^fN$_��"��}�ӟiG��H.�ю�X��� ;�REF(nG��CO
1
+ ��>Ϡِϣ�&�6fi'��O���֦�WM�C[���QO��b<�C3M2�\⌝{��-zvL�Ή��p+����u_�#S��X� �#U�t1�����j��()y(&��;��?Y�s�-�C)c����c[fwv��r1�(����*��Ԩ��h�S��k34��덋��BF��`�B0
2
+ I���A�1`�A��Z@Vh�qR�c�L�o�h�;���l�0�O)+9b��>�͖NGw��b]4�ޒ{7
data/.autotest CHANGED
@@ -1,7 +1,6 @@
1
1
  # -*- ruby -*-
2
2
 
3
3
  require 'autotest/restart'
4
- require 'autotest/isolate'
5
4
 
6
5
  Autotest.add_hook :initialize do |at|
7
6
  at.testlib = 'minitest/autorun'
@@ -1,3 +1,18 @@
1
+ === 2.0 / 2012-05-16
2
+
3
+ * API Change
4
+ * Split #construct into a Tokenizer and Parser. The Structure class is now
5
+ mostly empty.
6
+
7
+ * Enhancements
8
+ * Added a Tokenizer allows examination of a stream without the creation of
9
+ excessive objects.
10
+ * Added a Parser which can be used as a model for further examination of
11
+ Marshal streams.
12
+ * Added an ObjectCounter which counts the number of allocations that will be
13
+ made when loading the stream.
14
+ * Added Marshal::Structure#load which loads the object using Marshal.
15
+
1
16
  === 1.1.1 / 2011-10-06
2
17
 
3
18
  * Bug fix
@@ -5,4 +5,11 @@ README.rdoc
5
5
  Rakefile
6
6
  bin/marshal_structure
7
7
  lib/marshal/structure.rb
8
+ lib/marshal/structure/allocation_counter.rb
9
+ lib/marshal/structure/parser.rb
10
+ lib/marshal/structure/test_case.rb
11
+ lib/marshal/structure/tokenizer.rb
8
12
  test/test_marshal_structure.rb
13
+ test/test_marshal_structure_allocation_counter.rb
14
+ test/test_marshal_structure_parser.rb
15
+ test/test_marshal_structure_tokenizer.rb
@@ -1,18 +1,17 @@
1
1
  = marshal-structure
2
2
 
3
- * https://github.com/drbrain/marshal-structure
3
+ home :: https://github.com/drbrain/marshal-structure
4
+ rdoc :: http://docs.seattlerb.org/marshal-structure
5
+ bugs :: https://github.com/drbrain/marshal-structure/issues
4
6
 
5
- == DESCRIPTION:
7
+ == Description
6
8
 
7
- Dumps a tree based on the Marshal format. Supports the Marshal 4.8 format.
9
+ Tools to inspect and analyze Ruby's Marshal serialization format. Supports
10
+ the Marshal 4.8 format which is emitted by ruby 1.8 through 2.x.
8
11
 
9
- == FEATURES/PROBLEMS:
12
+ == Examples
10
13
 
11
- * Works like Marshal.load
12
-
13
- == SYNOPSIS:
14
-
15
- From the command line:
14
+ To dump the structure of a Marshal stream:
16
15
 
17
16
  ruby -rpp -rmarshal/structure \
18
17
  -e 'pp Marshal::Structure.load Marshal.dump "hello"'
@@ -24,21 +23,17 @@ Fancier usage:
24
23
 
25
24
  ms = Marshal::Structure.new Marshal.dump %w[hello world]
26
25
 
27
- # print the Marshal stream structure
28
- pp ms.construct
29
-
30
- # print ruby objects in Marshal stream
31
- pp ms.objects
32
-
33
- == REQUIREMENTS:
26
+ # print the stream structure
27
+ pp ms.structure
34
28
 
35
- * Ruby 1.8.7+
29
+ # show how many allocations are required to load the stream
30
+ p ms.count_allocations
36
31
 
37
- == INSTALL:
32
+ == Installation
38
33
 
39
34
  gem install marshal-structure
40
35
 
41
- == DEVELOPERS:
36
+ == Developers
42
37
 
43
38
  After checking out the source, run:
44
39
 
@@ -47,11 +42,11 @@ After checking out the source, run:
47
42
  This task will install any missing dependencies, run the tests/specs,
48
43
  and generate the RDoc.
49
44
 
50
- == LICENSE:
45
+ == License
51
46
 
52
47
  (The MIT License)
53
48
 
54
- Copyright (c) 2011 Eric Hodel
49
+ Copyright (c) Eric Hodel
55
50
 
56
51
  Permission is hereby granted, free of charge, to any person obtaining
57
52
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -4,8 +4,8 @@ require 'rubygems'
4
4
  require 'hoe'
5
5
 
6
6
  Hoe.plugin :git
7
- Hoe.plugin :isolate
8
7
  Hoe.plugin :minitest
8
+ Hoe.plugin :travis
9
9
 
10
10
  Hoe.spec 'marshal-structure' do
11
11
  developer 'Eric Hodel', 'drbrain@segment7.net'
@@ -15,12 +15,6 @@ Hoe.spec 'marshal-structure' do
15
15
  self.readme_file = 'README.rdoc'
16
16
  self.extra_rdoc_files << 'README.rdoc' # HACK fix in Hoe
17
17
 
18
- if respond_to? :isolate_dir= then # HACK Hoe issue #7
19
- self.isolate_dir = 'tmp/isolate'
20
- else
21
- warn 'please: gem install isolate'
22
- end
23
-
24
18
  extra_dev_deps << ['ben_string', '~> 1']
25
19
  end
26
20
 
@@ -1,164 +1,73 @@
1
1
  ##
2
2
  # Marshal::Structure dumps a nested Array describing the structure of a
3
- # Marshal stream.
3
+ # Marshal stream. Marshal format 4.8 (Ruby 1.8 through 2.x) is supported.
4
4
  #
5
- # Marshal format 4.8 is supported.
6
-
7
- class Marshal::Structure
8
-
9
- ##
10
- # Version of Marshal::Structure you are using
11
-
12
- VERSION = '1.1.1'
13
-
14
- ##
15
- # Supported major Marshal version
16
-
17
- MAJOR_VERSION = 4
18
-
19
- ##
20
- # Supported minor Marshal version
21
-
22
- MINOR_VERSION = 8
23
-
24
- ##
25
- # nil type prefix
26
-
27
- TYPE_NIL = '0'
28
-
29
- ##
30
- # true type prefix
31
-
32
- TYPE_TRUE = 'T'
33
-
34
- ##
35
- # false type prefix
36
-
37
- TYPE_FALSE = 'F'
38
-
39
- ##
40
- # Fixnum type prefix
41
-
42
- TYPE_FIXNUM = 'i'
43
-
44
- ##
45
- # An object that has been extended with a module
46
-
47
- TYPE_EXTENDED = 'e'
48
-
49
- ##
50
- # A subclass of a built-in type
51
-
52
- TYPE_UCLASS = 'C'
53
-
54
- ##
55
- # A ruby Object
56
-
57
- TYPE_OBJECT = 'o'
58
-
59
- ##
60
- # A wrapped C pointer
61
-
62
- TYPE_DATA = 'd'
63
-
64
- ##
65
- # An object saved with _dump
66
-
67
- TYPE_USERDEF = 'u'
68
-
69
- ##
70
- # An object saved with marshal_dump
71
-
72
- TYPE_USRMARSHAL = 'U'
73
-
74
- ##
75
- # A Float
76
-
77
- TYPE_FLOAT = 'f'
78
-
79
- ##
80
- # A Bignum
81
-
82
- TYPE_BIGNUM = 'l'
83
-
84
- ##
85
- # A String
86
-
87
- TYPE_STRING = '"'
88
-
89
- ##
90
- # A Regexp
91
-
92
- TYPE_REGEXP = '/'
93
-
94
- ##
95
- # An Array
96
-
97
- TYPE_ARRAY = '['
98
-
99
- ##
100
- # A Hash
101
-
102
- TYPE_HASH = '{'
103
-
104
- ##
105
- # A Hash with a default value (not proc)
106
-
107
- TYPE_HASH_DEF = '}'
108
-
109
- ##
110
- # A Struct
111
-
112
- TYPE_STRUCT = 'S'
5
+ # Examples:
6
+ #
7
+ # To dump the structure of a Marshal stream:
8
+ #
9
+ # ruby -rpp -rmarshal/structure \
10
+ # -e 'pp Marshal::Structure.load Marshal.dump "hello"'
11
+ #
12
+ # Fancier usage:
13
+ #
14
+ # require 'pp'
15
+ # require 'marshal/structure'
16
+ #
17
+ # ms = Marshal::Structure.new Marshal.dump %w[hello world]
18
+ #
19
+ # # print the stream structure
20
+ # pp ms.structure
21
+ #
22
+ # # show how many allocations are required to load the stream
23
+ # p ms.count_allocations
113
24
 
114
- ##
115
- # An old-style Module (reference, not content)
116
- #
117
- # I'm not sure what makes this old. The byte stream is identical to
118
- # TYPE_MODULE
119
25
 
120
- TYPE_MODULE_OLD = 'M'
26
+ class Marshal::Structure
121
27
 
122
28
  ##
123
- # A class (reference, not content)
29
+ # Generic error class for Marshal::Structure
124
30
 
125
- TYPE_CLASS = 'c'
31
+ class Error < RuntimeError
32
+ end
126
33
 
127
34
  ##
128
- # A module (reference, not content)
129
-
130
- TYPE_MODULE = 'm'
35
+ # Raised when the Marshal stream is at the end
131
36
 
132
- ##
133
- # A Symbol
37
+ class EndOfMarshal < Error
134
38
 
135
- TYPE_SYMBOL = ':'
39
+ ##
40
+ # Number of bytes of Marshal stream consumed
136
41
 
137
- ##
138
- # A reference to a previously Symbol
42
+ attr_reader :consumed
139
43
 
140
- TYPE_SYMLINK = ';'
44
+ ##
45
+ # Requested number of bytes that was not fulfillable
141
46
 
142
- ##
143
- # Instance variables for a following object
47
+ attr_reader :requested
144
48
 
145
- TYPE_IVAR = 'I'
49
+ ##
50
+ # Creates a new EndOfMarshal exception. Marshal::Structure previously
51
+ # read +consumed+ bytes and was unable to fulfill the request for
52
+ # +requested+ additional bytes.
146
53
 
147
- ##
148
- # A reference to a previously-stored Object
54
+ def initialize consumed, requested
55
+ @consumed = consumed
56
+ @requested = requested
149
57
 
150
- TYPE_LINK = '@'
58
+ super "consumed #{consumed} bytes, requested #{requested} more"
59
+ end
60
+ end
151
61
 
152
62
  ##
153
- # Objects found in the Marshal stream. Since objects aren't constructed the
154
- # actual object won't be present in this list.
63
+ # Version of Marshal::Structure you are using
155
64
 
156
- attr_reader :objects
65
+ VERSION = '2.0'
157
66
 
158
67
  ##
159
- # Symbols found in the Marshal stream
68
+ # The Marshal stream
160
69
 
161
- attr_reader :symbols
70
+ attr_reader :stream
162
71
 
163
72
  ##
164
73
  # Returns the structure of the Marshaled object +obj+ as nested Arrays.
@@ -178,24 +87,18 @@ class Marshal::Structure
178
87
  data = obj.to_s
179
88
  elsif obj.respond_to? :read then
180
89
  data = obj.read
181
- if data.empty? then
182
- raise EOFError, "end of file reached"
183
- end
90
+ raise EOFError, "end of file reached" if data.empty?
184
91
  elsif obj.respond_to? :getc then # FIXME - don't read all of it upfront
185
92
  data = ''
186
- data << c while (c = obj.getc.chr)
93
+
94
+ while c = obj.getc do
95
+ data << c.chr
96
+ end
187
97
  else
188
98
  raise TypeError, "instance of IO needed"
189
99
  end
190
100
 
191
- major = data[0].ord
192
- minor = data[1].ord
193
-
194
- if major != MAJOR_VERSION or minor > MINOR_VERSION then
195
- raise TypeError, "incompatible marshal file format (can't be read)\n\tformat version #{MAJOR_VERSION}.#{MINOR_VERSION} required; #{major}.#{minor} given"
196
- end
197
-
198
- new(data).construct
101
+ new(data).structure
199
102
  end
200
103
 
201
104
  ##
@@ -220,418 +123,47 @@ class Marshal::Structure
220
123
  # Prepares processing of +stream+
221
124
 
222
125
  def initialize stream
223
- @objects = []
224
- @symbols = []
225
-
226
- @stream = stream
227
- @byte_array = stream.bytes.to_a
228
- @consumed = 2
229
- end
230
-
231
- ##
232
- # Adds +obj+ to the objects list
233
-
234
- def add_object obj
235
- return if
236
- [NilClass, TrueClass, FalseClass, Symbol, Fixnum].any? { |c| c === obj }
237
-
238
- index = @objects.size
239
- @objects << obj
240
- index
126
+ @stream = stream
127
+ @tokenizer = Marshal::Structure::Tokenizer.new stream
241
128
  end
242
129
 
243
130
  ##
244
- # Adds +symbol+ to the symbols list
131
+ # Counts allocations required to load the Marshal stream. See
132
+ # Marshal::Structure::AllocationsCounter for a description of how counting
133
+ # is performed.
245
134
 
246
- def add_symlink symbol
247
- index = @symbols.size
248
- @symbols << symbol
249
- index
250
- end
135
+ def count_allocations
136
+ counter = Marshal::Structure::AllocationCounter.new token_stream
251
137
 
252
- ##
253
- # Creates the structure for the remaining stream.
254
-
255
- def construct
256
- type = consume_character
257
-
258
- case type
259
- when TYPE_NIL then
260
- :nil
261
- when TYPE_TRUE then
262
- :true
263
- when TYPE_FALSE then
264
- :false
265
-
266
- when TYPE_ARRAY then
267
- [:array, *construct_array]
268
- when TYPE_BIGNUM then
269
- [:bignum, *construct_bignum]
270
- when TYPE_CLASS then
271
- ref = store_unique_object Object.allocate
272
-
273
- [:class, ref, get_byte_sequence]
274
- when TYPE_DATA then
275
- [:data, *construct_data]
276
- when TYPE_EXTENDED then
277
- [:extended, get_symbol, construct]
278
- when TYPE_FIXNUM then
279
- [:fixnum, construct_integer]
280
- when TYPE_FLOAT then
281
- [:float, *construct_float]
282
- when TYPE_HASH then
283
- [:hash, *construct_hash]
284
- when TYPE_HASH_DEF then
285
- [:hash_default, *construct_hash_def]
286
- when TYPE_IVAR then
287
- [:instance_variables, construct, *construct_instance_variables]
288
- when TYPE_LINK then
289
- [:link, construct_integer]
290
- when TYPE_MODULE, TYPE_MODULE_OLD then
291
- ref = store_unique_object Object.allocate
292
-
293
- [:module, ref, get_byte_sequence]
294
- when TYPE_OBJECT then
295
- [:object, *construct_object]
296
- when TYPE_REGEXP then
297
- [:regexp, *construct_regexp]
298
- when TYPE_STRING then
299
- [:string, *construct_string]
300
- when TYPE_STRUCT then
301
- [:struct, *construct_struct]
302
- when TYPE_SYMBOL then
303
- [:symbol, *construct_symbol]
304
- when TYPE_SYMLINK then
305
- [:symbol_link, construct_integer]
306
- when TYPE_USERDEF then
307
- [:user_defined, *construct_user_defined]
308
- when TYPE_USRMARSHAL then
309
- [:user_marshal, *construct_user_marshal]
310
- when TYPE_UCLASS then
311
- name = get_symbol
312
-
313
- [:user_class, name, construct]
314
- else
315
- raise ArgumentError, "load error, unknown type #{type}"
316
- end
138
+ counter.count
317
139
  end
318
140
 
319
141
  ##
320
- # Creates the body of an +:array+ object
321
-
322
- def construct_array
323
- ref = store_unique_object Object.allocate
324
-
325
- obj = [ref]
326
-
327
- items = construct_integer
328
-
329
- obj << items
330
-
331
- items.times do
332
- obj << construct
333
- end
142
+ # Loads the stream with Marshal.load
334
143
 
335
- obj
144
+ def load
145
+ Marshal.load @stream
336
146
  end
337
147
 
338
148
  ##
339
- # Creates the body of a +:bignum+ object
149
+ # Returns the structure of the Marshal stream.
340
150
 
341
- def construct_bignum
342
- sign = consume_byte == ?- ? -1 : 1
343
- size = construct_integer * 2
151
+ def structure
152
+ parser = Marshal::Structure::Parser.new token_stream
344
153
 
345
- result = 0
346
-
347
- data = consume_bytes size
348
-
349
- data.each_with_index do |data, exp|
350
- result += (data * 2**(exp*8))
351
- end
352
-
353
- ref = store_unique_object Object.allocate
354
-
355
- [ref, sign, size, result]
154
+ parser.parse
356
155
  end
357
156
 
358
157
  ##
359
- # Creates the body of a wrapped C pointer object
360
-
361
- def construct_data
362
- ref = store_unique_object Object.allocate
158
+ # Returns an Enumerator for the tokens in the Marshal stream.
363
159
 
364
- [ref, get_symbol, construct]
365
- end
366
-
367
- ##
368
- # Creates the body of a +:float+ object
369
-
370
- def construct_float
371
- float = get_byte_sequence
372
-
373
- ref = store_unique_object Object.allocate
374
-
375
- [ref, float]
376
- end
377
-
378
- ##
379
- # Creates the body of a +:hash+ object
380
-
381
- def construct_hash
382
- ref = store_unique_object Object.allocate
383
-
384
- obj = [ref]
385
-
386
- pairs = construct_integer
387
- obj << pairs
388
-
389
- pairs.times do
390
- obj << construct
391
- obj << construct
392
- end
393
-
394
- obj
395
- end
396
-
397
- ##
398
- # Creates the body of a +:hash_def+ object
399
-
400
- def construct_hash_def
401
- ref, hash = construct_hash
402
-
403
- [ref, hash, construct]
404
- end
405
-
406
- ##
407
- # Instance variables contain an object followed by a count of instance
408
- # variables and their contents
409
-
410
- def construct_instance_variables
411
- instance_variables = []
412
-
413
- pairs = construct_integer
414
- instance_variables << pairs
415
-
416
- pairs.times do
417
- instance_variables << get_symbol
418
- instance_variables << construct
419
- end
420
-
421
- instance_variables
422
- end
423
-
424
- ##
425
- # Decodes a stored Fixnum
426
-
427
- def construct_integer
428
- c = consume_byte
429
-
430
- # The format appears to be a simple integer compression format
431
- #
432
- # The 0-123 cases are easy, and use one byte
433
- # We've read c as unsigned char in a way, but we need to honor
434
- # the sign bit. We do that by simply comparing with the +128 values
435
- return 0 if c == 0
436
- return c - 5 if 4 < c and c < 128
437
-
438
- # negative, but checked known it's instead in 2's compliment
439
- return c - 251 if 252 > c and c > 127
440
-
441
- # otherwise c (now in the 1 to 4 range) indicates how many
442
- # bytes to read to construct the value.
443
- #
444
- # Because we're operating on a small number of possible values,
445
- # it's cleaner to just unroll the calculate of each
446
-
447
- case c
448
- when 1
449
- consume_byte
450
- when 2
451
- consume_byte | (consume_byte << 8)
452
- when 3
453
- consume_byte | (consume_byte << 8) | (consume_byte << 16)
454
- when 4
455
- consume_byte | (consume_byte << 8) | (consume_byte << 16) |
456
- (consume_byte << 24)
457
-
458
- when 255 # -1
459
- consume_byte - 256
460
- when 254 # -2
461
- (consume_byte | (consume_byte << 8)) - 65536
462
- when 253 # -3
463
- (consume_byte |
464
- (consume_byte << 8) |
465
- (consume_byte << 16)) - 16777216 # 2 ** 24
466
- when 252 # -4
467
- (consume_byte |
468
- (consume_byte << 8) |
469
- (consume_byte << 16) |
470
- (consume_byte << 24)) - 4294967296
471
- else
472
- raise "Invalid integer size: #{c}"
473
- end
474
- end
475
-
476
- ##
477
- # Creates an Object
478
-
479
- def construct_object
480
- ref = store_unique_object Object.allocate
481
-
482
- [ref, get_symbol, construct_instance_variables]
483
- end
484
-
485
- ##
486
- # Creates a Regexp
487
-
488
- def construct_regexp
489
- ref =store_unique_object Object.allocate
490
-
491
- [ref, get_byte_sequence, consume_byte]
492
- end
493
-
494
- ##
495
- # Creates a String
496
-
497
- def construct_string
498
- ref = store_unique_object Object.allocate
499
-
500
- [ref, get_byte_sequence]
501
- end
502
-
503
- ##
504
- # Creates a Struct
505
-
506
- def construct_struct
507
- symbols = []
508
- values = []
509
-
510
- obj_ref = store_unique_object Object.allocate
511
-
512
- obj = [obj_ref, get_symbol]
513
-
514
- members = construct_integer
515
- obj << members
516
-
517
- members.times do
518
- obj << get_symbol
519
- obj << construct
520
- end
521
-
522
- obj
523
- end
524
-
525
- ##
526
- # Creates a Symbol
527
-
528
- def construct_symbol
529
- sym = get_byte_sequence
530
-
531
- ref = store_unique_object sym.to_sym
532
-
533
- [ref, sym]
534
- end
535
-
536
- ##
537
- # Creates an object saved by _dump
538
-
539
- def construct_user_defined
540
- name = get_symbol
541
-
542
- data = get_byte_sequence
543
-
544
- ref = store_unique_object Object.allocate
545
-
546
- [ref, name, data]
547
- end
548
-
549
- ##
550
- # Creates an object saved by marshal_dump
551
-
552
- def construct_user_marshal
553
- name = get_symbol
554
-
555
- obj = Object.allocate
556
-
557
- obj_ref = store_unique_object obj
558
-
559
- [obj_ref, name, construct]
560
- end
561
-
562
- ##
563
- # Consumes +bytes+ from the marshal stream
564
-
565
- def consume bytes
566
- raise ArgumentError, "marshal data too short" if @consumed > @stream.size
567
- data = @stream[@consumed, bytes]
568
- @consumed += bytes
569
- data
570
- end
571
-
572
- ##
573
- # Consumes +count+ bytes from the marshal stream as an Array of bytes
574
-
575
- def consume_bytes count
576
- consume(count).bytes.to_a
577
- end
578
-
579
- ##
580
- # Consumes one byte from the marshal stream
581
-
582
- def consume_byte
583
- raise ArgumentError, "marshal data too short" if
584
- @consumed > @byte_array.size
585
-
586
- data = @byte_array[@consumed]
587
- @consumed += 1
588
-
589
- data
590
- end
591
-
592
- ##
593
- # Consumes one byte from the marshal stream and returns a character
594
-
595
- def consume_character
596
- consume_byte.chr
597
- end
598
-
599
- ##
600
- # Consumes a sequence of bytes from the marshal stream based on the next
601
- # integer
602
-
603
- def get_byte_sequence
604
- size = construct_integer
605
- consume size
606
- end
607
-
608
- ##
609
- # Constructs a Symbol from a TYPE_SYMBOL or TYPE_SYMLINK
610
-
611
- def get_symbol
612
- type = consume_character
613
-
614
- case type
615
- when TYPE_SYMBOL then
616
- [:symbol, *construct_symbol]
617
- when TYPE_SYMLINK then
618
- num = construct_integer
619
- [:symbol_link, num]
620
- else
621
- raise ArgumentError, "expected TYPE_SYMBOL or TYPE_SYMLINK, got #{type.inspect}"
622
- end
623
- end
624
-
625
- ##
626
- # Stores a reference to +obj+
627
-
628
- def store_unique_object obj
629
- if Symbol === obj then
630
- add_symlink obj
631
- else
632
- add_object obj
633
- end
160
+ def token_stream
161
+ @tokenizer.tokens
634
162
  end
635
163
 
636
164
  end
637
165
 
166
+ require 'marshal/structure/allocation_counter'
167
+ require 'marshal/structure/parser'
168
+ require 'marshal/structure/tokenizer'
169
+