Skip to content

Commit

Permalink
Merge pull request #2 from StuffOfInterest/feature-foreach
Browse files Browse the repository at this point in the history
Feature foreach
  • Loading branch information
StuffOfInterest authored Apr 25, 2021
2 parents 3ec05c4 + 321eb52 commit 23640ac
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 17 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*.cs]

# CS0162: Unreachable code detected
dotnet_diagnostic.CS0162.severity = none
5 changes: 5 additions & 0 deletions LogicTagHelpers.Demo/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,10 @@ public IActionResult TestSwitch()
{
return View();
}

public IActionResult TestForeach()
{
return View();
}
}
}
1 change: 1 addition & 0 deletions LogicTagHelpers.Demo/Views/Home/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
<ul>
<li><a asp-action="TestIf">Test If</a></li>
<li><a asp-action="TestSwitch">Test Switch</a></li>
<li><a asp-action="TestForeach">Test Foreach</a></li>
</ul>
41 changes: 41 additions & 0 deletions LogicTagHelpers.Demo/Views/Home/TestForeach.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@{
var stringList = new[] { "one", "two", "three" };
var numberList = new[] { 1, 22, 333 };
var emptyList = new List<double>();
}

<h2>Test 1</h2>

@{ var foreachContext = new ForeachContext<string>(stringList); }
<foreach iterator="foreachContext">
<p>Should display @(foreachContext.Item).</p>
</foreach>

<h2>Test 2</h2>

@{ var foreachContext2 = new ForeachContext<int>(numberList); }
<foreach iterator="foreachContext2">
<p>Should display @(foreachContext2.Item).</p>
</foreach>

<h2>Test 3</h2>

<p>Should not display any additional content.</p>

@{ var foreachContext3 = new ForeachContext<double>(emptyList); }
<foreach iterator="foreachContext3">
<p>Should not display @(foreachContext3.Item).</p>
</foreach>

<h2>Test 4</h2>

@try
{
<foreach>
<p>Should not display.</p>
</foreach>
}
catch (Exception ex)
{
<p>Expected exception occurred: '@ex.Message'.</p>
}
16 changes: 8 additions & 8 deletions LogicTagHelpers.Demo/Views/Home/TestIf.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ catch (Exception ex)
<h2>Test 6</h2>
@try
{
<if condition="false">
<then>Should not display 1.</then>
<then>Should not display 2.</then>
</if>
<if condition="false">
<then>Should not display 1.</then>
<then>Should not display 2.</then>
</if>
}
catch (Exception ex)
{
Expand All @@ -49,10 +49,10 @@ catch (Exception ex)
<h2>Test 7</h2>
@try
{
<if condition="false">
<else>Should not display 1.</else>
<else>Should not display 2.</else>
</if>
<if condition="false">
<else>Should not display 1.</else>
<else>Should not display 2.</else>
</if>
}
catch (Exception ex)
{
Expand Down
10 changes: 10 additions & 0 deletions LogicTagHelpers.Tests/CreateClassTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,15 @@ public void CanCreateDefaultTagHelper()
// Assert
Assert.IsNotNull(result);
}

[TestMethod]
public void CanCreateForeachTagHelper()
{
// Act
var result = new ForeachTagHelper();

// Assert
Assert.IsNotNull(result);
}
}
}
56 changes: 56 additions & 0 deletions LogicTagHelpers.Tests/ForeachContextTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace LogicTagHelpers.Tests
{
[TestClass]
public class ForeachContextTests
{
[TestMethod]
public void CanGetFirstRecord()
{
// Arrange
var list = new[] {"one", "two", "three"};
var context = new ForeachContext<string>(list);

// Act
var result = context.LoadNext();

// Assert
Assert.IsTrue(result);
Assert.AreEqual("one", context.Item);
}

[TestMethod]
public void CanGetSecondRecord()
{
// Arrange
var list = new[] { "one", "two", "three" };
var context = new ForeachContext<string>(list);
context.LoadNext();

// Act
var result = context.LoadNext();

// Assert
Assert.IsTrue(result);
Assert.AreEqual("two", context.Item);
}

[TestMethod]
public void AfterLastRecordReturnsFalse()
{
// Arrange
var list = new[] { "one", "two" };
var context = new ForeachContext<string>(list);
context.LoadNext();
context.LoadNext();

// Act
var result = context.LoadNext();

// Assert
Assert.IsFalse(result);
Assert.AreEqual("two", context.Item);
}
}
}
13 changes: 7 additions & 6 deletions LogicTagHelpers.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31205.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogicTagHelpers", "LogicTagHelpers\LogicTagHelpers.csproj", "{D853F062-7102-4514-8AAD-A423A630C3E2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogicTagHelpers", "LogicTagHelpers\LogicTagHelpers.csproj", "{D853F062-7102-4514-8AAD-A423A630C3E2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{A7C8F405-9E36-4AD8-AECC-BEE7220B41B4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogicTagHelpers.Demo", "LogicTagHelpers.Demo\LogicTagHelpers.Demo.csproj", "{DE040CBB-9E3D-4D21-AD94-1C0262B5B513}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogicTagHelpers.Tests", "LogicTagHelpers.Tests\LogicTagHelpers.Tests.csproj", "{85652AC9-C0E4-4E21-87A7-BF6BE8D93E14}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C75224D3-C733-4CB8-A7C6-446EFF3196A6}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
.github\workflows\build-test-publish.yml = .github\workflows\build-test-publish.yml
.github\workflows\build-test.yml = .github\workflows\build-test.yml
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogicTagHelpers.Demo", "LogicTagHelpers.Demo\LogicTagHelpers.Demo.csproj", "{DE040CBB-9E3D-4D21-AD94-1C0262B5B513}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogicTagHelpers.Tests", "LogicTagHelpers.Tests\LogicTagHelpers.Tests.csproj", "{85652AC9-C0E4-4E21-87A7-BF6BE8D93E14}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
37 changes: 37 additions & 0 deletions LogicTagHelpers/ForeachContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Collections.Generic;

namespace LogicTagHelpers
{
/// <summary>
/// Generic implementation of a foreach context which can take any iterable object as a generic type.
/// </summary>
/// <typeparam name="T">Type of object to iterate over.</typeparam>
public class ForeachContext<T> : IForeachContext
{
public ForeachContext()
{
}

public ForeachContext(IEnumerable<T> items)
{
Collection = items;
}

private IEnumerator<T> _enumerator;

public IEnumerable<T> Collection { get; set; }
public T Item { get; set; }

public bool LoadNext()
{
var enumerator = _enumerator ??= Collection.GetEnumerator();
var result = enumerator.MoveNext();
if (result)
{
Item = enumerator.Current;
}

return result;
}
}
}
35 changes: 35 additions & 0 deletions LogicTagHelpers/ForeachTagHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace LogicTagHelpers
{
/// <summary>
/// Perform 'foreach' iteration over a set of data.
/// Inner content is rendered for each item in the iterator.
/// </summary>
[HtmlTargetElement("foreach")]
public class ForeachTagHelper : TagHelper
{
/// <summary>
/// Context which holds the collection to iterate over and a property for presenting the current item to the inner content.
/// </summary>
public IForeachContext Iterator { get; set; }

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (Iterator == null)
{
throw new LogicTagHelperException("Iterator may not be null.");
}

output.TagName = null;
output.Content.Clear();

while (Iterator.LoadNext())
{
var childContent = await output.GetChildContentAsync(false);
output.Content.AppendHtml(childContent);
}
}
}
}
11 changes: 11 additions & 0 deletions LogicTagHelpers/IForeachContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace LogicTagHelpers
{
/// <summary>
/// Context for 'foreach' tag helper which holds the collection to iterator over
/// and presents each item to the tag helper content.
/// </summary>
public interface IForeachContext
{
bool LoadNext();
}
}
9 changes: 7 additions & 2 deletions LogicTagHelpers/LogicTagHelpers.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>0.2.0</Version>
<Version>0.3.0</Version>
<Authors>Delbert Matlock</Authors>
<Company>Stuff Of Interest</Company>
<Product />
Expand All @@ -12,16 +12,21 @@
Done:
* if/then/else
* switch/case/default
* foreach

Future:
* foreach
* while
* for
* do</Description>
<PackageProjectUrl>https://github.com/StuffOfInterest/LogicTagHelpers</PackageProjectUrl>
<RepositoryUrl>https://github.com/StuffOfInterest/LogicTagHelpers</RepositoryUrl>
<LangVersion>8</LangVersion>
</PropertyGroup>

<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Razor" Version="2.2.0" />
</ItemGroup>
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
* else
* [switch](#switch)
* case
* [foreach](#foreach)

## Future Tags

* foreach
* while
* for
* do
Expand Down Expand Up @@ -53,3 +53,12 @@ Following line must be added to the `_ViewImports.cshtml` file for the logic tag
<default>(content to display if no value match)</default>
</switch>
```

### foreach

```cshtml
@{ var context = new ForeachContext<(type)>((values-of-type)); }
<foreach iterator="context">
(content to display for each item in collection)
</foreach>
```

0 comments on commit 23640ac

Please sign in to comment.