trackler 2.2.1.139 → 2.2.1.140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/tracks/csharp/exercises/matrix/Example.cs +1 -1
  4. data/tracks/csharp/exercises/matrix/Matrix.cs +2 -2
  5. data/tracks/csharp/exercises/matrix/MatrixTest.cs +41 -48
  6. data/tracks/csharp/exercises/twelve-days/Example.cs +17 -22
  7. data/tracks/csharp/exercises/twelve-days/README.md +0 -11
  8. data/tracks/csharp/exercises/twelve-days/TwelveDays.cs +3 -8
  9. data/tracks/csharp/exercises/twelve-days/TwelveDaysTest.cs +69 -56
  10. data/tracks/csharp/generators/Exercises/Matrix.cs +18 -0
  11. data/tracks/csharp/generators/Exercises/TwelveDays.cs +28 -0
  12. data/tracks/elm/docs/TESTS.md +3 -4
  13. data/tracks/erlang/config.json +8 -0
  14. data/tracks/erlang/exercises/pascals-triangle/README.md +64 -0
  15. data/tracks/erlang/exercises/pascals-triangle/rebar.config +30 -0
  16. data/tracks/erlang/exercises/pascals-triangle/src/example.erl +30 -0
  17. data/tracks/erlang/exercises/pascals-triangle/src/pascals_triangle.app.src +9 -0
  18. data/tracks/erlang/exercises/pascals-triangle/src/pascals_triangle.erl +8 -0
  19. data/tracks/erlang/exercises/pascals-triangle/test/pascals_triangle_tests.erl +51 -0
  20. data/tracks/fsharp/exercises/diffie-hellman/DiffieHellmanTest.fs +30 -50
  21. data/tracks/fsharp/exercises/yacht/YachtTest.fs +5 -1
  22. data/tracks/fsharp/generators/Generators.fs +53 -0
  23. data/tracks/go/config.json +12 -0
  24. data/tracks/go/exercises/markdown/.meta/gen.go +59 -0
  25. data/tracks/go/exercises/markdown/README.md +35 -0
  26. data/tracks/go/exercises/markdown/cases_test.go +59 -0
  27. data/tracks/go/exercises/markdown/example.go +70 -0
  28. data/tracks/go/exercises/markdown/markdown.go +66 -0
  29. data/tracks/go/exercises/markdown/markdown_test.go +21 -0
  30. data/tracks/python/exercises/crypto-square/README.md +23 -19
  31. data/tracks/python/exercises/yacht/yacht_test.py +4 -1
  32. data/tracks/swift/exercises/phone-number/Tests/PhoneNumberTests/PhoneNumberTests.swift +14 -14
  33. metadata +16 -2
@@ -0,0 +1,30 @@
1
+ %% Erlang compiler options
2
+ {erl_opts, [debug_info]}.
3
+
4
+ {deps, [{erl_exercism, "0.1.1"}]}.
5
+
6
+ {dialyzer, [
7
+ {warnings, [underspecs, no_return]},
8
+ {get_warnings, true},
9
+ {plt_apps, top_level_deps}, % top_level_deps | all_deps
10
+ {plt_extra_apps, []},
11
+ {plt_location, local}, % local | "/my/file/name"
12
+ {plt_prefix, "rebar3"},
13
+ {base_plt_apps, [stdlib, kernel, crypto]},
14
+ {base_plt_location, global}, % global | "/my/file/name"
15
+ {base_plt_prefix, "rebar3"}
16
+ ]}.
17
+
18
+ %% eunit:test(Tests)
19
+ {eunit_tests, []}.
20
+ %% Options for eunit:test(Tests, Opts)
21
+ {eunit_opts, [verbose]}.
22
+
23
+ %% == xref ==
24
+
25
+ {xref_warnings, true}.
26
+
27
+ %% xref checks to run
28
+ {xref_checks, [undefined_function_calls, undefined_functions,
29
+ locals_not_used, exports_not_used,
30
+ deprecated_function_calls, deprecated_functions]}.
@@ -0,0 +1,30 @@
1
+ -module(example).
2
+
3
+ -export([gen_pascals_triangle/1, test_version/0]).
4
+
5
+ gen_pascals_triangle(N) when N < 0 -> -1;
6
+ gen_pascals_triangle(0) -> [];
7
+ gen_pascals_triangle(N) ->
8
+ gen_pascals_triangle_helper(1, N, []).
9
+
10
+ gen_pascals_triangle_helper(Count, N, CurrentResult) ->
11
+ case Count > N of
12
+ true -> CurrentResult;
13
+ false ->
14
+ gen_pascals_triangle_helper(
15
+ Count + 1,
16
+ N,
17
+ CurrentResult ++ gen_next(CurrentResult))
18
+ end.
19
+
20
+ gen_next([]) -> [[1]];
21
+ gen_next(CurrentResult) ->
22
+ LastRowDropLast = lists:droplast(lists:last(CurrentResult)),
23
+ ReverseLastRowDropLast = lists:reverse(LastRowDropLast),
24
+ ZipList = lists:zipwith(
25
+ fun(X, Y) -> X + Y end,
26
+ LastRowDropLast,
27
+ ReverseLastRowDropLast),
28
+ [[1] ++ ZipList ++ [1]].
29
+
30
+ test_version() -> 1.
@@ -0,0 +1,9 @@
1
+ {application, pascals_triangle,
2
+ [{description, "exercism.io - pascals-triangle"},
3
+ {vsn, "0.0.1"},
4
+ {modules, []},
5
+ {registered, []},
6
+ {applications, [kernel,
7
+ stdlib]},
8
+ {env, []}
9
+ ]}.
@@ -0,0 +1,8 @@
1
+ -module(pascals_triangle).
2
+
3
+ -export([gen_pascals_triangle/1, test_version/0]).
4
+
5
+ gen_pascals_triangle(N) ->
6
+ undefined.
7
+
8
+ test_version() -> 1.
@@ -0,0 +1,51 @@
1
+ -module(pascals_triangle_tests).
2
+
3
+ -include_lib("erl_exercism/include/exercism.hrl").
4
+ -include_lib("eunit/include/eunit.hrl").
5
+
6
+
7
+ % test cases adapted from `x-common//canonical-data.json` @ version: 1.3.0
8
+
9
+ zero_row_test() ->
10
+ ?assertEqual([], pascals_triangle:gen_pascals_triangle(0)).
11
+
12
+ one_row_test() ->
13
+ ?assertEqual([[1]], pascals_triangle:gen_pascals_triangle(1)).
14
+
15
+ two_rows_test() ->
16
+ ?assertEqual([[1], [1, 1]], pascals_triangle:gen_pascals_triangle(2)).
17
+
18
+ three_rows_test() ->
19
+ ?assertEqual([[1], [1, 1], [1, 2, 1]], pascals_triangle:gen_pascals_triangle(3)).
20
+
21
+ four_rows_test() ->
22
+ ?assertEqual(
23
+ [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1]],
24
+ pascals_triangle:gen_pascals_triangle(4)).
25
+
26
+ five_rows_test() ->
27
+ ?assertEqual(
28
+ [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]],
29
+ pascals_triangle:gen_pascals_triangle(5)).
30
+
31
+ six_rows_test() ->
32
+ ?assertEqual(
33
+ [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]],
34
+ pascals_triangle:gen_pascals_triangle(6)).
35
+
36
+ ten_rows_test() ->
37
+ ?assertEqual(
38
+ [[1],
39
+ [1, 1],
40
+ [1, 2, 1],
41
+ [1, 3, 3, 1],
42
+ [1, 4, 6, 4, 1],
43
+ [1, 5, 10, 10, 5, 1],
44
+ [1, 6, 15, 20, 15, 6, 1],
45
+ [1, 7, 21, 35, 35, 21, 7, 1],
46
+ [1, 8, 28, 56, 70, 56, 28, 8, 1],
47
+ [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]],
48
+ pascals_triangle:gen_pascals_triangle(10)).
49
+
50
+ negative_rows_test() ->
51
+ ?assertEqual(-1, pascals_triangle:gen_pascals_triangle(-1)).
@@ -1,68 +1,48 @@
1
- // This file was created manually and its version is 1.0.0.
1
+ // This file was auto-generated based on version 1.0.0 of the canonical data.
2
2
 
3
3
  module DiffieHellmanTest
4
4
 
5
- open System.Numerics
6
-
7
- open Xunit
8
5
  open FsUnit.Xunit
6
+ open Xunit
9
7
 
10
8
  open DiffieHellman
11
9
 
12
10
  [<Fact>]
13
- let ``Private key in range`` () =
14
- let primeP = 23I
15
- let privateKeys = [for _ in 0 .. 10 -> privateKey primeP]
16
- privateKeys |> List.iter (fun x -> x |> should be (greaterThanOrEqualTo 1I))
17
- privateKeys |> List.iter (fun x -> x |> should be (lessThanOrEqualTo (primeP - 1I)))
11
+ let ``Private key is in range 1 .. p`` () =
12
+ let p = 7919I
13
+ let privateKeys = [for _ in 0 .. 10 -> privateKey p]
14
+ privateKeys |> List.iter (fun x -> x |> should be (greaterThan 1I))
15
+ privateKeys |> List.iter (fun x -> x |> should be (lessThan p))
18
16
 
19
- // Note: due to the nature of randomness, there is always a chance that this test fails
20
- // Be sure to check the actual generated values
21
- [<Fact(Skip = "Remove to run test")>]
22
- let ``Private key randomly generated`` () =
23
- let primeP = 7919I
24
- let privateKeys = [for _ in 0 .. 5 -> privateKey primeP]
25
- privateKeys.Length |> should equal <| List.length (List.distinct privateKeys)
26
-
27
17
  [<Fact(Skip = "Remove to run test")>]
28
- let ``Public key correctly calculated`` () =
29
- let primeP = 23I
30
- let primeG = 5I
31
- let privateKey = 6I
32
-
33
- let actual = publicKey primeP primeG privateKey
34
- actual |> should equal 8I
18
+ let ``Private key is random`` () =
19
+ let p = 7919I
20
+ let privateKeys = [for _ in 0 .. 10 -> privateKey p]
21
+ List.distinct privateKeys |> List.length |> should equal (List.length privateKeys)
35
22
 
36
23
  [<Fact(Skip = "Remove to run test")>]
37
- let ``Secret key correctly calculated`` () =
38
- let primeP = 23I
39
- let publicKey = 19I
24
+ let ``Can calculate public key using private key`` () =
25
+ let p = 23I
26
+ let g = 5I
40
27
  let privateKey = 6I
41
-
42
- let actual = secret primeP publicKey privateKey
43
- actual |> should equal 2I
28
+ publicKey p g privateKey |> should equal 8I
44
29
 
45
30
  [<Fact(Skip = "Remove to run test")>]
46
- let ``Secret key correctly calculated when using large primes`` () =
47
- let primeP = 120227323036150778550155526710966921740030662694578947298423549235265759593711587341037426347114541533006628856300552706996143592240453345642869233562886752930249953227657883929905072620233073626594386072962776144691433658814261874113232461749035425712805067202910389407991986070558964461330091797026762932543I
48
- let publicKey = 75205441154357919442925546169208711235485855904969178206313309299205868312399046149367516336607966149689640419216591714331722664409474612463910928128055994157922930443733535659848264364106037925315974095321112757711756912144137705613776063541350548911512715512539186192176020596861210448363099541947258202188I
49
- let privateKey = 2483479393625932939911081304356888505153797135447327501792696199190469015215177630758617902200417377685436170904594686456961202706692908603181062371925882I
50
- let expected = 70900735223964890815905879227737819348808518698920446491346508980461201746567735331455825644429877946556431095820785835497384849778344216981228226252639932672153547963980483673419756271345828771971984887453014488572245819864454136618980914729839523581263886740821363010486083940557620831348661126601106717071I
51
- let actual = secret primeP publicKey privateKey
52
- actual |> should equal expected
31
+ let ``Can calculate secret using other party's public key`` () =
32
+ let p = 23I
33
+ let theirPublicKey = 19I
34
+ let myPrivateKey = 6I
35
+ secret p theirPublicKey myPrivateKey |> should equal 2I
53
36
 
54
37
  [<Fact(Skip = "Remove to run test")>]
55
- let ``Test exchange`` () =
56
- let primeP = 23I
57
- let primeG = 5I
58
-
59
- let privateKeyA = privateKey primeP
60
- let privateKeyB = privateKey primeP
61
-
62
- let publicKeyA = publicKey primeP primeG privateKeyA
63
- let publicKeyB = publicKey primeP primeG privateKeyB
64
-
65
- let secretA = secret primeP publicKeyB privateKeyA
66
- let secretB = secret primeP publicKeyA privateKeyB
38
+ let ``Key exchange`` () =
39
+ let p = 23I
40
+ let g = 5I
41
+ let alicePrivateKey = privateKey p
42
+ let alicePublicKey = publicKey p g alicePrivateKey
43
+ let bobPrivateKey = privateKey p
44
+ let bobPublicKey = publicKey p g bobPrivateKey
45
+ let secretA = secret p bobPublicKey alicePrivateKey
46
+ let secretB = secret p alicePublicKey bobPrivateKey
47
+ secretA |> should equal secretB
67
48
 
68
- secretA |> should equal secretB
@@ -1,4 +1,4 @@
1
- // This file was auto-generated based on version 1.0.0 of the canonical data.
1
+ // This file was auto-generated based on version 1.1.0 of the canonical data.
2
2
 
3
3
  module YachtTest
4
4
 
@@ -59,6 +59,10 @@ let ``Full house three small, two big`` () =
59
59
  let ``Two pair is not a full house`` () =
60
60
  score Category.FullHouse [2; 2; 4; 4; 5] |> should equal 0
61
61
 
62
+ [<Fact(Skip = "Remove to run test")>]
63
+ let ``Four of a kind is not a full house`` () =
64
+ score Category.FullHouse [1; 4; 4; 4; 4] |> should equal 0
65
+
62
66
  [<Fact(Skip = "Remove to run test")>]
63
67
  let ``Yacht is not a full house`` () =
64
68
  score Category.FullHouse [2; 2; 2; 2; 2] |> should equal 0
@@ -431,6 +431,59 @@ type Diamond() =
431
431
  type DifferenceOfSquares() =
432
432
  inherit GeneratorExercise()
433
433
 
434
+ type DiffieHellman() =
435
+ inherit GeneratorExercise()
436
+
437
+ override __.RenderValue (canonicalDataCase, key, value) =
438
+ match canonicalDataCase.Property, value.Type with
439
+ | _, JTokenType.Integer ->
440
+ sprintf "%dI" (value.ToObject<int>())
441
+ | "keyExchange", _ ->
442
+ value.ToObject<string>().Replace(",", "").Replace("(", " ").Replace(")", "")
443
+ | _ ->
444
+ base.RenderValue(canonicalDataCase, key, value)
445
+
446
+ override __.RenderArrange canonicalDataCase =
447
+ let arrange = base.RenderArrange canonicalDataCase
448
+
449
+ match canonicalDataCase.Property with
450
+ | "privateKeyIsInRange" | "privateKeyIsRandom" ->
451
+ List.append arrange ["let privateKeys = [for _ in 0 .. 10 -> privateKey p]" ]
452
+ | _ -> arrange
453
+
454
+ override __.RenderAssert canonicalDataCase =
455
+ match canonicalDataCase.Property with
456
+ | "privateKeyIsInRange" ->
457
+ let greaterThan = canonicalDataCase.Expected.["greaterThan"].ToObject<int>()
458
+ let lessThan = canonicalDataCase.Expected.["lessThan"].ToObject<string>()
459
+
460
+ [ sprintf "privateKeys |> List.iter (fun x -> x |> should be (greaterThan %dI))" greaterThan;
461
+ sprintf "privateKeys |> List.iter (fun x -> x |> should be (lessThan %s))" lessThan ]
462
+ | "privateKeyIsRandom" ->
463
+ [ "List.distinct privateKeys |> List.length |> should equal (List.length privateKeys)" ]
464
+ | "keyExchange" ->
465
+ [ "secretA |> should equal secretB" ]
466
+ | _ -> base.RenderAssert canonicalDataCase
467
+
468
+ override __.MapCanonicalDataCase canonicalDataCase =
469
+ match canonicalDataCase.Property with
470
+ | "privateKeyIsInRange" | "privateKeyIsRandom" ->
471
+ { canonicalDataCase with Input = Map.add "p" (JToken.Parse("7919")) canonicalDataCase.Input }
472
+ | _ -> base.MapCanonicalDataCase canonicalDataCase
473
+
474
+ override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
475
+
476
+ override __.PropertiesUsedAsSutParameter canonicalDataCase =
477
+ match canonicalDataCase.Property with
478
+ | "publicKey" ->
479
+ ["p"; "g"; "privateKey"]
480
+ | "secret" ->
481
+ ["p"; "theirPublicKey"; "myPrivateKey"]
482
+ | "keyExchange" ->
483
+ ["p"; "g"; "alicePrivateKey"; "alicePublicKey"; "bobPrivateKey"; "bobPublicKey"; "secretA"; "secretB"]
484
+ | _ ->
485
+ base.PropertiesUsedAsSutParameter canonicalDataCase
486
+
434
487
  type Dominoes() =
435
488
  inherit GeneratorExercise()
436
489
 
@@ -1060,6 +1060,18 @@
1060
1060
  "unlocked_by": "tree-building",
1061
1061
  "uuid": "7aa53a27-4ff3-4891-809f-2af728eb55a0"
1062
1062
  },
1063
+ {
1064
+ "core": false,
1065
+ "difficulty": 4,
1066
+ "slug": "markdown",
1067
+ "topics": [
1068
+ "refactoring",
1069
+ "strings",
1070
+ "text_formatting"
1071
+ ],
1072
+ "unlocked_by": "twelve-days",
1073
+ "uuid": "a7469032-c4d0-4e15-aa0c-4e9f6588b4c8"
1074
+ },
1063
1075
  {
1064
1076
  "core": false,
1065
1077
  "difficulty": 4,
@@ -0,0 +1,59 @@
1
+ package main
2
+
3
+ import (
4
+ "log"
5
+ "text/template"
6
+
7
+ "../../../gen"
8
+ )
9
+
10
+ func main() {
11
+ t, err := template.New("").Parse(tmpl)
12
+ if err != nil {
13
+ log.Fatal(err)
14
+ }
15
+ var j js
16
+ if err := gen.Gen("markdown", &j, t); err != nil {
17
+ log.Fatal(err)
18
+ }
19
+ }
20
+
21
+ // The JSON structure we expect to be able to unmarshal into
22
+ type js struct {
23
+ Exercise string
24
+ Version string
25
+ Comments []string
26
+ Cases []oneCase
27
+ }
28
+
29
+ // Test cases
30
+ type oneCase struct {
31
+ Description string
32
+ Property string
33
+ Input struct {
34
+ Markdown string
35
+ }
36
+ Expected string
37
+ }
38
+
39
+ // Template to generate test cases.
40
+ var tmpl = `package markdown
41
+
42
+ {{.Header}}
43
+
44
+ {{range .J.Comments}}
45
+ // {{ . }}
46
+ {{end}}
47
+
48
+ var testCases = []struct {
49
+ description string
50
+ input string
51
+ expected string
52
+ }{ {{range .J.Cases}}
53
+ {
54
+ description: {{printf "%q" .Description}},
55
+ input: {{printf "%#v" .Input.Markdown}},
56
+ expected: {{printf "%#v" .Expected}},
57
+ },{{end}}
58
+ }
59
+ `
@@ -0,0 +1,35 @@
1
+ # Markdown
2
+
3
+ Refactor a Markdown parser.
4
+
5
+ The markdown exercise is a refactoring exercise. There is code that parses a
6
+ given string with [Markdown
7
+ syntax](https://guides.github.com/features/mastering-markdown/) and returns the
8
+ associated HTML for that string. Even though this code is confusingly written
9
+ and hard to follow, somehow it works and all the tests are passing! Your
10
+ challenge is to re-write this code to make it easier to read and maintain
11
+ while still making sure that all the tests keep passing.
12
+
13
+ It would be helpful if you made notes of what you did in your refactoring in
14
+ comments so reviewers can see that, but it isn't strictly necessary. The most
15
+ important thing is to make the code better!
16
+
17
+ ## Running the tests
18
+
19
+ To run the tests run the command `go test` from within the exercise directory.
20
+
21
+ If the test suite contains benchmarks, you can run these with the `-bench`
22
+ flag:
23
+
24
+ go test -bench .
25
+
26
+ Keep in mind that each reviewer will run benchmarks on a different machine, with
27
+ different specs, so the results from these benchmark tests may vary.
28
+
29
+ ## Further information
30
+
31
+ For more detailed information about the Go track, including how to get help if
32
+ you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about).
33
+
34
+ ## Submitting Incomplete Solutions
35
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,59 @@
1
+ package markdown
2
+
3
+ // Source: exercism/problem-specifications
4
+ // Commit: 9713d52 markdown: Apply new "input" policy
5
+ // Problem Specifications Version: 1.2.0
6
+
7
+ // Markdown is a shorthand for creating HTML from text strings.
8
+
9
+ var testCases = []struct {
10
+ description string
11
+ input string
12
+ expected string
13
+ }{
14
+ {
15
+ description: "parses normal text as a paragraph",
16
+ input: "This will be a paragraph",
17
+ expected: "<p>This will be a paragraph</p>",
18
+ },
19
+ {
20
+ description: "parsing italics",
21
+ input: "_This will be italic_",
22
+ expected: "<p><em>This will be italic</em></p>",
23
+ },
24
+ {
25
+ description: "parsing bold text",
26
+ input: "__This will be bold__",
27
+ expected: "<p><strong>This will be bold</strong></p>",
28
+ },
29
+ {
30
+ description: "mixed normal, italics and bold text",
31
+ input: "This will _be_ __mixed__",
32
+ expected: "<p>This will <em>be</em> <strong>mixed</strong></p>",
33
+ },
34
+ {
35
+ description: "with h1 header level",
36
+ input: "# This will be an h1",
37
+ expected: "<h1>This will be an h1</h1>",
38
+ },
39
+ {
40
+ description: "with h2 header level",
41
+ input: "## This will be an h2",
42
+ expected: "<h2>This will be an h2</h2>",
43
+ },
44
+ {
45
+ description: "with h6 header level",
46
+ input: "###### This will be an h6",
47
+ expected: "<h6>This will be an h6</h6>",
48
+ },
49
+ {
50
+ description: "unordered lists",
51
+ input: "* Item 1\n* Item 2",
52
+ expected: "<ul><li>Item 1</li><li>Item 2</li></ul>",
53
+ },
54
+ {
55
+ description: "With a little bit of everything",
56
+ input: "# Header!\n* __Bold Item__\n* _Italic Item_",
57
+ expected: "<h1>Header!</h1><ul><li><strong>Bold Item</strong></li><li><em>Italic Item</em></li></ul>",
58
+ },
59
+ }
@@ -0,0 +1,70 @@
1
+ package markdown
2
+
3
+ import (
4
+ "bytes"
5
+ "fmt"
6
+ "regexp"
7
+ )
8
+
9
+ type charType int
10
+
11
+ // used to keep track of which tag to close
12
+ const (
13
+ none charType = iota
14
+ hash
15
+ star
16
+ )
17
+
18
+ // Render translates markdown to HTML
19
+ func Render(markdown string) (html string) {
20
+ //first the easy one, via regexp substitution
21
+ reStrong := regexp.MustCompile("(__)(.*)(__)")
22
+ s := reStrong.ReplaceAll([]byte(markdown), []byte("<strong>$2</strong>"))
23
+ reEm := regexp.MustCompile("(_)(.*)(_)")
24
+ s = reEm.ReplaceAll(s, []byte("<em>$2</em>"))
25
+ //now manage <li> and <hN>
26
+ var output bytes.Buffer
27
+ starcount := 0
28
+ hcount := 0
29
+ needtoClose := none
30
+ for i := 0; i < len(s); i++ {
31
+ switch s[i] {
32
+ case '#':
33
+ for s[i] == '#' {
34
+ hcount++
35
+ i++
36
+ }
37
+ output.WriteString(fmt.Sprintf("<h%d>", hcount))
38
+ needtoClose = hash
39
+ case '*':
40
+ if starcount == 0 {
41
+ output.WriteString("<ul>")
42
+ }
43
+ i++
44
+ starcount++
45
+ output.WriteString("<li>")
46
+ needtoClose = star
47
+ case '\n':
48
+ if needtoClose == hash {
49
+ output.WriteString(fmt.Sprintf("</h%d>", hcount))
50
+ }
51
+ if needtoClose == star {
52
+ output.WriteString("</li>")
53
+ }
54
+
55
+ default:
56
+ output.WriteByte(s[i])
57
+
58
+ }
59
+ }
60
+ if starcount > 0 || hcount > 0 {
61
+ if needtoClose == hash {
62
+ output.WriteString(fmt.Sprintf("</h%d>", hcount))
63
+ }
64
+ if needtoClose == star {
65
+ output.WriteString("</li></ul>")
66
+ }
67
+ return output.String()
68
+ }
69
+ return fmt.Sprintf("<p>%s</p>", string(s))
70
+ }
@@ -0,0 +1,66 @@
1
+ package markdown
2
+
3
+ // implementation to refactor
4
+
5
+ import (
6
+ "fmt"
7
+ "strings"
8
+ )
9
+
10
+ // Render translates markdown to HTML
11
+ func Render(markdown string) string {
12
+ header := 0
13
+ markdown = strings.Replace(markdown, "__", "<strong>", 1)
14
+ markdown = strings.Replace(markdown, "__", "</strong>", 1)
15
+ markdown = strings.Replace(markdown, "_", "<em>", 1)
16
+ markdown = strings.Replace(markdown, "_", "</em>", 1)
17
+ pos := 0
18
+ list := 0
19
+ html := ""
20
+ for {
21
+ char := markdown[pos]
22
+ if char == '#' {
23
+ for char == '#' {
24
+ header++
25
+ pos++
26
+ char = markdown[pos]
27
+ }
28
+ html += fmt.Sprintf("<h%d>", header)
29
+ pos++
30
+ continue
31
+ }
32
+ if char == '*' {
33
+ if list == 0 {
34
+ html += "<ul>"
35
+ }
36
+ html += "<li>"
37
+ list++
38
+ pos += 2
39
+ continue
40
+ }
41
+ if char == '\n' {
42
+ if list > 0 {
43
+ html += "</li>"
44
+ }
45
+ if header > 0 {
46
+ html += fmt.Sprintf("</h%d>", header)
47
+ header = 0
48
+ }
49
+ pos++
50
+ continue
51
+ }
52
+ html += string(char)
53
+ pos++
54
+ if pos >= len(markdown) {
55
+ break
56
+ }
57
+ }
58
+ if header > 0 {
59
+ return html + fmt.Sprintf("</h%d>", header)
60
+ }
61
+ if list > 0 {
62
+ return html + "</li></ul>"
63
+ }
64
+ return "<p>" + html + "</p>"
65
+
66
+ }
@@ -0,0 +1,21 @@
1
+ package markdown
2
+
3
+ import "testing"
4
+
5
+ func TestMarkdown(t *testing.T) {
6
+ for _, test := range testCases {
7
+ if html := Render(test.input); html != test.expected {
8
+ t.Fatalf("FAIL: Render(%q) = %q, want %q.", test.input, html, test.expected)
9
+ }
10
+ t.Logf("PASS: %s\n", test.description)
11
+ }
12
+ }
13
+
14
+ func BenchmarkMarkdown(b *testing.B) {
15
+ // Benchmark time to parse all the test cases
16
+ for i := 0; i < b.N; i++ {
17
+ for _, test := range testCases {
18
+ Render(test.input)
19
+ }
20
+ }
21
+ }