Skip to content

Commit

Permalink
clean up and restructuring of the codebase.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sov3rain committed Oct 6, 2024
1 parent bf21952 commit 085e40d
Show file tree
Hide file tree
Showing 18 changed files with 127 additions and 99 deletions.
6 changes: 3 additions & 3 deletions Assets/Scripts/CSVExample.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Linq;
using Sov3rain;
using UniCSV;
using UnityEngine;

public class CSVExample : MonoBehaviour
Expand All @@ -27,14 +27,14 @@ private void Start()
LoadCSV(_usernamesCSV);
LoadCSV(_csvWithEmptyLines);

var users = CSVParser.ParseFromString<User>(_usernamesCSV.text).ToList();
var users = CsvParser.ParseFromString<User>(_usernamesCSV.text).ToList();
}

private void LoadCSV(TextAsset usernamesCsv)
{
try
{
var data = CSVParser.ParseFromString(usernamesCsv.text);
var data = CsvParser.ParseFromString(usernamesCsv.text);

Debug.Log($"Loaded {data.Count} rows from file");

Expand Down
76 changes: 4 additions & 72 deletions Assets/uni-csv/Runtime/CSVParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,12 @@
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using static Sov3rain.CSVParser.Delimiter;
using static UniCSV.Delimiter;

namespace Sov3rain
namespace UniCSV
{
public static class CSVParser
public static class CsvParser
{
private static readonly char[] COMMON_DELIMITERS = { ',', '\t', ';', '|' };

public enum Delimiter
{
Auto,
Comma,
Tab,
Semicolon,
Pipe
}

/// <summary>
/// Load CSV data from a specified path.
/// </summary>
Expand Down Expand Up @@ -112,7 +101,7 @@ public static List<List<string>> ParseFromString(
{
if (delimiter == Auto)
{
delimiter = DetectDelimiterFromContent(data);
delimiter = DelimiterUtils.DetectDelimiterFromContent(data);
}

ConvertToCrlf(ref data);
Expand Down Expand Up @@ -205,31 +194,6 @@ public static List<List<string>> ParseFromString(
return sheet;
}

private static Delimiter DetectDelimiterFromContent(string content)
{
if (string.IsNullOrWhiteSpace(content))
return Comma;

// Get the first non-empty line
var firstLine = content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
.FirstOrDefault(line => !string.IsNullOrWhiteSpace(line));

if (string.IsNullOrWhiteSpace(firstLine))
return Comma;

var delimiterCounts = COMMON_DELIMITERS
.ToDictionary(d => d, d => firstLine.Count(c => c == d));

var mostFrequentDelimiter = delimiterCounts
.OrderByDescending(kvp => kvp.Value)
.First();

if (mostFrequentDelimiter.Value <= 1)
return Comma;

return CharToDelimiter(mostFrequentDelimiter.Key);
}

private static bool IsRowNonEmpty(List<string> row) =>
row.Count > 0 &&
row.Any(cell => !string.IsNullOrWhiteSpace(cell));
Expand All @@ -251,24 +215,6 @@ private static void ConvertToCrlf(ref string data)
data = Regex.Replace(data, @"\r\n|\r|\n", "\r\n");
}

private static char ToChar(this Delimiter delimiter) => delimiter switch
{
Comma => ',',
Tab => '\t',
Semicolon => ';',
Pipe => '|',
_ => throw new ArgumentException($"Unsupported delimiter: {delimiter}")
};

private static Delimiter CharToDelimiter(char delimiterChar) => delimiterChar switch
{
',' => Comma,
'\t' => Tab,
';' => Semicolon,
'|' => Pipe,
_ => Comma
};

private static object ConvertValue(string value, Type targetType)
{
if (string.IsNullOrWhiteSpace(value))
Expand All @@ -279,9 +225,6 @@ private static object ConvertValue(string value, Type targetType)
return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
}

if (string.IsNullOrWhiteSpace(value))
return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;

if (targetType == typeof(string))
return value;

Expand All @@ -303,15 +246,4 @@ private static object ConvertValue(string value, Type targetType)
throw new NotSupportedException($"Type {targetType} is not supported for conversion.");
}
}
}

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class CsvColumnAttribute : Attribute
{
public string Name { get; }

public CsvColumnAttribute(string name)
{
Name = name;
}
}
15 changes: 15 additions & 0 deletions Assets/uni-csv/Runtime/CsvColumnAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace UniCSV
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class CsvColumnAttribute : Attribute
{
public string Name { get; }

public CsvColumnAttribute(string name)
{
Name = name;
}
}
}
3 changes: 3 additions & 0 deletions Assets/uni-csv/Runtime/CsvColumnAttribute.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 63 additions & 0 deletions Assets/uni-csv/Runtime/Delimiter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Linq;
using static UniCSV.Delimiter;

namespace UniCSV
{
public enum Delimiter
{
Auto,
Comma,
Tab,
Semicolon,
Pipe
}

public static class DelimiterUtils
{
private static readonly char[] COMMON_DELIMITERS = { ',', '\t', ';', '|' };

public static Delimiter DetectDelimiterFromContent(string content)
{
if (string.IsNullOrWhiteSpace(content))
return Comma;

// Get the first non-empty line
var firstLine = content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
.FirstOrDefault(line => !string.IsNullOrWhiteSpace(line));

if (string.IsNullOrWhiteSpace(firstLine))
return Comma;

var delimiterCounts = COMMON_DELIMITERS
.ToDictionary(d => d, d => firstLine.Count(c => c == d));

var mostFrequentDelimiter = delimiterCounts
.OrderByDescending(kvp => kvp.Value)
.First();

if (mostFrequentDelimiter.Value <= 1)
return Comma;

return CharToDelimiter(mostFrequentDelimiter.Key);
}

public static char ToChar(this Delimiter delimiter) => delimiter switch
{
Comma => ',',
Tab => '\t',
Semicolon => ';',
Pipe => '|',
_ => throw new ArgumentException($"Unsupported delimiter: {delimiter}")
};

public static Delimiter CharToDelimiter(char delimiterChar) => delimiterChar switch
{
',' => Comma,
'\t' => Tab,
';' => Semicolon,
'|' => Pipe,
_ => Comma
};
}
}
3 changes: 3 additions & 0 deletions Assets/uni-csv/Runtime/Delimiter.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Assets/uni-csv/Runtime/Sov3rain.UniCSV.asmdef
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "Sov3rain.UniCSV"
}
3 changes: 0 additions & 3 deletions Assets/uni-csv/Runtime/Sov3rain.Unity-CSV.asmdef

This file was deleted.

8 changes: 4 additions & 4 deletions Assets/uni-csv/Tests/Editor/AttributeMappingTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Linq;
using NUnit.Framework;

namespace Sov3rain.Tests
namespace UniCSV.Tests
{
[TestFixture]
public class AttributeMappingTests
Expand Down Expand Up @@ -34,7 +34,7 @@ private class NullableTypesClass
public void ParseFromString_WithAttributes_MapsCorrectly()
{
string csvData = "FirstName,YearsOld,Country\nJohn,25,USA";
var result = CSVParser.ParseFromString<PersonWithAttributes>(csvData).ToList();
var result = CsvParser.ParseFromString<PersonWithAttributes>(csvData).ToList();

Assert.AreEqual(1, result.Count);
Assert.AreEqual("John", result[0].Name);
Expand All @@ -46,7 +46,7 @@ public void ParseFromString_WithAttributes_MapsCorrectly()
public void ParseFromString_WithAttributes_HandlesEmptyValues()
{
string csvData = "FirstName,YearsOld,Country\n,25,\nJane,,UK";
var result = CSVParser.ParseFromString<PersonWithAttributes>(csvData).ToList();
var result = CsvParser.ParseFromString<PersonWithAttributes>(csvData).ToList();

Assert.AreEqual(2, result.Count);

Expand All @@ -63,7 +63,7 @@ public void ParseFromString_WithAttributes_HandlesEmptyValues()
public void ParseFromString_HandlesNullableTypes()
{
string csvData = "Int,Decimal,String\n,,\nInvalid,Invalid,Value";
var result = CSVParser.ParseFromString<NullableTypesClass>(csvData).ToList();
var result = CsvParser.ParseFromString<NullableTypesClass>(csvData).ToList();

Assert.AreEqual(1, result.Count);
Assert.IsNull(result[0].NullableInt);
Expand Down
6 changes: 3 additions & 3 deletions Assets/uni-csv/Tests/Editor/BasicParsingTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using NUnit.Framework;

namespace Sov3rain.Tests
namespace UniCSV.Tests
{
[TestFixture]
public class BasicParsingTests
Expand All @@ -9,7 +9,7 @@ public class BasicParsingTests
public void ParseFromString_CommaDelimited_ReturnsCorrectData()
{
string csvData = "Name,Age,Location\nJohn,25,USA\nJane,30,UK";
var result = CSVParser.ParseFromString(csvData, delimiter: CSVParser.Delimiter.Comma);
var result = CsvParser.ParseFromString(csvData, delimiter: Delimiter.Comma);

Assert.AreEqual(2, result.Count);
Assert.AreEqual("John", result[0][0]);
Expand All @@ -21,7 +21,7 @@ public void ParseFromString_CommaDelimited_ReturnsCorrectData()
public void ParseFromString_EmptyFile_ReturnsEmptyList()
{
string csvData = "";
var result = CSVParser.ParseFromString(csvData);
var result = CsvParser.ParseFromString(csvData);

Assert.AreEqual(0, result.Count);
}
Expand Down
6 changes: 3 additions & 3 deletions Assets/uni-csv/Tests/Editor/DelimiterTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using NUnit.Framework;

namespace Sov3rain.Tests
namespace UniCSV.Tests
{
[TestFixture]
public class DelimiterTests
Expand All @@ -9,7 +9,7 @@ public class DelimiterTests
public void ParseFromString_AutoDetectDelimiter_SemicolonDelimited()
{
string csvData = "Name;Age;Location\nJohn;25;USA";
var result = CSVParser.ParseFromString(csvData);
var result = CsvParser.ParseFromString(csvData);

Assert.AreEqual(1, result.Count);
Assert.AreEqual("John", result[0][0]);
Expand All @@ -20,7 +20,7 @@ public void ParseFromString_AutoDetectDelimiter_SemicolonDelimited()
[TestCase("Name|Age|Location\nJohn|25|USA", TestName = "PipeDelimited")]
public void ParseFromString_AutoDetectDelimiter(string csvData)
{
var result = CSVParser.ParseFromString(csvData);
var result = CsvParser.ParseFromString(csvData);

Assert.AreEqual(1, result.Count);
Assert.AreEqual("John", result[0][0]);
Expand Down
4 changes: 2 additions & 2 deletions Assets/uni-csv/Tests/Editor/FileHandlingTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using NUnit.Framework;

namespace Sov3rain.Tests
namespace UniCSV.Tests
{
[TestFixture]
public class FileHandlingTests
Expand All @@ -9,7 +9,7 @@ public class FileHandlingTests
public void ParseFromPath_WithInvalidPath_ThrowsFileNotFoundException()
{
Assert.Throws<System.IO.FileNotFoundException>(() =>
CSVParser.ParseFromPath("nonexistent.csv"));
CsvParser.ParseFromPath("nonexistent.csv"));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Sov3rain.Unity-CSV.Editor.Tests",
"name": "Sov3rain.UniCSV.Editor.Tests",
"rootNamespace": "",
"references": [
"GUID:a386fc7f936fef84b8c99b8a1802f3b6",
Expand Down
2 changes: 1 addition & 1 deletion Assets/uni-csv/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "com.sov3rain.uni-csv",
"version": "1.1.0",
"version": "1.1.1",
"displayName": "Uni-CSV",
"description": "Lightweight and efficient CSV parser without dependencies.",
"unity": "2019.2",
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.1] - 2024-10-06

### Breaking changes

- Renamed the base namespace to `UniCSV`.

- Renamed the primary static class to `CsvParser`.

## Changed

- Moved some parts of the code to their own utility classes and files.

## [1.1.0] - 2024-10-06

### Added
Expand Down
Loading

0 comments on commit 085e40d

Please sign in to comment.