trackler 2.2.1.139 → 2.2.1.140

Sign up to get free protection for your applications and to get access to all the features.
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
+ }