matter_compiler 0.1.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.
@@ -0,0 +1,8 @@
1
+ Then /^the output should contain the content file "(.*)"$/ do |filename|
2
+ expected = nil
3
+ in_current_dir do
4
+ expected = File.read(filename)
5
+ end
6
+
7
+ assert_partial_output(expected, all_output)
8
+ end
@@ -0,0 +1 @@
1
+ require 'aruba/cucumber'
@@ -0,0 +1,522 @@
1
+ module MatterCompiler
2
+
3
+ # The classes in this document should be 1:1 with relevant Snow Crash
4
+ # counterparts (https://github.com/apiaryio/snowcrash/blob/master/src/Blueprint.h)
5
+ # until Matter Compiler becomes a wrapper for Snow Crash.
6
+
7
+ #
8
+ # Blueprint AST node
9
+ #
10
+ class BlueprintNode
11
+ ONE_INDENTATION_LEVEL = " "
12
+
13
+ def initialize(hash = nil)
14
+ load_ast_hash!(hash) if hash
15
+ end
16
+
17
+ # Load AST has into block
18
+ def load_ast_hash!(hash)
19
+ end
20
+
21
+ # Serialize block to a Markdown string
22
+ # \param level ... optional requested indentation level
23
+ def serialize(level = 0)
24
+ end
25
+ end
26
+
27
+ #
28
+ # Named Blueprint AST node
29
+ #
30
+ class NamedBlueprintNode < BlueprintNode
31
+ def load_ast_hash!(hash)
32
+ @name = hash[:name]
33
+ @description = hash[:description]
34
+ end
35
+ end
36
+
37
+ #
38
+ # Key-value collection
39
+ #
40
+ class KeyValueCollection < BlueprintNode
41
+ attr_accessor :collection
42
+
43
+ def load_ast_hash!(hash)
44
+ return if hash.empty?
45
+
46
+ @collection = Array.new
47
+ hash.each do |key, value_hash|
48
+ @collection << Hash[key, value_hash[:value]]
49
+ end
50
+ end
51
+
52
+ # Serialize key value pairs
53
+ # \param ignore_keys ... optional array of keys to NOT be serialized
54
+ def serialize(level = 0, ignore_keys = nil)
55
+ buffer = ""
56
+ @collection.each do |hash|
57
+ # Skip ignored keys
58
+ unless ignore_keys && ignore_keys.include?(hash.keys.first)
59
+ level.times { buffer << ONE_INDENTATION_LEVEL }
60
+ buffer << "#{hash.keys.first}: #{hash.values.first}\n"
61
+ end
62
+ end
63
+
64
+ buffer << "\n" unless buffer.empty?
65
+ buffer
66
+ end
67
+
68
+ # Returns collection without ignored keys
69
+ def ignore(ignore_keys)
70
+ return @collection if ignore_keys.blank?
71
+ @collection.select { |kv_item| !ignore_keys.include?(kv_item.keys.first) }
72
+ end
73
+ end
74
+
75
+ #
76
+ # Collection of metadata
77
+ #
78
+ class Metadata < KeyValueCollection
79
+ end
80
+
81
+ #
82
+ # Collection of headers
83
+ #
84
+ class Headers < KeyValueCollection
85
+
86
+ CONTENT_TYPE_HEADER_KEY = :'Content-Type'
87
+
88
+ def serialize(level = 0, ignore_keys = nil)
89
+ return "" if @collection.blank? || ignore(ignore_keys).blank?
90
+
91
+ buffer = ""
92
+ level.times { buffer << ONE_INDENTATION_LEVEL }
93
+ buffer << "+ Headers\n\n"
94
+
95
+ buffer << super(level + 2, ignore_keys)
96
+ end
97
+
98
+ # Returns the value of Content-Type header, if any.
99
+ def content_type
100
+ content_type_header = @collection.detect { |header| header.has_key?(CONTENT_TYPE_HEADER_KEY) }
101
+ return (content_type_header.nil?) ? nil : content_type_header[CONTENT_TYPE_HEADER_KEY]
102
+ end
103
+ end;
104
+
105
+ #
106
+ # One URI parameter
107
+ #
108
+ class Parameter < BlueprintNode
109
+ attr_accessor :name
110
+ attr_accessor :description
111
+ attr_accessor :type
112
+ attr_accessor :use
113
+ attr_accessor :default_value
114
+ attr_accessor :example_value
115
+ attr_accessor :values
116
+
117
+ def initialize(name = nil, hash = nil)
118
+ super(hash)
119
+ @name = name.to_s if name
120
+ end
121
+
122
+ def load_ast_hash!(hash)
123
+ @description = hash[:description]
124
+ @type = hash[:type] if hash[:type]
125
+ @use = (hash[:required] && hash[:required] == true) ? :required : :optional
126
+ @default_value = hash[:default] if hash[:default]
127
+ @example_value = hash[:example] if hash[:example]
128
+
129
+ unless hash[:values].blank?
130
+ @values = Array.new
131
+ hash[:values].each { |value| @values << value }
132
+ end
133
+ end
134
+
135
+ def serialize
136
+ # Parameter name
137
+ buffer = "#{ONE_INDENTATION_LEVEL}+ #{@name}"
138
+
139
+ # Default value
140
+ buffer << " = `#{@default_value}`" if @default_value
141
+
142
+ # Attributes
143
+ unless @type.blank? && @example_value.blank? && @use == :required
144
+ attribute_buffer = ""
145
+
146
+ buffer << " ("
147
+
148
+ # Type
149
+ attribute_buffer << @type unless @type.blank?
150
+
151
+ # Use
152
+ if (@use == :optional)
153
+ attribute_buffer << ", " unless attribute_buffer.empty?
154
+ attribute_buffer << "optional"
155
+ end
156
+
157
+ # Example value
158
+ unless (@example_value.blank?)
159
+ attribute_buffer << ", " unless attribute_buffer.empty?
160
+ attribute_buffer << "`#{@example_value}`"
161
+ end
162
+
163
+ buffer << attribute_buffer
164
+ buffer << ")"
165
+ end
166
+
167
+ # Description
168
+ if @description.blank?
169
+ buffer << "\n"
170
+ else
171
+ if @description.lines.count == 1
172
+ # One line description
173
+ buffer << " ... #{@description}"
174
+ buffer << "\n" if @description[-1, 1] != "\n" # Additional newline needed if no provided
175
+ else
176
+ # Multi-line description
177
+ buffer << "\n\n"
178
+ @description.each_line do |line|
179
+ 2.times { buffer << ONE_INDENTATION_LEVEL }
180
+ buffer << "#{line}"
181
+ end
182
+ end
183
+ end
184
+
185
+ # Value
186
+ unless @values.blank?
187
+ buffer << "\n"
188
+ 2.times { buffer << ONE_INDENTATION_LEVEL }
189
+ buffer << "+ Values\n"
190
+ @values.each do |value|
191
+ 3.times { buffer << ONE_INDENTATION_LEVEL }
192
+ buffer << "+ `#{value}`\n"
193
+ end
194
+ end
195
+
196
+ buffer
197
+ end
198
+ end
199
+
200
+ #
201
+ # Collection of URI parameters
202
+ #
203
+ class Parameters < BlueprintNode
204
+ attr_accessor :collection
205
+
206
+ def load_ast_hash!(hash)
207
+ return if hash.empty?
208
+
209
+ @collection = Array.new
210
+ hash.each do |key, value_hash|
211
+ @collection << Parameter.new(key, value_hash)
212
+ end
213
+ end
214
+
215
+ def serialize
216
+ return "" if :collection.blank?
217
+
218
+ buffer = "+ Parameters\n"
219
+ @collection.each do |parameter|
220
+ buffer << parameter.serialize
221
+ end
222
+
223
+ buffer << "\n" unless @collection.blank?
224
+ buffer
225
+ end
226
+ end
227
+
228
+ #
229
+ # Generic payload base class
230
+ #
231
+ class Payload < NamedBlueprintNode
232
+ attr_accessor :name
233
+ attr_accessor :description
234
+ attr_accessor :parameters
235
+ attr_accessor :headers
236
+ attr_accessor :body
237
+ attr_accessor :schema
238
+
239
+ def load_ast_hash!(hash)
240
+ super(hash)
241
+
242
+ @headers = Headers.new(hash[:headers]) unless hash[:headers].blank?
243
+ @body = hash[:body] unless hash[:body].blank?
244
+ @schema = hash[:schema] unless hash[:schema].blank?
245
+ end
246
+
247
+ def serialize
248
+ # Name is serialized in Payload successors
249
+ buffer = ""
250
+
251
+ unless @description.blank?
252
+ buffer << "\n"
253
+ @description.each_line { |line| buffer << "#{ONE_INDENTATION_LEVEL}#{line}" }
254
+ buffer << "\n"
255
+ end
256
+
257
+ unless @headers.blank?
258
+ buffer << @headers.serialize(1, [Headers::CONTENT_TYPE_HEADER_KEY])
259
+ end
260
+
261
+ unless @body.blank?
262
+ abbreviated_synax = (headers.blank? || headers.ignore([Headers::CONTENT_TYPE_HEADER_KEY]).blank?) \
263
+ & description.blank? \
264
+ & schema.blank?
265
+ asset_indent_level = 2
266
+ unless abbreviated_synax
267
+ asset_indent_level = 3
268
+ buffer << "#{ONE_INDENTATION_LEVEL}+ Body\n"
269
+ end
270
+ buffer << "\n"
271
+
272
+ @body.each_line do |line|
273
+ asset_indent_level.times { buffer << ONE_INDENTATION_LEVEL }
274
+ buffer << "#{line}"
275
+ end
276
+ buffer << "\n"
277
+ end
278
+
279
+ unless @schema.blank?
280
+ buffer << "#{ONE_INDENTATION_LEVEL}+ Schema\n\n"
281
+ @schema.each_line do |line|
282
+ 3.times { buffer << ONE_INDENTATION_LEVEL }
283
+ buffer << "#{line}"
284
+ end
285
+ buffer << "\n"
286
+ end
287
+
288
+ buffer << "\n" if buffer.empty? # Separate empty payloads by a newline
289
+
290
+ buffer
291
+ end
292
+
293
+ # Serialize payload section lead-in (begin)
294
+ # \param section ... section keyword name
295
+ # \param ignore_name ... true to ignore section's name, false otherwise
296
+ def serialize_lead_in(section, ignore_name = false)
297
+ buffer = ""
298
+ buffer << "+ #{section}"
299
+ buffer << " #{@name}" unless ignore_name || @name.blank?
300
+
301
+ unless @headers.blank? || @headers.content_type.blank?
302
+ buffer << " (#{@headers.content_type})"
303
+ end
304
+
305
+ buffer << "\n"
306
+ end
307
+ end
308
+
309
+ #
310
+ # Model Payload
311
+ #
312
+ class Model < Payload
313
+ def serialize
314
+ buffer = serialize_lead_in("Model", true)
315
+ buffer << super
316
+ end
317
+ end
318
+
319
+ #
320
+ # Request Payload
321
+ #
322
+ class Request < Payload
323
+ def serialize
324
+ buffer = serialize_lead_in("Request")
325
+ buffer << super
326
+ end
327
+ end
328
+
329
+ #
330
+ # Response Payload
331
+ #
332
+ class Response < Payload;
333
+ def serialize
334
+ buffer = serialize_lead_in("Response")
335
+ buffer << super
336
+ end
337
+ end
338
+
339
+ #
340
+ # Transaction Example
341
+ #
342
+ class TransactionExample < NamedBlueprintNode
343
+ attr_accessor :name
344
+ attr_accessor :description
345
+ attr_accessor :requests
346
+ attr_accessor :responses
347
+
348
+ def load_ast_hash!(hash)
349
+ super(hash)
350
+
351
+ unless hash[:requests].blank?
352
+ @requests = Array.new
353
+ hash[:requests].each { |request_hash| @requests << Request.new(request_hash) }
354
+ end
355
+
356
+ unless hash[:responses].blank?
357
+ @responses = Array.new
358
+ hash[:responses].each { |response_hash| @responses << Response.new(response_hash) }
359
+ end
360
+ end
361
+
362
+ def serialize
363
+ buffer = ""
364
+ @requests.each { |request| buffer << request.serialize } unless @requests.nil?
365
+ @responses.each { |response| buffer << response.serialize } unless @responses.nil?
366
+ buffer
367
+ end
368
+ end
369
+
370
+ #
371
+ # Action
372
+ #
373
+ class Action < NamedBlueprintNode
374
+ attr_accessor :method
375
+ attr_accessor :name
376
+ attr_accessor :description
377
+ attr_accessor :parameters
378
+ attr_accessor :headers
379
+ attr_accessor :examples
380
+
381
+ def load_ast_hash!(hash)
382
+ super(hash)
383
+
384
+ @method = hash[:method]
385
+ @parameters = Parameters.new(hash[:parameters]) unless hash[:parameters].blank?
386
+ @headers = Headers.new(hash[:headers]) unless hash[:headers].blank?
387
+
388
+ unless hash[:examples].blank?
389
+ @examples = Array.new
390
+ hash[:examples].each { |example_hash| @examples << TransactionExample.new(example_hash) }
391
+ end
392
+ end
393
+
394
+ def serialize
395
+ buffer = ""
396
+ if @name.blank?
397
+ buffer << "### #{@method}\n"
398
+ else
399
+ buffer << "### #{@name} [#{@method}]\n"
400
+ end
401
+
402
+ buffer << "#{@description}" unless @description.blank?
403
+
404
+ buffer << @parameters.serialize unless @parameters.nil?
405
+ buffer << @headers.serialize unless @headers.nil?
406
+
407
+ @examples.each { |example| buffer << example.serialize } unless @examples.nil?
408
+ buffer
409
+ end
410
+ end
411
+
412
+ #
413
+ # Resource
414
+ #
415
+ class Resource < NamedBlueprintNode
416
+ attr_accessor :uri_template
417
+ attr_accessor :name
418
+ attr_accessor :description
419
+ attr_accessor :model
420
+ attr_accessor :parameters
421
+ attr_accessor :headers
422
+ attr_accessor :actions
423
+
424
+ def load_ast_hash!(hash)
425
+ super(hash)
426
+
427
+ @uri_template = hash[:uriTemplate]
428
+ @model = Model.new(hash[:model]) unless hash[:model].blank?
429
+ @parameters = Parameters.new(hash[:parameters]) unless hash[:parameters].blank?
430
+ @headers = Headers.new(hash[:headers]) unless hash[:headers].blank?
431
+
432
+ unless hash[:actions].blank?
433
+ @actions = Array.new
434
+ hash[:actions].each { |action_hash| @actions << Action.new(action_hash) }
435
+ end
436
+ end
437
+
438
+ def serialize
439
+ buffer = ""
440
+ if @name.blank?
441
+ buffer << "## #{@uri_template}\n"
442
+ else
443
+ buffer << "## #{@name} [#{@uri_template}]\n"
444
+ end
445
+
446
+ buffer << "#{@description}" unless @description.blank?
447
+
448
+ buffer << @model.serialize unless @model.nil?
449
+ buffer << @parameters.serialize unless @parameters.nil?
450
+ buffer << @headers.serialize unless @headers.nil?
451
+
452
+ @actions.each { |action| buffer << action.serialize } unless @actions.nil?
453
+ buffer
454
+ end
455
+ end
456
+
457
+ #
458
+ # Resource Group
459
+ #
460
+ class ResourceGroup < NamedBlueprintNode
461
+ attr_accessor :name
462
+ attr_accessor :description
463
+ attr_accessor :resources
464
+
465
+ def load_ast_hash!(hash)
466
+ super(hash)
467
+
468
+ unless hash[:resources].blank?
469
+ @resources = Array.new
470
+ hash[:resources].each { |resource_hash| @resources << Resource.new(resource_hash) }
471
+ end
472
+ end
473
+
474
+ def serialize
475
+ buffer = ""
476
+ buffer << "# Group #{@name}\n" unless @name.blank?
477
+ buffer << "#{@description}" unless @description.blank?
478
+
479
+ @resources.each { |resource| buffer << resource.serialize } unless @resources.nil?
480
+ buffer
481
+ end
482
+ end
483
+
484
+ #
485
+ # Blueprint
486
+ #
487
+ class Blueprint < NamedBlueprintNode
488
+ attr_accessor :metadata
489
+ attr_accessor :name
490
+ attr_accessor :description
491
+ attr_accessor :resource_groups
492
+
493
+ VERSION_KEY = :_version
494
+ SUPPORTED_VERSIONS = ["1.0"]
495
+
496
+ def load_ast_hash!(hash)
497
+ super(hash)
498
+
499
+ # Load Metadata
500
+ unless hash[:metadata].blank?
501
+ @metadata = Metadata.new(hash[:metadata])
502
+ end
503
+
504
+ # Load Resource Groups
505
+ unless hash[:resourceGroups].blank?
506
+ @resource_groups = Array.new
507
+ hash[:resourceGroups].each { |group_hash| @resource_groups << ResourceGroup.new(group_hash) }
508
+ end
509
+ end
510
+
511
+ def serialize
512
+ buffer = ""
513
+ buffer << "#{@metadata.serialize}" unless @metadata.nil?
514
+ buffer << "# #{@name}\n" unless @name.blank?
515
+ buffer << "#{@description}" unless @description.blank?
516
+
517
+ @resource_groups.each { |group| buffer << group.serialize } unless @resource_groups.nil?
518
+ buffer
519
+ end
520
+
521
+ end
522
+ end