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.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/lens-person/description.md +1 -1
- data/problem-specifications/exercises/palindrome-products/description.md +5 -12
- data/problem-specifications/exercises/pascals-triangle/canonical-data.json +1 -7
- data/tracks/c/exercises/meetup/src/example.c +64 -60
- data/tracks/c/exercises/meetup/src/example.h +2 -2
- data/tracks/c/exercises/meetup/test/test_meetup.c +4 -4
- data/tracks/cfml/config.json +179 -169
- data/tracks/cfml/exercises/markdown/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/markdown/Markdown.cfc +121 -0
- data/tracks/cfml/exercises/markdown/MarkdownTest.cfc +51 -0
- data/tracks/cfml/exercises/markdown/Solution.cfc +204 -0
- data/tracks/cfml/exercises/markdown/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/markdown/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/markdown/box.json +8 -0
- data/tracks/cfml/exercises/markdown/index.cfm +37 -0
- data/tracks/csharp/exercises/dominoes/DominoesTest.cs +40 -45
- data/tracks/csharp/exercises/meetup/MeetupTest.cs +761 -83
- data/tracks/csharp/generators/Exercises/Dominoes.cs +33 -0
- data/tracks/csharp/generators/Exercises/Meetup.cs +46 -0
- data/tracks/csharp/generators/Output/FormattingExtensions.cs +11 -1
- data/tracks/csharp/generators/Output/TypesExtensions.cs +23 -0
- data/tracks/csharp/generators/Output/ValueFormatter.cs +70 -69
- data/tracks/dart/config.json +15 -3
- data/tracks/dart/exercises/word-count/README.md +18 -0
- data/tracks/dart/exercises/word-count/lib/example.dart +26 -0
- data/tracks/dart/exercises/word-count/lib/word_count.dart +3 -0
- data/tracks/dart/exercises/word-count/pubspec.lock +293 -0
- data/tracks/dart/exercises/word-count/pubspec.yaml +3 -0
- data/tracks/dart/exercises/word-count/test/word_count_test.dart +64 -0
- data/tracks/ecmascript/docs/INSTALLATION.md +4 -7
- data/tracks/elixir/exercises/hello-world/README.md +1 -26
- data/tracks/elixir/exercises/hello-world/example.exs +3 -7
- data/tracks/elixir/exercises/hello-world/hello_world.exs +3 -25
- data/tracks/elixir/exercises/hello-world/hello_world_test.exs +2 -13
- data/tracks/elixir/mix.lock +1 -1
- data/tracks/elm/config.json +11 -0
- data/tracks/elm/exercises/pascals-triangle/README.md +51 -0
- data/tracks/elm/exercises/pascals-triangle/Triangle.elm +1 -0
- data/tracks/elm/exercises/pascals-triangle/Triangle.example.elm +23 -0
- data/tracks/elm/exercises/pascals-triangle/elm-package.json +14 -0
- data/tracks/elm/exercises/pascals-triangle/package.json +14 -0
- data/tracks/elm/exercises/pascals-triangle/tests/Tests.elm +34 -0
- data/tracks/elm/exercises/pascals-triangle/tests/elm-package.json +16 -0
- data/tracks/fsharp/exercises/grade-school/GradeSchool.fs +2 -2
- data/tracks/fsharp/exercises/grade-school/GradeSchoolTest.fs +3 -2
- data/tracks/java/CONTRIBUTING.md +34 -0
- data/tracks/java/config.json +42 -6
- data/tracks/java/exercises/largest-series-product/src/main/java/LargestSeriesProductCalculator.java +7 -3
- data/tracks/java/exercises/matrix/src/main/java/Matrix.java +23 -0
- data/tracks/julia/config.json +11 -2
- data/tracks/julia/exercises/grains/README.md +33 -0
- data/tracks/julia/exercises/grains/example.jl +23 -0
- data/tracks/julia/exercises/grains/grains.jl +9 -0
- data/tracks/julia/exercises/grains/runtests.jl +27 -0
- data/tracks/lua/README.md +1 -1
- data/tracks/mips/exercises/octal/README.md +3 -8
- data/tracks/ocaml/exercises/palindrome-products/README.md +8 -14
- data/tracks/perl6/.travis.yml +7 -3
- data/tracks/perl6/bin/exercise-gen.pl6 +5 -1
- data/tracks/perl6/exercises/accumulate/README.md +0 -3
- data/tracks/perl6/exercises/accumulate/accumulate.t +9 -3
- data/tracks/perl6/exercises/all-your-base/README.md +1 -1
- data/tracks/perl6/exercises/all-your-base/all-your-base.t +23 -11
- data/tracks/perl6/exercises/all-your-base/example.yaml +1 -1
- data/tracks/perl6/exercises/allergies/README.md +0 -1
- data/tracks/perl6/exercises/allergies/allergies.t +22 -10
- data/tracks/perl6/exercises/anagram/anagram.t +22 -10
- data/tracks/perl6/exercises/atbash-cipher/README.md +2 -1
- data/tracks/perl6/exercises/atbash-cipher/atbash-cipher.t +22 -10
- data/tracks/perl6/exercises/binary/README.md +2 -0
- data/tracks/perl6/exercises/bob/bob.t +24 -11
- data/tracks/perl6/exercises/bob/example.yaml +2 -2
- data/tracks/perl6/exercises/clock/clock.t +22 -10
- data/tracks/perl6/exercises/flatten-array/README.md +1 -2
- data/tracks/perl6/exercises/flatten-array/example.yaml +1 -1
- data/tracks/perl6/exercises/flatten-array/flatten-array.t +23 -11
- data/tracks/perl6/exercises/grade-school/README.md +0 -1
- data/tracks/perl6/exercises/grade-school/grade-school.t +9 -3
- data/tracks/perl6/exercises/grains/README.md +0 -1
- data/tracks/perl6/exercises/grains/grains.t +22 -10
- data/tracks/perl6/exercises/hello-world/example.yaml +3 -3
- data/tracks/perl6/exercises/hello-world/hello-world.t +25 -12
- data/tracks/perl6/exercises/leap/README.md +1 -1
- data/tracks/perl6/exercises/leap/example.yaml +1 -1
- data/tracks/perl6/exercises/leap/leap.t +23 -11
- data/tracks/perl6/exercises/linked-list/README.md +10 -10
- data/tracks/perl6/exercises/linked-list/linked-list.t +9 -3
- data/tracks/perl6/exercises/luhn/README.md +7 -7
- data/tracks/perl6/exercises/luhn/luhn.t +22 -10
- data/tracks/perl6/exercises/phone-number/README.md +3 -2
- data/tracks/perl6/exercises/phone-number/phone-number.t +22 -10
- data/tracks/perl6/exercises/raindrops/raindrops.t +22 -10
- data/tracks/perl6/exercises/rna-transcription/rna-transcription.t +22 -10
- data/tracks/perl6/exercises/robot-name/robot-name.t +9 -3
- data/tracks/perl6/exercises/scrabble-score/README.md +3 -1
- data/tracks/perl6/exercises/scrabble-score/scrabble-score.t +22 -10
- data/tracks/perl6/exercises/space-age/README.md +2 -1
- data/tracks/perl6/exercises/space-age/space-age.t +22 -10
- data/tracks/perl6/exercises/trinary/README.md +1 -1
- data/tracks/perl6/exercises/word-count/README.md +1 -2
- data/tracks/perl6/exercises/word-count/word-count.t +22 -10
- data/tracks/perl6/exercises/wordy/README.md +0 -5
- data/tracks/perl6/exercises/wordy/wordy.t +22 -10
- data/tracks/perl6/templates/test.mustache +26 -15
- data/tracks/python/config.json +10 -0
- data/tracks/python/exercises/book-store/book_store.py +1 -1
- data/tracks/python/exercises/flatten-array/flatten_array.py +1 -1
- data/tracks/python/exercises/matrix/matrix.py +1 -1
- data/tracks/python/exercises/palindrome-products/palindrome_products.py +2 -2
- data/tracks/python/exercises/perfect-numbers/perfect_numbers.py +2 -2
- data/tracks/python/exercises/pythagorean-triplet/pythagorean_triplet.py +3 -3
- data/tracks/python/exercises/raindrops/raindrops.py +1 -1
- data/tracks/python/exercises/scale-generator/scale_generator.py +1 -1
- data/tracks/python/exercises/sieve/sieve.py +1 -1
- data/tracks/python/exercises/sublist/sublist.py +1 -1
- data/tracks/python/exercises/transpose/transpose.py +1 -1
- data/tracks/python/exercises/triangle/triangle.py +4 -1
- data/tracks/python/exercises/two-bucket/example.py +59 -0
- data/tracks/python/exercises/two-bucket/two_bucket.py +2 -0
- data/tracks/python/exercises/two-bucket/two_bucket_test.py +32 -0
- data/tracks/scheme/config.json +59 -89
- data/tracks/scheme/config/maintainers.json +11 -11
- data/tracks/sml/exercises/allergies/README.md +20 -5
- data/tracks/sml/exercises/allergies/allergies.sml +11 -14
- data/tracks/sml/exercises/allergies/example.sml +9 -9
- data/tracks/sml/exercises/allergies/test.sml +65 -129
- data/tracks/sml/exercises/allergies/testlib.sml +159 -0
- data/tracks/sml/exercises/hamming/README.md +21 -5
- data/tracks/sml/exercises/hamming/example.sml +14 -10
- data/tracks/sml/exercises/hamming/hamming.sml +4 -3
- data/tracks/sml/exercises/hamming/test.sml +55 -64
- data/tracks/sml/exercises/hamming/testlib.sml +159 -0
- data/tracks/typescript/config.json +15 -0
- data/tracks/typescript/exercises/linked-list/linked-list.test.ts +11 -11
- data/tracks/typescript/exercises/nth-prime/README.md +36 -0
- data/tracks/typescript/exercises/nth-prime/nth-prime.example.ts +28 -0
- data/tracks/typescript/exercises/nth-prime/nth-prime.test.ts +25 -0
- data/tracks/typescript/exercises/nth-prime/nth-prime.ts +0 -0
- data/tracks/typescript/exercises/nth-prime/package.json +36 -0
- data/tracks/typescript/exercises/nth-prime/tsconfig.json +22 -0
- data/tracks/typescript/exercises/nth-prime/tslint.json +127 -0
- data/tracks/typescript/exercises/nth-prime/yarn.lock +2305 -0
- data/tracks/typescript/exercises/prime-factors/README.md +1 -1
- data/tracks/typescript/exercises/prime-factors/prime-factors.test.ts +11 -11
- data/tracks/typescript/exercises/series/README.md +1 -1
- data/tracks/typescript/exercises/series/series.test.ts +11 -11
- data/tracks/typescript/img/icon.png +0 -0
- data/tracks/typescript/img/icon.svg +3 -8
- 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,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
|
+
|