smashing_docs 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 22b7029c0973147b6d3a28e53a5f3cab6c77b9a0
4
+ data.tar.gz: 0d6744dbb8ebdd8a92dccc1302bdd51c2100ddc9
5
+ SHA512:
6
+ metadata.gz: bf8e59d70429b63875b0a3f405f26b598d644fd3dfc9a0cb8bc8f6dc0dd45e25d99711a11ba4ccb2a7b6e9260b56e31b2f5e37e267fa6d4e4df668437d11677b
7
+ data.tar.gz: 9ad103afe3b8f88ffa85ab7df2c0b716d9169f2134022b147855bb0e00d7d971e28220d6d66464d21880b12a9cc55834b2fad439ad477285cfd4f96e2a58fb9a
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /coverage/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # SmashingDocs
2
+
3
+ ### Based on [SmarfDoc](https://github.com/RickCarlino/smarf_doc) by [Rick Carlino](https://github.com/RickCarlino/)
4
+
5
+ ## Gem Installation in Rails
6
+
7
+ In your gemfile add the following to your test group:
8
+
9
+ `gem 'smashing_docs', git: 'https://github.com/smashingboxes/smashing_docs.git'`
10
+
11
+ Installation differs for RSpec/Minitest, so scroll to the appropriate section for guidance.
12
+
13
+ ## Rspec Installation
14
+
15
+ Add this to your `rails_helper.rb` It should go outside of other blocks
16
+ (Do not place it inside the `RSpec.configure` block).
17
+ ```ruby
18
+ SmarfDoc.config do |c|
19
+ c.template_file = 'spec/template.md.erb'
20
+ c.output_file = 'api_docs.md'
21
+ end
22
+ ```
23
+
24
+ Add the following line to `spec_helper.rb` inside the `RSpec.configure` block
25
+
26
+ `config.after(:suite) { SmashingDocs.finish! }`
27
+
28
+ It should look like this
29
+ ```ruby
30
+ RSpec.configure do |config|
31
+ # Existing code
32
+ config.after(:suite) { SmashingDocs.finish! }
33
+ end
34
+ ```
35
+ #### To run on all controller tests
36
+
37
+ Add this to your `spec_helper.rb`
38
+ ```ruby
39
+ config.after(:each, type: :controller) do
40
+ SmashingDocs.run!(request, response)
41
+ end
42
+ ```
43
+
44
+ The whole file should look like this
45
+ ```ruby
46
+ RSpec.configure do |config|
47
+ # Existing code
48
+ config.after(:each, type: :controller) do
49
+ SmashingDocs.run!(request, response)
50
+ end
51
+ config.after(:suite) { SmashingDocs.finish! }
52
+ end
53
+ ```
54
+ #### To run on only select tests
55
+ Just add `SmashingDocs.run!(request, response)` to specific tests
56
+ ```ruby
57
+ it "responds with 200" do
58
+ get :index
59
+ expect(response).to be_success
60
+ SmashingDocs.run!(request, response)
61
+ end
62
+ ```
63
+
64
+ ## Minitest Installation
65
+
66
+ Add the code from below to `test_helper.rb`:
67
+ ```ruby
68
+ class ActiveSupport::TestCase
69
+ # Already existing code
70
+ SmashingDocs.config do |c|
71
+ c.template_file = 'test/template.md.erb'
72
+ c.output_file = 'api_docs.md'
73
+ end
74
+ # More code
75
+ end
76
+
77
+ MiniTest::Unit.after_tests { SmashingDocs.finish! }
78
+ ```
79
+ #### To run on all controller tests
80
+ Add this to `test_helper.rb` as well:
81
+ ```ruby
82
+ class ActionController::TestCase < ActiveSupport::TestCase
83
+ def teardown
84
+ SmashingDocs.run!(request, response)
85
+ end
86
+ end
87
+ ```
88
+
89
+ Your code should look like this:
90
+ ```ruby
91
+ class ActiveSupport::TestCase
92
+ # Already existing code
93
+ SmashingDocs.config do |c|
94
+ c.template_file = 'test/template.md.erb'
95
+ c.output_file = 'api_docs.md'
96
+ end
97
+ # More code
98
+ end
99
+
100
+ class ActionController::TestCase < ActiveSupport::TestCase
101
+ def teardown
102
+ SmashingDocs.run!(request, response)
103
+ end
104
+ end
105
+
106
+ MiniTest::Unit.after_tests { SmashingDocs.finish! }
107
+ ```
108
+
109
+
110
+ #### To run on only select tests
111
+ Just add `SmashingDocs.run!(request, response)` to specific tests
112
+ ```ruby
113
+ def get_index
114
+ get :index
115
+ assert response.status == 200
116
+ SmashingDocs.run!(request, response)
117
+ end
118
+ ```
119
+
120
+ ## Setting a template
121
+
122
+ If you copied the code from above, SmashingDocs will look for a template file located at either
123
+ `test/template.md.erb` or `spec/template.md.erb`, depending on your test suite.
124
+ This template may be customized to fit your needs.
125
+
126
+ ```erb
127
+ <%= request.method %>
128
+ <%= request.path %>
129
+ <%= request.params %>
130
+ <%= response.body %>
131
+ <%= information[:note] %>
132
+ <%= aside %>
133
+ ```
134
+
135
+ ## Where to find the docs
136
+
137
+ By default, the docs are output to `api_docs.md` in the root of the Rails project.
138
+ You can change this by altering the config in `test_helper.rb` or `rails_helper.rb`.
139
+
140
+ ## Additional Features
141
+
142
+ #### Skipping documentation on tests
143
+
144
+ To leave certain tests out of the documentation, just add `SmashingDocs.skip` to the test.
145
+
146
+ ```ruby
147
+ it "responds with 200" do
148
+ SmashingDocs.skip
149
+ # test code
150
+ end
151
+ ```
152
+
153
+ #### Adding information, e.g. notes
154
+ SmashingDocs will log all requests and responses by default, but you can add some
155
+ **optional** parameters as well.
156
+
157
+ ```ruby
158
+ it "responds with 200" do
159
+ SmashingDocs.information(:note, "This endpoint only responds on Tuesdays")
160
+ # test code
161
+ end
162
+ ```
163
+ You can store any information with `:note`, `:message`, or any other key you can think of.
164
+ To access information in the template, just use `<%= information[:key] %>`
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/api_docs.md ADDED
File without changes
data/documentation.md ADDED
@@ -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"}
data/lib/base.rb ADDED
@@ -0,0 +1,99 @@
1
+ class SmashingDocs
2
+ attr_accessor :tests
3
+ def initialize
4
+ @tests = []
5
+ @skip = false
6
+ @information = {}
7
+ end
8
+
9
+ def sort_by_url!
10
+ @tests.sort! do |x, y|
11
+ x.request.path <=> y.request.path
12
+ end
13
+ end
14
+
15
+ def clean_up!
16
+ @tests = []
17
+ end
18
+
19
+ def aside(msg)
20
+ @aside = ''
21
+ @aside = "<aside class='notice'>\n #{msg}\n</aside>"
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
+ @information = {}
35
+ @skip = false
36
+ self
37
+ end
38
+
39
+ def add_test_case(request, response)
40
+ test = self.class::TestCase.new(request, response, @information, @aside)
41
+ test.template = self.class::Conf.template
42
+ self.tests << test
43
+ end
44
+
45
+ def skip
46
+ @skip = true
47
+ end
48
+
49
+ def output_testcases_to_file
50
+ docs = self.class::Conf.output_file
51
+ raise 'No output file specific for SmashingDocs' unless docs
52
+ File.delete docs if File.exists? docs
53
+ write_to_file
54
+ end
55
+
56
+ def write_to_file
57
+ File.open(self.class::Conf.output_file, 'a') do |file|
58
+ @tests.each do |test|
59
+ file.write(test.compile_template)
60
+ end
61
+ end
62
+ end
63
+
64
+ # = = = =
65
+ # These class methods are used to persist test data across tests
66
+ # RSpec and Minitest do not support hooks that would allow
67
+ # for an instance variable to be declared and used
68
+
69
+ def self.finish!
70
+ current.sort_by_url!
71
+ current.output_testcases_to_file
72
+ current.clean_up!
73
+ end
74
+
75
+ def self.run!(request, response)
76
+ current.run!(request, response)
77
+ end
78
+
79
+ def self.skip
80
+ current.skip
81
+ end
82
+
83
+ def self.information(key, value)
84
+ current.information(key, value)
85
+ end
86
+
87
+ def self.aside(message)
88
+ current.aside(message)
89
+ end
90
+
91
+ def self.current
92
+ # Behaves like an instance of SmashingDocs class
93
+ Thread.current[:instance] ||= self.new
94
+ end
95
+
96
+ def self.config(&block)
97
+ yield(self::Conf)
98
+ end
99
+ end
data/lib/conf.rb ADDED
@@ -0,0 +1,12 @@
1
+ class SmashingDocs::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
+
data/lib/test_case.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'erb'
2
+
3
+ class SmashingDocs::TestCase
4
+ attr_reader :request, :response, :created_at, :information, :aside
5
+ attr_accessor :template
6
+
7
+ def initialize(request, response, information = {}, aside = '')
8
+ @request, @response, @information, @aside = request, response, information, aside
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,18 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.authors = ['Tyler Rockwell', 'Annie Baer', 'Rick Carlino']
5
+ s.description = "Write API documentation using existing controller tests."
6
+ s.files = `git ls-files`.split("\n")
7
+ s.homepage = 'https://github.com/smashingboxes/smashing_docs'
8
+ s.license = 'MIT'
9
+ s.name = 'smashing_docs'
10
+ s.require_paths = ['lib']
11
+ s.summary = "Uses your test cases to write example documentation for your API."
12
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
+ s.version = '0.0.2'
14
+
15
+ s.add_development_dependency "bundler", "~> 1.11"
16
+ s.add_development_dependency "rake", "~> 10.0"
17
+ s.add_development_dependency "rspec", "~> 3.0"
18
+ end
data/spec/base_spec.rb ADDED
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SmashingDocs do
4
+ let(:file) { SmashingDocs::Conf.output_file }
5
+ let(:first) { Request.new("GET", {id: 12}, 'api/aaa') }
6
+ let(:middle) { Request.new("GET", { id: 12 }, 'api/ooo') }
7
+ let(:last) { Request.new("GET", {id: 12}, 'api/zzz') }
8
+ let(:tests) { SmashingDocs.current.tests }
9
+
10
+ describe ".run!(request, response)" do
11
+ context "when no tests have been run" do
12
+ it "has done nothing" do
13
+ expect(tests.length).to eq(0)
14
+ end
15
+ end
16
+ context "running 1 test" do
17
+ it "adds the test to the list of tests" do
18
+ SmashingDocs.run!(request, response)
19
+ expect(tests.length).to eq(1)
20
+ expect(tests.first).to be_a(SmashingDocs::TestCase)
21
+ end
22
+ end
23
+ context "running 2 tests" do
24
+ it "adds both tests to the list of tests" do
25
+ 2.times { SmashingDocs.run!(request, response) }
26
+ expect(tests.length).to eq(2)
27
+ end
28
+ end
29
+ end
30
+
31
+ describe ".sort!" do
32
+ let(:results) { SmashingDocs.current.sort_by_url!.map{|tc| tc.request.path} }
33
+ it "sorts tests alphabetically by endpoint" do
34
+ SmashingDocs.run!(first, response)
35
+ SmashingDocs.run!(last, response)
36
+ SmashingDocs.run!(middle, response)
37
+ expect(results).to eq(["api/aaa", "api/ooo", "api/zzz"])
38
+ end
39
+ end
40
+
41
+ describe ".finish!" do
42
+ it "creates the docs file with output from the template" do
43
+ SmashingDocs.run!(first, response)
44
+ SmashingDocs.run!(last, response)
45
+ SmashingDocs.finish!
46
+ expect(File).to exist(file)
47
+ expect(File.read(file)).to include("You can use ERB")
48
+ end
49
+ end
50
+
51
+ describe ".skip" do
52
+ context "one skip" do
53
+ it "skips a single test" do
54
+ SmashingDocs.skip
55
+ SmashingDocs.run!(first, response)
56
+ SmashingDocs.run!(last, response)
57
+ expect(tests.length).to eq(1)
58
+ expect(tests.first.request.path).to eq("api/zzz")
59
+ end
60
+ end
61
+ context "multiple skips" do
62
+ it "skips multiple tests" do
63
+ SmashingDocs.skip
64
+ SmashingDocs.run!(first, response)
65
+ SmashingDocs.skip
66
+ SmashingDocs.run!(middle, response)
67
+ SmashingDocs.run!(last, response)
68
+ expect(tests.length).to eq(1)
69
+ expect(tests.first.request.path).to eq("api/zzz")
70
+ end
71
+ end
72
+ end
73
+
74
+ describe ".information(key, value)" do
75
+ # The template file must have <%= information[:note] %>
76
+ it "sends information to be displayed about the endpoint" do
77
+ SmashingDocs.information(:note, "Endpoint note")
78
+ SmashingDocs.run!(first, response)
79
+ expect(tests.first.compile_template).to include("Endpoint note")
80
+ end
81
+ end
82
+
83
+ describe ".aside(message)" do
84
+ # The template file must have <%= information[:note] %>
85
+ it "sends information to be displayed about the endpoint" do
86
+ SmashingDocs.aside("I am an aside")
87
+ SmashingDocs.run!(first, response)
88
+ expect(tests.first.compile_template).to include("<aside class='notice'>")
89
+ expect(tests.first.compile_template).to include("I am an aside")
90
+ end
91
+ end
92
+ end
data/spec/conf_spec.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SmashingDocs::Conf do
4
+ let!(:config) {
5
+ SmashingDocs.config do |c|
6
+ c.template_file = "spec/template.md.erb"
7
+ c.output_file = "api_docs.md"
8
+ end
9
+ }
10
+ it "sets the template file" do
11
+ expect(SmashingDocs::Conf.output_file).to eq("api_docs.md")
12
+ end
13
+
14
+ it "sets the output file" do
15
+ expect(SmashingDocs::Conf.template_file).to eq("spec/template.md.erb")
16
+ end
17
+ 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
+ <%= information[:note] %>
7
+ <%= aside %>
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'smashing_docs'
3
+
4
+ RSpec.configure do |config|
5
+ config.expect_with :rspec do |expectations|
6
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
7
+ end
8
+ config.before(:each) do
9
+ SmashingDocs.config do |c|
10
+ c.template_file = 'spec/fake_template.md.erb'
11
+ c.output_file = 'spec/fake_output.md'
12
+ end
13
+ end
14
+ config.after(:each) do
15
+ SmashingDocs.finish!
16
+ end
17
+ end
18
+
19
+ # Include some fake structs that act like response/request objects.
20
+ Request = Struct.new :method, :params, :path
21
+ Response = Struct.new :body, :success?
22
+
23
+ def request
24
+ Request.new("GET", {id: 12}, 'api/users')
25
+ end
26
+
27
+ def response
28
+ Response.new('{"id": 12, "name": "rick"}', true)
29
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SmashingDocs::TestCase do
4
+ let(:test_case) { SmashingDocs::TestCase.new(request, response) }
5
+
6
+ describe "#compile_template" do
7
+ context "with text" do
8
+ let(:template) { "<%= 2 + 2 %>" }
9
+ it "evaluates erb and returns a value" do
10
+ test_case.template = template
11
+ expect(test_case.compile_template).to eq("4")
12
+ end
13
+ end
14
+
15
+ context "with a template file" do
16
+ let!(:template) { SmashingDocs.config { |c| c.template_file = 'spec/fake_template.md.erb' } }
17
+ it "sets the template file and returns docs matching the template" do
18
+ test_case.template = SmashingDocs::Conf.template
19
+ expect(test_case.compile_template).to include("use ERB")
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "#created_at" do
25
+ it "returns the time the TestCase was created" do
26
+ expect(test_case.created_at).to be_a(Time)
27
+ end
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smashing_docs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Rockwell
8
+ - Annie Baer
9
+ - Rick Carlino
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2016-02-18 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bundler
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '1.11'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '1.11'
29
+ - !ruby/object:Gem::Dependency
30
+ name: rake
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '10.0'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '10.0'
43
+ - !ruby/object:Gem::Dependency
44
+ name: rspec
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '3.0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '3.0'
57
+ description: Write API documentation using existing controller tests.
58
+ email:
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - README.md
66
+ - Rakefile
67
+ - api_docs.md
68
+ - documentation.md
69
+ - lib/base.rb
70
+ - lib/conf.rb
71
+ - lib/smashing_docs.rb
72
+ - lib/test_case.rb
73
+ - smashing_docs.gemspec
74
+ - spec/base_spec.rb
75
+ - spec/conf_spec.rb
76
+ - spec/fake_output.md
77
+ - spec/fake_template.md.erb
78
+ - spec/spec_helper.rb
79
+ - spec/test_case_spec.rb
80
+ homepage: https://github.com/smashingboxes/smashing_docs
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.4.5
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Uses your test cases to write example documentation for your API.
104
+ test_files:
105
+ - spec/base_spec.rb
106
+ - spec/conf_spec.rb
107
+ - spec/fake_output.md
108
+ - spec/fake_template.md.erb
109
+ - spec/spec_helper.rb
110
+ - spec/test_case_spec.rb