Skip to content

Commit

Permalink
Support pre- and post-parsing and formatting.
Browse files Browse the repository at this point in the history
  • Loading branch information
jehugaleahsa committed May 25, 2019
1 parent 7447d66 commit db0834f
Show file tree
Hide file tree
Showing 23 changed files with 237 additions and 65 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
## 4.4.0 (2019-05-25)
** Summary ** - Allow pre- and post- parsing and formatting on columns. Allow specifying a global `IFormatProvider` in `IOptions`.

### New Features
* The `IOptions` interface now has a `IFormatProvider FormatProvider` property. If provided, all columns will automatically use this `IFormatProvider` as their default.
* The `IFormatProvider` specified on a `IColumnDefinition` will override what is specified in `IOptions`.
* If no `IFormatProvider` is found at either level, FlatFiles defaults to `CultureInfo.CurrentInfo`, as before.
* The `IColumnDefinition` interface now exposes four new properties:
* OnParsing - Fires before attempting to parse the `string` value; the logical successor to `Preprocessor`.
* OnParsed - Fires after parsing the column, providing access to the parsed `object`.
* OnFormatting - Fires before formatting the column, providing access to the `object`.
* OnFormatted - Fires after formatting the column, providing access to the generated `string`.

Unlike `Preprocessor`, each of the new properties have the type `Func<IColumnContext, T, T>`, providing access to the column context.

### Deprecated
Since `Preprocessor` and `OnParsing` are effectively redundant, `Preprocessor` has been marked deprecated. Please upgrade any existing code to use `OnParsing` instead. The `Preprocessor` property will be removed in the next major release (a.k.a., v5.0).

## 4.3.4 (2019-03-10)
**Summary** - This release allows directly writing arbitrary text to the underlying `TextWriter`, for those who need it.

Expand Down
53 changes: 39 additions & 14 deletions FlatFiles.Test/ColumnContextTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ internal class Person

internal class IndexTrackingColumn : IColumnDefinition
{
private readonly IColumnDefinition columnDefinition;
private readonly IColumnDefinition column;
private readonly List<int> physicalIndexes;
private readonly List<int> logicalIndexes;

Expand All @@ -138,49 +138,74 @@ internal class IndexTrackingColumn : IColumnDefinition
List<int> physicalIndexes,
List<int> logicalIndexes)
{
this.columnDefinition = columnDefinition;
this.column = columnDefinition;
this.physicalIndexes = physicalIndexes;
this.logicalIndexes = logicalIndexes;
}

public string ColumnName => columnDefinition.ColumnName;
public string ColumnName => column.ColumnName;

public bool IsIgnored => columnDefinition.IsIgnored;
public bool IsIgnored => column.IsIgnored;

public bool IsNullable => columnDefinition.IsNullable;
public bool IsNullable => column.IsNullable;

public IDefaultValue DefaultValue
{
get => columnDefinition.DefaultValue;
set => columnDefinition.DefaultValue = value;
get => column.DefaultValue;
set => column.DefaultValue = value;
}

public INullFormatter NullFormatter
{
get => columnDefinition.NullFormatter;
set => columnDefinition.NullFormatter = value;
get => column.NullFormatter;
set => column.NullFormatter = value;
}

[Obsolete]
public Func<string, string> Preprocessor
{
get => columnDefinition.Preprocessor;
set => columnDefinition.Preprocessor = value;
get => column.Preprocessor;
set => column.Preprocessor = value;
}

public Type ColumnType => columnDefinition.ColumnType;
public Func<IColumnContext, string, string> OnParsing
{
get => column.OnParsing;
set => column.OnParsing = value;
}

public Func<IColumnContext, object, object> OnParsed
{
get => column.OnParsed;
set => column.OnParsed = value;
}

public Func<IColumnContext, object, object> OnFormatting
{
get => column.OnFormatting;
set => column.OnFormatting = value;
}

public Func<IColumnContext, string, string> OnFormatted
{
get => column.OnFormatted;
set => column.OnFormatted = value;
}

public Type ColumnType => column.ColumnType;

public string Format(IColumnContext context, object value)
{
physicalIndexes.Add(context.PhysicalIndex);
logicalIndexes.Add(context.LogicalIndex);
return columnDefinition.Format(context, value);
return column.Format(context, value);
}

public object Parse(IColumnContext context, string value)
{
physicalIndexes.Add(context.PhysicalIndex);
logicalIndexes.Add(context.LogicalIndex);
return columnDefinition.Parse(context, value);
return column.Parse(context, value);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions FlatFiles/ByteColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ public ByteColumn(string columnName)
/// <returns>The parsed byte value.</returns>
protected override byte OnParse(IColumnContext context, string value)
{
IFormatProvider provider = FormatProvider ?? CultureInfo.CurrentCulture;
return Byte.Parse(value, NumberStyles, provider);
return Byte.Parse(value, NumberStyles, GetFormatProvider(context, FormatProvider));
}

/// <summary>
Expand All @@ -52,11 +51,12 @@ protected override byte OnParse(IColumnContext context, string value)
/// <returns>The formatted value.</returns>
protected override string OnFormat(IColumnContext context, byte value)
{
var provider = GetFormatProvider(context, FormatProvider);
if (OutputFormat == null)
{
return value.ToString(FormatProvider ?? CultureInfo.CurrentCulture);
return value.ToString(provider);
}
return value.ToString(OutputFormat, FormatProvider ?? CultureInfo.CurrentCulture);
return value.ToString(OutputFormat, provider);
}
}
}
79 changes: 77 additions & 2 deletions FlatFiles/ColumnDefinition.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Globalization;
using FlatFiles.Properties;

namespace FlatFiles
Expand Down Expand Up @@ -36,8 +37,29 @@ public interface IColumnDefinition
/// <summary>
/// Gets or sets a function used to preprocess input before trying to parse it.
/// </summary>
[Obsolete("This property has been superseded by the OnParsing delegate.")]
Func<string, string> Preprocessor { get; set; }

/// <summary>
/// Gets or sets a function used to pre-process input before trying to parse it.
/// </summary>
Func<IColumnContext, string, string> OnParsing { get; set; }

/// <summary>
/// Gets or sets a function used to post-process input after parsing it.
/// </summary>
Func<IColumnContext, object, object> OnParsed { get; set; }

/// <summary>
/// Gets or sets a function used to pre-process output before trying to format it.
/// </summary>
Func<IColumnContext, object, object> OnFormatting { get; set; }

/// <summary>
/// Gets or sets a function used to post-process output after formatting it.
/// </summary>
Func<IColumnContext, string, string> OnFormatted { get; set; }

/// <summary>
/// Gets the type of the values in the column.
/// </summary>
Expand Down Expand Up @@ -139,6 +161,26 @@ public INullFormatter NullFormatter
/// </summary>
public Func<string, string> Preprocessor { get; set; }

/// <summary>
/// Gets or sets a function used to pre-process input before trying to parse it.
/// </summary>
public Func<IColumnContext, string, string> OnParsing { get; set; }

/// <summary>
/// Gets or sets a function used to post-process input after parsing it.
/// </summary>
public Func<IColumnContext, object, object> OnParsed { get; set; }

/// <summary>
/// Gets or sets a function used to pre-process output before trying to format it.
/// </summary>
public Func<IColumnContext, object, object> OnFormatting { get; set; }

/// <summary>
/// Gets or sets a function used to post-process output after formatting it.
/// </summary>
public Func<IColumnContext, string, string> OnFormatted { get; set; }

/// <summary>
/// Gets the type of the values in the column.
/// </summary>
Expand Down Expand Up @@ -169,6 +211,21 @@ protected internal static string TrimValue(string value)
/// <param name="value">The object to format.</param>
/// <returns>The formatted value.</returns>
public abstract string Format(IColumnContext context, object value);

/// <summary>
/// Gets the format provider to use. If the given provider is not null, it will be used.
/// Otherwise, the format provider set on the options object will be used. As a last resort,
/// the current culture specified by the operating system will be used.
/// </summary>
/// <param name="context">The current column context.</param>
/// <param name="formatProvider">The format provider set on the column.</param>
/// <returns>The format provider to use.</returns>
protected static IFormatProvider GetFormatProvider(IColumnContext context, IFormatProvider formatProvider)
{
return formatProvider
?? context?.RecordContext.ExecutionContext.Options.FormatProvider
?? CultureInfo.CurrentCulture;
}
}

/// <summary>
Expand Down Expand Up @@ -203,6 +260,10 @@ public override object Parse(IColumnContext context, string value)
{
value = Preprocessor(value);
}
if (OnParsing != null)
{
value = OnParsing(context, value);
}
if (NullFormatter.IsNullValue(context, value))
{
if (IsNullable)
Expand All @@ -212,7 +273,12 @@ public override object Parse(IColumnContext context, string value)
return DefaultValue.GetDefaultValue(context); // Should we check for the expected type?
}
string trimmed = IsTrimmed ? TrimValue(value) : value;
return OnParse(context, trimmed);
object result = OnParse(context, trimmed);
if (OnParsed != null)
{
result = OnParsed(context, result);
}
return result;
}

/// <summary>
Expand All @@ -236,11 +302,20 @@ public override object Parse(IColumnContext context, string value)
/// <returns>The formatted value.</returns>
public override string Format(IColumnContext context, object value)
{
if (OnFormatting != null)
{
value = OnFormatting(context, value);
}
if (value == null)
{
return NullFormatter.FormatNull(context);
}
return OnFormat(context, (T)value);
string result = OnFormat(context, (T)value);
if (OnFormatted != null)
{
result = OnFormatted(context, result);
}
return result;
}

/// <summary>
Expand Down
5 changes: 3 additions & 2 deletions FlatFiles/DateTimeColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ protected override DateTime OnParse(IColumnContext context, string value)
/// <returns>The formatted value.</returns>
protected override string OnFormat(IColumnContext context, DateTime value)
{
var provider = GetFormatProvider(context, FormatProvider);
if (OutputFormat == null)
{
return value.ToString(FormatProvider ?? CultureInfo.CurrentCulture);
return value.ToString(provider);
}
return value.ToString(OutputFormat, FormatProvider ?? CultureInfo.CurrentCulture);
return value.ToString(OutputFormat, provider);
}
}
}
4 changes: 2 additions & 2 deletions FlatFiles/DateTimeOffsetColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public DateTimeOffsetColumn(string columnName)
/// <inheritdoc />
protected override DateTimeOffset OnParse(IColumnContext context, string value)
{
var provider = FormatProvider ?? CultureInfo.CurrentCulture;
var provider = GetFormatProvider(context, FormatProvider);
if (InputFormat == null)
{
return DateTimeOffset.Parse(value, provider);
Expand All @@ -46,7 +46,7 @@ protected override DateTimeOffset OnParse(IColumnContext context, string value)
/// <inheritdoc />
protected override string OnFormat(IColumnContext context, DateTimeOffset value)
{
var provider = FormatProvider ?? CultureInfo.CurrentCulture;
var provider = GetFormatProvider(context, FormatProvider);
if (OutputFormat == null)
{
return value.ToString(provider);
Expand Down
7 changes: 4 additions & 3 deletions FlatFiles/DecimalColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public DecimalColumn(string columnName)
/// <returns>The parsed Decimal.</returns>
protected override decimal OnParse(IColumnContext context, string value)
{
var provider = FormatProvider ?? CultureInfo.CurrentCulture;
var provider = GetFormatProvider(context, FormatProvider);
return Decimal.Parse(value, NumberStyles, provider);
}

Expand All @@ -52,11 +52,12 @@ protected override decimal OnParse(IColumnContext context, string value)
/// <returns>The formatted value.</returns>
protected override string OnFormat(IColumnContext context, decimal value)
{
var provider = GetFormatProvider(context, FormatProvider);
if (OutputFormat == null)
{
return value.ToString(FormatProvider ?? CultureInfo.CurrentCulture);
return value.ToString(provider);
}
return value.ToString(OutputFormat, FormatProvider ?? CultureInfo.CurrentCulture);
return value.ToString(OutputFormat, provider);
}
}
}
7 changes: 4 additions & 3 deletions FlatFiles/DoubleColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public DoubleColumn(string columnName)
/// <returns>The parsed Double.</returns>
protected override double OnParse(IColumnContext context, string value)
{
var provider = FormatProvider ?? CultureInfo.CurrentCulture;
var provider = GetFormatProvider(context, FormatProvider);
return Double.Parse(value, NumberStyles, provider);
}

Expand All @@ -52,11 +52,12 @@ protected override double OnParse(IColumnContext context, string value)
/// <returns>The formatted value.</returns>
protected override string OnFormat(IColumnContext context, double value)
{
var provider = GetFormatProvider(context, FormatProvider);
if (OutputFormat == null)
{
return value.ToString(FormatProvider ?? CultureInfo.CurrentCulture);
return value.ToString(provider);
}
return value.ToString(OutputFormat, FormatProvider ?? CultureInfo.CurrentCulture);
return value.ToString(OutputFormat, provider);
}
}
}
5 changes: 5 additions & 0 deletions FlatFiles/FixedLengthOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ public OverflowTruncationPolicy TruncationPolicy
/// </summary>
public bool IsColumnContextDisabled { get; set; }

/// <summary>
/// Gets or sets the global, default format provider.
/// </summary>
public IFormatProvider FormatProvider { get; set; }

/// <summary>
/// Duplicates the options.
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions FlatFiles/FlatFiles.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
<RepositoryUrl>https://github.com/jehugaleahsa/FlatFiles.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>csv;comma;tab;separated;value;delimited;flat;file;fixed;width;fixed-width;length;fixed-length;parser;parsing;parse</PackageTags>
<PackageReleaseNotes>FixedLengthReader not reading records with metadata.</PackageReleaseNotes>
<PackageReleaseNotes>Support pre- and post-parsing and formatting operations. Support overriding IFormatProvider globally in IOptions.</PackageReleaseNotes>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>FlatFiles.snk</AssemblyOriginatorKeyFile>
<Version>4.3.4</Version>
<Version>4.4.0</Version>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net451' ">
Expand All @@ -27,8 +27,8 @@
<PropertyGroup>
<LangVersion>7.3</LangVersion>
<PackageIconUrl>https://raw.githubusercontent.com/jehugaleahsa/FlatFiles/master/icon.png</PackageIconUrl>
<AssemblyVersion>4.3.4.0</AssemblyVersion>
<FileVersion>4.3.4.0</FileVersion>
<AssemblyVersion>4.4.0.0</AssemblyVersion>
<FileVersion>4.4.0.0</FileVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard1.6|AnyCPU'">
Expand Down
Loading

0 comments on commit db0834f

Please sign in to comment.