Code Monkey home page Code Monkey logo

tommy's Introduction

GitHub release (latest SemVer) Nuget

Tommy

Tommy is a single-file TOML reader and writer for C#.
This library is meant for small, cross-platform projects that want support the most .NET versions possible.

To use it, simply include Tommy.cs into your project and you're done!

Alternatively, you can obtain the prebuilt package from NuGet!

Features

  • Full implementation of TOML 1.0.0 spec.
  • Parser implemented with TextReader for simplicity and vast input support (i.e. string inputs with StringReader, streams via StreamReader, etc).
  • Parses TOML into a node-based structure that is similar to SimpleJSON.
  • Basic support for parsing and saving comments.
  • Supports .NET 3.5+, Mono, .NET Core!
  • Uses C# 9 syntax for smaller file size.
  • Small footprint (~41 KB compiled) compared to other similar C# libraries.
  • Performs well compared to other similar C# libraries (view benchmarks)

Extensions

Tommy includes only a reader and a writer. There exist a few additional extensions that you can use

Officially maintained

3rd party

How to use

Parsing TOML file

The TOML file:

title = "TOML Example"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00

[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
// Reference the Tommy namespace at the start of the file
using Tommy;


// Parse into a node
using(StreamReader reader = File.OpenText("configuration.toml"))
{
    // Parse the table
    TomlTable table = TOML.Parse(reader);

    Console.WriteLine(table["title"]);  // Prints "TOML Example"

    // You can check the type of the node via a property and access the exact type via As*-property
    Console.WriteLine(table["owner"]["dob"].IsDateTime)  // Prints "True"

    // You can also do both with C# 7 syntax
    if(table["owner"]["dob"] is TomlDate date)
        Console.WriteLine(date.OnlyDate); // Some types contain additional properties related to formatting

    // You can also iterate through all nodes inside an array or a table
    foreach(TomlNode node in table["database"]["ports"])
        Console.WriteLine(node);
}

Note that TOML.Parse is just a shorthand for creating a TOMLParser object and parsing it. In essence, TOML.Parse is just simply a wrapper for the following code block:

TomlTable table;
using(TOMLParser parser = new TOMLParser(reader))
    table = parser.Parse();

In some cases, you might want to write the snippet manually, since the TOML parser can contain some additional parsing options.

Catching parse errors

Tommy is an optimistic parser: when it encounters a parsing error, it does not stop the parsing process right away. Instead, Tommy logs all parsing errors and throws them as a single TomlParseException. In addition to parsing errors, the exception object also contains the partially parsed TOML file that you can still attempt to use at your own risk.

Here's an example of handling parsing errors:

TomlTable table;

try
{
    // Read the TOML file normally.
    table = TOML.Parse(reader);
} catch(TomlParseException ex) 
{
    // Get access to the table that was parsed with best-effort.
    table = ex.ParsedTable;

    // Handle syntax error in whatever fashion you prefer
    foreach(TomlSyntaxException syntaxEx in ex.SyntaxErrors)
        Console.WriteLine($"Error on {syntaxEx.Column}:{syntaxEx.Line}: {syntaxEx.Message}");
}

If you do not wish to handle exceptions, you can instead use TommyExtensions.TryParse().

Generating or editing a TOML file

Tommy supports implicit casting from most built-in types to make file generation easy.

// Reference the Tommy namespace at the start of the file
using Tommy;


// Generate a TOML file programmatically
TomlTable toml = new TomlTable 
{
    ["title"] = "TOML Example",
    // You can also insert comments before a node with a special property
    ["value-with-comment"] = new TomlString
    {
        Value = "Some value",
        Comment = "This is just some value with a comment"
    },
    // You don't need to specify a type for tables or arrays -- Tommy will figure that out for you
    ["owner"] = 
    {
        ["name"] = "Tom Preston-Werner",
        ["dob"] = DateTime.Now
    },
    ["array-table"] = new TomlArray 
    {
        // This is marks the array as a TOML array table
        IsTableArray = true,
        [0] = 
        {
            ["value"] = 10
        },
        [1] = 
        {
            ["value"] = 20
        }
    },
    ["inline-table"] = new TomlTable
    {
        IsInline = true,
        ["foo"] = "bar",
        ["bar"] = "baz",
        // Implicit cast from TomlNode[] to TomlArray
        ["array"] = new TomlNode[] { 1, 2, 3 }
    }
};


// You can also define the toml file (or edit the loaded file directly):
toml["other-value"] = 10;
toml["value with spaces"] = new TomlString 
{
    IsMultiline = true,
    Value = "This is a\nmultiline string"
};

// Write to a file (or any TextWriter)
// You can forcefully escape ALL Unicode characters by uncommenting the following line:
// TOML.ForceASCII = true;
using(StreamWriter writer = File.CreateText("out.toml"))
{
    toml.WriteTo(writer);
    // Remember to flush the data if needed!
    writer.Flush();
}

The above code outputs the following TOML file:

title = "TOML Example"
# This is just some value with a comment
value-with-comment = "Some value"
inline-table = { foo = bar, bar = baz, array = [ 1, 2, 3, ], }
other-value = 10
"value with spaces" = """This is a
multiline string"""

[owner]
name = "Tom Preston-Werner"
dob = 2019-02-28 22:08:56

[[array-table]]
value = 10

[[array-table]]
value = 20

Collapsed values

Tommy supports collapsed values (i.e. values with keys of the form foo.bar). For that, simply set the CollapseLevel property of a value node.
By default, the collapse level for each TOML node is 0, which means that the node will appear under the table you define it in. Setting collapse level one value higher will move the value one table higher in the hierarchy.

In other words, if you define the following table:

TomlTable table = new TomlTable {
    ["foo"] = new TomlTable {
        ["bar"] = new TomlTable {
            ["baz"] = new TomlString {
                Value = "Hello, world!"
            }
        }
    }
};

Will output the TOML file:

[foo.bar]
baz = "Hello, world!"

Adding CollapseLevel = 1 to foo.bar.baz will "collapse" the key by one level:

TomlTable table = new TomlTable {
    ["foo"] = new TomlTable {
        ["bar"] = new TomlTable {
            ["baz"] = new TomlString {
                CollapseLevel = 1, // Here we collapse the foo.bar.baz by one level
                Value = "Hello, world!"
            }
        }
    }
};
[foo]
bar.baz = "Hello, world!"

Some notes about the writer

  • The writer does not currently preserve the layout of the original document! This is to save size and keep things simple for now.
  • Check out Style info for information on what style Tommy uses to output TOML
  • The writer only uses basic strings for complex keys (i.e. no literal strings).

Optional extensions

In addition to main functionality, Tommy includes optional extensions located in TommyExtensions.cs. The file is a collection of various functions that you might find handy, like TOMLParser.TryParse.

To use the extensions, simply include the file in your project. The extension methods will appear in types they are defined for.

Tests

Tommy's parser is tested against toml-lang/compliance test suite with additions from pyrmont/toml-specs.

What's with the name?

Because TOML sounded like Tommy, hahaha

tommy's People

Contributors

bugproof avatar dezhidki avatar gibbed avatar js6pak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

tommy's Issues

TomlString doesn't allow specifying initial newline after delimiter

https://toml.io/en/v1.0.0#string

Multi-line basic strings are surrounded by three quotation marks on each side and allow newlines. A newline immediately following the opening delimiter will be trimmed. All other whitespace and newline characters remain intact.

Multi-line literal strings are surrounded by three single quotes on each side and allow newlines. Like literal strings, there is no escaping whatsoever. A newline immediately following the opening delimiter will be trimmed. All other content between the delimiters is interpreted as-is without modification.

I'd like a way to flag TomlString so it writes that initial newline. I'm currently working around the issue by manually inserting a newline.

Formatting Question?

I was just wondering if maybe I was doing something wrong because when I build my toml I get what I'm expecting but with extra line breaks. Can I configure my input differently to remove the extra line breaks between keys and tables?
TomlTable toml = new TomlTable
{
["table_1"] =
{
["key_1"] = "Value1",
["key_2"] = "Value2",
["key_3"] = "Value3",
["key_4"] = "Value4"
},
["table_2"] =
{
["instance_1"] =
{
["key_1"] = "Value1"
},
["instance_2"] =
{
["key_1"] = "Value1"
}
}
};

image

Besides that, I think you've got everything I need! Great Stuff!

How to edit a single item ?

Hi, First of all, thanks for this library. I would like to edit a single item in toml file. For example, in your toml file, how do i change "name" in "owner" section ?

Does this require a concrete class or can we set and get values directly?

I just looked at toml and I like the syntax mush more then json.
However I am looking for something like this in a toml library...

var tomlFile = new TomlFile(filepath);
tomlFile.Set<T>(T value); //create if doesn't exist and sets it
T value = tomlFile.Get<T>(); //gets the value or default.
tomlFile.Save(); //optional filepath

Is this supported if not how hard would it be to do?

Edit: btw the name and avatar of this library made me laugh.

Parsing creates zero-length comments for uncommented nodes

I've been working on an application which uses Tommy in order to modify and existing TOML file. The newly created file has no-content comments for every entry. Though I don't have time to track this down fully, it looks like the parser may transform an absence of a comment to a zero-length string.

Toml sub-section quotes

Test Code

TomlTable expectedNode = new TomlTable
{
    ["section"] = new TomlTable
    {
        ["sub.section"] = new TomlTable
        {
            ["foo"] = "foo",
            ["bar"] = "bar"
        }
    }
};

using (var sw = new StringWriter())
{
    expectedNode.WriteTo(sw);

    string result = sw.ToString();
}

Expected Result:

[section."sub.section"]
foo = "foo"
bar = "bar"

Actual Result:

[section.sub.section]
foo = "foo"
bar = "bar"

Additional notes:

  1. This problem really only happens if a . dot exists in the key.
  2. Deserialization works fine if the quotes are supplied in the section. Only serialization has a problem.

Using an indexer on Table result in error

Thank you for this nice peace of software!

I tried to get a row from a table by indexing it, this resulted in a null:

var settingsTable= tml["Einstellungen"].AsTable;
var tableRow= settingsTable[0];

There should be a possibility to use an indexer to get the key and its value, like an Dictionary returns it.
With strings this works fine, but integers results into null, but I expected to get something ๐Ÿ˜‰

I added this code to the TomlTable to fix this:

public new KeyValuePair<string, TomlNode> this[int index] { get { if (index > RawTable.Count) return new KeyValuePair<string, TomlNode>(); return RawTable.ElementAt(index); } set { if (index > RawTable.Count) return; RawTable[RawTable.ElementAt(index).Key] = value!.Value; } }

Unclosed strings don't throw TomlParseException

Sample code:

using var reader = new StringReader("items = [ 'first', 'second ]");
var table = TOML.Parse(reader);
foreach (var element in table["items"].Children.Select(e => e.AsString?.Value))
{
    Console.WriteLine($"<{element}>");
}

Notice the missing closing string (') after the second element.

Expected behavior: a TomlParseException is thrown.

Actual behavior: the toml string is parsed and the the following lines are printed on the console:

<first>
<second ]>

Note that parsing is also successful for simple key/value pairs with missing closing string: key = 'value. I think this input should also throw TomlParseException.

Toml.WriteTo Custom Output support

i wanna be able to output to a textbox or otherwise! please add this support or please guide me where. or how is already possible, thanks!

How to handle TomlLazy?

From the README and the code I can't quite surmise what TomlLazy is actually used for, but in my tests it seems that if I try to access a key that doesn't exist in a table, a TomlLazy is returned instead. Is there a way I can check if a key doesn't exist so I can handle that?

I have found problems with double backslashes

If a value contains double backslashes, the writing to the file is incorrect. To correct the problem I changed the function "Escape" like this:

case '\\':
 stringBuilder.Append(@"\\");  // Aggiunta la seconda barra da Marco
 break;

If a value ends with double backslashes, the reading is incorrect. To correct the problem I changed the function "ProcessQuotedValueCharacter" like this:

if (isNonLiteral && c == TomlSyntax.ESCAPE_SYMBOL)
  //if (next >= 0 && (char) next == quote) // Linea eliminata da Marco
     escaped = true;

If there is no newline at the end of the file, the last value remains dirty. To correct the problem I changed the function "ToTomlString" like this:

if (sectionableItems.Count == 0)
{
  tw.Flush();  // Line aggiunta da Marco
  return;
}

I'm probably not following the correct path to reporting bugs, but I'm new to github and don't understand English. So I apologize.
Ciao

Unable to create TOML configuration from stream

Microsoft provided API for reading from stream, but Tommy doesn't use it. I tried to add it to my project with minimal effort:

public class TomlStreamSource : StreamConfigurationSource
{
    public TomlStreamSource(Stream stream)
    {
        Stream = stream;
    }

    public override IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new TomlStreamConfigurationProvider(this);
    }
}

public class TomlStreamConfigurationProvider : StreamConfigurationProvider
{
    public TomlStreamConfigurationProvider(StreamConfigurationSource source) : base(source)
    {
    }

    public override void Load(Stream stream)
    {
        try
        {
            Data = TomlConfigurationFileParser.Parse(stream);
        }
        catch (TomlParseException e)
        {
            throw new FormatException("Could not parse the TOML stream.", e);
        }
    }
}

public static class ConfigurationBuilderExtensions
{
   public static IConfigurationBuilder AddTomlStream(
      this IConfigurationBuilder builder,
      Stream stream)
  {
      return builder.Add(new TomlStreamSource(stream));
  }
}

It should work except it won't as the TomlConfigurationFileParser class is internal. Is there a reason for that?

Deserialize directly to a class?

Hey there,
I was just wondering if it were possible to read/write a file directly to/from a class, or am I going to have to manually assign each field? I didn't specifically see anything about it when I looked, but just wanted to make sure I didn't miss it somewhere if the functionality exists.

Thanks,
-MH

Can we get node key name from itself?

Hi @dezhidki ,
Thank so much for this TOML parser library! It is awesome!
For now, each time working with TomlNode, I need to get its key name.
For example:

title="TOML file"
[dataconfig]
     name="abc"

I can get TomlTable by:

var table_node = config["dataconfig"]
### Now how can i get "dataconfig" key name from table_node?
### We can get it from parent of couse but i think it is better to have that key name inside node itself.

Thanks!

TomlArray serialization extra comma

Hi again! Again, keep up the great work!

When serializing a TomlArray, an extra comma is appended to the end of the array in some cases.

Expected Result: array = [ 1 ]

Actual Result: array = [ 1, ]

[TestMethod]
public void TestArrayConstruct()
{
    TomlArray tomlArray = new TomlArray();

    tomlArray.Add(new TomlInteger()
    {
        Value = 1
    });

    string expectedResult = @"array = [ 1 ]";

    var table = new TomlTable
    {
        ["array"] = tomlArray
    };

    StringBuilder sb = new StringBuilder();
    using (var sw = new StringWriter(sb))
    {
        table.ToTomlString(sw);
    }

    string actualResult = sb.ToString();

    Assert.AreEqual(expectedResult, actualResult);
}

ParseTests TestArrayParse and TestMultilineValueParse failure

This is a great project! Please keep it up!

I just want to note that TestArrayParse and TestMultilineValueParse will fail on Windows in some cases if there is a newline mismatch.

In these cases, the "input" variable has newlines encoded in the .CS file as \n but the tests check for equality with newlines encoded with \r\n. Aside from the newline mismatch, the tests work perfectly.

> dotnet test TommyTests
Microsoft (R) Build Engine version 16.4.0-preview-19529-02+0c507a29b for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Test run for C:\tommy\TommyTests\bin\Debug\net46\uMod.Tests.dll(.NETFramework,Version=v4.6)
Microsoft (R) Test Execution Command Line Tool Version 16.3.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...

A total of 1 test files matched the specified pattern.
  X TestArrayParse [61ms]
  Error Message:
   Assert.AreEqual failed. Expected:<Just to make sure
we still work as expected
because reasons>. Actual:<Just to make sure
we still work as expected
because reasons>.
  Stack Trace:
     at TommyTests.Utils.TomlNodesAreEqual(Assert assert, TomlNode expected, TomlNode actual, Boolean ignoreComments) in C:\tommy\TommyTests\Utils.cs:line 20
   at TommyTests.Utils.TomlNodesAreEqual(Assert assert, TomlNode expected, TomlNode actual, Boolean ignoreComments) in C:\tommy\TommyTests\Utils.cs:line 41
   at TommyTests.Utils.TomlNodesAreEqual(Assert assert, TomlNode expected, TomlNode actual, Boolean ignoreComments) in C:\tommy\TommyTests\Utils.cs:line 50
   at TommyTests.ParseTests.TestArrayParse() in C:\tommy\TommyTests\ParseTests.cs:line 338

  X TestMultilineValueParse [1ms]
  Error Message:
   Assert.AreEqual failed. Expected:<The first newline is
trimmed in raw strings.
  All other whitespace
  is preserved.
>. Actual:<The first newline is
trimmed in raw strings.
  All other whitespace
  is preserved.
>.
  Stack Trace:
     at TommyTests.Utils.TomlNodesAreEqual(Assert assert, TomlNode expected, TomlNode actual, Boolean ignoreComments) in C:\tommy\TommyTests\Utils.cs:line 20
   at TommyTests.Utils.TomlNodesAreEqual(Assert assert, TomlNode expected, TomlNode actual, Boolean ignoreComments) in C:\tommy\TommyTests\Utils.cs:line 50
   at TommyTests.ParseTests.TestMultilineValueParse() in C:\tommy\TommyTests\ParseTests.cs:line 561


Test Run Failed.
Total tests: 11
     Passed: 9
     Failed: 2

Thank you for considering this.

When saving an edited TOML file the last line is repeated to the next line corrupted

When i save an edited TOML file the last line is repeated to the next line and its corrupted. It does not always happen though. Sometimes it just creates a new empty line at the end for no reason.
This is how the TOML file should look like:

# Help & Documentation: blablablabla
# IMPORTANT: blablablabla
[General]
AuthKey = ""
Debug = false
Description = "Test server"
Map = "/levels/Desert_Flats/info.json"
MaxCars = 4
MaxPlayers = 2
Name = "BeamMP Server"
Port = 30814
Private = true
ResourceFolder = 'Resources'

This is how it sometimes looks like after writing stuff into it:

# Help & Documentation: blablablabla
# IMPORTANT: blablablabla
[General]
AuthKey = ""
Debug = false
Description = "Test server"
Map = "/levels/Desert_Flats/info.json"
MaxCars = 4
MaxPlayers = 2
Name = "SECOND BeamMP Server"
Port = 30814
Private = true
ResourceFolder = 'Resources'
   'Resources'  <-- HERE IS THE CORRUPTED LINE. Sometimes it can be rces' or es etc. Its always a piece of text from the last line.
EMTPY LINE HERE <--here is a random emtpy line

Write layout - "As flat as possible option"

I have read this:

The writer does not currently preserve the layout of the original document! This is to save size and keep things simple for now.

But I have a file with a lot of nested stuff.
For instance:

[date.1]
RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))(\\-|\\/| \\- )(?<Month>(0[1-9]|[1-9]|1[0-2]))(\\-|\\/| \\- )(?<Year>((20|19)\\d\\d))"
Priority = 1

[date.2]
RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))(\\.|\\s|)+(?<MonthText>(jan|feb|maa|apr|mei|jun|jul|aug|sep|okt|nov|dec)).{0,6}(\\.|\\s|)+(?<Year>((20|19)\\d\\d))"
Priority = 2

[date.3]
RegEx = "(?<MonthText>(jan|feb|maa|apr|mei|jun|jul|aug|sep|okt|nov|dec)).{0,6}(\\.|\\s)+(?<Year>((20|19)\\d\\d))"
Priority = 3

[date.4]
RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))\\.(?<Month>(0[1-9]|[1-9]|1[0-2]))\\.(?<Year>((20|19)\\d\\d))"
Priority = 4

[date.5]
RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))(\\-|\\/)(?<Month>(0[1-9]|[1-9]|1[0-2]))(\\-|\\/)(?<YearMod100>(0|1|2)\\d)"
Priority = 5

[date.6]
RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))\\s?(\\-|\\/| \\- )\\s?(?<Month>(0[1-9]|[1-9]|1[0-2]))\\s?(\\-|\\/| \\- )\\s?(?<Year>((20|19)\\d\\d))"
Priority = 6

[date.7]
RegEx = "(?<Year>((20|19)\\d\\d))(\\-|\\/| \\- |\\.)?(?<Month>(0[1-9]|[1-9]|1[0-2]))(\\-|\\/| \\- |\\.)?(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))"
Priority = 1

That will get pretty hard to use after saving:

date = { 1 = { RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))(\\-|\\/| \\- )(?<Month>(0[1-9]|[1-9]|1[0-2]))(\\-|\\/| \\- )(?<Year>((20|19)\\d\\d))", Priority = 1 }, 2 = { RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))(\\.|\\s|)+(?<MonthText>(jan|feb|maa|apr|mei|jun|jul|aug|sep|okt|nov|dec)).{0,6}(\\.|\\s|)+(?<Year>((20|19)\\d\\d))", Priority = 2 }, 3 = { RegEx = "(?<MonthText>(jan|feb|maa|apr|mei|jun|jul|aug|sep|okt|nov|dec)).{0,6}(\\.|\\s)+(?<Year>((20|19)\\d\\d))", Priority = 3 }, 4 = { RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))\\.(?<Month>(0[1-9]|[1-9]|1[0-2]))\\.(?<Year>((20|19)\\d\\d))", Priority = 4 }, 5 = { RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))(\\-|\\/)(?<Month>(0[1-9]|[1-9]|1[0-2]))(\\-|\\/)(?<YearMod100>(0|1|2)\\d)", Priority = 5 }, 6 = { RegEx = "(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))\\s?(\\-|\\/| \\- )\\s?(?<Month>(0[1-9]|[1-9]|1[0-2]))\\s?(\\-|\\/| \\- )\\s?(?<Year>((20|19)\\d\\d))", Priority = 6 }, 7 = { RegEx = "(?<Year>((20|19)\\d\\d))(\\-|\\/| \\- |\\.)?(?<Month>(0[1-9]|[1-9]|1[0-2]))(\\-|\\/| \\- |\\.)?(?<Day>(0[1-9]|[1-9]|[1-2][0-9]|[3][0-1]))", Priority = 1 } }

Would it be possible to introduce a flag during writing which will write the file as flat (or elaborate) as possible.
Meaning generating a [part] wherever possible ?

TomlArray populated with TomlString missing quotations

Hey! I've got another one.

When serializing a TomlArray with TomlString elements, the TomlStrings are serialized without quotation marks. The output is invalid, causing a TomlParseException when attempting to deserialize the TOML.

Expected Result: array = [ "hello world" ]

Actual Result: array = [ hello world, ]

[TestMethod]
public void TestArrayConstruct()
{
    TomlArray tomlArray = new TomlArray();

    tomlArray.Add(new TomlString()
    {
        Value = "hello world"
    });

    string expectedResult = @"array = [ ""hello world"" ]";

    var table = new TomlTable
    {
        ["array"] = tomlArray
    };

    StringBuilder sb = new StringBuilder();
    using (var sw = new StringWriter(sb))
    {
        table.ToTomlString(sw);
    }

    string actualResult = sb.ToString();

    Assert.AreEqual(expectedResult, actualResult);
}

Generated TOML file contains unwanted hashtags between every line

When i edit a TOML file and then write it back to the disk, for some reason it has hashtags between every line of a setting. I used the code from the README.MD to write the file.
For example this is how it should be:

# Help & Documentation: blablabalba
# IMPORTANT: blablabalba

[General]
AuthKey = ''
Debug = false
Description = 'BeamMP Default Description'
Map = '/levels/gridmap/info.json'
MaxCars = 2
MaxPlayers = 10
Name = 'BeamMP Server'
Port = 30814
Private = false
ResourceFolder = 'Resources'

This is how it is saved:

# Help & Documentation: blablabalba
# IMPORTANT: blablabalba

# 
[General]
# 
AuthKey = ''
# 
Debug = false
# 
Description = 'BeamMP Default Description'
# 
Map = '/levels/gridmap/info.json'
# 
MaxCars = 1
# 
MaxPlayers = 10
# 
Name = 'BeamMP New Server'
Port = 10
# 
Private = true
# 
ResourceFolder = 'Resources'

Different variable types in one array

If there are some variables with different types in one array, for example, foo=["bar",1.0,1], Tommy won't report this as an error. Is that a bug?

Tables that are not loaded inline as write inline

Considering a toml file like this that is valid:

[package]
authors = [ "me", "I", "myself" ]
name = "proj"
version = "0.0.1"

[profile.debug]
sanitizer = true
coverage = true

[profile.release]
sanitizer = false
coverage = false

[profile.debug-opt]

When it loaded and save, the toml is broken.
The example code :

using Tommy;

TomlTable table;

using(StreamReader reader = File.OpenText("file.toml"))
{
    table = TOML.Parse(reader);
}

using (var file = File.OpenWrite("save.toml"))
{
    using StreamWriter sw = new(file);
    table.WriteTo(sw);
}

The resulting toml file is not correct:

[package]
authors = [ "me", "I", "myself" ]
name = "proj"
version = "0.0.1"
profile = { debug = { sanitizer = true, coverage = true }, release = { sanitizer = false, coverage = false }, debug-opt = {} }

Table that are not inline in original, should not be inlined when writing it.

Nested inline TomlTable writes out of order

Consider:

var example = new Tommy.TomlTable
{
  ["a"] = new Tommy.TomlTable
  {
    IsInline = true,
    ["a"] = "foo",
    ["b"] = new Tommy.TomlTable
    {
      ["a"] = 1,
      ["b"] = 2,
      ["c"] = 3,
    },
    ["c"] = "bar"
  }
};

When written, this results in:

a = { a = "foo", c = "bar", b = { a = 1, b = 2, c = 3 } }

Rather than:

a = { a = "foo", b = { a = 1, b = 2, c = 3 }, c = "bar" }

I'm guessing this has something to do with TomlTable.CollectCollapsedItems but I'm not certain.

Parse from a string rather than a file

Hi,

I need to parse a string representing a toml file. Tommy seems to only be able to read from a file from what I've seen. Is this right, or did I miss something?

Configuration binding of array leads to duplicate values

With configuration binding I see array values being duplicated.

With an app.toml file containing

[Logging]

[Logging.Sql]

[Logging.Email]
To = ['email1', 'email2']

config types

public record AppConfig(string ServiceName, LoggingConfig Logging)
{
    public AppConfig() : this(ServiceName: "AppName", Logging: new()) { }
}

public record LoggingConfig
{
    public LoggingEmailConfig? Email { get; set; }
}

public record LoggingEmailConfig(string[] To) { }

and setup

configurationManager.AddTomlFile("app.toml", optional: false, reloadOnChange: false);
var config = configurationManager..Get<AppConfig>();

config.Email.To now contains ["email1", "email2", "email1", "email2"] instead of ["email1", "email2"].

(I dropped unrelated properties and values from the types and toml to simplify the example.)

Unable to write all nodes inside an array or a table

using(StreamReader reader = File.OpenText("configuration.toml"))

{
TomlTable table = TOML.Parse(reader);
foreach(TomlNode node in table["database"]["ports"])
Console.WriteLine(node);
}
There is a problem,
CS0121: The call is ambiguous between the following methods or properties: 'Console.WriteLine(bool)' and 'Console.WriteLine(int)'

Won't generete the file as "toml" doesn't exist in the current context.

I'm trying to use "Tommy" as the toml parser/writer for my C# project. When creating a toml file, it won't generate as the toml namespace or class doesn't exist in the current context.

using System.IO;
using Tommy;

// later down the code

TomlTable meta = new TomlTable {
	// tait metadata
	["game title"] = name,
	["game author"] = author,
	["strings"] = {},
	["numbers"] = {},
	["switches"] = {}
};

using(StreamWriter writer = new StreamWriter(File.OpenWrite("bin/metadata.toml"))){
	toml.WriteTo(writer); // < error
	// Remember to flush the data if needed!
	writer.Flush();
}

unable to load numbers without decimal places as double

All numbers without decimal places are automatically loaded as integers which makes the implicit cast to double impossible.
The only way around is an abomination like this:

double value = _tomlFile["myFloatVal"].IsInteger ? (int)_tomlFile["myFloatVal"] : _tomlFile["myFloatVal"];

Otherwise the implicit operator double(TomlNode value) => value.AsFloat.Value; will throw an exception.

Is there really no way around this?

I am using .net 6.0 and the Tommy 3.1.2 NuGet package.

TommyExtensions MergeWith when using mergeNewValues bugged

if (tbl.TryGetNode(keyValuePair.Key, out var node))
node.MergeWith(keyValuePair.Value, mergeNewValues);
else if (mergeNewValues)
tbl[keyValuePair.Key] = node;

When the node isn't present (ie, TryGetNode fails) and mergeNewValues is true, it then assigns node. node at this point is null, resulting in weird broken behavior that left me scratching my head. ๐Ÿ™‚

Probably need to assign keyValuePair.Value instead, or cloning it somehow?

String value is returned with quotes

Is this intentional? I have to use trim to get the value I expected.
((String)config["my"]["key"]).Trim('"')

Thanks for the minimalist library that gets the job done!

Version Compliance

I came across this lib because its listed here:
https://github.com/toml-lang/toml/wiki

It is listed as v0.5 compliant. If it is compliant with version 1.0, it would be nice if we could get the list updated.

If it's not compliant with 1.0, what would it take to make it compliant?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.