api_docs_engine 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/app/assets/javascripts/docs.js.coffee +42 -0
- data/app/assets/javascripts/highlight.js +1 -0
- data/app/assets/stylesheets/docs.css.scss +127 -0
- data/app/assets/stylesheets/highlight/styles/github.css +129 -0
- data/app/controllers/concerns/docs/manage_resource.rb +98 -0
- data/app/controllers/docs/application_controller.rb +24 -0
- data/app/controllers/docs/markdown_controller.rb +8 -0
- data/app/controllers/docs/missing_docs_controller.rb +7 -0
- data/app/controllers/docs/page_categories_controller.rb +27 -0
- data/app/controllers/docs/pages_controller.rb +56 -0
- data/app/helpers/docs/application_helper.rb +47 -0
- data/app/models/docs/missing_collection.rb +11 -0
- data/app/models/docs/page.rb +64 -0
- data/app/models/docs/page_category.rb +30 -0
- data/app/models/docs/routes_collection.rb +71 -0
- data/app/views/docs/application/edit.html.slim +2 -0
- data/app/views/docs/application/new.html.slim +2 -0
- data/app/views/docs/layouts/docs.html.slim +24 -0
- data/app/views/docs/markdown/create.json.erb +3 -0
- data/app/views/docs/missing_docs/index.html.slim +9 -0
- data/app/views/docs/page_categories/_form.html.slim +19 -0
- data/app/views/docs/pages/_form.html.slim +35 -0
- data/app/views/docs/pages/_page.html.slim +24 -0
- data/app/views/docs/pages/index.html.slim +34 -0
- data/config/initializers/formtastic.rb +1 -0
- data/config/routes.rb +5 -0
- data/lib/api_docs_engine/docs.rb +50 -0
- data/lib/api_docs_engine.rb +2 -0
- data/lib/bootstrap/active_link_to.rb +135 -0
- data/lib/bootstrap/markdown_renderer.rb +10 -0
- data/lib/docs/core_ext.rb +39 -0
- data/lib/docs/engine.rb +9 -0
- data/lib/generators/active_record/api_docs_engine_generator.rb +16 -0
- data/lib/generators/active_record/templates/migration.rb +27 -0
- data/lib/generators/api_docs_engine/api_docs_engine_generator.rb +12 -0
- data/lib/generators/api_docs_engine/install_generator.rb +16 -0
- data/lib/generators/api_docs_engine/orm_helpers.rb +10 -0
- data/lib/generators/templates/api_docs_engine.rb +11 -0
- metadata +284 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
module Docs
|
2
|
+
class PageCategory < ActiveRecord::Base
|
3
|
+
extend FriendlyId
|
4
|
+
friendly_id :slug, use: :slugged
|
5
|
+
has_many :pages
|
6
|
+
alias_attribute :name, :title
|
7
|
+
|
8
|
+
before_validation :set_missing_title, unless: :title?
|
9
|
+
|
10
|
+
validates :slug, :title, presence: true
|
11
|
+
validates :slug, uniqueness: true, on: :create
|
12
|
+
|
13
|
+
def weight
|
14
|
+
@weight ||= splitted_title[0].to_i.nonzero? || 100
|
15
|
+
end
|
16
|
+
|
17
|
+
def only_title
|
18
|
+
@captures ||= splitted_title[1]
|
19
|
+
end
|
20
|
+
|
21
|
+
def splitted_title
|
22
|
+
@splitted_title ||= title.match(/^(?:(\d+)\. )?(.+)$/).captures
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def set_missing_title
|
27
|
+
self.title = slug.to_s.titleize
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Docs
|
2
|
+
class RoutesCollection
|
3
|
+
include Enumerable
|
4
|
+
attr_reader :routes
|
5
|
+
|
6
|
+
def initialize(filter = nil)
|
7
|
+
filter ||= Docs.missing_routes_filter
|
8
|
+
@routes = Inspector.new(Rails.application.routes.routes).enumerate(filter)
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](name)
|
12
|
+
routes[name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def each(&block)
|
16
|
+
routes.each(&block)
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def by_controller
|
21
|
+
routes.group_by(&:controller)
|
22
|
+
end
|
23
|
+
|
24
|
+
class Item
|
25
|
+
attr_accessor :path, :via, :reqs, :pattern, :controller, :action
|
26
|
+
|
27
|
+
def initialize(route)
|
28
|
+
@path = route.path.sub(/\(\.:format\)$/, '.json')
|
29
|
+
@via = route.verb
|
30
|
+
@reqs = route.reqs
|
31
|
+
@pattern = route.json_regexp
|
32
|
+
@controller, @action = reqs.split("#")
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_page_attributes
|
36
|
+
{ path: path, via: via, reqs: reqs, page_category_slug: controller[/^api\/(\w+)/, 1] }
|
37
|
+
end
|
38
|
+
|
39
|
+
def inspect
|
40
|
+
"#{via} #{path} => #{reqs}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Inspector < ::ActionDispatch::Routing::RoutesInspector
|
45
|
+
def enumerate(filter = nil)
|
46
|
+
routes_to_display = filter_routes(filter)
|
47
|
+
collect_routes(routes_to_display)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def filter_routes(filter)
|
52
|
+
if filter
|
53
|
+
@routes.select { |route| route.defaults[:controller] =~ filter }
|
54
|
+
else
|
55
|
+
@routes
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def collect_routes(routes)
|
60
|
+
routes.collect do |route|
|
61
|
+
ActionDispatch::Routing::RouteWrapper.new(route)
|
62
|
+
end.reject do |route|
|
63
|
+
route.internal?
|
64
|
+
end.collect do |route|
|
65
|
+
collect_engine_routes(route)
|
66
|
+
Item.new(route)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
doctype 5
|
2
|
+
html lang="en"
|
3
|
+
head
|
4
|
+
meta charset="utf-8"
|
5
|
+
meta name="viewport" content="width=device-width, initial-scale=1.0"
|
6
|
+
title = content_for?(:title) ? yield(:title) : Docs.title
|
7
|
+
= csrf_meta_tags
|
8
|
+
= stylesheet_link_tag "docs", media: "all"
|
9
|
+
= javascript_include_tag "docs"
|
10
|
+
body
|
11
|
+
.container-fluid
|
12
|
+
.row
|
13
|
+
#left-sidebar.col-sm-3.col-md-2.sidebar
|
14
|
+
ul.nav.nav-sidebar
|
15
|
+
- Docs::PageCategory.all.sort_by(&:weight).each do |c|
|
16
|
+
= li_active_to c.only_title, page_category_pages_path(c), data: { edit_path: edit_page_category_path(c) }
|
17
|
+
.row
|
18
|
+
.btn-group.btn-group-xs.pull-right
|
19
|
+
= link_to fa_icon(:plus, text: "Add category"), new_page_category_path, class: "btn btn-default"
|
20
|
+
= link_to fa_icon(:warning, text: "Missing"), missing_docs_path, class: "btn btn-default"
|
21
|
+
|
22
|
+
.col-sm-9.col-sm-offset-3.col-md-10.col-md-offset-2.main
|
23
|
+
h1.page-header = content_for?(:title) ? yield(:title) : Docs.title
|
24
|
+
= yield
|
@@ -0,0 +1,19 @@
|
|
1
|
+
= semantic_form_for @page_category do |f|
|
2
|
+
.row
|
3
|
+
.col-sm-5
|
4
|
+
= f.input :title
|
5
|
+
.col-sm-5
|
6
|
+
= f.input :slug
|
7
|
+
.col-sm-2 style="padding-top: 25px;"
|
8
|
+
= f.action :submit, button_html: { class: "btn btn-primary btn-block" }
|
9
|
+
|
10
|
+
ul.nav.nav-tabs role="tablist"
|
11
|
+
li.active = link_to "Description", "#desc", role: 'tab', data: { toggle: 'tab' }
|
12
|
+
li = link_to "Preview", "#preview", role: 'tab', data: { toggle: 'tab' }
|
13
|
+
|
14
|
+
= f.inputs do
|
15
|
+
.tab-content
|
16
|
+
#desc.tab-pane.fade.in.active
|
17
|
+
= f.input :body, input_html: { rows: 30, class: "process-markdown" }, label: false
|
18
|
+
#preview.tab-pane
|
19
|
+
.preview-markdown data-source=".process-markdown"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
= semantic_form_for @page do |f|
|
2
|
+
.row
|
3
|
+
.col-sm-6
|
4
|
+
= f.input :title
|
5
|
+
.col-sm-4
|
6
|
+
= f.input :page_category_slug
|
7
|
+
.col-sm-2 style="padding-top: 25px;"
|
8
|
+
= f.action :submit, button_html: { class: "btn btn-primary btn-block" }
|
9
|
+
.row
|
10
|
+
.col-sm-2
|
11
|
+
= f.input :via
|
12
|
+
.col-sm-4
|
13
|
+
= f.input :path
|
14
|
+
.col-sm-4
|
15
|
+
= f.input :reqs
|
16
|
+
.col-sm-2
|
17
|
+
= f.input :weight
|
18
|
+
|
19
|
+
ul.nav.nav-tabs role="tablist"
|
20
|
+
li.active
|
21
|
+
= link_to "Description", "#desc", role: 'tab', data: { toggle: 'tab' }
|
22
|
+
li
|
23
|
+
= link_to fa_icon(:eye, text: "Preview"), "#preview", role: 'tab', data: { toggle: 'tab' }
|
24
|
+
li
|
25
|
+
= link_to fa_icon(:code, text: "Example"), "#example", role: 'tab', data: { toggle: 'tab' }
|
26
|
+
|
27
|
+
|
28
|
+
= f.inputs do
|
29
|
+
.tab-content
|
30
|
+
#desc.tab-pane.fade.in.active
|
31
|
+
= f.input :body, input_html: { rows: 30, class: "process-markdown" }, label: false
|
32
|
+
#preview.tab-pane
|
33
|
+
.preview-markdown data-source=".process-markdown"
|
34
|
+
#example.tab-pane
|
35
|
+
= f.input :example, input_html: { rows: 20 }, label: false
|
@@ -0,0 +1,24 @@
|
|
1
|
+
.action
|
2
|
+
h3 id=page.anchor = page.title
|
3
|
+
|
4
|
+
.panel.panel-default
|
5
|
+
.panel-heading
|
6
|
+
code == "#{content_tag :strong, page.via} #{page.only_path}#{content_tag :span, page.only_query, class: 'text-muted'}"
|
7
|
+
.navbar.navbar-default.navbar-static-top.panel-navbar
|
8
|
+
ul.nav.navbar-nav role="tablist"
|
9
|
+
li class=( "active" if page.body.present? )
|
10
|
+
= link_to fa_icon('info-circle'), "##{page.anchor}-desc", role: "tab", data: { toggle: "tab" }
|
11
|
+
li class=( "active" unless page.body.present? )
|
12
|
+
= link_to fa_icon(:code, text: "Example"), "##{page.anchor}-example", role: "tab", data: { toggle: "tab" }
|
13
|
+
li
|
14
|
+
= link_to fa_icon(:edit), edit_page_path(page)
|
15
|
+
|
16
|
+
.tab-content.panel-body
|
17
|
+
.tab-pane id="#{page.anchor}-desc" class=( "active" if page.body.present? )
|
18
|
+
p
|
19
|
+
- if page.body?
|
20
|
+
== markdown(page.body)
|
21
|
+
.tab-pane id="#{page.anchor}-example" class=( "active" unless page.body.present? )
|
22
|
+
p
|
23
|
+
- if page.example?
|
24
|
+
pre: samp.json == page.example
|
@@ -0,0 +1,34 @@
|
|
1
|
+
- content_for :title, @page_category.only_title
|
2
|
+
|
3
|
+
.row
|
4
|
+
.col-md-9
|
5
|
+
- if @pages.any?
|
6
|
+
.panel.panel-default
|
7
|
+
.panel-heading: h4.panel-title Методы
|
8
|
+
table.table.table-condensed
|
9
|
+
tbody
|
10
|
+
- @pages.each do |page|
|
11
|
+
tr
|
12
|
+
td
|
13
|
+
code == "#{content_tag :strong, page.via} #{page.only_path}"
|
14
|
+
td
|
15
|
+
= link_to page.title, "##{page.anchor}"
|
16
|
+
td
|
17
|
+
small.text-muted = page.reqs
|
18
|
+
|
19
|
+
- if @page_category.body?
|
20
|
+
== markdown(@page_category.body)
|
21
|
+
|
22
|
+
- if @pages.any?
|
23
|
+
.actions
|
24
|
+
= render @pages
|
25
|
+
|
26
|
+
.col-md-3
|
27
|
+
.navbar-spyscroll
|
28
|
+
ul.nav.nav-right-spy role="tablist"
|
29
|
+
- @pages.each do |page|
|
30
|
+
li = link_to "#{content_tag(:strong, page.via)} #{page.only_path}".html_safe, "##{page.anchor}"
|
31
|
+
hr /
|
32
|
+
.btn-group.btn-group-xs
|
33
|
+
= link_to fa_icon(:edit, text: "Edit"), [:edit, @page_category], class: "btn btn-default"
|
34
|
+
= link_to fa_icon(:plus, text: "Add page"), [:new, @page_category, :page], class: "btn btn-default"
|
@@ -0,0 +1 @@
|
|
1
|
+
Formtastic::Helpers::FormHelper.builder = FormtasticBootstrap::FormBuilder
|
data/config/routes.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'slim-rails'
|
2
|
+
require 'sass-rails'
|
3
|
+
require 'jquery-rails'
|
4
|
+
require 'coffee-rails'
|
5
|
+
require 'bootstrap-sass'
|
6
|
+
require 'font-awesome-rails'
|
7
|
+
require 'redcarpet'
|
8
|
+
require 'friendly_id'
|
9
|
+
require 'formtastic'
|
10
|
+
require 'formtastic-bootstrap'
|
11
|
+
require 'turbolinks'
|
12
|
+
|
13
|
+
module Docs
|
14
|
+
mattr_accessor :title
|
15
|
+
@@title = "API documentation"
|
16
|
+
|
17
|
+
mattr_accessor :root_path
|
18
|
+
@@root_path = "missing_docs#index"
|
19
|
+
|
20
|
+
mattr_accessor :missing_routes_filter
|
21
|
+
@@missing_routes_filter = /api\/.*/
|
22
|
+
|
23
|
+
mattr_accessor :api_docs_prefix
|
24
|
+
@@api_docs_prefix = "api"
|
25
|
+
|
26
|
+
mattr_accessor :auth
|
27
|
+
@@auth = nil
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def setup
|
31
|
+
yield self
|
32
|
+
end
|
33
|
+
|
34
|
+
def route(router)
|
35
|
+
router.instance_exec do
|
36
|
+
root Docs.root_path
|
37
|
+
|
38
|
+
resources :missing_docs, only: [:index]
|
39
|
+
resources :page_categories, except: [:index, :show, :edit]
|
40
|
+
resources :pages, except: [:index, :show]
|
41
|
+
|
42
|
+
resources :page_categories, shallow: true, path: Docs.api_docs_prefix, only: [:edit] do
|
43
|
+
resources :pages, only: [:index, :new, :create], path: "", path_names: { new: "new_page" }
|
44
|
+
end
|
45
|
+
|
46
|
+
resources :markdown, only: "create"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "docs/core_ext"
|
2
|
+
|
3
|
+
module Bootstrap
|
4
|
+
module ActiveLinkTo
|
5
|
+
class ActiveLink
|
6
|
+
ACTIVE_OPTIONS = [:active, :class_active, :class_inactive, :active_disable]
|
7
|
+
|
8
|
+
def initialize(context)
|
9
|
+
@context = context
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(*args, &block)
|
13
|
+
@name = block_given? ? capture(&block) : args.shift
|
14
|
+
@link_options = args.extract_options!
|
15
|
+
@url = h.url_for(args.shift)
|
16
|
+
@active_options = @link_options.extract!(*ACTIVE_OPTIONS).only_presented
|
17
|
+
@after_link = @link_options.delete(:after_link).to_s
|
18
|
+
|
19
|
+
if is_wrap?
|
20
|
+
provide_wrap_with_content!
|
21
|
+
else
|
22
|
+
@link_options.smart_append_to :class, active_class
|
23
|
+
content
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def content
|
29
|
+
"#{link}#{@after_link}".html_safe
|
30
|
+
end
|
31
|
+
|
32
|
+
def h
|
33
|
+
@context
|
34
|
+
end
|
35
|
+
|
36
|
+
def link
|
37
|
+
return @name if is_active? && is_active_disable?
|
38
|
+
h.link_to @name, @url, @link_options
|
39
|
+
end
|
40
|
+
|
41
|
+
def is_active?
|
42
|
+
@is_active = h.is_active_link?(@url, @active_options[:active]) if @is_active.nil?
|
43
|
+
@is_active
|
44
|
+
end
|
45
|
+
|
46
|
+
def is_wrap?
|
47
|
+
!@link_options[:wrap_tag].nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
def is_dropdown?
|
51
|
+
!@link_options[:dropdown].nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def is_active_disable?
|
55
|
+
!!@active_options[:active_disable]
|
56
|
+
end
|
57
|
+
|
58
|
+
def provide_wrap_with_content!
|
59
|
+
@link_options[:wrap_options] ||= {}
|
60
|
+
@wrap_options, wrap_tag = @link_options.extract!(:wrap_options, :wrap_tag).values
|
61
|
+
@wrap_options.smart_append_to :class, active_class
|
62
|
+
|
63
|
+
provide_dropdown! if is_dropdown?
|
64
|
+
|
65
|
+
h.content_tag wrap_tag, content, @wrap_options
|
66
|
+
end
|
67
|
+
|
68
|
+
def provide_dropdown!
|
69
|
+
dropdown_html, dropdown = @link_options.extract!(:dropdown_html, :dropdown).values
|
70
|
+
@wrap_options.smart_append_to :class, 'dropdown'
|
71
|
+
@link_options.smart_update class: ['dropdown-toggle'], id: dropdown, data: {toggle: 'dropdown', hover: 'dropdown'}
|
72
|
+
@after_link << dropdown_html.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def active_class
|
76
|
+
h.active_link_to_class(@url, @active_options, is_active?)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Wrapper around link_to. Accepts following params:
|
81
|
+
# :active => Boolean | Symbol | Regex | Controller/Action Pair
|
82
|
+
# :class_active => String
|
83
|
+
# :class_inactive => String
|
84
|
+
# :disable_active => Boolean
|
85
|
+
# :wrap_tag => Symbol
|
86
|
+
# Example usage:
|
87
|
+
# active_link_to('/users', :class_active => 'enabled')
|
88
|
+
# active_link_to(users_path, :active => :exclusive, :wrap_tag => :li)
|
89
|
+
def active_link_to(*args, &block)
|
90
|
+
ActiveLink.new(self).render(*args, &block)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns css class name. Takes the link's URL and its params
|
94
|
+
# Example usage:
|
95
|
+
# active_link_to_class('/root', :class_active => 'on', :class_inactive => 'off')
|
96
|
+
#
|
97
|
+
def active_link_to_class(url, options={}, is_active=nil)
|
98
|
+
is_active = is_active_link?(url, options[:active]) if is_active.nil?
|
99
|
+
is_active ? (options[:class_active] ||= 'active') : options[:class_inactive]
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns true or false based on the provided path and condition
|
103
|
+
# Possible condition values are:
|
104
|
+
# Boolean -> true | false
|
105
|
+
# Symbol -> :exclusive | :inclusive
|
106
|
+
# Regex -> /regex/
|
107
|
+
# Controller/Action Pair -> [[:controller], [:action_a, :action_b]]
|
108
|
+
# Example usage:
|
109
|
+
# is_active_link?('/root', true)
|
110
|
+
# is_active_link?('/root', :exclusive)
|
111
|
+
# is_active_link?('/root', /^\/root/)
|
112
|
+
# is_active_link?('/root', ['users', ['show', 'edit']])
|
113
|
+
#
|
114
|
+
def is_active_link?(url, condition = nil)
|
115
|
+
url = url_for(url).sub(/\?.*/, '') # ignore GET params
|
116
|
+
case condition
|
117
|
+
when :inclusive, nil
|
118
|
+
!request.fullpath.match(/^#{Regexp.escape(url)}(\/.*|\?.*)?$/).blank?
|
119
|
+
when :exclusive
|
120
|
+
!request.fullpath.match(/^#{Regexp.escape(url)}\/?(\?.*)?$/).blank?
|
121
|
+
when Regexp
|
122
|
+
!request.fullpath.match(condition).blank?
|
123
|
+
when Array
|
124
|
+
controllers = [*condition[0]]
|
125
|
+
actions = [*condition[1]]
|
126
|
+
(controllers.blank? || controllers.member?(params[:controller])) &&
|
127
|
+
(actions.blank? || actions.member?(params[:action]))
|
128
|
+
when TrueClass
|
129
|
+
true
|
130
|
+
when FalseClass
|
131
|
+
false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Hash
|
2
|
+
def smart_append_to(key, value, delimeter=' ')
|
3
|
+
if self[key].nil?
|
4
|
+
self[key] ||= value
|
5
|
+
else
|
6
|
+
self[key] << delimeter if self[key].is_a?(String)
|
7
|
+
self[key] << value
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def smart_merge(other)
|
12
|
+
return self unless other.is_a? Hash and other.any?
|
13
|
+
return other unless self.any?
|
14
|
+
|
15
|
+
self.merge other do |key, left, right|
|
16
|
+
case left
|
17
|
+
when Hash
|
18
|
+
right.is_a?(Hash) ? left.smart_merge(right) : right
|
19
|
+
when Array
|
20
|
+
(left | [right]).flatten
|
21
|
+
when String
|
22
|
+
right.is_a?(Array) ? ([left]|right).flatten : right
|
23
|
+
else right
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def smart_merge!(other_hash)
|
29
|
+
self.replace(empty? ? other_hash : smart_merge(other_hash))
|
30
|
+
end
|
31
|
+
|
32
|
+
def smart_update(other_hash)
|
33
|
+
self.replace(other_hash.smart_merge(self))
|
34
|
+
end
|
35
|
+
|
36
|
+
def only_presented
|
37
|
+
select {|_, v| v.present? }
|
38
|
+
end
|
39
|
+
end
|
data/lib/docs/engine.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
require 'generators/api_docs_engine/orm_helpers'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module Generators
|
6
|
+
class ApiDocsEngine < ActiveRecord::Generators::Base
|
7
|
+
source_root File.expand_path("../templates", __FILE__)
|
8
|
+
|
9
|
+
include ::ApiDocsEngine::Generators::OrmHelpers
|
10
|
+
|
11
|
+
def copy_api_docs_engine_migration
|
12
|
+
migration_template "migration.rb", "db/migrate/api_docs_create.rb"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class ApiDocsCreate < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
enable_extension :hstore
|
4
|
+
|
5
|
+
create_table :docs_page_categories do |t|
|
6
|
+
t.string :slug, index: { unique: true }
|
7
|
+
t.string :title
|
8
|
+
t.text :body
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :docs_pages do |t|
|
12
|
+
t.belongs_to :page_category, index: true
|
13
|
+
t.string :path
|
14
|
+
t.string :via
|
15
|
+
t.string :title
|
16
|
+
t.text :body
|
17
|
+
t.text :example
|
18
|
+
t.hstore :data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def down
|
23
|
+
drop_table :docs_pages
|
24
|
+
drop_table :docs_page_categories
|
25
|
+
disable_extension :hstore
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module ApiDocsEngine
|
4
|
+
module Generators
|
5
|
+
class ApiDocsEngineGenerator < Rails::Generators::Base
|
6
|
+
hook_for :orm
|
7
|
+
|
8
|
+
namespace "api_docs_engine"
|
9
|
+
source_root File.expand_path("../templates", __FILE__)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
module ApiDocsEngine
|
5
|
+
module Generators
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
source_root File.expand_path("../../templates", __FILE__)
|
8
|
+
|
9
|
+
class_option :orm
|
10
|
+
|
11
|
+
def copy_initializer
|
12
|
+
template "api_docs_engine.rb", "config/initializers/api_docs_engine.rb"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Docs.setup do |config|
|
2
|
+
# config.title = "API documentation"
|
3
|
+
# config.root_path = { to: "pages#index", defaults: { page_category_id: "common" }}
|
4
|
+
# config.missing_routes_filter = /api\/.*/
|
5
|
+
# config.api_docs_prefix = "api"
|
6
|
+
# config.auth = Proc.new do |controller|
|
7
|
+
# controller.class_eval do
|
8
|
+
# http_basic_authenticate_with name: "admin", password: "admin", only: nil
|
9
|
+
# end
|
10
|
+
# end
|
11
|
+
end
|