rails_api_documentation 0.2.3 → 0.3.0
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 +9 -8
- data/app/assets/javascripts/table.js.coffee +10 -1
- data/app/assets/stylesheets/rails_api_doc/default.sass +39 -16
- data/app/assets/stylesheets/rails_api_doc/table.sass +21 -4
- data/app/controllers/rails_api_doc/api_docs_controller.rb +17 -20
- data/app/helpers/rails_api_doc/application_helper.rb +11 -0
- data/app/models/rails_api_doc/api_datum.rb +17 -0
- data/app/views/layouts/rails_api_doc/application.slim +2 -5
- data/app/views/rails_api_doc/api_docs/_request_api_table.slim +1 -1
- data/app/views/rails_api_doc/api_docs/_response_api_table.slim +4 -3
- data/app/views/rails_api_doc/api_docs/{index.slim → show.slim} +0 -0
- data/app/views/shared/_param_inputs.slim +2 -3
- data/app/views/shared/_table.slim +8 -6
- data/app/views/shared/_title.slim +8 -0
- data/config/routes.rb +1 -1
- data/lib/generators/rails_api_doc/templates/api_datum_migration.rb +4 -1
- data/lib/rails_api_doc.rb +16 -1
- data/lib/rails_api_doc/controller/headers.rb +59 -0
- data/lib/rails_api_doc/controller/param.rb +113 -0
- data/lib/rails_api_doc/controller/repo.rb +35 -0
- data/lib/rails_api_doc/controller/request/dsl.rb +1 -3
- data/lib/rails_api_doc/controller/request/factory.rb +29 -0
- data/lib/rails_api_doc/controller/request/headers.rb +11 -42
- data/lib/rails_api_doc/controller/request/param.rb +26 -33
- data/lib/rails_api_doc/controller/request/repository.rb +5 -26
- data/lib/rails_api_doc/controller/response/factory.rb +20 -2
- data/lib/rails_api_doc/controller/response/headers.rb +10 -21
- data/lib/rails_api_doc/controller/response/param.rb +38 -1
- data/lib/rails_api_doc/controller/response/rabl.rb +8 -19
- data/lib/rails_api_doc/controller/response/rabl_compiler.rb +7 -9
- data/lib/rails_api_doc/controller/response/repository.rb +38 -0
- data/lib/rails_api_doc/model/attribute_merger.rb +130 -0
- data/lib/rails_api_doc/model/attribute_parser.rb +23 -5
- data/lib/rails_api_doc/version.rb +1 -1
- metadata +10 -3
@@ -6,12 +6,30 @@ class RailsApiDoc::Controller::Response::Factory
|
|
6
6
|
class << self
|
7
7
|
|
8
8
|
# TODO: add more options later depending on app settings
|
9
|
+
# TODO: rename to :load_repo
|
9
10
|
def repo
|
10
|
-
|
11
|
+
attributes = RailsApiDoc::Controller::Response::Repository.new(repository.repo)
|
12
|
+
|
13
|
+
attributes = merge_attributes_from_model attributes
|
14
|
+
|
15
|
+
attributes
|
11
16
|
end
|
12
17
|
|
13
18
|
def controllers
|
14
|
-
RailsApiDoc::Controller::Request::
|
19
|
+
RailsApiDoc::Controller::Request::Factory.registered_controllers
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def repository
|
25
|
+
@repo ||= ::RailsApiDoc::Controller::Response::Rabl.new(controllers)
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# do not mutate attributes
|
30
|
+
#
|
31
|
+
def merge_attributes_from_model(attributes)
|
32
|
+
RailsApiDoc::Model::AttributeMerger.new(attributes).call(api_type: 'response')
|
15
33
|
end
|
16
34
|
|
17
35
|
end
|
@@ -1,27 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# author: Vadim Shaveiko <@vshaveyko>
|
1
3
|
# :nodoc:
|
2
4
|
module RailsApiDoc::Controller::Response::Headers
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
title = row_values.attr.to_s
|
13
|
-
title += '(NESTED)' if row_values.nested?
|
14
|
-
title
|
15
|
-
}
|
16
|
-
},
|
17
|
-
'Desc' => {
|
18
|
-
value: -> (row_name, row_values) {
|
19
|
-
'TODO: description' # if row_values[:desc]
|
20
|
-
},
|
21
|
-
fill_type: :input,
|
22
|
-
param: :desc
|
23
|
-
}
|
24
|
-
}
|
6
|
+
include RailsApiDoc::Controller::Headers
|
7
|
+
|
8
|
+
RESPONSE_HEADERS = [
|
9
|
+
NAME_HEADER,
|
10
|
+
TYPE_HEADER,
|
11
|
+
VALUE_HEADER,
|
12
|
+
DESC_HEADER
|
13
|
+
].reduce(&:merge).freeze
|
25
14
|
|
26
15
|
def headers
|
27
16
|
RESPONSE_HEADERS
|
@@ -1,13 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# author: Vadim Shaveiko <@vshaveyko>
|
1
3
|
# :nodoc:
|
2
4
|
module RailsApiDoc
|
3
5
|
module Controller
|
4
6
|
module Response
|
5
|
-
|
7
|
+
|
8
|
+
#
|
9
|
+
# name - attribute key returned in json response
|
10
|
+
# attr - actual attribute usage attribute
|
11
|
+
# nested - attribute nesting if present
|
12
|
+
# model - attribute model if nested and has model
|
13
|
+
# desc - description for attribute
|
14
|
+
# type - attribute type if set
|
15
|
+
# id - param id in DB for lookup on display
|
16
|
+
#
|
17
|
+
class Param < RailsApiDoc::Controller::Param
|
18
|
+
|
19
|
+
define_accessors *VALID_RESPONSE_KEYS
|
20
|
+
|
21
|
+
def initialize(name, attr, nested, model = nil, desc = nil, type = nil, id = nil, action_type = nil, is_new: false)
|
22
|
+
@name = name
|
23
|
+
@store = {
|
24
|
+
name: name,
|
25
|
+
attr: attr,
|
26
|
+
nested: nested,
|
27
|
+
model: model,
|
28
|
+
desc: desc,
|
29
|
+
type: type,
|
30
|
+
action_type: action_type,
|
31
|
+
id: id
|
32
|
+
}.compact
|
33
|
+
|
34
|
+
@is_new = is_new
|
35
|
+
@new = []
|
36
|
+
end
|
6
37
|
|
7
38
|
def nested?
|
8
39
|
!nested.nil?
|
9
40
|
end
|
10
41
|
|
42
|
+
def display_value
|
43
|
+
title = attr.to_s
|
44
|
+
title += '(NESTED)' if nested?
|
45
|
+
title
|
46
|
+
end
|
47
|
+
|
11
48
|
end
|
12
49
|
end
|
13
50
|
end
|
@@ -7,48 +7,37 @@ module RailsApiDoc::Controller::Response
|
|
7
7
|
# :nodoc:
|
8
8
|
class Rabl
|
9
9
|
|
10
|
-
include RailsApiDoc::Controller::Response::Headers
|
11
|
-
|
12
10
|
class << self
|
13
11
|
|
14
12
|
attr_accessor :renderer
|
15
13
|
|
16
14
|
end
|
17
15
|
|
18
|
-
attr_reader :
|
16
|
+
attr_reader :repo
|
19
17
|
|
20
18
|
# pass all controllers registered for api doc
|
21
19
|
# TODO: add setting for displaying all from start
|
22
20
|
def initialize(controllers)
|
23
21
|
@controllers = controllers
|
24
|
-
@routes = Rails.application.routes.set.anchored_routes.reject { |r| r.defaults[:internal] }
|
25
|
-
@map = construct_controller_template_map
|
26
|
-
end
|
27
22
|
|
28
|
-
|
29
|
-
RablCompiler.new("#{ctrl.controller_path}/#{action}").compile_source
|
30
|
-
end
|
23
|
+
@routes = Rails.application.routes.set.anchored_routes.reject { |r| r.defaults[:internal] }
|
31
24
|
|
32
|
-
|
33
|
-
action_route = @map[ctrl][:routes].detect { |r| r.defaults[:action] == action }
|
34
|
-
return unless action_route
|
35
|
-
method = action_route.instance_variable_get(:@request_method_match)&.first&.name&.split('::')&.last
|
36
|
-
route = action_route.path.spec.to_s
|
37
|
-
[method, route].compact.join(' ')
|
25
|
+
@repo = construct_controller_template_map
|
38
26
|
end
|
39
27
|
|
40
|
-
private
|
41
|
-
|
42
28
|
def construct_controller_template_map
|
43
|
-
@controllers.each_with_object({}) do |ctrl,
|
44
|
-
|
29
|
+
@controllers.each_with_object({}) do |ctrl, repo|
|
30
|
+
repo[ctrl] = ctrl_actions(ctrl)
|
45
31
|
end
|
46
32
|
end
|
47
33
|
|
34
|
+
private
|
35
|
+
|
48
36
|
def ctrl_actions(ctrl)
|
49
37
|
routes = @routes.select do |route|
|
50
38
|
route.defaults[:controller].in?([ctrl.controller_path, ctrl.controller_name])
|
51
39
|
end
|
40
|
+
|
52
41
|
actions = routes.map { |r| r.defaults[:action] }
|
53
42
|
{
|
54
43
|
routes: routes,
|
@@ -23,9 +23,7 @@ module RailsApiDoc::Controller::Response
|
|
23
23
|
# end
|
24
24
|
|
25
25
|
def add(n)
|
26
|
-
if n[:attr] && n[:name] != n[:attr]
|
27
|
-
n[:name] = "#{n[:name]}(#{n[:attr]})"
|
28
|
-
end
|
26
|
+
n[:name] = "#{n[:name]}(#{n[:attr]})" if n[:attr] && n[:name] != n[:attr]
|
29
27
|
|
30
28
|
@nodes[n[:name]] = RailsApiDoc::Controller::Response::Param.new(n[:name], n[:attr], n[:nested])
|
31
29
|
end
|
@@ -159,8 +157,8 @@ module RailsApiDoc::Controller::Response
|
|
159
157
|
# merge { |item| partial("specific/#{item.to_s}", object: item) }
|
160
158
|
#
|
161
159
|
# def merge
|
162
|
-
|
163
|
-
|
160
|
+
# return unless block_given?
|
161
|
+
# yield
|
164
162
|
# end
|
165
163
|
|
166
164
|
#
|
@@ -181,13 +179,13 @@ module RailsApiDoc::Controller::Response
|
|
181
179
|
# end
|
182
180
|
#
|
183
181
|
# def condition(*)
|
184
|
-
|
185
|
-
|
186
|
-
|
182
|
+
# return unless block_given?
|
183
|
+
# template = sub_compile(nil, true) { yield }
|
184
|
+
# @attributes.extends template
|
187
185
|
# end
|
188
186
|
#
|
189
187
|
def method_missing(name, *attrs)
|
190
|
-
return p("#{name} is not implemented in railsApiDoc") if name.in?(
|
188
|
+
return p("#{name} is not implemented in railsApiDoc") if name.in?(%w(merge condtiion))
|
191
189
|
super
|
192
190
|
end
|
193
191
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# :nodoc:
|
2
|
+
class RailsApiDoc::Controller::Response::Repository
|
3
|
+
|
4
|
+
include RailsApiDoc::Controller::Repo
|
5
|
+
include RailsApiDoc::Controller::Response::Headers
|
6
|
+
|
7
|
+
def initialize(repo)
|
8
|
+
@repo = repo.clone.transform_values { |v| v.deep_dup }
|
9
|
+
end
|
10
|
+
|
11
|
+
def load_template(ctrl, action)
|
12
|
+
RailsApiDoc::Controller::Response::RablCompiler.new("#{ctrl.controller_path}/#{action}").compile_source
|
13
|
+
end
|
14
|
+
|
15
|
+
def action_route(ctrl, action)
|
16
|
+
return unless action_route = action_route_for(ctrl, action)
|
17
|
+
|
18
|
+
{
|
19
|
+
method: method(action_route),
|
20
|
+
url: url(action_route)
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def method(route)
|
27
|
+
route.instance_variable_get(:@request_method_match)&.first&.name&.split('::')&.last
|
28
|
+
end
|
29
|
+
|
30
|
+
def url(a_route)
|
31
|
+
a_route.path.spec.to_s.gsub(/(\(.*\))/, '')
|
32
|
+
end
|
33
|
+
|
34
|
+
def action_route_for(ctrl, action)
|
35
|
+
@repo[ctrl][:routes].detect { |r| r.defaults[:action] == action }
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# author: Vadim Shaveiko <@vshaveyko>
|
3
|
+
# :nodoc:
|
4
|
+
class RailsApiDoc::Model::AttributeMerger
|
5
|
+
|
6
|
+
MODEL = RailsApiDoc::ApiDatum
|
7
|
+
MERGABLE_FIELDS = [:type, :desc, :action_type].freeze
|
8
|
+
|
9
|
+
#
|
10
|
+
# do not mutate attributes
|
11
|
+
#
|
12
|
+
# please - impossible
|
13
|
+
#
|
14
|
+
def initialize(attributes)
|
15
|
+
@attrs = attributes
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(api_type:)
|
19
|
+
@api_type = api_type
|
20
|
+
|
21
|
+
api_params = MODEL.where(api_type: api_type).all.each do |param|
|
22
|
+
_add_nested_param(param)
|
23
|
+
end
|
24
|
+
|
25
|
+
@attrs
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def _add_nested_param(param)
|
31
|
+
# nesting should be present for parameter to appear
|
32
|
+
return if param.nesting.blank?
|
33
|
+
|
34
|
+
attrs, nesting, name = _parse_settings(param)
|
35
|
+
|
36
|
+
return unless name
|
37
|
+
|
38
|
+
ctrl_param = _find_param(nesting, name, attrs)
|
39
|
+
|
40
|
+
ctrl_param.param = param
|
41
|
+
# _merge_data_to_param(ctrl_param, param)
|
42
|
+
end
|
43
|
+
|
44
|
+
def _parse_settings(param)
|
45
|
+
ctrl = param.nesting[0].constantize
|
46
|
+
nesting = param.nesting[1..-1]
|
47
|
+
name = param.name&.to_sym
|
48
|
+
attrs = @attrs[ctrl]
|
49
|
+
|
50
|
+
#
|
51
|
+
# making exception
|
52
|
+
# until request parameters are not split by actions
|
53
|
+
#
|
54
|
+
attrs = attrs[param.api_action] if @api_type == 'response'
|
55
|
+
|
56
|
+
[attrs, nesting, name]
|
57
|
+
end
|
58
|
+
|
59
|
+
def _merge_data_to_param(ctrl_param, param)
|
60
|
+
MERGABLE_FIELDS.each do |field|
|
61
|
+
next if ctrl_param_value = ctrl_param.public_send(field) # do not override data set in api ctrl
|
62
|
+
|
63
|
+
param_value = param.public_send(field)
|
64
|
+
next if param_value.blank?
|
65
|
+
|
66
|
+
ctrl_param.public_send("#{field}=", param_value)
|
67
|
+
ctrl_param.add_updated_field(field)
|
68
|
+
end
|
69
|
+
|
70
|
+
_merge_special(ctrl_param, param)
|
71
|
+
end
|
72
|
+
|
73
|
+
def _merge_special(ctrl_param, param)
|
74
|
+
return if param.special.blank?
|
75
|
+
|
76
|
+
if ctrl_param.enum? && ctrl_param.enum.blank?
|
77
|
+
ctrl_param.enum = _parse_enum(param.special)
|
78
|
+
ctrl_param.add_updated_field('enum')
|
79
|
+
elsif ctrl_param.nested? && ctrl_param.model.blank?
|
80
|
+
ctrl_param.model = special.capitalize
|
81
|
+
ctrl_param.add_updated_field('model')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def _find_param(nesting, name, attrs)
|
86
|
+
nesting.each do |model|
|
87
|
+
nested_attrs = attrs.each_value.detect { |v| v.nested? && v.model == model }
|
88
|
+
|
89
|
+
attrs = nested_attrs ? nested_attrs : _define_nesting_level(attrs, name, model)
|
90
|
+
end
|
91
|
+
|
92
|
+
if attrs[name]
|
93
|
+
attrs[name]
|
94
|
+
else
|
95
|
+
attrs[name] = _init_param_for_api_type(name)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def _define_nesting_level(attrs, name, model)
|
100
|
+
attr = _init_param_for_api_type(name, type: :object, model: model, nested: {})
|
101
|
+
|
102
|
+
attrs[name] = attr
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# common attrs:
|
107
|
+
# 1. name
|
108
|
+
# 2. type
|
109
|
+
# 3. desc
|
110
|
+
# 4. model
|
111
|
+
# 5. id
|
112
|
+
# 6. nested
|
113
|
+
#
|
114
|
+
# request attrs:
|
115
|
+
# 1. enum
|
116
|
+
# 2. value
|
117
|
+
# 3. required
|
118
|
+
#
|
119
|
+
# response attrs:
|
120
|
+
# 1. attr
|
121
|
+
#
|
122
|
+
def _init_param_for_api_type(name, options)
|
123
|
+
if @api_type == 'request'
|
124
|
+
RailsApiDoc::Controller::Request::Param.new(name, options, is_new: true)
|
125
|
+
elsif @api_type == 'response'
|
126
|
+
RailsApiDoc::Controller::Response::Param.new(name, name, options[:nested], options[:model], '', options[:type], is_new: true)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -5,16 +5,20 @@ class RailsApiDoc::Model::AttributeParser
|
|
5
5
|
|
6
6
|
# TODO : Change to I18n. Added on: 08.10.16. Added by: <@vshaveyko>
|
7
7
|
WRONG_NAME_ERROR_STRING = 'Name should consist only of letters\ciphers\underscores'
|
8
|
+
WRONG_TYPE_ERROR_STRING = 'Wrong type saved'
|
8
9
|
|
9
10
|
class << self
|
10
11
|
|
11
12
|
def parse_attributes(params)
|
12
|
-
type = :enum if params[:enum].present?
|
13
|
-
|
14
13
|
{
|
15
14
|
name: parse_name(params[:name]),
|
16
|
-
type:
|
17
|
-
|
15
|
+
type: parse_type(params[:type]),
|
16
|
+
desc: params[:desc],
|
17
|
+
special: parse_special(params[:type], params[:special]),
|
18
|
+
action_type: params[:action],
|
19
|
+
nesting: params[:nesting],
|
20
|
+
api_type: params[:api_type],
|
21
|
+
id: params[:id]
|
18
22
|
}.compact
|
19
23
|
end
|
20
24
|
|
@@ -46,9 +50,23 @@ class RailsApiDoc::Model::AttributeParser
|
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
53
|
+
def parse_special(type, special)
|
54
|
+
return unless special.present? && type
|
55
|
+
|
56
|
+
if type == :enum
|
57
|
+
parse_enum(special) # parse as enum array value
|
58
|
+
elsif RailsApiDoc::NESTED_TYPES.include?(type.to_sym)
|
59
|
+
special.capitalize # parse as model name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
49
63
|
def parse_type(type)
|
50
64
|
return if type.blank?
|
51
|
-
|
65
|
+
|
66
|
+
type = type.to_sym
|
67
|
+
raise NameError, WRONG_TYPE_ERROR_STRING unless type.in?(RailsApiDoc::ACCEPTED_TYPES)
|
68
|
+
|
69
|
+
type
|
52
70
|
end
|
53
71
|
|
54
72
|
end
|