genio-parser 0.0.1
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 +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +57 -0
- data/data/wadl2meta.xsl +180 -0
- data/data/wsdl2meta.xsl +371 -0
- data/lib/genio/parser/format/base.rb +59 -0
- data/lib/genio/parser/format/iodocs.rb +97 -0
- data/lib/genio/parser/format/json_schema.rb +207 -0
- data/lib/genio/parser/format/wadl.rb +283 -0
- data/lib/genio/parser/format/wsdl.rb +71 -0
- data/lib/genio/parser/logging.rb +16 -0
- data/lib/genio/parser/types/base.rb +58 -0
- data/lib/genio/parser/types.rb +37 -0
- data/lib/genio/parser/version.rb +5 -0
- data/lib/genio/parser.rb +15 -0
- data/lib/genio-parser.rb +1 -0
- metadata +171 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'uri'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
module Genio
|
6
|
+
module Parser
|
7
|
+
module Format
|
8
|
+
class Base
|
9
|
+
include Logging
|
10
|
+
|
11
|
+
attr_accessor :files, :services, :data_types, :enum_types, :options, :endpoint
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
@options = options
|
15
|
+
|
16
|
+
@files = Types::Base.new( "#" => "self" )
|
17
|
+
@services = Types::Base.new
|
18
|
+
@data_types = Types::Base.new
|
19
|
+
@enum_types = Types::Base.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_iodocs
|
23
|
+
IODocs.to_iodocs(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def open(file, options = {})
|
27
|
+
options[:ssl_verify_mode] ||= 0
|
28
|
+
super(file, options)
|
29
|
+
end
|
30
|
+
|
31
|
+
def load_files
|
32
|
+
@load_files ||= []
|
33
|
+
end
|
34
|
+
|
35
|
+
def expand_path(file)
|
36
|
+
if load_files.any? and file !~ /^(\/|https?:\/\/)/
|
37
|
+
parent_file = load_files.last
|
38
|
+
if parent_file =~ /^https?:/
|
39
|
+
file = URI.join(parent_file, file).to_s
|
40
|
+
else
|
41
|
+
file = File.expand_path(file, File.dirname(parent_file))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
file
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_file(file, &block)
|
48
|
+
file = expand_path(file)
|
49
|
+
load_files.push(file)
|
50
|
+
logger.info("GET #{file}")
|
51
|
+
block.call(open(file).read)
|
52
|
+
ensure
|
53
|
+
load_files.pop
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Genio
|
2
|
+
module Parser
|
3
|
+
module Format
|
4
|
+
class IODocs < Base
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def to_iodocs(schema)
|
9
|
+
{ "endpoints" => schema.services.map{|name, service| service_to_iodocs(name, service, schema) } }
|
10
|
+
end
|
11
|
+
|
12
|
+
def service_to_iodocs(name, service, schema)
|
13
|
+
{ "name" => name,
|
14
|
+
"methods" => service.operations.map{|name, operation| operation_to_iodocs(name, operation, schema) } }
|
15
|
+
end
|
16
|
+
|
17
|
+
URIPropertyName = /{([^}]+)}/
|
18
|
+
def operation_to_iodocs(name, operation, schema)
|
19
|
+
data = {
|
20
|
+
"Name" => name,
|
21
|
+
"HTTPMethod" => operation.type,
|
22
|
+
"URI" => operation.path.gsub(URIPropertyName,':\1') ,
|
23
|
+
"Required" => "Y",
|
24
|
+
"Type" => "complex",
|
25
|
+
"Parameters" => [],
|
26
|
+
"Description" => operation.description || "" }
|
27
|
+
if operation.parameters
|
28
|
+
data["Parameters"] =
|
29
|
+
operation.parameters.map do |name, property|
|
30
|
+
property_to_iodocs(name, property.merge( :required => (property.location == "path") ), schema)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
operation.path.scan(URIPropertyName) do |name|
|
34
|
+
if operation.parameters.nil? or operation.parameters[$1].nil?
|
35
|
+
property = Types::Property.new(:type => "string", :required => true)
|
36
|
+
data["Parameters"] << property_to_iodocs($1, property, schema)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
if operation.request_property
|
40
|
+
property = operation.request_property.merge( :required => true )
|
41
|
+
parameter = property_to_iodocs(property.type, property, schema)
|
42
|
+
data["Parameters"] += [ parameter ]
|
43
|
+
data["RequestContentType"] = "application/json"
|
44
|
+
end
|
45
|
+
data
|
46
|
+
end
|
47
|
+
|
48
|
+
def members_loaded
|
49
|
+
@members ||= {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def members_for_data_type(data_type, schema)
|
53
|
+
return [] if members_loaded[data_type]
|
54
|
+
members_loaded[data_type] = true
|
55
|
+
members = []
|
56
|
+
if data_type.extends and schema.data_types[data_type.extends]
|
57
|
+
members += members_for_data_type(schema.data_types[data_type.extends], schema)
|
58
|
+
end
|
59
|
+
data_type.properties.each{|name, property|
|
60
|
+
unless property.readonly
|
61
|
+
members.push(property_to_iodocs(name, property, schema))
|
62
|
+
end
|
63
|
+
}
|
64
|
+
members_loaded.delete(data_type)
|
65
|
+
members
|
66
|
+
end
|
67
|
+
|
68
|
+
def property_to_iodocs(name, property, schema)
|
69
|
+
if property.attribute and schema.options[:attribute]
|
70
|
+
name = "@#{name}"
|
71
|
+
elsif property.package and schema.options[:namespace]
|
72
|
+
name = "#{property.package}:#{name}"
|
73
|
+
end
|
74
|
+
data = {
|
75
|
+
"Name" => name,
|
76
|
+
"Type" => property.type,
|
77
|
+
"ValidatedClass" => property.type,
|
78
|
+
}
|
79
|
+
data["Description"] = property.description if property.description
|
80
|
+
data["Required"] = "Y" if property.required == true
|
81
|
+
data["Default"] = property.default unless property.default.nil?
|
82
|
+
if property.enum
|
83
|
+
data["Type"] = "enumerated"
|
84
|
+
data["EnumeratedList"] = property.enum
|
85
|
+
elsif schema.data_types[property.type]
|
86
|
+
data["Type"] = "complex"
|
87
|
+
data["Members"] = members_for_data_type(schema.data_types[property.type], schema)
|
88
|
+
data["Members"] = [ data["Members"] ] if property.array
|
89
|
+
end
|
90
|
+
data
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Genio
|
4
|
+
module Parser
|
5
|
+
module Format
|
6
|
+
class JsonSchema < Base
|
7
|
+
include Logging
|
8
|
+
|
9
|
+
# Load schema
|
10
|
+
# == Example
|
11
|
+
# schema.load("path/to/json_schema.json")
|
12
|
+
# schema.load("http://example.com/json_schema.json")
|
13
|
+
def load(filename, force = false)
|
14
|
+
if data_types[filename] || (!force and data_types[class_name(filename)])
|
15
|
+
class_name(filename)
|
16
|
+
elsif files[filename]
|
17
|
+
files[filename]
|
18
|
+
else
|
19
|
+
files[filename] = class_name(filename)
|
20
|
+
parse_file(filename)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse Given schema file and return class name
|
25
|
+
def parse_file(filename)
|
26
|
+
klass = class_name(filename)
|
27
|
+
read_file(filename) do |data|
|
28
|
+
data = JSON.parse(data, :object_class => Types::Base, :max_nesting => 100)
|
29
|
+
if data.type == "object" or data.properties or data.type.is_a? Array # Check the type is object or not.
|
30
|
+
data_types[klass] = {}
|
31
|
+
data_types[klass] = parse_object(data)
|
32
|
+
elsif data.resources # Checkout the schema file contains the services or not
|
33
|
+
parse_resource(data)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
klass
|
37
|
+
end
|
38
|
+
|
39
|
+
# Parse object schema
|
40
|
+
def parse_object(data)
|
41
|
+
if data["$ref"]
|
42
|
+
return self.data_types[self.load(data["$ref"], true)]
|
43
|
+
end
|
44
|
+
|
45
|
+
properties = Types::Base.new
|
46
|
+
|
47
|
+
# Parse each properties
|
48
|
+
if data.properties
|
49
|
+
data.properties.each do |name, options|
|
50
|
+
properties[name] = parse_property(name, options)
|
51
|
+
end
|
52
|
+
elsif data.type.is_a?(Array)
|
53
|
+
data.type.each do |object|
|
54
|
+
properties.merge!(parse_object(object).properties)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Load extends class.
|
59
|
+
if data.extends.is_a? String
|
60
|
+
data.extends = self.load(data.extends)
|
61
|
+
else
|
62
|
+
data.extends = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
# Parse array type
|
66
|
+
if data.items
|
67
|
+
array_type = parse_object(data.items)
|
68
|
+
properties.merge!(array_type.properties)
|
69
|
+
data.extends ||= array_type.extends
|
70
|
+
data.array = true
|
71
|
+
end
|
72
|
+
|
73
|
+
data.properties = properties
|
74
|
+
Types::DataType.new(data)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Parse property.
|
78
|
+
def parse_property(name, data)
|
79
|
+
data.array = true if data.type == "array"
|
80
|
+
data.type =
|
81
|
+
if data["$ref"] # Check the type is refer to another schema or not
|
82
|
+
self.load(data["$ref"])
|
83
|
+
elsif data.additionalProperties and data.additionalProperties["$ref"]
|
84
|
+
self.load(data.additionalProperties["$ref"])
|
85
|
+
elsif data.properties # Check the type has object definition or not
|
86
|
+
klass_name = class_name(name)
|
87
|
+
data_types[klass_name] = parse_object(data)
|
88
|
+
klass_name
|
89
|
+
elsif data.type.is_a? Array
|
90
|
+
data.union_types = data.type.map do |type|
|
91
|
+
parse_object(type)
|
92
|
+
end
|
93
|
+
"object"
|
94
|
+
elsif data.items # Parse array value type
|
95
|
+
array_property = parse_property(name, data.items)
|
96
|
+
array_property.type
|
97
|
+
else
|
98
|
+
data.type # Simple type
|
99
|
+
end
|
100
|
+
Types::Property.new(data)
|
101
|
+
rescue => error
|
102
|
+
logger.error error.message
|
103
|
+
Types::Property.new
|
104
|
+
end
|
105
|
+
|
106
|
+
# Parse resource schema
|
107
|
+
def parse_resource(data)
|
108
|
+
|
109
|
+
self.endpoint ||= data.rootUrl
|
110
|
+
|
111
|
+
if data.schemas
|
112
|
+
data.schemas.each do |name, options|
|
113
|
+
data_types[class_name(name)] = true
|
114
|
+
end
|
115
|
+
data.schemas.each do |name, options|
|
116
|
+
data_types[class_name(name)] = parse_object(options)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
parse_services(data.resources, data)
|
121
|
+
end
|
122
|
+
|
123
|
+
def parse_services(resources, data)
|
124
|
+
# Parse Resources
|
125
|
+
resources.each do |name, options|
|
126
|
+
service = parse_service(options, data)
|
127
|
+
service.path = File.join(data.servicePath, name)
|
128
|
+
if services[class_name(name)]
|
129
|
+
service.operations.merge!(services[class_name(name)].operations)
|
130
|
+
end
|
131
|
+
services[class_name(name)] = service
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Parse each operation in service
|
136
|
+
def parse_service(data, service)
|
137
|
+
data["methods"] ||= {}
|
138
|
+
|
139
|
+
data["methods"].each do |name, options|
|
140
|
+
options.relative_path = options.path
|
141
|
+
options.path = File.join(service.servicePath, options.path)
|
142
|
+
options.type = options.httpMethod
|
143
|
+
if options.request
|
144
|
+
options.request_property = parse_property("#{name}_request", options.request)
|
145
|
+
options.request = options.request_property.type
|
146
|
+
end
|
147
|
+
if options.response
|
148
|
+
options.response_property = parse_property("#{name}_response", options.response)
|
149
|
+
options.response = options.response_property.type
|
150
|
+
end
|
151
|
+
# Load service parameters
|
152
|
+
if options.parameters.nil? and options.type == "GET"
|
153
|
+
options.parameters = service.parameters
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
data.operations = data["methods"]
|
158
|
+
|
159
|
+
parse_services(data.resources, service) if data.resources
|
160
|
+
|
161
|
+
Types::Service.new(data)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Update configured ref links
|
165
|
+
def update_ref_paths(data, paths = {})
|
166
|
+
paths.each do |path, replace_path|
|
167
|
+
replace_path = replace_path.sub(/\/?$/, "/")
|
168
|
+
data = data.gsub(/("\$ref"\s*:\s*")#{Regexp.escape(path)}\/?/, "\\1#{replace_path}")
|
169
|
+
end
|
170
|
+
data
|
171
|
+
end
|
172
|
+
|
173
|
+
# Format class name
|
174
|
+
# === Example
|
175
|
+
# class_name("credit-card") # return "CreditCard"
|
176
|
+
# class_name("/path/to/payment.json") # return "Payment"
|
177
|
+
def class_name(name)
|
178
|
+
File.basename(name.to_s.gsub(/\#$/, "").gsub(/-/, "_"), ".json").camelcase
|
179
|
+
end
|
180
|
+
|
181
|
+
# Fix file name format
|
182
|
+
def file_name(name)
|
183
|
+
name.to_s.gsub(/-/, "_").underscore
|
184
|
+
end
|
185
|
+
|
186
|
+
# Map operations based on the Request or Response types.
|
187
|
+
def fix_unknown_service
|
188
|
+
new_services = Types::Base.new
|
189
|
+
services.each do |service_name, service|
|
190
|
+
unless data_types[service_name]
|
191
|
+
service.operations.each do |operation_name, operation|
|
192
|
+
if data_types[operation.request]
|
193
|
+
new_services[operation.request] ||= Types::Base.new( :operations => {} )
|
194
|
+
new_services[operation.request].operations[operation_name] = operation
|
195
|
+
elsif data_types[operation.response]
|
196
|
+
new_services[operation.response] ||= Types::Base.new( :operations => {} )
|
197
|
+
new_services[operation.response].operations[operation_name] = operation
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
services.merge!(new_services)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,283 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module Genio
|
4
|
+
module Parser
|
5
|
+
module Format
|
6
|
+
class Wadl < Base
|
7
|
+
|
8
|
+
attr_accessor :current_schema, :namespaces, :attributes, :element_form_defaults
|
9
|
+
|
10
|
+
def load(file)
|
11
|
+
return if self.files[file]
|
12
|
+
self.files[file] = file
|
13
|
+
|
14
|
+
doc = load_doc(file)
|
15
|
+
schema = xslt.transform(doc)
|
16
|
+
schema.remove_namespaces!
|
17
|
+
|
18
|
+
parse_schema(schema)
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_doc(file)
|
22
|
+
logger.info "GET #{file}"
|
23
|
+
document = Nokogiri::XML(open(file).read)
|
24
|
+
|
25
|
+
import_document = document.dup
|
26
|
+
import_document.remove_namespaces!
|
27
|
+
|
28
|
+
import_document.css("schema import").each do |import|
|
29
|
+
if import.attr("schemaLocation")
|
30
|
+
import_file = File.join(File.dirname(file), import.attr("schemaLocation"))
|
31
|
+
logger.info "GET #{import_file}"
|
32
|
+
parent = document.css("definitions types").first
|
33
|
+
if parent and parent.children.first
|
34
|
+
xml = Nokogiri::XML(open(import_file).read)
|
35
|
+
xml.children.each{|element| parent.children.first.before(element) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
document
|
41
|
+
end
|
42
|
+
|
43
|
+
def xslt
|
44
|
+
@xslt ||= Nokogiri::XSLT(File.read(File.expand_path("../../../../../data/wadl2meta.xsl", __FILE__)))
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_schema(schema)
|
48
|
+
|
49
|
+
self.current_schema = schema
|
50
|
+
|
51
|
+
self.namespaces ||= Types::Base.new
|
52
|
+
schema.css("properties namespace").map{|namespace|
|
53
|
+
self.namespaces[namespace.text] = namespace.attr("name")
|
54
|
+
}
|
55
|
+
|
56
|
+
self.attributes ||= Types::Base.new
|
57
|
+
schema.css("properties attribute").map{|attribute|
|
58
|
+
self.attributes[attribute.attr("name")] = attribute.text
|
59
|
+
}
|
60
|
+
|
61
|
+
self.element_form_defaults ||= Types::Base.new
|
62
|
+
schema.css("properties elementFormDefault").map{|element|
|
63
|
+
self.element_form_defaults[element.attr("namespace")] = element.text
|
64
|
+
}
|
65
|
+
|
66
|
+
schema.css("elements enum").each do |enum|
|
67
|
+
name = valid_class(enum.attr("name"))
|
68
|
+
type = Types::EnumType.new(enum.attributes.map{|k,v| [k, v.value] })
|
69
|
+
type.values = enum.css("value").map{|element| element.text }
|
70
|
+
self.enum_types[name] = type
|
71
|
+
end
|
72
|
+
|
73
|
+
# Load data_types
|
74
|
+
schema.css("classes class").each do |kls|
|
75
|
+
name = valid_class(kls.attr("name"))
|
76
|
+
value = parse_data_type(kls, self.namespaces[kls.attr("package")])
|
77
|
+
self.data_types[name] = value
|
78
|
+
end
|
79
|
+
|
80
|
+
# Validate property.type in each data_type
|
81
|
+
self.data_types.values.each do |data_type|
|
82
|
+
data_type.properties.values.each do |property|
|
83
|
+
property.type = valid_type(property.type)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Set endpoint
|
88
|
+
resources = schema.css("resources").first
|
89
|
+
self.endpoint ||= resources.attr("base") if resources
|
90
|
+
|
91
|
+
# Load service and operations
|
92
|
+
schema.css("resources resource").each do |resource|
|
93
|
+
parse_resource(resource)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def parse_data_type(kls, default_package = nil)
|
98
|
+
attrs = Hash[kls.attributes.map{|key, value| [ key, value.value ] }]
|
99
|
+
data_type = Types::DataType.new(attrs)
|
100
|
+
|
101
|
+
if data_type.package.blank?
|
102
|
+
element = self.current_schema.css("elements element[name=#{data_type.name}]")[0]
|
103
|
+
data_type.package = element.attr("package") if element
|
104
|
+
end
|
105
|
+
|
106
|
+
if kls.css("extends").any?
|
107
|
+
data_type.extends = kls.css("extends").first.attr("name")
|
108
|
+
end
|
109
|
+
|
110
|
+
data_type.properties = {}
|
111
|
+
kls.css("properties property").each do |property|
|
112
|
+
name = property.attr("name")
|
113
|
+
value = Hash[property.attributes.map{|key, value| [ key, value.value ] }]
|
114
|
+
value["package"] = default_package if default_package and name != "value"
|
115
|
+
data_type.properties[name] = parse_property(value)
|
116
|
+
end
|
117
|
+
|
118
|
+
data_type
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_element(name, level = 0)
|
122
|
+
if name.present?
|
123
|
+
element = self.current_schema.css("elements element[name=#{name}]").first
|
124
|
+
if element and element.attr("name") != element.attr("type") and level > 0
|
125
|
+
get_element(element.attr("type"), level - 1 ) || element
|
126
|
+
else
|
127
|
+
element
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def parse_property(property)
|
133
|
+
property = Types::Property.new(property)
|
134
|
+
|
135
|
+
# Check for complex type
|
136
|
+
if property.ref
|
137
|
+
property.type = valid_type(property.ref)
|
138
|
+
end
|
139
|
+
|
140
|
+
unless property.type
|
141
|
+
element = get_element(property.name)
|
142
|
+
if element
|
143
|
+
property.type = element.attr("type")
|
144
|
+
element_package = self.namespaces[element.attr("package")]
|
145
|
+
property.package = element_package if element_package
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
if property.type.present? and !current_schema.css("classes class[name=#{property.type}]").first
|
150
|
+
element = get_element(property.type)
|
151
|
+
property.type = element.attr("type") if element and element.attr("type").present?
|
152
|
+
end
|
153
|
+
|
154
|
+
# Array type
|
155
|
+
if property.max == "unbounded" or property.max.to_i > 1
|
156
|
+
property.array = true
|
157
|
+
end
|
158
|
+
|
159
|
+
# Required
|
160
|
+
if property.min and property.min.to_i > 0
|
161
|
+
property.required = true
|
162
|
+
end
|
163
|
+
|
164
|
+
# Description
|
165
|
+
if property.documentation
|
166
|
+
property.description = property.documentation.gsub(/\s+/, " ").strip
|
167
|
+
end
|
168
|
+
|
169
|
+
# Enum
|
170
|
+
if enum_types[property.type]
|
171
|
+
property.enum = enum_types[property.type].values
|
172
|
+
end
|
173
|
+
|
174
|
+
property.attribute = true if property.attrib
|
175
|
+
|
176
|
+
property
|
177
|
+
end
|
178
|
+
|
179
|
+
def parse_resource(resource)
|
180
|
+
resource.css("method").each do |method_object|
|
181
|
+
operation = Types::Operation.new(
|
182
|
+
:id => method_object.attr("id"),
|
183
|
+
:type => method_object.attr("name"),
|
184
|
+
:parameters => {},
|
185
|
+
:path => resource.attr("path") )
|
186
|
+
|
187
|
+
resource.css("> param").each do |param|
|
188
|
+
operation.parameters[param.attr("name")] =
|
189
|
+
Types::Property.new( :type => valid_type(param.attr("type")), :location => "path" )
|
190
|
+
end
|
191
|
+
|
192
|
+
method_object.css("param").each do |param|
|
193
|
+
operation.parameters[param.attr("name")] =
|
194
|
+
Types::Property.new( :type => valid_type(param.attr("type")) )
|
195
|
+
end
|
196
|
+
|
197
|
+
request = method_object.css("request representation").first
|
198
|
+
if request
|
199
|
+
operation.request_property = operation_property(request)
|
200
|
+
operation.request = operation.request_property.type
|
201
|
+
end
|
202
|
+
|
203
|
+
response = method_object.css("response representation").first
|
204
|
+
if response
|
205
|
+
operation.response_property = operation_property(response)
|
206
|
+
operation.response = operation.response_property.type
|
207
|
+
end
|
208
|
+
|
209
|
+
add_operation(operation)
|
210
|
+
operation
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def operation_property(type)
|
215
|
+
property = Types::Property.new(type.attributes.map{|k,v| [k, v.value] })
|
216
|
+
property.type = valid_type(property.element) || "string"
|
217
|
+
element = get_element(property.type)
|
218
|
+
property.type = valid_type(element.attr(:type)) if element and element.attr(:type).present?
|
219
|
+
property
|
220
|
+
end
|
221
|
+
|
222
|
+
def add_operation(operation)
|
223
|
+
path = operation.path.split("/")
|
224
|
+
type =
|
225
|
+
if path[-1] =~ /^{/ and path[-2].present? and self.data_types[valid_class(path[-2])]
|
226
|
+
valid_class(path[-2])
|
227
|
+
elsif path[-2] =~ /^{/ and path[-3].present? and self.data_types[valid_class(path[-3])]
|
228
|
+
valid_class(path[-3])
|
229
|
+
elsif path[-1].present? and path[-1] !~ /^{/ and self.data_types[valid_class(path[-1])]
|
230
|
+
valid_class(path[-1])
|
231
|
+
elsif operation.response and self.data_types[operation.response]
|
232
|
+
operation.response
|
233
|
+
elsif operation.request and self.data_types[operation.request]
|
234
|
+
operation.request
|
235
|
+
else
|
236
|
+
"Service"
|
237
|
+
end
|
238
|
+
if type
|
239
|
+
self.data_types[type] ||= Types::DataType.new( :properties => {} )
|
240
|
+
self.services[type] ||= Types::Service.new( :operations => {} )
|
241
|
+
name = operation_name(operation)
|
242
|
+
self.services[type].operations[name] = operation
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
private
|
247
|
+
|
248
|
+
def valid_class(name)
|
249
|
+
name.gsub(/-/, "_").camelcase
|
250
|
+
end
|
251
|
+
|
252
|
+
def valid_type(name)
|
253
|
+
if name
|
254
|
+
name = name.gsub(/^.*:/, "")
|
255
|
+
type = valid_class(name)
|
256
|
+
( data_types[type] || enum_types[type] ) ? type : name
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def operation_name(operation)
|
261
|
+
if operation.id
|
262
|
+
operation.id
|
263
|
+
elsif operation.type == "GET"
|
264
|
+
if operation.path =~ /}$/
|
265
|
+
"get"
|
266
|
+
else
|
267
|
+
"list"
|
268
|
+
end
|
269
|
+
elsif operation.type == "DELETE"
|
270
|
+
"delete"
|
271
|
+
elsif operation.path =~ /}\/([^{}]*)$/
|
272
|
+
$1.dup
|
273
|
+
elsif operation.type == "POST"
|
274
|
+
"create"
|
275
|
+
else
|
276
|
+
"update"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|