Skip to content

Commit a4d2fc3

Browse files
committed
Allow snippet section titles to be customized using document attributes
Closes gh-363
1 parent 86f6dba commit a4d2fc3

File tree

9 files changed

+159
-43
lines changed

9 files changed

+159
-43
lines changed

docs/src/docs/asciidoc/working-with-asciidoctor.adoc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,58 @@ operation::index[]
4545

4646

4747

48+
[[working-with-asciidoctor-including-snippets-operation-titles]]
49+
===== Section titles
50+
51+
For each snippet that's including using `operation` a section with a title will be
52+
created. Default titles are provided for the built-in snippets:
53+
54+
|===
55+
| Snippet | Title
56+
57+
| curl-request
58+
| Curl Request
59+
60+
| http-request
61+
| HTTP request
62+
63+
| http-response
64+
| HTTP response
65+
66+
| httpie-request
67+
| HTTPie request
68+
69+
| links
70+
| Links
71+
72+
| request-body
73+
| Request body
74+
75+
| request-fields
76+
| Request fields
77+
78+
| response-body
79+
| Response body
80+
81+
| response-fields
82+
| Response fields
83+
|===
84+
85+
For snippets not listed in the table above, a default title will be generated by replacing
86+
`-` characters with spaces and capitalising the first letter. For example, the title for a
87+
snippet named `custom-snippet` will be "Custom snippet".
88+
89+
The default titles can be customized using document attributes. The name of the attribute
90+
should be `operation-{snippet}-title`. For example, to customize the title of the
91+
`curl-request` snippet to be "Example request", use the following attribute:
92+
93+
[source,indent=0]
94+
----
95+
:operation-curl-request-title: Example request
96+
----
97+
98+
99+
48100
[[working-with-asciidoctor-including-snippets-individual]]
49101
==== Including individual snippets
50102

spring-restdocs-asciidoctor/src/main/resources/extensions/operation_block_macro.rb

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,32 @@ class OperationBlockMacro < Asciidoctor::Extensions::BlockMacroProcessor
1515
def process(parent, operation, attributes)
1616
snippets_dir = parent.document.attributes['snippets'].to_s
1717
snippet_names = attributes.fetch 'snippets', ''
18-
content = read_snippets(snippets_dir, snippet_names, parent, operation)
18+
snippet_titles = SnippetTitles.new parent.document.attributes
19+
content = read_snippets(snippets_dir, snippet_names, parent, operation,
20+
snippet_titles)
1921
add_blocks(content, parent.document, parent) unless content.empty?
2022
nil
2123
end
2224

23-
def read_snippets(snippets_dir, snippet_names, parent, operation)
25+
def read_snippets(snippets_dir, snippet_names, parent, operation,
26+
snippet_titles)
2427
snippets = snippets_to_include(snippet_names, snippets_dir, operation)
2528
if snippets.empty?
2629
warn "No snippets were found for operation #{operation} in"\
2730
"#{snippets_dir}"
2831
"No snippets found for operation::#{operation}"
2932
else
30-
do_read_snippets(snippets, parent, operation)
33+
do_read_snippets(snippets, parent, operation, snippet_titles)
3134
end
3235
end
3336

34-
def do_read_snippets(snippets, parent, operation)
37+
def do_read_snippets(snippets, parent, operation, snippet_titles)
3538
content = StringIO.new
3639
section_level = parent.level + 1
3740
section_id = parent.id
3841
snippets.each do |snippet|
3942
append_snippet_block(content, snippet, section_level, section_id,
40-
operation)
43+
operation, snippet_titles)
4144
end
4245
content.string
4346
end
@@ -59,7 +62,7 @@ def snippets_to_include(snippet_names, snippets_dir, operation)
5962
else
6063
snippet_names.split(',').map do |name|
6164
path = File.join snippets_dir, operation, "#{name}.adoc"
62-
Snippet.new(path, name)
65+
Snippet.new path, name
6366
end
6467
end
6568
end
@@ -74,8 +77,8 @@ def all_snippets(snippets_dir, operation)
7477
end
7578

7679
def append_snippet_block(content, snippet, section_level, section_id,
77-
operation)
78-
write_title content, snippet, section_level, section_id
80+
operation, snippet_titles)
81+
write_title content, snippet, section_level, section_id, snippet_titles
7982
write_content content, snippet, operation
8083
end
8184

@@ -91,38 +94,49 @@ def write_content(content, snippet, operation)
9194
end
9295
end
9396

94-
def write_title(content, snippet, level, id)
97+
def write_title(content, snippet, level, id, snippet_titles)
9598
section_level = '=' * (level + 1)
99+
title = snippet_titles.title_for_snippet snippet
96100
content.puts "[[#{id}_#{snippet.name.sub '-', '_'}]]"
97-
content.puts "#{section_level} #{snippet.title}"
101+
content.puts "#{section_level} #{title}"
98102
content.puts ''
99103
end
100104

101105
# Details of a snippet to be rendered
102106
class Snippet
103-
@titles = { 'http-request' => 'HTTP request',
104-
'curl-request' => 'Curl request',
105-
'httpie-request' => 'HTTPie request',
106-
'request-body' => 'Request body',
107-
'request-fields' => 'Request fields',
108-
'http-response' => 'HTTP response',
109-
'response-body' => 'Response body',
110-
'response-fields' => 'Response fields',
111-
'links' => 'Links' }
112-
113-
class << self
114-
attr_reader :titles
115-
end
116-
117107
attr_reader :name, :path
118108

119109
def initialize(path, name)
120110
@path = path
121111
@name = name
112+
@snippet_titles
113+
end
114+
end
115+
116+
class SnippetTitles
117+
@defaults = { 'http-request' => 'HTTP request',
118+
'curl-request' => 'Curl request',
119+
'httpie-request' => 'HTTPie request',
120+
'request-body' => 'Request body',
121+
'request-fields' => 'Request fields',
122+
'http-response' => 'HTTP response',
123+
'response-body' => 'Response body',
124+
'response-fields' => 'Response fields',
125+
'links' => 'Links' }
126+
127+
class << self
128+
attr_reader :defaults
122129
end
123130

124-
def title
125-
Snippet.titles.fetch @name, name.sub('-', ' ').capitalize
131+
def initialize(document_attributes)
132+
@document_attributes = document_attributes
133+
end
134+
135+
def title_for_snippet(snippet)
136+
attribute_name = "operation-#{snippet.name}-title"
137+
@document_attributes.fetch attribute_name do
138+
SnippetTitles.defaults.fetch snippet.name, snippet.name.sub('-', ' ').capitalize
139+
end
126140
end
127141
end
128142
end

spring-restdocs-asciidoctor/src/test/java/org/springframework/restdocs/asciidoctor/OperationBlockMacroTests.java

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232

3333
import org.springframework.util.FileSystemUtils;
3434

35-
import static org.hamcrest.CoreMatchers.containsString;
3635
import static org.hamcrest.CoreMatchers.equalTo;
3736
import static org.hamcrest.CoreMatchers.startsWith;
3837
import static org.junit.Assert.assertThat;
@@ -62,12 +61,6 @@ public void setUp() {
6261
this.options.setAttributes(getAttributes());
6362
}
6463

65-
private Attributes getAttributes() {
66-
Attributes attributes = new Attributes();
67-
attributes.setAttribute("projectdir", new File(".").getAbsolutePath());
68-
return attributes;
69-
}
70-
7164
@Test
7265
public void simpleSnippetInclude() throws Exception {
7366
String result = this.asciidoctor.convert(
@@ -106,27 +99,49 @@ public void useMacroWithEmptySnippetAttributeAddsAllSnippets() throws Exception
10699
}
107100

108101
@Test
109-
public void includingUnknownSnippetAddsWarning() throws Exception {
102+
public void includingMissingSnippetAddsWarning() throws Exception {
110103
String result = this.asciidoctor.convert(
111-
"operation::some-operation[snippets='unknown-snippet']", this.options);
104+
"operation::some-operation[snippets='missing-snippet']", this.options);
112105
assertThat(result, startsWith(getExpectedContentFromFile("missing-snippet")));
113106
}
114107

115108
@Test
116-
public void includingCustomSnippetCreatesCustomTitle() throws Exception {
109+
public void defaultTitleIsProvidedForCustomSnippet() throws Exception {
117110
String result = this.asciidoctor.convert(
118111
"operation::some-operation[snippets='custom-snippet']", this.options);
119112
assertThat(result,
120-
containsString(getExpectedContentFromFile("snippet-custom-title")));
113+
equalTo(getExpectedContentFromFile("custom-snippet-default-title")));
121114
}
122115

123116
@Test
124-
public void nonExistentOperationIsHandledGracefully() throws Exception {
125-
String result = this.asciidoctor.convert("operation::non-existent-operation[]",
117+
public void missingOperationIsHandledGracefully() throws Exception {
118+
String result = this.asciidoctor.convert("operation::missing-operation[]",
126119
this.options);
127120
assertThat(result, startsWith(getExpectedContentFromFile("missing-operation")));
128121
}
129122

123+
@Test
124+
public void titleOfBuiltInSnippetCanBeCustomizedUsingDocumentAttribute()
125+
throws URISyntaxException, IOException {
126+
String result = this.asciidoctor.convert(
127+
":operation-curl-request-title: Example request\n"
128+
+ "operation::some-operation[snippets='curl-request']",
129+
this.options);
130+
assertThat(result,
131+
equalTo(getExpectedContentFromFile("built-in-snippet-custom-title")));
132+
}
133+
134+
@Test
135+
public void titleOfCustomSnippetCanBeCustomizedUsingDocumentAttribute()
136+
throws Exception {
137+
String result = this.asciidoctor.convert(
138+
":operation-custom-snippet-title: Customized title\n"
139+
+ "operation::some-operation[snippets='custom-snippet']",
140+
this.options);
141+
assertThat(result,
142+
equalTo(getExpectedContentFromFile("custom-snippet-custom-title")));
143+
}
144+
130145
private String getExpectedContentFromFile(String fileName)
131146
throws URISyntaxException, IOException {
132147
Path filePath = Paths.get(
@@ -142,4 +157,10 @@ private boolean isWindows() {
142157
return File.separatorChar == '\\';
143158
}
144159

160+
private Attributes getAttributes() {
161+
Attributes attributes = new Attributes();
162+
attributes.setAttribute("projectdir", new File(".").getAbsolutePath());
163+
return attributes;
164+
}
165+
145166
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div class="sect1">
2+
<h2 id="_curl_request">Example request</h2>
3+
<div class="sectionbody">
4+
<div class="listingblock">
5+
<div class="content">
6+
<pre class="highlight"><code class="language-bash" data-lang="bash">$ curl 'http://localhost:8080/' -i</code></pre>
7+
</div>
8+
</div>
9+
</div>
10+
</div>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div class="sect1">
2+
<h2 id="_custom_snippet">Customized title</h2>
3+
<div class="sectionbody">
4+
<div class="listingblock">
5+
<div class="content">
6+
<pre class="highlight nowrap"><code class="language-http" data-lang="http">mycustomsnippet</code></pre>
7+
</div>
8+
</div>
9+
</div>
10+
</div>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div class="sect1">
2+
<h2 id="_custom_snippet">Custom snippet</h2>
3+
<div class="sectionbody">
4+
<div class="listingblock">
5+
<div class="content">
6+
<pre class="highlight nowrap"><code class="language-http" data-lang="http">mycustomsnippet</code></pre>
7+
</div>
8+
</div>
9+
</div>
10+
</div>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<div class="paragraph">
2-
<p>No snippets found for operation::non-existent-operation</p>
2+
<p>No snippets found for operation::missing-operation</p>
33
</div>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<div class="sect1">
2-
<h2 id="_unknown_snippet">Unknown snippet</h2>
2+
<h2 id="_missing_snippet">Missing snippet</h2>
33
<div class="sectionbody">
44
<div class="paragraph">
5-
<p>Snippet unknown-snippet not found for operation::some-operation</p>
5+
<p>Snippet missing-snippet not found for operation::some-operation</p>
66
</div>
77
</div>
88
</div>

spring-restdocs-asciidoctor/src/test/resources/operations/snippet-custom-title.html

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)