Skip to content

Commit

Permalink
[#50] Control whether fields can be quoted or not
Browse files Browse the repository at this point in the history
  • Loading branch information
fbiville committed Apr 2, 2017
1 parent 6195eda commit e4b4754
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 18 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ To make it work, you need to specify the following options (by passing `-A${CONF
- `GeneratedDocumentationPath`: mandatory - the folder path in which the files are going to be generated in. If not specified, the export won't be done.
- `Documentation.FieldDelimiter`: optional (default: ,) - the delimiter of values within a row
- `Documentation.DelimitedFirstField`: optional (default: false) - the first column of each row (headers included) is prefixed with the configured separator
- `Documentation.QuotedFields`: optional (default: true) - whether column values are quoted or not
- `Documentation.ExportGrouping`: optional (default: SINGLE) - comma-separated values of grouping strategy. The data is exported to a single place (SINGLE), to a single place per enclosing package (PACKAGE), to a single place per enclosing class (CLASS). For now, "place" may mean one or two files, depending on `Documentation.ExportSplit`.
- `Documentation.ExportSplit`: optional (default: NONE) - whether to split data by kind (KIND, e.g. procedure vs. function) or not (NONE).
- `Documentation.ExportedHeaders`: optional (default: *) - delimiter-separated values which define custom ordering and filtering of the available headers. They are separated by the configured delimiter (see `Documentation.FieldDelimiter`) and the first header must not be prefixed, even if `Documentation.DelimitedFirstField` is enabled. The available headers are (in default order):
- `Documentation.ExportedHeaders`: optional (default: *) - delimiter-separated values which define custom ordering and filtering of the available headers. They are not to be quoted (regardless of `Documentation.QuotedFields` setting), have to be separated by the configured delimiter (see `Documentation.FieldDelimiter`) and the first header must not be prefixed, even if `Documentation.DelimitedFirstField` is enabled. The available headers are (in default order):

- type: `'procedure'` or `'function'` for now
- name: procedure/function logical name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class DsvConfiguration
public static final String DOCUMENTATION_ROOT_PATH = "GeneratedDocumentationPath";
private static final String DOCUMENTATION_FIELD_DELIMITER = "Documentation.FieldDelimiter";
private static final String DOCUMENTATION_DELIMITED_FIRST_FIELD = "Documentation.DelimitedFirstField";
private static final String DOCUMENTATION_QUOTED_FIELDS = "Documentation.QuotedFields";
private static final String DOCUMENTATION_EXPORTED_HEADERS = "Documentation.ExportedHeaders";
private static final String DOCUMENTATION_EXPORT_GROUPING = "Documentation.ExportGrouping";
private static final String DOCUMENTATION_EXPORT_SPLIT = "Documentation.ExportSplit";
Expand All @@ -44,12 +45,14 @@ public class DsvConfiguration
private final EnumSet<DsvGroupingStrategy> groupingStrategy;
private final DsvSplitStrategy splitStrategy;
private final boolean delimitedFirstField;
private final boolean quotedFields;

public DsvConfiguration( Map<String,String> actualOptions )
{
rootPath = Optional.ofNullable( actualOptions.getOrDefault( DOCUMENTATION_ROOT_PATH, null ) ).map( Paths::get );
fieldDelimiter = actualOptions.getOrDefault( DOCUMENTATION_FIELD_DELIMITER, "," );
delimitedFirstField = parseBoolean(actualOptions.getOrDefault( DOCUMENTATION_DELIMITED_FIRST_FIELD, "false" ));
quotedFields = parseBoolean(actualOptions.getOrDefault( DOCUMENTATION_QUOTED_FIELDS, "true" ));
rawHeaders = actualOptions.getOrDefault( DOCUMENTATION_EXPORTED_HEADERS, "*" );
groupingStrategy = parseGroupingStrategy(
actualOptions.getOrDefault( DOCUMENTATION_EXPORT_GROUPING, "SINGLE" ).toUpperCase( Locale.ENGLISH ),
Expand All @@ -60,10 +63,11 @@ public DsvConfiguration( Map<String,String> actualOptions )

public static Set<String> getSupportedOptions()
{
Set<String> options = new HashSet<>( 6 );
Set<String> options = new HashSet<>( 7 );
options.add( DOCUMENTATION_ROOT_PATH );
options.add( DOCUMENTATION_EXPORTED_HEADERS );
options.add( DOCUMENTATION_FIELD_DELIMITER );
options.add( DOCUMENTATION_QUOTED_FIELDS );
options.add( DOCUMENTATION_DELIMITED_FIRST_FIELD );
options.add( DOCUMENTATION_EXPORT_GROUPING );
options.add( DOCUMENTATION_EXPORT_SPLIT );
Expand Down Expand Up @@ -91,6 +95,10 @@ public boolean isFirstFieldDelimited() {
return delimitedFirstField;
}

public boolean areFieldsQuoted() {
return quotedFields;
}

public String getRawHeaders()
{
return rawHeaders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,24 @@
import net.biville.florent.sproccompiler.UserFunctionProcessor;
import net.biville.florent.sproccompiler.export.Either;
import net.biville.florent.sproccompiler.export.messages.DsvExportError;
import org.neo4j.procedure.Description;
import org.neo4j.procedure.PerformsWrites;
import org.neo4j.procedure.Procedure;
import org.neo4j.procedure.UserFunction;

import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleTypeVisitor8;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleTypeVisitor8;

import org.neo4j.procedure.Description;
import org.neo4j.procedure.PerformsWrites;
import org.neo4j.procedure.Procedure;
import org.neo4j.procedure.UserFunction;

/**
* All possible DSV header values: this declaration order is the default one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,20 @@ public class DsvFileWriter implements AutoCloseable
private final Writer writer;
private final String separator;
private final boolean delimitFirstField;
private final boolean quoteFields;

public DsvFileWriter( Collection<String> header, Writer writer )
{
this( header, writer, "," , false);
this( header, writer, "," , false, true);
}

public DsvFileWriter( Collection<String> header, Writer writer, String separator, boolean delimitFirstField )
public DsvFileWriter( Collection<String> header, Writer writer, String separator, boolean delimitFirstField, boolean quoteFields )
{
this.header = header;
this.writer = writer;
this.separator = separator;
this.delimitFirstField = delimitFirstField;
this.quoteFields = quoteFields;
}

public <T> void write( Stream<T> records, Function<T,Stream<Either<DsvExportError,String>>> rowFunction,
Expand Down Expand Up @@ -77,7 +79,13 @@ public void close()

private String joinFields( Stream<String> fields )
{
String result = fields.map(field -> "\"" + field.replace("\"", "\"\"") + "\"").collect(joining(separator));
String result = fields.map(field -> {
if (quoteFields) {
return "\"" + field.replace("\"", "\"\"") + "\"";
}
return field;

}).collect(joining(separator));
if (delimitFirstField) {
return separator + result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ private void serializeWithHeaders( File file, DsvConfiguration configuration, Co
Collection<String> headers )
{
try ( FileWriter resource = new FileWriter( file );
DsvFileWriter writer = new DsvFileWriter( headers, resource, configuration.getFieldDelimiter(), configuration.isFirstFieldDelimited() ) )
DsvFileWriter writer = new DsvFileWriter( headers, resource, configuration.getFieldDelimiter(), configuration.isFirstFieldDelimited(), configuration.areFieldsQuoted() ) )
{
writer.write( methods.stream(), ( method ) -> fieldExporter.exportFields( method, headers ),
messagePrinter::print );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,29 @@ public void dumps_procedure_definition_to_dsv_with_custom_delimiter_and_package_
"|\"function\"|\"" + namespace + ".sum\"|\"long sum(int a,int b)\"|\"Performs super complex maths\"|\"\"|\"" + namespace + ".SimpleUserFunctions\"|\"\"");
}

@Test
public void dumps_procedure_definition_to_dsv_with_custom_delimiter_and_package_grouping_and_delimited_first_field_and_unquoted() throws IOException
{
Iterable<JavaFileObject> sources =
asList( JavaFileObjectUtils.INSTANCE.procedureSource( "valid/SimpleProcedures.java" ),
JavaFileObjectUtils.INSTANCE.procedureSource( "valid/SimpleUserFunctions.java" ) );

assert_().about( javaSources() ).that( sources )
.withCompilerOptions( "-AGeneratedDocumentationPath=" + folder.getAbsolutePath(),
"-ADocumentation.FieldDelimiter=|", "-ADocumentation.ExportGrouping=PACKAGE",
"-ADocumentation.DelimitedFirstField=true", "-ADocumentation.QuotedFields=false" )
.processedWith( processor ).compilesWithoutError();

String namespace = "net.biville.florent.sproccompiler.procedures.valid";
String generatedCsv = readContents(Paths.get(folder.getAbsolutePath(), namespace + ".csv"));
assertThat(generatedCsv).isEqualTo(
"|type|qualified name|signature|description|execution mode|location|deprecated by\n" +
"|procedure|" + namespace + ".doSomething|void doSomething(int foo)||PERFORMS_WRITE|" + namespace + ".SimpleProcedures|doSomething2\n" +
"|procedure|" + namespace + ".doSomething2|void doSomething2(long bar)|Much better than the former version|SCHEMA|" + namespace + ".SimpleProcedures|\n" +
"|procedure|" + namespace + ".doSomething3|void doSomething3(LongWrapper bar)|Much better with records|SCHEMA|" + namespace + ".SimpleProcedures|\n" +
"|function|" + namespace + ".sum|long sum(int a,int b)|Performs super complex maths||" + namespace + ".SimpleUserFunctions|");
}

@Test
public void dumps_only_exported_fields_with_default_delimiter_and_package_grouping() throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public void writes_csv_records_with_custom_separator_prefixing_first_field()
{
StringWriter writer = new StringWriter();
try ( DsvFileWriter dsvFileWriter = new DsvFileWriter( Arrays.asList( "first header", "second header" ),
writer, "$", true ) )
writer, "$", true, true ) )
{
dsvFileWriter.write( Stream.of( "haha_this is", "so much_fun" ), this::parseRow,
( error ) -> fail( "Unexpected export error: " + error ) );
Expand All @@ -59,6 +59,21 @@ public void writes_csv_records_with_custom_separator_prefixing_first_field()
}
}

@Test
public void writes_csv_records_with_custom_separator_prefixing_first_field_without_quoting_fields()
{
StringWriter writer = new StringWriter();
try ( DsvFileWriter dsvFileWriter = new DsvFileWriter( Arrays.asList( "first header", "second header" ),
writer, "$", true, false ) )
{
dsvFileWriter.write( Stream.of( "haha_this is", "so much_fun" ), this::parseRow,
( error ) -> fail( "Unexpected export error: " + error ) );
String result = writer.toString();
assertThat( result ).isEqualTo(
"$first header$second header\n" + "$haha$this is\n" + "$so much$fun\n" );
}
}

private Stream<Either<DsvExportError,String>> parseRow( String input )
{
return Arrays.stream( input.split( "_" ) ).map( Either::right );
Expand Down

0 comments on commit e4b4754

Please sign in to comment.