fern-documentation 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/fern-documentation.rb +1 -0
- data/lib/fern/documentation.rb +4 -0
- data/lib/fern/documentation/dsl.rb +20 -0
- data/lib/fern/documentation/markdown_generator.rb +94 -0
- data/lib/fern/documentation/railtie.rb +9 -0
- data/lib/fern/documentation/route_analyzer.rb +54 -0
- data/lib/fern/documentation/version.rb +5 -0
- data/lib/tasks/docs.rake +36 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3491257137267e449dc4e108d412604532bafd24
|
4
|
+
data.tar.gz: e070df10cc6dcaca700bcf9693736d718f4d8bc5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cd10e17c74c1d98ddfac57ddbde87218ad24578c0b9435075f086241d57ff06b06af93d89da0eccf8d5c6d75202d763c46ca28da6f881b149f6d92a858832441
|
7
|
+
data.tar.gz: 9c5a3f95fe0c43a4f7c0f451be478a1716fded5f8e7dfea01136e080c18d284f2059db43095ff6a456d99ef2d4ace3554940653ad6ea328282425f867dee057e
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'fern/documentation'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'fern/api'
|
2
|
+
|
3
|
+
module Fern
|
4
|
+
module Documentation
|
5
|
+
module Dsl
|
6
|
+
def self.included(receiver)
|
7
|
+
receiver.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
def doc(str)
|
14
|
+
@controller.fern[@name][:doc] = str
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Fern::Api::Endpoint.class_eval { include Fern::Documentation::Dsl }
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
module Fern
|
4
|
+
module Documentation
|
5
|
+
class MarkdownGenerator
|
6
|
+
TEMPLATE = %(# {{verb}} {{path}}
|
7
|
+
|
8
|
+
_{{controller}}\#{{action}}_
|
9
|
+
|
10
|
+
{{doc}}
|
11
|
+
|
12
|
+
{{#has_parameters}}
|
13
|
+
## Parameters
|
14
|
+
|
15
|
+
| Name | Type | Array | Required | Min | Max | Values | Default |
|
16
|
+
| ---- | ---- | ----- | -------- | --- | --- | ------ | ------- |
|
17
|
+
{{#parameters}}
|
18
|
+
| {{name}} | `{{ type }}` | {{ array }} | {{ required }} | {{ min }} | {{ max }} | {{ values }} | {{ default }} |
|
19
|
+
{{/parameters}}
|
20
|
+
{{/has_parameters}}
|
21
|
+
|
22
|
+
{{#has_form}}
|
23
|
+
## Form
|
24
|
+
|
25
|
+
{{#form}}
|
26
|
+
### Class
|
27
|
+
|
28
|
+
`{{klass}}`
|
29
|
+
|
30
|
+
{{#key}}
|
31
|
+
### Key
|
32
|
+
|
33
|
+
`{{key}}`
|
34
|
+
{{/key}}
|
35
|
+
{{/form}}
|
36
|
+
|
37
|
+
{{#presenter}}
|
38
|
+
## Presenter
|
39
|
+
|
40
|
+
### Class
|
41
|
+
|
42
|
+
`{{presenter}}`
|
43
|
+
{{/presenter}}
|
44
|
+
{{/has_form}}).freeze
|
45
|
+
|
46
|
+
def initialize(analysis)
|
47
|
+
@analysis = analysis
|
48
|
+
end
|
49
|
+
|
50
|
+
def generate
|
51
|
+
params = build_params
|
52
|
+
|
53
|
+
Mustache.render(
|
54
|
+
TEMPLATE,
|
55
|
+
verb: @analysis[:verb],
|
56
|
+
path: @analysis[:path],
|
57
|
+
controller: @analysis[:controller],
|
58
|
+
action: @analysis[:action],
|
59
|
+
doc: @analysis[:doc],
|
60
|
+
has_parameters: params.present?,
|
61
|
+
parameters: params,
|
62
|
+
has_form: @analysis[:form].present?,
|
63
|
+
form: @analysis[:form],
|
64
|
+
presenter: @analysis[:presenter]
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def build_params
|
71
|
+
return if @analysis[:params].nil?
|
72
|
+
@analysis[:params].map { |name, config| build_param(name, config) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_param(name, config)
|
76
|
+
constraints = config[:constraints]
|
77
|
+
{
|
78
|
+
name: name,
|
79
|
+
type: config[:type],
|
80
|
+
array: check(constraints[:array]),
|
81
|
+
required: check(constraints[:required]),
|
82
|
+
min: constraints[:min],
|
83
|
+
max: constraints[:max],
|
84
|
+
values: constraints[:values]&.join(', '),
|
85
|
+
default: constraints[:default]
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def check(val)
|
90
|
+
val ? '✓' : ''
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Fern
|
2
|
+
module Documentation
|
3
|
+
class RouteAnalyzer
|
4
|
+
def initialize(route)
|
5
|
+
@route = route
|
6
|
+
end
|
7
|
+
|
8
|
+
def analyze
|
9
|
+
return nil if path.nil?
|
10
|
+
|
11
|
+
puts "Analyzing #{path}"
|
12
|
+
|
13
|
+
{
|
14
|
+
verb: verb,
|
15
|
+
path: path,
|
16
|
+
controller_name: controller_name,
|
17
|
+
controller: controller,
|
18
|
+
action: action,
|
19
|
+
params: fern[:params],
|
20
|
+
doc: fern[:doc],
|
21
|
+
form: fern[:form],
|
22
|
+
presenter: fern[:presenter]
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def action
|
29
|
+
@route.defaults[:action]
|
30
|
+
end
|
31
|
+
|
32
|
+
def controller
|
33
|
+
"#{controller_name.camelize}Controller".constantize
|
34
|
+
end
|
35
|
+
|
36
|
+
def controller_name
|
37
|
+
@route.defaults[:controller]
|
38
|
+
end
|
39
|
+
|
40
|
+
def fern
|
41
|
+
controller.fern[action.to_sym]
|
42
|
+
end
|
43
|
+
|
44
|
+
def path
|
45
|
+
match = /(^[^\(]+)\([^\)]+\)/.match(@route.path.spec.to_s)
|
46
|
+
match[1] if match
|
47
|
+
end
|
48
|
+
|
49
|
+
def verb
|
50
|
+
@route.verb
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/tasks/docs.rake
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require 'fern/documentation/route_analyzer'
|
4
|
+
require 'fern/documentation/markdown_generator'
|
5
|
+
|
6
|
+
namespace :fern do
|
7
|
+
desc 'Generate documentation'
|
8
|
+
task docs: :environment do
|
9
|
+
endpoints = []
|
10
|
+
|
11
|
+
Rails.application.routes.routes.each do |route|
|
12
|
+
next if route.internal
|
13
|
+
analysis = Fern::Documentation::RouteAnalyzer.new(route).analyze
|
14
|
+
|
15
|
+
if analysis.nil?
|
16
|
+
puts "Skipping route"
|
17
|
+
else
|
18
|
+
endpoints << analysis
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
doc_root = Rails.root.join('docs', 'api')
|
23
|
+
|
24
|
+
FileUtils.rm_rf(doc_root)
|
25
|
+
FileUtils.mkdir_p(doc_root)
|
26
|
+
|
27
|
+
endpoints.each do |endpoint|
|
28
|
+
filename = "#{endpoint[:controller_name]}-#{endpoint[:action]}.md"
|
29
|
+
filepath = File.join(doc_root, filename)
|
30
|
+
filedir = File.dirname(filepath)
|
31
|
+
FileUtils.mkdir_p(filedir)
|
32
|
+
content = Fern::Documentation::MarkdownGenerator.new(endpoint).generate
|
33
|
+
File.write(filepath, content)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fern-documentation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kyle Kestell
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-02-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: actionpack
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mustache
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
83
|
+
description: Automatically generate documentation for Fern APIs.
|
84
|
+
email: kyle@kestell.org
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- lib/fern-documentation.rb
|
90
|
+
- lib/fern/documentation.rb
|
91
|
+
- lib/fern/documentation/dsl.rb
|
92
|
+
- lib/fern/documentation/markdown_generator.rb
|
93
|
+
- lib/fern/documentation/railtie.rb
|
94
|
+
- lib/fern/documentation/route_analyzer.rb
|
95
|
+
- lib/fern/documentation/version.rb
|
96
|
+
- lib/tasks/docs.rake
|
97
|
+
homepage: https://github.com/fern-fb/fern-documentation
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.3.0
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 2.6.14
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: Fern Documentation
|
121
|
+
test_files: []
|