Skip to content

Implement new concept exercise for extension methods #1585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f0f6eb5
concept/extension-methods docs
Sep 5, 2021
b488af6
calculator-extension code files
Sep 5, 2021
f704f69
calculator-extension docs
Sep 5, 2021
303d596
update list of implemented exercises
Sep 5, 2021
c6bf7eb
Update exercises/concept/calculator-extensions/CalculatorExtensions.c…
yzAlvin Sep 9, 2021
89ec8b9
Update concepts/extension-methods/introduction.md
yzAlvin Sep 9, 2021
2a12b5b
Update concepts/extension-methods/about.md
yzAlvin Sep 14, 2021
1479c38
improve documentation
Sep 14, 2021
542a0e0
log extension method exercise
Sep 14, 2021
48b3385
added log exercise to config.json
Sep 14, 2021
84ac2e3
instructions for exercise
Sep 14, 2021
0ec63b3
merge conflict
Sep 14, 2021
2a5dd8e
Update exercises/concept/log-analysis/.docs/instructions.md
yzAlvin Sep 16, 2021
add9d0c
Update exercises/concept/log-analysis/.docs/instructions.md
yzAlvin Sep 16, 2021
b7c8fff
Update exercises/concept/log-analysis/.docs/instructions.md
yzAlvin Sep 16, 2021
ddaae8b
Update exercises/concept/log-analysis/LogAnalysis.csproj
yzAlvin Sep 16, 2021
9f83ca5
Update exercises/concept/log-analysis/.meta/config.json
yzAlvin Sep 16, 2021
7f2a9fd
Update exercises/concept/log-analysis/.docs/introduction.md
yzAlvin Sep 16, 2021
22645de
Update exercises/concept/calculator-conundrum/CalculatorConundrum.cs
yzAlvin Sep 16, 2021
2b0cc06
Update exercises/concept/log-analysis/.docs/hints.md
yzAlvin Sep 22, 2021
24da38d
update docs
Sep 22, 2021
3770c25
update code files
Sep 22, 2021
5d458f1
Update exercises/concept/log-analysis/.docs/hints.md
yzAlvin Sep 23, 2021
22437c2
Update exercises/concept/log-analysis/.docs/hints.md
yzAlvin Sep 23, 2021
f0dd81e
Update exercises/concept/log-analysis/.docs/instructions.md
yzAlvin Sep 23, 2021
8520235
Update exercises/concept/log-analysis/LogAnalysis.cs
yzAlvin Sep 23, 2021
ec8c825
Update exercises/concept/log-analysis/.docs/instructions.md
yzAlvin Sep 23, 2021
5227af3
Update config.json
yzAlvin Sep 23, 2021
8e6c7fd
Update config.json
yzAlvin Sep 23, 2021
9771aeb
Update exercises/concept/log-analysis/.docs/instructions.md
yzAlvin Sep 23, 2021
30efa9d
Update exercises/concept/log-analysis/.docs/instructions.md
yzAlvin Sep 23, 2021
92155c9
Update instructions.md
yzAlvin Sep 23, 2021
240d946
Update Exemplar.cs
yzAlvin Sep 23, 2021
c788161
add mention of namespace import
Sep 25, 2021
152e084
add test case
Sep 25, 2021
18673bb
Update exercises/concept/log-analysis/.docs/instructions.md
yzAlvin Sep 29, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions concepts/extension-methods/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"blurb": "Extension methods allow you to add methods to existing types.",
"authors": [
"yzAlvin"
]
}
20 changes: 20 additions & 0 deletions concepts/extension-methods/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# About

[Extension methods][extension-methods] allow adding methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.

Extension methods are static methods, but they're called as if they were instance methods on the extended type. It achieves this by using `this` before the type, indicating the instance we put the `.` on is passed as the first parameter. For client code, there's no apparent difference between calling an extension method and the methods defined in a type.

```csharp
public static int WordCount(this string str)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to be a bit more explicit here and give the class a namespace, and then have a second code sample indicating another file that has a using statement for importing the extension method. That might make it a bit more explicit.

{
return str.Split().Length;
}

"Hello World".WordCount();
// => 2
```

A well-known example of extension methods are the [LINQ][linq] standard query operators that add query functionality to the existing IEnumerable types.

[linq]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/
[extension-methods]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
13 changes: 13 additions & 0 deletions concepts/extension-methods/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Introduction

Extension methods allow adding methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. They are defined as static methods but are called by using instance method syntax. Their first parameter is preceded by the 'this' modifier, and specifies which type the method operates on.

```csharp
public static int WordCount(this string str)
{
return str.Split().Length;
}

"Hello World".WordCount();
// => 2
```
6 changes: 6 additions & 0 deletions concepts/extension-methods/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods",
"description": "extension-methods"
}
]
11 changes: 11 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,17 @@
"overflow",
"integral-numbers"
]
},
{
"slug": "log-analysis",
"name": "Log Analysis",
"uuid": "4a940e54-eda8-4500-bcb2-25d83af01fb1",
"concepts": ["extension-methods"],
"prerequisites": [
"collections",
"strings",
"booleans"
]
}
],
"practice": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static int Division(int operand1, int operand2)
{
return operand1 / operand2;
}

public static int Multiplication(int operand1, int operand2)
{
return operand1 * operand2;
Expand Down
4 changes: 4 additions & 0 deletions exercises/concept/log-analysis/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Hints

All extension methods must be marked static
All extension methods must mark `this` for the first argument
35 changes: 35 additions & 0 deletions exercises/concept/log-analysis/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Instructions

In this exercise you will be adding extension-methods on the string type to make it easier to deal with logs. Extension-methods express intent of the code, make code more readable, and add common functionality.

The goal is to add extension-methods that abstract away the logic of finding out certain things about the log messages.

```csharp
var log = "[Error]: {Line 20} - 'Critical error found'";

log.WordCount(); // => returns 7

log.LogLevel(); // => returns "Error"

log.LogLine(); // => returns "20"

log.Truncate(10); // => returns "[Error]: {Line 20} - 'Critical error found'"

log.Truncate(5); // => returns "Error - 20"
```

## 1. Implement the extension method WordCount

Implement the `.Word()` method to return the total of all words in the string. A 'word' in this case is just any string separated by a space.

## 2. Implement the extension method LogLevel

Implement the `.LogLevel()` method to return the log level of the log string.

## 3. Implement the extension method LogLine

Implement the `.LogLine()` method to return the line the log occured at of the log string.

## 4. Implement the extension method Truncate

Implement the `.Truncate(int maxSize)` method to return the log message truncated to "loglevel - logline" if the message exceeds the maximum word count specified, otherwise return the original log message.
21 changes: 21 additions & 0 deletions exercises/concept/log-analysis/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Introduction

Extension methods allow adding methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.

```csharp
public static bool IsEven(this int number)
{
return number % 2 == 0;
}

int isEven = 3.IsEven();
// isEven == false

public static int WordCount(this string str)
{
return str.Split().Length;
}

int wordCount = "Hello World!".WordCount();
// wordCount == 2
```
18 changes: 18 additions & 0 deletions exercises/concept/log-analysis/.meta/Exemplar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

public static class LogAnalysis
{
public static int WordCount(this string log) =>
log.Split().Length;

public static string LogLevel(this string log) =>
log.Substring(log.IndexOf("[") + 1, log.IndexOf("]") - 1);

public static string LogLine(this string log) =>
log.Substring(log.IndexOf("{") + 6, log.IndexOf("}") - (log.IndexOf("{") + 6));

public static string Truncate(this string log, int maxSize) =>
log.WordCount() < maxSize
? log
: $"{log.LogLevel()} - {log.LogLine()}";
}
17 changes: 17 additions & 0 deletions exercises/concept/log-analysis/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"blurb": "Learn about extension-methods by analysing logs.",
"authors": [
"yzAlvin"
],
"files": {
"solution": [
"LogAnalysis.cs"
],
"test": [
"LogAnalysisTests.cs"
],
"exemplar": [
".meta/Exemplar.cs"
]
}
}
42 changes: 42 additions & 0 deletions exercises/concept/log-analysis/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Design

## Goal

The goal of this exercise is to teach the student the Concept of Extension Methods in C#.

## Learning objectives

- Know what extension methods are.
- Know how to define extension methods on reference and value types

## Out of scope

- Assemblies.

## Concepts

- `extension-methods`: know what extension methods are; know how to define extension methods on reference and value types.

## Prerequisites

- `classes`: know what instance methods are.
- `namespaces`: know what namespaces are; know how to import namespaces.
- `collections`: know what collections are.

## Resources to refer to

### Hints

- [Extension methods][extension-methods]: how to define extension methods.
- [Namespaces][namespaces]: how to define an import namespaces.
- [Collections][collections]: what a collections is.

### After

- [Extension methods][extension-methods]: how to define extension methods.
- [Namespaces][namespaces]: how to define an import namespaces.
- [Collections][collections]: what a collections is.

[extension-methods]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
[namespaces]: https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/types/namespaces
[collections]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/collections
24 changes: 24 additions & 0 deletions exercises/concept/log-analysis/LogAnalysis.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

public static class LogAnalysis
{
public static int WordCount(this string log)
{
throw new NotImplementedException("Please implement the WordCount() extension method for strings");
}

public static string LogLevel(this string log)
{
throw new NotImplementedException("Please implement the LogLevel() extension method for strings");
}

public static string LogLine(this string log)
{
throw new NotImplementedException("Please implement the LogLine() extension method for strings");
}

public static string Truncate(this string log, int maxSize)
{
throw new NotImplementedException("Please implement the Truncate() extension method for strings");
}
}
14 changes: 14 additions & 0 deletions exercises/concept/log-analysis/LogAnalysis.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="Exercism.Tests" Version="0.1.0-alpha" />
</ItemGroup>

</Project>
56 changes: 56 additions & 0 deletions exercises/concept/log-analysis/LogAnalysisTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Xunit;
using Exercism.Tests;
using System;

public class LogAnalysisTests
{
[Fact]
public void Word_count_of_words_in_log()
{
Assert.Equal(7, "[Error]: {Line 20} - 'Critical error found'".WordCount());
}

[Fact(Skip = "Remove this Skip property to run this test")]
public void Word_count_of_log_with_space_separated_non_alphabet()
{
Assert.Equal(6, "[Error]: {Line 3} - '; expected'".WordCount());
}

[Fact(Skip = "Remove this Skip property to run this test")]
public void Log_level_of_warning_log()
{
Assert.Equal("Warning", "[Warning]: {Line 11} - 'Trim will be deprecated soon'".LogLevel());
}

[Fact(Skip = "Remove this Skip property to run this test")]
public void Log_level_of_error_log()
{
Assert.Equal("Error", "[Error]: {Line 8} - '; expected'".LogLevel());
}

[Fact(Skip = "Remove this Skip property to run this test")]
public void Log_line_of_log_with_single_digit()
{
Assert.Equal("1", "[Warning]: {Line 1} - 'Trim will be deprecated soon'".LogLine());
}

[Fact(Skip = "Remove this Skip property to run this test")]
public void Log_line_of_log_of_log_with_mulitple_digits()
{
Assert.Equal("111", "[Warning]: {Line 111} - 'Trim will be deprecated soon'".LogLine());
}

[Fact(Skip = "Remove this Skip property to run this test")]
public void Truncate_log_does_not_change_log_with_less_than_10_characters()
{
var log = "[Warning]: {Line 9} - 'The library bogo is deprecated.'";
Assert.Equal("[Warning]: {Line 9} - 'The library bogo is deprecated.'", log.Truncate(10));
}

[Fact(Skip = "Remove this Skip property to run this test")]
public void Truncate_log_trims_log_with_more_than_10_words()
{
var log = "[Warning]: {Line 9} - 'The library bogo_sort is deprecated by really_quick_algorithm.'";
Assert.Equal("Warning - 9", log.Truncate(10));
}
}