trackler 2.0.6.10 → 2.0.6.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/circular-buffer/canonical-data.json +343 -0
  3. data/common/exercises/luhn/description.md +4 -1
  4. data/common/exercises/secret-handshake/canonical-data.json +67 -0
  5. data/common/exercises/secret-handshake/description.md +6 -8
  6. data/common/exercises/variable-length-quantity/canonical-data.json +147 -0
  7. data/lib/trackler/version.rb +1 -1
  8. data/tracks/ceylon/.gitignore +1 -0
  9. data/tracks/ceylon/.travis.yml +6 -1
  10. data/tracks/ceylon/README.md +143 -4
  11. data/tracks/ceylon/bin/test-all-exercises +13 -0
  12. data/tracks/ceylon/bin/test-exercise +30 -0
  13. data/tracks/ceylon/config.json +33 -3
  14. data/tracks/ceylon/{SETUP.md → exercises/TRACK_HINTS.md} +0 -0
  15. data/tracks/ceylon/exercises/anagram/example/Anagram.ceylon +8 -0
  16. data/tracks/ceylon/exercises/anagram/source/anagram/Anagram.ceylon +3 -0
  17. data/tracks/ceylon/exercises/anagram/source/anagram/AnagramTest.ceylon +47 -0
  18. data/tracks/ceylon/exercises/anagram/source/anagram/module.ceylon +3 -0
  19. data/tracks/ceylon/exercises/bracket-push/example/Brackets.ceylon +18 -0
  20. data/tracks/ceylon/exercises/bracket-push/example/module.ceylon +4 -0
  21. data/tracks/ceylon/exercises/bracket-push/source/bracketpush/Brackets.ceylon +3 -0
  22. data/tracks/ceylon/exercises/bracket-push/source/bracketpush/BracketsTest.ceylon +37 -0
  23. data/tracks/ceylon/exercises/bracket-push/source/bracketpush/module.ceylon +3 -0
  24. data/tracks/ceylon/exercises/leap/example/Leap.ceylon +3 -0
  25. data/tracks/ceylon/exercises/leap/source/leap/Leap.ceylon +3 -0
  26. data/tracks/ceylon/exercises/leap/source/leap/LeapTest.ceylon +10 -0
  27. data/tracks/ceylon/exercises/leap/source/leap/module.ceylon +3 -0
  28. data/tracks/ceylon/exercises/sieve/example/Sieve.ceylon +24 -0
  29. data/tracks/ceylon/exercises/sieve/example/module.ceylon +4 -0
  30. data/tracks/ceylon/exercises/sieve/source/sieve/Sieve.ceylon +3 -0
  31. data/tracks/ceylon/exercises/sieve/source/sieve/SieveTest.ceylon +23 -0
  32. data/tracks/ceylon/exercises/sieve/source/sieve/module.ceylon +3 -0
  33. data/tracks/csharp/.travis.yml +4 -0
  34. data/tracks/elm/SETUP.md +5 -4
  35. data/tracks/fsharp/.travis.yml +4 -0
  36. data/tracks/go/config.json +6 -2
  37. data/tracks/go/exercises/luhn/example.go +5 -4
  38. data/tracks/go/exercises/luhn/luhn_test.go +18 -34
  39. data/tracks/java/exercises/word-count/src/test/java/WordCountTest.java +10 -13
  40. data/tracks/lua/docs/ABOUT.md +1 -1
  41. data/tracks/lua/docs/LEARNING.md +1 -0
  42. data/tracks/lua/docs/RESOURCES.md +6 -1
  43. data/tracks/lua/exercises/flatten-array/flatten-array_spec.lua +11 -0
  44. data/tracks/lua/exercises/luhn/example.lua +11 -27
  45. data/tracks/lua/exercises/luhn/luhn_spec.lua +12 -39
  46. data/tracks/ocaml/exercises/all-your-base/all_your_base.mli +0 -2
  47. data/tracks/ocaml/exercises/bracket-push/bracket_push.mli +0 -2
  48. data/tracks/ocaml/exercises/luhn/example.ml +12 -16
  49. data/tracks/ocaml/exercises/luhn/luhn.mli +1 -2
  50. data/tracks/ocaml/exercises/luhn/test.ml +15 -12
  51. data/tracks/php/config.json +8 -0
  52. data/tracks/php/exercises/grains/example.php +63 -0
  53. data/tracks/php/exercises/grains/grains_test.php +82 -0
  54. data/tracks/pony/config.json +26 -14
  55. data/tracks/pony/exercises/anagram/example.pony +17 -73
  56. data/tracks/pony/exercises/anagram/test.pony +6 -13
  57. data/tracks/pony/exercises/bob/example.pony +24 -24
  58. data/tracks/pony/exercises/bob/test.pony +16 -34
  59. data/tracks/pony/exercises/difference-of-squares/example.pony +13 -25
  60. data/tracks/pony/exercises/difference-of-squares/test.pony +9 -16
  61. data/tracks/pony/exercises/hamming/example.pony +8 -23
  62. data/tracks/pony/exercises/hamming/test.pony +16 -30
  63. data/tracks/pony/exercises/hello-world/example.pony +3 -9
  64. data/tracks/pony/exercises/hello-world/test.pony +2 -11
  65. data/tracks/pony/exercises/leap/example.pony +4 -10
  66. data/tracks/pony/exercises/leap/test.pony +2 -11
  67. data/tracks/ruby/lib/generator/command_line.rb +5 -6
  68. data/tracks/ruby/lib/generator/repository.rb +13 -13
  69. data/tracks/ruby/lib/tasks/exercise_test_tasks.rb +2 -4
  70. data/tracks/ruby/lib/tasks/exercise_tests_runner.rb +6 -8
  71. data/tracks/ruby/test/generator/repository_test.rb +26 -34
  72. data/tracks/rust/README.md +1 -1
  73. data/tracks/scheme/config.json +5 -0
  74. data/tracks/scheme/docs/ABOUT.md +7 -0
  75. data/tracks/scheme/exercises/scrabble-score/example.scm +16 -0
  76. data/tracks/scheme/exercises/scrabble-score/scrabble-score-test.scm +57 -0
  77. data/tracks/scheme/exercises/scrabble-score/scrabble-score.scm +2 -0
  78. metadata +33 -5
  79. data/tracks/ceylon/exercises/.keep +0 -0
  80. data/tracks/ceylon/img/.keep +0 -0
@@ -0,0 +1,3 @@
1
+ module anagram "1.0" {
2
+ import "ceylon.test" "1.3.1";
3
+ }
@@ -0,0 +1,18 @@
1
+ import ceylon.collection { ArrayList }
2
+
3
+ Map<Character, Character> openFor = map {'}' -> '{', ')' -> '(', ']' -> '['};
4
+ Set<Character> opens = set(openFor.items);
5
+
6
+ Boolean balanced(String brackets) {
7
+ value expectedOpens = ArrayList<Character>();
8
+ for (c in brackets) {
9
+ if (opens.contains(c)) {
10
+ expectedOpens.push(c);
11
+ } else if (exists open = openFor[c]) {
12
+ if ((expectedOpens.pop() else '!') != open) {
13
+ return false;
14
+ }
15
+ }
16
+ }
17
+ return expectedOpens.empty;
18
+ }
@@ -0,0 +1,4 @@
1
+ module bracketpush "1.0" {
2
+ import "ceylon.collection" "1.3.1";
3
+ import "ceylon.test" "1.3.1";
4
+ }
@@ -0,0 +1,3 @@
1
+ Boolean balanced(String brackets) {
2
+ return nothing;
3
+ }
@@ -0,0 +1,37 @@
1
+ import ceylon.test { ... }
2
+
3
+ {[String, Boolean]*} cases =>
4
+ {
5
+ // paired square brackets
6
+ ["[]", true],
7
+ // empty string
8
+ ["", true],
9
+ // unpaired brackets
10
+ ["[[", false],
11
+ // wrong ordered brackets
12
+ ["}{", false],
13
+ // paired with whitespace
14
+ ["{ }", true],
15
+ // simple nested brackets
16
+ ["{[]}", true],
17
+ // several paired brackets
18
+ ["{}[]", true],
19
+ // paired and nested brackets
20
+ ["([{}({}[])])", true],
21
+ // unopened closing brackets
22
+ ["{[)][]}", false],
23
+ // unpaired and nested brackets
24
+ ["([{])", false],
25
+ // paired and wrong nested brackets
26
+ ["[({]})", false],
27
+ // math expression
28
+ ["(((185 + 223.85) * 15) - 543)/2", true],
29
+ // complex latex expression
30
+ ["\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \\end{array}\\right)", true]
31
+ };
32
+
33
+ test
34
+ parameters(`value cases`)
35
+ void testBalanced(String brackets, Boolean expected) {
36
+ assertEquals(balanced(brackets), expected);
37
+ }
@@ -0,0 +1,3 @@
1
+ module bracketpush "1.0" {
2
+ import "ceylon.test" "1.3.1";
3
+ }
@@ -0,0 +1,3 @@
1
+ Boolean leapYear(Integer year) {
2
+ return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
3
+ }
@@ -0,0 +1,3 @@
1
+ Boolean leapYear(Integer year) {
2
+ return nothing;
3
+ }
@@ -0,0 +1,10 @@
1
+ import ceylon.test { ... }
2
+
3
+ {[Integer, Boolean]*} cases =>
4
+ {[2015, false], [2016, true], [2100, false], [2000, true]};
5
+
6
+ test
7
+ parameters(`value cases`)
8
+ void testLeapYear(Integer year, Boolean isLeap) {
9
+ assertEquals(leapYear(year), isLeap);
10
+ }
@@ -0,0 +1,3 @@
1
+ module leap "1.0" {
2
+ import "ceylon.test" "1.3.1";
3
+ }
@@ -0,0 +1,24 @@
1
+ import ceylon.numeric.float { sqrt }
2
+
3
+ {Integer*} primesUpTo(Integer max) {
4
+ // if max < 4, sqrt(max) < 2, so 2..sqrt(max) gives decreasing values.
5
+ // Prevent this by just returning the small primes here:
6
+ if (max < 4) {
7
+ return {2, 3}.takeWhile((c) => c <= max);
8
+ }
9
+
10
+ value prime = Array.ofSize(max + 1, true);
11
+ prime[0] = false;
12
+ prime[1] = false;
13
+
14
+ for (i in 2..(sqrt(max.float).integer)) {
15
+ if (!(prime[i] else false)) {
16
+ continue;
17
+ }
18
+
19
+ for (multiple in ((i * i)..max).by(i)) {
20
+ prime[multiple] = false;
21
+ }
22
+ }
23
+ return { for (i -> p in prime.indexed) if (p) i };
24
+ }
@@ -0,0 +1,4 @@
1
+ module sieve "1.0" {
2
+ import "ceylon.numeric" "1.3.1";
3
+ import "ceylon.test" "1.3.1";
4
+ }
@@ -0,0 +1,3 @@
1
+ {Integer*} primesUpTo(Integer max) {
2
+ return nothing;
3
+ }
@@ -0,0 +1,23 @@
1
+ import ceylon.test { ... }
2
+
3
+ {Integer*} cases => {1, 2, 10, 13, 1000};
4
+
5
+ [Integer+] primes1000 = [
6
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
7
+ 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
8
+ 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
9
+ 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
10
+ 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
11
+ 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
12
+ 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
13
+ 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
14
+ 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
15
+ 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
16
+ 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997
17
+ ];
18
+
19
+ test
20
+ parameters(`value cases`)
21
+ void testPrimesUpto(Integer max) {
22
+ assertEquals([*primesUpTo(max)], [*primes1000.takeWhile((x) => x <= max)]);
23
+ }
@@ -0,0 +1,3 @@
1
+ module sieve "1.0" {
2
+ import "ceylon.test" "1.3.1";
3
+ }
@@ -1,5 +1,9 @@
1
1
  language: csharp
2
2
 
3
+ os:
4
+ - linux
5
+ - osx
6
+
3
7
  script:
4
8
  - ./bin/fetch-configlet
5
9
  - ./bin/configlet .
@@ -1,11 +1,12 @@
1
1
  ## Elm Installation
2
2
 
3
- Refer to the [exercism help page][http://exercism.io/languages/elm] for Elm installation and learning
4
- resources.
3
+ Refer to the [Exercism help page](http://exercism.io/languages/elm) for Elm
4
+ installation and learning resources.
5
5
 
6
6
  ## Writing the Code
7
7
 
8
- The first time you start an exercise, you'll need to ensure you have the appropriate dependancies installed.
8
+ The first time you start an exercise, you'll need to ensure you have the
9
+ appropriate dependencies installed.
9
10
 
10
11
  ```bash
11
12
  $ npm install
@@ -15,4 +16,4 @@ Execute the tests with:
15
16
 
16
17
  ```bash
17
18
  $ npm test
18
- ```
19
+ ```
@@ -1,5 +1,9 @@
1
1
  language: csharp
2
2
 
3
+ os:
4
+ - linux
5
+ - osx
6
+
3
7
  script:
4
8
  - ./bin/fetch-configlet
5
9
  - ./bin/configlet .
@@ -46,9 +46,13 @@
46
46
  ]
47
47
  },
48
48
  {
49
- "difficulty": 1,
49
+ "difficulty": 3,
50
50
  "slug": "clock",
51
- "topics": []
51
+ "topics": [
52
+ "Time",
53
+ "Mathematics",
54
+ "Text formatting"
55
+ ]
52
56
  },
53
57
  {
54
58
  "difficulty": 1,
@@ -1,6 +1,11 @@
1
1
  package luhn
2
2
 
3
+ const testVersion = 1
4
+
3
5
  func Valid(n string) bool {
6
+ if len(n) == 1 {
7
+ return false
8
+ }
4
9
  d := extract(n)
5
10
  if len(d) == 0 {
6
11
  return false
@@ -33,7 +38,3 @@ func check(d []int) int {
33
38
  }
34
39
  return s
35
40
  }
36
-
37
- func AddCheck(raw string) string {
38
- return raw + string('0'+(10-check(extract(raw))%10)%10)
39
- }
@@ -2,41 +2,25 @@ package luhn
2
2
 
3
3
  import "testing"
4
4
 
5
- var validTests = []struct {
6
- n string
7
- ok bool
8
- }{
9
- {"738", false},
10
- {"8739567", true},
11
- {"1111", false},
12
- {"8763", true},
13
- {" ", false},
14
- {"", false},
15
- {"2323 2005 7766 3554", true},
16
- }
5
+ const targetTestVersion = 1
17
6
 
18
- var addTests = []struct{ raw, luhn string }{
19
- {"123", "1230"},
20
- {"873956", "8739567"},
21
- {"837263756", "8372637564"},
22
- {"2323 2005 7766 355", "2323 2005 7766 3554"},
23
- // bonus Unicode cases
24
- // {"2323·2005·7766·355", "2323·2005·7766·3554"},
25
- // {"123", "1230"},
7
+ var testCases = []struct {
8
+ input string
9
+ description string
10
+ ok bool
11
+ }{
12
+ {"1", "single digit strings can not be valid", false},
13
+ {"0", "a single zero is invalid", false},
14
+ {"046 454 286", "valid Canadian SIN", true},
15
+ {"046 454 287", "invalid Canadian SIN", false},
16
+ {"8273 1232 7352 0569", "invalid credit card", false},
17
+ {"827a 1232 7352 0569", "strings that contain non-digits are not valid", false},
26
18
  }
27
19
 
28
20
  func TestValid(t *testing.T) {
29
- for _, test := range validTests {
30
- if ok := Valid(test.n); ok != test.ok {
31
- t.Fatalf("Valid(%s) = %t, want %t.", test.n, ok, test.ok)
32
- }
33
- }
34
- }
35
-
36
- func TestAddCheck(t *testing.T) {
37
- for _, test := range addTests {
38
- if luhn := AddCheck(test.raw); luhn != test.luhn {
39
- t.Fatalf("AddCheck(%s) = %s, want %s.", test.raw, luhn, test.luhn)
21
+ for _, test := range testCases {
22
+ if ok := Valid(test.input); ok != test.ok {
23
+ t.Fatalf("Valid(%s): %s\n\t Expected: %t\n\t Got: %t", test.input, test.description, ok, test.ok)
40
24
  }
41
25
  }
42
26
  }
@@ -47,8 +31,8 @@ func BenchmarkValid(b *testing.B) {
47
31
  }
48
32
  }
49
33
 
50
- func BenchmarkAddCheck(b *testing.B) {
51
- for i := 0; i < b.N; i++ {
52
- AddCheck("2323 2005 7766 355")
34
+ func TestTestVersion(t *testing.T) {
35
+ if testVersion != targetTestVersion {
36
+ t.Errorf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
53
37
  }
54
38
  }
@@ -1,3 +1,4 @@
1
+ import org.junit.Before;
1
2
  import org.junit.Test;
2
3
  import org.junit.Ignore;
3
4
 
@@ -10,13 +11,19 @@ import static org.junit.Assert.*;
10
11
 
11
12
  public class WordCountTest {
12
13
 
13
- private final WordCount wordCount = new WordCount();
14
+ private WordCount wordCount;
15
+ private Map<String, Integer> actualWordCount;
16
+ private Map<String, Integer> expectedWordCount;
17
+
18
+ @Before
19
+ public void setup() {
20
+ wordCount = new WordCount();
21
+ expectedWordCount = new HashMap<String, Integer>();
22
+ }
14
23
 
15
24
 
16
25
  @Test
17
26
  public void countOneWord() {
18
- Map<String, Integer> actualWordCount = new HashMap<String, Integer>();
19
- final Map<String, Integer> expectedWordCount = new HashMap<String, Integer>();
20
27
  expectedWordCount.put("word", 1);
21
28
 
22
29
  actualWordCount = wordCount.phrase("word");
@@ -28,8 +35,6 @@ public class WordCountTest {
28
35
  @Ignore
29
36
  @Test
30
37
  public void countOneOfEach() {
31
- Map<String, Integer> actualWordCount = new HashMap<String, Integer>();
32
- final Map<String, Integer> expectedWordCount = new HashMap<String, Integer>();
33
38
  expectedWordCount.put("one", 1);
34
39
  expectedWordCount.put("of", 1);
35
40
  expectedWordCount.put("each", 1);
@@ -43,8 +48,6 @@ public class WordCountTest {
43
48
  @Ignore
44
49
  @Test
45
50
  public void countMultipleOccurences() {
46
- Map<String, Integer> actualWordCount = new HashMap<String, Integer>();
47
- final Map<String, Integer> expectedWordCount = new HashMap<String, Integer>();
48
51
  expectedWordCount.put("one", 1);
49
52
  expectedWordCount.put("fish", 4);
50
53
  expectedWordCount.put("two", 1);
@@ -60,8 +63,6 @@ public class WordCountTest {
60
63
  @Ignore
61
64
  @Test
62
65
  public void ignorePunctuation() {
63
- Map<String, Integer> actualWordCount = new HashMap<String, Integer>();
64
- final Map<String, Integer> expectedWordCount = new HashMap<String, Integer>();
65
66
  expectedWordCount.put("car", 1);
66
67
  expectedWordCount.put("carpet", 1);
67
68
  expectedWordCount.put("as", 1);
@@ -78,8 +79,6 @@ public class WordCountTest {
78
79
  @Ignore
79
80
  @Test
80
81
  public void includeNumbers() {
81
- Map<String, Integer> actualWordCount = new HashMap<String, Integer>();
82
- final Map<String, Integer> expectedWordCount = new HashMap<String, Integer>();
83
82
  expectedWordCount.put("testing", 2);
84
83
  expectedWordCount.put("1", 1);
85
84
  expectedWordCount.put("2", 1);
@@ -93,8 +92,6 @@ public class WordCountTest {
93
92
  @Ignore
94
93
  @Test
95
94
  public void normalizeCase() {
96
- Map<String, Integer> actualWordCount = new HashMap<String, Integer>();
97
- final Map<String, Integer> expectedWordCount = new HashMap<String, Integer>();
98
95
  expectedWordCount.put("go", 3);
99
96
 
100
97
  actualWordCount = wordCount.phrase("go Go GO");
@@ -4,6 +4,6 @@ Lua supports procedural, object-oriented, functional, data-driven programming an
4
4
 
5
5
  Lua has been used in [many industrial applications](https://sites.google.com/site/marbux/home/where-lua-is-used#8S4UcLlroV5fq8i3WSheIA) with an emphasis on embedded systems and games.
6
6
 
7
- The home page for Lua is [Lua.org](https://www.lua.org/). You can [learn the language in 15 minutes](tylerneylon.com/a/learn-lua/). Enjoy!
7
+ The home page for Lua is [Lua.org](https://www.lua.org/). Enjoy!
8
8
 
9
9
  (Taken from https://www.lua.org/about.html)
@@ -0,0 +1 @@
1
+ Lua is a very small language and you can [learn the basics of the language in 15 minutes](tylerneylon.com/a/learn-lua/). For an exhaustive look at the language, written by the authors of Lua, you can read [Programming in Lua](https://www.lua.org/pil/) (the first edition which covers Lua 5.1 [is available online for free](https://www.lua.org/pil/contents.html)).
@@ -1,13 +1,18 @@
1
1
  There are many great free online resources for Lua including:
2
2
 
3
3
  1. [lua.org][8]
4
- 2. A highly recommended detailed and authoritative introduction to all aspects of Lua programming by Lua's chief architect: [Programming in Lua (2nd edition), by Roberto Ierusalimschy][6]
4
+ 2. A highly recommended detailed and authoritative introduction to all aspects of Lua programming by Lua's chief architect: [Programming in Lua, by Roberto Ierusalimschy][6]
5
5
  3. For an official definition of the Lua language, consult the [Lua 5.1 Reference Manual][7], by R. Ierusalimschy, L. H. de Figueiredo, W. Celes.
6
6
  4. [Lua Style Guide][4]
7
7
  5. [Learn Lua in 15 minutes][5]
8
+ 6. [Some][9] [options][10] [for][11] [linting][12]
8
9
 
9
10
  [4]: https://github.com/Olivine-Labs/lua-style-guide
10
11
  [5]: http://tylerneylon.com/a/learn-lua/
11
12
  [6]: http://www.lua.org/pil/
12
13
  [7]: http://www.lua.org/manual/5.1/
13
14
  [8]: http://www.lua.org
15
+ [9]: https://code.google.com/p/lua-checker/
16
+ [10]: http://lua-users.org/wiki/LuaLint
17
+ [11]: http://lua-users.org/wiki/LuaInspect
18
+ [12]: http://lua-users.org/wiki/DetectingUndefinedVariables
@@ -1,3 +1,14 @@
1
+ --[[-
2
+ Note that because ipairs and the length operator work correctly only for sequences
3
+ in Lua, no arrays with nils are included in these tests. This means that the provided
4
+ example is not included here:
5
+
6
+ input: [1,[2,3,null,4],[null],5]
7
+ output: [1,2,3,4,5]
8
+
9
+ See https://www.lua.org/manual/5.3/manual.html#3.4.7 for more information.
10
+ ]]
11
+
1
12
  local flatten = require 'flatten-array'
2
13
 
3
14
  describe('flatten-array', function()
@@ -1,14 +1,7 @@
1
- local Luhn = {}
2
- Luhn.__index = Luhn
3
-
4
- function Luhn:check_digit()
5
- return tonumber(self.s:sub(-1))
6
- end
7
-
8
- function Luhn:addends()
1
+ local function addends(s)
9
2
  local result = {}
10
- for i = #self.s, 1, -1 do
11
- local digit = tonumber(self.s:sub(i, i))
3
+ for i = #s, 1, -1 do
4
+ local digit = tonumber(s:sub(i, i))
12
5
  if #result % 2 > 0 then digit = digit * 2 end
13
6
  if digit > 9 then digit = digit - 9 end
14
7
  table.insert(result, 1, digit)
@@ -16,28 +9,19 @@ function Luhn:addends()
16
9
  return result
17
10
  end
18
11
 
19
- function Luhn:checksum()
12
+ local function checksum(s)
20
13
  local checksum = 0
21
- for _, addend in ipairs(self:addends()) do
14
+ for _, addend in ipairs(addends(s)) do
22
15
  checksum = checksum + addend
23
16
  end
24
17
  return checksum
25
18
  end
26
19
 
27
- function Luhn:valid()
28
- return self:checksum() % 10 == 0
29
- end
30
-
31
- local function new(s)
32
- return setmetatable({ s = s }, Luhn)
33
- end
34
-
35
- local function create(s)
36
- local checksum = new(s .. '0'):checksum()
37
- return s .. tostring((10 - (checksum % 10)) % 10)
38
- end
39
-
40
20
  return {
41
- new = new,
42
- create = create
21
+ valid = function(s)
22
+ s = s:gsub(' ', '')
23
+ if #s < 2 then return false end
24
+ if s:find('%D') then return false end
25
+ return checksum(s) % 10 == 0
26
+ end
43
27
  }