From f744a792e2dcfe9712d06cf596c9606b3cda607d Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 17 Jun 2019 23:45:43 +0900 Subject: [PATCH 01/10] fix: constructor with array-like types --- toml/value.hpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/toml/value.hpp b/toml/value.hpp index 278c78e..71e84de 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -779,18 +779,17 @@ class basic_value } template::value, + std::is_convertible::value, std::nullptr_t>::type = nullptr> basic_value(std::initializer_list list) : type_(value_t::array), region_info_(std::make_shared(region_base{})) { - array_type ary; ary.reserve(list.size()); - for(auto& elem : list) {ary.emplace_back(std::move(elem));} + array_type ary(list.begin(), list.end()); assigner(this->array_, std::move(ary)); } template::value, + std::is_convertible::value, std::nullptr_t>::type = nullptr> basic_value& operator=(std::initializer_list list) { @@ -798,8 +797,7 @@ class basic_value this->type_ = value_t::array; this->region_info_ = std::make_shared(region_base{}); - array_type ary; ary.reserve(list.size()); - for(auto& elem : list) {ary.emplace_back(std::move(elem));} + array_type ary(list.begin(), list.end()); assigner(this->array_, std::move(ary)); return *this; } From 228487eafdd1810a9cf0db9c4e90e05903167190 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 17 Jun 2019 23:46:42 +0900 Subject: [PATCH 02/10] test: fix typos in tests --- tests/test_extended_conversions.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/test_extended_conversions.cpp b/tests/test_extended_conversions.cpp index 8db1d02..c942a4e 100644 --- a/tests/test_extended_conversions.cpp +++ b/tests/test_extended_conversions.cpp @@ -134,14 +134,15 @@ BOOST_AUTO_TEST_CASE(test_conversion_by_member_methods) } { - const toml::basic_value + const toml::basic_value v{{"a", 42}, {"b", "baz"}}; const auto foo = toml::get(v); BOOST_CHECK_EQUAL(foo.a, 42); BOOST_CHECK_EQUAL(foo.b, "baz"); - const toml::value v2(foo); + const toml::basic_value + v2(foo); BOOST_CHECK_EQUAL(v, v2); } @@ -172,14 +173,15 @@ BOOST_AUTO_TEST_CASE(test_conversion_by_specialization) BOOST_CHECK_EQUAL(v, v2); } { - const toml::basic_value + const toml::basic_value v{{"a", 42}, {"b", "baz"}}; const auto bar = toml::get(v); BOOST_CHECK_EQUAL(bar.a, 42); BOOST_CHECK_EQUAL(bar.b, "baz"); - const toml::value v2(bar); + const toml::basic_value + v2(bar); BOOST_CHECK_EQUAL(v, v2); } @@ -253,12 +255,12 @@ BOOST_AUTO_TEST_CASE(test_recursive_conversion) } { - const toml::basic_value + const toml::basic_value v{ toml::table{{"a", 42}, {"b", "baz"}}, toml::table{{"a", 43}, {"b", "qux"}}, toml::table{{"a", 44}, {"b", "quux"}}, - toml::table{{"a", 45}, {"b", "foobar"}}, + toml::table{{"a", 45}, {"b", "foobar"}} }; const auto foos = toml::get>(v); From 7b1a788e2d680b7195807256d28373de1bf0d121 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 18 Jun 2019 00:43:25 +0900 Subject: [PATCH 03/10] feat: enable to convert vector to comments --- toml/comments.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/toml/comments.hpp b/toml/comments.hpp index 28ba28e..97ab610 100644 --- a/toml/comments.hpp +++ b/toml/comments.hpp @@ -55,6 +55,17 @@ struct preserve_comments explicit preserve_comments(std::vector&& c) : comments(std::move(c)) {} + preserve_comments& operator=(const std::vector& c) + { + comments = c; + return *this; + } + preserve_comments& operator=(std::vector&& c) + { + comments = std::move(c); + return *this; + } + explicit preserve_comments(const discard_comments&) {} explicit preserve_comments(size_type n): comments(n) {} @@ -278,6 +289,9 @@ struct discard_comments explicit discard_comments(const std::vector&) noexcept {} explicit discard_comments(std::vector&&) noexcept {} + discard_comments& operator=(const std::vector&) noexcept {return *this;} + discard_comments& operator=(std::vector&&) noexcept {return *this;} + explicit discard_comments(const preserve_comments&) noexcept {} explicit discard_comments(size_type) noexcept {} From ca084abe9002794bd9585b7144cddb99343449a3 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 18 Jun 2019 00:44:27 +0900 Subject: [PATCH 04/10] feat: consider the first comments as a file comment --- toml/parser.hpp | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index 6cc028b..b8a34cc 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -1703,6 +1703,44 @@ result parse_toml_file(location& loc) return ok(value_type(table_type{})); } + // put the first line as a region of a file + const region file(loc, loc.iter(), + std::find(loc.iter(), loc.end(), '\n')); + + // The first successive comments that are separated from the first value + // by an empty line are for a file itself. + // ```toml + // # this is a comment for a file. + // + // key = "the first value" + // ``` + // ```toml + // # this is a comment for "the first value". + // key = "the first value" + // ``` + std::vector comments; + using lex_first_comments = sequence< + repeat, lex_comment, lex_newline>, at_least<1>>, + sequence, lex_newline> + >; + if(const auto token = lex_first_comments::invoke(loc)) + { + location inner_loc(loc.name(), token.unwrap().str()); + while(inner_loc.iter() != inner_loc.end()) + { + maybe::invoke(inner_loc); // remove ws if exists + if(lex_newline::invoke(inner_loc)) + { + assert(inner_loc.iter() == inner_loc.end()); + break; // empty line found. + } + auto com = lex_comment::invoke(inner_loc).unwrap().str(); + com.erase(com.begin()); // remove # sign + comments.push_back(std::move(com)); + lex_newline::invoke(inner_loc); + } + } + table_type data; // root object is also a table, but without [tablename] if(auto tab = parse_ml_table(loc)) @@ -1752,7 +1790,11 @@ result parse_toml_file(location& loc) return err(format_underline("[error]: toml::parse_toml_file: " "unknown line appeared", {{std::addressof(loc), "unknown format"}})); } - return ok(data); + + Value v(std::move(data), file); + v.comments() = comments; + + return ok(std::move(v)); } } // detail From fb5834caabd4682b17f81aa7b6ca96794b3cdff8 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 18 Jun 2019 00:45:30 +0900 Subject: [PATCH 05/10] refactor: exchange order of test section --- tests/test_parse_file.cpp | 343 +++++++++++++++++++------------------- 1 file changed, 172 insertions(+), 171 deletions(-) diff --git a/tests/test_parse_file.cpp b/tests/test_parse_file.cpp index ef3cf84..6283c04 100644 --- a/tests/test_parse_file.cpp +++ b/tests/test_parse_file.cpp @@ -194,6 +194,178 @@ BOOST_AUTO_TEST_CASE(test_hard_example) expected_multi_line_array); } +BOOST_AUTO_TEST_CASE(test_example_preserve_comment) +{ + const auto data = toml::parse("toml/tests/example.toml"); + + BOOST_CHECK_EQUAL(toml::find(data, "title"), "TOML Example"); + const auto& owner = toml::find(data, "owner"); + { + BOOST_CHECK_EQUAL(toml::find(owner, "name"), "Tom Preston-Werner"); + BOOST_CHECK_EQUAL(toml::find(owner, "organization"), "GitHub"); + BOOST_CHECK_EQUAL(toml::find(owner, "bio"), + "GitHub Cofounder & CEO\nLikes tater tots and beer."); + BOOST_CHECK_EQUAL(toml::find(owner, "dob"), + toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27), + toml::local_time(7, 32, 0), toml::time_offset(0, 0))); + BOOST_CHECK_EQUAL(toml::find(owner, "dob").comments().at(0), + " First class dates? Why not?"); + } + + const auto& database = toml::find(data, "database"); + { + BOOST_CHECK_EQUAL(toml::find(database, "server"), "192.168.1.1"); + const std::vector expected_ports{8001, 8001, 8002}; + BOOST_CHECK(toml::find>(database, "ports") == expected_ports); + BOOST_CHECK_EQUAL(toml::find(database, "connection_max"), 5000); + BOOST_CHECK_EQUAL(toml::find(database, "enabled"), true); + } + + const auto& servers = toml::find(data, "servers"); + { + const auto& alpha = toml::find(servers, "alpha"); + BOOST_CHECK_EQUAL(alpha.comments().at(0), + " You can indent as you please. Tabs or spaces. TOML don't care."); + BOOST_CHECK_EQUAL(toml::find(alpha, "ip"), "10.0.0.1"); + BOOST_CHECK_EQUAL(toml::find(alpha, "dc"), "eqdc10"); + + const auto& beta = toml::find(servers, "beta"); + BOOST_CHECK_EQUAL(toml::find(beta, "ip"), "10.0.0.2"); + BOOST_CHECK_EQUAL(toml::find(beta, "dc"), "eqdc10"); + BOOST_CHECK_EQUAL(toml::find(beta, "country"), + "\xE4\xB8\xAD\xE5\x9B\xBD"); + BOOST_CHECK_EQUAL(toml::find(beta, "country").comments().at(0), + " This should be parsed as UTF-8"); + } + + const auto& clients = toml::find(data, "clients"); + { + BOOST_CHECK_EQUAL(toml::find(clients, "data").comments().at(0), + " just an update to make sure parsers support it"); + + + toml::array clients_data = toml::find(clients, "data"); + std::vector expected_name{"gamma", "delta"}; + BOOST_CHECK(toml::get>(clients_data.at(0)) == + expected_name); + std::vector expected_number{1, 2}; + BOOST_CHECK(toml::get>(clients_data.at(1)) == + expected_number); + std::vector expected_hosts{"alpha", "omega"}; + BOOST_CHECK(toml::find>(clients, "hosts") == + expected_hosts); + + BOOST_CHECK_EQUAL(toml::find(clients, "hosts").comments().at(0), + " Line breaks are OK when inside arrays"); + } + + std::vector products = + toml::find>(data, "products"); + { + BOOST_CHECK_EQUAL(toml::get(products.at(0).at("name")), + "Hammer"); + BOOST_CHECK_EQUAL(toml::get(products.at(0).at("sku")), + 738594937); + + BOOST_CHECK_EQUAL(toml::get(products.at(1).at("name")), + "Nail"); + BOOST_CHECK_EQUAL(toml::get(products.at(1).at("sku")), + 284758393); + BOOST_CHECK_EQUAL(toml::get(products.at(1).at("color")), + "gray"); + } +} + +BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque) +{ + const auto data = toml::parse("toml/tests/example.toml"); + + static_assert(std::is_same::type> + >::value, ""); + static_assert(std::is_same::type> + >::value, ""); + + BOOST_CHECK_EQUAL(toml::find(data, "title"), "TOML Example"); + const auto& owner = toml::find(data, "owner"); + { + BOOST_CHECK_EQUAL(toml::find(owner, "name"), "Tom Preston-Werner"); + BOOST_CHECK_EQUAL(toml::find(owner, "organization"), "GitHub"); + BOOST_CHECK_EQUAL(toml::find(owner, "bio"), + "GitHub Cofounder & CEO\nLikes tater tots and beer."); + BOOST_CHECK_EQUAL(toml::find(owner, "dob"), + toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27), + toml::local_time(7, 32, 0), toml::time_offset(0, 0))); + BOOST_CHECK_EQUAL(toml::find(owner, "dob").comments().at(0), + " First class dates? Why not?"); + } + + const auto& database = toml::find(data, "database"); + { + BOOST_CHECK_EQUAL(toml::find(database, "server"), "192.168.1.1"); + const std::vector expected_ports{8001, 8001, 8002}; + BOOST_CHECK(toml::find>(database, "ports") == expected_ports); + BOOST_CHECK_EQUAL(toml::find(database, "connection_max"), 5000); + BOOST_CHECK_EQUAL(toml::find(database, "enabled"), true); + } + + const auto& servers = toml::find(data, "servers"); + { + const auto& alpha = toml::find(servers, "alpha"); + BOOST_CHECK_EQUAL(alpha.comments().at(0), + " You can indent as you please. Tabs or spaces. TOML don't care."); + BOOST_CHECK_EQUAL(toml::find(alpha, "ip"), "10.0.0.1"); + BOOST_CHECK_EQUAL(toml::find(alpha, "dc"), "eqdc10"); + + const auto& beta = toml::find(servers, "beta"); + BOOST_CHECK_EQUAL(toml::find(beta, "ip"), "10.0.0.2"); + BOOST_CHECK_EQUAL(toml::find(beta, "dc"), "eqdc10"); + BOOST_CHECK_EQUAL(toml::find(beta, "country"), + "\xE4\xB8\xAD\xE5\x9B\xBD"); + BOOST_CHECK_EQUAL(toml::find(beta, "country").comments().at(0), + " This should be parsed as UTF-8"); + } + + const auto& clients = toml::find(data, "clients"); + { + BOOST_CHECK_EQUAL(toml::find(clients, "data").comments().at(0), + " just an update to make sure parsers support it"); + + + toml::array clients_data = toml::find(clients, "data"); + std::vector expected_name{"gamma", "delta"}; + BOOST_CHECK(toml::get>(clients_data.at(0)) == + expected_name); + std::vector expected_number{1, 2}; + BOOST_CHECK(toml::get>(clients_data.at(1)) == + expected_number); + std::vector expected_hosts{"alpha", "omega"}; + BOOST_CHECK(toml::find>(clients, "hosts") == + expected_hosts); + + BOOST_CHECK_EQUAL(toml::find(clients, "hosts").comments().at(0), + " Line breaks are OK when inside arrays"); + } + + std::vector products = + toml::find>(data, "products"); + { + BOOST_CHECK_EQUAL(toml::get(products.at(0).at("name")), + "Hammer"); + BOOST_CHECK_EQUAL(toml::get(products.at(0).at("sku")), + 738594937); + + BOOST_CHECK_EQUAL(toml::get(products.at(1).at("name")), + "Nail"); + BOOST_CHECK_EQUAL(toml::get(products.at(1).at("sku")), + 284758393); + BOOST_CHECK_EQUAL(toml::get(products.at(1).at("color")), + "gray"); + } +} + // --------------------------------------------------------------------------- // after here, the test codes generate the content of a file. @@ -695,174 +867,3 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines) } } -BOOST_AUTO_TEST_CASE(test_example_preserve_comment) -{ - const auto data = toml::parse("toml/tests/example.toml"); - - BOOST_CHECK_EQUAL(toml::find(data, "title"), "TOML Example"); - const auto& owner = toml::find(data, "owner"); - { - BOOST_CHECK_EQUAL(toml::find(owner, "name"), "Tom Preston-Werner"); - BOOST_CHECK_EQUAL(toml::find(owner, "organization"), "GitHub"); - BOOST_CHECK_EQUAL(toml::find(owner, "bio"), - "GitHub Cofounder & CEO\nLikes tater tots and beer."); - BOOST_CHECK_EQUAL(toml::find(owner, "dob"), - toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27), - toml::local_time(7, 32, 0), toml::time_offset(0, 0))); - BOOST_CHECK_EQUAL(toml::find(owner, "dob").comments().at(0), - " First class dates? Why not?"); - } - - const auto& database = toml::find(data, "database"); - { - BOOST_CHECK_EQUAL(toml::find(database, "server"), "192.168.1.1"); - const std::vector expected_ports{8001, 8001, 8002}; - BOOST_CHECK(toml::find>(database, "ports") == expected_ports); - BOOST_CHECK_EQUAL(toml::find(database, "connection_max"), 5000); - BOOST_CHECK_EQUAL(toml::find(database, "enabled"), true); - } - - const auto& servers = toml::find(data, "servers"); - { - const auto& alpha = toml::find(servers, "alpha"); - BOOST_CHECK_EQUAL(alpha.comments().at(0), - " You can indent as you please. Tabs or spaces. TOML don't care."); - BOOST_CHECK_EQUAL(toml::find(alpha, "ip"), "10.0.0.1"); - BOOST_CHECK_EQUAL(toml::find(alpha, "dc"), "eqdc10"); - - const auto& beta = toml::find(servers, "beta"); - BOOST_CHECK_EQUAL(toml::find(beta, "ip"), "10.0.0.2"); - BOOST_CHECK_EQUAL(toml::find(beta, "dc"), "eqdc10"); - BOOST_CHECK_EQUAL(toml::find(beta, "country"), - "\xE4\xB8\xAD\xE5\x9B\xBD"); - BOOST_CHECK_EQUAL(toml::find(beta, "country").comments().at(0), - " This should be parsed as UTF-8"); - } - - const auto& clients = toml::find(data, "clients"); - { - BOOST_CHECK_EQUAL(toml::find(clients, "data").comments().at(0), - " just an update to make sure parsers support it"); - - - toml::array clients_data = toml::find(clients, "data"); - std::vector expected_name{"gamma", "delta"}; - BOOST_CHECK(toml::get>(clients_data.at(0)) == - expected_name); - std::vector expected_number{1, 2}; - BOOST_CHECK(toml::get>(clients_data.at(1)) == - expected_number); - std::vector expected_hosts{"alpha", "omega"}; - BOOST_CHECK(toml::find>(clients, "hosts") == - expected_hosts); - - BOOST_CHECK_EQUAL(toml::find(clients, "hosts").comments().at(0), - " Line breaks are OK when inside arrays"); - } - - std::vector products = - toml::find>(data, "products"); - { - BOOST_CHECK_EQUAL(toml::get(products.at(0).at("name")), - "Hammer"); - BOOST_CHECK_EQUAL(toml::get(products.at(0).at("sku")), - 738594937); - - BOOST_CHECK_EQUAL(toml::get(products.at(1).at("name")), - "Nail"); - BOOST_CHECK_EQUAL(toml::get(products.at(1).at("sku")), - 284758393); - BOOST_CHECK_EQUAL(toml::get(products.at(1).at("color")), - "gray"); - } -} - -BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque) -{ - const auto data = toml::parse("toml/tests/example.toml"); - - static_assert(std::is_same::type> - >::value, ""); - static_assert(std::is_same::type> - >::value, ""); - - BOOST_CHECK_EQUAL(toml::find(data, "title"), "TOML Example"); - const auto& owner = toml::find(data, "owner"); - { - BOOST_CHECK_EQUAL(toml::find(owner, "name"), "Tom Preston-Werner"); - BOOST_CHECK_EQUAL(toml::find(owner, "organization"), "GitHub"); - BOOST_CHECK_EQUAL(toml::find(owner, "bio"), - "GitHub Cofounder & CEO\nLikes tater tots and beer."); - BOOST_CHECK_EQUAL(toml::find(owner, "dob"), - toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27), - toml::local_time(7, 32, 0), toml::time_offset(0, 0))); - BOOST_CHECK_EQUAL(toml::find(owner, "dob").comments().at(0), - " First class dates? Why not?"); - } - - const auto& database = toml::find(data, "database"); - { - BOOST_CHECK_EQUAL(toml::find(database, "server"), "192.168.1.1"); - const std::vector expected_ports{8001, 8001, 8002}; - BOOST_CHECK(toml::find>(database, "ports") == expected_ports); - BOOST_CHECK_EQUAL(toml::find(database, "connection_max"), 5000); - BOOST_CHECK_EQUAL(toml::find(database, "enabled"), true); - } - - const auto& servers = toml::find(data, "servers"); - { - const auto& alpha = toml::find(servers, "alpha"); - BOOST_CHECK_EQUAL(alpha.comments().at(0), - " You can indent as you please. Tabs or spaces. TOML don't care."); - BOOST_CHECK_EQUAL(toml::find(alpha, "ip"), "10.0.0.1"); - BOOST_CHECK_EQUAL(toml::find(alpha, "dc"), "eqdc10"); - - const auto& beta = toml::find(servers, "beta"); - BOOST_CHECK_EQUAL(toml::find(beta, "ip"), "10.0.0.2"); - BOOST_CHECK_EQUAL(toml::find(beta, "dc"), "eqdc10"); - BOOST_CHECK_EQUAL(toml::find(beta, "country"), - "\xE4\xB8\xAD\xE5\x9B\xBD"); - BOOST_CHECK_EQUAL(toml::find(beta, "country").comments().at(0), - " This should be parsed as UTF-8"); - } - - const auto& clients = toml::find(data, "clients"); - { - BOOST_CHECK_EQUAL(toml::find(clients, "data").comments().at(0), - " just an update to make sure parsers support it"); - - - toml::array clients_data = toml::find(clients, "data"); - std::vector expected_name{"gamma", "delta"}; - BOOST_CHECK(toml::get>(clients_data.at(0)) == - expected_name); - std::vector expected_number{1, 2}; - BOOST_CHECK(toml::get>(clients_data.at(1)) == - expected_number); - std::vector expected_hosts{"alpha", "omega"}; - BOOST_CHECK(toml::find>(clients, "hosts") == - expected_hosts); - - BOOST_CHECK_EQUAL(toml::find(clients, "hosts").comments().at(0), - " Line breaks are OK when inside arrays"); - } - - std::vector products = - toml::find>(data, "products"); - { - BOOST_CHECK_EQUAL(toml::get(products.at(0).at("name")), - "Hammer"); - BOOST_CHECK_EQUAL(toml::get(products.at(0).at("sku")), - 738594937); - - BOOST_CHECK_EQUAL(toml::get(products.at(1).at("name")), - "Nail"); - BOOST_CHECK_EQUAL(toml::get(products.at(1).at("sku")), - 284758393); - BOOST_CHECK_EQUAL(toml::get(products.at(1).at("color")), - "gray"); - } -} From 159283fdad035ee77785a9c3eb198095ea3cfe52 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 18 Jun 2019 01:25:43 +0900 Subject: [PATCH 06/10] test: check preserve_comment keep it read --- tests/test_parse_file.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test_parse_file.cpp b/tests/test_parse_file.cpp index 6283c04..e2d499b 100644 --- a/tests/test_parse_file.cpp +++ b/tests/test_parse_file.cpp @@ -193,6 +193,34 @@ BOOST_AUTO_TEST_CASE(test_hard_example) BOOST_CHECK(toml::find>(bit, "multi_line_array") == expected_multi_line_array); } +BOOST_AUTO_TEST_CASE(test_hard_example_comment) +{ + const auto data = toml::parse("toml/tests/hard_example.toml"); + const auto the = toml::find(data, "the"); + BOOST_CHECK_EQUAL(toml::find(the, "test_string"), + "You'll hate me after this - #"); + + const auto hard = toml::find(the, "hard"); + const std::vector expected_the_hard_test_array{"] ", " # "}; + BOOST_CHECK(toml::find>(hard, "test_array") == + expected_the_hard_test_array); + const std::vector expected_the_hard_test_array2{ + "Test #11 ]proved that", "Experiment #9 was a success"}; + BOOST_CHECK(toml::find>(hard, "test_array2") == + expected_the_hard_test_array2); + BOOST_CHECK_EQUAL(toml::find(hard, "another_test_string"), + " Same thing, but with a string #"); + BOOST_CHECK_EQUAL(toml::find(hard, "harder_test_string"), + " And when \"'s are in the string, along with # \""); + + const auto bit = toml::find(hard, "bit#"); + BOOST_CHECK_EQUAL(toml::find(bit, "what?"), + "You don't think some user won't do that?"); + const std::vector expected_multi_line_array{"]"}; + BOOST_CHECK(toml::find>(bit, "multi_line_array") == + expected_multi_line_array); +} + BOOST_AUTO_TEST_CASE(test_example_preserve_comment) { From 86e55c3bf7b3520589bca39aa4b50cd79f2f381d Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 18 Jun 2019 01:26:16 +0900 Subject: [PATCH 07/10] test: check serialization keeps comments --- tests/test_serialize_file.cpp | 52 ++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/tests/test_serialize_file.cpp b/tests/test_serialize_file.cpp index 816dbbe..372249b 100644 --- a/tests/test_serialize_file.cpp +++ b/tests/test_serialize_file.cpp @@ -9,7 +9,6 @@ #include #include - BOOST_AUTO_TEST_CASE(test_example) { const auto data = toml::parse("toml/tests/example.toml"); @@ -31,6 +30,31 @@ BOOST_AUTO_TEST_CASE(test_example) BOOST_CHECK(data == serialized); } +BOOST_AUTO_TEST_CASE(test_example_with_comment) +{ + const auto data = toml::parse("toml/tests/example.toml"); + { + std::ofstream ofs("tmp1_com.toml"); + ofs << std::setw(80) << data; + } + + auto serialized = toml::parse("tmp1_com.toml"); + { + auto& owner = toml::find(serialized, "owner"); + auto& bio = toml::get(owner.at("bio")); + const auto CR = std::find(bio.begin(), bio.end(), '\r'); + if(CR != bio.end()) + { + bio.erase(CR); + } + } + BOOST_CHECK(data == serialized); + { + std::ofstream ofs("tmp1_com1.toml"); + ofs << std::setw(80) << serialized; + } +} + BOOST_AUTO_TEST_CASE(test_fruit) { const auto data = toml::parse("toml/tests/fruit.toml"); @@ -42,6 +66,17 @@ BOOST_AUTO_TEST_CASE(test_fruit) BOOST_CHECK(data == serialized); } +BOOST_AUTO_TEST_CASE(test_fruit_with_comments) +{ + const auto data = toml::parse("toml/tests/fruit.toml"); + { + std::ofstream ofs("tmp2_com.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse("tmp2_com.toml"); + BOOST_CHECK(data == serialized); +} + BOOST_AUTO_TEST_CASE(test_hard_example) { const auto data = toml::parse("toml/tests/hard_example.toml"); @@ -52,3 +87,18 @@ BOOST_AUTO_TEST_CASE(test_hard_example) const auto serialized = toml::parse("tmp3.toml"); BOOST_CHECK(data == serialized); } + +BOOST_AUTO_TEST_CASE(test_hard_example_with_comment) +{ + const auto data = toml::parse("toml/tests/hard_example.toml"); + { + std::ofstream ofs("tmp3_com.toml"); + ofs << std::setw(80) << data; + } + const auto serialized = toml::parse("tmp3_com.toml"); + { + std::ofstream ofs("tmp3_com1.toml"); + ofs << std::setw(80) << serialized; + } + BOOST_CHECK(data == serialized); +} From 262f9c5fcc8ea8e42c9f8fe084534659fddcb7b1 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 18 Jun 2019 01:26:40 +0900 Subject: [PATCH 08/10] fix: avoid duplicating comment: array/table elems --- toml/region.hpp | 63 +++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/toml/region.hpp b/toml/region.hpp index 987238b..e6a7e68 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -304,38 +304,45 @@ struct region final : public region_base // # this also. // a = value # not this. // ``` - auto iter = this->line_begin(); // points the first character - while(iter != this->begin()) + + // # this is a comment for `a`, not array elements. + // a = [1, 2, 3, 4, 5] + if(this->first() == std::find_if(this->line_begin(), this->first(), + [](const char c) noexcept -> bool {return c == '[' || c == '{';})) { - iter = std::prev(iter); + auto iter = this->line_begin(); // points the first character + while(iter != this->begin()) + { + iter = std::prev(iter); - // range [line_start, iter) represents the previous line - const auto line_start = std::find( - rev_iter(iter), rev_iter(this->begin()), '\n').base(); - const auto comment_found = std::find(line_start, iter, '#'); - if(comment_found == iter) - { - break; // comment not found. - } + // range [line_start, iter) represents the previous line + const auto line_start = std::find( + rev_iter(iter), rev_iter(this->begin()), '\n').base(); + const auto comment_found = std::find(line_start, iter, '#'); + if(comment_found == iter) + { + break; // comment not found. + } - // exclude the following case. - // > a = "foo" # comment // <-- this is not a comment for b but a. - // > b = "current value" - if(std::all_of(line_start, comment_found, - [](const char c) noexcept -> bool { - return c == ' ' || c == '\t'; - })) - { - // unwrap the first '#' by std::next. - auto str = make_string(std::next(comment_found), iter); - if(str.back() == '\r') {str.pop_back();} - com.push_back(std::move(str)); + // exclude the following case. + // > a = "foo" # comment // <-- this is not a comment for b but a. + // > b = "current value" + if(std::all_of(line_start, comment_found, + [](const char c) noexcept -> bool { + return c == ' ' || c == '\t'; + })) + { + // unwrap the first '#' by std::next. + auto str = make_string(std::next(comment_found), iter); + if(str.back() == '\r') {str.pop_back();} + com.push_back(std::move(str)); + } + else + { + break; + } + iter = line_start; } - else - { - break; - } - iter = line_start; } } From 32d5c9e92413c7ff542e280ccb4de17276aac260 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 18 Jun 2019 01:27:52 +0900 Subject: [PATCH 09/10] fix: serialize array correctly --- toml/serializer.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/toml/serializer.hpp b/toml/serializer.hpp index b3e3637..cba2923 100644 --- a/toml/serializer.hpp +++ b/toml/serializer.hpp @@ -333,6 +333,11 @@ struct serializer current_line += ','; } } + if(!current_line.empty()) + { + if(current_line.back() != '\n') {current_line += '\n';} + token += current_line; + } token += "]\n"; return token; } From d9f9df61a2a02c737df1a50adf07d098d81f658a Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 18 Jun 2019 01:39:36 +0900 Subject: [PATCH 10/10] fix: fix links in README --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d1acaf1..3562f33 100644 --- a/README.md +++ b/README.md @@ -47,17 +47,17 @@ int main() - [Decoding a toml file](#decoding-a-toml-file) - [In the case of syntax error](#in-the-case-of-syntax-error) - [Invalid UTF-8 Codepoints](#invalid-utf-8-codepoints) -- [Finding a toml value](#getting-a-toml-value) +- [Finding a toml value](#finding-a-toml-value-from-a-table) - [In the case of type error](#in-the-case-of-type-error) - [Dotted keys](#dotted-keys) - [Casting a toml value](#casting-a-toml-value) - [Checking value type](#checking-value-type) - [More about conversion](#more-about-conversion) - - [Getting an array](#getting-an-array) - - [Getting a table](#getting-a-table) + - [Converting an array](#converting-an-array) + - [Converting a table](#converting-a-table) - [Getting an array of tables](#getting-an-array-of-tables) - [Cost of conversion](#cost-of-conversion) - - [Getting datetime and its variants](#getting-datetime-and-its-variants) + - [Converting datetime and its variants](#converting-datetime-and-its-variants) - [Getting with a fallback](#getting-with-a-fallback) - [Expecting conversion](#expecting-conversion) - [Visiting a toml::value](#visiting-a-tomlvalue) @@ -67,7 +67,6 @@ int main() - [TOML literal](#toml-literal) - [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types) - [Formatting user-defined error messages](#formatting-user-defined-error-messages) -- [Getting comments related to a value](#getting-comments) - [Serializing TOML data](#serializing-toml-data) - [Underlying types](#underlying-types) - [Breaking Changes from v2](#breaking-changes-from-v2) @@ -710,7 +709,7 @@ const auto value = toml::expect(data.at("number")) }).unwrap_or(/*default value =*/ 3.14); ``` -## Visiting toml::value +## Visiting a toml::value toml11 provides `toml::visit` to apply a function to `toml::value` in the same way as `std::variant`.