rspec-document_requests 1.1.0 → 1.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.
- checksums.yaml +4 -4
- data/README.md +8 -6
- data/lib/rspec/document_requests/builder.rb +36 -10
- data/lib/rspec/document_requests/dsl.rb +2 -3
- data/lib/rspec/document_requests/explanation.rb +10 -10
- data/lib/rspec/document_requests/organized_request.rb +10 -7
- data/lib/rspec/document_requests/version.rb +1 -1
- data/lib/rspec/document_requests/writers/base.rb +73 -5
- data/lib/rspec/document_requests/writers/markdown.rb +80 -65
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c1fd117650183a8e2b17f41acfeb19bcd011251
|
4
|
+
data.tar.gz: 582ddbaa7fd602d131b676747a10b084172fb479
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e31e5dcc0518b3c6305ad60a8ac1f34dd2047ccd4a5759aaf4ffebc7a4b79764cce964edc29ca069338314e21a31e9bab892a269d2d8feeb63c50217f97bdd8b
|
7
|
+
data.tar.gz: 8952825398234193dc0dad866685978a5fd4e5e601bbd9a3258e91dc53ed6ed8835b6612df2acaa2993100972656849640e8b8e2c34f7e3f67e7f9eff829a103
|
data/README.md
CHANGED
@@ -44,6 +44,8 @@ require 'rspec/document_requests/dsl' # <- this line
|
|
44
44
|
|
45
45
|
### Marking code to document
|
46
46
|
|
47
|
+
**NOTE:** The `nodoc` DSL is not available in example groups (`describe`/`context`) without `doc: true`.
|
48
|
+
|
47
49
|
In your example group (`describe`/`context`), simply add the `doc: true` metadata:
|
48
50
|
|
49
51
|
```ruby
|
@@ -85,7 +87,7 @@ also exclude any specs without `doc: true` metadata to make this run faster.
|
|
85
87
|
|
86
88
|
### Explaining the request
|
87
89
|
|
88
|
-
**NOTE:**
|
90
|
+
**NOTE:** The `explain` DSL is not available in example groups (`describe`/`context`) without `doc: true`.
|
89
91
|
|
90
92
|
Just before your request, it's a good idea to explain (everything is optional):
|
91
93
|
|
@@ -93,20 +95,20 @@ Just before your request, it's a good idea to explain (everything is optional):
|
|
93
95
|
# spec/requests/session_spec.rb
|
94
96
|
|
95
97
|
RSpec.describe "Session resource", type: :request, doc: true do
|
96
|
-
describe "Create session" do
|
98
|
+
describe "Create session", explanation: "This is how you create a session." do
|
97
99
|
before do
|
98
|
-
explain "Creating
|
100
|
+
explain { request "Creating a user" }
|
99
101
|
post "/users", user: { username: "myuser", password: "123123" }
|
100
102
|
end
|
101
103
|
|
102
104
|
before do
|
103
|
-
explain do
|
104
|
-
request do
|
105
|
+
explain do
|
106
|
+
request do # No request explanation
|
105
107
|
parameter 'session[username]', "The username", required: true, type: 'string'
|
106
108
|
parameter 'session[password]', required: true, type: 'string' # No explanation
|
107
109
|
header 'Content-Type', ... # you get the point
|
108
110
|
end
|
109
|
-
response do
|
111
|
+
response do # No response explanation
|
110
112
|
parameter 'message', "Message from the server", required: true # No type
|
111
113
|
parameter 'session_id', "The session ID" # Not required and no type
|
112
114
|
header 'Set-Cookie', ...
|
@@ -30,8 +30,9 @@ module RSpec
|
|
30
30
|
@writer = config.writer.new(file)
|
31
31
|
write_breadcrumb
|
32
32
|
write_title
|
33
|
-
@current.ungrouped_children.each { |child| write_child(child) }
|
33
|
+
@current.ungrouped_children.each { |child| write_child(child, last: child == @current.ungrouped_children.last) }
|
34
34
|
write_recursive_requests(@current)
|
35
|
+
@writer.close
|
35
36
|
end
|
36
37
|
|
37
38
|
@current.ungrouped_children.each do |child|
|
@@ -44,12 +45,18 @@ module RSpec
|
|
44
45
|
missing_levels = []
|
45
46
|
if not child == @current
|
46
47
|
missing = child
|
47
|
-
missing_levels.unshift(missing
|
48
|
+
missing_levels.unshift(missing) while (missing = missing.parent) and missing != @current
|
49
|
+
end
|
50
|
+
missing_levels = missing_levels.map do |organized_entry|
|
51
|
+
{
|
52
|
+
description: organized_entry.metadata[:description],
|
53
|
+
explanation: metadata_explanation(organized_entry.metadata),
|
54
|
+
}
|
48
55
|
end
|
49
56
|
|
50
57
|
child.example_requests.to_a.uniq { |e,| e.example_group }.each do |example, requests|
|
51
58
|
write_example_title(example, missing_levels: missing_levels) unless child == @current
|
52
|
-
requests.each { |request| write_request(request
|
59
|
+
requests.each { |request| write_request(request) }
|
53
60
|
end
|
54
61
|
|
55
62
|
child.grouped_children.each_with_index do |grandchild, i|
|
@@ -57,6 +64,10 @@ module RSpec
|
|
57
64
|
end
|
58
65
|
end
|
59
66
|
|
67
|
+
def metadata_explanation(metadata)
|
68
|
+
metadata[:explanation] if metadata[:parent_example_group].nil? or metadata[:explanation] != metadata[:parent_example_group][:explanation]
|
69
|
+
end
|
70
|
+
|
60
71
|
def write_breadcrumb
|
61
72
|
current = @current
|
62
73
|
parent_tree = []
|
@@ -67,7 +78,7 @@ module RSpec
|
|
67
78
|
parent_path = Pathname.new('.').join(*parent_tree.length.times.map { '..' })
|
68
79
|
parent_tree.each do |parent|
|
69
80
|
@writer.breadcrumb(
|
70
|
-
description: parent.description,
|
81
|
+
description: parent.metadata[:description],
|
71
82
|
filename: parent_path.join(parent.filename).sub_ext(config.writer::EXTENSION),
|
72
83
|
last: parent == @current.parent,
|
73
84
|
)
|
@@ -76,22 +87,37 @@ module RSpec
|
|
76
87
|
end
|
77
88
|
|
78
89
|
def write_title
|
79
|
-
@
|
90
|
+
metadata = @current.metadata
|
91
|
+
@writer.title(description: metadata[:description], explanation: metadata_explanation(metadata))
|
80
92
|
end
|
81
93
|
|
82
|
-
def write_child(child)
|
94
|
+
def write_child(child, last:)
|
83
95
|
@writer.child(
|
84
|
-
description: child.description,
|
96
|
+
description: child.metadata[:description],
|
85
97
|
filename: @current.filename.join(child.filename).sub_ext(config.writer::EXTENSION),
|
98
|
+
last: last,
|
86
99
|
)
|
87
100
|
end
|
88
101
|
|
89
102
|
def write_example_title(example, missing_levels:)
|
90
|
-
|
103
|
+
metadata = example.example_group.metadata
|
104
|
+
@writer.example_title(description: metadata[:description], explanation: metadata_explanation(metadata), missing_levels: missing_levels)
|
91
105
|
end
|
92
106
|
|
93
|
-
def write_request(request
|
94
|
-
|
107
|
+
def write_request(request)
|
108
|
+
# request
|
109
|
+
@writer.request.title(request.explanation.request.message)
|
110
|
+
@writer.request.path(request.method, request.path)
|
111
|
+
@writer.request.parameters(request.request_parameters) if request.request_parameters.present?
|
112
|
+
@writer.request.body(request.request_body) if request.request_body.present?
|
113
|
+
@writer.request.headers(request.request_headers) if request.request_headers.present?
|
114
|
+
# response
|
115
|
+
@writer.response.title(request.explanation.response.message)
|
116
|
+
@writer.response.status(request.response.status, request.response.status_message)
|
117
|
+
@writer.response.content_type(request.response.content_type)
|
118
|
+
@writer.response.parameters(request.response_parameters) if request.response_parameters.present?
|
119
|
+
@writer.response.body(request.response.body) if request.response.body.present?
|
120
|
+
@writer.response.headers(request.response_headers) if request.response_headers.present?
|
95
121
|
end
|
96
122
|
end
|
97
123
|
end
|
@@ -28,9 +28,8 @@ module RSpec
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
def explain(
|
32
|
-
document_request_explanation.
|
33
|
-
document_request_explanation.instance_eval(&block) if block_given?
|
31
|
+
def explain(&block)
|
32
|
+
document_request_explanation.instance_eval(&block)
|
34
33
|
end
|
35
34
|
|
36
35
|
def document_request_explanation
|
@@ -2,7 +2,7 @@ module RSpec
|
|
2
2
|
module DocumentRequests
|
3
3
|
class Explanation
|
4
4
|
class Side
|
5
|
-
attr_accessor :parameters, :headers
|
5
|
+
attr_accessor :message, :parameters, :headers
|
6
6
|
|
7
7
|
def initialize
|
8
8
|
@parameters = {}
|
@@ -18,22 +18,22 @@ module RSpec
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
attr_accessor :message
|
22
|
-
|
23
21
|
def initialize
|
24
22
|
@request = Side.new
|
25
23
|
@response = Side.new
|
26
24
|
end
|
27
25
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
26
|
+
def self.build_side(side)
|
27
|
+
define_method(side) do |message = nil, &block|
|
28
|
+
instance = instance_variable_get(:"@#{side}")
|
29
|
+
instance.message = message if message
|
30
|
+
instance.instance_eval(&block) if block_given?
|
31
|
+
instance
|
32
|
+
end
|
31
33
|
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
@response
|
36
|
-
end
|
35
|
+
build_side :request
|
36
|
+
build_side :response
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -1,19 +1,22 @@
|
|
1
1
|
module RSpec
|
2
2
|
module DocumentRequests
|
3
3
|
class OrganizedRequest
|
4
|
-
attr_reader :parent, :
|
5
|
-
def initialize(
|
6
|
-
@
|
4
|
+
attr_reader :parent, :metadata, :example_requests, :children, :levels
|
5
|
+
def initialize(metadata, parent: nil)
|
6
|
+
@metadata = metadata
|
7
7
|
@parent = parent
|
8
|
-
@filename = Pathname.new(DocumentRequests.configuration.filename_generator.call(description))
|
9
8
|
@example_requests = Hash.new { |h, k| h[k] = [] }
|
10
9
|
@children = {}
|
11
10
|
@levels = Hash.new { |h, k| h[k] = 0 }
|
12
11
|
@parent.increase_level(self) if @parent
|
13
12
|
end
|
14
13
|
|
15
|
-
def
|
16
|
-
@
|
14
|
+
def filename
|
15
|
+
@filename ||= Pathname.new(DocumentRequests.configuration.filename_generator.call(@metadata[:description]))
|
16
|
+
end
|
17
|
+
|
18
|
+
def child(metadata)
|
19
|
+
@children[DocumentRequests.configuration.filename_generator.call(metadata[:description])] ||= OrganizedRequest.new(metadata, parent: self)
|
17
20
|
end
|
18
21
|
|
19
22
|
def increase_level(child)
|
@@ -44,7 +47,7 @@ module RSpec
|
|
44
47
|
|
45
48
|
organized_request = root
|
46
49
|
metadata_tree.each do |metadata|
|
47
|
-
organized_request = organized_request.child(metadata
|
50
|
+
organized_request = organized_request.child(metadata)
|
48
51
|
end
|
49
52
|
organized_request.example_requests[request.example] << request
|
50
53
|
end
|
@@ -4,28 +4,96 @@ module RSpec
|
|
4
4
|
class Base
|
5
5
|
#EXTENSION = ".something"
|
6
6
|
|
7
|
+
attr_reader :request, :response
|
8
|
+
|
7
9
|
def initialize(file)
|
8
10
|
@file = file
|
11
|
+
@request = self.class::Request.new(file)
|
12
|
+
@response = self.class::Response.new(file)
|
9
13
|
end
|
10
14
|
|
11
15
|
def breadcrumb(description:, filename:, last:)
|
12
16
|
raise NotImplementedError
|
13
17
|
end
|
14
18
|
|
15
|
-
def title(description)
|
19
|
+
def title(description:, explanation:)
|
16
20
|
raise NotImplementedError
|
17
21
|
end
|
18
22
|
|
19
|
-
def child(description:, filename:)
|
23
|
+
def child(description:, filename:, last:)
|
20
24
|
raise NotImplementedError
|
21
25
|
end
|
22
26
|
|
23
|
-
|
27
|
+
# missing_levels: [{ description: "", explanation: "" || nil }, ...]
|
28
|
+
def example_title(description:, explanation:, missing_levels:)
|
24
29
|
raise NotImplementedError
|
25
30
|
end
|
26
31
|
|
27
|
-
def
|
28
|
-
|
32
|
+
def close
|
33
|
+
@request.close
|
34
|
+
@response.close
|
35
|
+
end
|
36
|
+
|
37
|
+
class Request
|
38
|
+
def initialize(file)
|
39
|
+
@file = file
|
40
|
+
end
|
41
|
+
|
42
|
+
def title(message)
|
43
|
+
raise NotImplementedError
|
44
|
+
end
|
45
|
+
|
46
|
+
def path(method, path)
|
47
|
+
raise NotImplementedError
|
48
|
+
end
|
49
|
+
|
50
|
+
def parameters(parameters)
|
51
|
+
raise NotImplementedError
|
52
|
+
end
|
53
|
+
|
54
|
+
def body(body)
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
|
+
|
58
|
+
def headers(headers)
|
59
|
+
raise NotImplementedError
|
60
|
+
end
|
61
|
+
|
62
|
+
def close
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Response
|
67
|
+
def initialize(file)
|
68
|
+
@file = file
|
69
|
+
end
|
70
|
+
|
71
|
+
def title(message)
|
72
|
+
raise NotImplementedError
|
73
|
+
end
|
74
|
+
|
75
|
+
def status(status, message)
|
76
|
+
raise NotImplementedError
|
77
|
+
end
|
78
|
+
|
79
|
+
def content_type(content_type)
|
80
|
+
raise NotImplementedError
|
81
|
+
end
|
82
|
+
|
83
|
+
def parameters(parameters)
|
84
|
+
raise NotImplementedError
|
85
|
+
end
|
86
|
+
|
87
|
+
def body(body)
|
88
|
+
raise NotImplementedError
|
89
|
+
end
|
90
|
+
|
91
|
+
def headers(headers)
|
92
|
+
raise NotImplementedError
|
93
|
+
end
|
94
|
+
|
95
|
+
def close
|
96
|
+
end
|
29
97
|
end
|
30
98
|
end
|
31
99
|
end
|
@@ -14,100 +14,115 @@ module RSpec
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
def title(description)
|
17
|
+
def title(description:, explanation:)
|
18
18
|
@file.puts "# #{description}"
|
19
19
|
@file.puts
|
20
|
+
if explanation
|
21
|
+
@file.puts explanation
|
22
|
+
@file.puts
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
|
-
def child(description:, filename:)
|
26
|
+
def child(description:, filename:, last:)
|
23
27
|
@file.puts "* [#{description}](#{filename})"
|
28
|
+
@file.puts if last
|
24
29
|
end
|
25
30
|
|
26
|
-
def example_title(description
|
27
|
-
@file.puts "## #{missing_levels.map { |l| "#{l} > " }.join}
|
31
|
+
def example_title(description:, explanation:, missing_levels:)
|
32
|
+
@file.puts "## #{missing_levels.map { |l| "#{l[:description]} > " }.join}#{description}"
|
28
33
|
@file.puts
|
34
|
+
if explanation
|
35
|
+
@file.puts explanation
|
36
|
+
@file.puts
|
37
|
+
end
|
29
38
|
end
|
30
39
|
|
31
|
-
|
32
|
-
|
33
|
-
### Request#{" (#{request.explanation.message})" if request.explanation.message}
|
34
|
-
|
35
|
-
#{request.method} #{request.path}
|
36
|
-
|
37
|
-
FILE
|
40
|
+
module ParametersTable
|
41
|
+
private
|
38
42
|
|
39
|
-
|
40
|
-
@file.
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@file.write <<FILE
|
47
|
-
#### Body
|
48
|
-
|
49
|
-
#{request.request_body}
|
50
|
-
|
51
|
-
FILE
|
43
|
+
def parameters_table(parameters)
|
44
|
+
@file.puts "| Name | Type | Required? | Value | |"
|
45
|
+
@file.puts "|------|------|-----------|-------|---|"
|
46
|
+
parameters.each do |name, parameter|
|
47
|
+
@file.puts "| #{name} | #{parameter.type} | #{"Required" if parameter.required} | #{parameter.value} | #{parameter.message} |"
|
48
|
+
end
|
49
|
+
@file.puts
|
52
50
|
end
|
51
|
+
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
#### Headers
|
53
|
+
class Request < Base::Request
|
54
|
+
include ParametersTable
|
57
55
|
|
58
|
-
|
59
|
-
|
56
|
+
def title(message)
|
57
|
+
@file.puts "### Request#{" (#{message})" if message}"
|
58
|
+
@file.puts
|
60
59
|
end
|
61
60
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
#{request.response.status} #{request.response.status_message}
|
68
|
-
|
69
|
-
#### Content-Type
|
70
|
-
|
71
|
-
#{request.response.content_type}
|
72
|
-
|
73
|
-
FILE
|
61
|
+
def path(method, path)
|
62
|
+
@file.puts " #{method} #{path}"
|
63
|
+
@file.puts
|
64
|
+
end
|
74
65
|
|
75
|
-
|
76
|
-
@file.
|
77
|
-
|
66
|
+
def parameters(parameters)
|
67
|
+
@file.puts "#### Parameters"
|
68
|
+
@file.puts
|
69
|
+
parameters_table(parameters)
|
70
|
+
end
|
78
71
|
|
79
|
-
|
80
|
-
|
72
|
+
def body(body)
|
73
|
+
@file.puts "#### Body"
|
74
|
+
@file.puts
|
75
|
+
@file.puts " #{body}"
|
76
|
+
@file.puts
|
81
77
|
end
|
82
78
|
|
83
|
-
|
84
|
-
####
|
79
|
+
def headers(headers)
|
80
|
+
@file.puts "#### Headers"
|
81
|
+
@file.puts
|
82
|
+
parameters_table(headers)
|
83
|
+
end
|
84
|
+
end
|
85
85
|
|
86
|
-
|
86
|
+
class Response < Base::Response
|
87
|
+
include ParametersTable
|
87
88
|
|
88
|
-
|
89
|
+
def title(message)
|
90
|
+
@file.puts "### Response#{" (#{message})" if message}"
|
91
|
+
@file.puts
|
92
|
+
end
|
89
93
|
|
90
|
-
|
91
|
-
@file.
|
92
|
-
|
94
|
+
def status(status, message)
|
95
|
+
@file.puts "#### Status"
|
96
|
+
@file.puts
|
97
|
+
@file.puts " #{status} #{message}"
|
98
|
+
@file.puts
|
99
|
+
end
|
93
100
|
|
94
|
-
|
95
|
-
|
101
|
+
def content_type(content_type)
|
102
|
+
@file.puts "#### Content-Type"
|
103
|
+
@file.puts
|
104
|
+
@file.puts " #{content_type}"
|
105
|
+
@file.puts
|
96
106
|
end
|
97
|
-
end
|
98
107
|
|
99
|
-
|
108
|
+
def parameters(parameters)
|
109
|
+
@file.puts "#### Parameters"
|
110
|
+
@file.puts
|
111
|
+
parameters_table(parameters)
|
112
|
+
end
|
100
113
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
114
|
+
def body(body)
|
115
|
+
@file.puts "#### Body"
|
116
|
+
@file.puts
|
117
|
+
@file.puts " #{body}"
|
118
|
+
@file.puts
|
119
|
+
end
|
106
120
|
|
107
|
-
|
108
|
-
@file.puts "
|
121
|
+
def headers(headers)
|
122
|
+
@file.puts "#### Headers"
|
123
|
+
@file.puts
|
124
|
+
parameters_table(headers)
|
109
125
|
end
|
110
|
-
@file.puts
|
111
126
|
end
|
112
127
|
end
|
113
128
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-document_requests
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oded Niv
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec-rails
|