matter_compiler 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,82 @@
1
+ require 'optparse'
2
+ require 'matter_compiler/composer'
3
+ require 'matter_compiler/version'
4
+
5
+ module MatterCompiler
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 = :compose if args.first.nil? || @command.nil?
19
+ command = @command if @command
20
+
21
+ if command == :compose && args.first.nil? && (options[:format].nil? || options[:format] == :unknown_ast)
22
+
23
+ print options[:format] ? "invalid value of" : "missing"
24
+ print " '--format option'\n\n"
25
+
26
+ CLI.help
27
+ exit 1
28
+ end
29
+
30
+ case command
31
+ when :compose
32
+ Composer.compose(args.first, options[:format])
33
+ when :version
34
+ puts MatterCompiler::VERSION
35
+ else
36
+ CLI.help
37
+ end
38
+
39
+ end
40
+
41
+ def parse_options!(args)
42
+ @command = nil
43
+ options = {}
44
+ options_parser = OptionParser.new do |opts|
45
+ opts.on('-f', '--format (yaml|json)') do |format|
46
+ options[:format] = Composer.parse_format(format)
47
+ @command = :compose
48
+ end
49
+
50
+ opts.on('-v', '--version') do
51
+ @command = :version
52
+ end
53
+
54
+ opts.on( '-h', '--help') do
55
+ @command = :help
56
+ end
57
+ end
58
+
59
+ options_parser.parse!
60
+ options
61
+
62
+ rescue OptionParser::InvalidOption => e
63
+ puts e
64
+ CLI.help
65
+ exit 1
66
+ end
67
+
68
+ def self.help
69
+ puts "Usage: matter_compiler [options] [<ast file>]"
70
+ puts "\nCompose an API blueprint from its AST."
71
+ puts "If no <ast file> is specified 'matter_compiler' will listen on stdin."
72
+
73
+ puts "\nOptions:\n\n"
74
+ puts "\t-f, --format (yaml|json) Set the AST media-type format of the input"
75
+ puts "\t-h, --help Show this help"
76
+ puts "\t-v, --version Show version"
77
+ puts "\n"
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,89 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'matter_compiler/blueprint'
4
+ require 'object'
5
+
6
+ module MatterCompiler
7
+
8
+ class Composer
9
+
10
+ # Read AST file
11
+ def self.read_file(file)
12
+ unless File.readable?(file)
13
+ abort "Unable to read input ast file: #{file.inspect}"
14
+ end
15
+ input = File.read(file)
16
+ end
17
+
18
+ # Read AST from stdin.
19
+ def self.read_stdin
20
+ input = $stdin.read
21
+ end
22
+
23
+ # Parse format from string
24
+ def self.parse_format(format)
25
+ format.downcase!
26
+ case format
27
+ when "json"
28
+ return :json_ast
29
+ when "yml"
30
+ when "yaml"
31
+ return :yaml_ast
32
+ else
33
+ return :unknown_ast
34
+ end
35
+ end
36
+
37
+ # Guess format from filename extension.
38
+ def self.guess_format(file)
39
+ extension = File.extname(file)
40
+ if extension.length < 1
41
+ return :unknown_ast
42
+ end
43
+
44
+ self.parse_format(extension[1..-1])
45
+ end
46
+
47
+ # Compose API Blueprint from an AST file.
48
+ # Returns a string with composed API Blueprint.
49
+ def self.compose(file = nil, format = nil)
50
+ # Read input
51
+ input = nil
52
+ if file.nil?
53
+ input = self.read_stdin
54
+ else
55
+ input = self.read_file(file)
56
+ end
57
+
58
+ if input.blank?
59
+ puts "Empty input"
60
+ exit
61
+ end
62
+
63
+ # Parse input
64
+ input_format = format ? format : self.guess_format(file)
65
+ ast_hash = nil;
66
+ case input_format
67
+ when :json_ast
68
+ ast_hash = JSON.parse(input).deep_symbolize_keys
69
+ when :yaml_ast
70
+ ast_hash = YAML.load(input).deep_symbolize_keys
71
+ else
72
+ abort "Undefined input format"
73
+ end
74
+
75
+ # Check version of the AST
76
+ unless Blueprint::SUPPORTED_VERSIONS.include?(ast_hash[Blueprint::VERSION_KEY].to_s)
77
+ abort("unsupported AST version: '#{ast_hash[Blueprint::VERSION_KEY]}'\n")
78
+ end
79
+
80
+ # Process the AST hash
81
+ blueprint = Blueprint.new(ast_hash)
82
+
83
+ # TODO: use $stdout for now, add serialization options later
84
+ puts blueprint.serialize
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,3 @@
1
+ module MatterCompiler
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,5 @@
1
+ require "matter_compiler/version"
2
+
3
+ module MatterCompiler
4
+ # Your code goes here...
5
+ end
data/lib/object.rb ADDED
@@ -0,0 +1,17 @@
1
+ # Essential extensions to base object class
2
+ # used throughout MatterCompiler
3
+
4
+ class Object
5
+
6
+ # Symbolizes keys of a hash
7
+ def deep_symbolize_keys
8
+ return self.inject({}){|memo, (k,v)| memo[k.to_sym] = v.deep_symbolize_keys; memo} if self.is_a? Hash
9
+ return self.inject([]){|memo, v | memo << v.deep_symbolize_keys; memo} if self.is_a? Array
10
+ return self
11
+ end
12
+
13
+ # Returns true if object is nil or empty, false otherwise
14
+ def blank?
15
+ respond_to?(:empty?) ? empty? : !self
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'matter_compiler/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "matter_compiler"
8
+ spec.version = MatterCompiler::VERSION
9
+ spec.authors = ["Zdenek Nemec"]
10
+ spec.email = ["z@apiary.io"]
11
+ spec.summary = %q{API Blueprint AST to API Blueprint convertor}
12
+ spec.description = %q{Matter Compiler is a API Blueprint AST Media Types to API Blueprint conversion tool. It composes an API blueprint from its serialzed AST media-type.}
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
+ # Use latest aruba for STDIN capabilities, see the Gemfile
27
+ # spec.add_development_dependency "aruba"
28
+ end
@@ -0,0 +1,48 @@
1
+ require 'minitest/autorun'
2
+ require 'matter_compiler/blueprint'
3
+ require_relative 'parameters_test'
4
+ require_relative 'headers_test'
5
+ require_relative 'transaction_example_test'
6
+
7
+ class ActionTest < Minitest::Unit::TestCase
8
+ AST_HASH = {
9
+ :name => "Into Action",
10
+ :description => "Dolor sit amet\n\n",
11
+ :method => "GET",
12
+ :parameters => ParametersTest::AST_HASH,
13
+ :headers => HeadersTest::AST_HASH,
14
+ :examples => [TransactionExampleTest::AST_HASH]
15
+ }
16
+
17
+ BLUEPRINT = \
18
+ %Q{### Into Action [GET]
19
+ Dolor sit amet
20
+
21
+ #{ParametersTest::BLUEPRINT}#{HeadersTest::BLUEPRINT}#{TransactionExampleTest::BLUEPRINT}}
22
+
23
+ def test_from_ast_hash
24
+ action = MatterCompiler::Action.new(ActionTest::AST_HASH)
25
+ assert_equal ActionTest::AST_HASH[:name], action.name
26
+ assert_equal ActionTest::AST_HASH[:description], action.description
27
+ assert_equal ActionTest::AST_HASH[:method], action.method
28
+
29
+ assert_instance_of MatterCompiler::Parameters, action.parameters
30
+ assert_instance_of Array, action.parameters.collection
31
+ assert_equal ParametersTest::AST_HASH.keys.length, action.parameters.collection.length
32
+
33
+ assert_instance_of MatterCompiler::Headers, action.headers
34
+ assert_instance_of Array, action.headers.collection
35
+ assert_equal HeadersTest::AST_HASH.keys.length, action.headers.collection.length
36
+
37
+ assert_instance_of Array, action.examples
38
+ assert_equal ActionTest::AST_HASH[:examples].length, action.examples.length
39
+ assert action.examples.length > 0
40
+ assert_instance_of MatterCompiler::TransactionExample, action.examples[0]
41
+ assert_equal TransactionExampleTest::AST_HASH[:name], action.examples[0].name
42
+ end
43
+
44
+ def test_serialize
45
+ action = MatterCompiler::Action.new(ActionTest::AST_HASH)
46
+ assert_equal ActionTest::BLUEPRINT, action.serialize
47
+ end
48
+ end
@@ -0,0 +1,43 @@
1
+ require 'minitest/autorun'
2
+ require 'matter_compiler/blueprint'
3
+ require_relative 'resource_group_test'
4
+ require_relative 'metadata_test'
5
+
6
+ class BlueprintTest < Minitest::Unit::TestCase
7
+ AST_HASH = {
8
+ :_version => 1.0,
9
+ :metadata => MetadataTest::AST_HASH,
10
+ :name => "My API",
11
+ :description => "Lorem Ipsum\n\n",
12
+ :resourceGroups => [ ResourceGroupTest::AST_HASH ]
13
+ }
14
+
15
+ BLUEPRINT = \
16
+ %Q{#{MetadataTest::BLUEPRINT}# My API
17
+ Lorem Ipsum
18
+
19
+ #{ResourceGroupTest::BLUEPRINT}}
20
+
21
+ def test_from_ast_hash
22
+ blueprint = MatterCompiler::Blueprint.new(BlueprintTest::AST_HASH)
23
+
24
+ assert_equal BlueprintTest::AST_HASH[:name], blueprint.name
25
+ assert_equal BlueprintTest::AST_HASH[:description], blueprint.description
26
+
27
+ assert_instance_of Array, blueprint.resource_groups
28
+ assert_equal BlueprintTest::AST_HASH[:resourceGroups].length, blueprint.resource_groups.length
29
+ assert_equal ResourceGroupTest::AST_HASH[:name], blueprint.resource_groups[0].name
30
+
31
+ assert_instance_of MatterCompiler::Metadata, blueprint.metadata
32
+ assert_instance_of Array, blueprint.metadata.collection
33
+ assert_equal BlueprintTest::AST_HASH[:metadata].keys.length, blueprint.metadata.collection.length
34
+ assert_equal BlueprintTest::AST_HASH[:metadata].keys[0], blueprint.metadata.collection[0].keys[0]
35
+ end
36
+
37
+ def test_serialize
38
+ blueprint = MatterCompiler::Blueprint.new(BlueprintTest::AST_HASH)
39
+ assert_equal BlueprintTest::BLUEPRINT, blueprint.serialize
40
+
41
+ #puts "\n\n>>>\n#{blueprint.serialize}"
42
+ end
43
+ end
@@ -0,0 +1,10 @@
1
+ require 'minitest/autorun'
2
+ require 'matter_compiler/composer'
3
+
4
+ class ComposerTest < Minitest::Unit::TestCase
5
+ def test_guess_format
6
+ assert_equal :yaml_ast, MatterCompiler::Composer.guess_format('test.yaml')
7
+ assert_equal :json_ast, MatterCompiler::Composer.guess_format('test.json')
8
+ assert_equal :unknown_ast, MatterCompiler::Composer.guess_format('test.txt')
9
+ end
10
+ end
@@ -0,0 +1,75 @@
1
+ require 'minitest/autorun'
2
+ require 'matter_compiler/blueprint'
3
+
4
+ class HeadersTest < Minitest::Unit::TestCase
5
+ AST_HASH = {
6
+ :'X-Header' => {
7
+ :value => "1"
8
+ },
9
+ :'Content-Type' => {
10
+ :value => "text/plain"
11
+ }
12
+ }
13
+
14
+ AST_HASH_CONTENT_ONLY = {
15
+ :'Content-Type' => {
16
+ :value => "text/plain"
17
+ }
18
+ }
19
+
20
+ BLUEPRINT = \
21
+ %Q{+ Headers
22
+
23
+ X-Header: 1
24
+ Content-Type: text/plain
25
+
26
+ }
27
+
28
+ BLUEPRINT_IGNORE_CONTENT = \
29
+ %Q{+ Headers
30
+
31
+ X-Header: 1
32
+
33
+ }
34
+
35
+ BLUEPRINT_CONTENT_ONLY = \
36
+ %Q{+ Headers
37
+
38
+ Content-Type: text/plain
39
+
40
+ }
41
+
42
+ BLUEPRINT_IGNORE_CONTENT_CONTENT_ONLY = %Q{}
43
+
44
+ BLUEPRINT_NESTED_IGNORE_CONTENT = \
45
+ %Q{ + Headers
46
+
47
+ X-Header: 1
48
+
49
+ }
50
+
51
+ def test_from_ast_hash
52
+ headers = MatterCompiler::Headers.new(HeadersTest::AST_HASH)
53
+ assert_equal 2, headers.collection.length
54
+
55
+ assert_instance_of Hash, headers.collection[0]
56
+ assert_equal :'X-Header', headers.collection[0].keys[0]
57
+ assert_equal "1", headers.collection[0][:'X-Header']
58
+
59
+ assert_instance_of Hash, headers.collection[1]
60
+ assert_equal :'Content-Type', headers.collection[1].keys[0]
61
+ assert_equal "text/plain", headers.collection[1][:'Content-Type']
62
+
63
+ assert_equal "text/plain", headers.content_type
64
+ end
65
+
66
+ def test_serialize
67
+ headers = MatterCompiler::Headers.new(HeadersTest::AST_HASH)
68
+ assert_equal HeadersTest::BLUEPRINT, headers.serialize(0)
69
+ assert_equal HeadersTest::BLUEPRINT_IGNORE_CONTENT, headers.serialize(0, [MatterCompiler::Headers::CONTENT_TYPE_HEADER_KEY])
70
+
71
+ headers = MatterCompiler::Headers.new(HeadersTest::AST_HASH_CONTENT_ONLY)
72
+ assert_equal HeadersTest::BLUEPRINT_CONTENT_ONLY, headers.serialize(0)
73
+ assert_equal HeadersTest::BLUEPRINT_IGNORE_CONTENT_CONTENT_ONLY, headers.serialize(0, [MatterCompiler::Headers::CONTENT_TYPE_HEADER_KEY])
74
+ end
75
+ end
@@ -0,0 +1,28 @@
1
+ require 'minitest/autorun'
2
+ require 'matter_compiler/blueprint'
3
+
4
+ class MetadataTest < Minitest::Unit::TestCase
5
+ AST_HASH = {
6
+ :FORMAT => {
7
+ :value => "1A"
8
+ }
9
+ }
10
+
11
+ BLUEPRINT = \
12
+ %Q{FORMAT: 1A
13
+
14
+ }
15
+
16
+ def test_from_ast_hash
17
+ metadata = MatterCompiler::Metadata.new(MetadataTest::AST_HASH)
18
+ assert_equal 1, metadata.collection.length
19
+ assert_instance_of Hash, metadata.collection[0]
20
+ assert_equal :FORMAT, metadata.collection[0].keys[0]
21
+ assert_equal "1A", metadata.collection[0][:FORMAT]
22
+ end
23
+
24
+ def test_serialize
25
+ metadata = MatterCompiler::Metadata.new(MetadataTest::AST_HASH)
26
+ assert_equal MetadataTest::BLUEPRINT, metadata.serialize
27
+ end
28
+ end