anujdas-thrift-validator 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7396a4d4b0ade73560af2af1a3582515b227011fa4f9e73bf139200c3cff328c
4
+ data.tar.gz: 2872e2cfb10594cdfc6239a2da1e363d0506d5092cb4e474eaafec1f84837a83
5
+ SHA512:
6
+ metadata.gz: 6b12095b4e3a0a7532bddaa5bb8d2237c14aebf59b776961dd14c307c77c528e06e76eddb152debd17c20d3865422acb7b4de04798aa00fdd320369e7416b716
7
+ data.tar.gz: fc9838ce5cfe1f42a7bb182568ddbc384ca04786d96cda2022ced77c58150c7d011ed35f89c13c3ada0cc6edb94ee9a33b4d7754c724afe0423309ea45220a99
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in thrift-validator.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 ahawkins
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,101 @@
1
+ # Thrift::Validator
2
+
3
+ Recursive [thrift][] struct validator. The thrift library out of the box does
4
+ not validated nested structs; This library fixes that problem. Rather than
5
+ monkey-patching Thrift, this library includes a class to validate objects
6
+ recursively.
7
+
8
+ Here's an example from this library's tests. Given the following schema:
9
+
10
+ ```thrift
11
+ struct SimpleStruct {
12
+ 1: required string required_string,
13
+ 2: optional string optional_string,
14
+ }
15
+
16
+ struct NestedExample {
17
+ 1: required SimpleStruct required_struct,
18
+ 2: optional SimpleStruct optional_struct,
19
+ }
20
+ ```
21
+
22
+ This library provides:
23
+
24
+ ```ruby
25
+ struct = SimpleStruct.new
26
+ nested = NestedStruct.new(required_struct: struct)
27
+
28
+ # Method defined by the Thrift library
29
+ struct.validate # => Thrift::ProtocolException
30
+
31
+ # Thrift only validates fields set as required on this instance. Since
32
+ # `required_struct` is non-nil, validation succeeds. Also note that Thrift
33
+ # does not validate semantics of the assigned objects, so assigning an
34
+ # invalid struct will pass its validation method.
35
+ nested.validate # => true
36
+
37
+ # With the validator
38
+ Thrift::Validator.new.validate(nested) # => Thrift::ProtocolException
39
+ ```
40
+
41
+ ## Semantics enforced
42
+
43
+ * all original Thrift validation semantics
44
+ * `optional` or `required` `struct` types
45
+ * `optional` or `required` `list<struct>` items
46
+ * `optional` or `required` `set<struct>` items
47
+ * `optional` or `required` `map` types with `struct` keys and/or values
48
+
49
+ ## Exception handling
50
+
51
+ Due to the recursive nature of `thrift-validator`, the validation
52
+ errors raised by Thrift become less than helpful. In order
53
+ to provide more information, the resulting `Thrift::ProtocolException`
54
+ message is prefixed with the type where the error occurred. For
55
+ example:
56
+
57
+ ```ruby
58
+ # Without thrift-validator
59
+ > struct.validate
60
+ Thrift::ProtocolException: Required field required_string is unset!
61
+
62
+ # With thrift-validator
63
+ > Thrift::Validator.new.validate(struct)
64
+ Thrift::ProtocolException: SimpleStruct: Required field required_string is unset!
65
+ ```
66
+
67
+ This feature becomes especially useful with nested structs, where validation
68
+ may fail at any depth.
69
+
70
+ ## Installation
71
+
72
+ Add this line to your application's Gemfile:
73
+
74
+ ```ruby
75
+ gem 'thrift-validator'
76
+ ```
77
+
78
+ And then execute:
79
+
80
+ $ bundle
81
+
82
+ Or install it yourself as:
83
+
84
+ $ gem install thrift-validator
85
+
86
+ ## Testing
87
+
88
+ First, install a `thrift` compiler on your platform (e.g., `brew install
89
+ thrift`, `sudo apt install thrift`). Then run:
90
+
91
+ $ rake test
92
+
93
+ ## Contributing
94
+
95
+ 1. Fork it ( https://github.com/saltside/thrift-validator-ruby/fork )
96
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
97
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
98
+ 4. Push to the branch (`git push origin my-new-feature`)
99
+ 5. Create a new Pull Request
100
+
101
+ [thrift]: https://thrift.apache.org
@@ -0,0 +1,23 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ THRIFT_IN = 'test/test.thrift'
5
+ THRIFT_OUT = Rake::FileList['test/gen-rb/test_constants.rb', 'test/gen-rb/test_types.rb']
6
+
7
+ THRIFT_OUT.each do |output|
8
+ file output => THRIFT_IN do
9
+ sh 'thrift', '-o', 'test', '--gen', 'rb', THRIFT_IN
10
+ end
11
+ end
12
+
13
+ desc 'Cleans generated files from workspace'
14
+ task :clean do
15
+ rm THRIFT_OUT
16
+ end
17
+
18
+ Rake::TestTask.new do |t|
19
+ t.test_files = Rake::FileList['test/**/*_test.rb']
20
+ end
21
+ task test: THRIFT_OUT # add dependency
22
+
23
+ task default: :test
@@ -0,0 +1 @@
1
+ require 'thrift/validator'
@@ -0,0 +1,32 @@
1
+ require 'thrift/validator/version'
2
+ require 'thrift'
3
+
4
+ module Thrift
5
+ class Validator
6
+ DEFAULT_TYPE = Thrift::ProtocolException::UNKNOWN
7
+
8
+ # @param structs [Object] any Thrift value -- struct, primitive, or a collection thereof
9
+ # @raise [Thrift::ProtocolException] if any deviation from schema was detected
10
+ # @return [nil] if no problems were detected; note that this does not include type checks
11
+ def validate(structs)
12
+ # handle anything -- Struct, Union, List, Set, Map, primitives...
13
+ Array(structs).flatten.each do |struct|
14
+ begin
15
+ # only Structs/Unions can be validated (see Thrift.type_checking for another option)
16
+ next unless struct.is_a?(Struct_Union)
17
+ # raises a ProtocolException if this specific struct is invalid
18
+ struct.validate
19
+ # recursively validate all fields except unset union fields
20
+ struct.struct_fields.each_value do |f|
21
+ next if struct.is_a?(Union) && struct.get_set_field != f[:name].to_sym
22
+ validate(struct.send(f[:name]))
23
+ end
24
+ rescue ProtocolException => e
25
+ raise ProtocolException.new(e.type, "#{struct.class}: #{e.message}")
26
+ rescue => e # union validation raises StandardError...
27
+ raise ProtocolException.new(DEFAULT_TYPE, "#{struct.class}: #{e.message}")
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ module Thrift
2
+ class Validator
3
+ VERSION = '0.2.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,163 @@
1
+ require_relative 'test_helper'
2
+
3
+ class AcceptanceTest < MiniTest::Unit::TestCase
4
+ def test_follows_thrift_semantics
5
+ struct = SimpleStruct.new required_string: nil, optional_string: nil
6
+ refute_valid struct
7
+ end
8
+
9
+ def test_fails_if_a_required_nested_struct_is_invalid
10
+ struct = NestedExample.new
11
+ struct.required_struct = SimpleStruct.new
12
+ refute_valid struct
13
+ end
14
+
15
+ def test_fails_if_an_optional_nested_struct_is_valid
16
+ struct = NestedExample.new
17
+ struct.required_struct = SimpleStruct.new required_string: 'foo'
18
+ struct.optional_struct = SimpleStruct.new
19
+ refute_valid struct
20
+ end
21
+
22
+ def test_passes_if_nested_structs_are_valid
23
+ struct = NestedExample.new
24
+ struct.required_struct = SimpleStruct.new required_string: 'foo'
25
+ struct.optional_struct = SimpleStruct.new required_string: 'bar'
26
+ assert_valid struct
27
+ end
28
+
29
+ def test_passes_if_nested_optional_struct_is_omitted
30
+ struct = NestedExample.new
31
+ struct.required_struct = SimpleStruct.new required_string: 'foo'
32
+ assert_valid struct
33
+ end
34
+
35
+ def test_fails_if_a_nested_list_item_is_invalid
36
+ struct = ListExample.new
37
+ struct.required_list = [ SimpleStruct.new ]
38
+ refute_valid struct
39
+ end
40
+
41
+ def test_fails_if_a_nested_list_item_is_invalid
42
+ struct = ListExample.new
43
+ struct.required_list = [ SimpleStruct.new({ required_string: 'foo' }) ]
44
+ struct.optional_list = [ SimpleStruct.new ]
45
+ refute_valid struct
46
+ end
47
+
48
+ def test_passes_if_given_valid_list_items
49
+ struct = ListExample.new
50
+ struct.required_list = [ SimpleStruct.new({ required_string: 'foo' }) ]
51
+ struct.optional_list = [ SimpleStruct.new({ required_string: 'bar' }) ]
52
+ assert_valid struct
53
+ end
54
+
55
+ def test_passes_with_primitives_list
56
+ struct = StringListExample.new
57
+ struct.required_list = [ 'foo' ]
58
+ assert_valid struct
59
+ end
60
+
61
+ def test_fails_if_a_nested_set_item_is_invalid
62
+ struct = SetExample.new
63
+ struct.required_set = Set.new([ SimpleStruct.new ])
64
+ refute_valid struct
65
+ end
66
+
67
+ def test_fails_if_a_nested_set_item_is_invalid
68
+ struct = SetExample.new
69
+ struct.required_set = Set.new([ SimpleStruct.new({ required_string: 'foo' }) ])
70
+ struct.optional_set = Set.new([ SimpleStruct.new ])
71
+ refute_valid struct
72
+ end
73
+
74
+ def test_passes_if_given_valid_set_items
75
+ struct = SetExample.new
76
+ struct.required_set = Set.new([ SimpleStruct.new({ required_string: 'foo' }) ])
77
+ struct.optional_set = Set.new([ SimpleStruct.new({ required_string: 'bar' }) ])
78
+ assert_valid struct
79
+ end
80
+
81
+ def test_passes_with_primitives_set
82
+ struct = StringSetExample.new
83
+ struct.required_set = Set.new([ 'foo' ])
84
+ assert_valid struct
85
+ end
86
+
87
+ def test_fails_if_nested_map_key_is_invalid
88
+ struct = MapKeyExample.new
89
+ struct.required_map = { SimpleStruct.new => 'foo' }
90
+ refute_valid struct
91
+ end
92
+
93
+ def test_fails_if_nested_map_key_is_invalid
94
+ struct = MapKeyExample.new
95
+ struct.required_map = { SimpleStruct.new({ required_string: 'foo' }) => 'foo' }
96
+ struct.optional_map = { SimpleStruct.new => 'foo' }
97
+ refute_valid struct
98
+ end
99
+
100
+ def test_passess_when_valid_map_keys_are_given
101
+ struct = MapKeyExample.new
102
+ struct.required_map = { SimpleStruct.new({ required_string: 'foo' }) => 'foo' }
103
+ struct.optional_map = { SimpleStruct.new({ required_string: 'bar' }) => 'bar' }
104
+ assert_valid struct
105
+ end
106
+
107
+ def test_fails_if_nested_map_value_is_invalid
108
+ struct = MapValueExample.new
109
+ struct.required_map = { 'foo' => SimpleStruct.new }
110
+ refute_valid struct
111
+ end
112
+
113
+ def test_fails_if_optional_nested_map_value_is_invalid
114
+ struct = MapValueExample.new
115
+ struct.required_map = { 'foo' => SimpleStruct.new({ required_string: 'foo' }) }
116
+ struct.required_map = { 'foo' => SimpleStruct.new }
117
+ refute_valid struct
118
+ end
119
+
120
+ def test_passes_if_optional_and_required_valid_map_values_are_given
121
+ struct = MapValueExample.new
122
+ struct.required_map = { 'foo' => SimpleStruct.new({ required_string: 'foo' }) }
123
+ struct.optional_map = { 'foo' => SimpleStruct.new({ required_string: 'bar' }) }
124
+ assert_valid struct
125
+ end
126
+
127
+ def test_fails_if_no_union_fields_set
128
+ union = UnionExample.new
129
+ refute_valid union
130
+ end
131
+
132
+ def test_fails_if_union_set_field_is_invalid
133
+ union = UnionExample.new
134
+ union.primary = [SimpleStruct.new]
135
+ refute_valid union
136
+ end
137
+
138
+ def test_passes_if_union_set_field_is_valid
139
+ union = UnionExample.new
140
+ union.primary = [SimpleStruct.new(required_string: 'foo')]
141
+ assert_valid union
142
+ end
143
+
144
+ def test_passes_if_unions_alternate_value_is_provided
145
+ union = UnionExample.new
146
+ union.alternate = 'foo'
147
+ assert_valid union
148
+ end
149
+
150
+ private
151
+
152
+ def refute_valid(struct)
153
+ assert_raises Thrift::ProtocolException, 'Incorrect validation' do
154
+ Thrift::Validator.new.validate(struct)
155
+ end
156
+ end
157
+
158
+ def assert_valid(struct)
159
+ Thrift::Validator.new.validate(struct)
160
+ rescue Thrift::ProtocolException => ex
161
+ flunk ex
162
+ end
163
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ExceptionsTest < MiniTest::Unit::TestCase
4
+ def test_exception_message_contains_class_name
5
+ # The error is in NestedExample - required_struct is unset
6
+ struct = NestedExample.new required_struct: nil
7
+
8
+ ex = assert_raises Thrift::ProtocolException do
9
+ Thrift::Validator.new.validate(struct)
10
+ end
11
+ assert_match /NestedExample/, ex.message
12
+ end
13
+
14
+ def test_exception_message_contains_nested_class_name
15
+ # Here NestedExample is valid, but the error is one level down
16
+ # in SimpleStruct (its required_string is unset)
17
+ struct = NestedExample.new
18
+ struct.required_struct = SimpleStruct.new required_string: nil
19
+
20
+ ex = assert_raises Thrift::ProtocolException do
21
+ Thrift::Validator.new.validate(struct)
22
+ end
23
+ assert_match /SimpleStruct/, ex.message
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.2)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require 'test_types'
9
+
@@ -0,0 +1,185 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.9.2)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+
9
+ class SimpleStruct
10
+ include ::Thrift::Struct, ::Thrift::Struct_Union
11
+ REQUIRED_STRING = 1
12
+ OPTIONAL_STRING = 2
13
+
14
+ FIELDS = {
15
+ REQUIRED_STRING => {:type => ::Thrift::Types::STRING, :name => 'required_string'},
16
+ OPTIONAL_STRING => {:type => ::Thrift::Types::STRING, :name => 'optional_string', :optional => true}
17
+ }
18
+
19
+ def struct_fields; FIELDS; end
20
+
21
+ def validate
22
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field required_string is unset!') unless @required_string
23
+ end
24
+
25
+ ::Thrift::Struct.generate_accessors self
26
+ end
27
+
28
+ class NestedExample
29
+ include ::Thrift::Struct, ::Thrift::Struct_Union
30
+ REQUIRED_STRUCT = 1
31
+ OPTIONAL_STRUCT = 2
32
+
33
+ FIELDS = {
34
+ REQUIRED_STRUCT => {:type => ::Thrift::Types::STRUCT, :name => 'required_struct', :class => ::SimpleStruct},
35
+ OPTIONAL_STRUCT => {:type => ::Thrift::Types::STRUCT, :name => 'optional_struct', :class => ::SimpleStruct, :optional => true}
36
+ }
37
+
38
+ def struct_fields; FIELDS; end
39
+
40
+ def validate
41
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field required_struct is unset!') unless @required_struct
42
+ end
43
+
44
+ ::Thrift::Struct.generate_accessors self
45
+ end
46
+
47
+ class ListExample
48
+ include ::Thrift::Struct, ::Thrift::Struct_Union
49
+ REQUIRED_LIST = 1
50
+ OPTIONAL_LIST = 2
51
+
52
+ FIELDS = {
53
+ REQUIRED_LIST => {:type => ::Thrift::Types::LIST, :name => 'required_list', :element => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}},
54
+ OPTIONAL_LIST => {:type => ::Thrift::Types::LIST, :name => 'optional_list', :element => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}, :optional => true}
55
+ }
56
+
57
+ def struct_fields; FIELDS; end
58
+
59
+ def validate
60
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field required_list is unset!') unless @required_list
61
+ end
62
+
63
+ ::Thrift::Struct.generate_accessors self
64
+ end
65
+
66
+ class StringListExample
67
+ include ::Thrift::Struct, ::Thrift::Struct_Union
68
+ REQUIRED_LIST = 1
69
+
70
+ FIELDS = {
71
+ REQUIRED_LIST => {:type => ::Thrift::Types::LIST, :name => 'required_list', :element => {:type => ::Thrift::Types::STRING}}
72
+ }
73
+
74
+ def struct_fields; FIELDS; end
75
+
76
+ def validate
77
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field required_list is unset!') unless @required_list
78
+ end
79
+
80
+ ::Thrift::Struct.generate_accessors self
81
+ end
82
+
83
+ class StringSetExample
84
+ include ::Thrift::Struct, ::Thrift::Struct_Union
85
+ REQUIRED_SET = 1
86
+
87
+ FIELDS = {
88
+ REQUIRED_SET => {:type => ::Thrift::Types::SET, :name => 'required_set', :element => {:type => ::Thrift::Types::STRING}}
89
+ }
90
+
91
+ def struct_fields; FIELDS; end
92
+
93
+ def validate
94
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field required_set is unset!') unless @required_set
95
+ end
96
+
97
+ ::Thrift::Struct.generate_accessors self
98
+ end
99
+
100
+ class SetExample
101
+ include ::Thrift::Struct, ::Thrift::Struct_Union
102
+ REQUIRED_SET = 1
103
+ OPTIONAL_SET = 2
104
+
105
+ FIELDS = {
106
+ REQUIRED_SET => {:type => ::Thrift::Types::SET, :name => 'required_set', :element => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}},
107
+ OPTIONAL_SET => {:type => ::Thrift::Types::SET, :name => 'optional_set', :element => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}, :optional => true}
108
+ }
109
+
110
+ def struct_fields; FIELDS; end
111
+
112
+ def validate
113
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field required_set is unset!') unless @required_set
114
+ end
115
+
116
+ ::Thrift::Struct.generate_accessors self
117
+ end
118
+
119
+ class MapKeyExample
120
+ include ::Thrift::Struct, ::Thrift::Struct_Union
121
+ REQUIRED_MAP = 1
122
+ OPTIONAL_MAP = 2
123
+
124
+ FIELDS = {
125
+ REQUIRED_MAP => {:type => ::Thrift::Types::MAP, :name => 'required_map', :key => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}, :value => {:type => ::Thrift::Types::STRING}},
126
+ OPTIONAL_MAP => {:type => ::Thrift::Types::MAP, :name => 'optional_map', :key => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}, :value => {:type => ::Thrift::Types::STRING}, :optional => true}
127
+ }
128
+
129
+ def struct_fields; FIELDS; end
130
+
131
+ def validate
132
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field required_map is unset!') unless @required_map
133
+ end
134
+
135
+ ::Thrift::Struct.generate_accessors self
136
+ end
137
+
138
+ class MapValueExample
139
+ include ::Thrift::Struct, ::Thrift::Struct_Union
140
+ REQUIRED_MAP = 1
141
+ OPTIONAL_MAP = 2
142
+
143
+ FIELDS = {
144
+ REQUIRED_MAP => {:type => ::Thrift::Types::MAP, :name => 'required_map', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}},
145
+ OPTIONAL_MAP => {:type => ::Thrift::Types::MAP, :name => 'optional_map', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}, :optional => true}
146
+ }
147
+
148
+ def struct_fields; FIELDS; end
149
+
150
+ def validate
151
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field required_map is unset!') unless @required_map
152
+ end
153
+
154
+ ::Thrift::Struct.generate_accessors self
155
+ end
156
+
157
+ class UnionExample < ::Thrift::Union
158
+ include ::Thrift::Struct_Union
159
+ class << self
160
+ def primary(val)
161
+ UnionExample.new(:primary, val)
162
+ end
163
+
164
+ def alternate(val)
165
+ UnionExample.new(:alternate, val)
166
+ end
167
+ end
168
+
169
+ PRIMARY = 1
170
+ ALTERNATE = 2
171
+
172
+ FIELDS = {
173
+ PRIMARY => {:type => ::Thrift::Types::LIST, :name => 'primary', :element => {:type => ::Thrift::Types::STRUCT, :class => ::SimpleStruct}, :optional => true},
174
+ ALTERNATE => {:type => ::Thrift::Types::STRING, :name => 'alternate', :optional => true}
175
+ }
176
+
177
+ def struct_fields; FIELDS; end
178
+
179
+ def validate
180
+ raise(StandardError, 'Union fields are not set.') if get_set_field.nil? || get_value.nil?
181
+ end
182
+
183
+ ::Thrift::Union.generate_accessors self
184
+ end
185
+
@@ -0,0 +1,42 @@
1
+ struct SimpleStruct {
2
+ 1: required string required_string
3
+ 2: optional string optional_string
4
+ }
5
+
6
+ struct NestedExample {
7
+ 1: required SimpleStruct required_struct
8
+ 2: optional SimpleStruct optional_struct
9
+ }
10
+
11
+ struct ListExample {
12
+ 1: required list<SimpleStruct> required_list
13
+ 2: optional list<SimpleStruct> optional_list
14
+ }
15
+
16
+ struct StringListExample {
17
+ 1: required list<string> required_list
18
+ }
19
+
20
+ struct StringSetExample {
21
+ 1: required set<string> required_set
22
+ }
23
+
24
+ struct SetExample {
25
+ 1: required set<SimpleStruct> required_set
26
+ 2: optional set<SimpleStruct> optional_set
27
+ }
28
+
29
+ struct MapKeyExample {
30
+ 1: required map<SimpleStruct, string> required_map
31
+ 2: optional map<SimpleStruct, string> optional_map
32
+ }
33
+
34
+ struct MapValueExample {
35
+ 1: required map<string, SimpleStruct> required_map
36
+ 2: optional map<string, SimpleStruct> optional_map
37
+ }
38
+
39
+ union UnionExample {
40
+ 1: list<SimpleStruct> primary
41
+ 2: string alternate
42
+ }
@@ -0,0 +1,10 @@
1
+ require 'bundler/setup'
2
+
3
+ $LOAD_PATH << File.expand_path('../gen-rb', __FILE__)
4
+
5
+ require 'thrift-validator'
6
+
7
+ Thrift.type_checking = true
8
+
9
+ require 'test_types'
10
+ require 'minitest/autorun'
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'thrift/validator/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'anujdas-thrift-validator'
8
+ spec.version = Thrift::Validator::VERSION
9
+ spec.authors = ['ahawkins', 'anujdas']
10
+ spec.email = ['adam@hawkins.io', 'anujdas@gmail.com']
11
+ spec.summary = %q{Recursive thrift struct validator}
12
+ spec.description = %q{}
13
+ spec.homepage = 'https://github.com/anujdas/thrift-validator-ruby'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.test_files = spec.files.grep(%r{^test/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'thrift', '~> 0.9'
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.7'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'minitest', '~> 5.11'
25
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: anujdas-thrift-validator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - ahawkins
8
+ - anujdas
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2018-05-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thrift
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.9'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0.9'
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.7'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.7'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '10.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '10.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: minitest
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '5.11'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '5.11'
70
+ description: ''
71
+ email:
72
+ - adam@hawkins.io
73
+ - anujdas@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - lib/thrift-validator.rb
84
+ - lib/thrift/validator.rb
85
+ - lib/thrift/validator/version.rb
86
+ - test/acceptance_test.rb
87
+ - test/exceptions_test.rb
88
+ - test/gen-rb/test_constants.rb
89
+ - test/gen-rb/test_types.rb
90
+ - test/test.thrift
91
+ - test/test_helper.rb
92
+ - thrift-validator.gemspec
93
+ homepage: https://github.com/anujdas/thrift-validator-ruby
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.7.6
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Recursive thrift struct validator
117
+ test_files:
118
+ - test/acceptance_test.rb
119
+ - test/exceptions_test.rb
120
+ - test/gen-rb/test_constants.rb
121
+ - test/gen-rb/test_types.rb
122
+ - test/test.thrift
123
+ - test/test_helper.rb