mirror of
https://gitee.com/dcren/initializr.git
synced 2025-04-05 17:38:06 +08:00
Add writer with indent support
This commit adds an `IndentingWriter` with a factory that supports different indenting option according to a content identifier (e.g. a language). Closes gh-812 Co-authored-by: Andy Wilkinson <awilkinson@pivotal.io>
This commit is contained in:
parent
3fa03b8438
commit
b6e675de40
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.generator.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A {@link Writer} with support for indenting.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class IndentingWriter extends Writer {
|
||||
|
||||
private final Writer out;
|
||||
|
||||
private final Function<Integer, String> indentStrategy;
|
||||
|
||||
private int level = 0;
|
||||
|
||||
private String indent = "";
|
||||
|
||||
private boolean prependIndent = false;
|
||||
|
||||
public IndentingWriter(Writer out) {
|
||||
this(out, new SimpleIndentStrategy(" "));
|
||||
}
|
||||
|
||||
public IndentingWriter(Writer out, Function<Integer, String> indentStrategy) {
|
||||
this.out = out;
|
||||
this.indentStrategy = indentStrategy;
|
||||
}
|
||||
|
||||
public void print(String string) {
|
||||
write(string.toCharArray(), 0, string.length());
|
||||
}
|
||||
|
||||
public void println(String string) {
|
||||
write(string.toCharArray(), 0, string.length());
|
||||
println();
|
||||
}
|
||||
|
||||
public void println() {
|
||||
String separator = System.lineSeparator();
|
||||
try {
|
||||
this.out.write(separator.toCharArray(), 0, separator.length());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
this.prependIndent = true;
|
||||
}
|
||||
|
||||
public void indented(Runnable runnable) {
|
||||
indent();
|
||||
runnable.run();
|
||||
outdent();
|
||||
}
|
||||
|
||||
private void indent() {
|
||||
this.level++;
|
||||
refreshIndent();
|
||||
}
|
||||
|
||||
private void outdent() {
|
||||
this.level--;
|
||||
refreshIndent();
|
||||
}
|
||||
|
||||
private void refreshIndent() {
|
||||
this.indent = this.indentStrategy.apply(this.level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] chars, int offset, int length) {
|
||||
try {
|
||||
if (this.prependIndent) {
|
||||
this.out.write(this.indent.toCharArray(), 0, this.indent.length());
|
||||
this.prependIndent = false;
|
||||
}
|
||||
this.out.write(chars, offset, length);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
this.out.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.out.close();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.generator.io;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A factory for {@link IndentingWriter} that provides customizations according to the
|
||||
* chosen content.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @see SimpleIndentStrategy
|
||||
*/
|
||||
public final class IndentingWriterFactory {
|
||||
|
||||
private final Function<Integer, String> defaultIndentingStrategy;
|
||||
|
||||
private final Map<String, Function<Integer, String>> indentingStrategies;
|
||||
|
||||
private IndentingWriterFactory(Builder builder) {
|
||||
this.defaultIndentingStrategy = builder.defaultIndentingStrategy;
|
||||
this.indentingStrategies = new HashMap<>(builder.indentingStrategies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link IndentingWriter} for the specified content and output.
|
||||
* @param contentId the identifier of the content
|
||||
* @param out the output to use
|
||||
* @return a configured {@link IndentingWriter}
|
||||
*/
|
||||
public IndentingWriter createIndentingWriter(String contentId, Writer out) {
|
||||
Function<Integer, String> indentingStrategy = this.indentingStrategies
|
||||
.getOrDefault(contentId, this.defaultIndentingStrategy);
|
||||
return new IndentingWriter(out, indentingStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link IndentingWriterFactory} with default settings.
|
||||
* @return an {@link IndentingWriterFactory} with default settings
|
||||
*/
|
||||
public static IndentingWriterFactory withDefaultSettings() {
|
||||
return create(new SimpleIndentStrategy(" "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link IndentingWriterFactory} with a single indenting strategy.
|
||||
* @param defaultIndentingStrategy the default indenting strategy to use
|
||||
* @return an {@link IndentingWriterFactory}
|
||||
*/
|
||||
public static IndentingWriterFactory create(
|
||||
Function<Integer, String> defaultIndentingStrategy) {
|
||||
return new IndentingWriterFactory(new Builder(defaultIndentingStrategy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link IndentingWriterFactory}.
|
||||
* @param defaultIndentingStrategy the default indenting strategy to use
|
||||
* @param factory a consumer of the builder to apply further customizations
|
||||
* @return an {@link IndentingWriterFactory}
|
||||
*/
|
||||
public static IndentingWriterFactory create(
|
||||
Function<Integer, String> defaultIndentingStrategy,
|
||||
Consumer<Builder> factory) {
|
||||
Builder factoryBuilder = new Builder(defaultIndentingStrategy);
|
||||
factory.accept(factoryBuilder);
|
||||
return new IndentingWriterFactory(factoryBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings customizer for {@link IndentingWriterFactory}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
|
||||
private final Function<Integer, String> defaultIndentingStrategy;
|
||||
|
||||
private final Map<String, Function<Integer, String>> indentingStrategies = new HashMap<>();
|
||||
|
||||
private Builder(Function<Integer, String> defaultIndentingStrategy) {
|
||||
this.defaultIndentingStrategy = defaultIndentingStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an indenting strategy for the specified content.
|
||||
* @param contentId the identifier of the content to configure
|
||||
* @param indentingStrategy the indent strategy for that particular content
|
||||
* @return this builder
|
||||
* @see #createIndentingWriter(String, Writer)
|
||||
*/
|
||||
public Builder indentingStrategy(String contentId,
|
||||
Function<Integer, String> indentingStrategy) {
|
||||
this.indentingStrategies.put(contentId, indentingStrategy);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.generator.io;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A simple indenting strategy that uses a configurable {@code indent} value.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class SimpleIndentStrategy implements Function<Integer, String> {
|
||||
|
||||
private final String indent;
|
||||
|
||||
/**
|
||||
* Create a new instance with the indent style to apply.
|
||||
* @param indent the indent to apply for a single level
|
||||
*/
|
||||
public SimpleIndentStrategy(String indent) {
|
||||
Assert.notNull(indent, "Indent must be provided");
|
||||
this.indent = indent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(Integer level) {
|
||||
if (level < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Indent level must not be negative, got" + level);
|
||||
}
|
||||
StringBuilder indentBuilder = new StringBuilder();
|
||||
for (int i = 0; i < level; i++) {
|
||||
indentBuilder.append(this.indent);
|
||||
}
|
||||
return indentBuilder.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for writing project assets.
|
||||
*/
|
||||
package io.spring.initializr.generator.io;
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.generator.io;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link IndentingWriterFactory}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class IndentingWriterFactoryTests {
|
||||
|
||||
private static final SimpleIndentStrategy SPACE_STRATEGY = new SimpleIndentStrategy(
|
||||
" ");
|
||||
|
||||
private static final SimpleIndentStrategy TAB_STRATEGY = new SimpleIndentStrategy(
|
||||
"\t");
|
||||
|
||||
private final StringWriter out = new StringWriter();
|
||||
|
||||
@Test
|
||||
void createWithSingleIndentStrategy() {
|
||||
IndentingWriter writer = IndentingWriterFactory.create((SPACE_STRATEGY))
|
||||
.createIndentingWriter("test", this.out);
|
||||
assertThat(writer).hasFieldOrPropertyWithValue("indentStrategy", SPACE_STRATEGY);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithSpecializedIndentStrategy() {
|
||||
SimpleIndentStrategy twoSpacesStrategy = new SimpleIndentStrategy(" ");
|
||||
IndentingWriterFactory indentingWriterFactory = IndentingWriterFactory
|
||||
.create(SPACE_STRATEGY, (factory) -> {
|
||||
factory.indentingStrategy("java", TAB_STRATEGY);
|
||||
factory.indentingStrategy("pom", twoSpacesStrategy);
|
||||
});
|
||||
assertThat(indentingWriterFactory.createIndentingWriter("java", this.out))
|
||||
.hasFieldOrPropertyWithValue("indentStrategy", TAB_STRATEGY);
|
||||
assertThat(indentingWriterFactory.createIndentingWriter("pom", this.out))
|
||||
.hasFieldOrPropertyWithValue("indentStrategy", twoSpacesStrategy);
|
||||
assertThat(indentingWriterFactory.createIndentingWriter("c", this.out))
|
||||
.hasFieldOrPropertyWithValue("indentStrategy", SPACE_STRATEGY);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.generator.io;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link IndentingWriter}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class IndentingWriterTests {
|
||||
|
||||
private final StringWriter stringWriter = new StringWriter();
|
||||
|
||||
private final IndentingWriter indentingWriter = new IndentingWriter(
|
||||
this.stringWriter);
|
||||
|
||||
@Test
|
||||
void linesAreNotIndentedByDefault() {
|
||||
this.indentingWriter.println("a");
|
||||
this.indentingWriter.println("b");
|
||||
this.indentingWriter.println("c");
|
||||
assertThat(this.stringWriter.toString()).isEqualTo("a\nb\nc\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void linesCanBeIndented() {
|
||||
this.indentingWriter.println("a");
|
||||
this.indentingWriter.indented(() -> this.indentingWriter.println("b"));
|
||||
this.indentingWriter.println("c");
|
||||
assertThat(this.stringWriter.toString()).isEqualTo("a\n b\nc\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void blankLinesAreNotIndented() {
|
||||
this.indentingWriter.println("a");
|
||||
this.indentingWriter.indented(() -> {
|
||||
this.indentingWriter.println("b");
|
||||
this.indentingWriter.println();
|
||||
});
|
||||
this.indentingWriter.println("c");
|
||||
assertThat(this.stringWriter.toString()).isEqualTo("a\n b\n\nc\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void useOfPrintDoesNotAddIndent() {
|
||||
this.indentingWriter.println("a");
|
||||
this.indentingWriter.indented(() -> {
|
||||
this.indentingWriter.print("b");
|
||||
this.indentingWriter.print("b");
|
||||
this.indentingWriter.println("b");
|
||||
});
|
||||
this.indentingWriter.println("c");
|
||||
assertThat(this.stringWriter.toString()).isEqualTo("a\n bbb\nc\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customIndentStrategyIsUsed() {
|
||||
IndentingWriter customIndentingWriter = new IndentingWriter(this.stringWriter,
|
||||
new SimpleIndentStrategy("\t"));
|
||||
customIndentingWriter.println("a");
|
||||
customIndentingWriter.indented(() -> {
|
||||
customIndentingWriter.println("b");
|
||||
customIndentingWriter.indented(() -> {
|
||||
customIndentingWriter.print("c");
|
||||
customIndentingWriter.println("e");
|
||||
});
|
||||
});
|
||||
assertThat(this.stringWriter.toString()).isEqualTo("a\n\tb\n\t\tce\n");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.generator.io;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link SimpleIndentStrategy}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class SimpleIndentStrategyTests {
|
||||
|
||||
@Test
|
||||
void noLevelIsAllowed() {
|
||||
assertThat(new SimpleIndentStrategy(" ").apply(0)).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleLevelIndentSpace() {
|
||||
assertThat(new SimpleIndentStrategy(" ").apply(1)).isEqualTo(" ");
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleLevelIndentTab() {
|
||||
assertThat(new SimpleIndentStrategy("\t").apply(1)).isEqualTo("\t");
|
||||
}
|
||||
|
||||
@Test
|
||||
void multiLevelIndentSpace() {
|
||||
assertThat(new SimpleIndentStrategy(" ").apply(3)).isEqualTo(" ");
|
||||
}
|
||||
|
||||
@Test
|
||||
void multiLevelIndentTab() {
|
||||
assertThat(new SimpleIndentStrategy("\t").apply(3)).isEqualTo("\t\t\t");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mustHaveIndent() {
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> new SimpleIndentStrategy(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indentLevelMustNotBeNegative() {
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> new SimpleIndentStrategy(" ").apply(-1))
|
||||
.withMessageContaining("Indent level must not be negative")
|
||||
.withMessageContaining("-1");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user