diff --git a/README.md b/README.md index c141eab..6d513c9 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Bill (Heath) Gates,65,3.3 int main() { ss::parser p{"students.csv", ","}; if (!p.valid()) { + std::cout << p.error_msg() << std::endl; exit(EXIT_FAILURE); } @@ -48,6 +49,7 @@ Bill (Heath) Gates 65 3.3 ``` # Features * Works on any type + * Easy to use * No exceptions * Columns and rows can be ignored * Works with any type of delimiter @@ -66,6 +68,118 @@ $ git clone https://github.com/red0124/ssp $ cd ssp $ sudo make install ``` + +Run tests (optional): +``` +$ make test +``` + # Usage -... +## Error handling + +Detailed error messages can be accessed via the **error_msg** method, and to +enable them the error mode has to be changed to **error_mode::String** using +the **set_error_mode** method: +```cpp +void parser::set_error_mode(ss::error_mode); +const std::string& parser::error_msg(); +bool parser::valid(); +``` +Error messages can always be disabled by setting the error mode to +**error_mode::Bool**. An error can be detected using the **valid** method which +will return **false** if the file could not be opened, or if the conversion +could not be made (invalid types, invalid number of columns, ...). + +## Conversions +The above example will be used to show some of the features of the library. +As seen above, the **get_next** method returns a tuple of objects specified +inside the template type list. + +We could pass **void** as the second template parameter to ignore the second (age) +column in our csv, a tuple of only 2 parameters will be retuned: + +```cpp +// returns std::tuple +auto [name, grade] = p.get_next(); +``` + +If a conversion could not be applied, the method would return a tuple of +default constructed objects, and **valid** would return **false** , for example +if the third (grade) column in our csv could not be converted to a double +the conversion would fail. **std::optional** could be passed if we +wanted the conversion to proceed in the case of a failure: + +```cpp +// returns std::tuple> +auto [name, age, grade] = p.get_next(); +if(grade) { + // do something with grade +} +``` + +Similar to **std::optional**, **std::variant** could be used to try other +conversions if the previous failed _(note: conversion to **std::string** will +always pass)_: + +```cpp +// returns std::tuple> +auto [name, age, grade] = + p.get_next(); +if(std::holds_alternative(grade)) { + // grade set as double +} else if(std::holds_alternative(grade)) { + // grade set as char +} +``` + +## Restrictions + +Custom **restrictions** can be used to narrow down the conversions of unwanted +values. **ss::ir** (in range) and **ss::ne** (none empty) are one of those: + +```cpp +// returns std::tuple +// ss::ne makes sure that the name is not empty +// ss::ir makes sure that the grade will be in range [0, 10] +auto [name, age, grade] = + p.get_next, int, ss::ir>(); +``` + +If the restrictions are not met, the conversion will fail. +Other predefined restrictions are **ss::ax** (all except), **ss::nx** (none except) +and **ss::oor** (out of range): + +```cpp +// all ints exept 10 and 20 +ss::ax +// only 10 and 20 +ss::nx +// all values except the range [0, 10] +ss::oor +``` + +To define a restriction, a class/struct needs to be made which has a +**ss_valid** method which returns a **bool** and accepts one object. The type of the +conversion will be the same as the type of the passed object within **ss_valid** +and not the restriction itself. Optionally, an **error** method can be made to +describe the invalid conversion. + +```cpp +template +struct even { + bool ss_valid(const T& value) const { + return value % 2 == 0; + } + + const char* error() const { + return "number not even"; + } +}; + +// ... +// only even numbers will pass +// returns std::tuple +auto [name, age] = p.get_next, void>(); + +``` diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index 845b2d8..47087d3 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -293,11 +293,8 @@ private: } void set_error_file_not_open() { - if (error_mode_ == error_mode::String) { - string_error_.append(file_name_).append(" could not be not open."); - } else { - bool_error_ = true; - } + string_error_.append(file_name_).append(" could not be not open."); + bool_error_ = true; } void set_error_eof_reached() {