-
Notifications
You must be signed in to change notification settings - Fork 300
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
Сазонов Александр #233
base: master
Are you sure you want to change the base?
Сазонов Александр #233
Changes from 11 commits
ee8842e
f19c836
cd5dc04
be46adb
79d1e65
e149587
f8e12c2
dc503e0
aee3615
c17136a
3bbe844
f1068d7
fd6a1a0
4a6be5d
f0429ab
65119ec
64c2a3f
e9f8459
1867fad
0c49358
1e36da5
7955386
5090645
6bf34a4
4ed3d1f
288342e
4a64ed2
e38afe3
a176465
ff1b502
4a8f2b4
498c754
5d67ab8
ee04ac4
f921258
3fb6a79
80fcee3
f8f5d84
93a160f
954e5c0
b66c900
d13d24a
751f4ff
e455978
c59dd5e
1aadbc9
91dd8ad
04644f3
4de72d8
dacaa2c
4f087ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Markdown.Html.Tags; | ||
|
||
namespace Markdown.Html; | ||
|
||
public class HtmlTagConverter | ||
{ | ||
private readonly IHtmlTag[] _htmlTags = | ||
[ | ||
new HeaderTag(), | ||
new BoldTag(), | ||
new ItalicTag() | ||
]; | ||
|
||
public string Convert(string tagContent, bool isClosedTag) | ||
{ | ||
foreach (var htmlTag in _htmlTags) | ||
{ | ||
var isConvertedToHtml = htmlTag.TryConvert(tagContent, isClosedTag, out var resultHtmlTag); | ||
|
||
if (isConvertedToHtml) | ||
return resultHtmlTag; | ||
} | ||
|
||
throw new ArgumentException($"{nameof(tagContent)} doesn't match to any html tag."); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Markdown.Html.Tags; | ||
|
||
public class BoldTag : IHtmlTag | ||
{ | ||
public bool TryConvert(string content, bool isClosedTag, out string resultContent) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Markdown.Html.Tags; | ||
|
||
public class HeaderTag : IHtmlTag | ||
{ | ||
public bool TryConvert(string content, bool isClosedTag, out string resultContent) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Markdown.Html.Tags; | ||
|
||
public interface IHtmlTag | ||
{ | ||
bool TryConvert(string content, bool isClosedTag, out string resultContent); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Markdown.Html.Tags; | ||
|
||
public class ItalicTag : IHtmlTag | ||
{ | ||
public bool TryConvert(string content, bool isClosedTag, out string resultContent) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Library</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using Markdown.Renderers; | ||
using Markdown.Tokens; | ||
|
||
namespace Markdown; | ||
|
||
public class Md | ||
{ | ||
private readonly IRenderer _renderer = new HtmlRenderer(); | ||
private readonly MarkdownTokenParser _tokenParser = new(); | ||
|
||
public string Render(string text) | ||
{ | ||
var tokens = _tokenParser.Parse(text); | ||
return _renderer.Render(tokens.ToArray()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System.Text; | ||
using Markdown.Html; | ||
using Markdown.Tokens; | ||
|
||
namespace Markdown.Renderers; | ||
|
||
public class HtmlRenderer : IRenderer | ||
{ | ||
private readonly HtmlTagConverter _tagConverter; | ||
|
||
public string Render(IList<MarkdownToken> tokens) | ||
{ | ||
var tokenBuilder = new StringBuilder(); | ||
|
||
foreach (var token in tokens) | ||
{ | ||
if (token.Type is TokenType.Tag) | ||
tokenBuilder.Append(_tagConverter.Convert(token.Content, token.IsClosedTag)); | ||
else | ||
tokenBuilder.Append(token.Content); | ||
} | ||
|
||
return tokenBuilder.ToString(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
using Markdown.Tokens; | ||
|
||
namespace Markdown.Renderers; | ||
public interface IRenderer | ||
{ | ||
string Render(IList<MarkdownToken> document); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace Markdown.Tokens; | ||
|
||
public class MarkdownToken(string content, TokenType type, bool isClosedTag = false) | ||
{ | ||
public string Content { get; } = content; | ||
public TokenType Type { get; } = type; | ||
public bool IsClosedTag { get; } = isClosedTag; | ||
|
||
public static bool TryGetTagToken(string str, out MarkdownToken resultToken) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public static MarkdownToken GetToken(string str) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
namespace Markdown.Tokens; | ||
|
||
public class MarkdownTokenParser | ||
{ | ||
public IEnumerable<MarkdownToken> Parse(string text) | ||
{ | ||
var lines = SplitIntoLines(text); | ||
return ParseLines(lines); | ||
} | ||
|
||
private static string[] SplitIntoLines(string text) | ||
{ | ||
return text.Split('\n', '\r'); | ||
} | ||
|
||
private IEnumerable<MarkdownToken> ParseLines(string[] lines) | ||
{ | ||
foreach (var line in lines) | ||
{ | ||
foreach (var token in ParseLine(line)) | ||
{ | ||
yield return token; | ||
} | ||
yield return MarkdownToken.GetToken("\n"); | ||
} | ||
} | ||
|
||
private static IEnumerable<MarkdownToken> ParseLine(string line) | ||
{ | ||
for (var i = 0; i < line.Length; i++) | ||
{ | ||
//TODO: ����� ����� ���������� ���������� ������ �� ������ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А что здесь написано? Какой кодировкой? Давай все оформлять в стандартной - UTF-8 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Здесь будет реализация парсинга строк на токены=) |
||
var currStr = line.Substring(i, 1); | ||
|
||
var isTagToken = MarkdownToken.TryGetTagToken(currStr, out var tagToken); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Раньше идея была работать с токенами абстрактно, сейчас, предполагаю, идея модернизировалась и теперь с текстом будет более плотное взаимодействие. К сожалению, я не нашел никаких сущностей, ответственных за md-теги, их обработку, логику и тд. Оттого есть подозрение, что логика их обработки будет или размазана, или храниться в одном классе потоком кода. Так делать точно не стоит) У нас ООП и DDD =) а еще всегда держим в голове SRP |
||
if (isTagToken) | ||
yield return tagToken; | ||
else | ||
yield return MarkdownToken.GetToken(currStr); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace Markdown.Tokens; | ||
|
||
public enum TokenType | ||
{ | ||
Tag, | ||
Text, | ||
NewLine, | ||
Space, | ||
Digit | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Markdown | ||
|
||
Напиши процессор упрощённого markdown-подобного языка разметки. | ||
|
||
[Спецификация языка разметки](MarkdownSpec.md). | ||
|
||
## Формат | ||
|
||
В fork-е этого репозитория создай проект Markdown и реализуй метод Render класса Md. Он принимает в качестве аргумента текст в markdown-подобной разметке, и возвращает строку с html-кодом этого текста согласно спецификации. | ||
|
||
Обрати внимание, что в этой задаче <ins>запрещено</ins> использовать регулярные выражения. | ||
|
||
## Важные моменты | ||
1. Проведи начальное проектирование: зафиксируй классы и их методы в коде (а также связи между классами), но не пиши внутренности методов | ||
2. Покажи декомпозицию наставнику, получи обратную связь | ||
3. После этого приступай к реализации методов, используя TDD | ||
4. Помни, твой алгоритм должен работать быстро — линейно или почти линейно от размера входа. Не забудь написать такой тест! | ||
|
||
## Оценка | ||
|
||
#### Минимальные требования (на 1 балл) | ||
1. Поддерживаются тэги `_`, `__` и `#` согласно спецификации | ||
2. Тесты | ||
|
||
#### Полное решение (на 2 балла) | ||
1. Выполнены минимальные требования | ||
2. Решение разбито на составные части, каждая из которых легко читается | ||
|
||
#### Максимальное решение (на 3 балла) | ||
1. Выполнено полное решение | ||
2. Умеет рендериться <ins>один</ins> из дополнительных тегов: | ||
- Маркерованный список | ||
- Нумерованный список | ||
- Ссылка | ||
- Картинка | ||
3. В файле [спецификации](MarkdownSpec.md) подробно описано, как работает новый тег | ||
4. Обрати внимание: если упадет читаемость кода, то дополнительный балл засчитан не будет! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Спецификация языка разметки | ||
|
||
Посмотрите этот файл в сыром виде. Сравните с тем, что показывает github. | ||
Все совпадения случайны ;) | ||
|
||
|
||
|
||
# Курсив | ||
|
||
Текст, _окруженный с двух сторон_ одинарными символами подчерка, | ||
должен помещаться в HTML-тег \<еm> вот так: | ||
|
||
Текст, \<еm>окруженный с двух сторон\</еm> одинарными символами подчерка, | ||
должен помещаться в HTML-тег \<еm>. | ||
|
||
|
||
|
||
# Полужирный | ||
|
||
__Выделенный двумя символами текст__ должен становиться полужирным с помощью тега \<strоng>. | ||
|
||
|
||
|
||
# Экранирование | ||
|
||
Любой символ можно экранировать, чтобы он не считался частью разметки. | ||
\_Вот это\_, не должно выделиться тегом \<еm>. | ||
|
||
Символ экранирования исчезает из результата, только если экранирует что-то. | ||
Здесь сим\волы экранирования\ \должны остаться.\ | ||
|
||
Символ экранирования тоже можно экранировать: \\_вот это будет выделено тегом_ \<еm> | ||
|
||
|
||
|
||
# Взаимодействие тегов | ||
|
||
Внутри __двойного выделения _одинарное_ тоже__ работает. | ||
|
||
Но не наоборот — внутри _одинарного __двойное__ не_ работает. | ||
|
||
Подчерки внутри текста c цифрами_12_3 не считаются выделением и должны оставаться символами подчерка. | ||
|
||
Однако выделять часть слова они могут: и в _нач_але, и в сер_еди_не, и в кон_це._ | ||
|
||
В то же время выделение в ра_зных сл_овах не работает. | ||
|
||
__Непарные_ символы в рамках одного абзаца не считаются выделением. | ||
|
||
За подчерками, начинающими выделение, должен следовать непробельный символ. Иначе эти_ подчерки_ не считаются выделением | ||
и остаются просто символами подчерка. | ||
|
||
Подчерки, заканчивающие выделение, должны следовать за непробельным символом. Иначе эти _подчерки _не считаются_ окончанием выделения | ||
и остаются просто символами подчерка. | ||
|
||
В случае __пересечения _двойных__ и одинарных_ подчерков ни один из них не считается выделением. | ||
|
||
Если внутри подчерков пустая строка ____, то они остаются символами подчерка. | ||
|
||
|
||
|
||
# Заголовки | ||
|
||
Абзац, начинающийся с "# ", выделяется тегом \<h1> в заголовок. | ||
В тексте заголовка могут присутствовать все прочие символы разметки с указанными правилами. | ||
|
||
Таким образом | ||
|
||
# Заголовок __с _разными_ символами__ | ||
|
||
превратится в: | ||
|
||
\<h1>Заголовок \<strоng>с \<еm>разными\</еm> символами\</strоng>\</h1> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
|
||
<IsPackable>false</IsPackable> | ||
<IsTestProject>true</IsTestProject> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="coverlet.collector" Version="6.0.0" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Все еще есть лишние подключения) |
||
<PackageReference Include="FluentAssertions" Version="6.12.2" /> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> | ||
<PackageReference Include="NUnit" Version="3.14.0" /> | ||
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" /> | ||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Markdown\Markdown.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Using Include="NUnit.Framework" /> | ||
</ItemGroup> | ||
|
||
</Project> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Кстати) давай попробуем анемичные модели данных. Т.е. оставлять объекты описательными, а все методы над ними выносить в самостоятельные классы. Зачем? Объект и бизнес-требования могут быть связаны сегодня, но нет гарантий, что завтра не появится бизнес-требование v2 или v3, а объект почти наверняка останется тот же. Также можно рассмотреть через SRP-призму: в текущем классе две ответственности
И следует стараться оставлять в классе только одну причину для изменений