Skip to content

Commit

Permalink
Issue #54 Generate Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
bytefish committed Oct 31, 2020
1 parent 99e39b6 commit ea1757e
Show file tree
Hide file tree
Showing 128 changed files with 18,657 additions and 2,918 deletions.
Binary file modified TinyCsvParser/Documentation/build/doctrees/environment.pickle
Binary file not shown.
Binary file modified TinyCsvParser/Documentation/build/doctrees/index.doctree
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified TinyCsvParser/Documentation/build/doctrees/sections/faq.doctree
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion TinyCsvParser/Documentation/build/html/.buildinfo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: e8ec982bd7f52df4525c4ed61d6d6b52
config: ffc8d2ef8e45a0dd35befa8f465ab5df
tags: 645f666f9bcd5a90fca523b33c5a78b7
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This is a list of Frequently Asked Questions (FAQ) about TinyCsvParser.

* How can I parse CSV data coming in a custom format?
* All built-in converters support format strings and other advanced formatting options. Please see the detailed guide on :ref:`Type Converter <userguide_type_converter>`
and have a look at the tutorial on :ref:`Parsing Custom Formats <tutorials_custom_formats>`.
and have a look at the tutorial on :ref:`Parsing Custom Formats <tutorials_custom_formats>`. If your needs are highly specific, check out :ref:`Custom Mapping <tutorials_custom_mapping>`.

* Can I contribute to the project?
* **Yes!** You can help out with code, documentation, bug reports, bug fixes, ... Please see the section on :ref:`Contributing`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Tutorials
tutorials/custom_formats
tutorials/parsing_enums
tutorials/mapping_arrays
tutorials/custom_mapping

Tutorials are a great way to learn how to accomplish common tasks.

Expand All @@ -18,3 +19,5 @@ Tutorials are a great way to learn how to accomplish common tasks.
Explains how to parse enums by using an :code:`EnumConverter`.
:ref:`tutorials_mapping_arrays`
Explains how to map CSV data into an array of values.
:ref:`tutorials_custom_mapping`
Explains how to map to non-scalar objects and combine columns with :code:`MapUsing`
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ Reading a Date with a custom Format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Imagine a client sends data with a weird format for dates and writes dates like this :code:`2004###01###25`.
These values cannot be parsed with the default date format, but in `TinyCsvParser`_ a :csharp:`DateTimeConverter`
These values cannot be parsed with the default date format, but in `TinyCsvParser`_ a :code:`DateTimeConverter`
with the custom date time format can be used for the mapping.

To use the custom converter, you are simply pass the Converter to the :csharp:`MapProperty` method to define a custom
To use the custom converter, you are simply pass the Converter to the :code:`MapProperty` method to define a custom
converter for the property mapping.

.. code-block:: csharp
Expand All @@ -34,15 +34,15 @@ converter for the property mapping.
}
}
Reading a Boolean wit a custom Format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Reading a Boolean with a custom Format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Imagine you want to map between the CSV value and a boolean. The library makes the assumption, that the
string value for true is :code:`"true"` and for false is :code:`"false"`. But now imagine your CSV data
uses the text :code:`"ThisIsTrue"` for the boolean value :code:`true`, and :code:`"ThisIsFalse"` for
the boolean value :code:`false`.

Then you have to instantiate and use the :csharp:`BoolConverter` like this:
Then you have to instantiate and use the :code:`BoolConverter` like this:

.. code-block:: csharp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
.. _tutorials_custom_mapping:

Custom Mapping
==============

In some cases you may need to map CSV columns onto properties of your output entity in a way that is not 1:1, or your
output entity may contain other non-scalar types which you need to populate using multiple columns from the CSV row.
This is where :code:`MapUsing` comes into play. MapUsing accepts a delegate which will be called for each non-empty,
non-comment row in your CSV. The call to the supplied delegate happens *after* all of the :code:`MapProperty` mappings
have executed for that row, so your entity maybe partially populated with data by the time your delegate executes.

Example
~~~~~~~

First, like any other mapping, you need to establish an implementation of :code:`CsvMapping<MyEntity>`.

.. code-block:: csharp
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class MyEntity
{
public string OrderId { get; set; }
public Person Customer { get; set; }
}
// CSV format: 1234,Doe,John
public class MyMap : CsvMapping<MyEntity>
{
public MyMap()
{
MapProperty(0, x => x.OrderId);
// TODO: Map person using MapUsing()
}
}
Adding MapUsing
~~~~~~~~~~~~~~~

Now we have our first column mapped to the OrderId, but how can we map the second & third columns to an instance of our :code:`Person` class?
:code:`MapUsing` to the rescue!

.. code-block:: csharp
// CSV format: 1234,Doe,John
public class MyMap : CsvMapping<MyEntity>
{
public MyMap()
{
MapProperty(0, x => x.OrderId);
MapUsing((entity, values) =>
{
// TODO: Invalidate the row if first name is missing.
var customer = new Person();
// WARNING: IndexOutOfRangeException could happen here!!
customer.LastName = values.Tokens[1];
customer.FirstName = values.Tokens[2];
entity.Customer = customer;
return true;
});
}
}
Getting Defensive
~~~~~~~~~~~~~~~~~

Great! Now our :code:`MyEntity` class will get correctly populated with the order ID and a :code:`Person` instance with the correct
first & last name set. But what happens if we encounter a row that is missing the first name, along the lines of "1234,Acme Inc"?
This is bad news, especially if multiple rows could be missing the third column ... each row will raise an exception, which would be
very detrimental to parsing performance. That's why we require your :code:`MapUsing` delegate to return a boolean, indicating
whether the data you mapped resulted in a valid row.

Note: you should avoid doing things that could raise exceptions within your
delegate, **even** if you use :code:`try...catch`. The very fact that the exception is raised will slow your CSV parsing down
tremendously, even if it is caught and discarded.


.. code-block:: csharp
// CSV format: 1234,Doe,John
public class MyMap : CsvMapping<MyEntity>
{
public MyMap()
{
MapProperty(0, x => x.OrderId);
MapUsing((entity, values) =>
{
// Checking that we have enough data and that the data is within range
// should happen before we try to access & map it below.
if(values.Tokens.Length < 3)
{
return false;
}
var customer = new Person();
customer.LastName = values.Tokens[1];
customer.FirstName = values.Tokens[2];
entity.Customer = customer;
return true;
});
}
}
.. _TinyCsvParser: https://github.com/bytefish/TinyCsvParser
Loading

0 comments on commit ea1757e

Please sign in to comment.