fdoc 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +102 -43
- data/lib/fdoc/presenters/html_presenter.rb +11 -0
- data/lib/fdoc/presenters/meta_service_presenter.rb +1 -0
- data/lib/fdoc/presenters/schema_presenter.rb +9 -1
- data/lib/fdoc/templates/endpoint.html.erb +9 -9
- data/lib/fdoc/templates/meta_service.html.erb +4 -12
- data/lib/fdoc/templates/service.html.erb +3 -9
- data/lib/fdoc/templates/styles.css +12 -0
- metadata +16 -15
data/README.md
CHANGED
@@ -18,26 +18,32 @@ Add fdoc to your Gemfile.
|
|
18
18
|
|
19
19
|
gem 'fdoc'
|
20
20
|
|
21
|
-
Tell fdoc where to look for
|
21
|
+
Tell fdoc where to look for `.fdoc` files. By default, fdoc will look in `docs/fdoc`, but you can change this behavior to look anywhere. This fits best in something like a spec\_helper file.
|
22
22
|
|
23
|
-
|
23
|
+
```ruby
|
24
|
+
require 'fdoc'
|
24
25
|
|
25
|
-
|
26
|
+
Fdoc.service_path = "path/to/your/fdocs"
|
27
|
+
```
|
26
28
|
|
27
29
|
fdoc is built to work around controller specs in rspec, and provides `Fdoc::SpecWatcher` as a mixin. Make sure to include it *inside* your top level describe.
|
28
30
|
|
29
|
-
|
31
|
+
```ruby
|
32
|
+
require 'fdoc/spec_watcher'
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
describe MembersController do
|
35
|
+
include Fdoc::SpecWatcher
|
36
|
+
# ...
|
37
|
+
end
|
38
|
+
```
|
35
39
|
|
36
40
|
To enable fdoc for an endpoint, add the `fdoc` option with the path to the endpoint. fdoc will intercept all calls to `get`, `post`, `put`, and `delete` and verify those parameters accordingly.
|
37
41
|
|
38
|
-
|
39
|
-
|
40
|
-
|
42
|
+
```ruby
|
43
|
+
context "#show", :fdoc => 'members/list' do
|
44
|
+
# ...
|
45
|
+
end
|
46
|
+
```
|
41
47
|
|
42
48
|
fdoc also has a scaffolding mode, where it attemps to infer the schema of a request based on sample responses. The interface is exactly the same as verifying, just set the environment variable `FDOC_SCAFFOLD=true`.
|
43
49
|
|
@@ -51,7 +57,7 @@ fdoc provides the `fdoc_to_html` script to transform a directory of `.fdoc` file
|
|
51
57
|
|
52
58
|
In this repo, try running:
|
53
59
|
|
54
|
-
bin/fdoc_to_html spec/fixtures html
|
60
|
+
bin/fdoc_to_html ./spec/fixtures ./html
|
55
61
|
|
56
62
|
## Example
|
57
63
|
|
@@ -60,37 +66,90 @@ In this repo, try running:
|
|
60
66
|
- For more information on fdoc file naming conventions, please see the [fdoc file conventions guide][github_files].
|
61
67
|
- For more information on how fdoc uses JSON schema, please see the [json schema usage document][github_json].
|
62
68
|
|
63
|
-
Here is `members/list-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
69
|
+
Here is `docs/fdoc/members/list-GET.fdoc`:
|
70
|
+
|
71
|
+
```yaml
|
72
|
+
description: The list of members.
|
73
|
+
requestParameters:
|
74
|
+
properties:
|
75
|
+
limit:
|
76
|
+
type: integer
|
77
|
+
required: no
|
78
|
+
default: 50
|
79
|
+
description: Limits the number of results returned, used for paging.
|
80
|
+
responseParameters:
|
81
|
+
properties:
|
82
|
+
members:
|
83
|
+
type: array
|
84
|
+
items:
|
85
|
+
title: member
|
86
|
+
description: Representation of a member
|
87
|
+
type: object
|
88
|
+
properties:
|
89
|
+
name:
|
90
|
+
description: Member's name
|
91
|
+
type: string
|
92
|
+
required: yes
|
93
|
+
example: Captain Smellypants
|
94
|
+
responseCodes:
|
95
|
+
- status: 200 OK
|
96
|
+
successful: yes
|
97
|
+
description: A list of current members
|
98
|
+
- status: 400 Bad Request
|
99
|
+
successful: no
|
100
|
+
description: Indicates malformed parameters
|
101
|
+
```
|
102
|
+
|
103
|
+
If we run a test against our members controller with an undocumented parameter, `offset`, we'll get an error.
|
104
|
+
|
105
|
+
Our spec file, `spec/controllers/members_controller_spec.rb` looks like:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
require 'fdoc/spec_watcher'
|
109
|
+
|
110
|
+
describe MembersController do
|
111
|
+
content "#show", :fdoc => "members/list" do
|
112
|
+
it "can take an offset" do
|
113
|
+
get :show, {
|
114
|
+
:offset => 5
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
We run:
|
122
|
+
|
123
|
+
bundle exec rspec spec/controllers/members_controller_spec.rb
|
124
|
+
|
125
|
+
And since `offset` is undocumented, fdoc will fail the test:
|
126
|
+
|
127
|
+
Failures:
|
128
|
+
|
129
|
+
1) MembersController#show can take an offset
|
130
|
+
Failure/Error: get :show, { :offset => 5 }
|
131
|
+
JSON::Schema::ValidationError:
|
132
|
+
The property '#/' contains additional properties ["offset"] outside of the schema when none are allowed in schema 8fcac6c4-294b-56a2-a3de-9342e2e729da#
|
133
|
+
# ./spec/controllers/members_controller_spec.rb:5:in `block (3 levels) in <top (required)>'
|
134
|
+
|
135
|
+
If we run the same spec in scaffold mode, it passes and fdoc will write changes to the correspoding `.fdoc` file:
|
136
|
+
|
137
|
+
FDOC_SCAFFOLD=true bundle exec spec/controllers/members_controller_spec.rb
|
138
|
+
|
139
|
+
The diff looks like:
|
140
|
+
|
141
|
+
```diff
|
142
|
+
diff --git a/docs/fdoc/members/list-GET.fdoc b/docs/fdoc/members/list-GET.fdoc b2e3656..dfa363a 100644
|
143
|
+
--- a/docs/fdoc/members/list-GET.fdoc
|
144
|
+
+++ b/docs/fdoc/members/list-GET.fdoc
|
145
|
+
+ offset:
|
146
|
+
+ description: ???
|
147
|
+
+ required: ???
|
148
|
+
+ type: integer
|
149
|
+
+ example: 5
|
150
|
+
```
|
151
|
+
|
152
|
+
Notice how it infers a type, and copies an example, but leaves description and required blank. These fields are best left to humans to decide.
|
94
153
|
|
95
154
|
|
96
155
|
## Goals
|
@@ -55,4 +55,15 @@ class Fdoc::HtmlPresenter
|
|
55
55
|
html_path
|
56
56
|
end
|
57
57
|
end
|
58
|
+
|
59
|
+
def tag_with_anchor(tag, content, anchor_slug = nil)
|
60
|
+
anchor_slug ||= content.downcase.gsub(' ', '_')
|
61
|
+
<<-EOS
|
62
|
+
<#{tag} id="#{anchor_slug}">
|
63
|
+
<a href="##{anchor_slug}" class="anchor">
|
64
|
+
#{content}
|
65
|
+
</a>
|
66
|
+
</#{tag}>
|
67
|
+
EOS
|
68
|
+
end
|
58
69
|
end
|
@@ -128,11 +128,19 @@ class Fdoc::SchemaPresenter < Fdoc::HtmlPresenter
|
|
128
128
|
properties.each do |key, property|
|
129
129
|
next if property.nil?
|
130
130
|
html << '<li>'
|
131
|
-
html <<
|
131
|
+
html << tag_with_anchor(
|
132
|
+
'span',
|
133
|
+
'<tt>%s</tt>' % key,
|
134
|
+
schema_slug(key, property)
|
135
|
+
)
|
132
136
|
html << self.class.new(property, options.merge(:nested => true)).to_html
|
133
137
|
html << '</li>'
|
134
138
|
end
|
135
139
|
|
136
140
|
html
|
137
141
|
end
|
142
|
+
|
143
|
+
def schema_slug(key, property)
|
144
|
+
"#{key}-#{property.hash}"
|
145
|
+
end
|
138
146
|
end
|
@@ -28,27 +28,27 @@
|
|
28
28
|
<%= description %>
|
29
29
|
|
30
30
|
<% if show_request? %>
|
31
|
-
|
31
|
+
<%= tag_with_anchor('h2', 'Request') %>
|
32
32
|
|
33
|
-
|
33
|
+
<%= tag_with_anchor('h3', 'Example Request') %>
|
34
34
|
<%= example_request %>
|
35
35
|
|
36
|
-
|
36
|
+
<%= tag_with_anchor('h3', 'Request Parameters') %>
|
37
37
|
<%= request_parameters %>
|
38
38
|
<% end %>
|
39
39
|
|
40
|
-
|
40
|
+
<%= tag_with_anchor('h2', 'Response') %>
|
41
41
|
<% if show_response? %>
|
42
|
-
|
42
|
+
<%= tag_with_anchor('h3', 'Example Response') %>
|
43
43
|
<%= example_response %>
|
44
44
|
|
45
|
-
|
45
|
+
<%= tag_with_anchor('h3', 'Response Parameters') %>
|
46
46
|
<%= response_parameters %>
|
47
47
|
<% end %>
|
48
48
|
|
49
|
-
|
49
|
+
<%= tag_with_anchor('h3', 'Response Codes') %>
|
50
50
|
<% if !successful_response_codes.empty? %>
|
51
|
-
|
51
|
+
<%= tag_with_anchor('h4', 'Successful Response Codes') %>
|
52
52
|
<ul>
|
53
53
|
<% successful_response_codes.each do |response_code| %>
|
54
54
|
<li>
|
@@ -59,7 +59,7 @@
|
|
59
59
|
<% end %>
|
60
60
|
|
61
61
|
<% if !successful_response_codes.empty? %>
|
62
|
-
|
62
|
+
<%= tag_with_anchor('h4', 'Failure Response Codes') %>
|
63
63
|
<ul>
|
64
64
|
<% failure_response_codes.each do |response_code| %>
|
65
65
|
<li>
|
@@ -16,9 +16,7 @@
|
|
16
16
|
|
17
17
|
<%= description %>
|
18
18
|
|
19
|
-
|
20
|
-
Services
|
21
|
-
</h2>
|
19
|
+
<%= tag_with_anchor('h2', 'Services') %>
|
22
20
|
|
23
21
|
<ul>
|
24
22
|
<% services.each do |serv| %>
|
@@ -30,14 +28,10 @@
|
|
30
28
|
<% end %>
|
31
29
|
</ul>
|
32
30
|
|
33
|
-
|
34
|
-
Endpoints
|
35
|
-
</h2>
|
31
|
+
<%= tag_with_anchor('h2', 'Endpoints') %>
|
36
32
|
|
37
33
|
<% endpoints.each do |endpoint_ary| %>
|
38
|
-
|
39
|
-
<%= endpoint_ary.first.prefix %>
|
40
|
-
</h3>
|
34
|
+
<%= tag_with_anchor('h3', endpoint_ary.first.prefix) %>
|
41
35
|
<ul>
|
42
36
|
<% endpoint_ary.each do |endpoint| %>
|
43
37
|
<li>
|
@@ -48,9 +42,7 @@
|
|
48
42
|
<% end %>
|
49
43
|
|
50
44
|
<% if discussion %>
|
51
|
-
|
52
|
-
Discussion
|
53
|
-
</h2>
|
45
|
+
<%= tag_with_anchor('h2', 'Discussion') %>
|
54
46
|
<%= discussion %>
|
55
47
|
<% end %>
|
56
48
|
</div>
|
@@ -24,14 +24,10 @@
|
|
24
24
|
|
25
25
|
<%= description %>
|
26
26
|
|
27
|
-
|
28
|
-
Endpoints
|
29
|
-
</h2>
|
27
|
+
<%= tag_with_anchor('h2', 'Endpoints') %>
|
30
28
|
|
31
29
|
<% endpoints.each do |endpoint_ary| %>
|
32
|
-
|
33
|
-
<%= endpoint_ary.first.prefix %>
|
34
|
-
</h3>
|
30
|
+
<%= tag_with_anchor('h3', endpoint_ary.first.prefix) %>
|
35
31
|
<ul>
|
36
32
|
<% endpoint_ary.each do |endpoint| %>
|
37
33
|
<li>
|
@@ -42,9 +38,7 @@
|
|
42
38
|
<% end %>
|
43
39
|
|
44
40
|
<% if discussion %>
|
45
|
-
|
46
|
-
Discussion
|
47
|
-
</h2>
|
41
|
+
<%= tag_with_anchor('h2', 'Discussion') %>
|
48
42
|
<%= discussion %>
|
49
43
|
<% end %>
|
50
44
|
</div>
|
@@ -29,6 +29,18 @@ h1, h2, h3 { font-weight: 200; }
|
|
29
29
|
a { text-decoration: none; color: #66f; }
|
30
30
|
a:hover, a:active { text-decoration: underline; }
|
31
31
|
|
32
|
+
a.anchor { color: inherit; }
|
33
|
+
a.anchor:hover, a.anchor:active { text-decoration: none;}
|
34
|
+
a.anchor:hover::before, a.anchor.active::before {
|
35
|
+
background: white;
|
36
|
+
display: inline-block;
|
37
|
+
position: absolute;
|
38
|
+
content: '\0261E';
|
39
|
+
font-size: 120%;
|
40
|
+
font-weight: bold;
|
41
|
+
margin-left: -1.2em;
|
42
|
+
}
|
43
|
+
|
32
44
|
ul {
|
33
45
|
list-style: square;
|
34
46
|
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fdoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -15,7 +15,7 @@ date: 2011-11-07 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: json
|
18
|
-
requirement: &
|
18
|
+
requirement: &70290789895620 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ! '>='
|
@@ -23,10 +23,10 @@ dependencies:
|
|
23
23
|
version: '0'
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *70290789895620
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: json-schema
|
29
|
-
requirement: &
|
29
|
+
requirement: &70290789911300 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ! '>='
|
@@ -34,10 +34,10 @@ dependencies:
|
|
34
34
|
version: 1.0.1
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *70290789911300
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: kramdown
|
40
|
-
requirement: &
|
40
|
+
requirement: &70290789910780 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
@@ -45,10 +45,10 @@ dependencies:
|
|
45
45
|
version: '0'
|
46
46
|
type: :runtime
|
47
47
|
prerelease: false
|
48
|
-
version_requirements: *
|
48
|
+
version_requirements: *70290789910780
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: rake
|
51
|
-
requirement: &
|
51
|
+
requirement: &70290789910100 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
54
|
- - ! '>='
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
version: '0'
|
57
57
|
type: :development
|
58
58
|
prerelease: false
|
59
|
-
version_requirements: *
|
59
|
+
version_requirements: *70290789910100
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: rspec
|
62
|
-
requirement: &
|
62
|
+
requirement: &70290789909420 !ruby/object:Gem::Requirement
|
63
63
|
none: false
|
64
64
|
requirements:
|
65
65
|
- - ~>
|
@@ -67,10 +67,10 @@ dependencies:
|
|
67
67
|
version: '2.5'
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
|
-
version_requirements: *
|
70
|
+
version_requirements: *70290789909420
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: nokogiri
|
73
|
-
requirement: &
|
73
|
+
requirement: &70290789908980 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - ! '>='
|
@@ -78,10 +78,10 @@ dependencies:
|
|
78
78
|
version: '0'
|
79
79
|
type: :development
|
80
80
|
prerelease: false
|
81
|
-
version_requirements: *
|
81
|
+
version_requirements: *70290789908980
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: cane
|
84
|
-
requirement: &
|
84
|
+
requirement: &70290789908380 !ruby/object:Gem::Requirement
|
85
85
|
none: false
|
86
86
|
requirements:
|
87
87
|
- - ! '>='
|
@@ -89,7 +89,7 @@ dependencies:
|
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *70290789908380
|
93
93
|
description: A tool for documenting API endpoints.
|
94
94
|
email: support@squareup.com
|
95
95
|
executables:
|
@@ -172,3 +172,4 @@ test_files:
|
|
172
172
|
- spec/fixtures/members/members.fdoc.service
|
173
173
|
- spec/fixtures/sample_group.fdoc.meta
|
174
174
|
- spec/spec_helper.rb
|
175
|
+
has_rdoc:
|