From 5f4541bf69ee50ce318878462d93324e77932c6f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 27 Jan 2016 16:55:04 +0000 Subject: [PATCH] Collapse Maven and Gradle setup into one section with switchable examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds an Asciidoctor extension that post-processes code blocks, collapsing any secondary blocks into the preceding primary block. The primary block is then augmented with a switch. This switch contains one item for each block. Clicking an item causes the associated block’s content to be displayed. Each item is named using its block’s title. The getting started instructions have been updated to take advantage of this new switching support, with the Maven and Gradle instructions being collapsed into a single section. Closes gh-189 --- buildSrc/build.gradle | 7 + .../CodeBlockSwitchExtension.groovy | 28 ++++ .../CodeBlockSwitchPostProcessor.groovy | 39 +++++ ...sciidoctor.extension.spi.ExtensionRegistry | 1 + .../src/main/resources/codeBlockSwitch.css | 23 +++ .../src/main/resources/codeBlockSwitch.js | 45 ++++++ docs/src/docs/asciidoc/getting-started.adoc | 152 ++++++++---------- 7 files changed, 210 insertions(+), 85 deletions(-) create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/src/main/groovy/org/springframework/restdocs/asciidoctor/CodeBlockSwitchExtension.groovy create mode 100644 buildSrc/src/main/groovy/org/springframework/restdocs/asciidoctor/CodeBlockSwitchPostProcessor.groovy create mode 100644 buildSrc/src/main/resources/META-INF/services/org.asciidoctor.extension.spi.ExtensionRegistry create mode 100644 buildSrc/src/main/resources/codeBlockSwitch.css create mode 100644 buildSrc/src/main/resources/codeBlockSwitch.js diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 00000000..ec63ab98 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,7 @@ +repositories { + mavenCentral() +} + +dependencies { + compile 'org.asciidoctor:asciidoctorj:1.5.2' +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/springframework/restdocs/asciidoctor/CodeBlockSwitchExtension.groovy b/buildSrc/src/main/groovy/org/springframework/restdocs/asciidoctor/CodeBlockSwitchExtension.groovy new file mode 100644 index 00000000..2dbd0364 --- /dev/null +++ b/buildSrc/src/main/groovy/org/springframework/restdocs/asciidoctor/CodeBlockSwitchExtension.groovy @@ -0,0 +1,28 @@ +/* + * Copyright 2014-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.restdocs.asciidoctor + +import org.asciidoctor.Asciidoctor +import org.asciidoctor.extension.spi.ExtensionRegistry + +class CodeBlockSwitchExtension implements ExtensionRegistry { + + @Override + public void register(Asciidoctor asciidoctor) { + asciidoctor.javaExtensionRegistry().postprocessor(new CodeBlockSwitchPostProcessor()); + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/springframework/restdocs/asciidoctor/CodeBlockSwitchPostProcessor.groovy b/buildSrc/src/main/groovy/org/springframework/restdocs/asciidoctor/CodeBlockSwitchPostProcessor.groovy new file mode 100644 index 00000000..e87edf96 --- /dev/null +++ b/buildSrc/src/main/groovy/org/springframework/restdocs/asciidoctor/CodeBlockSwitchPostProcessor.groovy @@ -0,0 +1,39 @@ +/* + * Copyright 2014-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.restdocs.asciidoctor + +import org.asciidoctor.ast.Document +import org.asciidoctor.extension.Postprocessor + +class CodeBlockSwitchPostProcessor extends Postprocessor { + + String process(Document document, String output) { + def css = getClass().getResource("/codeBlockSwitch.css").text + def javascript = getClass().getResource("/codeBlockSwitch.js").text + def replacement = """ + + + +""" + return output.replace("", replacement); + } + +} \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/services/org.asciidoctor.extension.spi.ExtensionRegistry b/buildSrc/src/main/resources/META-INF/services/org.asciidoctor.extension.spi.ExtensionRegistry new file mode 100644 index 00000000..2dcc8a1d --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/services/org.asciidoctor.extension.spi.ExtensionRegistry @@ -0,0 +1 @@ +org.springframework.restdocs.asciidoctor.CodeBlockSwitchExtension \ No newline at end of file diff --git a/buildSrc/src/main/resources/codeBlockSwitch.css b/buildSrc/src/main/resources/codeBlockSwitch.css new file mode 100644 index 00000000..6fb1947b --- /dev/null +++ b/buildSrc/src/main/resources/codeBlockSwitch.css @@ -0,0 +1,23 @@ +.hidden { + display: none; +} + +.switch { + border-width: 1px 1px 0 1px; + border-style: solid; + border-color: #7a2518; + display: inline-block; +} + +.switch--item { + padding: 10px; + background-color: #ffffff; + color: #7a2518; + display: inline-block; + cursor: pointer; +} + +.switch--item.selected { + background-color: #7a2519; + color: #ffffff; +} \ No newline at end of file diff --git a/buildSrc/src/main/resources/codeBlockSwitch.js b/buildSrc/src/main/resources/codeBlockSwitch.js new file mode 100644 index 00000000..13ac0fc1 --- /dev/null +++ b/buildSrc/src/main/resources/codeBlockSwitch.js @@ -0,0 +1,45 @@ +function addBlockSwitches() { + $('.primary').each(function() { + primary = $(this); + createSwitchItem(primary, createBlockSwitch(primary)).item.addClass("selected"); + primary.children('.title').remove(); + }); + $('.secondary').each(function(idx, node) { + secondary = $(node); + primary = findPrimary(secondary); + switchItem = createSwitchItem(secondary, primary.children('.switch')); + switchItem.content.addClass('hidden'); + findPrimary(secondary).append(switchItem.content); + secondary.remove(); + }); +} + +function createBlockSwitch(primary) { + blockSwitch = $('
'); + primary.prepend(blockSwitch); + return blockSwitch; +} + +function findPrimary(secondary) { + candidate = secondary.prev(); + while (!candidate.is('.primary')) { + candidate = candidate.prev(); + } + return candidate; +} + +function createSwitchItem(block, blockSwitch) { + blockName = block.children('.title').text(); + content = block.children('.content').first().append(block.next('.colist')); + item = $('
' + blockName + '
'); + item.on('click', '', content, function(e) { + $(this).addClass('selected'); + $(this).siblings().removeClass('selected'); + e.data.siblings('.content').addClass('hidden'); + e.data.removeClass('hidden'); + }); + blockSwitch.append(item); + return {'item': item, 'content': content}; +} + +$(addBlockSwitches); \ No newline at end of file diff --git a/docs/src/docs/asciidoc/getting-started.adoc b/docs/src/docs/asciidoc/getting-started.adoc index 6a652de6..ccc0f7a5 100644 --- a/docs/src/docs/asciidoc/getting-started.adoc +++ b/docs/src/docs/asciidoc/getting-started.adoc @@ -28,82 +28,14 @@ The code that produces the generated snippets can be found in `src/test/java`. [[getting-started-build-configuration]] === Build configuration -The first step in using Spring REST Docs is to configure your project's build. +The first step in using Spring REST Docs is to configure your project's build. The +{samples}/rest-notes-spring-hateoas[Spring HATEOAS] and +{samples}/rest-notes-spring-data-rest[Spring Data REST] samples contain a `build.gradle` +and `pom.xml` respectively that you may wish to use as a reference. The key parts of +the configuration are described below. - - -[[getting-started-build-configuration-gradle]] -==== Gradle build configuration - -The {samples}/rest-notes-spring-hateoas[Spring HATEOAS sample] contains a `build.gradle` -file that you may wish to use as a reference. The key parts of the configuration are -described below. - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - plugins { <1> - id "org.asciidoctor.convert" version "1.5.2" - } - - dependencies { <2> - testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc:{project-version}' - } - - ext { <3> - snippetsDir = file('build/generated-snippets') - } - - test { <4> - outputs.dir snippetsDir - } - - asciidoctor { <5> - attributes 'snippets': snippetsDir <6> - inputs.dir snippetsDir <7> - dependsOn test <8> - } ----- -<1> Apply the Asciidoctor plugin. -<2> Add a dependency on `spring-restdocs-mockmvc` in the `testCompile` configuration. -<3> Configure a property to define the output location for generated snippets. -<4> Configure the `test` task to add the snippets directory as an output. -<5> Configure the `asciidoctor` task -<6> Define an attribute named `snippets` that can be used when including the generated - snippets in your documentation. -<7> Configure the snippets directory as an input. -<8> Make the task depend on the test task so that the tests are run before the - documentation is created. - - -[[getting-started-build-configuration-gradle-packaging-the-documentation]] -==== Packaging the documentation - -You may want to package the generated documentation in your project's jar file, for -example to have it {spring-boot-docs}/#boot-features-spring-mvc-static-content[served as -static content] by Spring Boot. You can do so by configuring the `jar` task to depend on -the `asciidoctor` task and to copy the generated documentation into the jar's static -directory: - -[source,groovy,indent=0] ----- - jar { - dependsOn asciidoctor - from ("${asciidoctor.outputDir}/html5") { - into 'static/docs' - } - } ----- - - - -[[getting-started-build-configuration-maven]] -==== Maven build configuration - -The {samples}/rest-notes-spring-data-rest[Spring Data REST sample] contains a `pom.xml` -file that you may wish to use as a reference. The key parts of the configuration are -described below. - -[source,xml,indent=0,subs="verbatim,attributes"] +[source,xml,indent=0,subs="verbatim,attributes",role="primary"] +.Maven ---- <1> org.springframework.restdocs @@ -150,7 +82,6 @@ described below. - ---- <1> Add a dependency on `spring-restdocs-mockmvc` in the `test` scope. <2> Configure a property to define the output location for generated snippets. @@ -163,19 +94,55 @@ described below. <> in your project's jar you should use the `prepare-package` phase. -[[getting-started-build-configuration-maven-packaging]] +[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] +.Gradle +---- + plugins { <1> + id "org.asciidoctor.convert" version "1.5.2" + } + + dependencies { <2> + testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc:{project-version}' + } + + ext { <3> + snippetsDir = file('build/generated-snippets') + } + + test { <4> + outputs.dir snippetsDir + } + + asciidoctor { <5> + attributes 'snippets': snippetsDir <6> + inputs.dir snippetsDir <7> + dependsOn test <8> + } +---- +<1> Apply the Asciidoctor plugin. +<2> Add a dependency on `spring-restdocs-mockmvc` in the `testCompile` configuration. +<3> Configure a property to define the output location for generated snippets. +<4> Configure the `test` task to add the snippets directory as an output. +<5> Configure the `asciidoctor` task +<6> Define an attribute named `snippets` that can be used when including the generated + snippets in your documentation. +<7> Configure the snippets directory as an input. +<8> Make the task depend on the test task so that the tests are run before the + documentation is created. + + +[[getting-started-build-configuration-gradle-packaging-the-documentation]] ==== Packaging the documentation You may want to package the generated documentation in your project's jar file, for example to have it {spring-boot-docs}/#boot-features-spring-mvc-static-content[served as -static content] by Spring Boot. +static content] by Spring Boot. To do so, configure your project's build so that: -First, configure the Asciidoctor plugin so that it runs in the `prepare-package` phase, as -<>. Now configure -Maven's resources plugin to copy the generated documentation into a location where it'll -be included in the project's jar: +1. The documentation is generated before the jar is built +2. The generated documentation is included in the jar -[source,xml,indent=0] +[source,xml,indent=0,role="primary",role="primary"] +.Maven ---- <1> org.asciidoctor @@ -192,7 +159,7 @@ be included in the project's jar: copy-resources - + <3> ${project.build.outputDirectory}/static/docs @@ -211,7 +178,22 @@ be included in the project's jar: <1> The existing declaration for the Asciidoctor plugin. <2> The resource plugin must be declared after the Asciidoctor plugin as they are bound to the same phase (`prepare-package`) and the resource plugin must run after the -Asciidoctor plugin. +Asciidoctor plugin to ensure that the documentation is generated before it's copied. +<3> Copy the generated documentation into the build output's `static/docs` directory, +from where it will be included in the jar file. + +[source,groovy,indent=0,role="secondary"] +.Gradle +---- + jar { + dependsOn asciidoctor <1> + from ("${asciidoctor.outputDir}/html5") { <2> + into 'static/docs' + } + } +---- +<1> Ensure that the documentation has been generated before the jar is built. +<2> Copy the generated documentation into the jar's `static/docs` directory.