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