api_def 1.0.0

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: 2cf0a8c51de632e9b5a12ad9aa40733cbf39c0f7
4
+ data.tar.gz: 74351fd28942fc015d13048ae8e9343b749db347
5
+ SHA512:
6
+ metadata.gz: 3419a50a596b5e0d68461a82f8451a82880e48877b692c1dd253b294b42ab5972190b4686bd2ded9002018116daa8140900a64f173b77749732efa6403b9da0a
7
+ data.tar.gz: 3399a162a124f985c2acce996f55e253520f060ec672178ecceb5561a3624c4bfd98ec4c08196360d5422e6dd60ae9857287150ef664e9f9c7554cf128f85c91
data/bin/api_def ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #TODO: remove after development finished
4
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__)
5
+
6
+ require 'api_def'
7
+
8
+ ApiDef::CLI.start(ARGV)
@@ -0,0 +1,33 @@
1
+ require 'thor'
2
+
3
+ class ApiDef::CLI < Thor
4
+ desc "build FILE", "build API specification for FILE"
5
+ option :template, {
6
+ aliases: '-t',
7
+ default: 'markdown',
8
+ required: true,
9
+ type: :string,
10
+ enum: ['markdown', 'html'],
11
+ desc: 'Output template'
12
+ }
13
+ def build(file)
14
+ spec = load_spec file
15
+ tpl = ApiDef::Template.find(options[:template]).new
16
+ STDOUT.write tpl.render(spec)
17
+ end
18
+
19
+ desc "mock FILE", "start a mock server for FILE"
20
+ def mock(file)
21
+ spec = load_spec file
22
+ app = ApiDef::Mock.create_application spec
23
+ app.run!
24
+ end
25
+
26
+ private
27
+ def load_spec(file)
28
+ content = File.open(file).read.to_s
29
+ spec = ApiDef::Specification.new
30
+ spec.instance_eval content, file
31
+ end
32
+
33
+ end
@@ -0,0 +1,17 @@
1
+ class ApiDef::Element
2
+ include ApiDef::Support::AttrUno
3
+ include ApiDef::Support::AttrArray
4
+ include ApiDef::Support::AttrUnoArray
5
+
6
+ attr_uno :name, :desc
7
+
8
+ def initialize(name = nil, options = {})
9
+ self.name name
10
+ self.on_options(options)
11
+ yield self if block_given?
12
+ end
13
+
14
+ def on_options(options)
15
+ self.desc options[:desc]
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # ApiDef::Entry means a entry of api
2
+ class ApiDef::Entry < ApiDef::Element
3
+ attr_uno :method, :path
4
+
5
+ attr_uno_array :request, class: 'ApiDef::Request'
6
+ attr_uno_array :response,class: 'ApiDef::Response'
7
+ end
@@ -0,0 +1,4 @@
1
+ # ApiDef::Group means a group of api entries
2
+ class ApiDef::Group < ApiDef::Element
3
+ attr_uno_array :entry, store: :entries, class: 'ApiDef::Entry'
4
+ end
@@ -0,0 +1,32 @@
1
+ require 'sinatra/base'
2
+
3
+ class ApiDef::Mock
4
+
5
+ def self.create_application(spec)
6
+ Class.new(Sinatra::Base) do
7
+ configure do
8
+ set :public_folder, File.expand_path("../../public", __FILE__)
9
+ disable :protection
10
+ settings.add_charset << "application/json"
11
+ end
12
+ before do
13
+ content_type :json
14
+ end
15
+ # root for description
16
+ get "/" do
17
+ content_type :html
18
+ tpl = ApiDef::Template::Html.new
19
+ tpl.render spec
20
+ end
21
+ # entries
22
+ spec.groups.each do |group|
23
+ group.entries.each do |entry|
24
+ self.send(entry.method.to_sym, entry.path) do
25
+ JSON.pretty_generate(entry.responses.sample.body)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,9 @@
1
+ class ApiDef::Parameter < ApiDef::Element
2
+ attr_uno :optional, :type
3
+
4
+ def on_options(options)
5
+ super
6
+ self.optional options[:optional]
7
+ self.type options[:type]
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ # ApiDef::Request means a request made to a api entry
2
+ class ApiDef::Request < ApiDef::Element
3
+ attr_uno_array :param, class: 'ApiDef::Parameter'
4
+ end
@@ -0,0 +1,13 @@
1
+ require 'jbuilder'
2
+
3
+ # ApiDef::Response means a response api returned
4
+ class ApiDef::Response < ApiDef::Element
5
+
6
+ def body(&block)
7
+ if block
8
+ @body = Jbuilder.new(&block).attributes!
9
+ else
10
+ @body
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class ApiDef::Specification < ApiDef::Element
2
+ attr_uno :version
3
+ attr_uno_array :group, class: 'ApiDef::Group'
4
+ attr_uno_array :element, class: 'ApiDef::Element'
5
+ end
@@ -0,0 +1,22 @@
1
+ module ApiDef::Support::AttrArray
2
+
3
+ def self.included(mod)
4
+
5
+ mod.class_eval do
6
+
7
+ # Create method +name+ with +@name+ for array storage
8
+ def self.attr_array(*names)
9
+ names.flatten.each do |name|
10
+ self.class_eval <<-EOF
11
+ def #{name}
12
+ @#{name} ||= []
13
+ end
14
+ EOF
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,26 @@
1
+ module ApiDef::Support::AttrUno
2
+
3
+ def self.included(mod)
4
+
5
+ mod.class_eval do
6
+
7
+ # Create method +name+ with +name(value)+ for setter and +name+ for getter
8
+ def self.attr_uno(*names)
9
+ names.flatten.each do |name|
10
+ self.class_eval <<-EOF
11
+ def #{name}(value = nil)
12
+ if value
13
+ @#{name} = value
14
+ else
15
+ @#{name}
16
+ end
17
+ end
18
+ EOF
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,29 @@
1
+ module ApiDef::Support::AttrUnoArray
2
+
3
+ def self.included(mod)
4
+
5
+ mod.class_eval do
6
+
7
+ def self.attr_uno_array(name, opts)
8
+ clazz = opts[:class]
9
+ raise "Please specify a class" unless clazz
10
+ store = opts[:store] || (name.to_s + "s")
11
+
12
+ self.attr_array store
13
+ self.class_eval <<-EOF
14
+
15
+ def #{name}(value = nil, opts = {})
16
+ obj = #{clazz}.new(value, opts)
17
+ yield obj if block_given?
18
+ self.#{store} << obj
19
+ self
20
+ end
21
+
22
+ EOF
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,37 @@
1
+ require 'redcarpet'
2
+
3
+ class ApiDef::Template::Html < ApiDef::Template
4
+
5
+ def render(spec)
6
+ tpl = ApiDef::Template::Markdown.new
7
+ md = tpl.render(spec)
8
+ content = Redcarpet::Markdown.new(Redcarpet::Render::HTML,
9
+ :autolink => true,
10
+ :space_after_headers => true,
11
+ :fenced_code_blocks => true
12
+ ).render(md)
13
+ %{
14
+ <!doctype html>
15
+ <html>
16
+ <head>
17
+ <meta name="content-type" content="text/html;charset=utf-8">
18
+ <meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui">
19
+ <title>#{spec.name}</title>
20
+ <style>
21
+ body {
22
+ min-width: 200px;
23
+ max-width: 790px;
24
+ margin: 0 auto;
25
+ padding: 30px;
26
+ }
27
+ </style>
28
+ </head>
29
+ <body>
30
+ <article class="markdown-body">
31
+ #{content}
32
+ </article>
33
+ </body>
34
+ </html>
35
+ }
36
+ end
37
+ end
@@ -0,0 +1,64 @@
1
+ require 'erb'
2
+ require 'json'
3
+
4
+ class ApiDef::Template::Markdown < ApiDef::Template
5
+ TEMPLATE_FILE= %{
6
+ # <%= spec.name %>
7
+ # <%= spec.version %>
8
+
9
+ <% spec.elements.each do |ele| -%>
10
+ ## <%= ele.name %>
11
+
12
+ <%= ele.desc %>
13
+ <% end -%>
14
+
15
+ <% spec.groups.each do |group| -%>
16
+ ## <%= group.name %>
17
+
18
+ <%= group.desc %>
19
+ <% group.entries.each do |entry| %>
20
+ ### <%= entry.name %>
21
+
22
+ <%= entry.desc %>
23
+
24
+ #### `<%= entry.path %>` [<%= entry.method.to_s.upcase %>]
25
+ <% entry.requests.each do |request| -%>
26
+
27
+ ##### Request <%= request.name %>
28
+
29
+ <%= request.desc %>
30
+
31
+ <% request.params.each do |param| -%>
32
+ + `<%= param.name %>`, <%= param.type %>, <%="Optional, " if param.optional%><%= param.desc %>
33
+ <% end -%>
34
+
35
+ <% end -%>
36
+
37
+ <% entry.responses.each do |response| -%>
38
+
39
+ ##### Response <%= response.name %>
40
+
41
+ <%= response.desc %>
42
+
43
+ ```json
44
+ <%= JSON.pretty_generate(response.body) %>
45
+ ```
46
+ <% end -%>
47
+ <% end -%>
48
+ <% end -%>
49
+ }
50
+
51
+ def render(_spec)
52
+ clazz = ::ERB.new(TEMPLATE_FILE, nil, "-").def_class
53
+ clazz.class_eval do
54
+ def initialize(_spec)
55
+ @spec = _spec
56
+ end
57
+
58
+ def spec
59
+ @spec
60
+ end
61
+ end
62
+ clazz.new(_spec).result
63
+ end
64
+ end
@@ -0,0 +1,17 @@
1
+ class ApiDef::Template
2
+ autoload :Markdown, 'api_def/template/markdown'
3
+ autoload :Html, 'api_def/template/html'
4
+
5
+ def self.find(name)
6
+ case name.to_s
7
+ when 'html'
8
+ ApiDef::Template::Html
9
+ when 'markdown'
10
+ ApiDef::Template::Markdown
11
+ end
12
+ end
13
+
14
+ def render(spec)
15
+ raise "Implementation required"
16
+ end
17
+ end
data/lib/api_def.rb ADDED
@@ -0,0 +1,28 @@
1
+ module ApiDef
2
+ VERSION="1.0.0"
3
+ # CLI
4
+ autoload :CLI, 'api_def/cli'
5
+ autoload :Template, 'api_def/template'
6
+
7
+ # Specification and DSL
8
+ autoload :Specification, 'api_def/specification'
9
+
10
+ # ApiDef models
11
+ autoload :Element, 'api_def/element'
12
+
13
+ autoload :Group, 'api_def/group'
14
+ autoload :Entry, 'api_def/entry'
15
+ autoload :Request, 'api_def/request'
16
+ autoload :Parameter,'api_def/parameter'
17
+ autoload :Response, 'api_def/response'
18
+
19
+ # Mock Server
20
+ autoload :Mock, 'api_def/mock'
21
+
22
+ # Supports
23
+ module Support
24
+ autoload :AttrUno, 'api_def/support/attr_uno'
25
+ autoload :AttrUnoArray, 'api_def/support/attr_uno_array'
26
+ autoload :AttrArray, 'api_def/support/attr_array'
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: api_def
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - YANKE Guo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0.19'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0.19'
27
+ - !ruby/object:Gem::Dependency
28
+ name: jbuilder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.3.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 2.3.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.4.6
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.4.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: redcarpet
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 3.3.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 3.3.2
69
+ description: Ruby DSL based API definition tool.
70
+ email: me@yanke.io
71
+ executables:
72
+ - api_def
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/api_def/cli.rb
77
+ - lib/api_def/element.rb
78
+ - lib/api_def/entry.rb
79
+ - lib/api_def/group.rb
80
+ - lib/api_def/mock.rb
81
+ - lib/api_def/parameter.rb
82
+ - lib/api_def/request.rb
83
+ - lib/api_def/response.rb
84
+ - lib/api_def/specification.rb
85
+ - lib/api_def/support/attr_array.rb
86
+ - lib/api_def/support/attr_uno.rb
87
+ - lib/api_def/support/attr_uno_array.rb
88
+ - lib/api_def/template/html.rb
89
+ - lib/api_def/template/markdown.rb
90
+ - lib/api_def/template.rb
91
+ - lib/api_def.rb
92
+ - bin/api_def
93
+ homepage: http://rubygems.org/gems/api_def
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.0.14
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: API definition tool
117
+ test_files: []