genio-parser 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|