rat_pack_swagger 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.
@@ -0,0 +1,52 @@
1
+ class SwaggerObject
2
+ instance_methods.each do |m|
3
+ unless m =~ /^__/ || [:inspect, :instance_eval, :object_id].include?(m)
4
+ undef_method m
5
+ end
6
+ end
7
+
8
+ def initialize(*args, **kwargs, &block)
9
+ if args.count > 0 && (!kwargs.empty? || block_given?)
10
+ raise "Cannot give both unnamed arguments AND named arguments or block to Swagger parameter '#{m}'."
11
+ elsif block_given?
12
+ @obj = kwargs unless kwargs.empty?
13
+ instance_eval &block
14
+ elsif !kwargs.empty?
15
+ @obj = kwargs
16
+ elsif args.count > 0
17
+ @obj = [*args]
18
+ else
19
+ raise "Cannot create SwaggerObject with no arguments."
20
+ end
21
+ end
22
+
23
+ def add(*args, **kwargs)
24
+ @obj ||= []
25
+ if !@obj.is_a?(Array)
26
+ raise "Swagger object must be an array to append data '#{item}'"
27
+ elsif args.count > 0
28
+ @obj << [*args, kwargs]
29
+ else
30
+ @obj << kwargs
31
+ end
32
+ end
33
+
34
+ def method_missing(m, *args, **kwargs, &block)
35
+ @obj ||= {}
36
+ if block_given?
37
+ @obj[m] = SwaggerObject.new(**kwargs, &block).to_h
38
+ elsif !kwargs.empty?
39
+ @obj[m] = SwaggerObject.new(**kwargs).to_h
40
+ elsif args.count > 1
41
+ @obj[m] = [*args]
42
+ elsif args.count == 1
43
+ @obj[m] = args[0]
44
+ else
45
+ raise "Cannot give zero arguments to Swagger key '#{m}'"
46
+ end
47
+ end
48
+
49
+ def to_h
50
+ @obj
51
+ end
52
+ end
@@ -0,0 +1,172 @@
1
+ require 'json'
2
+
3
+ module RatPackSwagger
4
+ module SwaggerType
5
+ def to_h
6
+ h = {}
7
+ getters = methods.select{|m| m =~ /\w+=$/}.map{|m| m.to_s.chop}
8
+ getters.each do |getter|
9
+ val = send(getter)
10
+ next if [nil, [], {}].include?(val)
11
+ val = val.to_h if val.is_a?(SwaggerType)
12
+ h[getter.to_sym] = val
13
+ end
14
+ return h
15
+ end
16
+ end
17
+
18
+ class SwaggerPathItem
19
+ include SwaggerType
20
+ attr_accessor :get, :put, :post, :delete, :options, :head, :patch
21
+ end
22
+
23
+ class SwaggerOperation
24
+ include SwaggerType
25
+ attr_accessor :tags, :summary, :description,
26
+ :externalDocs, :consumes, :produces, :parameters, :responses,
27
+ :schemes, :deprecated, :security
28
+ def initialize
29
+ @tags = []
30
+ @consumes = []
31
+ @parameters = []
32
+ @responses = {}
33
+ @schemes = []
34
+ @security = []
35
+ end
36
+ end
37
+
38
+ class SwaggerSpec
39
+ attr_accessor :swagger_schema, :spec, :this_route
40
+
41
+ def initialize
42
+ @spec = {
43
+ paths: {}
44
+ }
45
+ @spec_cache_invalid = true
46
+ @spec_cache = {
47
+ api_spec: nil, # the data returned byt /v2/swagger.json
48
+ api_spec_json: nil, # api_spec as json string
49
+ resolved_spec: nil, # a hash where all json pointers are resolved
50
+ # for request/response validation, because json-schema sucks at pointers
51
+ }
52
+ @swagger_schema = ::JSON.parse(File.read(File.join(File.dirname(__FILE__), 'swagger_json_schema.json')))
53
+ @this_route = SwaggerOperation.new
54
+ end
55
+
56
+ def route_consumes?(path, verb, mime)
57
+ route = @spec[:paths][path][verb]
58
+ return true if route[:consumes] && route[:consumes].include?(mime)
59
+ return true if @spec[:consumes].include?(mime)
60
+ return false
61
+ end
62
+
63
+ def register_this_route(path, verb)
64
+ verb.downcase!
65
+ paths = @spec[:paths]
66
+ paths[path] ||= {}
67
+ paths[path][verb] = @this_route.to_h
68
+ @this_route = SwaggerOperation.new
69
+ @spec_cache_invalid = true
70
+ end
71
+
72
+ def add_definitions(*constants)
73
+ @spec[:definitions] ||= {}
74
+ constants.each do |constant|
75
+ if constant.is_a?(Module)
76
+ constant.constants.each do |c|
77
+ klass = constant.const_get(c)
78
+ if klass.is_a?(Class) && klass.ancestors.include?(Definition)
79
+ @spec[:definitions][c] = klass.definition
80
+ end
81
+ end
82
+ else
83
+ if constant.is_a?(Class) && constant.ancestors.include?(Definition)
84
+ @@doc[:definitions][constant.to_s.rpartition('::').last] = constant.definition
85
+ end
86
+ end
87
+ end
88
+ @spec_cache_invalid = true
89
+ end
90
+
91
+ def resolved_spec
92
+ update_spec_cache if @spec_cache_invalid
93
+ @spec_cache[:resolved_spec]
94
+ end
95
+ def api_spec
96
+ update_spec_cache if @spec_cache_invalid
97
+ @spec_cache[:api_spec]
98
+ end
99
+ def api_spec_json
100
+ update_spec_cache if @spec_cache_invalid
101
+ @spec_cache[:api_spec_json]
102
+ end
103
+
104
+ private
105
+
106
+ def update_spec_cache
107
+ cache_resolved_spec
108
+ cache_api_spec
109
+ @spec_cache[:api_spec_json] = @spec_cache[:api_spec].to_json
110
+ @spec_cache_invalid = false
111
+ end
112
+
113
+ def cache_resolved_spec
114
+ resolved_spec = make_deep_copy(@spec)
115
+ map_hash_values!(resolved_spec) do |k,v|
116
+ new_v = v
117
+ if v.is_a?(Hash) && v[:$ref]
118
+ if v[:$ref].respond_to?(:to_h)
119
+ new_v = v[:$ref].to_h
120
+ end
121
+ end
122
+ new_v
123
+ end
124
+ @spec_cache[:resolved_spec] = resolved_spec
125
+ end
126
+
127
+ def cache_api_spec
128
+ api_spec = make_deep_copy(@spec)
129
+ map_hash_values!(api_spec) do |k,v|
130
+ new_v = v
131
+ if k.to_s == '$ref'
132
+ if v.is_a?(Class)
133
+ classname = v.to_s.rpartition('::').last
134
+ if v.ancestors.include?(Definition)
135
+ new_v = "#/definitions/#{classname}"
136
+ end
137
+ # TODO: Add other types like Parameters"
138
+ end
139
+ end
140
+ new_v
141
+ end
142
+ @spec_cache[:api_spec] = api_spec
143
+ end
144
+
145
+ def make_deep_copy(arg)
146
+ Marshal.load(Marshal.dump(arg))
147
+ end
148
+
149
+ def map_hash_values!(obj, &block)
150
+ if obj.is_a? Hash
151
+ obj.each do |k,v|
152
+ # perform mapping first, THEN if result is hash/array, go recursive
153
+ obj[k] = yield(k,v)
154
+ if obj[k].is_a?(Hash) || obj[k].is_a?(Array)
155
+ obj[k] = map_hash_values!(obj[k], &block)
156
+ end
157
+ end
158
+ elsif obj.is_a? Array
159
+ obj.each_with_index do |e,i|
160
+ if e.is_a?(Hash) || e.is_a?(Array)
161
+ obj[i] = map_hash_values!(e, &block)
162
+ end
163
+ end
164
+ else
165
+ raise "Argument must be a Hash or an Array."
166
+ end
167
+ return obj
168
+ end
169
+
170
+ end
171
+ end
172
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rat_pack_swagger
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
  - Chris Hildebrand
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-07-15 00:00:00.000000000 Z
12
+ date: 2015-07-20 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json-schema
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2.5'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.5'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: sinatra
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -36,6 +50,10 @@ files:
36
50
  - README.md
37
51
  - lib/rat_pack_swagger.rb
38
52
  - lib/rat_pack_swagger/version.rb
53
+ - lib/request_validators.rb
54
+ - lib/swagger_json_schema.json
55
+ - lib/swagger_object.rb
56
+ - lib/swagger_spec.rb
39
57
  homepage: https://github.com/ckhrysze/rat_pack_swagger
40
58
  licenses:
41
59
  - MIT