ghost_writer 0.0.1 → 0.1.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/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ script: "bundle exec rake spec build"
3
+ rvm:
4
+ - 1.9.3
5
+ notifications:
6
+ email:
7
+ on_success: never
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # GhostWriter
2
+ [![Build Status](https://travis-ci.org/joker1007/ghost_writer.png)](https://travis-ci.org/joker1007/ghost_writer)
2
3
 
3
4
  Generate API examples from params and response of controller specs
4
5
 
@@ -20,6 +21,18 @@ Or install it yourself as:
20
21
 
21
22
  Write controller spec:
22
23
  ```ruby
24
+ # spec_helper
25
+ RSpec.configure do |config|
26
+ config.include GhostWriter
27
+ config.after(:suite) do
28
+ GhostWriter.generate_api_doc
29
+ end
30
+
31
+ GhostWriter.output_dir = "api_docs" # Optional (default is "api_examples")
32
+ GhostWriter.github_base_url = "https://github.com/joker1007/ghost_writer/tree/master/output_examples" # Optional
33
+ end
34
+
35
+ # posts_controller_spec
23
36
  require 'spec_helper'
24
37
 
25
38
  describe PostsController do
@@ -28,6 +41,11 @@ describe PostsController do
28
41
  get :index
29
42
  response.should be_success
30
43
  end
44
+
45
+ it "should be success", generate_api_doc: "index_error" do # if metadata value is string, use it as filename
46
+ get :index
47
+ response.status.should eq 404
48
+ end
31
49
  end
32
50
  end
33
51
  ```
@@ -40,6 +58,14 @@ GENERATE_API_DOC=1 bundle exec rspec spec
40
58
 
41
59
  If you don't set environment variable, this gem doesn't generate docs.
42
60
 
61
+ ## Output Example
62
+ Please look at [output_examples](https://github.com/joker1007/ghost_writer/tree/master/output_examples)
63
+
64
+ ## Config
65
+ If output_dir is set, generate docs at `[Rails.root]/doc/[output_dir]`
66
+
67
+ If github_base_url is set, link index is based on the url, like output_examples
68
+
43
69
  ## TODO
44
70
  - support more output formats (now markdown only)
45
71
 
data/lib/ghost_writer.rb CHANGED
@@ -1,44 +1,58 @@
1
1
  require "ghost_writer/version"
2
+ require "ghost_writer/document"
3
+ require "ghost_writer/document_index"
2
4
  require "active_support/concern"
3
5
 
4
6
  module GhostWriter
5
7
  extend ActiveSupport::Concern
6
8
 
7
- mattr_accessor :output_dir
9
+ module Format
10
+ autoload "Markdown", "ghost_writer/format/markdown"
11
+ end
12
+
13
+ DOCUMENT_INDEX_FILENAME = "document_index.markdown"
14
+
15
+ class << self
16
+ attr_accessor :output_dir, :github_base_url
8
17
 
9
- def generate_api_doc
10
- @@output_path = @@output_dir ? Rails.root + "doc" + @@output_dir : Rails.root + "doc" + "api_examples"
11
- unless File.exist?(doc_dir)
12
- FileUtils.mkdir_p(doc_dir)
18
+ def documents
19
+ @documents ||= []
20
+ @documents
13
21
  end
14
22
 
15
- doc = File.open(File.join(doc_dir, "#{doc_name}.markdown"), "w")
23
+ def generate_api_doc
24
+ if ENV["GENERATE_API_DOC"]
25
+ unless File.exist?(output_path)
26
+ FileUtils.mkdir_p(output_path)
27
+ end
28
+ document_index = GhostWriter::DocumentIndex.new(output_path + DOCUMENT_INDEX_FILENAME, documents)
29
+ document_index.write_file
30
+ @documents.each(&:write_file)
31
+ @documents.clear
32
+ end
33
+ end
16
34
 
17
- doc.puts headword("#{described_class} #{doc_name.titleize}", 1)
18
- doc.puts headword("access path:", 2)
19
- doc.puts quote("#{request.env["REQUEST_METHOD"]} #{request.env["PATH_INFO"]}")
20
- doc.puts ""
21
- doc.puts headword("request params:", 2)
22
- doc.puts quote(controller.params.reject {|key, val| key == "controller" || key == "action"}.inspect, :ruby)
23
- doc.puts ""
24
- doc.puts headword("status code:", 2)
25
- doc.puts quote(response.status.inspect)
26
- doc.puts ""
27
- doc.puts headword("response:", 2)
28
- if controller.params[:format] && controller.params[:format].to_sym == :json
29
- puts_json_data(doc)
30
- else
31
- doc.puts quote(response.body)
35
+ def output_path
36
+ output_dir ? Rails.root + "doc" + output_dir : Rails.root + "doc" + "api_examples"
32
37
  end
33
- doc.puts ""
34
- doc.puts "Generated by \"#{example.full_description}\" at #{example.location}"
35
- doc.puts ""
36
- doc.close
38
+ end
39
+
40
+ def collect_example
41
+ document = GhostWriter::Document.new(File.join(doc_dir, "#{doc_name}.markdown"), {
42
+ title: "#{described_class} #{doc_name.titleize}",
43
+ description: example.full_description.dup,
44
+ location: example.location.dup,
45
+ url_example: "#{request.env["REQUEST_METHOD"]} #{request.env["PATH_INFO"]}",
46
+ param_example: controller.params.reject {|key, val| key == "controller" || key == "action"},
47
+ status_example: response.status.inspect,
48
+ response_example: response.body,
49
+ })
50
+ GhostWriter.documents << document
37
51
  end
38
52
 
39
53
  private
40
54
  def doc_dir
41
- @@output_path + described_class.to_s.underscore
55
+ GhostWriter.output_path + described_class.to_s.underscore
42
56
  end
43
57
 
44
58
  def doc_name
@@ -49,32 +63,10 @@ module GhostWriter
49
63
  end
50
64
  end
51
65
 
52
- # TODO: outputのフォーマットを選択可能に
53
- def headword(text, level = 1)
54
- "#{'#'*level} #{text}\n"
55
- end
56
-
57
- def paragraph(text)
58
- text + "\n\n"
59
- end
60
-
61
- def quote(text, quote_format = nil)
62
- "```#{quote_format}\n#{text}\n```"
63
- end
64
-
65
- def puts_json_data(doc)
66
- data = ActiveSupport::JSON.decode(response.body)
67
- if data.is_a?(Array) || data.is_a?(Hash)
68
- doc.puts quote(JSON.pretty_generate(data), :javascript)
69
- else
70
- doc.puts quote(data)
71
- end
72
- end
73
-
74
66
  included do
75
67
  after do
76
68
  if example.metadata[:type] == :controller && example.metadata[:generate_api_doc]
77
- generate_api_doc if ENV["GENERATE_API_DOC"]
69
+ collect_example if ENV["GENERATE_API_DOC"]
78
70
  end
79
71
  end
80
72
  end
@@ -0,0 +1,71 @@
1
+ class GhostWriter::Document
2
+ attr_reader :title, :description, :location, :url_example, :param_example, :status_example, :response_example, :output, :relative_path
3
+
4
+ def initialize(output, attrs)
5
+ extend(GhostWriter::Format::Markdown)
6
+ @output = output
7
+ @relative_path = Pathname.new(output).relative_path_from(GhostWriter.output_path)
8
+ @title = attrs[:title]
9
+ @description = attrs[:description]
10
+ @location = attrs[:location]
11
+ @url_example = attrs[:url_example]
12
+ @param_example = attrs[:param_example]
13
+ @status_example = attrs[:status_example]
14
+ @response_example = attrs[:response_example]
15
+ end
16
+
17
+ def write_file
18
+ unless File.exist?(File.dirname(output))
19
+ FileUtils.mkdir_p(File.dirname(output))
20
+ end
21
+ doc = File.open(output, "w")
22
+
23
+ doc.write paragraph(<<EOP)
24
+ #{headword(title, 1)}
25
+ EOP
26
+
27
+ doc.write paragraph(<<EOP)
28
+ #{headword("access path:", 2)}
29
+ #{quote(url_example)}
30
+ EOP
31
+
32
+ doc.write paragraph(<<EOP)
33
+ #{headword("request params:", 2)}
34
+ #{quote(param_example.inspect, :ruby)}
35
+ EOP
36
+
37
+ doc.write paragraph(<<EOP)
38
+ #{headword("status code:", 2)}
39
+ #{quote(status_example)}
40
+ EOP
41
+
42
+ doc.write paragraph(<<EOP)
43
+ #{headword("response:", 2)}
44
+ #{quote_response(response_example)}
45
+ EOP
46
+
47
+ doc.write paragraph(<<EOP)
48
+ "Generated by \"#{description}\" at #{location}"
49
+ EOP
50
+
51
+ doc.close
52
+ end
53
+
54
+ private
55
+ def quote_response(body)
56
+ if param_example[:format] && param_example[:format].to_sym == :json
57
+ quote(arrange_json(response_example), :javascript)
58
+ else
59
+ quote(response_example, param_example[:format])
60
+ end
61
+ end
62
+
63
+ def arrange_json(body)
64
+ data = ActiveSupport::JSON.decode(body)
65
+ if data.is_a?(Array) || data.is_a?(Hash)
66
+ JSON.pretty_generate(data)
67
+ else
68
+ data
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,30 @@
1
+ class GhostWriter::DocumentIndex
2
+ attr_reader :output, :documents
3
+
4
+ def initialize(output, documents)
5
+ extend(GhostWriter::Format::Markdown)
6
+ @output = output
7
+ @documents = documents
8
+ end
9
+
10
+ def write_file
11
+ if GhostWriter.github_base_url
12
+ base_url = GhostWriter.github_base_url + "/"
13
+ else
14
+ base_url = ""
15
+ end
16
+
17
+ document_list = documents.map do |document|
18
+ list(
19
+ link(document.description, base_url + "#{document.relative_path}")
20
+ )
21
+ end
22
+
23
+ index_file = File.open(output, "w")
24
+ index_file.write paragraph(<<EOP)
25
+ #{headword("API Examples")}
26
+ #{document_list.join("\n")}
27
+ EOP
28
+ index_file.close
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module GhostWriter
2
+ module Format
3
+ module Markdown
4
+ private
5
+ # TODO: outputのフォーマットを選択可能に
6
+ def headword(text, level = 1)
7
+ "#{'#'*level} #{text}"
8
+ end
9
+
10
+ def paragraph(text)
11
+ text + "\n"
12
+ end
13
+
14
+ def quote(text, quote_format = nil)
15
+ "```#{quote_format}\n#{text}\n```"
16
+ end
17
+
18
+ def list(text, level = 1)
19
+ "#{" " * (level - 1)}- #{text}"
20
+ end
21
+
22
+ def link(text, url)
23
+ "[#{text}](#{url})"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,3 +1,3 @@
1
1
  module GhostWriter
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,24 @@
1
+ # AnonymousController Index
2
+
3
+ ## access path:
4
+ ```
5
+ GET /anonymous
6
+ ```
7
+
8
+ ## request params:
9
+ ```ruby
10
+ {"param1"=>"value"}
11
+ ```
12
+
13
+ ## status code:
14
+ ```
15
+ 200
16
+ ```
17
+
18
+ ## response:
19
+ ```
20
+ [{"id":1,"name":"name"},{"id":2,"name":"name"}]
21
+ ```
22
+
23
+ "Generated by "GET /anonymous returns Resources array" at ./spec/lib/ghost_writer_spec.rb:38"
24
+
@@ -0,0 +1,27 @@
1
+ # AnonymousController Show
2
+
3
+ ## access path:
4
+ ```
5
+ GET /anonymous/1.json
6
+ ```
7
+
8
+ ## request params:
9
+ ```ruby
10
+ {"param1"=>"value", "params2"=>["value1", "value2"], "id"=>"1", "format"=>"json"}
11
+ ```
12
+
13
+ ## status code:
14
+ ```
15
+ 200
16
+ ```
17
+
18
+ ## response:
19
+ ```javascript
20
+ {
21
+ "id": 1,
22
+ "name": "name"
23
+ }
24
+ ```
25
+
26
+ "Generated by "GET /anonymous/1.json returns a Resource json" at ./spec/lib/ghost_writer_spec.rb:49"
27
+
@@ -0,0 +1,4 @@
1
+ # API Examples
2
+ - [GET /anonymous returns Resources array](https://github.com/joker1007/ghost_writer/tree/master/output_examples/anonymous_controller/index.markdown)
3
+ - [GET /anonymous/1.json returns a Resource json](https://github.com/joker1007/ghost_writer/tree/master/output_examples/anonymous_controller/show.markdown)
4
+
@@ -28,12 +28,27 @@ describe GhostWriter do
28
28
  ]
29
29
  render json: collection.as_json
30
30
  end
31
+
32
+ def show
33
+ render json: {id: 1, name: "name"}
34
+ end
35
+ end
36
+
37
+ describe "GET /anonymous" do
38
+ it "returns Resources array", 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
31
46
  end
32
47
 
33
- describe "GET index" do
34
- it "should be success", generate_api_doc: true do
48
+ describe "GET /anonymous/1.json" do
49
+ it "returns a Resource json", generate_api_doc: true do
35
50
  begin
36
- get :index
51
+ get :show, id: 1, format: :json, param1: "value", params2: ["value1", "value2"]
37
52
  response.should be_success
38
53
  rescue Exception => e
39
54
  p e
@@ -59,17 +74,30 @@ describe GhostWriter do
59
74
 
60
75
  it "generate api doc file" do
61
76
  group.run(NullObject.new)
77
+ GhostWriter.generate_api_doc
62
78
  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").should =~ /# AnonymousController Index/
80
+ end
81
+
82
+ context "Given github_base_url" do
83
+ let(:github_base_url) { "https://github.com/joker1007/ghost_writer/tree/master/output_examples" }
84
+ it "create index file written github links" do
85
+ GhostWriter.github_base_url = github_base_url
86
+ group.run(NullObject.new)
87
+ GhostWriter.generate_api_doc
88
+ File.read(Rails.root + "doc" + "api_examples" + GhostWriter::DOCUMENT_INDEX_FILENAME).should =~ /#{github_base_url}/
89
+ end
63
90
  end
64
91
  end
65
92
 
66
- context 'ENV["GENERATE_API_DOC"] is true' do
93
+ context 'ENV["GENERATE_API_DOC"] is false' do
67
94
  before do
68
95
  ENV["GENERATE_API_DOC"] = nil
69
96
  end
70
97
 
71
98
  it "does not generate api doc file" do
72
99
  group.run(NullObject.new)
100
+ GhostWriter.generate_api_doc
73
101
  File.exist?(Rails.root + "doc" + "api_examples" + "anonymous_controller" + "index.markdown").should be_false
74
102
  end
75
103
  end
@@ -91,7 +119,9 @@ describe GhostWriter do
91
119
  it "generate api doc file" do
92
120
  ENV["GENERATE_API_DOC"] = "1"
93
121
  group.run(NullObject.new)
122
+ GhostWriter.generate_api_doc
94
123
  File.exist?(Rails.root + "doc" + output_dir + "anonymous_controller" + "index.markdown").should be_true
124
+ File.read(Rails.root + "doc" + output_dir + "anonymous_controller" + "index.markdown").should =~ /# AnonymousController Index/
95
125
  end
96
126
  end
97
127
 
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.0.1
4
+ version: 0.1.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-01-08 00:00:00.000000000 Z
12
+ date: 2013-01-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -99,13 +99,20 @@ extensions: []
99
99
  extra_rdoc_files: []
100
100
  files:
101
101
  - .gitignore
102
+ - .travis.yml
102
103
  - Gemfile
103
104
  - LICENSE.txt
104
105
  - README.md
105
106
  - Rakefile
106
107
  - ghost_writer.gemspec
107
108
  - lib/ghost_writer.rb
109
+ - lib/ghost_writer/document.rb
110
+ - lib/ghost_writer/document_index.rb
111
+ - lib/ghost_writer/format/markdown.rb
108
112
  - lib/ghost_writer/version.rb
113
+ - output_examples/anonymous_controller/index.markdown
114
+ - output_examples/anonymous_controller/show.markdown
115
+ - output_examples/document_index.markdown
109
116
  - spec/lib/ghost_writer_spec.rb
110
117
  - spec/rails_app/.gitignore
111
118
  - spec/rails_app/README.rdoc
@@ -160,7 +167,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
160
167
  version: '0'
161
168
  segments:
162
169
  - 0
163
- hash: 1116131178365198946
170
+ hash: 2108698769650766932
164
171
  required_rubygems_version: !ruby/object:Gem::Requirement
165
172
  none: false
166
173
  requirements:
@@ -169,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
176
  version: '0'
170
177
  segments:
171
178
  - 0
172
- hash: 1116131178365198946
179
+ hash: 2108698769650766932
173
180
  requirements: []
174
181
  rubyforge_project:
175
182
  rubygems_version: 1.8.23