bitgirder-platform 0.1.7

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 (51) hide show
  1. data/LICENSE.txt +176 -0
  2. data/bin/ensure-test-db +117 -0
  3. data/bin/install-mysql +375 -0
  4. data/bin/tomcat7 +569 -0
  5. data/lib/bitgirder/concurrent.rb +400 -0
  6. data/lib/bitgirder/core.rb +1235 -0
  7. data/lib/bitgirder/etl.rb +58 -0
  8. data/lib/bitgirder/event/file.rb +485 -0
  9. data/lib/bitgirder/event/logger/testing.rb +140 -0
  10. data/lib/bitgirder/event/logger.rb +137 -0
  11. data/lib/bitgirder/event/testing.rb +88 -0
  12. data/lib/bitgirder/http.rb +255 -0
  13. data/lib/bitgirder/io/testing.rb +33 -0
  14. data/lib/bitgirder/io.rb +959 -0
  15. data/lib/bitgirder/irb.rb +35 -0
  16. data/lib/bitgirder/mysql.rb +60 -0
  17. data/lib/bitgirder/ops/java.rb +117 -0
  18. data/lib/bitgirder/ops/ruby.rb +235 -0
  19. data/lib/bitgirder/testing.rb +152 -0
  20. data/lib/doc-gen0.rb +0 -0
  21. data/lib/doc-gen1.rb +0 -0
  22. data/lib/doc-gen10.rb +0 -0
  23. data/lib/doc-gen11.rb +0 -0
  24. data/lib/doc-gen12.rb +0 -0
  25. data/lib/doc-gen13.rb +0 -0
  26. data/lib/doc-gen14.rb +0 -0
  27. data/lib/doc-gen15.rb +0 -0
  28. data/lib/doc-gen16.rb +0 -0
  29. data/lib/doc-gen17.rb +14 -0
  30. data/lib/doc-gen18.rb +0 -0
  31. data/lib/doc-gen19.rb +0 -0
  32. data/lib/doc-gen2.rb +0 -0
  33. data/lib/doc-gen20.rb +182 -0
  34. data/lib/doc-gen21.rb +0 -0
  35. data/lib/doc-gen3.rb +0 -0
  36. data/lib/doc-gen4.rb +0 -0
  37. data/lib/doc-gen5.rb +0 -0
  38. data/lib/doc-gen6.rb +0 -0
  39. data/lib/doc-gen7.rb +0 -0
  40. data/lib/doc-gen8.rb +0 -0
  41. data/lib/doc-gen9.rb +0 -0
  42. data/lib/mingle/bincodec.rb +512 -0
  43. data/lib/mingle/codec.rb +54 -0
  44. data/lib/mingle/http.rb +156 -0
  45. data/lib/mingle/io/stream.rb +142 -0
  46. data/lib/mingle/io.rb +160 -0
  47. data/lib/mingle/json.rb +257 -0
  48. data/lib/mingle/service.rb +110 -0
  49. data/lib/mingle-em.rb +92 -0
  50. data/lib/mingle.rb +2917 -0
  51. metadata +100 -0
data/lib/doc-gen20.rb ADDED
@@ -0,0 +1,182 @@
1
+
2
+ # Autogenerated docs on 2012-11-21 11:47:21 -0800
3
+ #
4
+
5
+ # This code is only included for rdoc purposes and would not normally get
6
+ # required. Even so, in case of overzealous scripts which might auto-require
7
+ # this file, we enclose the entire body of this file in a guard that will
8
+ # prevent it from being interpreted in an actual run
9
+ #
10
+ if false
11
+
12
+
13
+ class BitGirder::Http::HttpHeaders
14
+
15
+
16
+
17
+ #
18
+ attr_reader :pairs
19
+
20
+
21
+
22
+
23
+
24
+ # Default constructor which takes a hash containing the following attributes:
25
+ #
26
+ # :+pairs+ ::
27
+ #
28
+ #
29
+ def initialize( opts = {} )
30
+ # Autogenerated stub for docs
31
+ end
32
+
33
+
34
+ end
35
+
36
+
37
+ class BitGirder::Http::HttpEndpoint
38
+
39
+
40
+
41
+ #
42
+ attr_reader :host
43
+
44
+ #
45
+ attr_reader :port
46
+
47
+ #
48
+ attr_reader :is_ssl
49
+
50
+
51
+
52
+
53
+
54
+ # Default constructor which takes a hash containing the following attributes:
55
+ #
56
+ # :+host+ ::
57
+ #
58
+ #
59
+ # :+is_ssl+ ::
60
+ #
61
+ #
62
+ # :+port+ ::
63
+ #
64
+ #
65
+ def initialize( opts = {} )
66
+ # Autogenerated stub for docs
67
+ end
68
+
69
+
70
+ end
71
+
72
+
73
+ class BitGirder::Http::HttpRequest
74
+
75
+
76
+
77
+ #
78
+ attr_reader :headers
79
+
80
+ #
81
+ attr_reader :path
82
+
83
+ #
84
+ attr_reader :body
85
+
86
+
87
+
88
+
89
+
90
+ # Default constructor which takes a hash containing the following attributes:
91
+ #
92
+ # :+body+ ::
93
+ #
94
+ #
95
+ # :+headers+ ::
96
+ #
97
+ #
98
+ # :+path+ ::
99
+ #
100
+ #
101
+ def initialize( opts = {} )
102
+ # Autogenerated stub for docs
103
+ end
104
+
105
+
106
+ end
107
+
108
+
109
+ class BitGirder::Http::HttpStatus
110
+
111
+
112
+
113
+ #
114
+ attr_reader :code
115
+
116
+ #
117
+ attr_reader :message
118
+
119
+ #
120
+ attr_reader :version
121
+
122
+
123
+
124
+
125
+
126
+ # Default constructor which takes a hash containing the following attributes:
127
+ #
128
+ # :+code+ ::
129
+ #
130
+ #
131
+ # :+message+ ::
132
+ #
133
+ #
134
+ # :+version+ ::
135
+ #
136
+ #
137
+ def initialize( opts = {} )
138
+ # Autogenerated stub for docs
139
+ end
140
+
141
+
142
+ end
143
+
144
+
145
+ class BitGirder::Http::HttpResponse
146
+
147
+
148
+
149
+ #
150
+ attr_reader :status
151
+
152
+ #
153
+ attr_reader :headers
154
+
155
+ #
156
+ attr_reader :body
157
+
158
+
159
+
160
+
161
+
162
+ # Default constructor which takes a hash containing the following attributes:
163
+ #
164
+ # :+body+ ::
165
+ #
166
+ #
167
+ # :+headers+ ::
168
+ #
169
+ #
170
+ # :+status+ ::
171
+ #
172
+ #
173
+ def initialize( opts = {} )
174
+ # Autogenerated stub for docs
175
+ end
176
+
177
+
178
+ end
179
+
180
+
181
+ end # 'if false...' block
182
+
data/lib/doc-gen21.rb ADDED
File without changes
data/lib/doc-gen3.rb ADDED
File without changes
data/lib/doc-gen4.rb ADDED
File without changes
data/lib/doc-gen5.rb ADDED
File without changes
data/lib/doc-gen6.rb ADDED
File without changes
data/lib/doc-gen7.rb ADDED
File without changes
data/lib/doc-gen8.rb ADDED
File without changes
data/lib/doc-gen9.rb ADDED
File without changes
@@ -0,0 +1,512 @@
1
+ require 'bitgirder/core'
2
+ require 'bitgirder/io'
3
+ require 'mingle'
4
+ require 'mingle/codec'
5
+
6
+ module Mingle
7
+ module BinCodec
8
+
9
+ TYPE_CODE_END = 0x00
10
+ TYPE_CODE_BOOLEAN = 0x01
11
+ TYPE_CODE_FLOAT64 = 0x03
12
+ TYPE_CODE_ENUM = 0x04
13
+ TYPE_CODE_FLOAT32 = 0x05
14
+ TYPE_CODE_INT32 = 0x06
15
+ TYPE_CODE_UINT32 = 0x07
16
+ TYPE_CODE_INT64 = 0x08
17
+ TYPE_CODE_UINT64 = 0x09
18
+ TYPE_CODE_STRING = 0x0a
19
+ TYPE_CODE_RFC3339_STR = 0x0b
20
+ TYPE_CODE_RFC3339_BIN = 0x0c
21
+ TYPE_CODE_BUFFER = 0x0d
22
+ TYPE_CODE_UTF8_STRING = 0x0e
23
+ TYPE_CODE_LIST = 0x0f
24
+ TYPE_CODE_STRUCT = 0x10
25
+ TYPE_CODE_SYMBOL_MAP = 0x11
26
+ TYPE_CODE_NULL = 0x012
27
+ TYPE_CODE_FIELD = 0x13
28
+
29
+ Io = BitGirder::Io
30
+
31
+ class MingleBinCodec < BitGirder::Core::BitGirderClass
32
+
33
+ include BitGirder::Core
34
+ include Mingle
35
+ include Mingle::Codec::MingleCodecImpl
36
+
37
+ BYTE_ORDER = Io::ORDER_LITTLE_ENDIAN
38
+
39
+ def initialize
40
+ @conv = Io::BinaryConverter.new( :order => BYTE_ORDER )
41
+ end
42
+
43
+ private
44
+ def append_type_code( wr, code )
45
+ wr.write_int8( code )
46
+ end
47
+
48
+ private
49
+ def append_sized_buffer( wr, buf )
50
+ wr.write_buffer32( buf )
51
+ end
52
+
53
+ private
54
+ def append_utf8( wr, str )
55
+
56
+ append_type_code( wr, TYPE_CODE_UTF8_STRING )
57
+
58
+ # str = BitGirder::Io.as_utf8( str )
59
+ # append_sized_buffer( wr, str.encode( "binary" ) )
60
+ wr.write_utf8( str )
61
+ end
62
+
63
+ private
64
+ def append_type_reference( wr, typ )
65
+ BinWriter.as_bin_writer( wr ).write_type_reference( typ )
66
+ # append_utf8( wr, typ.external_form )
67
+ end
68
+
69
+ private
70
+ def append_identifier( wr, id )
71
+ BinWriter.as_bin_writer( wr ).write_identifier( id )
72
+ # append_utf8( wr, id.external_form )
73
+ end
74
+
75
+ private
76
+ def append_boolean( wr, val )
77
+
78
+ append_type_code( wr, TYPE_CODE_BOOLEAN )
79
+ wr.write_bool( val.to_bool )
80
+ end
81
+
82
+ private
83
+ def append_string( wr, str )
84
+
85
+ append_type_code( wr, TYPE_CODE_STRING )
86
+ append_utf8( wr, str.to_s )
87
+ end
88
+
89
+ private
90
+ def append_num( wr, mg_num, type_code, enc_meth )
91
+
92
+ append_type_code( wr, type_code )
93
+ wr.send( enc_meth, mg_num.num )
94
+ end
95
+
96
+ private
97
+ def append_int64( wr, val )
98
+ append_num( wr, val, TYPE_CODE_INT64, :write_int64 )
99
+ end
100
+
101
+ private
102
+ def append_int32( wr, val )
103
+ append_num( wr, val, TYPE_CODE_INT32, :write_int32 )
104
+ end
105
+
106
+ private
107
+ def append_uint32( wr, val )
108
+ append_num( wr, val, TYPE_CODE_UINT32, :write_uint32 )
109
+ end
110
+
111
+ private
112
+ def append_uint64( wr, val )
113
+ append_num( wr, val, TYPE_CODE_UINT64, :write_uint64 )
114
+ end
115
+
116
+ private
117
+ def append_float64( wr, val )
118
+ append_num( wr, val, TYPE_CODE_FLOAT64, :write_float64 )
119
+ end
120
+
121
+ private
122
+ def append_float32( wr, val )
123
+ append_num( wr, val, TYPE_CODE_FLOAT32, :write_float32 )
124
+ end
125
+
126
+ private
127
+ def append_buffer( wr, val )
128
+
129
+ append_type_code( wr, TYPE_CODE_BUFFER )
130
+ append_sized_buffer( wr, val.buf )
131
+ end
132
+
133
+ private
134
+ def append_enum( wr, val )
135
+
136
+ append_type_code( wr, TYPE_CODE_ENUM )
137
+ append_type_reference( wr, val.type )
138
+ append_identifier( wr, val.value )
139
+ end
140
+
141
+ private
142
+ def append_timestamp( wr, val )
143
+
144
+ append_type_code( wr, TYPE_CODE_RFC3339_STR )
145
+ append_utf8( wr, val.rfc3339 )
146
+ end
147
+
148
+ private
149
+ def append_symbol_map( wr, val )
150
+
151
+ append_type_code( wr, TYPE_CODE_SYMBOL_MAP )
152
+ append_fields( wr, val )
153
+ end
154
+
155
+ private
156
+ def append_list( wr, val )
157
+
158
+ append_type_code( wr, TYPE_CODE_LIST )
159
+ wr.write_int32( -1 )
160
+ val.each { |elt| append_value( wr, elt ) }
161
+ append_type_code( wr, TYPE_CODE_END )
162
+ end
163
+
164
+ private
165
+ def append_value( wr, val )
166
+
167
+ case val
168
+
169
+ when MingleBoolean then append_boolean( wr, val )
170
+ when MingleString then append_string( wr, val )
171
+ when MingleInt32 then append_int32( wr, val )
172
+ when MingleInt64 then append_int64( wr, val )
173
+ when MingleUint32 then append_uint32( wr, val )
174
+ when MingleUint64 then append_uint64( wr, val )
175
+ when MingleFloat32 then append_float32( wr, val )
176
+ when MingleFloat64 then append_float64( wr, val )
177
+ when MingleBuffer then append_buffer( wr, val )
178
+ when MingleEnum then append_enum( wr, val )
179
+ when MingleTimestamp then append_timestamp( wr, val )
180
+ when MingleStruct then append_struct( wr, val )
181
+ when MingleSymbolMap then append_symbol_map( wr, val )
182
+ when MingleList then append_list( wr, val )
183
+ when MingleNull then append_type_code( wr, TYPE_CODE_NULL )
184
+
185
+ else raise "Unhandled value type: #{val.class}"
186
+ end
187
+ end
188
+
189
+ private
190
+ def append_fields( wr, flds )
191
+
192
+ flds.each_pair do |fld, val|
193
+
194
+ unless val.is_a?( MingleNull )
195
+ append_type_code( wr, TYPE_CODE_FIELD )
196
+ append_identifier( wr, fld )
197
+ append_value( wr, val )
198
+ end
199
+ end
200
+
201
+ append_type_code( wr, TYPE_CODE_END )
202
+ end
203
+
204
+ private
205
+ def append_struct( wr, ms )
206
+
207
+ append_type_code( wr, TYPE_CODE_STRUCT )
208
+ wr.write_int32( -1 )
209
+ append_type_reference( wr, ms.type )
210
+ append_fields( wr, ms.fields )
211
+ end
212
+
213
+ public
214
+ def as_buffer( obj )
215
+
216
+ not_nil( obj, :obj )
217
+ obj.is_a?( MingleStruct ) or codec_raise( "Not a struct: #{obj}" )
218
+
219
+ buf = RubyVersions.when_19x( StringIO.new ) do |io|
220
+ io.set_encoding( "binary" )
221
+ end
222
+
223
+ wr = Io::BinaryWriter.new( :order => BYTE_ORDER, :io => buf )
224
+
225
+ append_struct( wr, obj )
226
+
227
+ buf.string
228
+ end
229
+
230
+ private
231
+ def to_hex_byte( i )
232
+ sprintf( "0x%02x", i % 256 )
233
+ end
234
+
235
+ # Useful when reporting errors; returns the index just before pos, which was
236
+ # presumably related to the error
237
+ private
238
+ def last_pos( scanner )
239
+ scanner.pos - 1
240
+ end
241
+
242
+ private
243
+ def cur_pos( scanner )
244
+ scanner.pos
245
+ end
246
+
247
+ private
248
+ def decode_raise( pos_obj, msg )
249
+
250
+ off = case pos_obj
251
+ when Fixnum then pos_obj
252
+ when Io::BinaryReader then last_pos( pos_obj )
253
+ else raise "Unexpected pos_obj of type #{pos_obj.class}"
254
+ end
255
+
256
+ codec_raise( "[offset #{off}]: #{msg}" )
257
+ end
258
+
259
+ private
260
+ def type_code_expect_raise( code_sym, code_act, pos )
261
+
262
+ code_val = BinCodec.const_get( code_sym )
263
+
264
+ codec_raise "Expected #{code_sym} (#{to_hex_byte( code_val )}) " \
265
+ "but saw #{to_hex_byte( code_act )} at byte #{pos}"
266
+ end
267
+
268
+ private
269
+ def expect_type_code( scanner, code_sym )
270
+
271
+ code_val = Mingle::BinCodec.const_get( code_sym )
272
+
273
+ if ( b = scanner.read_int8 ) == code_val
274
+ code_val
275
+ else
276
+ type_code_expect_raise( code_sym, b, last_pos( scanner ) )
277
+ end
278
+ end
279
+
280
+ private
281
+ def expect_type_code_end( scanner )
282
+ expect_type_code( scanner, :TYPE_CODE_END )
283
+ end
284
+
285
+ private
286
+ def read_string_with_info( scanner )
287
+
288
+ # Only handling utf8 strings right now
289
+ expect_type_code( scanner, :TYPE_CODE_UTF8_STRING )
290
+
291
+ str = scanner.read_utf8
292
+ start_pos = scanner.pos - str.bytesize
293
+ [ str, { :string_start => start_pos } ]
294
+ end
295
+
296
+ private
297
+ def read_string( scanner )
298
+ read_string_with_info( scanner )[ 0 ]
299
+ end
300
+
301
+ private
302
+ def parse_string( opts )
303
+
304
+ scanner = has_key( opts, :scanner )
305
+ parser = has_key( opts, :parser )
306
+ parse_type = has_key( opts, :parse_type )
307
+ error_type = has_key( opts, :error_type )
308
+
309
+ str, info = read_string_with_info( scanner )
310
+
311
+ begin
312
+ parser.call( str )
313
+ rescue error_type => err
314
+ pos = has_key( info, :string_start )
315
+ decode_raise( pos, "Invalid #{parse_type}: #{err}" )
316
+ end
317
+ end
318
+
319
+ private
320
+ def read_type_reference( scanner )
321
+
322
+ return BinReader.as_bin_reader( scanner ).read_type_reference
323
+
324
+ # parse_string(
325
+ # :scanner => scanner,
326
+ # :parser => lambda { |str| MingleTypeReference.get( str ) },
327
+ # :parse_type => "type reference",
328
+ # :error_type => MingleParseError
329
+ # )
330
+ end
331
+
332
+ private
333
+ def read_identifier( scanner )
334
+
335
+ return BinReader.as_bin_reader( scanner ).read_identifier
336
+ # parse_string(
337
+ # :scanner => scanner,
338
+ # :parser => lambda { |str| MingleIdentifier.get( str ) },
339
+ # :parse_type => "identifier",
340
+ # :error_type => MingleParseError
341
+ # )
342
+ end
343
+
344
+ private
345
+ def read_field( scanner, flds )
346
+
347
+ id = read_identifier( scanner )
348
+ fld = read_value( scanner )
349
+
350
+ flds[ id ] = fld
351
+ end
352
+
353
+ private
354
+ def read_fields( scanner )
355
+
356
+ flds = {}
357
+
358
+ while ( tc = scanner.read_int8 ) != TYPE_CODE_END
359
+ if tc == TYPE_CODE_FIELD
360
+ read_field( scanner, flds )
361
+ else
362
+ type_code_expect_raise(
363
+ :TYPE_CODE_FIELD, tc, cur_pos( scanner ) )
364
+ end
365
+ end
366
+
367
+ MingleSymbolMap.create( flds )
368
+ end
369
+
370
+ private
371
+ def read_mg_boolean( scanner )
372
+
373
+ case b = scanner.read_int8
374
+ when 0x00 then MingleBoolean::FALSE
375
+ when 0x01 then MingleBoolean::TRUE
376
+ else raise "Unexpected bool val: #{to_hex_byte( b )}"
377
+ end
378
+ end
379
+
380
+ private
381
+ def read_mg_string( scanner )
382
+ MingleString.new( read_string( scanner ) )
383
+ end
384
+
385
+ private
386
+ def read_mg_struct( scanner )
387
+
388
+ sz = scanner.read_int32
389
+ typ = read_type_reference( scanner )
390
+ flds = read_fields( scanner )
391
+
392
+ MingleStruct.new( :type => typ, :fields => flds )
393
+ end
394
+
395
+ [
396
+ [ :int64, MingleInt64, :read_int64 ],
397
+ [ :int32, MingleInt32, :read_int32 ],
398
+ [ :uint32, MingleUint32, :read_uint32 ],
399
+ [ :uint64, MingleUint64, :read_uint64 ],
400
+ [ :float64, MingleFloat64, :read_float64 ],
401
+ [ :float32, MingleFloat32, :read_float32 ],
402
+ ].
403
+ each do |arr|
404
+
405
+ meth, num_cls, scan_meth = *arr
406
+
407
+ define_method( :"read_mg_#{meth}" ) do |scanner|
408
+ num_cls.new( scanner.send( scan_meth ) )
409
+ end
410
+ end
411
+
412
+ private
413
+ def read_mg_buffer( scanner )
414
+ MingleBuffer.new( scanner.read_buffer32 )
415
+ end
416
+
417
+ private
418
+ def read_mg_enum( scanner )
419
+
420
+ typ = read_type_reference( scanner )
421
+ value = read_identifier( scanner )
422
+
423
+ MingleEnum.new( :type => typ, :value => value )
424
+ end
425
+
426
+ private
427
+ def read_mg_timestamp( scanner )
428
+
429
+ parse_string(
430
+ :scanner => scanner,
431
+ :parser => lambda { |str| MingleTimestamp.rfc3339( str ) },
432
+ :parse_type => "rfc3339 timestamp",
433
+ :error_type => MingleTimestamp::Rfc3339FormatError
434
+ )
435
+ end
436
+
437
+ private
438
+ def read_mg_list( scanner )
439
+
440
+ res = []
441
+ len = scanner.read_int32 # ignored for now
442
+
443
+ while ( tc = scanner.read_int8 ) != TYPE_CODE_END
444
+ res << read_value( scanner, tc )
445
+ end
446
+
447
+ MingleList.new( res )
448
+ end
449
+
450
+ private
451
+ def read_value( scanner, typ = scanner.read_int8 )
452
+
453
+ case typ
454
+
455
+ when TYPE_CODE_BOOLEAN then read_mg_boolean( scanner )
456
+ when TYPE_CODE_INT64 then read_mg_int64( scanner )
457
+ when TYPE_CODE_INT32 then read_mg_int32( scanner )
458
+ when TYPE_CODE_UINT32 then read_mg_uint32( scanner )
459
+ when TYPE_CODE_UINT64 then read_mg_uint64( scanner )
460
+ when TYPE_CODE_FLOAT64 then read_mg_float64( scanner )
461
+ when TYPE_CODE_FLOAT32 then read_mg_float32( scanner )
462
+ when TYPE_CODE_STRING then read_mg_string( scanner )
463
+ when TYPE_CODE_BUFFER then read_mg_buffer( scanner )
464
+ when TYPE_CODE_ENUM then read_mg_enum( scanner )
465
+ when TYPE_CODE_RFC3339_STR then read_mg_timestamp( scanner )
466
+ when TYPE_CODE_STRUCT then read_mg_struct( scanner )
467
+ when TYPE_CODE_SYMBOL_MAP then read_fields( scanner )
468
+ when TYPE_CODE_LIST then read_mg_list( scanner )
469
+ when TYPE_CODE_NULL then MingleNull::INSTANCE
470
+
471
+ else
472
+ decode_raise(
473
+ scanner, "Unexpected type code: #{to_hex_byte( typ )}" )
474
+ end
475
+ end
476
+
477
+ private
478
+ def validate_from_buffer_args( buf )
479
+
480
+ not_nil( buf, :buf )
481
+
482
+ RubyVersions.when_19x do
483
+ buf.encoding == Encoding::BINARY or
484
+ codec_raise( "Buffer encoding is not binary" )
485
+ end
486
+
487
+ unless ( tc = @conv.read_int8( buf[ 0, 1 ] ) ) == TYPE_CODE_STRUCT
488
+
489
+ msg = "Saw type code #{to_hex_byte( tc )} but expected " +
490
+ to_hex_byte( TYPE_CODE_STRUCT )
491
+ decode_raise( 0, msg )
492
+ end
493
+ end
494
+
495
+ public
496
+ def from_buffer( buf )
497
+
498
+ validate_from_buffer_args( buf )
499
+
500
+ scanner = Io::BinaryReader.new(
501
+ :order => BYTE_ORDER, :io => StringIO.new( buf ) )
502
+
503
+ if ( res = read_value( scanner ) ).is_a?( MingleStruct )
504
+ res
505
+ else
506
+ raise "Decode res wasn't a struct; got #{res.class}"
507
+ end
508
+ end
509
+ end
510
+
511
+ end
512
+ end