ghost_writer 0.1.1 → 0.2.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.
- data/README.md +5 -7
- data/bin/ghost_writer +43 -0
- data/ghost_writer.gemspec +2 -0
- data/lib/ghost_writer/document.rb +22 -8
- data/lib/ghost_writer/document_index.rb +6 -4
- data/lib/ghost_writer/version.rb +1 -1
- data/lib/ghost_writer.rb +29 -12
- data/output_examples/anonymous_controller/index.markdown +40 -5
- data/output_examples/anonymous_controller/show.markdown +13 -5
- data/output_examples/document_index.markdown +2 -1
- data/spec/lib/ghost_writer_spec.rb +15 -7
- metadata +39 -5
data/README.md
CHANGED
@@ -21,14 +21,12 @@ Or install it yourself as:
|
|
21
21
|
## Usage
|
22
22
|
|
23
23
|
Write controller spec:
|
24
|
+
|
25
|
+
**Caution: Using ghost_writer command and Defining after fook manually at the same time, after hook is executed twice, because of it document_index is cleared.**
|
24
26
|
```ruby
|
25
27
|
# spec_helper
|
26
28
|
RSpec.configure do |config|
|
27
|
-
|
28
|
-
config.after(:suite) do
|
29
|
-
GhostWriter.generate_api_doc
|
30
|
-
end
|
31
|
-
|
29
|
+
# The difference with previous version. already no need including Module and Defining after hook
|
32
30
|
GhostWriter.output_dir = "api_docs" # Optional (default is "api_examples")
|
33
31
|
GhostWriter.github_base_url = "https://github.com/joker1007/ghost_writer/tree/master/output_examples" # Optional
|
34
32
|
end
|
@@ -53,7 +51,7 @@ end
|
|
53
51
|
|
54
52
|
And set environment variable GENERATE_API_DOC at runtime
|
55
53
|
```
|
56
|
-
|
54
|
+
bundle exec ghost_writer spec/controllers
|
57
55
|
-> generate docs at [Rails.root]/doc/api_examples
|
58
56
|
```
|
59
57
|
|
@@ -65,7 +63,7 @@ Please look at [output_examples](https://github.com/joker1007/ghost_writer/tree/
|
|
65
63
|
## Config
|
66
64
|
If output_dir is set, generate docs at `[Rails.root]/doc/[output_dir]`
|
67
65
|
|
68
|
-
If
|
66
|
+
If github\_base\_url is set, link index is based on the url, like output\_examples
|
69
67
|
|
70
68
|
## TODO
|
71
69
|
- support more output formats (now markdown only)
|
data/bin/ghost_writer
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "trollop"
|
4
|
+
require "rspec"
|
5
|
+
require "ghost_writer"
|
6
|
+
|
7
|
+
GhostWriter.output_flag = true
|
8
|
+
|
9
|
+
parser = Trollop::Parser.new do
|
10
|
+
version "ghost_writer v#{GhostWriter::VERSION}"
|
11
|
+
banner <<-EOS
|
12
|
+
Generate API Examples using Controller spec parameters.
|
13
|
+
|
14
|
+
Usage:
|
15
|
+
ghost_writer [options] <spec file or directory>
|
16
|
+
|
17
|
+
where [options] are:
|
18
|
+
EOS
|
19
|
+
|
20
|
+
opt :output, "Output directory", :type => String
|
21
|
+
opt :clear, "[Caution] Clear Output directory before running specs", :default => false
|
22
|
+
end
|
23
|
+
|
24
|
+
opts = Trollop::with_standard_exception_handling parser do
|
25
|
+
raise Trollop::HelpNeeded if ARGV.empty?
|
26
|
+
parser.parse ARGV
|
27
|
+
end
|
28
|
+
|
29
|
+
RSpec.configure do |c|
|
30
|
+
c.include GhostWriter
|
31
|
+
GhostWriter.output_dir = opts[:output]
|
32
|
+
c.after(:suite) do
|
33
|
+
GhostWriter.generate_api_doc
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if opts[:clear]
|
38
|
+
cmd = "rm -rf doc/#{GhostWriter.output_dir}"
|
39
|
+
puts cmd
|
40
|
+
system(cmd)
|
41
|
+
end
|
42
|
+
|
43
|
+
require "rspec/autorun"
|
data/ghost_writer.gemspec
CHANGED
@@ -19,8 +19,10 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.add_dependency "activesupport", ">= 3.0.0"
|
21
21
|
gem.add_dependency "rspec-rails", "~> 2.11"
|
22
|
+
gem.add_dependency "trollop"
|
22
23
|
|
23
24
|
gem.add_development_dependency "rspec", "~> 2.12"
|
24
25
|
gem.add_development_dependency 'rake', ['>= 0']
|
25
26
|
gem.add_development_dependency 'rails', ['~> 3.2.9']
|
27
|
+
gem.add_development_dependency 'tapp'
|
26
28
|
end
|
@@ -14,38 +14,52 @@ class GhostWriter::Document
|
|
14
14
|
@response_example = attrs[:response_example]
|
15
15
|
end
|
16
16
|
|
17
|
-
def write_file
|
17
|
+
def write_file(overwrite = false)
|
18
18
|
unless File.exist?(File.dirname(output))
|
19
19
|
FileUtils.mkdir_p(File.dirname(output))
|
20
20
|
end
|
21
|
-
doc = File.open(output, "w")
|
22
21
|
|
23
|
-
|
22
|
+
mode = overwrite ? "w" : "a"
|
23
|
+
doc = File.open(output, mode)
|
24
|
+
|
25
|
+
if overwrite
|
26
|
+
doc.write paragraph(<<EOP)
|
24
27
|
#{headword(title, 1)}
|
28
|
+
|
29
|
+
--------------------------------
|
30
|
+
|
31
|
+
EOP
|
32
|
+
end
|
33
|
+
|
34
|
+
doc.write paragraph(<<EOP)
|
35
|
+
#{headword(description, 2)}
|
25
36
|
EOP
|
26
37
|
|
27
38
|
doc.write paragraph(<<EOP)
|
28
|
-
#{headword("access path:",
|
39
|
+
#{headword("access path:", 3)}
|
29
40
|
#{quote(url_example)}
|
30
41
|
EOP
|
31
42
|
|
32
43
|
doc.write paragraph(<<EOP)
|
33
|
-
#{headword("request params:",
|
44
|
+
#{headword("request params:", 3)}
|
34
45
|
#{quote(param_example.inspect, :ruby)}
|
35
46
|
EOP
|
36
47
|
|
37
48
|
doc.write paragraph(<<EOP)
|
38
|
-
#{headword("status code:",
|
49
|
+
#{headword("status code:", 3)}
|
39
50
|
#{quote(status_example)}
|
40
51
|
EOP
|
41
52
|
|
42
53
|
doc.write paragraph(<<EOP)
|
43
|
-
#{headword("response:",
|
54
|
+
#{headword("response:", 3)}
|
44
55
|
#{quote_response(response_example)}
|
45
56
|
EOP
|
46
57
|
|
47
58
|
doc.write paragraph(<<EOP)
|
48
|
-
|
59
|
+
Generated by "#{description}\" at #{location}
|
60
|
+
|
61
|
+
--------------------------------
|
62
|
+
|
49
63
|
EOP
|
50
64
|
|
51
65
|
doc.close
|
@@ -14,10 +14,12 @@ class GhostWriter::DocumentIndex
|
|
14
14
|
base_url = ""
|
15
15
|
end
|
16
16
|
|
17
|
-
document_list = documents.
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
document_list = documents.flat_map do |output, docs|
|
18
|
+
docs.map do |d|
|
19
|
+
list(
|
20
|
+
link(d.description, base_url + "#{d.relative_path}")
|
21
|
+
)
|
22
|
+
end
|
21
23
|
end
|
22
24
|
|
23
25
|
index_file = File.open(output, "w")
|
data/lib/ghost_writer/version.rb
CHANGED
data/lib/ghost_writer.rb
CHANGED
@@ -10,35 +10,51 @@ module GhostWriter
|
|
10
10
|
autoload "Markdown", "ghost_writer/format/markdown"
|
11
11
|
end
|
12
12
|
|
13
|
+
DEFAULT_OUTPUT_DIR = "api_examples"
|
13
14
|
DOCUMENT_INDEX_FILENAME = "document_index.markdown"
|
14
15
|
|
15
16
|
class << self
|
16
|
-
|
17
|
+
attr_writer :output_dir, :output_flag
|
18
|
+
attr_accessor :github_base_url
|
17
19
|
|
18
|
-
def
|
19
|
-
@
|
20
|
-
@
|
20
|
+
def document_group
|
21
|
+
@document_group ||= {}
|
22
|
+
@document_group
|
21
23
|
end
|
22
24
|
|
23
25
|
def generate_api_doc
|
24
|
-
if
|
26
|
+
if output_flag
|
25
27
|
unless File.exist?(output_path)
|
26
28
|
FileUtils.mkdir_p(output_path)
|
27
29
|
end
|
28
|
-
document_index = GhostWriter::DocumentIndex.new(output_path + DOCUMENT_INDEX_FILENAME,
|
30
|
+
document_index = GhostWriter::DocumentIndex.new(output_path + DOCUMENT_INDEX_FILENAME, document_group)
|
29
31
|
document_index.write_file
|
30
|
-
|
31
|
-
|
32
|
+
document_group.each do |output, docs|
|
33
|
+
docs.sort_by!(&:description)
|
34
|
+
docs.shift.write_file(true)
|
35
|
+
docs.each(&:write_file)
|
36
|
+
end
|
37
|
+
|
38
|
+
document_group.clear
|
32
39
|
end
|
33
40
|
end
|
34
41
|
|
42
|
+
def output_flag
|
43
|
+
!!(@output_flag ? @output_flag : ENV["GENERATE_API_DOC"])
|
44
|
+
end
|
45
|
+
|
46
|
+
def output_dir
|
47
|
+
@output_dir ? @output_dir : DEFAULT_OUTPUT_DIR
|
48
|
+
end
|
49
|
+
|
35
50
|
def output_path
|
36
|
-
|
51
|
+
Rails.root + "doc" + output_dir
|
37
52
|
end
|
38
53
|
end
|
39
54
|
|
40
55
|
def collect_example
|
41
|
-
|
56
|
+
output = File.join(doc_dir, "#{doc_name}.markdown")
|
57
|
+
document = GhostWriter::Document.new(output, {
|
42
58
|
title: "#{described_class} #{doc_name.titleize}",
|
43
59
|
description: example.full_description.dup,
|
44
60
|
location: example.location.dup,
|
@@ -47,7 +63,8 @@ module GhostWriter
|
|
47
63
|
status_example: response.status.inspect,
|
48
64
|
response_example: response.body,
|
49
65
|
})
|
50
|
-
GhostWriter.
|
66
|
+
GhostWriter.document_group[output] ||= []
|
67
|
+
GhostWriter.document_group[output] << document
|
51
68
|
end
|
52
69
|
|
53
70
|
private
|
@@ -66,7 +83,7 @@ module GhostWriter
|
|
66
83
|
included do
|
67
84
|
after do
|
68
85
|
if example.metadata[:type] == :controller && example.metadata[:generate_api_doc]
|
69
|
-
collect_example if
|
86
|
+
collect_example if GhostWriter.output_flag
|
70
87
|
end
|
71
88
|
end
|
72
89
|
end
|
@@ -1,24 +1,59 @@
|
|
1
1
|
# AnonymousController Index
|
2
2
|
|
3
|
-
|
3
|
+
--------------------------------
|
4
|
+
|
5
|
+
|
6
|
+
## GET /anonymous first spec
|
7
|
+
|
8
|
+
### access path:
|
4
9
|
```
|
5
10
|
GET /anonymous
|
6
11
|
```
|
7
12
|
|
8
|
-
|
13
|
+
### request params:
|
9
14
|
```ruby
|
10
15
|
{"param1"=>"value"}
|
11
16
|
```
|
12
17
|
|
13
|
-
|
18
|
+
### status code:
|
14
19
|
```
|
15
20
|
200
|
16
21
|
```
|
17
22
|
|
18
|
-
|
23
|
+
### response:
|
19
24
|
```
|
20
25
|
[{"id":1,"name":"name"},{"id":2,"name":"name"}]
|
21
26
|
```
|
22
27
|
|
23
|
-
|
28
|
+
Generated by "GET /anonymous first spec" at ./spec/lib/ghost_writer_spec.rb:38
|
29
|
+
|
30
|
+
--------------------------------
|
31
|
+
|
32
|
+
|
33
|
+
## GET /anonymous second spec
|
34
|
+
|
35
|
+
### access path:
|
36
|
+
```
|
37
|
+
GET /anonymous
|
38
|
+
```
|
39
|
+
|
40
|
+
### request params:
|
41
|
+
```ruby
|
42
|
+
{"param1"=>"value"}
|
43
|
+
```
|
44
|
+
|
45
|
+
### status code:
|
46
|
+
```
|
47
|
+
200
|
48
|
+
```
|
49
|
+
|
50
|
+
### response:
|
51
|
+
```
|
52
|
+
[{"id":1,"name":"name"},{"id":2,"name":"name"}]
|
53
|
+
```
|
54
|
+
|
55
|
+
Generated by "GET /anonymous second spec" at ./spec/lib/ghost_writer_spec.rb:47
|
56
|
+
|
57
|
+
--------------------------------
|
58
|
+
|
24
59
|
|
@@ -1,21 +1,26 @@
|
|
1
1
|
# AnonymousController Show
|
2
2
|
|
3
|
-
|
3
|
+
--------------------------------
|
4
|
+
|
5
|
+
|
6
|
+
## GET /anonymous/1.json returns a Resource json
|
7
|
+
|
8
|
+
### access path:
|
4
9
|
```
|
5
10
|
GET /anonymous/1.json
|
6
11
|
```
|
7
12
|
|
8
|
-
|
13
|
+
### request params:
|
9
14
|
```ruby
|
10
15
|
{"param1"=>"value", "params2"=>["value1", "value2"], "id"=>"1", "format"=>"json"}
|
11
16
|
```
|
12
17
|
|
13
|
-
|
18
|
+
### status code:
|
14
19
|
```
|
15
20
|
200
|
16
21
|
```
|
17
22
|
|
18
|
-
|
23
|
+
### response:
|
19
24
|
```javascript
|
20
25
|
{
|
21
26
|
"id": 1,
|
@@ -23,5 +28,8 @@ GET /anonymous/1.json
|
|
23
28
|
}
|
24
29
|
```
|
25
30
|
|
26
|
-
|
31
|
+
Generated by "GET /anonymous/1.json returns a Resource json" at ./spec/lib/ghost_writer_spec.rb:58
|
32
|
+
|
33
|
+
--------------------------------
|
34
|
+
|
27
35
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# API Examples
|
2
|
-
- [GET /anonymous
|
2
|
+
- [GET /anonymous first spec](https://github.com/joker1007/ghost_writer/tree/master/output_examples/anonymous_controller/index.markdown)
|
3
|
+
- [GET /anonymous second spec](https://github.com/joker1007/ghost_writer/tree/master/output_examples/anonymous_controller/index.markdown)
|
3
4
|
- [GET /anonymous/1.json returns a Resource json](https://github.com/joker1007/ghost_writer/tree/master/output_examples/anonymous_controller/show.markdown)
|
4
5
|
|
@@ -35,7 +35,16 @@ describe GhostWriter do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
describe "GET /anonymous" do
|
38
|
-
it "
|
38
|
+
it "first spec", generate_api_doc: true do
|
39
|
+
begin
|
40
|
+
get :index, param1: "value"
|
41
|
+
response.should be_success
|
42
|
+
rescue Exception => e
|
43
|
+
p e
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "second spec", generate_api_doc: true do
|
39
48
|
begin
|
40
49
|
get :index, param1: "value"
|
41
50
|
response.should be_success
|
@@ -60,10 +69,7 @@ describe GhostWriter do
|
|
60
69
|
|
61
70
|
context "Not given output_dir" do
|
62
71
|
before do
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
after do
|
72
|
+
GhostWriter.output_dir = nil
|
67
73
|
clear_output("api_examples")
|
68
74
|
end
|
69
75
|
|
@@ -76,7 +82,10 @@ describe GhostWriter do
|
|
76
82
|
group.run(NullObject.new)
|
77
83
|
GhostWriter.generate_api_doc
|
78
84
|
File.exist?(Rails.root + "doc" + "api_examples" + "anonymous_controller" + "index.markdown").should be_true
|
79
|
-
File.read(Rails.root + "doc" + "api_examples" + "anonymous_controller" + "index.markdown")
|
85
|
+
doc_body = File.read(Rails.root + "doc" + "api_examples" + "anonymous_controller" + "index.markdown")
|
86
|
+
doc_body.should =~ /# AnonymousController Index/
|
87
|
+
doc_body.should =~ /first spec/
|
88
|
+
doc_body.should =~ /second spec/
|
80
89
|
end
|
81
90
|
|
82
91
|
context "Given github_base_url" do
|
@@ -113,7 +122,6 @@ describe GhostWriter do
|
|
113
122
|
|
114
123
|
after do
|
115
124
|
GhostWriter.output_dir = nil
|
116
|
-
clear_output(output_dir)
|
117
125
|
end
|
118
126
|
|
119
127
|
it "generate api doc file" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ghost_writer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-02-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '2.11'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: trollop
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: rspec
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,10 +107,27 @@ dependencies:
|
|
91
107
|
- - ~>
|
92
108
|
- !ruby/object:Gem::Version
|
93
109
|
version: 3.2.9
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: tapp
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
94
126
|
description: Generate API examples from params and response of controller specs
|
95
127
|
email:
|
96
128
|
- kakyoin.hierophant@gmail.com
|
97
|
-
executables:
|
129
|
+
executables:
|
130
|
+
- ghost_writer
|
98
131
|
extensions: []
|
99
132
|
extra_rdoc_files: []
|
100
133
|
files:
|
@@ -104,6 +137,7 @@ files:
|
|
104
137
|
- LICENSE.txt
|
105
138
|
- README.md
|
106
139
|
- Rakefile
|
140
|
+
- bin/ghost_writer
|
107
141
|
- ghost_writer.gemspec
|
108
142
|
- lib/ghost_writer.rb
|
109
143
|
- lib/ghost_writer/document.rb
|
@@ -167,7 +201,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
167
201
|
version: '0'
|
168
202
|
segments:
|
169
203
|
- 0
|
170
|
-
hash:
|
204
|
+
hash: 885870710401004349
|
171
205
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
206
|
none: false
|
173
207
|
requirements:
|
@@ -176,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
176
210
|
version: '0'
|
177
211
|
segments:
|
178
212
|
- 0
|
179
|
-
hash:
|
213
|
+
hash: 885870710401004349
|
180
214
|
requirements: []
|
181
215
|
rubyforge_project:
|
182
216
|
rubygems_version: 1.8.23
|