api_doc_generation 0.0.10 → 0.2.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 +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: ''
|