matter_compiler 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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