Skip to content

Commit 8d4836b

Browse files
committed
released v0.11.0
1 parent 3ab6b13 commit 8d4836b

10 files changed

Lines changed: 1063 additions & 1030 deletions

lib/open_api_import.rb

Lines changed: 10 additions & 1027 deletions
Large diffs are not rendered by default.

lib/open_api_import/filter.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module LibOpenApiImport
2+
#filter hash
3+
def filter(hash, keys, nested = false)
4+
result = {}
5+
keys = [keys] unless keys.is_a?(Array)
6+
if nested
7+
result = hash.nice_filter(keys)
8+
else
9+
#to be backwards compatible
10+
keys.each do |k|
11+
if k.is_a?(Symbol) and hash.key?(k)
12+
if hash[k].is_a?(Hash)
13+
result[k] = {}
14+
else
15+
result[k] = hash[k]
16+
end
17+
elsif k.is_a?(Symbol) and k.to_s.include?(".") and hash.key?((k.to_s.scan(/(\w+)\./).join).to_sym) #nested 'uno.dos.tres
18+
kn = k.to_s.split(".")
19+
vn = kn[1].to_sym
20+
result[kn.first.to_sym][vn] = filter(hash[kn.first.to_sym], vn).values[0]
21+
elsif k.is_a?(Hash) and hash.key?(k.keys[0]) #nested {uno: {dos: :tres}}
22+
result[k.keys[0]][k.values[0]] = filter(hash[k.keys[0]], k.values[0]).values[0]
23+
end
24+
end
25+
end
26+
return result
27+
end
28+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module LibOpenApiImport
2+
private def get_data_all_of_bodies(p)
3+
bodies = []
4+
data_examples_all_of = false
5+
if p.is_a?(Array)
6+
q = p
7+
elsif p.key?(:schema) and p[:schema].key?(:allOf)
8+
q = p[:schema][:allOf]
9+
else
10+
q = [p]
11+
end
12+
q.each do |pt|
13+
if pt.is_a?(Hash) and pt.key?(:allOf)
14+
bodies += get_data_all_of_bodies(pt[:allOf])[1]
15+
data_examples_all_of = true
16+
else
17+
bodies << pt
18+
end
19+
end
20+
return data_examples_all_of, bodies
21+
end
22+
end
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
module LibOpenApiImport
2+
# Retrieve the examples from the properties hash
3+
private def get_examples(properties, type = :key_value, remove_readonly = false)
4+
#todo: consider using this method also to get data examples
5+
example = []
6+
example << "{" unless properties.empty? or type == :only_value
7+
properties.each do |prop, val|
8+
unless remove_readonly and val.key?(:readOnly) and val[:readOnly] == true
9+
if val.key?(:properties) and !val.key?(:example) and !val.key?(:type)
10+
val[:type] = "object"
11+
end
12+
if val.key?(:items) and !val.key?(:example) and !val.key?(:type)
13+
val[:type] = "array"
14+
end
15+
if val.key?(:example)
16+
if val[:example].is_a?(Array) and val.key?(:type) and val[:type] == "string"
17+
example << " #{prop.to_sym}: \"#{val[:example][0]}\", " # only the first example
18+
else
19+
if val[:example].is_a?(String)
20+
val[:example].gsub!('"', "'")
21+
example << " #{prop.to_sym}: \"#{val[:example]}\", "
22+
elsif val[:example].is_a?(Time)
23+
example << " #{prop.to_sym}: \"#{val[:example]}\", "
24+
else
25+
example << " #{prop.to_sym}: #{val[:example]}, "
26+
end
27+
end
28+
elsif val.key?(:type)
29+
format = val[:format]
30+
format = val[:type] if format.to_s == ""
31+
case val[:type].downcase
32+
when "string"
33+
example << " #{prop.to_sym}: \"#{format}\", "
34+
when "integer", "number"
35+
example << " #{prop.to_sym}: 0, "
36+
when "boolean"
37+
example << " #{prop.to_sym}: true, "
38+
when "array"
39+
if val.key?(:items) and val[:items].size == 1 and val[:items].is_a?(Hash) and val[:items].key?(:type)
40+
val[:items][:enum] = [val[:items][:type]]
41+
end
42+
43+
if val.key?(:items) and val[:items].key?(:enum)
44+
#before we were getting in all these cases a random value from the enum, now we are getting the first position by default
45+
#the reason is to avoid confusion later in case we want to compare two swaggers and verify the changes
46+
if type == :only_value
47+
if val[:items][:enum][0].is_a?(String)
48+
example << " [\"" + val[:items][:enum][0] + "\"] "
49+
else
50+
example << " [" + val[:items][:enum][0] + "] "
51+
end
52+
else
53+
if val[:items][:enum][0].is_a?(String)
54+
example << " #{prop.to_sym}: [\"" + val[:items][:enum][0] + "\"], "
55+
else
56+
example << " #{prop.to_sym}: [" + val[:items][:enum][0] + "], "
57+
end
58+
end
59+
else
60+
#todo: differ between response examples and data examples
61+
examplet = get_response_examples({ schema: val }, remove_readonly).join("\n")
62+
examplet = '[]' if examplet.empty?
63+
if type == :only_value
64+
example << examplet
65+
else
66+
example << " #{prop.to_sym}: " + examplet + ", "
67+
end
68+
69+
end
70+
when "object"
71+
#todo: differ between response examples and data examples
72+
res_ex = get_response_examples({ schema: val }, remove_readonly)
73+
if res_ex.size == 0
74+
res_ex = "{ }"
75+
else
76+
res_ex = res_ex.join("\n")
77+
end
78+
example << " #{prop.to_sym}: " + res_ex + ", "
79+
else
80+
example << " #{prop.to_sym}: \"#{format}\", "
81+
end
82+
end
83+
end
84+
end
85+
example << "}" unless properties.empty? or type == :only_value
86+
example
87+
end
88+
end
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
module LibOpenApiImport
2+
# Get patterns
3+
private def get_patterns(dpk, dpv)
4+
data_pattern = []
5+
if dpv.keys.include?(:pattern)
6+
#todo: control better the cases with back slashes
7+
if dpv[:pattern].include?('\\\\/')
8+
#for cases like this: ^[^\.\\/:*?"<>|][^\\/:*?"<>|]{0,13}[^\.\\/:*?"<>|]?$
9+
data_pattern << "'#{dpk}': /#{dpv[:pattern].to_s.gsub('\/', "/")}/"
10+
elsif dpv[:pattern].include?('\\x')
11+
data_pattern << "'#{dpk}': /#{dpv[:pattern].to_s.gsub('\\x', '\\u')}/"
12+
else
13+
data_pattern << "'#{dpk}': /#{dpv[:pattern].to_s}/"
14+
end
15+
elsif dpv.key?(:minLength) and dpv.key?(:maxLength)
16+
data_pattern << "'#{dpk}': :'#{dpv[:minLength]}-#{dpv[:maxLength]}:LN$'"
17+
elsif dpv.key?(:minLength) and !dpv.key?(:maxLength)
18+
data_pattern << "'#{dpk}': :'#{dpv[:minLength]}:LN$'"
19+
elsif !dpv.key?(:minLength) and dpv.key?(:maxLength)
20+
data_pattern << "'#{dpk}': :'0-#{dpv[:maxLength]}:LN$'"
21+
elsif dpv.key?(:minimum) and dpv.key?(:maximum) and dpv[:type] == "string"
22+
data_pattern << "'#{dpk}': :'#{dpv[:minimum]}-#{dpv[:maximum]}:LN$'"
23+
elsif dpv.key?(:minimum) and dpv.key?(:maximum)
24+
data_pattern << "'#{dpk}': #{dpv[:minimum]}..#{dpv[:maximum]}"
25+
elsif dpv.key?(:minimum) and !dpv.key?(:maximum)
26+
if RUBY_VERSION >= "2.6.0"
27+
data_pattern << "'#{dpk}': #{dpv[:minimum]}.. "
28+
else
29+
data_pattern << "#'#{dpk}': #{dpv[:minimum]}.. # INFINITE only working on ruby>=2.6.0"
30+
end
31+
elsif !dpv.key?(:minimum) and dpv.key?(:maximum)
32+
data_pattern << "'#{dpk}': 0..#{dpv[:maximum]}"
33+
elsif dpv[:format] == "date-time"
34+
data_pattern << "'#{dpk}': DateTime"
35+
elsif dpv[:type] == "boolean"
36+
data_pattern << "'#{dpk}': Boolean"
37+
elsif dpv.key?(:enum)
38+
data_pattern << "'#{dpk}': :'#{dpv[:enum].join("|")}'"
39+
elsif dpv[:type] == "array" and dpv.key?(:items) and dpv[:items].is_a?(Hash) and dpv[:items].key?(:enum) and dpv[:items][:enum].is_a?(Array)
40+
#{:title=>"Balala", :type=>"array", :items=>{:type=>"string", :enum=>["uno","dos"], :example=>"uno"}}
41+
data_pattern << "'#{dpk}': [:'#{dpv[:items][:enum].join("|")}']"
42+
elsif dpv[:type] == "array" and dpv.key?(:items) and dpv[:items].is_a?(Hash) and !dpv[:items].key?(:enum) and dpv[:items].key?(:properties)
43+
#{:title=>"Balala", :type=>"array", :items=>{title: 'xxxx, properties: {server: {enum:['ibm','msa','pytan']}}}
44+
dpv[:items][:properties].each do |dpkk, dpvv|
45+
if dpk == ""
46+
data_pattern += get_patterns("#{dpkk}", dpvv)
47+
else
48+
data_pattern += get_patterns("#{dpk}.#{dpkk}", dpvv)
49+
end
50+
end
51+
elsif dpv[:type] == "array" and dpv.key?(:items) and dpv[:items].is_a?(Hash) and
52+
!dpv[:items].key?(:enum) and !dpv[:items].key?(:properties) and dpv[:items].key?(:type)
53+
#{:title=>"labels", :description=>"Labels specified for the file system", :type=>"array", :items=>{:type=>"string", :enum=>["string"]}}
54+
data_pattern << "'#{dpk}': [ #{get_patterns("", dpv[:items]).join[4..-1]} ]"
55+
elsif dpv[:type] == "object" and dpv.key?(:properties)
56+
dpv[:properties].each do |dpkk, dpvv|
57+
if dpk == ""
58+
data_pattern += get_patterns("#{dpkk}", dpvv)
59+
else
60+
data_pattern += get_patterns("#{dpk}.#{dpkk}", dpvv)
61+
end
62+
end
63+
end
64+
data_pattern.uniq!
65+
return data_pattern
66+
end
67+
end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module LibOpenApiImport
2+
# Get required data
3+
private def get_required_data(body)
4+
data_required = []
5+
if body.keys.include?(:required) and body[:required].size > 0
6+
body[:required].each do |r|
7+
data_required << r.to_sym
8+
end
9+
end
10+
if body.key?(:allOf)
11+
body[:allOf].each do |r|
12+
if r.key?(:required)
13+
r[:required].each do |r2|
14+
data_required << r2.to_sym
15+
end
16+
end
17+
end
18+
end
19+
data_required.each do |key|
20+
if body.key?(:properties) and body[:properties][key].is_a?(Hash) and
21+
body[:properties][key].key?(:required) and body[:properties][key][:required].size > 0
22+
dr = get_required_data(body[:properties][key])
23+
dr.each do |k|
24+
data_required.push("#{key}.#{k}".to_sym)
25+
end
26+
end
27+
end
28+
return data_required
29+
end
30+
end
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
module LibOpenApiImport
2+
# Retrieve the response examples from the hash
3+
private def get_response_examples(v, remove_readonly = false)
4+
# TODO: take in consideration the case allOf, oneOf... schema.items.allOf[0].properties schema.items.allOf[1].properties
5+
# example on https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v2.0/yaml/petstore-expanded.yaml
6+
v = v.dup
7+
response_example = Array.new()
8+
# for open api 3.0 with responses schema inside content
9+
if v.key?(:content) && v[:content].is_a?(Hash) && v[:content].key?(:'application/json') &&
10+
v[:content][:'application/json'].key?(:schema)
11+
v = v[:content][:'application/json'].dup
12+
end
13+
if v.key?(:examples) && v[:examples].is_a?(Hash) && v[:examples].key?(:'application/json')
14+
if v[:examples][:'application/json'].is_a?(String)
15+
response_example << v[:examples][:'application/json']
16+
elsif v[:examples][:'application/json'].is_a?(Hash)
17+
exs = v[:examples][:'application/json'].to_s
18+
exs.gsub!(/:(\w+)=>/, "\n\\1: ")
19+
response_example << exs
20+
elsif v[:examples][:'application/json'].is_a?(Array)
21+
response_example << "["
22+
v[:examples][:'application/json'].each do |ex|
23+
exs = ex.to_s
24+
if ex.is_a?(Hash)
25+
exs.gsub!(/:(\w+)=>/, "\n\\1: ")
26+
end
27+
response_example << (exs + ", ")
28+
end
29+
response_example << "]"
30+
end
31+
# for open api 3.0. examples on reponses, for example: api-with-examples.yaml
32+
elsif v.key?(:content) && v[:content].is_a?(Hash) && v[:content].key?(:'application/json') &&
33+
v[:content][:'application/json'].key?(:examples)
34+
v[:content][:'application/json'][:examples].each do |tk, tv|
35+
#todo: for the moment we only take in consideration the first example of response.
36+
# we need to decide how to manage to do it correctly
37+
if tv.key?(:value)
38+
tresp = tv[:value]
39+
else
40+
tresp = ""
41+
end
42+
if tresp.is_a?(String)
43+
response_example << tresp
44+
elsif tresp.is_a?(Hash)
45+
exs = tresp.to_s
46+
exs.gsub!(/:(\w+)=>/, "\n\\1: ")
47+
response_example << exs
48+
elsif tresp.is_a?(Array)
49+
response_example << "["
50+
tresp.each do |ex|
51+
exs = ex.to_s
52+
if ex.is_a?(Hash)
53+
exs.gsub!(/:(\w+)=>/, "\n\\1: ")
54+
end
55+
response_example << (exs + ", ")
56+
end
57+
response_example << "]"
58+
end
59+
break #only the first one it is considered
60+
end
61+
elsif v.key?(:schema) && v[:schema].is_a?(Hash) &&
62+
(v[:schema].key?(:properties) ||
63+
(v[:schema].key?(:items) && v[:schema][:items].key?(:properties)) ||
64+
(v[:schema].key?(:items) && v[:schema][:items].key?(:allOf)) ||
65+
v[:schema].key?(:allOf))
66+
properties = {}
67+
if v[:schema].key?(:properties)
68+
properties = v[:schema][:properties]
69+
elsif v[:schema].key?(:allOf)
70+
v[:schema][:allOf].each do |pr|
71+
properties.merge!(pr[:properties]) if pr.key?(:properties)
72+
end
73+
elsif v[:schema][:items].key?(:properties)
74+
properties = v[:schema][:items][:properties]
75+
response_example << "["
76+
elsif v[:schema][:items].key?(:allOf)
77+
v[:schema][:items][:allOf].each do |pr|
78+
properties.merge!(pr[:properties]) if pr.key?(:properties)
79+
end
80+
response_example << "["
81+
end
82+
83+
response_example += get_examples(properties, :key_value, remove_readonly) unless properties.empty?
84+
85+
unless response_example.empty?
86+
if v[:schema].key?(:properties) || v[:schema].key?(:allOf)
87+
#
88+
else # array, items
89+
response_example << "]"
90+
end
91+
end
92+
elsif v.key?(:schema) and v[:schema].key?(:items) and v[:schema][:items].key?(:type)
93+
# for the case only type supplied but nothing else for the array
94+
response_example << "[\"#{v[:schema][:items][:type]}\"]"
95+
end
96+
response_example.each do |rs|
97+
#(@type Google) for the case in example the key is something like: @type:
98+
if rs.match?(/^\s*@\w+:/)
99+
rs.gsub!(/@(\w+):/, '\'@\1\':')
100+
end
101+
end
102+
return response_example
103+
end
104+
end

0 commit comments

Comments
 (0)