angus-sdoc 0.0.1 → 0.0.2
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.
- data/lib/angus/base.rb +11 -0
- data/lib/angus/definitions/base.rb +18 -0
- data/lib/angus/definitions/glossary.rb +52 -0
- data/lib/angus/definitions/glossary_term.rb +37 -0
- data/lib/angus/definitions/message.rb +31 -0
- data/lib/angus/definitions/operation.rb +62 -0
- data/lib/angus/definitions/proxy_operation.rb +24 -0
- data/lib/angus/definitions/representation.rb +15 -0
- data/lib/angus/definitions/representation_field.rb +51 -0
- data/lib/angus/definitions/request_element.rb +61 -0
- data/lib/angus/definitions/response_element.rb +41 -0
- data/lib/angus/definitions/service.rb +118 -0
- data/lib/angus/definitions/uri_element.rb +20 -0
- data/lib/angus/definitions_reader.rb +305 -0
- data/lib/angus/definitions_utils.rb +72 -0
- data/lib/angus/exceptions/base.rb +1 -0
- data/lib/angus/exceptions/invalid_service_message.rb +32 -0
- data/lib/angus/sdoc/html_formatter.rb +42 -0
- data/lib/angus/sdoc/json_formatter.rb +317 -0
- data/lib/angus/sdoc/templates/doc.erb +295 -0
- data/lib/angus/sdoc/templates/styles.erb +70 -0
- data/lib/angus/sdoc/version.rb +3 -3
- data/lib/angus/sdoc.rb +5 -6
- metadata +169 -26
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -22
- data/README.md +0 -29
- data/Rakefile +0 -1
- data/angus-sdoc.gemspec +0 -23
@@ -0,0 +1,305 @@
|
|
1
|
+
module Angus
|
2
|
+
module SDoc
|
3
|
+
class DefinitionsReader
|
4
|
+
|
5
|
+
OPERATIONS = 'operations'
|
6
|
+
CONFIGURATIONS = %w{service proxy_operations representations glossary messages}
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# Returns the tree of objects for the service.
|
11
|
+
#
|
12
|
+
# @param [String] base_path The base path of the YML files.
|
13
|
+
#
|
14
|
+
# @return [Angus::SDoc::Definitions::Service] The service definition.
|
15
|
+
def service_definition(base_path)
|
16
|
+
definition_hash = load_definitions(base_path)
|
17
|
+
|
18
|
+
build_service_definition(definition_hash)
|
19
|
+
end
|
20
|
+
|
21
|
+
# It builds a Definitions::Service object from a service metadata.
|
22
|
+
#
|
23
|
+
# @param [Hash] definition_hash The service metadata.
|
24
|
+
#
|
25
|
+
# @return [Angus::SDoc::Definitions::Service] The service definition.
|
26
|
+
def build_service_definition(definition_hash)
|
27
|
+
definition = Angus::SDoc::Definitions::Service.new
|
28
|
+
definition.name = definition_hash['service']['service']
|
29
|
+
definition.code_name = definition_hash['service']['code_name']
|
30
|
+
definition.version = definition_hash['service']['version']
|
31
|
+
|
32
|
+
if definition_hash['messages']
|
33
|
+
definition.messages = build_messages(definition_hash['messages'])
|
34
|
+
end
|
35
|
+
|
36
|
+
if definition_hash['representations']
|
37
|
+
definition.representations = build_representations(definition_hash['representations'])
|
38
|
+
end
|
39
|
+
|
40
|
+
definition.operations = build_operations(
|
41
|
+
definition_hash['operations'],
|
42
|
+
definition.messages
|
43
|
+
)
|
44
|
+
|
45
|
+
definition.proxy_operations = build_proxy_operations(
|
46
|
+
# As long as services uses a Angus version which don't support proxy operations,
|
47
|
+
# we should default to an empty array.
|
48
|
+
#
|
49
|
+
# Remove the default when all services update Angus gem.
|
50
|
+
definition_hash['proxy_operations'] || []
|
51
|
+
)
|
52
|
+
|
53
|
+
if definition_hash['glossary']
|
54
|
+
definition.glossary = build_glossary(definition_hash['glossary'])
|
55
|
+
end
|
56
|
+
|
57
|
+
definition
|
58
|
+
end
|
59
|
+
|
60
|
+
# Reads the YML files in the given base path and returns a hash with the results loaded.
|
61
|
+
def load_definitions(base_path)
|
62
|
+
loaded_files = []
|
63
|
+
|
64
|
+
result = {}
|
65
|
+
|
66
|
+
Dir["#{base_path}/{#{CONFIGURATIONS.join(',')}}.yml"].each do |config_file|
|
67
|
+
loaded_files << config_file
|
68
|
+
|
69
|
+
namespace = File.basename(config_file, '.*')
|
70
|
+
|
71
|
+
result[namespace] = YAML.load_file(config_file) || {}
|
72
|
+
end
|
73
|
+
|
74
|
+
Dir["#{base_path}/**/#{OPERATIONS}.yml"].each do |config_file|
|
75
|
+
unless loaded_files.include?(config_file)
|
76
|
+
loaded_files << config_file
|
77
|
+
|
78
|
+
namespace = File.basename(config_file, '.*')
|
79
|
+
|
80
|
+
operation_namespace = Pathname.new(File.dirname(config_file)).basename.to_s
|
81
|
+
operation = YAML.load_file(config_file)
|
82
|
+
|
83
|
+
result[namespace] ||= {}
|
84
|
+
result[namespace][operation_namespace] = operation
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
result
|
89
|
+
end
|
90
|
+
private :load_definitions
|
91
|
+
|
92
|
+
# Builds Definitions::Message objects for each message metadata.
|
93
|
+
#
|
94
|
+
# @param [Hash] messages_hash The metadata messages.
|
95
|
+
# @example metadata message example
|
96
|
+
# {'InvalidJsonError' =>
|
97
|
+
# {
|
98
|
+
# 'status_code' => 422,
|
99
|
+
# 'level' => 'error',
|
100
|
+
# 'description' => 'Invalid json'
|
101
|
+
# }
|
102
|
+
# }
|
103
|
+
#
|
104
|
+
# @return [Hash<String, Message>] The hash with the messages.
|
105
|
+
def build_messages(messages_hash)
|
106
|
+
messages = {}
|
107
|
+
|
108
|
+
messages_hash.each do |key, attrs|
|
109
|
+
messages[key] = build_message(key, attrs['level'], attrs['status_code'],
|
110
|
+
attrs['description'], attrs['text'])
|
111
|
+
end
|
112
|
+
|
113
|
+
messages
|
114
|
+
end
|
115
|
+
private :build_messages
|
116
|
+
|
117
|
+
# Builds Definitions::Message with the message data.
|
118
|
+
#
|
119
|
+
# @param [String] key The message key.
|
120
|
+
# @param [String] level The message level.
|
121
|
+
# @param [String] status_code The message status code.
|
122
|
+
# @param [String] description The message description.
|
123
|
+
# @param [String] text The message text.
|
124
|
+
#
|
125
|
+
# @raise [Angus::SDoc::InvalidServiceMessage] if the level or the status code
|
126
|
+
# was not specified.
|
127
|
+
#
|
128
|
+
# @return [Message] the message.
|
129
|
+
def build_message(key, level, status_code, description, text)
|
130
|
+
unless level
|
131
|
+
raise Angus::SDoc::InvalidServiceMessage.new(key ,'Can not create message without level.')
|
132
|
+
end
|
133
|
+
|
134
|
+
unless status_code
|
135
|
+
raise Angus::SDoc::InvalidServiceMessage.new(key , 'Can not create message without a status code.')
|
136
|
+
end
|
137
|
+
|
138
|
+
message = Angus::SDoc::Definitions::Message.new
|
139
|
+
message.key = key
|
140
|
+
message.level = level
|
141
|
+
message.status_code = status_code
|
142
|
+
message.description = description
|
143
|
+
message.text = text
|
144
|
+
|
145
|
+
message
|
146
|
+
end
|
147
|
+
private :build_message
|
148
|
+
|
149
|
+
# Builds Definitions::ProxyOperation objects for each proxy operation metadata.
|
150
|
+
#
|
151
|
+
# @param [Hash] proxy_operations_hash The proxy operations metadata.
|
152
|
+
def build_proxy_operations(proxy_operations_hash)
|
153
|
+
proxy_operations_hash.map do |code_name, fields|
|
154
|
+
proxy_op = Angus::SDoc::Definitions::ProxyOperation.new
|
155
|
+
proxy_op.code_name = code_name
|
156
|
+
|
157
|
+
proxy_op.path = fields['path']
|
158
|
+
proxy_op.method = fields['method']
|
159
|
+
proxy_op.service_name = fields['service']
|
160
|
+
|
161
|
+
proxy_op
|
162
|
+
end
|
163
|
+
end
|
164
|
+
private :build_proxy_operations
|
165
|
+
|
166
|
+
# Builds Definitions::Representation objects for each representation metadata.
|
167
|
+
#
|
168
|
+
# @param [Hash] representations_hash The representations metadata.
|
169
|
+
# @option [String] :name
|
170
|
+
# @option [String] :field
|
171
|
+
# @option [String] :description
|
172
|
+
# @option [String] :type
|
173
|
+
# @option [String] :required
|
174
|
+
# @option [String] :elements_type
|
175
|
+
def build_representations(representations_hash)
|
176
|
+
representations_hash.map do |name, fields|
|
177
|
+
representation = Angus::SDoc::Definitions::Representation.new
|
178
|
+
representation.name = name
|
179
|
+
|
180
|
+
representation.fields = fields.map do |field_hash|
|
181
|
+
field = Angus::SDoc::Definitions::RepresentationField.new
|
182
|
+
field.name = field_hash['field']
|
183
|
+
field.description = field_hash['description']
|
184
|
+
field.type = field_hash['type']
|
185
|
+
field.required = field_hash['required']
|
186
|
+
field.elements_type = field_hash['elements_type']
|
187
|
+
field
|
188
|
+
end
|
189
|
+
|
190
|
+
representation
|
191
|
+
end
|
192
|
+
end
|
193
|
+
private :build_representations
|
194
|
+
|
195
|
+
# @todo Clarify the method explaining in a better way the note.
|
196
|
+
# @todo Refactor?
|
197
|
+
# Builds Definitions::Operation objects for each operation metadata.
|
198
|
+
#
|
199
|
+
# @note It also builds and associates:
|
200
|
+
# - request elements
|
201
|
+
# - uri elements
|
202
|
+
# - messages
|
203
|
+
# - response elements
|
204
|
+
#
|
205
|
+
# @param [Hash] operations_hash The operations' metadata.
|
206
|
+
# @param [Array<Message>] messages The service messages.
|
207
|
+
#
|
208
|
+
# @return [Hash<String, Array<Operation>>] hash with namespace as key and a list of
|
209
|
+
# operations as values.
|
210
|
+
def build_operations(operations_hash, messages)
|
211
|
+
result = {}
|
212
|
+
|
213
|
+
operations_hash.each do |namespace, operations|
|
214
|
+
operations.each do |code_name, op_metadata|
|
215
|
+
operation = Angus::SDoc::Definitions::Operation.new
|
216
|
+
|
217
|
+
operation.name = op_metadata['name']
|
218
|
+
operation.code_name = code_name
|
219
|
+
operation.description = op_metadata['description']
|
220
|
+
operation.path = op_metadata['path']
|
221
|
+
operation.method = op_metadata['method']
|
222
|
+
|
223
|
+
op_metadata['uri'] ||= []
|
224
|
+
operation.uri_elements = op_metadata['uri'].map do |element_hash|
|
225
|
+
uri_element = Angus::SDoc::Definitions::UriElement.new
|
226
|
+
|
227
|
+
uri_element.name = element_hash['element']
|
228
|
+
uri_element.description = element_hash['description']
|
229
|
+
|
230
|
+
uri_element
|
231
|
+
end
|
232
|
+
|
233
|
+
op_metadata['request'] ||= []
|
234
|
+
operation.request_elements = op_metadata['request'].map do |element_hash|
|
235
|
+
request_element = Angus::SDoc::Definitions::RequestElement.new
|
236
|
+
|
237
|
+
request_element.name = element_hash['element']
|
238
|
+
request_element.description = element_hash['description']
|
239
|
+
request_element.required = element_hash['required']
|
240
|
+
request_element.type = element_hash['type']
|
241
|
+
request_element.constraints = element_hash['constraints']
|
242
|
+
request_element.valid_values = element_hash['valid_values']
|
243
|
+
request_element.elements_type = element_hash['elements_type']
|
244
|
+
|
245
|
+
request_element
|
246
|
+
end
|
247
|
+
|
248
|
+
op_metadata['messages'] ||= []
|
249
|
+
operation.messages = op_metadata['messages'].map do |message_hash|
|
250
|
+
message_key = message_hash['key']
|
251
|
+
|
252
|
+
message = messages[message_key]
|
253
|
+
|
254
|
+
if message
|
255
|
+
# The operation could override some description or level attributes, so we clone it
|
256
|
+
message = message.clone
|
257
|
+
message.description = message_hash['description'] if message_hash['description']
|
258
|
+
message.level = message_hash['level'] if message_hash['level']
|
259
|
+
else
|
260
|
+
message = build_message(message_key, message_hash['level'], message_hash['status_code'],
|
261
|
+
message_hash['description'], message_hash['text'])
|
262
|
+
end
|
263
|
+
|
264
|
+
message
|
265
|
+
end
|
266
|
+
|
267
|
+
op_metadata['response'] ||= []
|
268
|
+
operation.response_elements = op_metadata['response'].map do |element_hash|
|
269
|
+
response_element = Angus::SDoc::Definitions::ResponseElement.new
|
270
|
+
|
271
|
+
response_element.name = element_hash['element']
|
272
|
+
response_element.description = element_hash['description']
|
273
|
+
response_element.required = element_hash['required']
|
274
|
+
response_element.type = element_hash['type']
|
275
|
+
response_element.default = element_hash['default']
|
276
|
+
response_element.elements_type = element_hash['elements_type']
|
277
|
+
|
278
|
+
response_element
|
279
|
+
end
|
280
|
+
|
281
|
+
result[namespace] ||= []
|
282
|
+
result[namespace] << operation
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
result
|
287
|
+
end
|
288
|
+
private :build_operations
|
289
|
+
|
290
|
+
# Builds a glossary from a hash.
|
291
|
+
#
|
292
|
+
# @param [Hash<String, Hash>] glossary_hash The hash contains GlossaryTerm#short_name
|
293
|
+
# as the key and a hash containing GlossaryTerm#long_name and GlossaryTerm#description
|
294
|
+
# as a value.
|
295
|
+
# @return [Glossary] the glossary
|
296
|
+
def build_glossary(glossary_hash)
|
297
|
+
Angus::SDoc::Definitions::Glossary.new(glossary_hash)
|
298
|
+
end
|
299
|
+
private :build_glossary
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Angus
|
2
|
+
module SDoc
|
3
|
+
module DefinitionsUtils
|
4
|
+
|
5
|
+
# Builds a new definition hash based on the given operation names.
|
6
|
+
# @todo Explain better this method. Needs refactor?
|
7
|
+
#
|
8
|
+
# @param [Hash] definition The service definition.
|
9
|
+
# @param [Array<String>] operation_names The names of the operations.
|
10
|
+
#
|
11
|
+
# @return [Hash] the definition.
|
12
|
+
def self.slice(definition, operation_names)
|
13
|
+
result = {
|
14
|
+
:operations => {},
|
15
|
+
:representations => {},
|
16
|
+
:messages => {}
|
17
|
+
}
|
18
|
+
|
19
|
+
result[:service] = definition['service']
|
20
|
+
|
21
|
+
representations = Set.new
|
22
|
+
messages = Set.new
|
23
|
+
|
24
|
+
definition['operations'].each do |code_name, operation|
|
25
|
+
if operation_names.include?(code_name)
|
26
|
+
result[:operations][code_name] = operation
|
27
|
+
|
28
|
+
types = (operation['response'] || []).map do |element|
|
29
|
+
element['type'] || element['elements_type']
|
30
|
+
end
|
31
|
+
|
32
|
+
representations += types
|
33
|
+
|
34
|
+
messages += (operation['messages'] || []).map do |message|
|
35
|
+
message['key']
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
representations.each do |name|
|
42
|
+
include_representation(name, definition['representations'], result[:representations])
|
43
|
+
end
|
44
|
+
|
45
|
+
messages.each do |key|
|
46
|
+
result[:messages][key] = definition['messages'][key]
|
47
|
+
end
|
48
|
+
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
# Inserts a representation and its children into a destination.
|
53
|
+
#
|
54
|
+
# @note The purpose of this method is to be used as an utility method from a method which
|
55
|
+
# selects a subset of representations.
|
56
|
+
#
|
57
|
+
# @param [String] name The representation name.
|
58
|
+
# @param [Hash] representations The source of the representations.
|
59
|
+
# @param [Hash] into the destination hash.
|
60
|
+
def self.include_representation(name, representations, into)
|
61
|
+
if representation = representations[name]
|
62
|
+
into[name] = representation
|
63
|
+
representation.each do |field|
|
64
|
+
field_type = field['type'] || field['elements_type']
|
65
|
+
include_representation(field_type, representations, into)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'invalid_service_message'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Angus
|
2
|
+
module SDoc
|
3
|
+
|
4
|
+
class InvalidServiceMessage < StandardError
|
5
|
+
|
6
|
+
attr_accessor :error_message, :message_key
|
7
|
+
|
8
|
+
def initialize(message_key, error_message)
|
9
|
+
self.error_message= error_message
|
10
|
+
self.message_key= message_key
|
11
|
+
end
|
12
|
+
|
13
|
+
def error_key
|
14
|
+
self.class.name
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
"#@message_key => #@error_message"
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
message
|
23
|
+
end
|
24
|
+
|
25
|
+
def == (other)
|
26
|
+
other.kind_of?(InvalidServiceMessage) &&
|
27
|
+
other.message == self.message && self.message_key == other.message_key
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Angus
|
4
|
+
module SDoc
|
5
|
+
class HtmlFormatter
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# Generates the html for the service definition.
|
10
|
+
#
|
11
|
+
# @param [Angus::SDoc::Definitions::Service] service_definition the service definition.
|
12
|
+
#
|
13
|
+
# @return [String] the generated html.
|
14
|
+
def format_service(service_definition)
|
15
|
+
@service = service_definition
|
16
|
+
|
17
|
+
erb(:doc)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def erb(template)
|
23
|
+
template = File.open(File.join(templates_path, "#{template}.erb")).read
|
24
|
+
ERB.new(template).result(binding)
|
25
|
+
end
|
26
|
+
|
27
|
+
def h_type(type, service)
|
28
|
+
if service.representations_hash.include?(type)
|
29
|
+
"<a href='#representation-#{service.representations_hash[type].name}'>#{type}</a>"
|
30
|
+
else
|
31
|
+
type
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def templates_path
|
36
|
+
File.join(File.dirname(__FILE__), 'templates')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|