service_contract 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 375af4c11c52d3fd5594769255fd23677ecc784f
4
- data.tar.gz: 73d98f54671f7a9fec7bd4878f2d38d6d6c33857
3
+ metadata.gz: cda29b086c0922a685bcf1c3ada63c6e5786dd21
4
+ data.tar.gz: d2471890764bdb42b78ab77107c748e8af0f1599
5
5
  SHA512:
6
- metadata.gz: 2b148df034846a5d796a85ea75a36e05f8400be7df0c2881199cca51a8c1ccc41c95c0511966993388da16ba64f84487b72083ff8e6129d05594aa115af5f240
7
- data.tar.gz: c82ee8d3f16eefcfd1c84187571a67e9f3724844432af64501c0906f6553dd81e755f9b159bc9097d0abf6e4a6b96d64e5b4d48795eb8bab3d1513f70858b367
6
+ metadata.gz: b55b44ca63fe651c4de836ed6b37c5bee7df090374e307bfcf86322a46df76c9e525161cbdab9f7be24417d9bb6676185932ba5b66d72d47b4ba7645cb3e79c4
7
+ data.tar.gz: 990b883ac9c8da2d8a230cd0c2ce53860b526392fc808ef54e221b7e6f86ddca14bfe44ccb3e2f269fb6b93f69dc7a032eda85929821463afdb1698d942da7b6
data/.travis.yml CHANGED
@@ -1,3 +1,9 @@
1
1
  env:
2
2
  global:
3
- - CODECLIMATE_REPO_TOKEN=2ca11363f82515a172ab992c3e4bacf032fc088c57a9907bcb2bcb9eaa71e344
3
+ - CODECLIMATE_REPO_TOKEN=2ca11363f82515a172ab992c3e4bacf032fc088c57a9907bcb2bcb9eaa71e344
4
+
5
+ rvm:
6
+ - 2.1.0
7
+ - 2.2.0
8
+
9
+ before_install: gem install bundler
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## 0.4.0
4
+
5
+ * add enum types
6
+ * refactor some internals for types
@@ -8,10 +8,6 @@ module ServiceContract
8
8
  raise :not_implemented
9
9
  end
10
10
 
11
- def subtype
12
- nil
13
- end
14
-
15
11
  def default
16
12
  nil
17
13
  end
@@ -20,4 +16,4 @@ module ServiceContract
20
16
  nil
21
17
  end
22
18
  end
23
- end
19
+ end
@@ -12,16 +12,20 @@ module ServiceContract
12
12
  []
13
13
  end
14
14
 
15
- def array?
16
- false
15
+ def valid_value?(value)
16
+ if valid_values.empty?
17
+ true
18
+ else
19
+ valid_values.include?(value)
20
+ end
17
21
  end
18
22
 
19
- def complex?
20
- false
23
+ def valid_values
24
+ []
21
25
  end
22
26
 
23
27
  def valid_ruby_types
24
28
  [Object]
25
29
  end
26
30
  end
27
- end
31
+ end
@@ -6,36 +6,37 @@ module ServiceContract
6
6
  end
7
7
 
8
8
  def assert_data_matches_type(data, type, allow_nil = true)
9
- if type.array?
10
- assert data.is_a?(Array), "expected #{type.name} to be an Array; instead got: #{data.inspect} (#{data.class.name})"
9
+ # Skip out if object is nil and allowed to be nil
10
+ return true if data.nil? && allow_nil
11
+
12
+ # basic type checking
13
+ assert type.valid_ruby_types.any?{|type| data.is_a?(type) }, "expected #{type.name} to be one of #{type.valid_ruby_types}"
14
+ assert type.valid_value?(data), "#{data} is not an allowed value of type: #{type.name}"
15
+
16
+ # check subtype
17
+ if type.subtype
11
18
  data.each do |datum|
12
19
  assert_data_matches_type(datum, type.subtype, allow_nil)
13
20
  end
14
- elsif type.complex?
15
- # Skip out of the complex object is nil and allowed to be nil
16
- return true if data.nil? && allow_nil
17
- # type should have fields
18
- type.fields.each do |field|
19
-
20
- #Does data contain attributes that the contract doesn't specify?
21
- data_extra_attrs = (data.keys.map(&:to_sym) - type.fields.map{|n| n.name.to_sym})
22
- assert_equal 0, data_extra_attrs.size, "#{type.name} contains attributes not described in contract: #{data_extra_attrs.join(',')}"
23
-
24
- # ensure the field is present
25
- value = data.fetch(field.name) do
26
- data.fetch(field.name.to_sym) do
27
- assert false, "expected #{type.name} to have attribute: #{field.name}"
28
- end
29
- end
21
+ end
30
22
 
31
- # check the data type
32
- assert_data_matches_type(value, field.type, allow_nil)
23
+ # check subfields
24
+ type.fields.each do |field|
25
+ #Does data contain attributes that the contract doesn't specify?
26
+ data_extra_attrs = (data.keys.map(&:to_sym) - type.fields.map{|n| n.name.to_sym})
27
+ assert_equal 0, data_extra_attrs.size, "#{type.name} contains attributes not described in contract: #{data_extra_attrs.join(',')}"
28
+
29
+ # ensure the field is present
30
+ value = data.fetch(field.name) do
31
+ data.fetch(field.name.to_sym) do
32
+ assert false, "expected #{type.name} to have attribute: #{field.name}"
33
+ end
33
34
  end
34
- else
35
- # type is a scalar
36
- assert (allow_nil && data.nil?) || type.valid_ruby_types.any?{|klass| data.is_a?(klass)}, "expected scalar type #{type.inspect} or nil; instead got: #{data.inspect} (#{data.class.name})"
35
+
36
+ # check the data type
37
+ assert_data_matches_type(value, field.type, allow_nil)
37
38
  end
38
39
  end
39
40
 
40
41
  end
41
- end
42
+ end
@@ -62,8 +62,8 @@ module ServiceContract
62
62
  return false if parameters.empty?
63
63
 
64
64
  first_param_type = parameters.first.type
65
- first_param_type.complex? && first_param_type.name == protocol.main_type
65
+ first_param_type.is_a?(RecordType) && first_param_type.name == protocol.main_type
66
66
  end
67
67
  end
68
68
  end
69
- end
69
+ end
@@ -9,12 +9,6 @@ module ServiceContract
9
9
  Type.build(definition.type)
10
10
  end
11
11
 
12
- def subtype
13
- definition.array? ?
14
- definition.type.items :
15
- nil
16
- end
17
-
18
12
  def default
19
13
  definition.default
20
14
  end
@@ -24,4 +18,4 @@ module ServiceContract
24
18
  end
25
19
  end
26
20
  end
27
- end
21
+ end
@@ -13,7 +13,7 @@ module ServiceContract
13
13
 
14
14
  def types
15
15
  avro.types.map do |type|
16
- Type.new(type)
16
+ Type.build(type)
17
17
  end
18
18
  end
19
19
 
@@ -41,4 +41,4 @@ module ServiceContract
41
41
  end
42
42
  end
43
43
  end
44
- end
44
+ end
@@ -1,12 +1,8 @@
1
1
  module ServiceContract
2
2
  module Avro
3
- class Type < AbstractType
3
+ class RecordType < AbstractType
4
4
  def name
5
- array? ?
6
- "Array(#{subtype.name})" :
7
- complex? ?
8
- definition.name :
9
- definition.type.to_s
5
+ definition.name
10
6
  end
11
7
 
12
8
  def fields
@@ -15,66 +11,140 @@ module ServiceContract
15
11
  end
16
12
  end
17
13
 
18
- def to_s
19
- return name unless union?
20
-
21
- union_types.map(&:name).join(", ")
14
+ def valid_ruby_types
15
+ [Hash]
16
+ end
17
+ end
18
+
19
+ class ArrayType < AbstractType
20
+ def name
21
+ "Array(#{subtype.name})"
22
22
  end
23
23
 
24
24
  def subtype
25
- return nil unless definition.respond_to?(:items)
26
25
  Type.build(definition.items)
27
26
  end
28
27
 
29
- def array?
30
- type_string == "array"
28
+ def valid_ruby_types
29
+ [Array]
31
30
  end
31
+ end
32
32
 
33
- def self.build(definition)
34
- Type.new(definition)
33
+ class UnionType < AbstractType
34
+ def name
35
+ "Union(#{union_types.map(&:name).join(", ")})"
35
36
  end
36
37
 
37
- def complex?
38
- type_string == "record"
38
+ def valid_ruby_types
39
+ union_types.map(&:valid_ruby_types).flatten
39
40
  end
40
41
 
41
- def union?
42
- type_string == "union"
42
+ protected
43
+
44
+ def union_types
45
+ definition.schemas.map{|schema| Type.build(schema)}
46
+ end
47
+ end
48
+
49
+ class EnumType < AbstractType
50
+ def name
51
+ "Enum(#{definition.name})"
43
52
  end
44
53
 
45
54
  def valid_ruby_types
46
- case type_string
47
- when "array"
48
- [Array]
49
- when "int"
50
- [Fixnum]
51
- when "string"
52
- [String]
53
- when "float"
54
- [Float]
55
- when "boolean"
56
- [TrueClass, FalseClass]
57
- when "null"
58
- [NilClass]
59
- when "union"
60
- union_types.map(&:valid_ruby_types).flatten
61
- else # a complex type
62
- [Hash]
63
- end
55
+ [String]
64
56
  end
65
57
 
66
- protected
58
+ def valid_values
59
+ definition.symbols.map{|str| str.to_s.downcase}
60
+ end
61
+ end
67
62
 
68
- def union_types
69
- definition.schemas.map{|schema| Type.build(schema)}
63
+ class StringType < AbstractType
64
+ def name
65
+ "string"
66
+ end
67
+
68
+ def valid_ruby_types
69
+ [String]
70
+ end
71
+ end
72
+
73
+ class IntegerType < AbstractType
74
+ def name
75
+ "int"
76
+ end
77
+
78
+ def valid_ruby_types
79
+ [Fixnum]
70
80
  end
81
+ end
71
82
 
72
- def type_string
73
- type = definition.type
74
- type = type.type_sym.to_s if type.respond_to?(:type_sym)
75
- type
83
+ class FloatType < AbstractType
84
+ def name
85
+ "float"
76
86
  end
77
87
 
88
+ def valid_ruby_types
89
+ [Float]
90
+ end
91
+ end
92
+
93
+ class BooleanType < AbstractType
94
+ def name
95
+ "boolean"
96
+ end
97
+
98
+ def valid_ruby_types
99
+ [TrueClass, FalseClass]
100
+ end
101
+ end
102
+
103
+ class NullType < AbstractType
104
+ def name
105
+ "null"
106
+ end
107
+ alias :to_s :name
108
+
109
+ def valid_ruby_types
110
+ [NilClass]
111
+ end
112
+ end
113
+
114
+ class Type
115
+ class << self
116
+ def build(definition)
117
+ type = type_string(definition)
118
+ case type
119
+ when "array"
120
+ ArrayType.new(definition)
121
+ when "record"
122
+ RecordType.new(definition)
123
+ when "union"
124
+ UnionType.new(definition)
125
+ when "enum"
126
+ EnumType.new(definition)
127
+ when "string"
128
+ StringType.new
129
+ when "int"
130
+ IntegerType.new
131
+ when "float"
132
+ FloatType.new
133
+ when "boolean"
134
+ BooleanType.new
135
+ when "null"
136
+ NullType.new
137
+ else
138
+ raise "unknown type: #{type}"
139
+ end
140
+ end
141
+
142
+ def type_string(definition)
143
+ type_string = definition.type
144
+ type_string = type_string.type_sym.to_s if type_string.respond_to?(:type_sym)
145
+ type_string
146
+ end
147
+ end
78
148
  end
79
149
  end
80
- end
150
+ end
@@ -25,12 +25,12 @@ a href=to(version.version)
25
25
  ul
26
26
  - endpoint.parameters.each do |parameter|
27
27
  li
28
- => parameter.type
28
+ => parameter.type.name
29
29
  = parameter.name
30
30
 
31
31
  h4 Response
32
32
  p
33
- = endpoint.response_type
33
+ = endpoint.response_type.name
34
34
 
35
35
  .col-md-4
36
36
  h2 Types
@@ -44,13 +44,16 @@ a href=to(version.version)
44
44
  = type.name
45
45
  .panel-collapse.collapse.in id="collapse#{type.name}"
46
46
  .panel-body
47
+ - type.valid_values.each do |value|
48
+ p = value
47
49
  - type.fields.each do |field|
48
50
  p
49
- a.pull-right data-toggle="collapse" href="#collapseDescription#{type.name}#{field.name}"
51
+ - if field.doc
52
+ a.pull-right data-toggle="collapse" href="#collapseDescription#{type.name}#{field.name}"
50
53
  i.glyphicon.glyphicon-info-sign
51
- => field.type
54
+ => field.type.name
52
55
  | -
53
56
  =< field.name
54
57
  - if field.doc
55
58
  p.collapse id="collapseDescription#{type.name}#{field.name}"
56
- em = field.doc
59
+ em = field.doc
@@ -33,11 +33,11 @@ module ServiceContract
33
33
  end
34
34
 
35
35
  def mock_value(field)
36
- if field.array?
36
+ if field.subtype
37
37
  Array.new(3) do
38
38
  mock_value(field.subtype)
39
39
  end
40
- elsif field.complex?
40
+ elsif !field.fields.empty?
41
41
  # recursively mock values
42
42
  mock_fields(field)
43
43
  else
@@ -51,8 +51,8 @@ module ServiceContract
51
51
  when "boolean", :boolean
52
52
  [true, false].sample
53
53
  end
54
- end
54
+ end
55
55
  end
56
56
  end
57
57
  end
58
- end
58
+ end
@@ -1,3 +1,3 @@
1
1
  module ServiceContract
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -78,4 +78,33 @@ class AssertionsTest < Minitest::Test
78
78
 
79
79
  end
80
80
 
81
- end
81
+ def test_enum_values
82
+ service = SampleService.find(2)
83
+ assert service, "expect to find a service by version"
84
+
85
+ protocol = service.protocol("social_login")
86
+ endpoint = protocol.endpoint("index")
87
+
88
+ data = [
89
+ {token: "sometoken", provider: "facebook"},
90
+ {token: "anothertoken", provider: "linkedin"}
91
+ ]
92
+
93
+ assert_endpoint_response(data, endpoint)
94
+
95
+ # test can be nil
96
+ bad_data = [
97
+ {token: "sometoken", provider: "bad provider"}
98
+ ]
99
+ failure_data = nil
100
+ begin
101
+ assert_endpoint_response(bad_data, endpoint)
102
+ rescue Minitest::Assertion => failure
103
+ failure_data = failure
104
+ end
105
+
106
+ assert !failure_data.nil?
107
+ assert failure_data.to_s.include?("is not an allowed value"), failure_data
108
+ end
109
+
110
+ end
@@ -0,0 +1,28 @@
1
+ {
2
+ "protocol" : "SocialLogin",
3
+ "namespace" : "Gnomon",
4
+ "types" : [ {
5
+ "type" : "enum",
6
+ "name" : "SocialNetwork",
7
+ "symbols" : [ "FACEBOOK", "GOOGLE", "TWITTER", "LINKEDIN" ]
8
+ }, {
9
+ "type" : "record",
10
+ "name" : "Authorization",
11
+ "fields" : [ {
12
+ "name" : "token",
13
+ "type" : "string"
14
+ }, {
15
+ "name" : "provider",
16
+ "type" : "SocialNetwork"
17
+ } ]
18
+ } ],
19
+ "messages" : {
20
+ "index" : {
21
+ "request" : [ ],
22
+ "response" : {
23
+ "type" : "array",
24
+ "items" : "Authorization"
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,16 @@
1
+ @namespace("Gnomon")
2
+
3
+ protocol SocialLogin {
4
+
5
+ enum SocialNetwork {
6
+ FACEBOOK, GOOGLE, TWITTER, LINKEDIN
7
+ }
8
+
9
+ record Authorization {
10
+ string token;
11
+
12
+ SocialNetwork provider;
13
+ }
14
+
15
+ array<Authorization> index();
16
+ }
data/test/service_test.rb CHANGED
@@ -68,9 +68,22 @@ class ServiceTest < Minitest::Test
68
68
 
69
69
  field_type = field.type
70
70
 
71
- assert_equal('union', field_type.name)
72
- assert_equal('null, int, Array(int)', field_type.to_s)
71
+ assert_equal('Union(null, int, Array(int))', field_type.name)
73
72
  assert_equal([NilClass, Fixnum, Array], field_type.valid_ruby_types)
74
73
  end
75
74
 
76
- end
75
+ def test_enum_types
76
+ service = SampleService.find(2)
77
+ protocol = service.protocol('social_login')
78
+ type = protocol.type('Authorization')
79
+
80
+ field = type.fields.detect{|field| field.name == 'provider'}
81
+ assert(field, 'expected to find a provider field')
82
+
83
+ field_type = field.type
84
+
85
+ assert_equal('Enum(SocialNetwork)', field_type.name)
86
+ assert_equal([String], field_type.valid_ruby_types)
87
+ end
88
+
89
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: service_contract
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Ching
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-08 00:00:00.000000000 Z
11
+ date: 2016-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro
@@ -89,13 +89,13 @@ extra_rdoc_files: []
89
89
  files:
90
90
  - ".gitignore"
91
91
  - ".travis.yml"
92
+ - CHANGELOG.md
92
93
  - Gemfile
93
94
  - LICENSE.txt
94
95
  - README.md
95
96
  - Rakefile
96
97
  - lib/service_contract.rb
97
98
  - lib/service_contract/abstract_endpoint.rb
98
- - lib/service_contract/abstract_field.rb
99
99
  - lib/service_contract/abstract_parameter.rb
100
100
  - lib/service_contract/abstract_protocol.rb
101
101
  - lib/service_contract/abstract_service.rb
@@ -127,7 +127,9 @@ files:
127
127
  - test/sample/1/source/location.avdl
128
128
  - test/sample/1/source/sales_region.avdl
129
129
  - test/sample/2/compiled/search_param.avpr
130
+ - test/sample/2/compiled/social_login.avpr
130
131
  - test/sample/2/source/search_param.avdl
132
+ - test/sample/2/source/social_login.avdl
131
133
  - test/service_test.rb
132
134
  - test/test_helper.rb
133
135
  homepage: ''
@@ -164,6 +166,9 @@ test_files:
164
166
  - test/sample/1/source/location.avdl
165
167
  - test/sample/1/source/sales_region.avdl
166
168
  - test/sample/2/compiled/search_param.avpr
169
+ - test/sample/2/compiled/social_login.avpr
167
170
  - test/sample/2/source/search_param.avdl
171
+ - test/sample/2/source/social_login.avdl
168
172
  - test/service_test.rb
169
173
  - test/test_helper.rb
174
+ has_rdoc:
@@ -1,3 +0,0 @@
1
- module ServiceContract
2
- AbstractField = Struct.new(:type, :name)
3
- end