diff options
Diffstat (limited to 'raku/clock')
-rw-r--r-- | raku/clock/Clock.rakumod | 27 | ||||
-rw-r--r-- | raku/clock/README.md | 30 | ||||
-rw-r--r-- | raku/clock/clock.rakutest | 642 |
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 |