trackler 2.2.1.43 → 2.2.1.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/lens-person/description.md +1 -1
  4. data/problem-specifications/exercises/palindrome-products/description.md +5 -12
  5. data/problem-specifications/exercises/pascals-triangle/canonical-data.json +1 -7
  6. data/tracks/c/exercises/meetup/src/example.c +64 -60
  7. data/tracks/c/exercises/meetup/src/example.h +2 -2
  8. data/tracks/c/exercises/meetup/test/test_meetup.c +4 -4
  9. data/tracks/cfml/config.json +179 -169
  10. data/tracks/cfml/exercises/markdown/.meta/HINTS.md +0 -0
  11. data/tracks/cfml/exercises/markdown/Markdown.cfc +121 -0
  12. data/tracks/cfml/exercises/markdown/MarkdownTest.cfc +51 -0
  13. data/tracks/cfml/exercises/markdown/Solution.cfc +204 -0
  14. data/tracks/cfml/exercises/markdown/SolutionTest.cfc +7 -0
  15. data/tracks/cfml/exercises/markdown/TestRunner.cfc +103 -0
  16. data/tracks/cfml/exercises/markdown/box.json +8 -0
  17. data/tracks/cfml/exercises/markdown/index.cfm +37 -0
  18. data/tracks/csharp/exercises/dominoes/DominoesTest.cs +40 -45
  19. data/tracks/csharp/exercises/meetup/MeetupTest.cs +761 -83
  20. data/tracks/csharp/generators/Exercises/Dominoes.cs +33 -0
  21. data/tracks/csharp/generators/Exercises/Meetup.cs +46 -0
  22. data/tracks/csharp/generators/Output/FormattingExtensions.cs +11 -1
  23. data/tracks/csharp/generators/Output/TypesExtensions.cs +23 -0
  24. data/tracks/csharp/generators/Output/ValueFormatter.cs +70 -69
  25. data/tracks/dart/config.json +15 -3
  26. data/tracks/dart/exercises/word-count/README.md +18 -0
  27. data/tracks/dart/exercises/word-count/lib/example.dart +26 -0
  28. data/tracks/dart/exercises/word-count/lib/word_count.dart +3 -0
  29. data/tracks/dart/exercises/word-count/pubspec.lock +293 -0
  30. data/tracks/dart/exercises/word-count/pubspec.yaml +3 -0
  31. data/tracks/dart/exercises/word-count/test/word_count_test.dart +64 -0
  32. data/tracks/ecmascript/docs/INSTALLATION.md +4 -7
  33. data/tracks/elixir/exercises/hello-world/README.md +1 -26
  34. data/tracks/elixir/exercises/hello-world/example.exs +3 -7
  35. data/tracks/elixir/exercises/hello-world/hello_world.exs +3 -25
  36. data/tracks/elixir/exercises/hello-world/hello_world_test.exs +2 -13
  37. data/tracks/elixir/mix.lock +1 -1
  38. data/tracks/elm/config.json +11 -0
  39. data/tracks/elm/exercises/pascals-triangle/README.md +51 -0
  40. data/tracks/elm/exercises/pascals-triangle/Triangle.elm +1 -0
  41. data/tracks/elm/exercises/pascals-triangle/Triangle.example.elm +23 -0
  42. data/tracks/elm/exercises/pascals-triangle/elm-package.json +14 -0
  43. data/tracks/elm/exercises/pascals-triangle/package.json +14 -0
  44. data/tracks/elm/exercises/pascals-triangle/tests/Tests.elm +34 -0
  45. data/tracks/elm/exercises/pascals-triangle/tests/elm-package.json +16 -0
  46. data/tracks/fsharp/exercises/grade-school/GradeSchool.fs +2 -2
  47. data/tracks/fsharp/exercises/grade-school/GradeSchoolTest.fs +3 -2
  48. data/tracks/java/CONTRIBUTING.md +34 -0
  49. data/tracks/java/config.json +42 -6
  50. data/tracks/java/exercises/largest-series-product/src/main/java/LargestSeriesProductCalculator.java +7 -3
  51. data/tracks/java/exercises/matrix/src/main/java/Matrix.java +23 -0
  52. data/tracks/julia/config.json +11 -2
  53. data/tracks/julia/exercises/grains/README.md +33 -0
  54. data/tracks/julia/exercises/grains/example.jl +23 -0
  55. data/tracks/julia/exercises/grains/grains.jl +9 -0
  56. data/tracks/julia/exercises/grains/runtests.jl +27 -0
  57. data/tracks/lua/README.md +1 -1
  58. data/tracks/mips/exercises/octal/README.md +3 -8
  59. data/tracks/ocaml/exercises/palindrome-products/README.md +8 -14
  60. data/tracks/perl6/.travis.yml +7 -3
  61. data/tracks/perl6/bin/exercise-gen.pl6 +5 -1
  62. data/tracks/perl6/exercises/accumulate/README.md +0 -3
  63. data/tracks/perl6/exercises/accumulate/accumulate.t +9 -3
  64. data/tracks/perl6/exercises/all-your-base/README.md +1 -1
  65. data/tracks/perl6/exercises/all-your-base/all-your-base.t +23 -11
  66. data/tracks/perl6/exercises/all-your-base/example.yaml +1 -1
  67. data/tracks/perl6/exercises/allergies/README.md +0 -1
  68. data/tracks/perl6/exercises/allergies/allergies.t +22 -10
  69. data/tracks/perl6/exercises/anagram/anagram.t +22 -10
  70. data/tracks/perl6/exercises/atbash-cipher/README.md +2 -1
  71. data/tracks/perl6/exercises/atbash-cipher/atbash-cipher.t +22 -10
  72. data/tracks/perl6/exercises/binary/README.md +2 -0
  73. data/tracks/perl6/exercises/bob/bob.t +24 -11
  74. data/tracks/perl6/exercises/bob/example.yaml +2 -2
  75. data/tracks/perl6/exercises/clock/clock.t +22 -10
  76. data/tracks/perl6/exercises/flatten-array/README.md +1 -2
  77. data/tracks/perl6/exercises/flatten-array/example.yaml +1 -1
  78. data/tracks/perl6/exercises/flatten-array/flatten-array.t +23 -11
  79. data/tracks/perl6/exercises/grade-school/README.md +0 -1
  80. data/tracks/perl6/exercises/grade-school/grade-school.t +9 -3
  81. data/tracks/perl6/exercises/grains/README.md +0 -1
  82. data/tracks/perl6/exercises/grains/grains.t +22 -10
  83. data/tracks/perl6/exercises/hello-world/example.yaml +3 -3
  84. data/tracks/perl6/exercises/hello-world/hello-world.t +25 -12
  85. data/tracks/perl6/exercises/leap/README.md +1 -1
  86. data/tracks/perl6/exercises/leap/example.yaml +1 -1
  87. data/tracks/perl6/exercises/leap/leap.t +23 -11
  88. data/tracks/perl6/exercises/linked-list/README.md +10 -10
  89. data/tracks/perl6/exercises/linked-list/linked-list.t +9 -3
  90. data/tracks/perl6/exercises/luhn/README.md +7 -7
  91. data/tracks/perl6/exercises/luhn/luhn.t +22 -10
  92. data/tracks/perl6/exercises/phone-number/README.md +3 -2
  93. data/tracks/perl6/exercises/phone-number/phone-number.t +22 -10
  94. data/tracks/perl6/exercises/raindrops/raindrops.t +22 -10
  95. data/tracks/perl6/exercises/rna-transcription/rna-transcription.t +22 -10
  96. data/tracks/perl6/exercises/robot-name/robot-name.t +9 -3
  97. data/tracks/perl6/exercises/scrabble-score/README.md +3 -1
  98. data/tracks/perl6/exercises/scrabble-score/scrabble-score.t +22 -10
  99. data/tracks/perl6/exercises/space-age/README.md +2 -1
  100. data/tracks/perl6/exercises/space-age/space-age.t +22 -10
  101. data/tracks/perl6/exercises/trinary/README.md +1 -1
  102. data/tracks/perl6/exercises/word-count/README.md +1 -2
  103. data/tracks/perl6/exercises/word-count/word-count.t +22 -10
  104. data/tracks/perl6/exercises/wordy/README.md +0 -5
  105. data/tracks/perl6/exercises/wordy/wordy.t +22 -10
  106. data/tracks/perl6/templates/test.mustache +26 -15
  107. data/tracks/python/config.json +10 -0
  108. data/tracks/python/exercises/book-store/book_store.py +1 -1
  109. data/tracks/python/exercises/flatten-array/flatten_array.py +1 -1
  110. data/tracks/python/exercises/matrix/matrix.py +1 -1
  111. data/tracks/python/exercises/palindrome-products/palindrome_products.py +2 -2
  112. data/tracks/python/exercises/perfect-numbers/perfect_numbers.py +2 -2
  113. data/tracks/python/exercises/pythagorean-triplet/pythagorean_triplet.py +3 -3
  114. data/tracks/python/exercises/raindrops/raindrops.py +1 -1
  115. data/tracks/python/exercises/scale-generator/scale_generator.py +1 -1
  116. data/tracks/python/exercises/sieve/sieve.py +1 -1
  117. data/tracks/python/exercises/sublist/sublist.py +1 -1
  118. data/tracks/python/exercises/transpose/transpose.py +1 -1
  119. data/tracks/python/exercises/triangle/triangle.py +4 -1
  120. data/tracks/python/exercises/two-bucket/example.py +59 -0
  121. data/tracks/python/exercises/two-bucket/two_bucket.py +2 -0
  122. data/tracks/python/exercises/two-bucket/two_bucket_test.py +32 -0
  123. data/tracks/scheme/config.json +59 -89
  124. data/tracks/scheme/config/maintainers.json +11 -11
  125. data/tracks/sml/exercises/allergies/README.md +20 -5
  126. data/tracks/sml/exercises/allergies/allergies.sml +11 -14
  127. data/tracks/sml/exercises/allergies/example.sml +9 -9
  128. data/tracks/sml/exercises/allergies/test.sml +65 -129
  129. data/tracks/sml/exercises/allergies/testlib.sml +159 -0
  130. data/tracks/sml/exercises/hamming/README.md +21 -5
  131. data/tracks/sml/exercises/hamming/example.sml +14 -10
  132. data/tracks/sml/exercises/hamming/hamming.sml +4 -3
  133. data/tracks/sml/exercises/hamming/test.sml +55 -64
  134. data/tracks/sml/exercises/hamming/testlib.sml +159 -0
  135. data/tracks/typescript/config.json +15 -0
  136. data/tracks/typescript/exercises/linked-list/linked-list.test.ts +11 -11
  137. data/tracks/typescript/exercises/nth-prime/README.md +36 -0
  138. data/tracks/typescript/exercises/nth-prime/nth-prime.example.ts +28 -0
  139. data/tracks/typescript/exercises/nth-prime/nth-prime.test.ts +25 -0
  140. data/tracks/typescript/exercises/nth-prime/nth-prime.ts +0 -0
  141. data/tracks/typescript/exercises/nth-prime/package.json +36 -0
  142. data/tracks/typescript/exercises/nth-prime/tsconfig.json +22 -0
  143. data/tracks/typescript/exercises/nth-prime/tslint.json +127 -0
  144. data/tracks/typescript/exercises/nth-prime/yarn.lock +2305 -0
  145. data/tracks/typescript/exercises/prime-factors/README.md +1 -1
  146. data/tracks/typescript/exercises/prime-factors/prime-factors.test.ts +11 -11
  147. data/tracks/typescript/exercises/series/README.md +1 -1
  148. data/tracks/typescript/exercises/series/series.test.ts +11 -11
  149. data/tracks/typescript/img/icon.png +0 -0
  150. data/tracks/typescript/img/icon.svg +3 -8
  151. metadata +44 -2
File without changes
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Your implmentation of the Markdown exercise
3
+ */
4
+ component {
5
+
6
+ /**
7
+ * @returns
8
+ */
9
+ function parse(required string input) {
10
+
11
+ var lines = listToArray( arguments.input, chr( 10 ) );
12
+ var output = [];
13
+
14
+ var isInList = false;
15
+
16
+ for (var line in lines) {
17
+ var matches = reMatchNoCase( "^[##]+(.*)", line);
18
+ if ( matches.len() ) {
19
+ var hLevel = reMatchNoCase( "[##]+", matches[1])[1];
20
+ line = "<h#hLevel.len()#>" & trim( replace( matches[1], hLevel, "" ) ) & "</h#hLevel.len()#>";
21
+ }
22
+
23
+ matches = reMatchNoCase( "\*(.*)", line);
24
+ if ( matches.len() ) {
25
+ if ( !isInList ) {
26
+ isInList = true;
27
+ var isBold = false;
28
+ var isItalic = false;
29
+
30
+ var matches2 = reFindNoCase( "(.*)__(.*)__(.*)", matches[1], 0, true );
31
+ if ( matches2.len[1] ) {
32
+ var match1 = mid(line, matches2.pos[2], matches2.len[2]);
33
+ var match2 = mid(line, matches2.pos[3], matches2.len[3]);
34
+ var match3 = mid(line, matches2.pos[4], matches2.len[4]);
35
+ matches[1] = match1 & "<strong>" & match2 & "</strong>" & match3;
36
+ isBold = true;
37
+ }
38
+
39
+ var matches3 = reFindNoCase( "(.*)_(.*)_(.*)", matches[1], 0, true );
40
+ if ( matches3.len[1] ) {
41
+ var match1 = mid(line, matches3.pos[2], matches3.len[2]);
42
+ var match2 = mid(line, matches3.pos[3], matches3.len[3]);
43
+ var match3 = mid(line, matches3.pos[4], matches3.len[4]);
44
+ matches[1] = match1 & "<em>" & match2 & "</em>" & match3;
45
+ isItalic = true;
46
+ }
47
+
48
+ if ( isItalic || isBold ) {
49
+ line = "<ul><li>" & trim( replace( matches[1], "*", "", "all" ) ) & "</li>";
50
+ }
51
+ else {
52
+ line = "<ul><li><p>" & trim( replace( matches[1], "*", "", "all" ) ) & "</p></li>";
53
+ }
54
+
55
+ }
56
+ else {
57
+ var isBold = false;
58
+ var isItalic = false;
59
+
60
+ var matches2 = reFindNoCase( "(.*)__(.*)__(.*)", matches[1], 0, true );
61
+ if ( matches2.len[1] ) {
62
+ var match1 = mid(line, matches2.pos[2], matches2.len[2]);
63
+ var match2 = mid(line, matches2.pos[3], matches2.len[3]);
64
+ var match3 = mid(line, matches2.pos[4], matches2.len[4]);
65
+ matches[1] = match1 & "<strong>" & match2 & "</strong>" & match3;
66
+ isBold = true;
67
+ }
68
+
69
+ var matches3 = reFindNoCase( "(.*)_(.*)_(.*)", matches[1], 0, true );
70
+ if ( matches3.len[1] ) {
71
+ var match1 = mid(line, matches3.pos[2], matches3.len[2]);
72
+ var match2 = mid(line, matches3.pos[3], matches3.len[3]);
73
+ var match3 = mid(line, matches3.pos[4], matches3.len[4]);
74
+ matches[1] = match1 & "<em>" & match2 & "</em>" & match3;
75
+ isItalic = true;
76
+ }
77
+
78
+ if ( isItalic || isBold ) {
79
+ line = "<li>" & trim( replace( matches[1], "*", "", "all" ) ) & "</li>";
80
+ }
81
+ else {
82
+ line = "<li><p>" & trim( replace( matches[1], "*", "", "all" ) ) & "</p></li>";
83
+ }
84
+ }
85
+ }
86
+ else {
87
+ if ( isInList ) {
88
+ line = "</ul>" & line;
89
+ isInList = false;
90
+ }
91
+ }
92
+
93
+ if ( !reMatchNoCase( "<h|<ul|<p|<li", line ).len() ) {
94
+ line = "<p>#line#</p>";
95
+ }
96
+
97
+ var matches = reFindNoCase( "(.*)__(.*)__(.*)", line, 0, true );
98
+ if ( matches.len[1] ) {
99
+ var match1 = mid(line, matches.pos[2], matches.len[2]);
100
+ var match2 = mid(line, matches.pos[3], matches.len[3]);
101
+ var match3 = mid(line, matches.pos[4], matches.len[4]);
102
+ line = match1 & "<strong>" & match2 & "</strong>" & match3;
103
+ }
104
+
105
+ var matches = reFindNoCase( "(.*)_(.*)_(.*)", line, 0, true );
106
+ if ( matches.len[1] ) {
107
+ var match1 = mid(line, matches.pos[2], matches.len[2]);
108
+ var match2 = mid(line, matches.pos[3], matches.len[3]);
109
+ var match3 = mid(line, matches.pos[4], matches.len[4]);
110
+ line = match1 & "<em>" & match2 & "</em>" & match3;
111
+ }
112
+ output.append( line );
113
+ }
114
+ var html = arrayToList( output, "" );
115
+ if ( isInList ) {
116
+ html &= "</ul>";
117
+ }
118
+
119
+ return html;
120
+ }
121
+ }
@@ -0,0 +1,51 @@
1
+ component extends="testbox.system.BaseSpec" {
2
+
3
+ function beforeAll(){
4
+ SUT = createObject( 'Markdown' );
5
+ }
6
+
7
+ function run(){
8
+
9
+ describe( "My Markdown class", function(){
10
+
11
+ it( 'parses normal text as a paragraph', function(){
12
+ expect( SUT.parse( input='This will be a paragraph' ) ).toBe( '<p>This will be a paragraph</p>' );
13
+ });
14
+
15
+ it( 'parsing italics', function(){
16
+ expect( SUT.parse( input='_This will be italic_' ) ).toBe( '<p><em>This will be italic</em></p>' );
17
+ });
18
+
19
+ it( 'parsing bold text', function(){
20
+ expect( SUT.parse( input='__This will be bold__' ) ).toBe( '<p><strong>This will be bold</strong></p>' );
21
+ });
22
+
23
+ it( 'mixed normal, italics and bold text', function(){
24
+ expect( SUT.parse( input='This will _be_ __mixed__' ) ).toBe( '<p>This will <em>be</em> <strong>mixed</strong></p>' );
25
+ });
26
+
27
+ it( 'with h1 header level', function(){
28
+ expect( SUT.parse( input='## This will be an h1' ) ).toBe( '<h1>This will be an h1</h1>' );
29
+ });
30
+
31
+ it( 'with h2 header level', function(){
32
+ expect( SUT.parse( input='#### This will be an h2' ) ).toBe( '<h2>This will be an h2</h2>' );
33
+ });
34
+
35
+ it( 'with h6 header level', function(){
36
+ expect( SUT.parse( input='############ This will be an h6' ) ).toBe( '<h6>This will be an h6</h6>' );
37
+ });
38
+
39
+ it( 'unordered lists', function(){
40
+ expect( SUT.parse( input='* Item 1#chr( 10 )#* Item 2' ) ).toBe( '<ul><li><p>Item 1</p></li><li><p>Item 2</p></li></ul>' );
41
+ });
42
+
43
+ it( 'With a little bit of everything', function(){
44
+ expect( SUT.parse( input='## Header!#chr( 10 )#* __Bold Item__#chr( 10 )#* _Italic Item_' ) ).toBe( '<h1>Header!</h1><ul><li><strong>Bold Item</strong></li><li><em>Italic Item</em></li></ul>' );
45
+ });
46
+
47
+ });
48
+
49
+ }
50
+
51
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Here is an example solution for the Markdown exercise
3
+ */
4
+ component {
5
+
6
+ /**
7
+ * Parse markdown
8
+ *
9
+ * @input.hint markdown to parse
10
+ */
11
+ public string function parse(required string input) {
12
+
13
+ var lines = listToArray( arguments.input, chr( 10 ) );
14
+ var output = [];
15
+ var isInList = false;
16
+
17
+ for (var line in lines) {
18
+ line = parseHeader(line);
19
+ line = parseBold( line );
20
+ line = parseItalic( line );
21
+
22
+ line = parseList( line, isInList );
23
+ /* We are in a list if the line contains a list item and not the unordered list closing tag */
24
+ isInList = ( reFindNoCase("<li>", line ) && !reFindNoCase("</ul>", line ) );
25
+
26
+ line = parseParagraph( line );
27
+ output.append( line );
28
+ }
29
+
30
+ /* Just in case the last line was a list item */
31
+ if ( isInList ) {
32
+ output.append( "</ul>" );
33
+ }
34
+
35
+ var html = arrayToList( output, "" );
36
+ return html;
37
+
38
+ }
39
+
40
+ /**
41
+ *
42
+ * Parse html headers from markdown text
43
+ *
44
+ * @markdown.hint Markdown text to parse
45
+ *
46
+ */
47
+ private string function parseHeader( required string markdown ) {
48
+ /* Get the header number */
49
+ var headerNumber = reMatchNoCase( "^[##]+", arguments.markdown).len() ? reMatchNoCase( "^[##]+", arguments.markdown)[1].len() : 0;
50
+
51
+ if (headerNumber) {
52
+ var pattern = "^[##]+ (.*)";
53
+ var replacement = "<h#headerNumber#>\1</h#headerNumber#>";
54
+
55
+ var output = reReplaceNoCase( arguments.markdown, pattern, replacement);
56
+ }
57
+ else {
58
+ var output = arguments.markdown;
59
+ }
60
+
61
+ return output;
62
+ }
63
+
64
+ /**
65
+ *
66
+ * Parse a list
67
+ *
68
+ * @markdown.hint Markdown text to parse
69
+ * @isInList.hint Flag to indicate if currently parsing a list or not
70
+ *
71
+ */
72
+ private string function parseList(
73
+ required string markdown,
74
+ required boolean isInList
75
+ ) {
76
+
77
+ var output = arguments.markdown;
78
+
79
+ if ( isListItem( arguments.markdown ) ) {
80
+ if ( !arguments.isInList ) {
81
+ output = "<ul>" & parseListItem( output );
82
+ }
83
+ else {
84
+ output = parseListItem( output );
85
+ }
86
+ }
87
+ else if ( arguments.isInList ) {
88
+ output = "</ul>" & output;
89
+ }
90
+
91
+ return output;
92
+ }
93
+
94
+
95
+ /**
96
+ *
97
+ * Parse a paragraph
98
+ *
99
+ * @markdown.hint Markdown text to parse
100
+ *
101
+ */
102
+ private string function parseParagraph( required string markdown ) {
103
+
104
+ if ( !reMatchNoCase( "<h|<ul|<p|<li", arguments.markdown ).len() ) {
105
+ var output = "<p>#arguments.markdown#</p>";
106
+ }
107
+ else {
108
+ var output = arguments.markdown;
109
+ }
110
+
111
+ return output;
112
+ }
113
+
114
+ /**
115
+ *
116
+ * Wrap a list with <ul> tags
117
+ *
118
+ * @markdown.hint Markdown text to parse
119
+ *
120
+ */
121
+ private string function wrapList( required string markdown ) {
122
+ return "<ul>#arguments.markdown#</ul>";
123
+ }
124
+
125
+ /**
126
+ *
127
+ * Check if markdown is a list item
128
+ *
129
+ * @markdown.hint Markdown text to parse
130
+ *
131
+ */
132
+ public boolean function isListItem( required string markdown ) {
133
+ /* Use regex to determine if markdown is list item */
134
+ return ( reFindNoCase( "\* (.*)",arguments.markdown ) > 0 );
135
+ }
136
+
137
+
138
+ /**
139
+ *
140
+ * Parse a list item
141
+ *
142
+ * @markdown.hint Markdown text to parse
143
+ *
144
+ */
145
+ private string function parseListItem( required string markdown ) {
146
+
147
+ var pattern = "\* (.*)";
148
+ var replacement = "<li>\1</li>";
149
+ var output = reReplaceNoCase( arguments.markdown, pattern, replacement );
150
+
151
+ /* Add a p tag to item if no other tag is present */
152
+ if ( !reFindNoCase("<li><", output ) ) {
153
+ var pattern = "<li>(.*)</li>";
154
+ var replacement = "<li><p>\1</p></li>";
155
+ var output = reReplaceNoCase( output, pattern, replacement );
156
+ }
157
+
158
+ return output;
159
+ }
160
+
161
+
162
+ /**
163
+ *
164
+ * Parse bold text from markdown
165
+ *
166
+ * @markdown.hint Markdown text to parse
167
+ *
168
+ */
169
+ private string function parseBold( required string markdown ) {
170
+ return parseWithDelimiter( arguments.markdown, "__", "strong" );
171
+ }
172
+
173
+ /**
174
+ *
175
+ * Parse bold text from markdown
176
+ *
177
+ * @markdown.hint Markdown text to parse
178
+ *
179
+ */
180
+ private string function parseItalic( required string markdown ) {
181
+
182
+ return parseWithDelimiter( arguments.markdown, "_", "em" );
183
+ }
184
+
185
+ /**
186
+ *
187
+ * Utility function to replace markdown delimiter with their tag equivalent
188
+ *
189
+ * @markdown.hint Markdown to parse
190
+ * @delimiter.hint Markdown syntax to replace with tag i.e __
191
+ * @tag.hint HTML tag to replace it with. i.e <strong>
192
+ *
193
+ */
194
+ public any function parseWithDelimiter(
195
+ required string markdown,
196
+ required string delimiter,
197
+ required string tag
198
+ ) {
199
+ var pattern = "#arguments.delimiter#(.*)#arguments.delimiter#";
200
+ var replacement = "<#arguments.tag#>\1</#arguments.tag#>";
201
+
202
+ return reReplaceNoCase( arguments.markdown, pattern, replacement);
203
+ }
204
+ }
@@ -0,0 +1,7 @@
1
+ component extends="MarkdownTest" {
2
+
3
+ function beforeAll(){
4
+ SUT = createObject( 'Solution' );
5
+ }
6
+
7
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * I am a CommandBox task runner which you can use to test your implementation of this exercise against the
3
+ * provided test suite. To use me, open the CommandBox CLI and run this:
4
+ *
5
+ * CommandBox> task run TestRunner
6
+ *
7
+ * To start up a test watcher that will automatically rerun the test suite every time you save a file change, run this:
8
+ *
9
+ * CommandBox> task run TestRunner --watcher
10
+ *
11
+ */
12
+ component {
13
+
14
+ /**
15
+ * @solution Runs the tests against the solution
16
+ * @watcher Start up a file watch that re-runs the tests on file changes. Use Ctrl-C to stop
17
+ */
18
+ function run( boolean solution=false, boolean watcher=false ) {
19
+
20
+ ensureTestBox();
21
+
22
+ if( watcher ) {
23
+
24
+ // Tabula rasa
25
+ command( 'cls' ).run();
26
+
27
+ // Start watcher
28
+ watch()
29
+ .paths( '*.cfc' )
30
+ .inDirectory( getCWD() )
31
+ .withDelay( 500 )
32
+ .onChange( function() {
33
+
34
+ // Clear the screen
35
+ command( 'cls' )
36
+ .run();
37
+
38
+ // This is neccessary so changes to tests get picked up right away.
39
+ pagePoolClear();
40
+
41
+ runTests( solution );
42
+
43
+ } )
44
+ .start();
45
+
46
+ } else {
47
+ runTests( solution );
48
+ }
49
+
50
+ }
51
+
52
+ /**
53
+ * Make sure the TestBox framework is installed
54
+ */
55
+ private function ensureTestBox() {
56
+ var excerciseRoot = getCWD();
57
+ var testBoxRoot = excerciseRoot & '/testbox';
58
+
59
+ if( !directoryExists( testBoxRoot ) ) {
60
+
61
+ print.boldYellowLine( 'Installing some missing dependencies for you!' ).toConsole();
62
+ command( 'install' )
63
+ .inWorkingDirectory( excerciseRoot )
64
+ .run();
65
+ }
66
+
67
+ // Bootstrap TestBox framework
68
+ filesystemUtil.createMapping( '/testbox', testBoxRoot );
69
+ }
70
+
71
+ /**
72
+ * Invoke TestBox to run the test suite
73
+ */
74
+ private function runTests( boolean solution=false ) {
75
+
76
+ // Create TestBox and run the tests
77
+ testData = new testbox.system.TestBox()
78
+ .runRaw( directory = {
79
+ // Find all CFCs...
80
+ mapping = filesystemUtil.makePathRelative( getCWD() ),
81
+ // ... in this directory ...
82
+ recurse = false,
83
+ // ... whose name ends in "test"
84
+ filter = function( path ) {
85
+ return path.reFind( ( solution ? 'Solution' : '' ) & 'Test.cfc$' );
86
+ }
87
+ } )
88
+ .getMemento();
89
+
90
+ // Print out the results with ANSI formatting for the CLI
91
+ getInstance( 'CLIRenderer@testbox-commands' )
92
+ .render( print, testData, true );
93
+
94
+ print.toConsole();
95
+
96
+ // Set proper exit code
97
+ if( testData.totalFail || testData.totalError ) {
98
+ setExitCode( 1 );
99
+ }
100
+ }
101
+
102
+ }
103
+