summary refs log tree commit diff stats
path: root/raku/clock
diff options
context:
space:
mode:
Diffstat (limited to 'raku/clock')
-rw-r--r--raku/clock/Clock.rakumod27
-rw-r--r--raku/clock/README.md30
-rw-r--r--raku/clock/clock.rakutest642
3 files changed, 699 insertions, 0 deletions
diff --git a/raku/clock/Clock.rakumod b/raku/clock/Clock.rakumod
new file mode 100644
index 0000000..cf2b5d4
--- /dev/null
+++ b/raku/clock/Clock.rakumod
@@ -0,0 +1,27 @@
+unit class Clock;
+
+has Int $.hour;
+has Int $.minute;
+
+submethod TWEAK() { self.wrap-time; }
+
+method time { sprintf "%02d:%02d", $!hour, $!minute; }
+
+method add-minutes(UInt $amount --> Clock) {
+    $!hour += $amount div 60;
+    $!minute += $amount % 60;
+    self.wrap-time;
+}
+
+method subtract-minutes(UInt $amount --> Clock) {
+    $!hour -= $amount div 60;
+    $!minute -= $amount % 60;
+    self.wrap-time;
+}
+
+method wrap-time(--> Clock) {
+    $!hour += $!minute div 60;
+    $!minute %= 60;
+    $!hour %= 24;
+    return self;
+}
diff --git a/raku/clock/README.md b/raku/clock/README.md
new file mode 100644
index 0000000..57a61aa
--- /dev/null
+++ b/raku/clock/README.md
@@ -0,0 +1,30 @@
+# Clock
+
+Implement a clock that handles times without dates.
+
+You should be able to add and subtract minutes to it.
+
+Two clocks that represent the same time should be equal to each other.
+
+## Resources
+
+Remember to check out the Raku [documentation](https://docs.raku.org/) and
+[resources](https://raku.org/resources/) pages for information, tips, and
+examples if you get stuck.
+
+## Running the tests
+
+There is a test suite and module included with the exercise.
+The test suite (a file with the extension `.rakutest`) will attempt to run routines
+from the module (a file with the extension `.rakumod`).
+Add/modify routines in the module so that the tests will pass! You can view the
+test data by executing the command `raku --doc *.rakutest` (\* being the name of the
+test suite), and run the test suite for the exercise by executing the command
+`prove6 .` in the exercise directory.
+
+## Source
+
+Pairing session with Erin Drummond [https://twitter.com/ebdrummond](https://twitter.com/ebdrummond)
+
+## Submitting Incomplete Solutions
+It's possible to submit an incomplete solution so you can see how others have completed the exercise.
diff --git a/raku/clock/clock.rakutest b/raku/clock/clock.rakutest
new file mode 100644
index 0000000..ee57c0e
--- /dev/null
+++ b/raku/clock/clock.rakutest
@@ -0,0 +1,642 @@
+#!/usr/bin/env raku
+use Test;
+use JSON::Fast;
+use lib $?FILE.IO.dirname;
+use Clock;
+plan 55;
+
+subtest 'Class methods', {
+  for <time add-minutes subtract-minutes> -> $method {
+    can-ok Clock, $method;
+  }
+} or bail-out 'Cannot run expected method(s).';
+
+my @test-cases = from-json($=pod.pop.contents).List;
+for @test-cases -> %case {
+  given %case<property> {
+
+    when 'create' {
+      is Clock.new( |%(.<input><hour minute>:p) ).time,
+        |.<expected description> given %case;
+    }
+
+    when <add subtract>.any {
+      given %case {
+        my $clock = Clock.new: |%(.<input><hour minute>:p);
+        $clock.add-minutes: .<input><value>
+          if .<property> eq 'add';
+        $clock.subtract-minutes: .<input><value>
+          if .<property> eq 'subtract';
+        is $clock.time, |.<expected description>;
+      }
+    }
+
+    when 'equal' {
+      is-deeply ([eq] gather {
+        take Clock.new( |%(.<hour minute>:p) ).time
+          for %case<input><clock1 clock2>;
+      }), |%case<expected description>;
+    }
+
+  }
+}
+
+is Clock.new(:0hour,:0minute).add-minutes(65).?time,
+  '01:05', 'add-minutes method can be chained';
+
+is Clock.new(:0hour,:0minute).subtract-minutes(65).?time,
+  '22:55', 'subtract-minutes method can be chained';
+
+CATCH {
+  when X::StubCode {
+    flunk 'Caught stub';
+    note "{.message} (does the sub/method contain '!!!'?)\n"
+      ~ .backtrace.concise;
+  }
+}
+
+=head2 Test Cases
+=begin code
+[
+  {
+    "description": "Create a new clock with an initial time: on the hour",
+    "expected": "08:00",
+    "input": {
+      "hour": 8,
+      "minute": 0
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: past the hour",
+    "expected": "11:09",
+    "input": {
+      "hour": 11,
+      "minute": 9
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: midnight is zero hours",
+    "expected": "00:00",
+    "input": {
+      "hour": 24,
+      "minute": 0
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: hour rolls over",
+    "expected": "01:00",
+    "input": {
+      "hour": 25,
+      "minute": 0
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: hour rolls over continuously",
+    "expected": "04:00",
+    "input": {
+      "hour": 100,
+      "minute": 0
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: sixty minutes is next hour",
+    "expected": "02:00",
+    "input": {
+      "hour": 1,
+      "minute": 60
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: minutes roll over",
+    "expected": "02:40",
+    "input": {
+      "hour": 0,
+      "minute": 160
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: minutes roll over continuously",
+    "expected": "04:43",
+    "input": {
+      "hour": 0,
+      "minute": 1723
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: hour and minutes roll over",
+    "expected": "03:40",
+    "input": {
+      "hour": 25,
+      "minute": 160
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: hour and minutes roll over continuously",
+    "expected": "11:01",
+    "input": {
+      "hour": 201,
+      "minute": 3001
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: hour and minutes roll over to exactly midnight",
+    "expected": "00:00",
+    "input": {
+      "hour": 72,
+      "minute": 8640
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative hour",
+    "expected": "23:15",
+    "input": {
+      "hour": -1,
+      "minute": 15
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative hour rolls over",
+    "expected": "23:00",
+    "input": {
+      "hour": -25,
+      "minute": 0
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative hour rolls over continuously",
+    "expected": "05:00",
+    "input": {
+      "hour": -91,
+      "minute": 0
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative minutes",
+    "expected": "00:20",
+    "input": {
+      "hour": 1,
+      "minute": -40
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative minutes roll over",
+    "expected": "22:20",
+    "input": {
+      "hour": 1,
+      "minute": -160
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative minutes roll over continuously",
+    "expected": "16:40",
+    "input": {
+      "hour": 1,
+      "minute": -4820
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative sixty minutes is previous hour",
+    "expected": "01:00",
+    "input": {
+      "hour": 2,
+      "minute": -60
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative hour and minutes both roll over",
+    "expected": "20:20",
+    "input": {
+      "hour": -25,
+      "minute": -160
+    },
+    "property": "create"
+  },
+  {
+    "description": "Create a new clock with an initial time: negative hour and minutes both roll over continuously",
+    "expected": "22:10",
+    "input": {
+      "hour": -121,
+      "minute": -5810
+    },
+    "property": "create"
+  },
+  {
+    "description": "Add minutes: add minutes",
+    "expected": "10:03",
+    "input": {
+      "hour": 10,
+      "minute": 0,
+      "value": 3
+    },
+    "property": "add"
+  },
+  {
+    "description": "Add minutes: add no minutes",
+    "expected": "06:41",
+    "input": {
+      "hour": 6,
+      "minute": 41,
+      "value": 0
+    },
+    "property": "add"
+  },
+  {
+    "description": "Add minutes: add to next hour",
+    "expected": "01:25",
+    "input": {
+      "hour": 0,
+      "minute": 45,
+      "value": 40
+    },
+    "property": "add"
+  },
+  {
+    "description": "Add minutes: add more than one hour",
+    "expected": "11:01",
+    "input": {
+      "hour": 10,
+      "minute": 0,
+      "value": 61
+    },
+    "property": "add"
+  },
+  {
+    "description": "Add minutes: add more than two hours with carry",
+    "expected": "03:25",
+    "input": {
+      "hour": 0,
+      "minute": 45,
+      "value": 160
+    },
+    "property": "add"
+  },
+  {
+    "description": "Add minutes: add across midnight",
+    "expected": "00:01",
+    "input": {
+      "hour": 23,
+      "minute": 59,
+      "value": 2
+    },
+    "property": "add"
+  },
+  {
+    "description": "Add minutes: add more than one day (1500 min = 25 hrs)",
+    "expected": "06:32",
+    "input": {
+      "hour": 5,
+      "minute": 32,
+      "value": 1500
+    },
+    "property": "add"
+  },
+  {
+    "description": "Add minutes: add more than two days",
+    "expected": "11:21",
+    "input": {
+      "hour": 1,
+      "minute": 1,
+      "value": 3500
+    },
+    "property": "add"
+  },
+  {
+    "description": "Subtract minutes: subtract minutes",
+    "expected": "10:00",
+    "input": {
+      "hour": 10,
+      "minute": 3,
+      "value": 3
+    },
+    "property": "subtract"
+  },
+  {
+    "description": "Subtract minutes: subtract to previous hour",
+    "expected": "09:33",
+    "input": {
+      "hour": 10,
+      "minute": 3,
+      "value": 30
+    },
+    "property": "subtract"
+  },
+  {
+    "description": "Subtract minutes: subtract more than an hour",
+    "expected": "08:53",
+    "input": {
+      "hour": 10,
+      "minute": 3,
+      "value": 70
+    },
+    "property": "subtract"
+  },
+  {
+    "description": "Subtract minutes: subtract across midnight",
+    "expected": "23:59",
+    "input": {
+      "hour": 0,
+      "minute": 3,
+      "value": 4
+    },
+    "property": "subtract"
+  },
+  {
+    "description": "Subtract minutes: subtract more than two hours",
+    "expected": "21:20",
+    "input": {
+      "hour": 0,
+      "minute": 0,
+      "value": 160
+    },
+    "property": "subtract"
+  },
+  {
+    "description": "Subtract minutes: subtract more than two hours with borrow",
+    "expected": "03:35",
+    "input": {
+      "hour": 6,
+      "minute": 15,
+      "value": 160
+    },
+    "property": "subtract"
+  },
+  {
+    "description": "Subtract minutes: subtract more than one day (1500 min = 25 hrs)",
+    "expected": "04:32",
+    "input": {
+      "hour": 5,
+      "minute": 32,
+      "value": 1500
+    },
+    "property": "subtract"
+  },
+  {
+    "description": "Subtract minutes: subtract more than two days",
+    "expected": "00:20",
+    "input": {
+      "hour": 2,
+      "minute": 20,
+      "value": 3000
+    },
+    "property": "subtract"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with same time",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 15,
+        "minute": 37
+      },
+      "clock2": {
+        "hour": 15,
+        "minute": 37
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks a minute apart",
+    "expected": false,
+    "input": {
+      "clock1": {
+        "hour": 15,
+        "minute": 36
+      },
+      "clock2": {
+        "hour": 15,
+        "minute": 37
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks an hour apart",
+    "expected": false,
+    "input": {
+      "clock1": {
+        "hour": 14,
+        "minute": 37
+      },
+      "clock2": {
+        "hour": 15,
+        "minute": 37
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with hour overflow",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 10,
+        "minute": 37
+      },
+      "clock2": {
+        "hour": 34,
+        "minute": 37
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with hour overflow by several days",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 3,
+        "minute": 11
+      },
+      "clock2": {
+        "hour": 99,
+        "minute": 11
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with negative hour",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 22,
+        "minute": 40
+      },
+      "clock2": {
+        "hour": -2,
+        "minute": 40
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with negative hour that wraps",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 17,
+        "minute": 3
+      },
+      "clock2": {
+        "hour": -31,
+        "minute": 3
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with negative hour that wraps multiple times",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 13,
+        "minute": 49
+      },
+      "clock2": {
+        "hour": -83,
+        "minute": 49
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with minute overflow",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 0,
+        "minute": 1
+      },
+      "clock2": {
+        "hour": 0,
+        "minute": 1441
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with minute overflow by several days",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 2,
+        "minute": 2
+      },
+      "clock2": {
+        "hour": 2,
+        "minute": 4322
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with negative minute",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 2,
+        "minute": 40
+      },
+      "clock2": {
+        "hour": 3,
+        "minute": -20
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with negative minute that wraps",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 4,
+        "minute": 10
+      },
+      "clock2": {
+        "hour": 5,
+        "minute": -1490
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with negative minute that wraps multiple times",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 6,
+        "minute": 15
+      },
+      "clock2": {
+        "hour": 6,
+        "minute": -4305
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with negative hours and minutes",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 7,
+        "minute": 32
+      },
+      "clock2": {
+        "hour": -12,
+        "minute": -268
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: clocks with negative hours and minutes that wrap",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 18,
+        "minute": 7
+      },
+      "clock2": {
+        "hour": -54,
+        "minute": -11513
+      }
+    },
+    "property": "equal"
+  },
+  {
+    "description": "Compare two clocks for equality: full clock and zeroed clock",
+    "expected": true,
+    "input": {
+      "clock1": {
+        "hour": 24,
+        "minute": 0
+      },
+      "clock2": {
+        "hour": 0,
+        "minute": 0
+      }
+    },
+    "property": "equal"
+  }
+]
+=end code