trackler 2.2.1.68 → 2.2.1.69
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.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/pov/description.md +0 -2
- data/problem-specifications/exercises/protein-translation/canonical-data.json +3 -3
- data/problem-specifications/exercises/simple-cipher/description.md +4 -6
- data/tracks/csharp/exercises/all-your-base/AllYourBaseTest.cs +7 -7
- data/tracks/csharp/exercises/dominoes/README.md +2 -11
- data/tracks/csharp/exercises/reverse-string/ReverseStringTest.cs +2 -2
- data/tracks/dart/CONTRIBUTING.md +7 -4
- data/tracks/delphi/config.json +23 -20
- data/tracks/ecmascript/CONTRIBUTING.md +3 -0
- data/tracks/ecmascript/README.md +2 -5
- data/tracks/fsharp/config.json +11 -0
- data/tracks/fsharp/exercises/Exercises.sln +6 -0
- data/tracks/fsharp/exercises/all-your-base/AllYourBaseTest.fs +7 -7
- data/tracks/fsharp/exercises/diamond/Diamond.fsproj +1 -0
- data/tracks/fsharp/exercises/diamond/DiamondTest.fs +111 -114
- data/tracks/fsharp/exercises/diamond/README.md +2 -1
- data/tracks/fsharp/exercises/dominoes/README.md +2 -5
- data/tracks/fsharp/exercises/palindrome-products/Example.fs +27 -19
- data/tracks/fsharp/exercises/palindrome-products/PalindromeProducts.fs +3 -3
- data/tracks/fsharp/exercises/palindrome-products/PalindromeProductsTest.fs +52 -49
- data/tracks/fsharp/exercises/reverse-string/ReverseStringTest.fs +2 -2
- data/tracks/fsharp/exercises/spiral-matrix/Example.fs +35 -0
- data/tracks/fsharp/exercises/spiral-matrix/Program.fs +1 -0
- data/tracks/fsharp/exercises/spiral-matrix/README.md +25 -0
- data/tracks/fsharp/exercises/spiral-matrix/SpiralMatrix.fs +3 -0
- data/tracks/fsharp/exercises/spiral-matrix/SpiralMatrix.fsproj +23 -0
- data/tracks/fsharp/exercises/spiral-matrix/SpiralMatrixTest.fs +47 -0
- data/tracks/fsharp/generators/Generators.fs +42 -5
- data/tracks/fsharp/generators/Properties/launchSettings.json +1 -2
- data/tracks/java/config.json +7 -2
- data/tracks/java/exercises/binary-search-tree/src/test/java/BinarySearchTreeTest.java +0 -1
- data/tracks/javascript/.eslintignore +1 -2
- data/tracks/javascript/exercises/wordy/example.js +2 -2
- data/tracks/perl6/exercises/atbash-cipher/AtbashCipher.pm6 +6 -0
- data/tracks/perl6/exercises/atbash-cipher/atbash-cipher.t +2 -9
- data/tracks/perl6/exercises/atbash-cipher/example.yaml +8 -9
- data/tracks/perl6/exercises/grade-school/Example.pm6 +1 -1
- data/tracks/perl6/exercises/grade-school/GradeSchool.pm6 +1 -1
- data/tracks/perl6/exercises/grade-school/example.yaml +19 -12
- data/tracks/perl6/exercises/grade-school/grade-school.t +19 -12
- data/tracks/python/.github/stale.yml +6 -3
- data/tracks/python/config.json +17 -0
- data/tracks/python/exercises/dot-dsl/.meta/hints.md +14 -0
- data/tracks/python/exercises/dot-dsl/README.md +52 -0
- data/tracks/python/exercises/dot-dsl/dot_dsl.py +27 -0
- data/tracks/python/exercises/dot-dsl/dot_dsl_test.py +117 -0
- data/tracks/python/exercises/dot-dsl/example.py +52 -0
- data/tracks/python/exercises/proverb/README.md +5 -2
- data/tracks/python/exercises/proverb/example.py +5 -5
- data/tracks/python/exercises/proverb/proverb.py +1 -1
- data/tracks/python/exercises/proverb/proverb_test.py +42 -52
- data/tracks/python/exercises/say/example.py +2 -2
- data/tracks/python/exercises/say/say_test.py +2 -2
- data/tracks/rust/README.md +2 -0
- data/tracks/rust/_test/count-ignores.sh +15 -8
- data/tracks/rust/bin/test-exercise +4 -1
- data/tracks/rust/exercises/perfect-numbers/.meta/ignore-count-ignores +6 -0
- data/tracks/rust/exercises/perfect-numbers/tests/perfect-numbers.rs +32 -22
- data/tracks/typescript/config.json +16 -0
- data/tracks/typescript/exercises/two-bucket/README.md +66 -0
- data/tracks/typescript/exercises/two-bucket/package.json +36 -0
- data/tracks/typescript/exercises/two-bucket/tsconfig.json +22 -0
- data/tracks/typescript/exercises/two-bucket/tslint.json +127 -0
- data/tracks/typescript/exercises/two-bucket/two-bucket.example.ts +97 -0
- data/tracks/typescript/exercises/two-bucket/two-bucket.test.ts +47 -0
- data/tracks/typescript/exercises/two-bucket/two-bucket.ts +0 -0
- data/tracks/typescript/exercises/two-bucket/yarn.lock +2624 -0
- metadata +23 -2
|
@@ -449,19 +449,35 @@ type OcrNumbers() =
|
|
|
449
449
|
|
|
450
450
|
type Pangram() =
|
|
451
451
|
inherit Exercise()
|
|
452
|
-
|
|
453
|
-
type
|
|
452
|
+
|
|
453
|
+
type PalindromeProducts() =
|
|
454
454
|
inherit Exercise()
|
|
455
455
|
|
|
456
|
-
let
|
|
456
|
+
let toFactors (value: obj) =
|
|
457
|
+
let jArray = value :?> JArray
|
|
458
|
+
let factors = jArray.ToObject<int list>()
|
|
459
|
+
sprintf "(%A, %A)" factors.[0] factors.[1]
|
|
460
|
+
|
|
461
|
+
let toPalindromeProducts (value: obj) =
|
|
462
|
+
let jObject = value :?> JObject
|
|
463
|
+
let palindromeValue = jObject.Value<int>("value")
|
|
464
|
+
let factors =
|
|
465
|
+
jObject.Value<JArray>("factors")
|
|
466
|
+
|> normalizeJArray
|
|
467
|
+
|> Seq.map toFactors
|
|
468
|
+
|> formatList
|
|
469
|
+
|
|
470
|
+
sprintf "(%d, %s)" palindromeValue factors
|
|
457
471
|
|
|
458
472
|
override this.RenderExpected (canonicalDataCase, key, value) =
|
|
459
473
|
value
|
|
460
|
-
|> Option.ofNonError
|
|
461
|
-
|> Option.map
|
|
474
|
+
|> Option.ofNonError
|
|
475
|
+
|> Option.map toPalindromeProducts
|
|
462
476
|
|> formatOption
|
|
463
477
|
|> parenthesizeOption
|
|
464
478
|
|
|
479
|
+
override this.PropertiesUsedAsSutParameter canonicalDataCase = ["input_min"; "input_max"]
|
|
480
|
+
|
|
465
481
|
type PascalsTriangle() =
|
|
466
482
|
inherit Exercise()
|
|
467
483
|
|
|
@@ -491,6 +507,18 @@ type PascalsTriangle() =
|
|
|
491
507
|
| _ -> base.IdentifierTypeAnnotation (canonicalDataCase, key, value)
|
|
492
508
|
|
|
493
509
|
override this.ToTestMethodBodyAssertTemplate canonicalDataCase = "AssertEqual"
|
|
510
|
+
|
|
511
|
+
type PerfectNumbers() =
|
|
512
|
+
inherit Exercise()
|
|
513
|
+
|
|
514
|
+
let toClassification value = string value |> String.humanize
|
|
515
|
+
|
|
516
|
+
override this.RenderExpected (canonicalDataCase, key, value) =
|
|
517
|
+
value
|
|
518
|
+
|> Option.ofNonError
|
|
519
|
+
|> Option.map toClassification
|
|
520
|
+
|> formatOption
|
|
521
|
+
|> parenthesizeOption
|
|
494
522
|
|
|
495
523
|
type PhoneNumber() =
|
|
496
524
|
inherit Exercise()
|
|
@@ -717,6 +745,15 @@ type RomanNumerals() =
|
|
|
717
745
|
type ScrabbleScore() =
|
|
718
746
|
inherit Exercise()
|
|
719
747
|
|
|
748
|
+
type SpiralMatrix() =
|
|
749
|
+
inherit Exercise()
|
|
750
|
+
|
|
751
|
+
override this.RenderExpected (canonicalDataCase, key, value) =
|
|
752
|
+
(value :?> JArray)
|
|
753
|
+
|> normalizeJArray
|
|
754
|
+
|> Seq.map formatValue
|
|
755
|
+
|> formatMultiLineList
|
|
756
|
+
|
|
720
757
|
type TwelveDays() =
|
|
721
758
|
inherit Exercise()
|
|
722
759
|
|
data/tracks/java/config.json
CHANGED
|
@@ -721,7 +721,12 @@
|
|
|
721
721
|
"core": true,
|
|
722
722
|
"difficulty": 6,
|
|
723
723
|
"slug": "binary-search",
|
|
724
|
-
"topics":
|
|
724
|
+
"topics": [
|
|
725
|
+
"recursion",
|
|
726
|
+
"arrays",
|
|
727
|
+
"searching",
|
|
728
|
+
"generics"
|
|
729
|
+
],
|
|
725
730
|
"unlocked_by": null,
|
|
726
731
|
"uuid": "50136dc3-caf7-4fa1-b7bd-0cba1bea9176"
|
|
727
732
|
},
|
|
@@ -1150,4 +1155,4 @@
|
|
|
1150
1155
|
],
|
|
1151
1156
|
"language": "Java",
|
|
1152
1157
|
"solution_pattern": "reference"
|
|
1153
|
-
}
|
|
1158
|
+
}
|
|
@@ -47,11 +47,11 @@ WordProblem.prototype.evaluate = function () {
|
|
|
47
47
|
var out = 0;
|
|
48
48
|
var m = this.matches;
|
|
49
49
|
|
|
50
|
-
if (m[1]
|
|
50
|
+
if ( (typeof m[1]) === 'string' && (typeof m[2]) === 'string' && (typeof m[3]) === 'string') {
|
|
51
51
|
out = this.operate(m[2], m[1], m[3]);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
if (m[4]
|
|
54
|
+
if ( (typeof m[4]) === 'string' && (typeof m[5]) === 'string') {
|
|
55
55
|
out = this.operate(m[4], out, m[5]);
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -7,7 +7,7 @@ use JSON::Fast;
|
|
|
7
7
|
my Str:D $exercise := 'AtbashCipher';
|
|
8
8
|
my Version:D $version = v1;
|
|
9
9
|
my Str $module //= $exercise;
|
|
10
|
-
plan
|
|
10
|
+
plan 14;
|
|
11
11
|
|
|
12
12
|
use-ok $module or bail-out;
|
|
13
13
|
require ::($module);
|
|
@@ -22,14 +22,7 @@ if ::($exercise).^ver !~~ $version {
|
|
|
22
22
|
require ::($module) <&encode &decode>;
|
|
23
23
|
|
|
24
24
|
my $c-data = from-json $=pod.pop.contents;
|
|
25
|
-
for
|
|
26
|
-
my $test = .<description> ~~ 'encode' ?? 'encode' !! 'decode';
|
|
27
|
-
subtest $test => {
|
|
28
|
-
my @cases = |.<cases>;
|
|
29
|
-
plan +@cases;
|
|
30
|
-
is &::($test)(.<phrase>), |.<expected description> for @cases;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
25
|
+
is .<phrase>.&::(.<property>), |.<expected description> for $c-data<cases>»<cases>».Array.flat;
|
|
33
26
|
|
|
34
27
|
=head2 Canonical Data
|
|
35
28
|
=begin code
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
exercise: AtbashCipher
|
|
2
2
|
version: 1
|
|
3
|
-
plan:
|
|
3
|
+
plan: 14
|
|
4
4
|
imports: '&encode &decode'
|
|
5
5
|
tests: |-
|
|
6
|
-
for
|
|
7
|
-
my $test = .<description> ~~ 'encode' ?? 'encode' !! 'decode';
|
|
8
|
-
subtest $test => {
|
|
9
|
-
my @cases = |.<cases>;
|
|
10
|
-
plan +@cases;
|
|
11
|
-
is &::($test)(.<phrase>), |.<expected description> for @cases;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
6
|
+
is .<phrase>.&::(.<property>), |.<expected description> for $c-data<cases>»<cases>».Array.flat;
|
|
14
7
|
|
|
15
8
|
unit: module
|
|
16
9
|
example: |-
|
|
@@ -26,3 +19,9 @@ example: |-
|
|
|
26
19
|
.subst( /\W/, '', :g )
|
|
27
20
|
.trans( [ 'a'..'z' ] => ['a'..'z'].reverse );
|
|
28
21
|
}
|
|
22
|
+
stub: |-
|
|
23
|
+
sub encode ($phrase) is export {
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
sub decode ($phrase) is export {
|
|
27
|
+
}
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
exercise: GradeSchool
|
|
2
|
-
version:
|
|
3
|
-
plan:
|
|
2
|
+
version: 2
|
|
3
|
+
plan: 19
|
|
4
4
|
imports: Roster
|
|
5
5
|
tests: |-
|
|
6
6
|
subtest "Roster class methods", {
|
|
7
7
|
plan 3;
|
|
8
8
|
ok ::('Roster').can($_), $_ for <add-student list-grade list-all>;
|
|
9
9
|
}
|
|
10
|
+
|
|
10
11
|
my $roster = ::('Roster').new;
|
|
12
|
+
|
|
11
13
|
ok $roster.?add-student(:name('Jim'), :2grade), 'Add Jim to grade 2';
|
|
12
|
-
|
|
14
|
+
cmp-ok $roster.?list-grade(2), '~~', <Jim>, 'List grade 2';
|
|
15
|
+
|
|
13
16
|
ok $roster.?add-student(:name('Zoe'), :2grade), 'Add Zoe to grade 2';
|
|
14
17
|
ok $roster.?add-student(:name('Barb'), :1grade), 'Add Barb to grade 1';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
cmp-ok $roster.?list-grade(2), '~~', <Jim Zoe>, 'List grade 2';
|
|
19
|
+
cmp-ok $roster.?list-grade(1), '~~', <Barb>, 'List grade 1';
|
|
20
|
+
|
|
21
|
+
cmp-ok $roster.?list-all, '~~', ('Grade 1', <Barb>, 'Grade 2', <Jim Zoe>), 'List all';
|
|
22
|
+
|
|
23
|
+
ok $roster.?add-student(:name($_), :1grade), "Add $_ to grade 1" for <Charlie Anna>;
|
|
24
|
+
ok $roster.?add-student(:name('Alex'), :2grade), 'Add Alex to grade 2';
|
|
25
|
+
ok $roster.?add-student(:name($_), :3grade), "Add $_ to grade 3" for <Tom Dick Harry>;
|
|
26
|
+
|
|
27
|
+
cmp-ok $roster.?list-grade(1), '~~', <Anna Barb Charlie>, 'List grade 1';
|
|
28
|
+
cmp-ok $roster.?list-grade(2), '~~', <Alex Jim Zoe>, 'List grade 2';
|
|
29
|
+
cmp-ok $roster.?list-grade(3), '~~', <Dick Harry Tom>, 'List grade 3';
|
|
30
|
+
cmp-ok $roster.?list-all, '~~', ('Grade 1', <Anna Barb Charlie>, 'Grade 2', <Alex Jim Zoe>, 'Grade 3', <Dick Harry Tom>), 'List all';
|
|
24
31
|
|
|
25
32
|
unit: module
|
|
26
33
|
example: |-
|
|
@@ -4,9 +4,9 @@ use Test;
|
|
|
4
4
|
use lib $?FILE.IO.dirname;
|
|
5
5
|
|
|
6
6
|
my Str:D $exercise := 'GradeSchool';
|
|
7
|
-
my Version:D $version =
|
|
7
|
+
my Version:D $version = v2;
|
|
8
8
|
my Str $module //= $exercise;
|
|
9
|
-
plan
|
|
9
|
+
plan 19;
|
|
10
10
|
|
|
11
11
|
use-ok $module or bail-out;
|
|
12
12
|
require ::($module);
|
|
@@ -24,19 +24,26 @@ subtest "Roster class methods", {
|
|
|
24
24
|
plan 3;
|
|
25
25
|
ok ::('Roster').can($_), $_ for <add-student list-grade list-all>;
|
|
26
26
|
}
|
|
27
|
+
|
|
27
28
|
my $roster = ::('Roster').new;
|
|
29
|
+
|
|
28
30
|
ok $roster.?add-student(:name('Jim'), :2grade), 'Add Jim to grade 2';
|
|
29
|
-
|
|
31
|
+
cmp-ok $roster.?list-grade(2), '~~', <Jim>, 'List grade 2';
|
|
32
|
+
|
|
30
33
|
ok $roster.?add-student(:name('Zoe'), :2grade), 'Add Zoe to grade 2';
|
|
31
34
|
ok $roster.?add-student(:name('Barb'), :1grade), 'Add Barb to grade 1';
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
cmp-ok $roster.?list-grade(2), '~~', <Jim Zoe>, 'List grade 2';
|
|
36
|
+
cmp-ok $roster.?list-grade(1), '~~', <Barb>, 'List grade 1';
|
|
37
|
+
|
|
38
|
+
cmp-ok $roster.?list-all, '~~', ('Grade 1', <Barb>, 'Grade 2', <Jim Zoe>), 'List all';
|
|
39
|
+
|
|
40
|
+
ok $roster.?add-student(:name($_), :1grade), "Add $_ to grade 1" for <Charlie Anna>;
|
|
41
|
+
ok $roster.?add-student(:name('Alex'), :2grade), 'Add Alex to grade 2';
|
|
42
|
+
ok $roster.?add-student(:name($_), :3grade), "Add $_ to grade 3" for <Tom Dick Harry>;
|
|
43
|
+
|
|
44
|
+
cmp-ok $roster.?list-grade(1), '~~', <Anna Barb Charlie>, 'List grade 1';
|
|
45
|
+
cmp-ok $roster.?list-grade(2), '~~', <Alex Jim Zoe>, 'List grade 2';
|
|
46
|
+
cmp-ok $roster.?list-grade(3), '~~', <Dick Harry Tom>, 'List grade 3';
|
|
47
|
+
cmp-ok $roster.?list-all, '~~', ('Grade 1', <Anna Barb Charlie>, 'Grade 2', <Alex Jim Zoe>, 'Grade 3', <Dick Harry Tom>), 'List all';
|
|
41
48
|
|
|
42
49
|
INIT { $module = 'Example' if %*ENV<EXERCISM> }
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# Number of days of inactivity before an issue becomes stale
|
|
2
|
-
daysUntilStale:
|
|
2
|
+
daysUntilStale: 21
|
|
3
3
|
# Number of days of inactivity before a stale issue is closed
|
|
4
4
|
daysUntilClose: 7
|
|
5
5
|
# Issues with these labels will never be considered stale
|
|
6
6
|
exemptLabels:
|
|
7
7
|
- discussion
|
|
8
8
|
- pinned
|
|
9
|
+
- epic
|
|
10
|
+
- enhancement
|
|
11
|
+
- beginner friendly
|
|
9
12
|
# Label to use when marking an issue as stale
|
|
10
|
-
staleLabel:
|
|
13
|
+
staleLabel: abandoned
|
|
11
14
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
|
12
15
|
markComment: >
|
|
13
|
-
This issue has been automatically marked as `
|
|
16
|
+
This issue has been automatically marked as `abandoned` because it has not had
|
|
14
17
|
recent activity. It will be closed if no further activity occurs. Thank you
|
|
15
18
|
for your contributions.
|
|
16
19
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
data/tracks/python/config.json
CHANGED
|
@@ -763,6 +763,23 @@
|
|
|
763
763
|
"object_oriented_programming"
|
|
764
764
|
]
|
|
765
765
|
},
|
|
766
|
+
{
|
|
767
|
+
"uuid": "a9c2fbda-a1e4-42dd-842f-4de5bb361b91",
|
|
768
|
+
"slug": "dot-dsl",
|
|
769
|
+
"core": false,
|
|
770
|
+
"unlocked_by": null,
|
|
771
|
+
"difficulty": 5,
|
|
772
|
+
"topics": [
|
|
773
|
+
"equality",
|
|
774
|
+
"classes",
|
|
775
|
+
"lists",
|
|
776
|
+
"domain_specific_languages",
|
|
777
|
+
"graphs",
|
|
778
|
+
"object_oriented_programming",
|
|
779
|
+
"test_driven_development",
|
|
780
|
+
"transforming"
|
|
781
|
+
]
|
|
782
|
+
},
|
|
766
783
|
{
|
|
767
784
|
"uuid": "dc6e61a2-e9b9-4406-ba5c-188252afbba1",
|
|
768
785
|
"slug": "transpose",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Description of DSL
|
|
2
|
+
|
|
3
|
+
A graph, in this DSL, is an object of type `Graph`, taking a list of one
|
|
4
|
+
or more
|
|
5
|
+
|
|
6
|
+
+ attributes
|
|
7
|
+
+ nodes
|
|
8
|
+
+ edges
|
|
9
|
+
|
|
10
|
+
described as tuples.
|
|
11
|
+
|
|
12
|
+
The implementations of `Node` and `Edge` provided in `dot_dsl.py`.
|
|
13
|
+
|
|
14
|
+
Observe the test cases in `dot_dsl_test.py` to understand the DSL's design.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Dot Dsl
|
|
2
|
+
|
|
3
|
+
Write a Domain Specific Language similar to the Graphviz dot language.
|
|
4
|
+
|
|
5
|
+
A [Domain Specific Language
|
|
6
|
+
(DSL)](https://en.wikipedia.org/wiki/Domain-specific_language) is a
|
|
7
|
+
small language optimized for a specific domain.
|
|
8
|
+
|
|
9
|
+
For example the dot language of [Graphviz](http://graphviz.org) allows
|
|
10
|
+
you to write a textual description of a graph which is then transformed
|
|
11
|
+
into a picture by one of the graphviz tools (such as `dot`). A simple
|
|
12
|
+
graph looks like this:
|
|
13
|
+
|
|
14
|
+
graph {
|
|
15
|
+
graph [bgcolor="yellow"]
|
|
16
|
+
a [color="red"]
|
|
17
|
+
b [color="blue"]
|
|
18
|
+
a -- b [color="green"]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Putting this in a file `example.dot` and running `dot example.dot -T png
|
|
22
|
+
-o example.png` creates an image `example.png` with red and blue circle
|
|
23
|
+
connected by a green line on a yellow background.
|
|
24
|
+
|
|
25
|
+
Create a DSL similar to the dot language.
|
|
26
|
+
|
|
27
|
+
## Description of DSL
|
|
28
|
+
|
|
29
|
+
A graph, in this DSL, is an object of type `Graph`, taking a list of one
|
|
30
|
+
or more
|
|
31
|
+
|
|
32
|
+
+ attributes
|
|
33
|
+
+ nodes
|
|
34
|
+
+ edges
|
|
35
|
+
|
|
36
|
+
described as tuples.
|
|
37
|
+
|
|
38
|
+
The implementations of `Node` and `Edge` provided in `dot_dsl.py`.
|
|
39
|
+
|
|
40
|
+
Observe the test cases in `dot_dsl_test.py` to understand the DSL's design.
|
|
41
|
+
|
|
42
|
+
## Submitting Exercises
|
|
43
|
+
|
|
44
|
+
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
|
|
45
|
+
|
|
46
|
+
For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
|
|
47
|
+
|
|
48
|
+
For more detailed information about running tests, code style and linting, please see the [help page](http://exercism.io/languages/python).
|
|
49
|
+
|
|
50
|
+
## Submitting Incomplete Solutions
|
|
51
|
+
|
|
52
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
NODE, EDGE, ATTR = range(3)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Node(object):
|
|
5
|
+
def __init__(self, name, attrs={}):
|
|
6
|
+
self.name = name
|
|
7
|
+
self.attrs = attrs
|
|
8
|
+
|
|
9
|
+
def __eq__(self, other):
|
|
10
|
+
return self.name == other.name and self.attrs == other.attrs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Edge(object):
|
|
14
|
+
def __init__(self, src, dst, attrs={}):
|
|
15
|
+
self.src = src
|
|
16
|
+
self.dst = dst
|
|
17
|
+
self.attrs = attrs
|
|
18
|
+
|
|
19
|
+
def __eq__(self, other):
|
|
20
|
+
return (self.src == other.src and
|
|
21
|
+
self.dst == other.dst and
|
|
22
|
+
self.attrs == other.attrs)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Graph(object):
|
|
26
|
+
def __init__(self, data=[]):
|
|
27
|
+
pass
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from dot_dsl import Graph, Node, Edge, NODE, EDGE, ATTR
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DotDslTest(unittest.TestCase):
|
|
7
|
+
def test_empty_graph(self):
|
|
8
|
+
g = Graph()
|
|
9
|
+
|
|
10
|
+
self.assertEqual(g.nodes, [])
|
|
11
|
+
self.assertEqual(g.edges, [])
|
|
12
|
+
self.assertEqual(g.attrs, {})
|
|
13
|
+
|
|
14
|
+
def test_graph_with_one_node(self):
|
|
15
|
+
g = Graph([
|
|
16
|
+
(NODE, "a", {})
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
self.assertEqual(g.nodes, [Node("a")])
|
|
20
|
+
self.assertEqual(g.edges, [])
|
|
21
|
+
self.assertEqual(g.attrs, {})
|
|
22
|
+
|
|
23
|
+
def test_graph_with_one_node_with_keywords(self):
|
|
24
|
+
g = Graph([
|
|
25
|
+
(NODE, "a", {"color": "green"})
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
self.assertEqual(g.nodes, [Node("a", {"color": "green"})])
|
|
29
|
+
self.assertEqual(g.edges, [])
|
|
30
|
+
self.assertEqual(g.attrs, {})
|
|
31
|
+
|
|
32
|
+
def test_graph_with_one_edge(self):
|
|
33
|
+
g = Graph([
|
|
34
|
+
(EDGE, "a", "b", {})
|
|
35
|
+
])
|
|
36
|
+
|
|
37
|
+
self.assertEqual(g.nodes, [])
|
|
38
|
+
self.assertEqual(g.edges, [Edge("a", "b", {})])
|
|
39
|
+
self.assertEqual(g.attrs, {})
|
|
40
|
+
|
|
41
|
+
def test_graph_with_one_attribute(self):
|
|
42
|
+
g = Graph([
|
|
43
|
+
(ATTR, "foo", "1")
|
|
44
|
+
])
|
|
45
|
+
|
|
46
|
+
self.assertEqual(g.nodes, [])
|
|
47
|
+
self.assertEqual(g.edges, [])
|
|
48
|
+
self.assertEqual(g.attrs, {"foo": "1"})
|
|
49
|
+
|
|
50
|
+
def test_graph_with_attributes(self):
|
|
51
|
+
g = Graph([
|
|
52
|
+
(ATTR, "foo", "1"),
|
|
53
|
+
(ATTR, "title", "Testing Attrs"),
|
|
54
|
+
(NODE, "a", {"color": "green"}),
|
|
55
|
+
(NODE, "c", {}),
|
|
56
|
+
(NODE, "b", {"label", "Beta!"}),
|
|
57
|
+
(EDGE, "b", "c", {}),
|
|
58
|
+
(EDGE, "a", "b", {"color": "blue"}),
|
|
59
|
+
(ATTR, "bar", "true")
|
|
60
|
+
])
|
|
61
|
+
|
|
62
|
+
self.assertEqual(g.nodes, [Node("a", {"color": "green"}),
|
|
63
|
+
Node("c", {}),
|
|
64
|
+
Node("b", {"label", "Beta!"})])
|
|
65
|
+
self.assertEqual(g.edges, [Edge("b", "c", {}),
|
|
66
|
+
Edge("a", "b", {"color": "blue"})])
|
|
67
|
+
self.assertEqual(g.attrs, {
|
|
68
|
+
"foo": "1",
|
|
69
|
+
"title": "Testing Attrs",
|
|
70
|
+
"bar": "true"
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
def test_malformed_graph(self):
|
|
74
|
+
with self.assertRaises(TypeError):
|
|
75
|
+
Graph(1)
|
|
76
|
+
|
|
77
|
+
with self.assertRaises(TypeError):
|
|
78
|
+
Graph("problematic")
|
|
79
|
+
|
|
80
|
+
def test_malformed_graph_item(self):
|
|
81
|
+
with self.assertRaises(TypeError):
|
|
82
|
+
Graph([
|
|
83
|
+
()
|
|
84
|
+
])
|
|
85
|
+
|
|
86
|
+
with self.assertRaises(TypeError):
|
|
87
|
+
Graph([
|
|
88
|
+
(ATTR, )
|
|
89
|
+
])
|
|
90
|
+
|
|
91
|
+
def test_malformed_attr(self):
|
|
92
|
+
with self.assertRaises(ValueError):
|
|
93
|
+
Graph([
|
|
94
|
+
(ATTR, 1, 2, 3)
|
|
95
|
+
])
|
|
96
|
+
|
|
97
|
+
def test_malformed_node(self):
|
|
98
|
+
with self.assertRaises(ValueError):
|
|
99
|
+
Graph([
|
|
100
|
+
(NODE, 1, 2, 3)
|
|
101
|
+
])
|
|
102
|
+
|
|
103
|
+
def test_malformed_EDGE(self):
|
|
104
|
+
with self.assertRaises(ValueError):
|
|
105
|
+
Graph([
|
|
106
|
+
(EDGE, 1, 2)
|
|
107
|
+
])
|
|
108
|
+
|
|
109
|
+
def test_unknown_item(self):
|
|
110
|
+
with self.assertRaises(ValueError):
|
|
111
|
+
Graph([
|
|
112
|
+
(99, 1, 2)
|
|
113
|
+
])
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == '__main__':
|
|
117
|
+
unittest.main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
NODE, EDGE, ATTR = range(3)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Node(object):
|
|
5
|
+
def __init__(self, name, attrs={}):
|
|
6
|
+
self.name = name
|
|
7
|
+
self.attrs = attrs
|
|
8
|
+
|
|
9
|
+
def __eq__(self, other):
|
|
10
|
+
return self.name == other.name and self.attrs == other.attrs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Edge(object):
|
|
14
|
+
def __init__(self, src, dst, attrs={}):
|
|
15
|
+
self.src = src
|
|
16
|
+
self.dst = dst
|
|
17
|
+
self.attrs = attrs
|
|
18
|
+
|
|
19
|
+
def __eq__(self, other):
|
|
20
|
+
return (self.src == other.src and
|
|
21
|
+
self.dst == other.dst and
|
|
22
|
+
self.attrs == other.attrs)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Graph(object):
|
|
26
|
+
def __init__(self, data=[]):
|
|
27
|
+
self.nodes = []
|
|
28
|
+
self.edges = []
|
|
29
|
+
self.attrs = {}
|
|
30
|
+
|
|
31
|
+
if not isinstance(data, list):
|
|
32
|
+
raise TypeError("Graph data malformed")
|
|
33
|
+
|
|
34
|
+
for item in data:
|
|
35
|
+
if len(item) < 3:
|
|
36
|
+
raise TypeError("Graph item incomplete")
|
|
37
|
+
|
|
38
|
+
type_ = item[0]
|
|
39
|
+
if type_ == ATTR:
|
|
40
|
+
if len(item) != 3:
|
|
41
|
+
raise ValueError("ATTR malformed")
|
|
42
|
+
self.attrs[item[1]] = item[2]
|
|
43
|
+
elif type_ == NODE:
|
|
44
|
+
if len(item) != 3:
|
|
45
|
+
raise ValueError("NODE malformed")
|
|
46
|
+
self.nodes.append(Node(item[1], item[2]))
|
|
47
|
+
elif type_ == EDGE:
|
|
48
|
+
if len(item) != 4:
|
|
49
|
+
raise ValueError("EDGE malformed")
|
|
50
|
+
self.edges.append(Edge(item[1], item[2], item[3]))
|
|
51
|
+
else:
|
|
52
|
+
raise ValueError("Unknown item {}".format(item[0]))
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
For want of a horseshoe nail, a kingdom was lost, or so the saying goes.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Given a list of inputs, generate the relevant proverb. For example, given the list `["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]`, you will output the full text of this proverbial rhyme:
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
8
|
For want of a nail the shoe was lost.
|
|
@@ -11,8 +11,11 @@ For want of a horse the rider was lost.
|
|
|
11
11
|
For want of a rider the message was lost.
|
|
12
12
|
For want of a message the battle was lost.
|
|
13
13
|
For want of a battle the kingdom was lost.
|
|
14
|
-
And all for the want of a
|
|
14
|
+
And all for the want of a nail.
|
|
15
15
|
```
|
|
16
|
+
|
|
17
|
+
Note that the list of inputs may vary; your solution should be able to handle lists of arbitrary length and content. No line of the output text should be a static, unchanging string; all should vary according to the input given.
|
|
18
|
+
|
|
16
19
|
## Submitting Exercises
|
|
17
20
|
|
|
18
21
|
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
def proverb(
|
|
1
|
+
def proverb(rhyme_items):
|
|
2
|
+
if not rhyme_items:
|
|
3
|
+
return ""
|
|
2
4
|
phrases = ['For want of a {0} the {1} was lost.'.format(el1, el2)
|
|
3
|
-
for el1, el2 in zip(
|
|
4
|
-
|
|
5
|
-
phrases.append('And all for the want of a {0}{1}.'.format(qualifier,
|
|
6
|
-
itens[0]))
|
|
5
|
+
for el1, el2 in zip(rhyme_items, rhyme_items[1:])]
|
|
6
|
+
phrases.append('And all for the want of a {0}.'.format(rhyme_items[0]))
|
|
7
7
|
return '\n'.join(phrases)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
def proverb(
|
|
1
|
+
def proverb(rhyme_items):
|
|
2
2
|
pass
|