api_doc_generation 0.0.10 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -1
- data/lib/api_doc_generation/format_file.rb +77 -0
- data/lib/api_doc_generation/format_note.rb +86 -0
- data/lib/api_doc_generation/generation.rb +53 -0
- data/lib/api_doc_generation/version.rb +1 -1
- data/lib/api_doc_generation/view_helper.rb +45 -25
- data/lib/api_doc_generation.rb +4 -179
- data/lib/rake/tasks/api_doc.rake +15 -11
- data/templates/_controller.html.erb +71 -0
- data/templates/_menu.html.erb +29 -0
- data/templates/_params_table.html.erb +53 -0
- data/templates/doc_detailed.html.erb +4 -177
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3c631601be29797aa6e14707a92b515fa6b68be
|
4
|
+
data.tar.gz: 942cee388e1db6bfd6cd96672e2e7c51a5b9db2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c12bf362dc163eb5f8c3befc5dca58a17494ae0ff5928520f23698d07feec8f759fb6ee4124aa406c24e729009bb6ef3ba7a3f6713131d05206de5b922f944f8
|
7
|
+
data.tar.gz: 83f02c76a07a1f33291cdfd9e4d391d36c9d2b60b8a2f1053de8f71c769dc3b05deb2cf8c7c542a55eea62d220a8b81793c45fdd1244b441260482a73a148384
|
data/README.md
CHANGED
@@ -18,11 +18,15 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
`rake doc:api [CODES_PATH=app/controllers/api]`
|
21
|
+
`rake doc:api [CODES_PATH=app/controllers/api] [OUT_FORMAT=simple_html|detailed_html]`
|
22
22
|
|
23
23
|
__代码注释格式:__
|
24
24
|
|
25
25
|
```
|
26
|
+
|
27
|
+
# About: 文件说明
|
28
|
+
# Host: 定义api host
|
29
|
+
# Other: ...
|
26
30
|
class Api::UsersController < class Api::BaseController
|
27
31
|
# 取得所有用户
|
28
32
|
#
|
@@ -49,6 +53,20 @@ __代码注释格式:__
|
|
49
53
|
def show
|
50
54
|
# ...
|
51
55
|
end
|
56
|
+
|
57
|
+
# 自定义路由
|
58
|
+
#
|
59
|
+
# Path: /path/to/api
|
60
|
+
# Method: POST
|
61
|
+
# Params:
|
62
|
+
# user_id: [String] 用户的id
|
63
|
+
# Return:
|
64
|
+
# name: [String] xxx
|
65
|
+
# Other: 自定义的信息
|
66
|
+
# Other2: 更多的自定义信息..
|
67
|
+
def update
|
68
|
+
# ...
|
69
|
+
end
|
52
70
|
end
|
53
71
|
```
|
54
72
|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module ApiDocGeneration; module FormatFile; class << self
|
4
|
+
def analyze_file(path)
|
5
|
+
controller_path = path.split("app/controllers").last
|
6
|
+
class_name = controller_path.gsub(/controller.*\.rb/, 'controller').classify
|
7
|
+
|
8
|
+
klass = class_name.safe_constantize
|
9
|
+
filelines = File.readlines(path)
|
10
|
+
actions = klass.action_methods - klass.superclass.action_methods
|
11
|
+
|
12
|
+
actions = actions.map do |action|
|
13
|
+
method = klass.instance_method action
|
14
|
+
filepath, line = method.source_location
|
15
|
+
note = FormatNote.analyze(filelines, line - 2)
|
16
|
+
note["Level"] ||= ''
|
17
|
+
note['Name'] = action.to_s
|
18
|
+
note = get_routes(klass, action).merge(note) unless note['Path']
|
19
|
+
note
|
20
|
+
end
|
21
|
+
|
22
|
+
{
|
23
|
+
'Path' => path,
|
24
|
+
'Klass' => klass.to_s,
|
25
|
+
'About' => get_controller_about(filelines, klass.to_s),
|
26
|
+
'Actions' => actions
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def get_controller_about(filelines, class_name)
|
34
|
+
filelines.each_with_index do |line, line_number|
|
35
|
+
next if line =~ /^\s*(\#.*)?$/
|
36
|
+
|
37
|
+
doc = FormatNote.analyze(filelines, line_number -1)
|
38
|
+
|
39
|
+
doc.delete_if {|key, v| key =~ /encoding/ }
|
40
|
+
|
41
|
+
return doc
|
42
|
+
end
|
43
|
+
|
44
|
+
return {}
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def get_routes(klass, action)
|
49
|
+
controller = klass.to_s.gsub(/Controller$/, '').underscore
|
50
|
+
|
51
|
+
(@routes ||= rails_routes).each do |route|
|
52
|
+
if route[:reqs] == "#{controller}##{action}"
|
53
|
+
return {
|
54
|
+
'Path' => route[:path].gsub('(.:format)', ''),
|
55
|
+
'Method' => route[:verb]
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
{
|
61
|
+
'Path' => "",
|
62
|
+
'Method' => ""
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def rails_routes
|
68
|
+
Rails.application.reload_routes!
|
69
|
+
all_routes = Rails.application.routes.routes
|
70
|
+
|
71
|
+
require 'rails/application/route_inspector'
|
72
|
+
inspector = Rails::Application::RouteInspector.new
|
73
|
+
|
74
|
+
inspector.collect_routes(all_routes) +
|
75
|
+
inspector.instance_variable_get(:@engines).flatten
|
76
|
+
end
|
77
|
+
end; end; end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
# desc
|
6
|
+
#
|
7
|
+
# Params:
|
8
|
+
# attr: xxx
|
9
|
+
# other: yyy
|
10
|
+
# asdf las dflkj
|
11
|
+
# Other:
|
12
|
+
# attr: aaa
|
13
|
+
#
|
14
|
+
#
|
15
|
+
# conversion =>
|
16
|
+
# {
|
17
|
+
# 'desc' => 'desc',
|
18
|
+
# 'Params' => [{level: 1, }],
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
|
22
|
+
module ApiDocGeneration; module FormatNote; class << self
|
23
|
+
|
24
|
+
def analyze(filelines, line_number)
|
25
|
+
document = {}
|
26
|
+
|
27
|
+
tmp = []; last_line = ""
|
28
|
+
|
29
|
+
line_number.downto(0) do |i|
|
30
|
+
line = filelines[i]
|
31
|
+
|
32
|
+
break unless line =~ /^\s*(\#.*?\n)?$/
|
33
|
+
break if line =~ /encoding/
|
34
|
+
|
35
|
+
line.gsub!(/\s*\#/, '')
|
36
|
+
next if line =~ /^\s*$/
|
37
|
+
|
38
|
+
format_line(line, tmp, document)
|
39
|
+
|
40
|
+
last_line = line
|
41
|
+
end
|
42
|
+
|
43
|
+
document['Desc'] = last_line
|
44
|
+
document.delete last_line
|
45
|
+
|
46
|
+
Hash[document.to_a.reverse]
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def format_line(line, tmp, document)
|
54
|
+
m = line.match(/(?<level>\s*)(?<desc>(?<key>.*?)(\:(?<val>.*?))?)$/)
|
55
|
+
level = m[:level].length / 2
|
56
|
+
desc = m[:desc].gsub(/^\s*|\s*$/, '')
|
57
|
+
line.gsub!(/^\s*|\:?\s*$/, '')
|
58
|
+
|
59
|
+
if level == 0
|
60
|
+
if tmp.length == 0 && m[:val] && m[:val].length > 0
|
61
|
+
document[m[:key]] = m[:val]
|
62
|
+
else
|
63
|
+
document[m[:key] + (m[:val] || '')] = tmp.reverse.each_with_object([]) do |p, result|
|
64
|
+
if p['level'] >= 2 && result.last
|
65
|
+
result.last['children'] ||= []
|
66
|
+
result.last['children'] << p
|
67
|
+
else
|
68
|
+
result << p
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
tmp.clear
|
73
|
+
else
|
74
|
+
m = desc.match(/(?<name>\w+)\:?\s*((\[(?<type>.*?)\]\s*)?(?<val>.*))?$/)
|
75
|
+
p = {'level' => level, 'desc' => desc}
|
76
|
+
|
77
|
+
p.merge!({
|
78
|
+
'name' => m[:name],
|
79
|
+
'type' => m[:type],
|
80
|
+
'val' => m[:val]
|
81
|
+
}) if m
|
82
|
+
|
83
|
+
tmp << p
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end; end; end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require 'api_doc_generation/format_file'
|
4
|
+
require 'api_doc_generation/format_note'
|
5
|
+
|
6
|
+
|
7
|
+
module ApiDocGeneration; class Generation
|
8
|
+
attr_reader :controller_documents
|
9
|
+
|
10
|
+
def initialize(codes_path = nil, title = '')
|
11
|
+
codes_path ||= File.expand_path('app/controllers/api', Rails.root)
|
12
|
+
@controller_documents = []
|
13
|
+
@title = title
|
14
|
+
|
15
|
+
each_api_controllers_file(codes_path) do |path|
|
16
|
+
@controller_documents << FormatFile.analyze_file(path)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def generate_html_string(opts = {})
|
22
|
+
path = File.read(File.expand_path('templates/doc.html.erb', ROOT_PATH))
|
23
|
+
|
24
|
+
ViewHelper.render(ERB.new(path), opts.merge({
|
25
|
+
:documents => @controller_documents,
|
26
|
+
:title => @title
|
27
|
+
}), path)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def generate_detailed_html_string(opts = {})
|
32
|
+
path = File.read(File.expand_path('templates/doc_detailed.html.erb', ROOT_PATH))
|
33
|
+
|
34
|
+
ViewHelper.render(ERB.new(path), opts.merge({
|
35
|
+
:documents => @controller_documents,
|
36
|
+
:title => @title
|
37
|
+
}), path)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
|
44
|
+
# API_CONTROLLERS_DIR = File.expand_path('app/controllers/api/**/*.rb', Rails.root)
|
45
|
+
def each_api_controllers_file(codes_path, &block)
|
46
|
+
|
47
|
+
Dir[codes_path + '/**/*.rb'].each do |path|
|
48
|
+
next if path =~ /base_controller.*\.rb$/
|
49
|
+
block.call path
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end; end
|
53
|
+
|
@@ -1,13 +1,20 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module ApiDocGeneration; class ViewHelper
|
4
|
-
def self.render(template, args = {})
|
4
|
+
def self.render(template, args = {}, file_path = '')
|
5
5
|
template.result(self.new(args).obj_binding)
|
6
|
+
|
7
|
+
rescue => e
|
8
|
+
e.backtrace[0].gsub!(/^\(erb\)/, file_path)
|
9
|
+
|
10
|
+
raise e
|
6
11
|
end
|
7
12
|
|
8
13
|
|
9
14
|
# {:a => 1, :b => 2}
|
10
15
|
def initialize(args)
|
16
|
+
@args = args
|
17
|
+
|
11
18
|
args.each do |key, val|
|
12
19
|
self.instance_variable_set("@#{key}", val)
|
13
20
|
end
|
@@ -20,6 +27,19 @@ module ApiDocGeneration; class ViewHelper
|
|
20
27
|
|
21
28
|
|
22
29
|
|
30
|
+
|
31
|
+
################## View Helper ###################
|
32
|
+
|
33
|
+
def render(path, opts = {})
|
34
|
+
file_path = File.expand_path("templates/_#{path}.html.erb", ROOT_PATH)
|
35
|
+
|
36
|
+
template = ERB.new(File.read(file_path))
|
37
|
+
|
38
|
+
self.class.render(template, @args.merge(opts), file_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
23
43
|
################## Helper #######################
|
24
44
|
def action_identifer(controller_name, action_name)
|
25
45
|
"action-#{Digest::MD5.hexdigest(controller_name)}-#{action_name}"
|
@@ -32,47 +52,47 @@ module ApiDocGeneration; class ViewHelper
|
|
32
52
|
|
33
53
|
|
34
54
|
def format_param(param)
|
35
|
-
return unless param[
|
55
|
+
return unless param['val'].to_s =~ /^\s*$/
|
36
56
|
|
37
|
-
case param[
|
57
|
+
case param['name']
|
38
58
|
when 'app_uname'
|
39
|
-
param[
|
40
|
-
param[
|
59
|
+
param['type'] = 'String'
|
60
|
+
param['val'] = 'app的唯一标识名,表明调用此api是在哪个app下'
|
41
61
|
when 'access_token'
|
42
|
-
param[
|
43
|
-
param[
|
62
|
+
param['type'] = 'String'
|
63
|
+
param['val'] = '请求的唯一标识,用于识别用户,用户登陆返回或是使用refresh_token换取'
|
44
64
|
when 'refresh_token'
|
45
|
-
param[
|
46
|
-
param[
|
65
|
+
param['type'] = 'String'
|
66
|
+
param['val'] = '用户登陆时返回,使用此token来取得新的access_token'
|
47
67
|
when 'page'
|
48
|
-
param[
|
49
|
-
param[
|
68
|
+
param['type'] = 'Integer'
|
69
|
+
param['val'] = '返回所有数据中的第几页'
|
50
70
|
when 'perpage'
|
51
|
-
param[
|
52
|
-
param[
|
71
|
+
param['type'] = 'Integer'
|
72
|
+
param['val'] = '返回数据每页多少条'
|
53
73
|
end
|
54
74
|
end
|
55
75
|
|
56
76
|
|
57
77
|
def format_response_param(param)
|
58
|
-
return unless param[
|
78
|
+
return unless param['val'].to_s =~ /^\s*$/
|
59
79
|
|
60
|
-
case param[
|
80
|
+
case param['name']
|
61
81
|
when 'current_page'
|
62
|
-
param[
|
63
|
-
param[
|
82
|
+
param['type'] = 'Integer'
|
83
|
+
param['val'] = '当前返回数据是第几页'
|
64
84
|
when 'perpage'
|
65
|
-
param[
|
66
|
-
param[
|
85
|
+
param['type'] = 'Integer'
|
86
|
+
param['val'] = '每页返回的数据量'
|
67
87
|
when 'count'
|
68
|
-
param[
|
69
|
-
param[
|
88
|
+
param['type'] = 'Integer'
|
89
|
+
param['val'] = '数据总数量'
|
70
90
|
when 'items'
|
71
|
-
param[
|
72
|
-
param[
|
91
|
+
param['type'] = 'Array'
|
92
|
+
param['val'] = '数组中存放当前页的数据'
|
73
93
|
when 'total_pages'
|
74
|
-
param[
|
75
|
-
param[
|
94
|
+
param['type'] = 'Integer'
|
95
|
+
param['val'] = '数据的总页数'
|
76
96
|
end
|
77
97
|
end
|
78
98
|
|
data/lib/api_doc_generation.rb
CHANGED
@@ -8,184 +8,9 @@ if defined? Rake
|
|
8
8
|
require "rake/api_doc_generation"
|
9
9
|
end
|
10
10
|
|
11
|
+
require 'api_doc_generation/generation'
|
11
12
|
|
12
|
-
module ApiDocGeneration; class Generation
|
13
|
-
def initialize(codes_path = nil)
|
14
|
-
codes_path ||= File.expand_path('app/controllers/api', Rails.root)
|
15
|
-
@controller_documents = []
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
klass = class_name.safe_constantize
|
21
|
-
|
22
|
-
@controller_documents << generate_controller(path, klass)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
def generate_html_string(opts = {})
|
28
|
-
template = ERB.new(
|
29
|
-
File.read(File.expand_path('../../templates/doc.html.erb', __FILE__))
|
30
|
-
)
|
31
|
-
|
32
|
-
ViewHelper.render(template, opts.merge({
|
33
|
-
:documents => @controller_documents
|
34
|
-
}))
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
def generate_detailed_html_string(opts = {})
|
39
|
-
template = ERB.new(
|
40
|
-
File.read(File.expand_path('../../templates/doc_detailed.html.erb', __FILE__))
|
41
|
-
)
|
42
|
-
|
43
|
-
ViewHelper.render(template, opts.merge({
|
44
|
-
:documents => @controller_documents
|
45
|
-
}))
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
|
52
|
-
# API_CONTROLLERS_DIR = File.expand_path('app/controllers/api/**/*.rb', Rails.root)
|
53
|
-
def each_api_controllers_file(codes_path, &block)
|
54
|
-
|
55
|
-
Dir[codes_path + '/**/*.rb'].each do |path|
|
56
|
-
next if path =~ /base_controller.rb$/
|
57
|
-
block.call path
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
# {
|
64
|
-
#
|
65
|
-
# :path => path,
|
66
|
-
# :actions => [
|
67
|
-
# {
|
68
|
-
# "Params" => ['xxx', 'yyy'],
|
69
|
-
# "zzz" => ["zz1", "zz2"]
|
70
|
-
# }
|
71
|
-
# ]
|
72
|
-
# }
|
73
|
-
def generate_controller(path, klass)
|
74
|
-
filelines = File.readlines(path)
|
75
|
-
actions = klass.action_methods - klass.superclass.action_methods
|
76
|
-
|
77
|
-
actions = actions.map do |action|
|
78
|
-
generate_action(klass, action, filelines)
|
79
|
-
end
|
80
|
-
|
81
|
-
{
|
82
|
-
:path => path,
|
83
|
-
:klass => klass.to_s,
|
84
|
-
:actions => actions,
|
85
|
-
:about => get_controller_about(filelines, klass.to_s)
|
86
|
-
}
|
87
|
-
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
# {name: 'xx', desc: 'yy', Params: [{level: 1, }]}
|
92
|
-
def generate_action(klass, action, filelines)
|
93
|
-
document = {:name => action.to_s}
|
94
|
-
method = klass.instance_method action
|
95
|
-
filepath, line = method.source_location
|
96
|
-
tmp = []; last_line = ""
|
97
|
-
|
98
|
-
(line - 2).downto(0) do |i|
|
99
|
-
line = filelines[i]
|
100
|
-
|
101
|
-
unless line =~ /^\s*(\#.*?\n)?$/
|
102
|
-
document[:desc] = last_line
|
103
|
-
document.delete last_line
|
104
|
-
break
|
105
|
-
end
|
106
|
-
|
107
|
-
line.gsub!(/\s*\#/, '')
|
108
|
-
next if line =~ /^\s*$/
|
109
|
-
|
110
|
-
format_line(line, tmp, document)
|
111
|
-
|
112
|
-
last_line = line
|
113
|
-
end
|
114
|
-
|
115
|
-
Hash[document.merge(get_routes(klass, action)).to_a.reverse]
|
116
|
-
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
def get_routes(klass, action)
|
121
|
-
controller = klass.to_s.gsub(/Controller$/, '').underscore
|
122
|
-
|
123
|
-
|
124
|
-
Rails.application.routes.named_routes.routes.each do |name, journey|
|
125
|
-
defaults = journey.defaults
|
126
|
-
|
127
|
-
if defaults[:controller] == controller && defaults[:action] == action
|
128
|
-
req_m = journey.verb.to_s.match(/\^(?<req_method>\w+)\$/)
|
129
|
-
return {
|
130
|
-
:path => journey.path.spec.to_s.gsub(/\(\.\:format\)$/, ''),
|
131
|
-
:method => req_m ? req_m[:req_method] : 'POST | GET'
|
132
|
-
}
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
{
|
137
|
-
:path => "",
|
138
|
-
:method => ""
|
139
|
-
}
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
def format_line(line, tmp, document)
|
144
|
-
m = line.match(/(?<level>\s*)(?<desc>(?<key>.*?)(\:(?<val>.*?))?)$/)
|
145
|
-
level = m[:level].length / 2
|
146
|
-
desc = m[:desc].gsub(/^\s*|\s*$/, '')
|
147
|
-
line.gsub!(/^\s*|\:?\s*$/, '')
|
148
|
-
|
149
|
-
if level == 0
|
150
|
-
if tmp.length == 0 && m[:val] && m[:val].length > 0
|
151
|
-
document[m[:key]] = m[:val]
|
152
|
-
else
|
153
|
-
document[m[:key] + (m[:val] || '')] = tmp.reverse.each_with_object([]) do |p, result|
|
154
|
-
if p[:level] >= 2 && result.last
|
155
|
-
result.last[:children] ||= []
|
156
|
-
result.last[:children] << p
|
157
|
-
else
|
158
|
-
result << p
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
tmp.clear
|
163
|
-
else
|
164
|
-
m = desc.match(/(?<name>\w+)\:?\s*((\[(?<type>.*?)\]\s*)?(?<val>.*))?$/)
|
165
|
-
p = {:level => level, :desc => desc}
|
166
|
-
|
167
|
-
p.merge!({
|
168
|
-
:name => m[:name],
|
169
|
-
:type => m[:type],
|
170
|
-
:val => m[:val]
|
171
|
-
}) if m
|
172
|
-
|
173
|
-
tmp << p
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
def get_controller_about(filelines, class_name)
|
180
|
-
pre_line = ''
|
181
|
-
|
182
|
-
filelines.each do |line|
|
183
|
-
break if line =~ /class\s#{Regexp.escape(class_name)}/
|
184
|
-
pre_line = line
|
185
|
-
end
|
186
|
-
|
187
|
-
pre_line.gsub(/^\s*#\s*/, '')
|
188
|
-
end
|
189
|
-
|
190
|
-
|
191
|
-
end; end
|
14
|
+
module ApiDocGeneration
|
15
|
+
ROOT_PATH = File.expand_path('../../', __FILE__)
|
16
|
+
end
|
data/lib/rake/tasks/api_doc.rake
CHANGED
@@ -6,23 +6,27 @@ namespace :doc do
|
|
6
6
|
out_format = ENV['OUT_FORMAT'] || 'detailed_html'
|
7
7
|
codes_path = ENV['CODES_PATH'] || File.expand_path('app/controllers/api', Rails.root)
|
8
8
|
level = ENV['LEVEL'] ? ENV['LEVEL'].split(',') : nil
|
9
|
+
title = ENV['TITLE']
|
9
10
|
|
10
|
-
puts out_format
|
11
|
+
puts "Template: #{out_format}"
|
12
|
+
generation = ApiDocGeneration::Generation.new(codes_path, title)
|
13
|
+
|
14
|
+
puts generation.controller_documents if ENV['SHOW_DOCS']
|
11
15
|
|
12
16
|
case out_format
|
13
17
|
when 'simple_html'
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
)
|
18
|
+
path = "./tmp/api_doc.html"
|
19
|
+
puts "out_path: #{path}"
|
20
|
+
|
21
|
+
File.open(path, "w+") do |f|
|
22
|
+
f.write(generation.generate_html_string(:level => level))
|
19
23
|
end
|
20
24
|
when 'detailed_html'
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
)
|
25
|
+
path = "./tmp/api_doc.html"
|
26
|
+
puts "Out path: #{path}"
|
27
|
+
|
28
|
+
File.open(path, 'w+') do |f|
|
29
|
+
f.write(generation.generate_detailed_html_string(:level => level))
|
26
30
|
end
|
27
31
|
else
|
28
32
|
puts "undefined OUT_FORMAT: '#{out_format}'"
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<% @documents.each do |controller| %>
|
2
|
+
<div class='controller' id='<%= controller_identifer(controller['Klass']) %>'>
|
3
|
+
<h2 class='controller-title'><%= controller['About']['Desc'] %></h2>
|
4
|
+
|
5
|
+
<div class='action'>
|
6
|
+
<% controller['About'].each do |key, val| %>
|
7
|
+
<% next if %w{Desc}.include?(key.to_s) %>
|
8
|
+
|
9
|
+
<h4><%= key %></h4>
|
10
|
+
<% unless val && (val.is_a?(Array) && val.length > 1) %>
|
11
|
+
<p>
|
12
|
+
<% if val.is_a?(Array) %>
|
13
|
+
<%= val.first.try('fetch', 'desc') %>
|
14
|
+
<% else %>
|
15
|
+
<%= val %>
|
16
|
+
<% end %>
|
17
|
+
</p>
|
18
|
+
<% else %>
|
19
|
+
<%= render 'params_table', :params => controller['About'][key] %>
|
20
|
+
<% end %>
|
21
|
+
<% end %>
|
22
|
+
</div>
|
23
|
+
<hr />
|
24
|
+
|
25
|
+
<% controller['Actions'].each_with_index do |action, i| %>
|
26
|
+
<% next if @level && !@level.include?(action['Level'].strip) %>
|
27
|
+
|
28
|
+
<div class='action action-<%= i % 2 == 0 ? 'even' : 'odd' %>'
|
29
|
+
id='<%= action_identifer(controller['Klass'], action['Name']) %>'>
|
30
|
+
|
31
|
+
<h4>功能说明</h4>
|
32
|
+
<p class='about text-info'><%= action['Desc'] %></p>
|
33
|
+
|
34
|
+
<h4>请求地址</h4>
|
35
|
+
<p class='about text-info'><%= action['Path'] %></p>
|
36
|
+
|
37
|
+
<h4>请求方法</h4>
|
38
|
+
<p class='about text-info'><%= action['Method'] %></p>
|
39
|
+
|
40
|
+
<h4>参数说明</h4>
|
41
|
+
<%= render 'params_table', :params => action['Params'] || [], :type => 'params' %>
|
42
|
+
|
43
|
+
<h4>正常返回信息</h4>
|
44
|
+
<p class='about text-info'>正常完成时response.status 为 200.</p>
|
45
|
+
<%= render 'params_table', :params => action['Return'] || [], :type => 'return' %>
|
46
|
+
|
47
|
+
<h4>出错误时信息</h4>
|
48
|
+
<p class='about text-info'>出错时response.status 为 400.</p>
|
49
|
+
<%= render 'params_table', :params => action['Error'] || [], :type => 'error' %>
|
50
|
+
|
51
|
+
<% action.each do |key, val| %>
|
52
|
+
<% next if %w{Desc Path Method Params Return Error Name}.include?(key.to_s) %>
|
53
|
+
<h4><%= key %></h4>
|
54
|
+
<% unless val && (val.is_a?(Array) && val.length > 1) %>
|
55
|
+
<p>
|
56
|
+
<% if val.is_a?(Array) %>
|
57
|
+
<%= val.first.try('fetch', 'desc') %>
|
58
|
+
<% else %>
|
59
|
+
<%= val %>
|
60
|
+
<% end %>
|
61
|
+
</p>
|
62
|
+
<% else %>
|
63
|
+
<%= render 'params_table', :params => action[key] %>
|
64
|
+
<% end %>
|
65
|
+
<% end %>
|
66
|
+
<br /><hr />
|
67
|
+
</div>
|
68
|
+
<% end %>
|
69
|
+
|
70
|
+
</div>
|
71
|
+
<% end %>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<div class='list'>
|
2
|
+
<strong class='no_print no_opacity about'>* 被勾选的内容将被打印</strong>
|
3
|
+
|
4
|
+
<ul>
|
5
|
+
<% @documents.each do |controller| %>
|
6
|
+
<li>
|
7
|
+
<input type='checkbox' class='no_print no_opacity print_selector' checked=1 />
|
8
|
+
<a href='#<%= controller_identifer(controller['Klass']) %>'>
|
9
|
+
<%= controller['About']['Desc'] %>
|
10
|
+
</a>
|
11
|
+
|
12
|
+
<ul class='ul-controller'>
|
13
|
+
<% controller['Actions'].each do |action| %>
|
14
|
+
<% next if @level && !@level.include?(action['Level'].strip) %>
|
15
|
+
|
16
|
+
<li>
|
17
|
+
<input type='checkbox' class='no_print no_opacity print_selector' checked=1 />
|
18
|
+
<a href='#<%= action_identifer(controller['Klass'], action['Name']) %>'>
|
19
|
+
<%= action['Desc'] %>
|
20
|
+
</a>
|
21
|
+
</li>
|
22
|
+
<% end %>
|
23
|
+
</ul>
|
24
|
+
|
25
|
+
</li>
|
26
|
+
<% end %>
|
27
|
+
</ul>
|
28
|
+
</div>
|
29
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
<table class='table table-bordered table-striped'>
|
3
|
+
<thead>
|
4
|
+
<th>参数名</th>
|
5
|
+
<th>参数类型</th>
|
6
|
+
<th>描述</th>
|
7
|
+
</thead>
|
8
|
+
|
9
|
+
<tbody>
|
10
|
+
<% unless @params.nil? || @params.length == 0 %>
|
11
|
+
<% @params.each do |param| %>
|
12
|
+
<% if @type == 'params' %>
|
13
|
+
<% format_param(param) %>
|
14
|
+
<% elsif @type == 'return' || @type == 'error' %>
|
15
|
+
<% format_response_param(param); %>
|
16
|
+
<% else %>
|
17
|
+
<% format_other_param(param) %>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<tr>
|
21
|
+
<% ['name', 'type'].each do |key| %>
|
22
|
+
<td><%= param[key] %></td>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<td>
|
26
|
+
<%= param['val'] %>
|
27
|
+
|
28
|
+
<% if param['children'] %>
|
29
|
+
<% param['children'].each do |cp| %>
|
30
|
+
<p style='padding-left: <%= (cp['level'] - 1) * 20 %>px'>
|
31
|
+
<%= cp['desc'] %>
|
32
|
+
</p>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
35
|
+
</td>
|
36
|
+
|
37
|
+
</tr>
|
38
|
+
<% end %>
|
39
|
+
<% else %>
|
40
|
+
<tr>
|
41
|
+
<td>error</td>
|
42
|
+
<td>String</td>
|
43
|
+
<td>错误标识</td>
|
44
|
+
</tr>
|
45
|
+
|
46
|
+
<tr>
|
47
|
+
<td>error_description</td>
|
48
|
+
<td>String</td>
|
49
|
+
<td>错误具体描述</td>
|
50
|
+
</tr>
|
51
|
+
<% end %>
|
52
|
+
</tbody>
|
53
|
+
</table>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<head>
|
3
3
|
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
4
4
|
|
5
|
-
<title
|
5
|
+
<title><%= @title %></title>
|
6
6
|
|
7
7
|
<link href='http://libs.baidu.com/bootstrap/2.3.2/css/bootstrap.css' rel='stylesheet'>
|
8
8
|
<style type='text/css'>
|
@@ -73,182 +73,9 @@
|
|
73
73
|
</head>
|
74
74
|
|
75
75
|
<body>
|
76
|
-
<h1 class='title'
|
76
|
+
<h1 class='title'><%= @title %></h1>
|
77
|
+
<%= render 'menu' %>
|
77
78
|
|
78
|
-
|
79
|
-
<strong class='no_print no_opacity about'>* 被勾选的内容将被打印</strong>
|
80
|
-
|
81
|
-
<ul>
|
82
|
-
<% @documents.each do |controller| %>
|
83
|
-
<li>
|
84
|
-
<input type='checkbox' class='no_print no_opacity print_selector' checked=1 />
|
85
|
-
<a href='#<%= controller_identifer(controller[:klass]) %>'><%= controller[:about] %></a>
|
86
|
-
|
87
|
-
<ul class='ul-controller'>
|
88
|
-
<% controller[:actions].each do |action| %>
|
89
|
-
<% next if @level && !@level.include?(action['Level'].strip) %>
|
90
|
-
|
91
|
-
<li>
|
92
|
-
<input type='checkbox' class='no_print no_opacity print_selector' checked=1 />
|
93
|
-
<a href='#<%= action_identifer(controller[:klass], action[:name]) %>'>
|
94
|
-
<%= action[:desc] %>
|
95
|
-
</a>
|
96
|
-
</li>
|
97
|
-
<% end %>
|
98
|
-
</ul>
|
99
|
-
|
100
|
-
</li>
|
101
|
-
<% end %>
|
102
|
-
</ul>
|
103
|
-
</div>
|
104
|
-
|
105
|
-
<% @documents.each do |controller| %>
|
106
|
-
<div class='controller' id='<%= controller_identifer(controller[:klass]) %>'>
|
107
|
-
<h2 class='controller-title'><%= controller[:about] %></h2>
|
108
|
-
|
109
|
-
<% controller[:actions].each_with_index do |action, i| %>
|
110
|
-
<% next if @level && !@level.include?(action['Level'].strip) %>
|
111
|
-
|
112
|
-
<div class='action action-<%= i % 2 == 0 ? 'even' : 'odd' %>'
|
113
|
-
id='<%= action_identifer(controller[:klass], action[:name]) %>'>
|
114
|
-
|
115
|
-
<h4>功能说明</h4>
|
116
|
-
<p class='about text-info'><%= action[:desc] %></p>
|
117
|
-
|
118
|
-
<h4>请求地址</h4>
|
119
|
-
<p class='about text-info'><%= action[:path] %></p>
|
120
|
-
|
121
|
-
<h4>请求方法</h4>
|
122
|
-
<p class='about text-info'><%= action[:method] %></p>
|
123
|
-
|
124
|
-
<h4>参数说明</h4>
|
125
|
-
<table class='table table-bordered table-striped'>
|
126
|
-
<thead>
|
127
|
-
<th>参数名</th>
|
128
|
-
<th>参数类型</th>
|
129
|
-
<th>描述</th>
|
130
|
-
</thead>
|
131
|
-
|
132
|
-
<tbody>
|
133
|
-
<% (action['Params'] || []).each do |param| %>
|
134
|
-
<% format_param(param) %>
|
135
|
-
|
136
|
-
<tr>
|
137
|
-
<% [:name, :type].each do |key| %>
|
138
|
-
<td><%= param[key] %></td>
|
139
|
-
<% end %>
|
140
|
-
|
141
|
-
<td>
|
142
|
-
<%= param[:val] %>
|
143
|
-
|
144
|
-
<% if param[:children] %>
|
145
|
-
<% param[:children].each do |cp| %>
|
146
|
-
<p style='padding-left: <%= (cp[:level] - 1) * 20 %>px'><%= cp[:desc] %></p>
|
147
|
-
<% end %>
|
148
|
-
<% end %>
|
149
|
-
</td>
|
150
|
-
|
151
|
-
</tr>
|
152
|
-
<% end %>
|
153
|
-
</tbody>
|
154
|
-
</table>
|
155
|
-
|
156
|
-
<h4>正常返回信息</h4>
|
157
|
-
<p class='about text-info'>正常完成时response.status 为 200.</p>
|
158
|
-
<table class='table table-bordered table-striped'>
|
159
|
-
<thead>
|
160
|
-
<th>参数名</th>
|
161
|
-
<th>参数类型</th>
|
162
|
-
<th>描述</th>
|
163
|
-
</thead>
|
164
|
-
|
165
|
-
<tbody>
|
166
|
-
<% (action['Return'] || []).each do |param| %>
|
167
|
-
<% format_response_param(param) %>
|
168
|
-
|
169
|
-
<tr>
|
170
|
-
<% [:name, :type, :val].each do |key| %>
|
171
|
-
<td><%= param[key] %></td>
|
172
|
-
<% end %>
|
173
|
-
</tr>
|
174
|
-
<% end %>
|
175
|
-
</tbody>
|
176
|
-
</table>
|
177
|
-
|
178
|
-
<h4>出错误时信息</h4>
|
179
|
-
<p class='about text-info'>出错时response.status 为 400.</p>
|
180
|
-
<table class='table table-bordered table-striped'>
|
181
|
-
<thead>
|
182
|
-
<th>参数名</th>
|
183
|
-
<th>参数类型</th>
|
184
|
-
<th>描述</th>
|
185
|
-
</thead>
|
186
|
-
|
187
|
-
<tbody>
|
188
|
-
<% if action['Error'] %>
|
189
|
-
<% action['Error'].each do |param| %>
|
190
|
-
<% format_response_param(param) %>
|
191
|
-
|
192
|
-
<tr>
|
193
|
-
<% [:name, :type, :val].each do |key| %>
|
194
|
-
<td><%= param[key] %></td>
|
195
|
-
<% end %>
|
196
|
-
</tr>
|
197
|
-
<% end %>
|
198
|
-
<% else %>
|
199
|
-
<tr>
|
200
|
-
<td>error</td>
|
201
|
-
<td>String</td>
|
202
|
-
<td>错误标识</td>
|
203
|
-
</tr>
|
204
|
-
|
205
|
-
<tr>
|
206
|
-
<td>error_description</td>
|
207
|
-
<td>String</td>
|
208
|
-
<td>错误具体描述</td>
|
209
|
-
</tr>
|
210
|
-
<% end %>
|
211
|
-
</tbody>
|
212
|
-
</table>
|
213
|
-
|
214
|
-
<% action.each do |key, val| %>
|
215
|
-
<% next if %w{desc path method Params Return Error name}.include?(key.to_s) %>
|
216
|
-
<h4><%= key %></h4>
|
217
|
-
<% unless val && (val.is_a?(Array) && val.length > 1) %>
|
218
|
-
<p>
|
219
|
-
<% if val.is_a?(Array) %>
|
220
|
-
<%= val.first[:desc] %>
|
221
|
-
<% else %>
|
222
|
-
<%= val %>
|
223
|
-
<% end %>
|
224
|
-
</p>
|
225
|
-
<% else %>
|
226
|
-
<table class='table table-bordered table-striped'>
|
227
|
-
<thead>
|
228
|
-
<th>参数名</th>
|
229
|
-
<th>参数类型</th>
|
230
|
-
<th>描述</th>
|
231
|
-
</thead>
|
232
|
-
|
233
|
-
<tbody>
|
234
|
-
<% (action[key] || []).each do |param| %>
|
235
|
-
<% format_other_param(param) %>
|
236
|
-
|
237
|
-
<tr>
|
238
|
-
<% [:name, :type, :val].each do |key| %>
|
239
|
-
<td><%= param[key] %></td>
|
240
|
-
<% end %>
|
241
|
-
</tr>
|
242
|
-
<% end %>
|
243
|
-
</tbody>
|
244
|
-
</table>
|
245
|
-
<% end %>
|
246
|
-
<% end %>
|
247
|
-
<br /><hr />
|
248
|
-
</div>
|
249
|
-
<% end %>
|
250
|
-
|
251
|
-
</div>
|
252
|
-
<% end %>
|
79
|
+
<%= render 'controller'%>
|
253
80
|
</body>
|
254
81
|
</html>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api_doc_generation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jiangzhi.xie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,10 +52,16 @@ files:
|
|
52
52
|
- Rakefile
|
53
53
|
- api_doc_generation.gemspec
|
54
54
|
- lib/api_doc_generation.rb
|
55
|
+
- lib/api_doc_generation/format_file.rb
|
56
|
+
- lib/api_doc_generation/format_note.rb
|
57
|
+
- lib/api_doc_generation/generation.rb
|
55
58
|
- lib/api_doc_generation/version.rb
|
56
59
|
- lib/api_doc_generation/view_helper.rb
|
57
60
|
- lib/rake/api_doc_generation.rb
|
58
61
|
- lib/rake/tasks/api_doc.rake
|
62
|
+
- templates/_controller.html.erb
|
63
|
+
- templates/_menu.html.erb
|
64
|
+
- templates/_params_table.html.erb
|
59
65
|
- templates/doc.html.erb
|
60
66
|
- templates/doc_detailed.html.erb
|
61
67
|
homepage: ''
|