smarf_doc 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 035b5d1410143ff9b925041dfe1ac3b1ced0fe95
4
+ data.tar.gz: 835909a904ab7d01fcb169d2369a81245c357c53
5
+ SHA512:
6
+ metadata.gz: 8e136d5bf18e873e74e044a15f32f226e17f893121a7d62889a7b5332a962256a95a55a2dabeebdaa335ca8b9963890abb42fdcc185fb0fd5dbb9ce928104908
7
+ data.tar.gz: a40c8a9b9df76935feffffb355fdd87ab9711c6743a7626db1dd95436f6612e94fc24558773851f019674b126af6b96b3b78f4fd517287847057beadacd6d042
@@ -0,0 +1 @@
1
+ /coverage/
@@ -0,0 +1,183 @@
1
+ # SmarfDoc
2
+
3
+ (Formerly 'DocYoSelf')
4
+
5
+ ![Smarf](http://i.imgur.com/f5mzeRU.png)
6
+
7
+ Too many docs spoil the broth.
8
+
9
+ SmarfDoc lets you turn your controller tests into API docs _without making changes to your test suite or how you write tests_.
10
+
11
+ Pop it into your test suite and watch it amaze.
12
+
13
+ Time for this project was provided by my employer, [SmashingBoxes](http://smashingboxes.com/). What a great place to work!
14
+
15
+
16
+ ## Gem Installation in Rails
17
+
18
+ In your gemfile add the following to your test group:
19
+
20
+ `gem 'smarf_doc', group: :test, github: 'RickCarlino/smarf_doc'`
21
+
22
+ Installation differs for RSpec/Minitest, so scroll to the appropriate section for guidance.
23
+
24
+ ## Rspec Installation
25
+
26
+ Add this to your `rails_helper.rb` It should go outside of other blocks
27
+ (Do not place it inside the `RSpec.configure` block).
28
+ ```ruby
29
+ SmarfDoc.config do |c|
30
+ c.template_file = 'spec/template.md.erb'
31
+ c.output_file = 'api_docs.md'
32
+ end
33
+ ```
34
+
35
+ Add the following line to `spec_helper.rb` inside the `RSpec.configure` block
36
+
37
+ `config.after(:suite) { SmarfDoc.finish! }`
38
+
39
+ It should look like this
40
+ ```ruby
41
+ RSpec.configure do |config|
42
+ # Existing code
43
+ config.after(:suite) { SmarfDoc.finish! }
44
+ end
45
+ ```
46
+ #### To run on all controller tests
47
+
48
+ Add this to your `spec_helper.rb`
49
+ ```ruby
50
+ config.after(:each, type: :controller) do
51
+ SmarfDoc.run!(request, response)
52
+ end
53
+ ```
54
+
55
+ The whole file should look like this
56
+ ```ruby
57
+ RSpec.configure do |config|
58
+ # Existing code
59
+ config.after(:each, type: :controller) do
60
+ SmarfDoc.run!(request, response)
61
+ end
62
+ config.after(:suite) { SmarfDoc.finish! }
63
+ end
64
+ ```
65
+ #### To run on only select tests
66
+ Just add `SmarfDoc.run!(request, response)` to specific tests
67
+ ```ruby
68
+ it "responds with 200" do
69
+ get :index
70
+ expect(response).to be_success
71
+ SmarfDoc.run!(request, response)
72
+ end
73
+ ```
74
+
75
+ ## Minitest Installation
76
+
77
+ Add the code from below to `test_helper.rb`:
78
+ ```ruby
79
+ class ActiveSupport::TestCase
80
+ # Already existing code
81
+ SmarfDoc.config do |c|
82
+ c.template_file = 'test/template.md.erb'
83
+ c.output_file = 'api_docs.md'
84
+ end
85
+ # More code
86
+ end
87
+
88
+ MiniTest::Unit.after_tests { SmarfDoc.finish! }
89
+ ```
90
+ #### To run on all controller tests
91
+ Add this to `test_helper.rb` as well:
92
+ ```ruby
93
+ class ActionController::TestCase < ActiveSupport::TestCase
94
+ def teardown
95
+ SmarfDoc.run!(request, response)
96
+ end
97
+ end
98
+ ```
99
+
100
+ Your code should look like this:
101
+ ```ruby
102
+ class ActiveSupport::TestCase
103
+ # Already existing code
104
+ SmarfDoc.config do |c|
105
+ c.template_file = 'test/template.md.erb'
106
+ c.output_file = 'api_docs.md'
107
+ end
108
+ # More code
109
+ end
110
+
111
+ class ActionController::TestCase < ActiveSupport::TestCase
112
+ def teardown
113
+ SmarfDoc.run!(request, response)
114
+ end
115
+ end
116
+
117
+ MiniTest::Unit.after_tests { SmarfDoc.finish! }
118
+ ```
119
+
120
+
121
+ #### To run on only select tests
122
+ Just add `SmarfDoc.run!(request, response)` to specific tests
123
+ ```ruby
124
+ def get_index
125
+ get :index
126
+ assert response.status == 200
127
+ SmarfDoc.run!(request, response)
128
+ end
129
+ ```
130
+
131
+ ## Setting a template
132
+
133
+ If you copied the code from above, SmarfDoc will look for a template file located at either
134
+ `test/template.md.erb` or `spec/template.md.erb`, depending on your test suite.
135
+ This template may be customized to fit your needs.
136
+
137
+ ```erb
138
+ <%= request.method %>
139
+ <%= request.path %>
140
+ <%= request.params %>
141
+ <%= response.body %>
142
+ <%= information[:message] %>
143
+ <%= note %>
144
+ ```
145
+
146
+ ## Where to find the docs
147
+
148
+ By default, the docs are output to `api_docs.md` in the root of the Rails project.
149
+ You can change this by altering the config in `test_helper.rb` or `rails_helper.rb`.
150
+
151
+ ## Additional Features
152
+
153
+ #### Skipping documentation on tests
154
+
155
+ To leave certain tests out of the documentation, just add `SmarfDoc.skip` to the test.
156
+
157
+ ```ruby
158
+ it "responds with 200" do
159
+ SmarfDoc.skip
160
+ # test code
161
+ end
162
+ ```
163
+
164
+ #### Adding information and notes
165
+ SmarfDoc will log all requests and responses by default, but you can add some
166
+ **optional** parameters as well.
167
+
168
+ ```ruby
169
+ it "responds with 200" do
170
+ SmarfDoc.note("This endpoint prefers butterscotch")
171
+ # test code
172
+ end
173
+ ```
174
+ #### OR
175
+ ```ruby
176
+ it "responds with 200" do
177
+ SmarfDoc.information(:message, "This endpoint only responds on Tuesdays")
178
+ # test code
179
+ end
180
+ ```
181
+
182
+ You can store any information with `:message` or any other key you can think of.
183
+ To access information in the template, just use `<%= information[:message] %>`
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
File without changes
@@ -0,0 +1,80 @@
1
+ You can use ERB to format each test case.
2
+ GET
3
+ api/aaa
4
+ {:id=>12}
5
+ {"id": 12, "name": "rick"}
6
+ You can use ERB to format each test case.
7
+ GET
8
+ api/users
9
+ {:id=>12}
10
+ {"id": 12, "name": "rick"}
11
+ You can use ERB to format each test case.
12
+ GET
13
+ api/users
14
+ {:id=>12}
15
+ {"id": 12, "name": "rick"}
16
+ You can use ERB to format each test case.
17
+ GET
18
+ api/zzz
19
+ {:id=>12}
20
+ {"id": 12, "name": "rick"}
21
+ You can use ERB to format each test case.
22
+ GET
23
+ api/aaa
24
+ {:id=>12}
25
+ {"id": 12, "name": "rick"}
26
+ You can use ERB to format each test case.
27
+ GET
28
+ api/users
29
+ {:id=>12}
30
+ {"id": 12, "name": "rick"}
31
+ You can use ERB to format each test case.
32
+ GET
33
+ api/users
34
+ {:id=>12}
35
+ {"id": 12, "name": "rick"}
36
+ You can use ERB to format each test case.
37
+ GET
38
+ api/zzz
39
+ {:id=>12}
40
+ {"id": 12, "name": "rick"}
41
+ You can use ERB to format each test case.
42
+ GET
43
+ api/aaa
44
+ {:id=>12}
45
+ {"id": 12, "name": "rick"}
46
+ You can use ERB to format each test case.
47
+ GET
48
+ api/zzz
49
+ {:id=>12}
50
+ {"id": 12, "name": "rick"}
51
+ You can use ERB to format each test case.
52
+ GET
53
+ api/users
54
+ {:id=>12}
55
+ {"id": 12, "name": "rick"}
56
+ You can use ERB to format each test case.
57
+ GET
58
+ api/users
59
+ {:id=>12}
60
+ {"id": 12, "name": "rick"}
61
+ You can use ERB to format each test case.
62
+ GET
63
+ api/aaa
64
+ {:id=>12}
65
+ {"id": 12, "name": "rick"}
66
+ You can use ERB to format each test case.
67
+ GET
68
+ api/zzz
69
+ {:id=>12}
70
+ {"id": 12, "name": "rick"}
71
+ You can use ERB to format each test case.
72
+ GET
73
+ api/aaa
74
+ {:id=>12}
75
+ {"id": 12, "name": "rick"}
76
+ You can use ERB to format each test case.
77
+ GET
78
+ api/zzz
79
+ {:id=>12}
80
+ {"id": 12, "name": "rick"}
@@ -0,0 +1,94 @@
1
+ class SmarfDoc
2
+ attr_accessor :tests
3
+ def initialize
4
+ @tests = []
5
+ @skip = false
6
+ @note = ''
7
+ @information = {}
8
+ end
9
+
10
+ def sort_by_url!
11
+ @tests.sort! do |x, y|
12
+ x.request.path <=> y.request.path
13
+ end
14
+ end
15
+
16
+ def clean_up!
17
+ @tests = []
18
+ end
19
+
20
+ def note(msg)
21
+ @note = msg
22
+ end
23
+
24
+ def information(key, value)
25
+ @information[key] = value
26
+ end
27
+
28
+ def run!(request, response)
29
+ if @skip
30
+ @skip = false
31
+ return
32
+ end
33
+ add_test_case(request, response)
34
+ @note = ''
35
+ self
36
+ end
37
+
38
+ def add_test_case(request, response)
39
+ test = self.class::TestCase.new(request, response, @note, @information)
40
+ test.template = self.class::Conf.template
41
+ self.tests << test
42
+ end
43
+
44
+ def skip
45
+ @skip = true
46
+ end
47
+
48
+ def output_testcases_to_file
49
+ docs = self.class::Conf.output_file
50
+ raise 'No output file specific for SmarfDoc' unless docs
51
+ File.delete docs if File.exists? docs
52
+ write_to_file
53
+ end
54
+
55
+ def write_to_file
56
+ File.open(self.class::Conf.output_file, 'a') do |file|
57
+ @tests.each do |test|
58
+ file.write(test.compile_template)
59
+ end
60
+ end
61
+ end
62
+
63
+ # = = = =
64
+
65
+ def self.finish!
66
+ current.sort_by_url!
67
+ current.output_testcases_to_file
68
+ current.clean_up!
69
+ end
70
+
71
+ def self.run!(request, response)
72
+ current.run!(request, response)
73
+ end
74
+
75
+ def self.skip
76
+ current.skip
77
+ end
78
+
79
+ def self.note(msg)
80
+ current.note(msg)
81
+ end
82
+
83
+ def self.information(key, value)
84
+ current.information(key, value)
85
+ end
86
+
87
+ def self.current
88
+ Thread.current[:instance] ||= self.new
89
+ end
90
+
91
+ def self.config(&block)
92
+ yield(self::Conf)
93
+ end
94
+ end
@@ -0,0 +1,12 @@
1
+ class SmarfDoc::Conf
2
+ class << self
3
+ attr_accessor :template_file, :output_file
4
+
5
+ @output_file = 'documentation.md'
6
+
7
+ def template
8
+ raise 'You must set a template file.' unless template_file
9
+ @template ||= File.read(template_file)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ require 'base'
2
+ require 'conf'
3
+ require 'test_case'
4
+
@@ -0,0 +1,15 @@
1
+ require 'erb'
2
+
3
+ class SmarfDoc::TestCase
4
+ attr_reader :request, :response, :created_at, :note, :information
5
+ attr_accessor :template
6
+
7
+ def initialize(request, response, note = '', information = {})
8
+ @request, @response, @note, @information = request, response, note, information
9
+ @created_at = Time.now
10
+ end
11
+
12
+ def compile_template
13
+ ERB.new(template).result binding
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.authors = ['Rick Carlino']
5
+ s.description = "Write API documentation using existing controller tests."
6
+ s.email = 'rick.carlino@gmail.com'
7
+ s.files = `git ls-files`.split("\n")
8
+ s.homepage = 'https://github.com/RickCarlino/smarf_doc'
9
+ s.license = 'MIT'
10
+ s.name = 'smarf_doc'
11
+ s.require_paths = ['lib']
12
+ s.summary = "Uses your test cases to write example documentation for your API."
13
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ s.version = '1.0.0'
15
+ end
File without changes
@@ -0,0 +1,7 @@
1
+ You can use ERB to format each test case.
2
+ <%= request.method %>
3
+ <%= request.path %>
4
+ <%= request.params %>
5
+ <%= response.body %>
6
+ <%= note %>
7
+ <%= information[:aside] %>
@@ -0,0 +1,102 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestBase < SmarfDocTest
4
+
5
+ def test_run!
6
+ tests = SmarfDoc.current.tests
7
+ assert_equal 0, tests.length,
8
+ "Expected current tests to be an empty array"
9
+ SmarfDoc.run!(request, response)
10
+ assert_equal 1, tests.length,
11
+ "Expected run!() to increase number of tests"
12
+ assert tests.first.is_a?(SmarfDoc::TestCase)
13
+ SmarfDoc.run!(request, response)
14
+ assert_equal 2, tests.length,
15
+ "Expected run!() to increase number of tests"
16
+ assert_includes tests.first.compile_template,
17
+ "You can use ERB to format each test case",
18
+ "Did not load correct template file"
19
+ end
20
+
21
+ def test_sort!
22
+ first = Request.new("GET", {id: 12}, 'api/aaa')
23
+ last = Request.new("GET", {id: 12}, 'api/zzz')
24
+ SmarfDoc.run!(first, response)
25
+ SmarfDoc.run!(last, response)
26
+ results = SmarfDoc.current.sort_by_url!.map{|tc| tc.request.path}
27
+ assert_equal ["api/aaa", "api/zzz"], results,
28
+ "Did not sort test cases by request URL"
29
+ end
30
+
31
+ def test_finish!
32
+ file = SmarfDoc::Conf.output_file
33
+ first = Request.new("GET", {id: 12}, 'api/aaa')
34
+ last = Request.new("GET", {id: 12}, 'api/zzz')
35
+ SmarfDoc.run!(first, response)
36
+ SmarfDoc.run!(last, response)
37
+ SmarfDoc.finish!
38
+ assert File.exists?(file),
39
+ "Did not create an output file after finish!()ing"
40
+ assert_includes File.read(file), "You can use ERB",
41
+ "Did not utilize template to output docs."
42
+ end
43
+
44
+ def test_skip
45
+ file = SmarfDoc::Conf.output_file
46
+ tests= SmarfDoc.current.tests
47
+ first = Request.new("GET", {id: 12}, 'api/skip')
48
+ last = Request.new("GET", {id: 12}, 'api/noskip')
49
+ SmarfDoc.skip
50
+ SmarfDoc.run!(first, response)
51
+ SmarfDoc.run!(last, response)
52
+ assert_equal 1, tests.length,
53
+ "Did not skip tests."
54
+ assert_equal 'api/noskip', tests.first.request.path,
55
+ "Did not skip tests."
56
+ end
57
+
58
+ def test_multiple_skips
59
+ file = SmarfDoc::Conf.output_file
60
+ tests= SmarfDoc.current.tests
61
+ first = Request.new("GET", {id: 12}, 'api/noskip1')
62
+ second = Request.new("GET", {id: 12}, 'api/skip1')
63
+ third = Request.new("GET", {id: 12}, 'api/skip2')
64
+ fourth = Request.new("GET", {id: 12}, 'api/noskip2')
65
+ SmarfDoc.run!(first, response)
66
+ SmarfDoc.skip
67
+ SmarfDoc.run!(second, response)
68
+ SmarfDoc.skip
69
+ SmarfDoc.run!(third, response)
70
+ SmarfDoc.run!(fourth, response)
71
+ assert_equal 2, tests.length,
72
+ "Skipped 2 tests."
73
+ assert_equal 'api/noskip1', tests[0].request.path,
74
+ "Did not skip first unskipped test."
75
+ assert_equal 'api/noskip2', tests[1].request.path,
76
+ "Did not skip second unskipped test."
77
+ end
78
+
79
+ def test_note
80
+ file = SmarfDoc::Conf.output_file
81
+ tests= SmarfDoc.current.tests
82
+ first = Request.new("GET", {id: 12}, 'api/skip')
83
+ last = Request.new("GET", {id: 12}, 'api/noskip')
84
+ SmarfDoc.note "안녕하세요"
85
+ SmarfDoc.run!(first, response)
86
+ SmarfDoc.run!(last, response)
87
+ assert_includes tests.first.compile_template, "안녕하세요",
88
+ "Could not find note in documentation."
89
+ end
90
+
91
+ def test_information
92
+ file = SmarfDoc::Conf.output_file
93
+ tests= SmarfDoc.current.tests
94
+ first = Request.new("GET", {id: 12}, 'api/skip')
95
+ last = Request.new("GET", {id: 12}, 'api/noskip')
96
+ SmarfDoc.information(:aside, "This controller only responds on Tuesdays")
97
+ SmarfDoc.run!(first, response)
98
+ SmarfDoc.run!(last, response)
99
+ assert_includes tests.first.compile_template, "This controller only responds on Tuesdays",
100
+ "Could not find note in documentation."
101
+ end
102
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestConfig < SmarfDocTest
4
+
5
+ def test_set_configs
6
+ SmarfDoc.config do |c|
7
+ c.template_file = 'test/template.md.erb'
8
+ c.output_file = 'api_docs.md'
9
+ end
10
+ assert_equal 'api_docs.md', SmarfDoc::Conf.output_file,
11
+ "Unable to set output file"
12
+ assert_equal 'test/template.md.erb', SmarfDoc::Conf.template_file,
13
+ "Unable to set template file"
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ require_relative '../lib/smarf_doc'
2
+ require 'minitest/autorun'
3
+ require 'minitest/pride'
4
+ require 'pry'
5
+
6
+ class SmarfDocTest < Minitest::Test
7
+ def setup
8
+ SmarfDoc.config do |c|
9
+ c.template_file = 'test/fake_template.md'
10
+ c.output_file = 'test/fake_output.md'
11
+ end
12
+ end
13
+
14
+ def teardown
15
+ SmarfDoc.finish!
16
+ end
17
+
18
+ # Include some fake structs that act like response/request objects.
19
+ Request = Struct.new :method, :params, :path
20
+ Response = Struct.new :body, :success?
21
+
22
+ def request
23
+ Request.new("GET", {id: 12}, 'api/users')
24
+ end
25
+
26
+ def response
27
+ Response.new('{"id": 12, "name": "rick"}', true)
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestTestCase < SmarfDocTest
4
+
5
+ def test_case
6
+ @test_case ||= SmarfDoc::TestCase.new(request, response)
7
+ end
8
+
9
+ def test_compile_template
10
+ template = "<%= 2 + 2 %>"
11
+ test_case.template = template
12
+ assert_equal test_case.template, template,
13
+ "Could not set a template."
14
+ assert_equal "4", test_case.compile_template,
15
+ "Could not compile template"
16
+ end
17
+
18
+ def test_compile_with_file
19
+ SmarfDoc.config { |c| c.template_file = 'test/fake_template.md' }
20
+ test = SmarfDoc::TestCase.new(request, response)
21
+ test.template = SmarfDoc::Conf.template
22
+ assert_includes test.compile_template, "use ERB"
23
+ end
24
+
25
+ def test_created_at
26
+ assert test_case.created_at.is_a?(Time)
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smarf_doc
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rick Carlino
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Write API documentation using existing controller tests.
14
+ email: rick.carlino@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - README.md
21
+ - Rakefile
22
+ - api_docs.md
23
+ - documentation.md
24
+ - lib/base.rb
25
+ - lib/conf.rb
26
+ - lib/smarf_doc.rb
27
+ - lib/test_case.rb
28
+ - smarf_doc.gemspec
29
+ - test/fake_output.md
30
+ - test/fake_template.md
31
+ - test/test_base.rb
32
+ - test/test_config.rb
33
+ - test/test_helper.rb
34
+ - test/test_test_case.rb
35
+ homepage: https://github.com/RickCarlino/smarf_doc
36
+ licenses:
37
+ - MIT
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 2.4.8
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Uses your test cases to write example documentation for your API.
59
+ test_files: []