trackler 2.2.1.72 → 2.2.1.73
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/armstrong-numbers/canonical-data.json +70 -0
- data/problem-specifications/exercises/armstrong-numbers/description.md +10 -0
- data/problem-specifications/exercises/armstrong-numbers/metadata.yml +4 -0
- data/problem-specifications/exercises/bob/canonical-data.json +2 -2
- data/problem-specifications/exercises/bob/description.md +2 -0
- data/tracks/c/config.json +41 -41
- data/tracks/common-lisp/exercises/etl/README.md +1 -1
- data/tracks/common-lisp/exercises/isogram/README.md +1 -1
- data/tracks/delphi/config.json +10 -0
- data/tracks/delphi/config/maintainers.json +2 -2
- data/tracks/delphi/exercises/armstrong-numbers/ArmstrongNumbers.dpr +60 -0
- data/tracks/delphi/exercises/armstrong-numbers/README.md +39 -0
- data/tracks/delphi/exercises/armstrong-numbers/uArmstrongNumbersExample.pas +24 -0
- data/tracks/delphi/exercises/armstrong-numbers/uArmstrongNumbersTests.pas +101 -0
- data/tracks/delphi/exercises/bob/README.md +2 -0
- data/tracks/delphi/exercises/bob/uBobExample.pas +12 -3
- data/tracks/delphi/exercises/bob/uBobTests.pas +80 -23
- data/tracks/go/exercises/bob/README.md +2 -0
- data/tracks/go/exercises/bob/cases_test.go +3 -3
- data/tracks/go/exercises/bob/example.go +3 -0
- data/tracks/go/exercises/book-store/cases_test.go +7 -2
- data/tracks/go/exercises/word-count/cases_test.go +6 -1
- data/tracks/groovy/exercises/linked-list/README.md +1 -1
- data/tracks/haskell/.travis.yml +1 -0
- data/tracks/haskell/bin/ensure-readmes-are-updated.sh +40 -0
- data/tracks/haskell/config.json +9 -0
- data/tracks/haskell/exercises/rail-fence-cipher/README.md +119 -0
- data/tracks/haskell/exercises/rail-fence-cipher/examples/success-standard/package.yaml +16 -0
- data/tracks/haskell/exercises/rail-fence-cipher/examples/success-standard/src/RailFenceCipher.hs +12 -0
- data/tracks/haskell/exercises/rail-fence-cipher/package.yaml +20 -0
- data/tracks/haskell/exercises/rail-fence-cipher/src/RailFenceCipher.hs +7 -0
- data/tracks/haskell/exercises/rail-fence-cipher/stack.yaml +1 -0
- data/tracks/haskell/exercises/rail-fence-cipher/test/Tests.hs +60 -0
- data/tracks/java/CONTRIBUTING.md +14 -5
- data/tracks/java/bin/run-journey-test-from-ci.sh +1 -1
- data/tracks/java/config.json +13 -0
- data/tracks/java/exercises/custom-set/.meta/src/reference/java/CustomSet.java +12 -12
- data/tracks/java/exercises/food-chain/.meta/src/reference/java/FoodChain.java +3 -3
- data/tracks/java/exercises/grade-school/.meta/src/reference/java/School.java +7 -7
- data/tracks/java/exercises/hamming/.meta/src/reference/java/Hamming.java +3 -3
- data/tracks/java/exercises/hexadecimal/.meta/src/reference/java/Hexadecimal.java +2 -4
- data/tracks/java/exercises/isogram/.meta/src/reference/java/IsogramChecker.java +2 -2
- data/tracks/java/exercises/largest-series-product/.meta/src/reference/java/LargestSeriesProductCalculator.java +3 -3
- data/tracks/java/exercises/linked-list/.meta/src/reference/java/DoublyLinkedList.java +6 -6
- data/tracks/java/exercises/markdown/.meta/src/reference/java/Markdown.java +96 -0
- data/tracks/java/exercises/markdown/.meta/version +1 -0
- data/tracks/java/exercises/markdown/README.md +30 -0
- data/tracks/java/exercises/markdown/build.gradle +18 -0
- data/tracks/java/exercises/markdown/src/main/java/Markdown.java +83 -0
- data/tracks/java/exercises/markdown/src/test/java/MarkdownTest.java +95 -0
- data/tracks/java/exercises/settings.gradle +1 -0
- data/tracks/javascript/exercises/alphametics/example.js +13 -9
- data/tracks/kotlin/docs/TESTS.md +14 -11
- data/tracks/ocaml/exercises/bob/example.ml +5 -3
- data/tracks/ocaml/exercises/bob/test.ml +3 -4
- data/tracks/ocaml/exercises/word-count/test.ml +3 -0
- data/tracks/ocaml/tools/test-generator/templates/ocaml/bob/test.ml +0 -1
- data/tracks/perl6/config.json +16 -6
- data/tracks/perl6/exercises/bob/Bob.pm6 +1 -1
- data/tracks/perl6/exercises/bob/Example.pm6 +11 -7
- data/tracks/perl6/exercises/bob/README.md +2 -0
- data/tracks/perl6/exercises/bob/bob.t +3 -3
- data/tracks/perl6/exercises/bob/example.yaml +11 -7
- data/tracks/perl6/exercises/clock/clock.t +17 -17
- data/tracks/perl6/exercises/clock/example.yaml +17 -17
- data/tracks/perl6/exercises/roman-numerals/Example.pm6 +17 -0
- data/tracks/perl6/exercises/roman-numerals/RomanNumerals.pm6 +4 -0
- data/tracks/perl6/exercises/roman-numerals/example.yaml +30 -0
- data/tracks/perl6/exercises/roman-numerals/roman-numerals.t +162 -0
- data/tracks/python/exercises/book-store/book_store_test.py +7 -1
- data/tracks/ruby/config.json +11 -0
- data/tracks/ruby/exercises/isbn-verifier/.meta/.version +1 -0
- data/tracks/ruby/exercises/isbn-verifier/.meta/generator/isbn_verifier_case.rb +28 -0
- data/tracks/ruby/exercises/isbn-verifier/.meta/solutions/isbn_verifier.rb +25 -0
- data/tracks/ruby/exercises/isbn-verifier/README.md +73 -0
- data/tracks/ruby/exercises/isbn-verifier/isbn_verifier_test.rb +105 -0
- data/tracks/ruby/exercises/isogram/.meta/generator/isogram_case.rb +3 -3
- data/tracks/ruby/exercises/isogram/isogram_test.rb +18 -18
- data/tracks/rust/README.md +0 -2
- data/tracks/rust/config.json +11 -0
- data/tracks/rust/exercises/diffie-hellman/tests/diffie-hellman.rs +0 -1
- data/tracks/rust/exercises/parallel-letter-frequency/HINTS.md +2 -2
- data/tracks/rust/exercises/parallel-letter-frequency/README.md +2 -2
- data/tracks/rust/exercises/rna-transcription/example.rs +10 -10
- data/tracks/rust/exercises/rna-transcription/tests/rna-transcription.rs +10 -10
- data/tracks/rust/exercises/series/.gitignore +3 -0
- data/tracks/rust/exercises/series/Cargo.toml +5 -0
- data/tracks/rust/exercises/series/README.md +60 -0
- data/tracks/rust/exercises/series/example.rs +13 -0
- data/tracks/rust/exercises/series/src/lib.rs +3 -0
- data/tracks/rust/exercises/series/tests/series.rs +34 -0
- data/tracks/sml/exercises/nth-prime/README.md +1 -1
- data/tracks/vimscript/.travis.yml +3 -0
- data/tracks/vimscript/docs/LEARNING.md +1 -1
- metadata +38 -2
@@ -24,29 +24,29 @@ subtest 'Class methods', {
|
|
24
24
|
}
|
25
25
|
|
26
26
|
my $c-data = from-json $=pod.pop.contents;
|
27
|
-
for
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
my $clock = ::($exercise)
|
35
|
-
$clock.?add-minutes
|
36
|
-
is $clock.?time,
|
37
|
-
}
|
38
|
-
when 'equal' {
|
39
|
-
is ::($exercise).new(hour => $case<clock1><hour>, minute => $case<clock1><minute>).?time eq
|
40
|
-
::($exercise).new(hour => $case<clock2><hour>, minute => $case<clock2><minute>).?time,
|
41
|
-
|$case<expected description>;
|
27
|
+
for $c-data<cases>»<cases>».Array.flat -> %case {
|
28
|
+
given %case<property> {
|
29
|
+
when 'create' {
|
30
|
+
is ::($exercise).?new( |%(.<hour minute>:p) ).?time, |.<expected description> given %case;
|
31
|
+
}
|
32
|
+
when 'add' {
|
33
|
+
given %case {
|
34
|
+
my $clock = ::($exercise).?new: |%(.<hour minute>:p);
|
35
|
+
$clock.?add-minutes: .<add>;
|
36
|
+
is $clock.?time, |.<expected description>;
|
42
37
|
}
|
43
|
-
when %*ENV<EXERCISM>.so { bail-out "no case for property '$case<property>'" }
|
44
38
|
}
|
39
|
+
when 'equal' {
|
40
|
+
is-deeply ([eq] gather {
|
41
|
+
take ::($exercise).?new( |%(.<hour minute>:p) ).?time for %case<clock1 clock2>;
|
42
|
+
}), |%case<expected description>;
|
43
|
+
}
|
44
|
+
when %*ENV<EXERCISM>.so { bail-out "no case for property '%case<property>'" }
|
45
45
|
}
|
46
46
|
}
|
47
47
|
|
48
48
|
todo 'optional test' unless %*ENV<EXERCISM>;
|
49
|
-
is ::($exercise)
|
49
|
+
is ::($exercise).?new(:0hour,:0minute).?add-minutes(65).?time, '01:05', 'add-minutes method can be chained';
|
50
50
|
|
51
51
|
=head2 Canonical Data
|
52
52
|
=begin code
|
@@ -3,29 +3,29 @@ version: 1
|
|
3
3
|
methods: time add-minutes
|
4
4
|
plan: 54
|
5
5
|
tests: |-
|
6
|
-
for
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
my $clock = ::($exercise)
|
14
|
-
$clock.?add-minutes
|
15
|
-
is $clock.?time,
|
16
|
-
}
|
17
|
-
when 'equal' {
|
18
|
-
is ::($exercise).new(hour => $case<clock1><hour>, minute => $case<clock1><minute>).?time eq
|
19
|
-
::($exercise).new(hour => $case<clock2><hour>, minute => $case<clock2><minute>).?time,
|
20
|
-
|$case<expected description>;
|
6
|
+
for $c-data<cases>»<cases>».Array.flat -> %case {
|
7
|
+
given %case<property> {
|
8
|
+
when 'create' {
|
9
|
+
is ::($exercise).?new( |%(.<hour minute>:p) ).?time, |.<expected description> given %case;
|
10
|
+
}
|
11
|
+
when 'add' {
|
12
|
+
given %case {
|
13
|
+
my $clock = ::($exercise).?new: |%(.<hour minute>:p);
|
14
|
+
$clock.?add-minutes: .<add>;
|
15
|
+
is $clock.?time, |.<expected description>;
|
21
16
|
}
|
22
|
-
when %*ENV<EXERCISM>.so { bail-out "no case for property '$case<property>'" }
|
23
17
|
}
|
18
|
+
when 'equal' {
|
19
|
+
is-deeply ([eq] gather {
|
20
|
+
take ::($exercise).?new( |%(.<hour minute>:p) ).?time for %case<clock1 clock2>;
|
21
|
+
}), |%case<expected description>;
|
22
|
+
}
|
23
|
+
when %*ENV<EXERCISM>.so { bail-out "no case for property '%case<property>'" }
|
24
24
|
}
|
25
25
|
}
|
26
26
|
|
27
27
|
todo 'optional test' unless %*ENV<EXERCISM>;
|
28
|
-
is ::($exercise)
|
28
|
+
is ::($exercise).?new(:0hour,:0minute).?add-minutes(65).?time, '01:05', 'add-minutes method can be chained';
|
29
29
|
|
30
30
|
unit: class
|
31
31
|
example: |-
|
@@ -0,0 +1,17 @@
|
|
1
|
+
unit module RomanNumerals:ver<1>;
|
2
|
+
|
3
|
+
|
4
|
+
my %table{Int} = <1000 900 500 400 100 90 50 40 10 9 5 4 1>
|
5
|
+
Z=>
|
6
|
+
<M CM D CD C XC L XL X IX V IV I>;
|
7
|
+
|
8
|
+
sub to-roman ($number is copy) is export {
|
9
|
+
[~] gather {
|
10
|
+
for %table.keys.sort.reverse -> $k {
|
11
|
+
if (my $repeat = $number div $k) {
|
12
|
+
$number -= $k * $repeat;
|
13
|
+
take %table{$k} x $repeat;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
exercise: RomanNumerals
|
2
|
+
version: 1
|
3
|
+
plan: 20
|
4
|
+
imports: '&to-roman'
|
5
|
+
tests: |-
|
6
|
+
for $c-data<cases>.values {
|
7
|
+
is to-roman(.<number>), |.<expected description>;
|
8
|
+
}
|
9
|
+
|
10
|
+
unit: module
|
11
|
+
example: |-
|
12
|
+
|
13
|
+
my %table{Int} = <1000 900 500 400 100 90 50 40 10 9 5 4 1>
|
14
|
+
Z=>
|
15
|
+
<M CM D CD C XC L XL X IX V IV I>;
|
16
|
+
|
17
|
+
sub to-roman ($number is copy) is export {
|
18
|
+
[~] gather {
|
19
|
+
for %table.keys.sort.reverse -> $k {
|
20
|
+
if (my $repeat = $number div $k) {
|
21
|
+
$number -= $k * $repeat;
|
22
|
+
take %table{$k} x $repeat;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
stub: |-
|
29
|
+
sub to-roman ($number) is export {
|
30
|
+
}
|
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/usr/bin/env perl6
|
2
|
+
use v6;
|
3
|
+
use Test;
|
4
|
+
use lib my $dir = $?FILE.IO.dirname;
|
5
|
+
use JSON::Fast;
|
6
|
+
|
7
|
+
my Str:D $exercise := 'RomanNumerals';
|
8
|
+
my Version:D $version = v1;
|
9
|
+
my Str $module //= $exercise;
|
10
|
+
plan 20;
|
11
|
+
|
12
|
+
use-ok $module or bail-out;
|
13
|
+
require ::($module);
|
14
|
+
|
15
|
+
if ::($exercise).^ver !~~ $version {
|
16
|
+
warn "\nExercise version mismatch. Further tests may fail!"
|
17
|
+
~ "\n$exercise is $(::($exercise).^ver.gist). "
|
18
|
+
~ "Test is $($version.gist).\n";
|
19
|
+
bail-out 'Example version must match test version.' if %*ENV<EXERCISM>;
|
20
|
+
}
|
21
|
+
|
22
|
+
require ::($module) <&to-roman>;
|
23
|
+
|
24
|
+
my $c-data = from-json $=pod.pop.contents;
|
25
|
+
for $c-data<cases>.values {
|
26
|
+
is to-roman(.<number>), |.<expected description>;
|
27
|
+
}
|
28
|
+
|
29
|
+
=head2 Canonical Data
|
30
|
+
=begin code
|
31
|
+
|
32
|
+
{
|
33
|
+
"exercise": "roman-numerals",
|
34
|
+
"version": "1.0.0",
|
35
|
+
"cases": [
|
36
|
+
{
|
37
|
+
"description": "1 is a single I",
|
38
|
+
"property": "roman",
|
39
|
+
"number": 1,
|
40
|
+
"expected": "I"
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"description": "2 is two I's",
|
44
|
+
"property": "roman",
|
45
|
+
"number": 2,
|
46
|
+
"expected": "II"
|
47
|
+
},
|
48
|
+
{
|
49
|
+
"description": "3 is three I's",
|
50
|
+
"property": "roman",
|
51
|
+
"number": 3,
|
52
|
+
"expected": "III"
|
53
|
+
},
|
54
|
+
{
|
55
|
+
"description": "4, being 5 - 1, is IV",
|
56
|
+
"property": "roman",
|
57
|
+
"number": 4,
|
58
|
+
"expected": "IV"
|
59
|
+
},
|
60
|
+
{
|
61
|
+
"description": "5 is a single V",
|
62
|
+
"property": "roman",
|
63
|
+
"number": 5,
|
64
|
+
"expected": "V"
|
65
|
+
},
|
66
|
+
{
|
67
|
+
"description": "6, being 5 + 1, is VI",
|
68
|
+
"property": "roman",
|
69
|
+
"number": 6,
|
70
|
+
"expected": "VI"
|
71
|
+
},
|
72
|
+
{
|
73
|
+
"description": "9, being 10 - 1, is IX",
|
74
|
+
"property": "roman",
|
75
|
+
"number": 9,
|
76
|
+
"expected": "IX"
|
77
|
+
},
|
78
|
+
{
|
79
|
+
"description": "20 is two X's",
|
80
|
+
"property": "roman",
|
81
|
+
"number": 27,
|
82
|
+
"expected": "XXVII"
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"description": "48 is not 50 - 2 but rather 40 + 8",
|
86
|
+
"property": "roman",
|
87
|
+
"number": 48,
|
88
|
+
"expected": "XLVIII"
|
89
|
+
},
|
90
|
+
{
|
91
|
+
"description": "50 is a single L",
|
92
|
+
"property": "roman",
|
93
|
+
"number": 59,
|
94
|
+
"expected": "LIX"
|
95
|
+
},
|
96
|
+
{
|
97
|
+
"description": "90, being 100 - 10, is XC",
|
98
|
+
"property": "roman",
|
99
|
+
"number": 93,
|
100
|
+
"expected": "XCIII"
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"description": "100 is a single C",
|
104
|
+
"property": "roman",
|
105
|
+
"number": 141,
|
106
|
+
"expected": "CXLI"
|
107
|
+
},
|
108
|
+
{
|
109
|
+
"description": "60, being 50 + 10, is LX",
|
110
|
+
"property": "roman",
|
111
|
+
"number": 163,
|
112
|
+
"expected": "CLXIII"
|
113
|
+
},
|
114
|
+
{
|
115
|
+
"description": "400, being 500 - 100, is CD",
|
116
|
+
"property": "roman",
|
117
|
+
"number": 402,
|
118
|
+
"expected": "CDII"
|
119
|
+
},
|
120
|
+
{
|
121
|
+
"description": "500 is a single D",
|
122
|
+
"property": "roman",
|
123
|
+
"number": 575,
|
124
|
+
"expected": "DLXXV"
|
125
|
+
},
|
126
|
+
{
|
127
|
+
"description": "900, being 1000 - 100, is CM",
|
128
|
+
"property": "roman",
|
129
|
+
"number": 911,
|
130
|
+
"expected": "CMXI"
|
131
|
+
},
|
132
|
+
{
|
133
|
+
"description": "1000 is a single M",
|
134
|
+
"property": "roman",
|
135
|
+
"number": 1024,
|
136
|
+
"expected": "MXXIV"
|
137
|
+
},
|
138
|
+
{
|
139
|
+
"description": "3000 is three M's",
|
140
|
+
"property": "roman",
|
141
|
+
"number": 3000,
|
142
|
+
"expected": "MMM"
|
143
|
+
}
|
144
|
+
]
|
145
|
+
}
|
146
|
+
|
147
|
+
=end code
|
148
|
+
|
149
|
+
unless %*ENV<EXERCISM> {
|
150
|
+
skip-rest 'exercism tests';
|
151
|
+
exit;
|
152
|
+
}
|
153
|
+
|
154
|
+
subtest 'canonical-data' => {
|
155
|
+
(my $c-data-file = "$dir/../../problem-specifications/exercises/{
|
156
|
+
$dir.IO.resolve.basename
|
157
|
+
}/canonical-data.json".IO.resolve) ~~ :f ??
|
158
|
+
is-deeply $c-data, EVAL('from-json $c-data-file.slurp'), 'match problem-specifications' !!
|
159
|
+
flunk 'problem-specifications file not found';
|
160
|
+
}
|
161
|
+
|
162
|
+
INIT { $module = 'Example' if %*ENV<EXERCISM> }
|
@@ -3,7 +3,7 @@ import unittest
|
|
3
3
|
from book_store import calculate_total
|
4
4
|
|
5
5
|
|
6
|
-
# Tests adapted from `problem-specifications//canonical-data.json` @ v1.0
|
6
|
+
# Tests adapted from `problem-specifications//canonical-data.json` @ v1.1.0
|
7
7
|
|
8
8
|
class BookStoreTests(unittest.TestCase):
|
9
9
|
def test_only_a_single_book(self):
|
@@ -67,6 +67,12 @@ class BookStoreTests(unittest.TestCase):
|
|
67
67
|
75.20,
|
68
68
|
places=2)
|
69
69
|
|
70
|
+
def test_four_groups_of_4_are_cheaper_than_2_groups_each_of_5_and_3(self):
|
71
|
+
self.assertAlmostEqual(
|
72
|
+
calculate_total([1, 1, 2, 2, 3, 3, 4, 5, 1, 1, 2, 2, 3, 3, 4, 5]),
|
73
|
+
102.40,
|
74
|
+
places=2)
|
75
|
+
|
70
76
|
|
71
77
|
if __name__ == '__main__':
|
72
78
|
unittest.main()
|
data/tracks/ruby/config.json
CHANGED
@@ -912,6 +912,17 @@
|
|
912
912
|
"slug": "complex-numbers",
|
913
913
|
"difficulty": 3,
|
914
914
|
"topics": [ "Mathematics" ]
|
915
|
+
},
|
916
|
+
{
|
917
|
+
"uuid": "a0aac827-8f7a-4065-9d05-a57009f5668d",
|
918
|
+
"slug": "isbn-verifier",
|
919
|
+
"core": false,
|
920
|
+
"unlocked_by": null,
|
921
|
+
"difficulty": 2,
|
922
|
+
"topics": [
|
923
|
+
"strings",
|
924
|
+
"logic"
|
925
|
+
]
|
915
926
|
}
|
916
927
|
],
|
917
928
|
"foregone": [
|
@@ -0,0 +1 @@
|
|
1
|
+
1
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'generator/exercise_case'
|
2
|
+
|
3
|
+
class IsbnVerifierCase < Generator::ExerciseCase
|
4
|
+
|
5
|
+
def workload
|
6
|
+
indent_lines(
|
7
|
+
[
|
8
|
+
"string = #{input.inspect}",
|
9
|
+
"#{assert} IsbnVerifier.valid?(string), #{failure_message}"
|
10
|
+
], 4
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def failure_message
|
17
|
+
%Q("Expected #{expected}, #{reason}")
|
18
|
+
end
|
19
|
+
|
20
|
+
def reason
|
21
|
+
"'\#{string}' #{is_or_not} a valid isbn"
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_or_not
|
25
|
+
expected ? 'is' : 'is not'
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module BookKeeping
|
2
|
+
VERSION = 1
|
3
|
+
end
|
4
|
+
|
5
|
+
class IsbnVerifier
|
6
|
+
def self.valid?(str)
|
7
|
+
return false unless /\A\d-?\d{3}-?\d{5}-?[\dX]\z/.match(str)
|
8
|
+
|
9
|
+
result = str
|
10
|
+
.gsub("-", "")
|
11
|
+
.chars
|
12
|
+
.map { |char|
|
13
|
+
char.gsub("X","10")
|
14
|
+
}
|
15
|
+
.zip(10.downto(1))
|
16
|
+
.map { |number, index|
|
17
|
+
number.to_i * index
|
18
|
+
}
|
19
|
+
.reduce(0){ |sum, digit|
|
20
|
+
sum + digit
|
21
|
+
}
|
22
|
+
|
23
|
+
result % 11 == 0
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Isbn Verifier
|
2
|
+
|
3
|
+
The [ISBN-10 verification process](https://en.wikipedia.org/wiki/International_Standard_Book_Number) is used to validate book identification
|
4
|
+
numbers. These normally contain dashes and look like: `3-598-21508-8`
|
5
|
+
|
6
|
+
## ISBN
|
7
|
+
|
8
|
+
The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula:
|
9
|
+
|
10
|
+
```
|
11
|
+
(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0
|
12
|
+
```
|
13
|
+
|
14
|
+
If the result is 0, then it is a valid ISBN-10, otherwise it is invalid.
|
15
|
+
|
16
|
+
## Example
|
17
|
+
|
18
|
+
Let's take the ISBN-10 `3-598-21508-8`. We plug it in to the formula, and get:
|
19
|
+
```
|
20
|
+
(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0
|
21
|
+
```
|
22
|
+
|
23
|
+
Since the result is 0, this proves that our ISBN is valid.
|
24
|
+
|
25
|
+
## Task
|
26
|
+
|
27
|
+
Given a string the program should check if the provided string is a valid ISBN-10.
|
28
|
+
Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN.
|
29
|
+
|
30
|
+
The program should be able to verify ISBN-10 both with and without separating dashes.
|
31
|
+
|
32
|
+
|
33
|
+
## Caveats
|
34
|
+
|
35
|
+
Converting from strings to numbers can be tricky in certain languages.
|
36
|
+
Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). For instance `3-598-21507-X` is a valid ISBN-10.
|
37
|
+
|
38
|
+
## Bonus tasks
|
39
|
+
|
40
|
+
* Generate a valid ISBN-13 from the input ISBN-10 (and maybe verify it again with a derived verifier).
|
41
|
+
|
42
|
+
* Generate valid ISBN, maybe even from a given starting ISBN.
|
43
|
+
* * * *
|
44
|
+
|
45
|
+
For installation and learning resources, refer to the
|
46
|
+
[exercism help page](http://exercism.io/languages/ruby).
|
47
|
+
|
48
|
+
For running the tests provided, you will need the Minitest gem. Open a
|
49
|
+
terminal window and run the following command to install minitest:
|
50
|
+
|
51
|
+
gem install minitest
|
52
|
+
|
53
|
+
If you would like color output, you can `require 'minitest/pride'` in
|
54
|
+
the test file, or note the alternative instruction, below, for running
|
55
|
+
the test file.
|
56
|
+
|
57
|
+
In order to run the test, you can run the test file from the exercise
|
58
|
+
directory. For example, if the test suite is called
|
59
|
+
`hello_world_test.rb`, you can run the following command:
|
60
|
+
|
61
|
+
ruby hello_world_test.rb
|
62
|
+
|
63
|
+
To include color from the command line:
|
64
|
+
|
65
|
+
ruby -r minitest/pride hello_world_test.rb
|
66
|
+
|
67
|
+
|
68
|
+
## Source
|
69
|
+
|
70
|
+
Converting a string into a number and some basic processing utilizing a relatable real world example. [https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation](https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation)
|
71
|
+
|
72
|
+
## Submitting Incomplete Solutions
|
73
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|