service_contract 0.3.0 → 0.4.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.
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