smarf_doc 1.0.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.
@@ -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: []