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.
@@ -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