sparsam 0.1.4 → 0.1.5
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/ext/serializer.cpp +64 -16
- data/ext/serializer.h +1 -1
- data/lib/sparsam/base_class.rb +0 -1
- data/lib/sparsam/exceptions.rb +12 -4
- data/spec/gen-ruby/user_types.rb +22 -0
- data/spec/sparsam_spec.rb +105 -0
- data/spec/user.thrift +21 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82b851a7cec00fa3805571f1cd89d43077b86ed5
|
4
|
+
data.tar.gz: c4617c449ccd26bb73896e49ceb430b15f6f973c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73aff3bcae386d83adb457c63ef35ec0d0281e2bab33436b4f05c7fa8b79f80e5110d7600cfa3427cfbd5eeb222f01cf997ce8f312cd3be72dbb6f7d6fbebdc1
|
7
|
+
data.tar.gz: 6f060447c4d06c8abd9f014dcdbafe5e3e1e8ffc8ce0a23c999c7c445138ac019a0257eccf48bdfc5af4cf722ccd64e44155574190c65f67dadc026b1f223317
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Sparsam [](https://travis-ci.org/airbnb/sparsam) [](https://coveralls.io/github/airbnb/sparsam?branch=master)
|
1
|
+
# Sparsam [](https://travis-ci.org/airbnb/sparsam) [](https://coveralls.io/github/airbnb/sparsam?branch=master) [](https://badge.fury.io/rb/sparsam)
|
2
2
|
New Thrift bindings and generator for Ruby!
|
3
3
|
|
4
4
|
## Super basic Example
|
data/ext/serializer.cpp
CHANGED
@@ -136,6 +136,18 @@ static inline VALUE make_ruby_binary(const string &val) {
|
|
136
136
|
return rb_str_new(val.c_str(), val.size());
|
137
137
|
}
|
138
138
|
|
139
|
+
static void raise_exc_with_struct_and_field_names(
|
140
|
+
VALUE exc_class,
|
141
|
+
VALUE msg,
|
142
|
+
VALUE outer_struct_class,
|
143
|
+
VALUE field_sym) {
|
144
|
+
VALUE struct_name = rb_class_name(outer_struct_class);
|
145
|
+
VALUE field_name = rb_sym_to_s(field_sym);
|
146
|
+
VALUE args[3] = {msg, struct_name, field_name};
|
147
|
+
VALUE e = rb_class_new_instance(3, args, exc_class);
|
148
|
+
rb_exc_raise(e);
|
149
|
+
}
|
150
|
+
|
139
151
|
static inline VALUE make_ruby_bool(bool val) { return val ? Qtrue : Qfalse; }
|
140
152
|
|
141
153
|
void ThriftSerializer::skip_n_type(uint32_t n, TType ttype) {
|
@@ -301,8 +313,11 @@ VALUE ThriftSerializer::readStruct(VALUE klass) {
|
|
301
313
|
typeId = fieldInfo->ftype;
|
302
314
|
|
303
315
|
if (typeId != fieldBegin.ftype) {
|
304
|
-
|
305
|
-
|
316
|
+
raise_exc_with_struct_and_field_names(
|
317
|
+
SparsamTypeMismatchError,
|
318
|
+
rb_sprintf("Type Mismatch. Defenition: %d, Actual: %d", fieldBegin.ftype, typeId),
|
319
|
+
klass,
|
320
|
+
fieldInfo->symName);
|
306
321
|
}
|
307
322
|
|
308
323
|
VALUE rb_value = this->readAny(fieldBegin.ftype, iter->second);
|
@@ -387,6 +402,8 @@ void ThriftSerializer::writeAny(TType ttype, FieldInfo *field_info,
|
|
387
402
|
HANDLE_TYPE(BYTE, Byte, NUM2SHORT)
|
388
403
|
|
389
404
|
case protocol::T_STRING: {
|
405
|
+
Check_Type(actual, T_STRING);
|
406
|
+
|
390
407
|
string data = string(StringValuePtr(actual), RSTRING_LEN(actual));
|
391
408
|
if (field_info->isBinaryString) {
|
392
409
|
this->tprot->writeBinary(data);
|
@@ -397,6 +414,8 @@ void ThriftSerializer::writeAny(TType ttype, FieldInfo *field_info,
|
|
397
414
|
}
|
398
415
|
|
399
416
|
case protocol::T_LIST: {
|
417
|
+
Check_Type(actual, T_ARRAY);
|
418
|
+
|
400
419
|
long length = RARRAY_LEN(actual);
|
401
420
|
TType elem = field_info->elementType->ftype;
|
402
421
|
this->tprot->writeListBegin(elem, static_cast<size_t>(length));
|
@@ -420,6 +439,8 @@ void ThriftSerializer::writeAny(TType ttype, FieldInfo *field_info,
|
|
420
439
|
}
|
421
440
|
|
422
441
|
case protocol::T_MAP: {
|
442
|
+
Check_Type(actual, T_HASH);
|
443
|
+
|
423
444
|
TType keyTType = field_info->keyType->ftype,
|
424
445
|
valueTType = field_info->elementType->ftype;
|
425
446
|
this->tprot->writeMapBegin(keyTType, valueTType,
|
@@ -454,6 +475,11 @@ void ThriftSerializer::writeStruct(VALUE klass, VALUE data) {
|
|
454
475
|
FieldBegin fieldBegin;
|
455
476
|
FieldInfo *fieldInfo;
|
456
477
|
auto fields = FindOrCreateFieldInfoMap(klass);
|
478
|
+
|
479
|
+
if (!validateStruct(klass, data, false, false)) {
|
480
|
+
return;
|
481
|
+
}
|
482
|
+
|
457
483
|
for (auto const & entry : *fields) {
|
458
484
|
fieldBegin.fid = entry.first;
|
459
485
|
fieldInfo = entry.second;
|
@@ -490,15 +516,23 @@ VALUE serializer_readStruct(VALUE self, VALUE klass) {
|
|
490
516
|
catch_thrift_and_reraise();
|
491
517
|
}
|
492
518
|
|
493
|
-
static
|
494
|
-
|
519
|
+
static void raise_type_mismatch(VALUE outer_struct, VALUE field_sym) {
|
520
|
+
raise_exc_with_struct_and_field_names(
|
521
|
+
SparsamTypeMismatchError,
|
522
|
+
rb_str_new2("Type mismatch in field data"),
|
523
|
+
CLASS_OF(outer_struct),
|
524
|
+
field_sym);
|
495
525
|
}
|
496
526
|
|
497
|
-
bool validateArray(
|
527
|
+
bool validateArray(
|
528
|
+
FieldInfo *type,
|
529
|
+
VALUE arr,
|
530
|
+
bool recursive,
|
531
|
+
VALUE outer_struct,
|
532
|
+
VALUE field_sym) {
|
498
533
|
long length = RARRAY_LEN(arr);
|
499
534
|
for (long i = 0; i < length; i++) {
|
500
|
-
if (!validateAny(type, rb_ary_entry(arr, i), recursive)) {
|
501
|
-
rb_raise(SparsamTypeMismatchError, "Type mismatch in container element");
|
535
|
+
if (!validateAny(type, rb_ary_entry(arr, i), recursive, outer_struct, field_sym)) {
|
502
536
|
return false;
|
503
537
|
}
|
504
538
|
}
|
@@ -507,7 +541,7 @@ bool validateArray(FieldInfo *type, VALUE arr, bool recursive) {
|
|
507
541
|
|
508
542
|
#define TEST_RB_VAL_FOR_CLASS(VAL, KLASS) \
|
509
543
|
if (!RTEST(rb_obj_is_kind_of(VAL, KLASS))) { \
|
510
|
-
raise_type_mismatch();
|
544
|
+
raise_type_mismatch(outer_struct, field_sym); \
|
511
545
|
ret = false; \
|
512
546
|
}
|
513
547
|
|
@@ -517,7 +551,7 @@ bool validateArray(FieldInfo *type, VALUE arr, bool recursive) {
|
|
517
551
|
break; \
|
518
552
|
}
|
519
553
|
|
520
|
-
bool validateAny(FieldInfo *type, VALUE val, bool recursive) {
|
554
|
+
bool validateAny(FieldInfo *type, VALUE val, bool recursive, VALUE outer_struct, VALUE field_sym) {
|
521
555
|
bool ret = true;
|
522
556
|
switch (type->ftype) {
|
523
557
|
|
@@ -528,6 +562,14 @@ bool validateAny(FieldInfo *type, VALUE val, bool recursive) {
|
|
528
562
|
HANDLE_TYPE(DOUBLE, klass_for_float)
|
529
563
|
HANDLE_TYPE(STRING, klass_for_string)
|
530
564
|
|
565
|
+
case protocol::T_BOOL: {
|
566
|
+
if ( !(val == Qtrue || val == Qfalse) ) {
|
567
|
+
raise_type_mismatch(outer_struct, field_sym);
|
568
|
+
ret = false;
|
569
|
+
}
|
570
|
+
break;
|
571
|
+
}
|
572
|
+
|
531
573
|
case protocol::T_STRUCT: {
|
532
574
|
TEST_RB_VAL_FOR_CLASS(val, type->klass)
|
533
575
|
if (ret && recursive) {
|
@@ -540,14 +582,14 @@ bool validateAny(FieldInfo *type, VALUE val, bool recursive) {
|
|
540
582
|
TEST_RB_VAL_FOR_CLASS(val, klass_for_set)
|
541
583
|
if (ret) {
|
542
584
|
VALUE ary = rb_funcall(val, intern_for_to_a, 0);
|
543
|
-
ret = validateArray(type->elementType, ary, recursive);
|
585
|
+
ret = validateArray(type->elementType, ary, recursive, outer_struct, field_sym);
|
544
586
|
}
|
545
587
|
break;
|
546
588
|
}
|
547
589
|
case protocol::T_LIST: {
|
548
590
|
TEST_RB_VAL_FOR_CLASS(val, klass_for_array)
|
549
591
|
if (ret) {
|
550
|
-
ret = validateArray(type->elementType, val, recursive);
|
592
|
+
ret = validateArray(type->elementType, val, recursive, outer_struct, field_sym);
|
551
593
|
}
|
552
594
|
break;
|
553
595
|
}
|
@@ -557,12 +599,13 @@ bool validateAny(FieldInfo *type, VALUE val, bool recursive) {
|
|
557
599
|
if (ret) {
|
558
600
|
bool flag = true;
|
559
601
|
HASH_FOREACH_BEGIN(val, &flag, type->keyType, type->elementType,
|
560
|
-
&recursive)
|
602
|
+
&recursive, &outer_struct, &field_sym)
|
561
603
|
bool *flag = (bool *)argv[0], *recursive = (bool *)argv[3];
|
604
|
+
VALUE *outer_struct = (VALUE *)argv[4], *field_sym = (VALUE *)argv[5];
|
562
605
|
FieldInfo *field_info_key = (FieldInfo *)argv[1];
|
563
606
|
FieldInfo *field_info_value = (FieldInfo *)argv[2];
|
564
|
-
if (!validateAny(field_info_key, k, *recursive) ||
|
565
|
-
!validateAny(field_info_value, v, *recursive)) {
|
607
|
+
if (!validateAny(field_info_key, k, *recursive, *outer_struct, *field_sym) ||
|
608
|
+
!validateAny(field_info_value, v, *recursive, *outer_struct, *field_sym)) {
|
566
609
|
*flag = false;
|
567
610
|
HASH_FOREACH_ABORT()
|
568
611
|
}
|
@@ -594,12 +637,17 @@ bool validateStruct(VALUE klass, VALUE data, bool validateContainerTypes,
|
|
594
637
|
VALUE val = rb_ivar_get(data, entry.second->ivarName);
|
595
638
|
if (NIL_P(val)) {
|
596
639
|
if (!entry.second->isOptional) {
|
597
|
-
|
640
|
+
raise_exc_with_struct_and_field_names(
|
641
|
+
SparsamMissingMandatory,
|
642
|
+
rb_sprintf("Missing: fieldID %d", entry.first),
|
643
|
+
klass,
|
644
|
+
entry.second->symName);
|
598
645
|
return false;
|
599
646
|
}
|
600
647
|
continue;
|
601
648
|
}
|
602
|
-
if (validateContainerTypes &&
|
649
|
+
if (validateContainerTypes &&
|
650
|
+
!validateAny(entry.second, val, recursive, data, entry.second->symName)) {
|
603
651
|
return false;
|
604
652
|
}
|
605
653
|
}
|
data/ext/serializer.h
CHANGED
@@ -92,7 +92,7 @@ private:
|
|
92
92
|
|
93
93
|
bool validateStruct(VALUE klass, VALUE data, bool validateContainerTypes,
|
94
94
|
bool recursive);
|
95
|
-
bool validateAny(FieldInfo *type, VALUE val, bool recursive);
|
95
|
+
bool validateAny(FieldInfo *type, VALUE val, bool recursive, VALUE outer_struct, VALUE field_sym);
|
96
96
|
FieldInfoMap *FindOrCreateFieldInfoMap(VALUE klass);
|
97
97
|
FieldInfo *CreateFieldInfo(VALUE field_map_entry);
|
98
98
|
FieldInfoMap *CreateFieldInfoMap(VALUE klass);
|
data/lib/sparsam/base_class.rb
CHANGED
data/lib/sparsam/exceptions.rb
CHANGED
@@ -8,14 +8,22 @@ module Sparsam
|
|
8
8
|
end
|
9
9
|
|
10
10
|
class MissingMandatory < Exception
|
11
|
-
|
12
|
-
|
11
|
+
attr_reader :struct_name, :field_name
|
12
|
+
|
13
|
+
def initialize(msg, struct_name = nil, field_name = nil)
|
14
|
+
@struct_name = struct_name
|
15
|
+
@field_name = field_name
|
16
|
+
super(msg)
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
16
20
|
class TypeMismatch < Exception
|
17
|
-
|
18
|
-
|
21
|
+
attr_reader :struct_name, :field_name
|
22
|
+
|
23
|
+
def initialize(msg, struct_name = nil, field_name = nil)
|
24
|
+
@struct_name = struct_name
|
25
|
+
@field_name = field_name
|
26
|
+
super(msg)
|
19
27
|
end
|
20
28
|
end
|
21
29
|
|
data/spec/gen-ruby/user_types.rb
CHANGED
@@ -104,3 +104,25 @@ class Nothing < ::Sparsam::Struct
|
|
104
104
|
init_thrift_struct(self)
|
105
105
|
end
|
106
106
|
|
107
|
+
class EveryType < ::Sparsam::Struct
|
108
|
+
FIELDS = {
|
109
|
+
1 => {:type => ::Sparsam::Types::BOOL, :name => 'a_bool', :optional => true},
|
110
|
+
2 => {:type => ::Sparsam::Types::BYTE, :name => 'a_byte', :optional => true},
|
111
|
+
3 => {:type => ::Sparsam::Types::I16, :name => 'an_i16', :optional => true},
|
112
|
+
4 => {:type => ::Sparsam::Types::I32, :name => 'an_i32', :optional => true},
|
113
|
+
5 => {:type => ::Sparsam::Types::I64, :name => 'an_i64', :optional => true},
|
114
|
+
6 => {:type => ::Sparsam::Types::DOUBLE, :name => 'a_double', :optional => true},
|
115
|
+
7 => {:type => ::Sparsam::Types::STRING, :name => 'a_binary', :binary => true, :optional => true},
|
116
|
+
8 => {:type => ::Sparsam::Types::STRING, :name => 'a_string', :optional => true},
|
117
|
+
9 => {:type => ::Sparsam::Types::LIST, :name => 'an_i64_list', :element => {:type => ::Sparsam::Types::I64}, :optional => true},
|
118
|
+
10 => {:type => ::Sparsam::Types::SET, :name => 'an_i64_set', :element => {:type => ::Sparsam::Types::I64}, :optional => true},
|
119
|
+
11 => {:type => ::Sparsam::Types::MAP, :name => 'an_i64_map', :key => {:type => ::Sparsam::Types::I64}, :value => {:type => ::Sparsam::Types::I64}, :optional => true},
|
120
|
+
12 => {:type => ::Sparsam::Types::LIST, :name => 'a_list_of_i64_maps', :element => {:type => ::Sparsam::Types::MAP, :key => {:type => ::Sparsam::Types::I64}, :value => {:type => ::Sparsam::Types::I64}}, :optional => true},
|
121
|
+
13 => {:type => ::Sparsam::Types::MAP, :name => 'a_map_of_i64_maps', :key => {:type => ::Sparsam::Types::MAP, :key => {:type => ::Sparsam::Types::I64}, :value => {:type => ::Sparsam::Types::I64}}, :value => {:type => ::Sparsam::Types::MAP, :key => {:type => ::Sparsam::Types::I64}, :value => {:type => ::Sparsam::Types::I64}}, :optional => true},
|
122
|
+
14 => {:type => ::Sparsam::Types::STRUCT, :name => 'a_struct', :class => ::US, :optional => true},
|
123
|
+
15 => {:type => ::Sparsam::Types::STRUCT, :name => 'a_union', :class => ::UN, :optional => true}
|
124
|
+
}
|
125
|
+
|
126
|
+
init_thrift_struct(self)
|
127
|
+
end
|
128
|
+
|
data/spec/sparsam_spec.rb
CHANGED
@@ -92,6 +92,7 @@ describe 'Sparsam' do
|
|
92
92
|
expect {
|
93
93
|
Sparsam.validate(NotSS, data, Sparsam::STRICT)
|
94
94
|
}.to raise_error(Sparsam::TypeMismatch)
|
95
|
+
|
95
96
|
expect {
|
96
97
|
Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
|
97
98
|
}.to raise_error(Sparsam::TypeMismatch)
|
@@ -151,6 +152,21 @@ describe 'Sparsam' do
|
|
151
152
|
}.to raise_error(Sparsam::TypeMismatch)
|
152
153
|
end
|
153
154
|
|
155
|
+
it "includes additional data in TypeMismatch errors" do
|
156
|
+
data = EasilyInvalid.new
|
157
|
+
data.id_i32 = "definitely a string"
|
158
|
+
|
159
|
+
e = nil
|
160
|
+
begin
|
161
|
+
Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
|
162
|
+
rescue Sparsam::TypeMismatch => exception
|
163
|
+
e = exception
|
164
|
+
end
|
165
|
+
|
166
|
+
e.struct_name.should == EasilyInvalid.name
|
167
|
+
e.field_name.should == "id_i32"
|
168
|
+
end
|
169
|
+
|
154
170
|
it "works with crazy thriftness" do
|
155
171
|
data = EasilyInvalid.new
|
156
172
|
data.sure = [{ Set.new([1]) => { 1 => Set.new([[{ EasilyInvalid.new => "sure" }]]) } }]
|
@@ -189,6 +205,20 @@ describe 'Sparsam' do
|
|
189
205
|
expect { data.validate }.to raise_error(Sparsam::MissingMandatory)
|
190
206
|
end
|
191
207
|
|
208
|
+
it "includes additional information on missing required fields in exception" do
|
209
|
+
data = MiniRequired.new
|
210
|
+
|
211
|
+
e = nil
|
212
|
+
begin
|
213
|
+
data.validate
|
214
|
+
rescue Sparsam::MissingMandatory => exception
|
215
|
+
e = exception
|
216
|
+
end
|
217
|
+
|
218
|
+
e.struct_name.should == MiniRequired.name
|
219
|
+
e.field_name.should == "id_i32"
|
220
|
+
end
|
221
|
+
|
192
222
|
it "will throw errors when given junk data" do
|
193
223
|
expect {
|
194
224
|
Sparsam::Deserializer.deserialize(SS, "wolololololol")
|
@@ -300,5 +330,80 @@ describe 'Sparsam' do
|
|
300
330
|
Sparsam::Deserializer.deserialize(SS, really_bad, Sparsam::BinaryProtocol)
|
301
331
|
}.to raise_error(Sparsam::Exception)
|
302
332
|
end
|
333
|
+
|
334
|
+
it "handles all sorts of type issues without crashing" do
|
335
|
+
field_map = {
|
336
|
+
a_bool: :boolean,
|
337
|
+
a_byte: :int,
|
338
|
+
an_i16: :int,
|
339
|
+
an_i32: :int,
|
340
|
+
an_i64: :int,
|
341
|
+
a_double: :float,
|
342
|
+
a_binary: :string,
|
343
|
+
a_string: :string,
|
344
|
+
|
345
|
+
an_i64_list: :int_list,
|
346
|
+
an_i64_set: :int_set,
|
347
|
+
an_i64_map: :int_map,
|
348
|
+
|
349
|
+
a_list_of_i64_maps: :int_map_list,
|
350
|
+
a_map_of_i64_maps: :int_map_map,
|
351
|
+
|
352
|
+
a_struct: :struct,
|
353
|
+
a_union: :union,
|
354
|
+
}
|
355
|
+
|
356
|
+
scalar_values = {
|
357
|
+
boolean: true,
|
358
|
+
int: 42,
|
359
|
+
float: 3.14,
|
360
|
+
string: "Hello",
|
361
|
+
struct: US.new(id_i32: 10),
|
362
|
+
union: UN.new(id_s: "woo"),
|
363
|
+
complex: Complex(1),
|
364
|
+
bigint: 2**128,
|
365
|
+
rational: Rational(2, 3),
|
366
|
+
}
|
367
|
+
|
368
|
+
simple_collection_values = scalar_values.each_with_object({}) do |(type, val), obj|
|
369
|
+
obj[:"#{type}_list"] = [val]
|
370
|
+
obj[:"#{type}_set"] = Set.new([val])
|
371
|
+
obj[:"#{type}_map"] = { val => val }
|
372
|
+
end
|
373
|
+
|
374
|
+
nested_collection_values =
|
375
|
+
simple_collection_values.each_with_object({}) do |(type, val), obj|
|
376
|
+
obj[:"#{type}_list"] = [val]
|
377
|
+
obj[:"#{type}_set"] = Set.new([val])
|
378
|
+
obj[:"#{type}_map"] = { val => val }
|
379
|
+
end
|
380
|
+
|
381
|
+
all_values = scalar_values.merge(simple_collection_values).merge(nested_collection_values)
|
382
|
+
|
383
|
+
field_map.each do |field, type|
|
384
|
+
all_values.each do |val_type, val|
|
385
|
+
next if val_type == type
|
386
|
+
|
387
|
+
s = EveryType.new
|
388
|
+
s.send(:"#{field}=", val)
|
389
|
+
|
390
|
+
# Validation doesn't do range checking, though serialization does
|
391
|
+
unless val_type.to_s =~ /bigint/
|
392
|
+
expect {
|
393
|
+
Sparsam.validate(s.class, s, Sparsam::STRICT)
|
394
|
+
}.to(
|
395
|
+
raise_error(Sparsam::TypeMismatch),
|
396
|
+
"assigning #{field} : #{type} a value of " \
|
397
|
+
"#{val.inspect} : #{val_type} did not raise TypeMismatch"
|
398
|
+
)
|
399
|
+
end
|
400
|
+
|
401
|
+
begin
|
402
|
+
s.serialize
|
403
|
+
rescue TypeError, RangeError, NoMethodError, Sparsam::TypeMismatch
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
303
408
|
end
|
304
409
|
end
|
data/spec/user.thrift
CHANGED
@@ -60,3 +60,24 @@ struct NotSS_plus {
|
|
60
60
|
|
61
61
|
struct nothing {
|
62
62
|
}
|
63
|
+
|
64
|
+
struct EveryType {
|
65
|
+
1: optional bool a_bool
|
66
|
+
2: optional byte a_byte
|
67
|
+
3: optional i16 an_i16
|
68
|
+
4: optional i32 an_i32
|
69
|
+
5: optional i64 an_i64
|
70
|
+
6: optional double a_double
|
71
|
+
7: optional binary a_binary
|
72
|
+
8: optional string a_string
|
73
|
+
|
74
|
+
9: optional list<i64> an_i64_list
|
75
|
+
10: optional set<i64> an_i64_set
|
76
|
+
11: optional map<i64, i64> an_i64_map
|
77
|
+
|
78
|
+
12: optional list<map<i64, i64>> a_list_of_i64_maps
|
79
|
+
13: optional map<map<i64, i64>, map<i64, i64>> a_map_of_i64_maps
|
80
|
+
|
81
|
+
14: optional US a_struct
|
82
|
+
15: optional UN a_union
|
83
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sparsam
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Airbnb Thrift Developers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -161,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
161
|
version: '0'
|
162
162
|
requirements: []
|
163
163
|
rubyforge_project: thrift
|
164
|
-
rubygems_version: 2.6.
|
164
|
+
rubygems_version: 2.6.11
|
165
165
|
signing_key:
|
166
166
|
specification_version: 4
|
167
167
|
summary: Ruby bindings for Apache Thrift
|