apiary_blueprint_convertor 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 848054e783c9a61d69e0a2be0dbdb0eef16a7388
4
+ data.tar.gz: 963c51bb0f6b0ec32a8dd973d3f613973acc2741
5
+ SHA512:
6
+ metadata.gz: 6060f1dc3dad96ce6af4b5bac882272496cb59d4b27f440806f676a278ce95a77100eaa4bc102c2f3d3dc397d6a3d11bc5b0e4e46b829bef447a8cb127215db6
7
+ data.tar.gz: 7be67e76e709b687ca30cfe4754f15f5f30ff37c1f50b71a796f24e230c558b99b0cf70f673bbcc0c002f42aff5bcd3336712f25ed397738ce5f6ffa991cfc0f
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.1.0
5
+ before_install: gem update bundler
6
+ notifications:
7
+ email:
8
+ recipients:
9
+ - z@apiary.io
10
+ on_success: change
11
+ on_failure: always
12
+ hipchat:
13
+ secure: "JT63QEBAHHbcM9MiLheYGfpztUCnzwcDuOXmn9A96J9DqMvinOlEhLW2sl0aGr9YsF8mXY9zB03KglpSeP9yLZyroAPjIqNGh2+eLFy+v/ELpDBW4EA1XwBNwz1CvHSReJWupujTSHiV9r4+WPPIb0+KIsqPsOvbh1sGPMhulkA="
14
+
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in apiary_blueprint_convertor.gemspec
4
+ gemspec
5
+
6
+ # Manual Aruba Installation
7
+ group :development do
8
+ gem 'aruba', :git => 'git://github.com/cucumber/aruba.git'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,47 @@
1
+ GIT
2
+ remote: git://github.com/cucumber/aruba.git
3
+ revision: 99d8e6a5992af17b014783e775409bc3fd422273
4
+ specs:
5
+ aruba (0.5.4)
6
+ childprocess (>= 0.3.6)
7
+ cucumber (>= 1.1.1)
8
+ rspec-expectations (>= 2.7.0)
9
+
10
+ PATH
11
+ remote: .
12
+ specs:
13
+ apiary_blueprint_convertor (0.1.1)
14
+
15
+ GEM
16
+ remote: https://rubygems.org/
17
+ specs:
18
+ builder (3.2.2)
19
+ childprocess (0.3.9)
20
+ ffi (~> 1.0, >= 1.0.11)
21
+ cucumber (1.3.10)
22
+ builder (>= 2.1.2)
23
+ diff-lcs (>= 1.1.3)
24
+ gherkin (~> 2.12)
25
+ multi_json (>= 1.7.5, < 2.0)
26
+ multi_test (>= 0.0.2)
27
+ diff-lcs (1.2.5)
28
+ ffi (1.9.3)
29
+ gherkin (2.12.2)
30
+ multi_json (~> 1.3)
31
+ minitest (5.2.1)
32
+ multi_json (1.8.4)
33
+ multi_test (0.0.3)
34
+ rake (10.1.1)
35
+ rspec-expectations (2.14.4)
36
+ diff-lcs (>= 1.1.3, < 2.0)
37
+
38
+ PLATFORMS
39
+ ruby
40
+
41
+ DEPENDENCIES
42
+ apiary_blueprint_convertor!
43
+ aruba!
44
+ bundler (~> 1.5)
45
+ cucumber
46
+ minitest
47
+ rake
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2013 Apiary Inc. <support@apiary.io>.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Apiary Blueprint AST Convertor [![Build Status](https://travis-ci.org/apiaryio/apiary_blueprint_convertor.png?branch=master)](https://travis-ci.org/apiaryio/apiary_blueprint_convertor)
2
+ A migration tool for legacy [Apiary Blueprint](https://github.com/apiaryio/blueprint-parser) AST into [API Blueprint](http://apiblueprint.org) AST. Converts Apiary Blueprint AST serialized into a JSON file to [API Blueprint AST](https://github.com/apiaryio/snowcrash/wiki/API-Blueprint-AST-Media-Types) JSON representation (`vnd.apiblueprint.ast.raw+json; version=1.0`).
3
+
4
+ ## Installation
5
+ Add this line to your application's Gemfile:
6
+
7
+ gem 'apiary_blueprint_convertor'
8
+
9
+ And then execute:
10
+
11
+ $ bundle
12
+
13
+ Or install it yourself as:
14
+
15
+ $ gem install apiary_blueprint_convertor
16
+
17
+ ## Usage
18
+
19
+ ```sh
20
+ $ apiary_blueprint_convertor path/to/legacy/ast.json
21
+ ```
22
+
23
+ See the [convert feature](features/convert.feature) for details or run `apiary_blueprint_convertor --help`.
24
+
25
+ ### Convert Legacy Apiary Blueprint to API Blueprint
26
+ Use this convertor together with the legacy [Apiary Blueprint Parser](https://github.com/apiaryio/blueprint-parser) and API Blueprint Composer – [Matter Compiler](https://github.com/apiaryio/matter_compiler).
27
+
28
+ 1. Parse Legacy Apiary Blueprint into its JSON AST using `Apiary Blueprint Parser`
29
+ 2. Convert legacy JSON AST into API Blueprint JSON AST using `apiary_blueprint_convertor`
30
+ 3. Compose API Blueprint from API Blueprint JSON AST using `matter_compiler`
31
+
32
+ ## Contributing
33
+ 1. Fork this repository (http://github.com/apiaryio/apiary_blueprint_convertor/fork)
34
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
35
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
36
+ 4. Push to the branch (`git push origin my-new-feature`)
37
+ 5. Create new Pull Request
38
+
39
+ ## License
40
+ MIT License. See the [LICENSE](LICENSE) file.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+ require 'cucumber/rake/task'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs.push "lib"
7
+ t.test_files = FileList['test/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ Cucumber::Rake::Task.new(:features) do |t|
12
+ t.cucumber_opts = "features --format pretty"
13
+ end
14
+
15
+ desc "Run all CI tests"
16
+ task :test_ci do
17
+ Rake::Task['test'].invoke
18
+ Rake::Task['features'].invoke
19
+ end
20
+
21
+ task :default => :test_ci
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'apiary_blueprint_convertor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "apiary_blueprint_convertor"
8
+ spec.version = ApiaryBlueprintConvertor::VERSION
9
+ spec.authors = ["Zdenek Nemec"]
10
+ spec.email = ["z@apiary.io"]
11
+ spec.summary = %q{Apiary Blueprint AST convertor.}
12
+ spec.description = %q{Convert legacy Apiary Blueprint AST into API Blueprint AST (JSON).}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "cucumber"
24
+ spec.add_development_dependency "minitest"
25
+
26
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'apiary_blueprint_convertor/cli'
3
+ ApiaryBlueprintConvertor::CLI.start
@@ -0,0 +1,321 @@
1
+ Feature: Convert AST
2
+
3
+ Background:
4
+ Given a file named "legacy_ast.json" with:
5
+ """
6
+ {
7
+ "location": "http://www.google.com/",
8
+ "name": "Sample API v2",
9
+ "description": "Welcome to our sample API documentation. All comments can be written in (support [Markdown](http://daringfireball.net/projects/markdown/syntax) syntax)",
10
+ "sections": [
11
+ {
12
+ "name": "Shopping Cart Resources",
13
+ "description": "The following is a section of resources related to the shopping cart",
14
+ "resources": [
15
+ {
16
+ "description": "List products added into your shopping-cart. (comment block again in Markdown)",
17
+ "method": "GET",
18
+ "url": "/shopping-cart",
19
+ "request": {
20
+ "headers": {},
21
+ "body": null
22
+ },
23
+ "responses": [
24
+ {
25
+ "status": 200,
26
+ "headers": {
27
+ "Content-Type": "application/json"
28
+ },
29
+ "body": "{\n \"items\": [\n {\n \"url\": \"/shopping-cart/1\",\n \"product\": \"2ZY48XPZ\",\n \"quantity\": 1,\n \"name\": \"New socks\",\n \"price\": 1.25\n }\n ]\n}"
30
+ }
31
+ ]
32
+ },
33
+ {
34
+ "description": "Save new products in your shopping cart",
35
+ "method": "POST",
36
+ "url": "/shopping-cart",
37
+ "request": {
38
+ "headers": {
39
+ "Content-Type": "application/json"
40
+ },
41
+ "body": "{\n \"product\": \"1AB23ORM\",\n \"quantity\": 2\n}"
42
+ },
43
+ "responses": [
44
+ {
45
+ "status": 201,
46
+ "headers": {
47
+ "Content-Type": "application/json"
48
+ },
49
+ "body": "{\n \"status\": \"created\",\n \"url\": \"/shopping-cart/2\"\n}"
50
+ },
51
+ {
52
+ "status": 401,
53
+ "headers": {
54
+ "Content-Type": "application/json; charset=utf-8"
55
+ },
56
+ "body": "{\n \"message\": \"You have not provided proper request token\"\n}"
57
+ }
58
+ ]
59
+ }
60
+ ]
61
+ },
62
+ {
63
+ "name": "Payment Resources",
64
+ "description": null,
65
+ "resources": [
66
+ {
67
+ "description": "This resource allows you to submit payment information to process your *shopping cart* items",
68
+ "method": "POST",
69
+ "url": "/payment",
70
+ "request": {
71
+ "headers": {},
72
+ "body": "{\n \"cc\": \"12345678900\",\n \"cvc\": \"123\",\n \"expiry\": \"0112\"\n}"
73
+ },
74
+ "responses": [
75
+ {
76
+ "status": 200,
77
+ "headers": {},
78
+ "body": "{\n \"receipt\": \"/payment/receipt/1\"\n}"
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ "description": null,
84
+ "method": "POST",
85
+ "url": "/resource",
86
+ "request": {
87
+ "headers": {
88
+ "Content-Type": "application/json"
89
+ },
90
+ "body": "{\n \"a\": \"b\",\n \"c\": \"0\"\n}"
91
+ },
92
+ "responses": [
93
+ {
94
+ "status": 200,
95
+ "headers": {},
96
+ "body": "{\n \"status\": \"ok\"\n}"
97
+ }
98
+ ]
99
+ }
100
+ ]
101
+ }
102
+ ],
103
+ "validations": [
104
+ {
105
+ "method": "POST",
106
+ "url": "/resource",
107
+ "body": "{\n \"request\": {\n \"type\": \"object\",\n \"properties\": {\n \"a\": {\n \"type\": \"string\",\n \"format\": \"alphanumeric\"\n },\n \"c\": {\n \"type\": \"integer\"\n }\n }\n },\n \"response\": {\n \"type\": \"object\",\n \"properties\": {\n \"status\": {\n \"type\": \"string\",\n \"format\": \"alphanumeric\"\n }\n }\n }\n}"
108
+ }
109
+ ]
110
+ }
111
+ """
112
+
113
+ Given a file named "apiblueprint_ast.json" with:
114
+ """
115
+ {
116
+ "_version": "1.0",
117
+ "metadata": {
118
+ "HOST": {
119
+ "value": "http://www.google.com/"
120
+ }
121
+ },
122
+ "name": "Sample API v2",
123
+ "description": "Welcome to our sample API documentation. All comments can be written in (support [Markdown](http://daringfireball.net/projects/markdown/syntax) syntax)",
124
+ "resourceGroups": [
125
+ {
126
+ "name": "Shopping Cart Resources",
127
+ "description": "The following is a section of resources related to the shopping cart",
128
+ "resources": [
129
+ {
130
+ "name": null,
131
+ "description": null,
132
+ "uriTemplate": "/shopping-cart",
133
+ "model": null,
134
+ "parameters": null,
135
+ "headers": null,
136
+ "actions": [
137
+ {
138
+ "name": null,
139
+ "description": "List products added into your shopping-cart. (comment block again in Markdown)",
140
+ "method": "GET",
141
+ "parameters": null,
142
+ "headers": null,
143
+ "examples": [
144
+ {
145
+ "name": null,
146
+ "description": null,
147
+ "requests": null,
148
+ "responses": [
149
+ {
150
+ "name": "200",
151
+ "description": null,
152
+ "headers": {
153
+ "Content-Type": {
154
+ "value": "application/json"
155
+ }
156
+ },
157
+ "body": "{\n \"items\": [\n {\n \"url\": \"/shopping-cart/1\",\n \"product\": \"2ZY48XPZ\",\n \"quantity\": 1,\n \"name\": \"New socks\",\n \"price\": 1.25\n }\n ]\n}",
158
+ "schema": null
159
+ }
160
+ ]
161
+ }
162
+ ]
163
+ },
164
+ {
165
+ "name": null,
166
+ "description": "Save new products in your shopping cart",
167
+ "method": "POST",
168
+ "parameters": null,
169
+ "headers": null,
170
+ "examples": [
171
+ {
172
+ "name": null,
173
+ "description": null,
174
+ "requests": [
175
+ {
176
+ "name": null,
177
+ "description": null,
178
+ "headers": {
179
+ "Content-Type": {
180
+ "value": "application/json"
181
+ }
182
+ },
183
+ "body": "{\n \"product\": \"1AB23ORM\",\n \"quantity\": 2\n}",
184
+ "schema": null
185
+ }
186
+ ],
187
+ "responses": [
188
+ {
189
+ "name": "201",
190
+ "description": null,
191
+ "headers": {
192
+ "Content-Type": {
193
+ "value": "application/json"
194
+ }
195
+ },
196
+ "body": "{\n \"status\": \"created\",\n \"url\": \"/shopping-cart/2\"\n}",
197
+ "schema": null
198
+ },
199
+ {
200
+ "name": "401",
201
+ "description": null,
202
+ "headers": {
203
+ "Content-Type": {
204
+ "value": "application/json; charset=utf-8"
205
+ }
206
+ },
207
+ "body": "{\n \"message\": \"You have not provided proper request token\"\n}",
208
+ "schema": null
209
+ }
210
+ ]
211
+ }
212
+ ]
213
+ }
214
+ ]
215
+ }
216
+ ]
217
+ },
218
+ {
219
+ "name": "Payment Resources",
220
+ "description": null,
221
+ "resources": [
222
+ {
223
+ "name": null,
224
+ "description": null,
225
+ "uriTemplate": "/payment",
226
+ "model": null,
227
+ "parameters": null,
228
+ "headers": null,
229
+ "actions": [
230
+ {
231
+ "name": null,
232
+ "description": "This resource allows you to submit payment information to process your *shopping cart* items",
233
+ "method": "POST",
234
+ "parameters": null,
235
+ "headers": null,
236
+ "examples": [
237
+ {
238
+ "name": null,
239
+ "description": null,
240
+ "requests": [
241
+ {
242
+ "name": null,
243
+ "description": null,
244
+ "headers": null,
245
+ "body": "{\n \"cc\": \"12345678900\",\n \"cvc\": \"123\",\n \"expiry\": \"0112\"\n}",
246
+ "schema": null
247
+ }
248
+ ],
249
+ "responses": [
250
+ {
251
+ "name": "200",
252
+ "description": null,
253
+ "headers": null,
254
+ "body": "{\n \"receipt\": \"/payment/receipt/1\"\n}",
255
+ "schema": null
256
+ }
257
+ ]
258
+ }
259
+ ]
260
+ }
261
+ ]
262
+ },
263
+ {
264
+ "name": null,
265
+ "description": null,
266
+ "uriTemplate": "/resource",
267
+ "model": null,
268
+ "parameters": null,
269
+ "headers": null,
270
+ "actions": [
271
+ {
272
+ "name": null,
273
+ "description": null,
274
+ "method": "POST",
275
+ "parameters": null,
276
+ "headers": null,
277
+ "examples": [
278
+ {
279
+ "name": null,
280
+ "description": null,
281
+ "requests": [
282
+ {
283
+ "name": null,
284
+ "description": null,
285
+ "headers": {
286
+ "Content-Type": {
287
+ "value": "application/json"
288
+ }
289
+ },
290
+ "body": "{\n \"a\": \"b\",\n \"c\": \"0\"\n}",
291
+ "schema": "{\"type\":\"object\",\"properties\":{\"a\":{\"type\":\"string\",\"format\":\"alphanumeric\"},\"c\":{\"type\":\"integer\"}}}"
292
+ }
293
+ ],
294
+ "responses": [
295
+ {
296
+ "name": "200",
297
+ "description": null,
298
+ "headers": null,
299
+ "body": "{\n \"status\": \"ok\"\n}",
300
+ "schema": "{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\",\"format\":\"alphanumeric\"}}}"
301
+ }
302
+ ]
303
+ }
304
+ ]
305
+ }
306
+ ]
307
+ }
308
+ ]
309
+ }
310
+ ]
311
+ }
312
+ """
313
+
314
+ Scenario: Convert Legacy Apiary Blueprint AST into API Blueprint AST
315
+ When I run `apiary_blueprint_convertor legacy_ast.json`
316
+ Then the output should contain the content of file "apiblueprint_ast.json"
317
+
318
+ Scenario: Convert Legacy Apiary Blueprint AST on STDIN into API Blueprint AST
319
+ When I run `apiary_blueprint_convertor` interactively
320
+ When I pipe in the file "legacy_ast.json"
321
+ Then the output should contain the content of file "apiblueprint_ast.json"
@@ -0,0 +1,8 @@
1
+ Then /^the output should contain the content of 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,65 @@
1
+ require 'optparse'
2
+ require 'apiary_blueprint_convertor/version'
3
+ require 'apiary_blueprint_convertor/convertor'
4
+
5
+ module ApiaryBlueprintConvertor
6
+
7
+ class CLI
8
+
9
+ attr_reader :command
10
+
11
+ def self.start
12
+ cli = CLI.new
13
+ options = cli.parse_options!(ARGV)
14
+ cli.runCommand(ARGV, options)
15
+ end
16
+
17
+ def runCommand(args, options)
18
+ command = :convert if args.first.nil? || @command.nil?
19
+ command = @command if @command
20
+
21
+ case command
22
+ when :convert
23
+ Convertor.convert(args.first)
24
+ when :version
25
+ puts ApiaryBlueprintConvertor::VERSION
26
+ else
27
+ CLI.help
28
+ end
29
+ end
30
+
31
+ def parse_options!(args)
32
+ @command = nil
33
+ options = {}
34
+ options_parser = OptionParser.new do |opts|
35
+ opts.on('-v', '--version') do
36
+ @command = :version
37
+ end
38
+
39
+ opts.on( '-h', '--help') do
40
+ @command = :help
41
+ end
42
+ end
43
+
44
+ options_parser.parse!
45
+ options
46
+
47
+ rescue OptionParser::InvalidOption => e
48
+ puts e
49
+ CLI.help
50
+ exit 1
51
+ end
52
+
53
+ def self.help
54
+ puts "Usage: apiary_blueprint_convertor <legacy ast file>"
55
+ puts "\nConvert Legacy Apiary Blueprint AST into API Blueprint AST (JSON)."
56
+ puts "If no <legacy ast file> is specified 'apiary_blueprint_convertor' will listen on stdin."
57
+
58
+ puts "\nOptions:\n\n"
59
+ puts "\t-h, --help Show this help"
60
+ puts "\t-v, --version Show version"
61
+ puts "\n"
62
+ end
63
+ end
64
+
65
+ end
@@ -0,0 +1,319 @@
1
+ require 'json'
2
+ require 'object'
3
+
4
+ module ApiaryBlueprintConvertor
5
+
6
+ class Convertor
7
+
8
+ API_BLUEPRONT_AST_VERSION = "1.0"
9
+
10
+ def self.read_file(file)
11
+ unless File.readable?(file)
12
+ abort "Unable to read input ast file: #{file.inspect}"
13
+ end
14
+ input = File.read(file)
15
+ end
16
+
17
+ # Read file / input and convert the AST
18
+ def self.convert(file = nil)
19
+ # Read input
20
+ input = nil
21
+ if file.nil?
22
+ input = $stdin.read
23
+ else
24
+ input = self.read_file(file)
25
+ end
26
+
27
+ if input.blank?
28
+ puts "Empty input, bailing out!"
29
+ exit
30
+ end
31
+
32
+ legacy_ast = JSON.parse(input).deep_symbolize_keys
33
+
34
+ # Top level API Blueprint Template
35
+ blueprint_ast = {
36
+ :_version => API_BLUEPRONT_AST_VERSION,
37
+ :metadata => nil,
38
+ :name => nil,
39
+ :description => nil,
40
+ :resourceGroups => nil
41
+ }
42
+
43
+ # Run the conversion
44
+ convert_blueprint(legacy_ast, blueprint_ast)
45
+
46
+ # Print output to stdou
47
+ puts JSON.pretty_generate(blueprint_ast)
48
+
49
+ rescue JSON::ParserError => e
50
+ abort("unable to parse input JSON: #{e}")
51
+ end
52
+
53
+ # Convert AST root
54
+ def self.convert_blueprint(legacy_ast, blueprint_ast)
55
+
56
+ # Location key
57
+ convert_location(legacy_ast[:location], blueprint_ast) if legacy_ast[:location]
58
+
59
+ # Name key
60
+ blueprint_ast[:name] = legacy_ast[:name]
61
+
62
+ # Description
63
+ blueprint_ast[:description] = legacy_ast[:description]
64
+
65
+ # Sections
66
+ convert_sections(legacy_ast[:sections], legacy_ast[:validations], blueprint_ast)
67
+
68
+ # NOTE: Validations are processed in `convert_sections`.
69
+ end
70
+
71
+ # Convert Location / Metadata key
72
+ # \param location ... location to convert
73
+ # \param blueprint_ast ... output AST
74
+ def self.convert_location(legacy_location, blueprint_ast)
75
+ if legacy_location.blank?
76
+ blueprint_ast[:metadata] = nil
77
+ return
78
+ end
79
+
80
+ blueprint_ast[:metadata] = {
81
+ :HOST => {
82
+ :value => "#{legacy_location}"
83
+ }
84
+ }
85
+ end
86
+
87
+ # Convert array of blueprint sections
88
+ # \param legacy_sections ... sections to convert
89
+ # \param legacy_validations ... legacy validations
90
+ # \param blueprint_ast ... output AST
91
+ def self.convert_sections(legacy_sections, legacy_validations, blueprint_ast)
92
+ resourceGroups = [];
93
+ legacy_sections.each do |legact_section|
94
+ group = {
95
+ :name => legact_section[:name],
96
+ :description => legact_section[:description],
97
+ :resources => nil
98
+ }
99
+
100
+ convert_resources(legact_section[:resources], legacy_validations, group)
101
+ resourceGroups << group
102
+ end
103
+
104
+ blueprint_ast[:resourceGroups] = resourceGroups unless resourceGroups.blank?
105
+ end
106
+
107
+ # Convert all resources of a resource group
108
+ # \param legacy_resources ... resources to convert
109
+ # \param legacy_validations ... legacy validations
110
+ # \param resource_group ... output resource group
111
+ def self.convert_resources(legacy_resources, legacy_validations, resource_group)
112
+ resources = [];
113
+ legacy_resources.each do |legacy_resource|
114
+
115
+ resource = find_resource(resources, legacy_resource[:url])
116
+
117
+ if (resource)
118
+ # Existing Resource
119
+ add_resource_action(legacy_resource, legacy_validations, resource)
120
+ else
121
+ # New Resource
122
+ resource = {
123
+ :name => nil,
124
+ :description => nil,
125
+ :uriTemplate => legacy_resource[:url],
126
+ :model => nil,
127
+ :parameters => nil,
128
+ :headers => nil,
129
+ :actions => nil
130
+ }
131
+
132
+ add_resource_action(legacy_resource, legacy_validations, resource)
133
+ resources << resource
134
+ end
135
+ end
136
+
137
+ resource_group[:resources] = resources unless resources.blank?
138
+ end
139
+
140
+ # Look for a resource by URL in array of resources
141
+ # \returns the matching resource or nil
142
+ def self.find_resource(resources, uri_template)
143
+ return nil if resources.blank?
144
+ matches = resources.select { |resource| resource[:uriTemplate] == uri_template }
145
+ return matches.blank? ? nil : matches.first
146
+ end
147
+
148
+ # Add an action entry in resources
149
+ # \param legacy_resource ... resource with action to be converted
150
+ # \param legacy_validations ... legacy validations
151
+ # \param resource ... output resource to recieve the action
152
+ def self.add_resource_action(legacy_resource, legacy_validations, resource)
153
+
154
+ action = find_action(resource[:actions], legacy_resource[:method])
155
+ if action
156
+ $stderr.write "Ignoring duplicate action definiton for resource '#{resource[:uriTemplate]}' and request method '#{action[:method]}'\n"
157
+ return
158
+ end
159
+
160
+ action = {
161
+ :name => nil,
162
+ :description => legacy_resource[:description],
163
+ :method => legacy_resource[:method],
164
+ :parameters => nil,
165
+ :headers => nil,
166
+ :examples => nil
167
+ }
168
+
169
+ add_action_example(legacy_resource, legacy_validations, action)
170
+
171
+ resource[:actions] = Array.new if resource[:actions].nil?
172
+ resource[:actions] << action
173
+ end
174
+
175
+ # Look for an action by Method in array of actions
176
+ # \returns the matching action or nil
177
+ def self.find_action(actions, method)
178
+ return nil if actions.blank?
179
+ matches = actions.select { |action| action[:method] == method }
180
+ return matches.blank? ? nil : matches.first
181
+ end
182
+
183
+ # Add an example entry in action
184
+ # \param legacy_resource ... resource with example to be converted
185
+ # \param legacy_validations ... legacy validations
186
+ # \param action ... output action to recieve the example
187
+ def self.add_action_example(legacy_resource, legacy_validations, action)
188
+ example = {
189
+ :name => nil,
190
+ :description => nil,
191
+ :requests => nil,
192
+ :responses => nil
193
+ }
194
+
195
+ schema = resource_schema(legacy_resource, legacy_validations)
196
+
197
+ # Convert Request
198
+ if legacy_resource[:request] &&
199
+ !(legacy_resource[:request][:headers].blank? && legacy_resource[:request][:body].blank?)
200
+
201
+ request = {
202
+ :name => nil,
203
+ :description => nil,
204
+ :headers => create_headers_hash(legacy_resource[:request][:headers]),
205
+ :body => legacy_resource[:request][:body],
206
+ :schema => (schema) ? schema[:request] : nil
207
+ }
208
+ example[:requests] = Array.new
209
+ example[:requests] << request
210
+ end
211
+
212
+ # Convert resources
213
+ unless legacy_resource[:responses].blank?
214
+ example[:responses] = Array.new
215
+
216
+ legacy_resource[:responses].each do |legacy_response|
217
+ response = {
218
+ :name => "#{legacy_response[:status]}",
219
+ :description => nil,
220
+ :headers => create_headers_hash(legacy_response[:headers]),
221
+ :body => legacy_response[:body],
222
+ :schema => (schema) ? schema[:response] : nil
223
+ }
224
+
225
+ example[:responses] << response
226
+ end
227
+ end
228
+
229
+ action[:examples] = Array.new if action[:examples].nil?
230
+ action[:examples] << example
231
+ end
232
+
233
+ # Create an API Blueprint header hash
234
+ # from legacy headers hash
235
+ def self.create_headers_hash(legacy_headers)
236
+ return nil if legacy_headers.blank?
237
+ headers = {}
238
+
239
+ legacy_headers.each do |key, value|
240
+ headers[key] = {
241
+ :value => value
242
+ }
243
+ end
244
+
245
+ headers
246
+ end
247
+
248
+ # Returns legacy resource validation if exists, nil otherwise
249
+ def self.legacy_resource_validation(legacy_resource, legacy_validations)
250
+ return nil if legacy_validations.blank?
251
+
252
+ matches = legacy_validations.select do |legacy_validation|
253
+ (legacy_validation[:url] == legacy_resource[:url] &&
254
+ legacy_validation[:method] == legacy_resource[:method])
255
+ end
256
+
257
+ return nil if matches.blank? || matches.first[:body].blank?
258
+
259
+ matches.first[:body]
260
+ end
261
+
262
+ # Attempt to retrieve request and response schema from legacy validations
263
+ # for given legacy resource
264
+ def self.resource_schema(legacy_resource, legacy_validations)
265
+
266
+ validation = legacy_resource_validation(legacy_resource, legacy_validations)
267
+ return nil if validation.blank?
268
+
269
+ # Attempt to parse validation
270
+ validation_hash = JSON.parse(validation)
271
+ validation_hash = validation_hash.deep_symbolize_keys
272
+
273
+ schema = {
274
+ :request => nil,
275
+ :response => nil
276
+ }
277
+
278
+ if validation_hash.nil?
279
+ schema[:request] = validation
280
+ return schema
281
+ end
282
+
283
+ if validation_hash[:request]
284
+ if validation_hash[:request].is_a?(Hash)
285
+ schema[:request] = validation_hash[:request].to_json
286
+ else
287
+ schema[:request] = validation_hash[:request]
288
+ end
289
+ end
290
+
291
+ if validation_hash[:response]
292
+ if validation_hash[:response].is_a?(Hash)
293
+ schema[:response] = validation_hash[:response].to_json
294
+ else
295
+ schema[:response] = validation_hash[:response]
296
+ end
297
+ end
298
+
299
+ if validation_hash[:request].nil? && validation_hash[:response].nil?
300
+ schema[:request] = validation
301
+ end
302
+ return schema
303
+ rescue
304
+ return {
305
+ :request => validation,
306
+ :response => nil
307
+ }
308
+ end
309
+ end
310
+ end
311
+
312
+
313
+
314
+
315
+
316
+
317
+
318
+
319
+
@@ -0,0 +1,3 @@
1
+ module ApiaryBlueprintConvertor
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,5 @@
1
+ require "apiary_blueprint_convertor/version"
2
+
3
+ module ApiaryBlueprintConvertor
4
+ # Your code goes here...
5
+ end
data/lib/object.rb ADDED
@@ -0,0 +1,14 @@
1
+ class Object
2
+
3
+ # Symbolizes keys of a hash
4
+ def deep_symbolize_keys
5
+ return self.inject({}){|memo, (k,v)| memo[k.to_sym] = v.deep_symbolize_keys; memo} if self.is_a? Hash
6
+ return self.inject([]){|memo, v | memo << v.deep_symbolize_keys; memo} if self.is_a? Array
7
+ return self
8
+ end
9
+
10
+ # Returns true if object is nil or empty, false otherwise
11
+ def blank?
12
+ respond_to?(:empty?) ? empty? : !self
13
+ end
14
+ end
@@ -0,0 +1,241 @@
1
+ require 'minitest/autorun'
2
+ require 'apiary_blueprint_convertor/convertor'
3
+
4
+ class ConvertorTest < Minitest::Test
5
+ include ApiaryBlueprintConvertor
6
+
7
+ VALIDATIONS_AST = [{
8
+ :url => "/resource2",
9
+ :method => "POST",
10
+ :body => "{ \"request\": \"42\", \"response\": \"0xdeadbeef\" }"
11
+ },
12
+ {
13
+ :url => "/resource1",
14
+ :method => "GET",
15
+ :body => "GOOD STUFF"
16
+ }
17
+ ]
18
+
19
+ REQUEST_AST = {
20
+ :headers => nil,
21
+ :body => "A"
22
+ }
23
+
24
+ RESPONSES_AST = [{
25
+ :status => 200,
26
+ :headers => {
27
+ :'Content-Type' => "text/plain"
28
+ },
29
+ :body => "Hello World!"
30
+ },
31
+ {
32
+ :status => 404,
33
+ :headers => {
34
+ :'Content-Type' => "application/json",
35
+ :'X-Header' => "42"
36
+ },
37
+ :body => "42 not found."
38
+ }
39
+ ]
40
+
41
+ RESOURCES_AST = [{
42
+ :description => "Ipsum Lorem",
43
+ :method => "GET",
44
+ :url => "/resource1",
45
+ :request => REQUEST_AST,
46
+ :responses => []
47
+ },
48
+ {
49
+ :description => nil,
50
+ :method => "POST",
51
+ :url => "/resource2",
52
+ :request => REQUEST_AST,
53
+ :responses => RESPONSES_AST
54
+ },
55
+ {
56
+ :description => nil,
57
+ :method => "PUT",
58
+ :url => "/resource1",
59
+ :request => nil,
60
+ :responses => []
61
+ }
62
+ ]
63
+
64
+ SECTIONS_AST = [{
65
+ :name => "Section One",
66
+ :description => "Lorem Ipsum",
67
+ :resources => []
68
+ },
69
+ {
70
+ :name => "Section TWO",
71
+ :description => nil,
72
+ :resources => RESOURCES_AST
73
+ }
74
+ ]
75
+
76
+ BLUEPRINT_AST = {
77
+ :location => "http://google.com",
78
+ :name => "API NAME",
79
+ :description => "Lorem Ipsum",
80
+ :sections => SECTIONS_AST,
81
+ :validations => VALIDATIONS_AST
82
+ }
83
+
84
+ def test_convert_location
85
+ blueprint_ast = {}
86
+ Convertor.convert_location("http://google.com", blueprint_ast)
87
+
88
+ assert_equal 1, blueprint_ast.keys.length
89
+ assert_equal :metadata, blueprint_ast.keys.first
90
+
91
+ assert_equal 1, blueprint_ast[:metadata].keys.length
92
+ assert_equal :HOST, blueprint_ast[:metadata].keys.first
93
+
94
+ assert_equal 1, blueprint_ast[:metadata][:HOST].keys.length
95
+ assert_equal :value, blueprint_ast[:metadata][:HOST].keys.first
96
+
97
+ assert_equal "http://google.com", blueprint_ast[:metadata][:HOST][:value]
98
+ end
99
+
100
+ def test_convert_blueprint
101
+ blueprint_ast = {}
102
+ Convertor.convert_blueprint(BLUEPRINT_AST, blueprint_ast)
103
+
104
+ assert_equal 4, blueprint_ast.keys.length
105
+
106
+ assert blueprint_ast[:metadata]
107
+ assert_equal "API NAME", blueprint_ast[:name]
108
+ assert_equal "Lorem Ipsum", blueprint_ast[:description]
109
+ assert blueprint_ast[:resourceGroups]
110
+ assert_equal 2, blueprint_ast[:resourceGroups].length
111
+
112
+ #puts "\n\n>>#{JSON.pretty_generate(blueprint_ast)}\n"
113
+ end
114
+
115
+ def test_convert_sections
116
+ blueprint_ast = {}
117
+ Convertor.convert_sections(SECTIONS_AST, {}, blueprint_ast)
118
+
119
+ assert_equal 1, blueprint_ast.keys.length
120
+ assert_equal :resourceGroups, blueprint_ast.keys.first
121
+ assert_instance_of Array, blueprint_ast[:resourceGroups]
122
+ assert_equal 2, blueprint_ast[:resourceGroups].length
123
+
124
+ assert_equal "Section One", blueprint_ast[:resourceGroups][0][:name]
125
+ assert_equal "Lorem Ipsum", blueprint_ast[:resourceGroups][0][:description]
126
+ assert_equal nil, blueprint_ast[:resourceGroups][0][:resources]
127
+
128
+ assert_equal "Section TWO", blueprint_ast[:resourceGroups][1][:name]
129
+ assert_equal nil, blueprint_ast[:resourceGroups][1][:description]
130
+ assert_instance_of Array, blueprint_ast[:resourceGroups][1][:resources]
131
+ assert_equal 2, blueprint_ast[:resourceGroups][1][:resources].length
132
+ end
133
+
134
+ def test_convert_resources
135
+ group_ast = {}
136
+ Convertor.convert_resources(RESOURCES_AST, {}, group_ast)
137
+
138
+ assert_equal 1, group_ast.keys.length
139
+ assert_equal :resources, group_ast.keys.first
140
+ assert_instance_of Array, group_ast[:resources]
141
+ assert_equal 2, group_ast[:resources].length
142
+
143
+ assert_equal nil, group_ast[:resources][0][:name]
144
+ assert_equal nil, group_ast[:resources][0][:description]
145
+ assert_equal "/resource1", group_ast[:resources][0][:uriTemplate]
146
+ assert_equal nil, group_ast[:resources][0][:model]
147
+ assert_equal nil, group_ast[:resources][0][:parameters]
148
+ assert_equal nil, group_ast[:resources][0][:headers]
149
+ assert group_ast[:resources][0][:actions]
150
+ assert_equal 2, group_ast[:resources][0][:actions].length
151
+
152
+ assert_equal nil, group_ast[:resources][1][:name]
153
+ assert_equal nil, group_ast[:resources][1][:description]
154
+ assert_equal "/resource2", group_ast[:resources][1][:uriTemplate]
155
+ assert_equal nil, group_ast[:resources][1][:model]
156
+ assert_equal nil, group_ast[:resources][1][:parameters]
157
+ assert_equal nil, group_ast[:resources][1][:headers]
158
+ assert group_ast[:resources][1][:actions]
159
+ assert_equal 1, group_ast[:resources][1][:actions].length
160
+ end
161
+
162
+ def test_add_resource_action
163
+ resource_ast = {}
164
+ Convertor.add_resource_action(RESOURCES_AST[0], {}, resource_ast)
165
+
166
+ assert resource_ast[:actions], "resource actions exists"
167
+ assert_equal 1, resource_ast[:actions].length
168
+ assert_equal "GET", resource_ast[:actions][0][:method]
169
+ assert_equal "Ipsum Lorem", resource_ast[:actions][0][:description]
170
+ assert_equal nil, resource_ast[:actions][0][:parameters]
171
+ assert_equal nil, resource_ast[:actions][0][:headers]
172
+ assert_instance_of Array, resource_ast[:actions][0][:examples]
173
+ end
174
+
175
+ def test_add_action_example
176
+ action_ast = {}
177
+ Convertor.add_action_example(RESOURCES_AST[1], VALIDATIONS_AST, action_ast)
178
+
179
+ assert_instance_of Array, action_ast[:examples]
180
+ assert_equal 1, action_ast[:examples].length
181
+ assert_equal nil, action_ast[:examples][0][:name]
182
+ assert_equal nil, action_ast[:examples][0][:description]
183
+
184
+ assert_instance_of Array, action_ast[:examples][0][:requests]
185
+ assert_equal 1, action_ast[:examples][0][:requests].length
186
+ assert_equal nil, action_ast[:examples][0][:requests][0][:name]
187
+ assert_equal nil, action_ast[:examples][0][:requests][0][:description]
188
+ assert_equal nil, action_ast[:examples][0][:requests][0][:headers]
189
+ assert_equal "A", action_ast[:examples][0][:requests][0][:body]
190
+ assert_equal "42", action_ast[:examples][0][:requests][0][:schema]
191
+
192
+ assert_instance_of Array, action_ast[:examples][0][:responses]
193
+ assert_equal 2, action_ast[:examples][0][:responses].length
194
+
195
+ assert_equal "200", action_ast[:examples][0][:responses][0][:name]
196
+ assert_equal nil, action_ast[:examples][0][:responses][0][:description]
197
+
198
+ assert_instance_of Hash, action_ast[:examples][0][:responses][0][:headers]
199
+ assert_equal 1, action_ast[:examples][0][:responses][0][:headers].keys.length
200
+ assert_equal :'Content-Type', action_ast[:examples][0][:responses][0][:headers].keys[0]
201
+ assert_instance_of Hash, action_ast[:examples][0][:responses][0][:headers][:'Content-Type']
202
+ assert_equal 1, action_ast[:examples][0][:responses][0][:headers][:'Content-Type'].keys.length
203
+ assert_equal :value, action_ast[:examples][0][:responses][0][:headers][:'Content-Type'].keys[0]
204
+ assert_equal "text/plain", action_ast[:examples][0][:responses][0][:headers][:'Content-Type'][:value]
205
+
206
+ assert_equal "Hello World!", action_ast[:examples][0][:responses][0][:body]
207
+ assert_equal "0xdeadbeef", action_ast[:examples][0][:responses][0][:schema]
208
+
209
+ assert_equal "404", action_ast[:examples][0][:responses][1][:name]
210
+ assert_equal nil, action_ast[:examples][0][:responses][1][:description]
211
+
212
+ assert_instance_of Hash, action_ast[:examples][0][:responses][1][:headers]
213
+ assert_equal 2, action_ast[:examples][0][:responses][1][:headers].keys.length
214
+
215
+ assert_equal :'Content-Type', action_ast[:examples][0][:responses][1][:headers].keys[0]
216
+ assert_instance_of Hash, action_ast[:examples][0][:responses][1][:headers][:'Content-Type']
217
+ assert_equal 1, action_ast[:examples][0][:responses][1][:headers][:'Content-Type'].keys.length
218
+ assert_equal :value, action_ast[:examples][0][:responses][1][:headers][:'Content-Type'].keys[0]
219
+ assert_equal "application/json", action_ast[:examples][0][:responses][1][:headers][:'Content-Type'][:value]
220
+
221
+ assert_equal :'X-Header', action_ast[:examples][0][:responses][1][:headers].keys[1]
222
+ assert_instance_of Hash, action_ast[:examples][0][:responses][1][:headers][:'X-Header']
223
+ assert_equal 1, action_ast[:examples][0][:responses][1][:headers][:'X-Header'].keys.length
224
+ assert_equal :value, action_ast[:examples][0][:responses][1][:headers][:'X-Header'].keys[0]
225
+ assert_equal "42", action_ast[:examples][0][:responses][1][:headers][:'X-Header'][:value]
226
+
227
+ assert_equal "42 not found.", action_ast[:examples][0][:responses][1][:body]
228
+ assert_equal "0xdeadbeef", action_ast[:examples][0][:responses][1][:schema]
229
+ end
230
+ end
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
240
+
241
+
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apiary_blueprint_convertor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Zdenek Nemec
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cucumber
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Convert legacy Apiary Blueprint AST into API Blueprint AST (JSON).
70
+ email:
71
+ - z@apiary.io
72
+ executables:
73
+ - apiary_blueprint_convertor
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - apiary_blueprint_convertor.gemspec
85
+ - bin/apiary_blueprint_convertor
86
+ - features/convert.feature
87
+ - features/step_definitions/file_content_step.rb
88
+ - features/support/setup.rb
89
+ - lib/apiary_blueprint_convertor.rb
90
+ - lib/apiary_blueprint_convertor/cli.rb
91
+ - lib/apiary_blueprint_convertor/convertor.rb
92
+ - lib/apiary_blueprint_convertor/version.rb
93
+ - lib/object.rb
94
+ - test/convertor_test.rb
95
+ homepage: ''
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.2.0
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Apiary Blueprint AST convertor.
119
+ test_files:
120
+ - features/convert.feature
121
+ - features/step_definitions/file_content_step.rb
122
+ - features/support/setup.rb
123
+ - test/convertor_test.rb