diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml
new file mode 100644
index 0000000..7de0407
--- /dev/null
+++ b/.github/workflows/code-coverage.yml
@@ -0,0 +1,31 @@
+name: Code Coverage
+
+on:
+ push:
+ branches: [ master ]
+
+ workflow_dispatch:
+
+jobs:
+ raku:
+ strategy:
+ matrix:
+ os:
+ - ubuntu-latest
+ raku-version:
+ - 'latest'
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v2
+ - uses: Raku/setup-raku@v1
+ with:
+ raku-version: ${{ matrix.raku-version }}
+ - name: Install Dependencies
+ run: zef install --/test --test-depends --deps-only .
+ - name: Install Test Engine
+ run: zef install --/test App::Racoco App::Racoco::Report::ReporterCoveralls App::Prove6
+ - name: Run RaCoCo
+ run: racoco coveralls
+ env:
+ RAKULIB: './lib'
+ COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
new file mode 100644
index 0000000..0de0eca
--- /dev/null
+++ b/.github/workflows/macos.yml
@@ -0,0 +1,28 @@
+name: MacOS
+
+on:
+ push:
+ branches: [ master, dev ]
+
+ workflow_dispatch:
+
+jobs:
+ raku:
+ strategy:
+ matrix:
+ os:
+ - macOS-latest
+ raku-version:
+ - 'latest'
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v2
+ - uses: Raku/setup-raku@v1
+ with:
+ raku-version: ${{ matrix.raku-version }}
+ - name: Install Dependencies
+ run: zef install --/test --test-depends --deps-only .
+ - name: Install Test Engine
+ run: zef install --/test App::Prove6
+ - name: Run Tests
+ run: prove6 t
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
deleted file mode 100644
index 8e26cdb..0000000
--- a/.github/workflows/main.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: build
-
-on:
- push:
- branches:
- - dev
- - master
-jobs:
- build:
- name: prove
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v1
- - name: Runs tests
- id: tests
- uses: JJ/raku-container-action@master
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
new file mode 100644
index 0000000..295647c
--- /dev/null
+++ b/.github/workflows/ubuntu.yml
@@ -0,0 +1,30 @@
+name: Ubuntu
+
+on:
+ push:
+ branches: [ master, dev ]
+ pull_request:
+ branches: [ master ]
+
+ workflow_dispatch:
+
+jobs:
+ raku:
+ strategy:
+ matrix:
+ os:
+ - ubuntu-latest
+ raku-version:
+ - 'latest'
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v2
+ - uses: Raku/setup-raku@v1
+ with:
+ raku-version: ${{ matrix.raku-version }}
+ - name: Install Dependencies
+ run: zef install --/test --test-depends --deps-only .
+ - name: Install Test Engine
+ run: zef install --/test App::Prove6
+ - name: Run Tests
+ run: prove6 t
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
new file mode 100644
index 0000000..25a46c8
--- /dev/null
+++ b/.github/workflows/windows.yml
@@ -0,0 +1,28 @@
+name: Windows
+
+on:
+ push:
+ branches: [ master, dev ]
+
+ workflow_dispatch:
+
+jobs:
+ raku:
+ strategy:
+ matrix:
+ os:
+ - windows-latest
+ raku-version:
+ - 'latest'
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v2
+ - uses: Raku/setup-raku@v1
+ with:
+ raku-version: ${{ matrix.raku-version }}
+ - name: Install Dependencies
+ run: zef install --/test --test-depends --deps-only .
+ - name: Install Test Engine
+ run: zef install --/test App::Prove6
+ - name: Run Tests
+ run: prove6 t
diff --git a/.gitignore b/.gitignore
index fd0a2b7..38b559c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
-.idea/
-**/.precomp/
\ No newline at end of file
+**/*.iml
+**/.idea/**
+**/.precomp/**
+**/.racoco/**
+**/.DS_Store
diff --git a/Changes b/Changes
new file mode 100644
index 0000000..e4e3922
--- /dev/null
+++ b/Changes
@@ -0,0 +1,7 @@
+Version history:
+
+
+1.3.1 2021-03-14 'Rethinking API'
+ - Implemented the new API of the module
+
+0.1.1 ....-..-.. 'The first public release'
diff --git a/META6.json b/META6.json
index ad554a5..ef14521 100644
--- a/META6.json
+++ b/META6.json
@@ -1,13 +1,22 @@
{
- "perl" : "6.*",
- "name" : "TimeUnit",
- "version" : "0.1.1",
- "description" : "Library for conversion a time unit to another.",
- "author" : [ "Mikhail Khorkov" ],
- "license" : "Artistic-2.0",
- "provides" : {
- "TimeUnit" : "lib/TimeUnit.rakumod"
+ "name": "TimeUnit",
+ "description": "Library for conversion a time from one unit to another.",
+ "version": "1.3.1",
+ "perl": "6.d",
+ "authors": [
+ "Mikhail Khorkov"
+ ],
+ "auth": "zef:atroxaper",
+ "depends": [],
+ "build-depends": [],
+ "test-depends": [],
+ "provides": {
+ "TimeUnit": "lib/TimeUnit.rakumod"
},
- "tags": [ "time" ],
- "source-url" : "git://github.com/atroxaper/p6-TimeUnit.git"
-}
+ "license": "Artistic-2.0",
+ "tags": [
+ "TIME"
+ ],
+ "api": "1",
+ "source-url": "https://github.com/atroxaper/raku-TimeUnit.git"
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index cb5e252..b03d658 100644
--- a/README.md
+++ b/README.md
@@ -1,71 +1,50 @@
-[![Build Status](https://github.com/atroxaper/p6-TimeUnit/workflows/build/badge.svg)](https://github.com/atroxaper/p6-TimeUnit/actions)
+[![Ubuntu](https://github.com/atroxaper/raku-TimeUnit/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/atroxaper/raku-TimeUnit/actions/workflows/ubuntu.yml)
+[![MacOS](https://github.com/atroxaper/raku-TimeUnit/actions/workflows/macos.yml/badge.svg)](https://github.com/atroxaper/raku-TimeUnit/actions/workflows/macos.yml)
+[![Windows](https://github.com/atroxaper/raku-TimeUnit/actions/workflows/windows.yml/badge.svg)](https://github.com/atroxaper/raku-TimeUnit/actions/workflows/windows.yml)
+[![Coverage Status](https://coveralls.io/repos/github/atroxaper/raku-TimeUnit/badge.svg?branch=master)](https://coveralls.io/github/atroxaper/raku-TimeUnit?branch=master)
-TimeUnit
-========
+# NAME
-Library for conversion a time unit to another.
+`TimeUnit` - library for conversion a time from one unit to another.
-Purpose
--------
+# SYNOPSIS
-* Add possibility to use different time units in
-code - not only seconds:
+
+use TimeUnit;
- sub beep-after($time, TimeUnit:D $unit) { ... }
- beep-after(5, hours);
- beep-after(3, seconds);
+sub beep-after(TimeUnit:D $time) {
+ Promise.in($time.to-seconds).then: { beep() }
+}
-* Add a simple way for conversion time units from
-one to another without any 'magic numbers' in code:
+Promise.in(timeunit(:3days :1hour :3sec).to-seconds).then: { send-email() }
- say 'In 36 hours contains ', seconds.from(:36hours), ' seconds.';
+days(4) + hours(3).minus(nanos(3)) < timeunit(:4d :3h);
-Exported constants
-------------------
+minutes(15).to(hours) == 0.25;
+
-**nanos** - just nanoseconds;
+# INSTALLATION
-**micros** - is a thousand of nanoseconds;
+If you use zef, then `zef install TimeUnit`, or `pakku add TimeUnit` if you use Pakku.
-**millis** - is a thousand of microseconds;
+# DESCRIPTION
-**seconds** - is a thousand of milliseconds;
+`TimeUnit` library provides a simple way for conversion time without any 'magic numbers' in code. Also, `TimeUnit` can help you to write a more intuitive API in part of using time.
-**minutes** - is sixty seconds;
+You may use the following routines to create corresponding `TimeUnit` object: `nanos`, `micros`, `millis`, `seconds`, `minutes`, `hours` and `days`. All of them take a single `Numeric()` argument. Additionally, you may create `TimeUnit` object through `timeunit` routing in a relaxed way like `timeunit(:1day :3h :6nanoseconds)`.
-**hours** - is sixty minutes;
+`TimeUnit` object can be compared as ordinary Numerics. Also, you may add and subtract them with `infix:<+>` and `infix:<->` routines and `plus` and `minus` methods.
-**days** - is twenty four hours;
+To convert `TimeUnit` object to some numeric representation use one of the following method: `to-nanos`, `to-micros`, `to-millis`, `to-seconds`, `to-hours`, `to-days` or simply `to('days')`. It is possible to pass a name of unit to `to` method with or without quotation.
-Available methods
------------------
+# AUTHOR
-With any constants you can use methods **from**, **to-nanos**, **to-micros**, **to-millis**,
-**to-seconds**, **to-minutes**, **to-hours**, **to-days** for conversion numbers
-from one unit to another like this:
+Mikhail Khorkov
- nanos.to-hours(432); # convert 432 nanosecons to 0.00000000012 hour
- hours.from(90, minutes); # retrieve 1.5 hours from 90 minutes
- seconds.from(:17minutes); # retrieve 1020 seconds 17 minutes in short named form
- minutes.from(hours => 3.6);
- # retrieve 216 minutes from 3.6 (3:36) hours in full named form
-
-Sources
--------
-
-[GitHub](https://github.com/atroxaper/p6-TimeUnit)
-
-Author
-------
-
-Mikhail Khorkov
-
-License
--------
-
-See [LICENSE](LICENSE) file for the details of the license of the code in this repository.
-
-
+Sources can be found at: [github](https://github.com/atroxaper/raku-TimeUnit). The new Issues and Pull Requests are welcome.
+# COPYRIGHT AND LICENSE
+Copyright 2022 Mikhail Khorkov
+This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.
diff --git a/lib/TimeUnit.rakumod b/lib/TimeUnit.rakumod
index f2923cd..c4a77a9 100644
--- a/lib/TimeUnit.rakumod
+++ b/lib/TimeUnit.rakumod
@@ -8,102 +8,101 @@ my constant min = sec * 60;
my constant hour = min * 60;
my constant day = hour * 24;
-#|[Class for representing a time unit like nanosecond or hour.
+enum UnitTimeName (
+ nanos => nano,
+ micros => micro,
+ millis => milli,
+ seconds => sec,
+ minutes => min,
+ hours => hour,
+ days => day
+);
+
+#|[Class for representing a time unit like nanosecond or hour
#
-# Class is private. You can use corresponding instances like nanos or hours.
-#]
+# Class is private. You can use corresponding instances like nanos or hours.]
class TimeUnit {
- has Str $.name;
- has Int $.nanos-volume;
+ has $!nano is built;
+ method !nano() { $!nano }
- #|Convert specified number from current unit to nanoseconds.
- method to-nanos($d) {
- $d * ($!nanos-volume / nano);
+ method to-nanos(TimeUnit:D: --> Numeric:D) { $!nano }
+ method to-micros(TimeUnit:D: --> Numeric:D) { $!nano / micro }
+ method to-millis(TimeUnit:D: --> Numeric:D) { $!nano / milli }
+ method to-seconds(TimeUnit:D: --> Numeric:D) { $!nano / sec }
+ method to-minutes(TimeUnit:D: --> Numeric:D) { $!nano / min }
+ method to-hours(TimeUnit:D: --> Numeric:D) { $!nano / hour }
+ method to-days(TimeUnit:D: --> Numeric:D) { $!nano / day }
+ multi method to(TimeUnit:D: UnitTimeName:D $unit --> Numeric:D) { $!nano / $unit.value }
+ multi method to(TimeUnit:D: Str:D $unit --> Numeric:D) {
+ $!nano / UnitTimeName::{$unit}.value
}
- #|Convert specified number from current unit to microseconds.
- method to-micros($d) {
- $d * ($!nanos-volume / micro);
+ multi method plus(TimeUnit:D: TimeUnit:D $plus --> TimeUnit:D) {
+ create($!nano + $plus!nano, 'n')
}
-
- #|Convert specified number from current unit to milliseconds.
- method to-millis($d) {
- $d * ($!nanos-volume / milli);
- }
-
- #|Convert specified number from current unit to seconds.
- method to-seconds($d) {
- $d * ($!nanos-volume / sec);
- }
-
- #|Convert specified number from current unit to minutes.
- method to-minutes($d) {
- $d * ($!nanos-volume / min);
- }
-
- #|Convert specified number from current unit to hours.
- method to-hours($d) {
- $d * ($!nanos-volume / hour);
+ multi method plus(TimeUnit:D: |c --> TimeUnit:D) {
+ create($!nano + nanos-from(|c), 'n')
}
-
- #|Convert specified number from current unit to days.
- method to-days($d) {
- $d * ($!nanos-volume / day);
- }
-
- #|Convert specified number from specified unit to current unit.
- multi method from($d, TimeUnit:D $u) {
- $d * ($u.nanos-volume / $!nanos-volume);
+ multi method minus(TimeUnit:D: TimeUnit:D $plus --> TimeUnit:D) {
+ create($!nano - $plus!nano, 'n')
}
-
- #|Convert specified number from nanos unit to current unit.
- multi method from(:$nanos!) {
- $nanos * (nano / $!nanos-volume);
+ multi method minus(TimeUnit:D: |c --> TimeUnit:D) {
+ create($!nano - nanos-from(|c), 'n')
}
- #|Convert specified number from micros unit to current unit.
- multi method from(:$micros!) {
- $micros * (micro / $!nanos-volume);
+ method WHICH(TimeUnit:D: --> ValueObjAt:D) {
+ ValueObjAt.new("TimeUnit|$!nano");
}
- #|Convert specified number from millis unit to current unit.
- multi method from(:$millis!) {
- $millis * (milli / $!nanos-volume);
- }
-
- #|Convert specified number from seconds unit to current unit.
- multi method from(:$seconds!) {
- $seconds * (sec / $!nanos-volume);
- }
+ method Real() { $!nano }
- #|Convert specified number from minutes unit to current unit.
- multi method from(:$minutes!) {
- $minutes * (min / $!nanos-volume);
- }
-
- #|Convert specified number from hours unit to current unit.
- multi method from(:$hours!) {
- $hours * (hour / $!nanos-volume);
- }
-
- #|Convert specified number from days unit to current unit.
- multi method from(:$days!) {
- $days * (day / $!nanos-volume);
- }
-
- multi method from(|) {
- die 'you can only use from method with named parameters: ' ~
- 'nanos, micros, millis, seconds, minutes, hours, days.';
- }
+ method Numeric() { $!nano }
}
-constant nanos = TimeUnit.new: name => 'nanosecond', nanos-volume => nano;
-constant micros = TimeUnit.new: name => 'microsecond', nanos-volume => micro;
-constant millis = TimeUnit.new: name => 'millisecond', nanos-volume => milli;
-constant seconds = TimeUnit.new: name => 'second', nanos-volume => sec;
-constant minutes = TimeUnit.new: name => 'minute', nanos-volume => min;
-constant hours = TimeUnit.new: name => 'hour', nanos-volume => hour;
-constant days = TimeUnit.new: name => 'day', nanos-volume => day;
-
+sub create($n, $unit) {
+ TimeUnit.new: nano => nanos-from(|($unit => $n));
+}
+sub nanos(Numeric() $n where * >= 0 --> TimeUnit:D) is export { create($n, 'n') }
+sub micros(Numeric() $n where * >= 0 --> TimeUnit:D) is export { create($n, 'mic') }
+sub millis(Numeric() $n where * >= 0 --> TimeUnit:D) is export { create($n, 'mil') }
+sub seconds(Numeric() $n where * >= 0 --> TimeUnit:D) is export { create($n, 'sec') }
+sub minutes(Numeric() $n where * >= 0 --> TimeUnit:D) is export { create($n, 'min') }
+sub hours(Numeric() $n where * >= 0 --> TimeUnit:D) is export { create($n, 'h') }
+sub days(Numeric() $n where * >= 0 --> TimeUnit:D) is export { create($n, 'd') }
+multi sub timeunit(Numeric() $n where * >= 0, UnitTimeName:D $unit --> TimeUnit:D) is export {
+ create($n, $unit.key)
+}
+multi sub timeunit(|c --> TimeUnit:D) is export {
+ create(nanos-from(|c), 'n');
+}
+multi sub infix:<+>(TimeUnit:D $l, TimeUnit:D $r --> TimeUnit:D) is export { $l.plus($r) }
+multi sub infix:<->(TimeUnit:D $l, TimeUnit:D $r --> TimeUnit:D) is export { $l.minus($r) }
+
+multi sub nanos-from(
+ Numeric() :d(:day(:$days)) where { $_ >= 0 } = 0,
+ Numeric() :h(:hour(:$hours)) where { $_ >= 0 } = 0,
+ Numeric() :min(:minute(:$minutes)) where { $_ >= 0 } = 0,
+ Numeric() :s(:sec(:second(:$seconds))) where { $_ >= 0 } = 0,
+ Numeric() :mil(:milli(:millisecond(:milliseconds(:$millis)))) where { $_ >= 0 } = 0,
+ Numeric() :mic(:mocro(:microsecond(:microseconds(:$micros)))) where { $_ >= 0 } = 0,
+ Numeric() :n(:nano(:nanosecond(:nanoseconds(:$nanos)))) where { $_ >= 0 } = 0,
+ |c
+ --> Numeric:D
+) {
+ nextwith(|c) if c;
+ $nanos * nano +
+ $micros * micro +
+ $millis * milli +
+ $seconds * sec +
+ $minutes * min +
+ $hours * hour +
+ $days * day
+}
+#| Fallback to die
+multi sub nanos-from(|c) {
+ die "With TimeUnit you only can use named parameters:\n" ~
+ "nanos, micros, millis, seconds, minutes, hours, days.\n" ~
+ "But you specified: [{c}].";
+}
diff --git a/racoco.ini b/racoco.ini
new file mode 100644
index 0000000..476dcf8
--- /dev/null
+++ b/racoco.ini
@@ -0,0 +1,12 @@
+exec = prove6 t
+
+[full]
+exec = prove6 t
+
+[html]
+exec = prove6 t
+reporter = html-color-blind
+
+[coveralls]
+exec = prove6 t
+reporter = coveralls
diff --git a/t/00-meta.t b/t/00-meta.t
deleted file mode 100644
index 8967b38..0000000
--- a/t/00-meta.t
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env perl6
-
-use v6;
-use Test;
-use lib 'lib';
-
-plan 1;
-
-constant AUTHOR = ?%*ENV;
-
-if AUTHOR {
- require Test::META <&meta-ok>;
- meta-ok;
- done-testing;
-}
-else {
- skip-rest "Skipping author test";
- exit;
-}
\ No newline at end of file
diff --git a/t/01-simple.t b/t/01-simple.t
deleted file mode 100644
index aebdf6f..0000000
--- a/t/01-simple.t
+++ /dev/null
@@ -1,27 +0,0 @@
-use v6.c;
-
-use Test;
-use lib 'lib';
-use TimeUnit;
-
-plan 15;
-
-is seconds.to-nanos(1), 1000 * 1000 * 1000, '1 sec to nonos';
-is seconds.to-nanos(0.5), 500 * 1000 * 1000, 'half sec to nonos';
-is days.to-seconds(15), 15 * 86400, '15 days to sec';
-is micros.to-hours(hours.to-micros(5)), 5, '5 hours to microseconds and back';
-is nanos.to-hours(432), 0.00000000012, '432 nanosecond to hours';
-is hours.from(90, minutes), 1.5, '1.5 hours from 90 minutes';
-
-is micros.from(:100nanos), 0.1, 'micros from named nanos';
-is nanos.from(:100micros), 100 * 1000, 'nanos from named micros';
-is millis.from(:99millis), 99, 'millis stay millis by named parameter';
-is hours.from(:90minutes), 1.5, '1.5 hours from 90 minutes with named parameter';
-is hours.from(:99seconds), 0.0275, 'little hours from named 99 seconds';
-is minutes.from(:99hours), 5940, 'minutes from named 99 hours';
-is seconds.from(days => 1.5), 129600, 'seconds from one and half named days';
-
-dies-ok { minutes.from(:33hour) }, 'wrong named parameter';
-dies-ok { minutes.from(hours => '5hours') }, 'parameter is not a number';
-
-done-testing;
\ No newline at end of file
diff --git a/t/01-usage.rakutest b/t/01-usage.rakutest
new file mode 100644
index 0000000..0ee8dc6
--- /dev/null
+++ b/t/01-usage.rakutest
@@ -0,0 +1,30 @@
+use v6.d;
+use Test;
+use lib 'lib';
+use TimeUnit;
+
+plan 20;
+
+is millis(1).to-nanos, 1 * 1000 * 1000, 'millis unit to nanos';
+is minutes(30).to-seconds, 30 * 60, 'min unit to seconds';
+is timeunit(3, minutes).to-seconds, 3 * 60, 'time unit to seconds';
+is timeunit(:3min, :1sec).to-seconds, 3 * 60 + 1, 'time unit all to seconds';
+is seconds(10).plus(minutes(1)).to-seconds, 10 + 60, 'unit plus unit';
+is minutes(50).plus(:1hour :1minute).to-minutes, 50 + 60 + 1, 'unit plus all to minutes';
+is (minutes(30) + days(4)).to-hours, 0.5 + 4 * 24, 'unit + unit to hours';
+is hours(3).minus(:1hour :30min).to-hours, 1.5, 'unit minus unit all';
+is timeunit(:3min).minus(seconds(1)).to-millis, (3 * 60 - 1) * 1000, 'unit minus unit to millis';
+is (millis(4) - micros(3)).to-micros, 4 * 1000 - 3, 'unit - unit to micros';
+is nanos(35500).to(micros), 35.5, 'unit to type';
+is nanos(35500).to('micros'), 35.5, 'unit to type as string';
+ok minutes(30) === minutes(10) + minutes(20), '===';
+ok minutes(30) <= minutes(30), '<=';
+ok minutes(40) > minutes(30), '>';
+is nanos(3001) <=> micros(3), More, '<=>';
+ok nanos(3000) == micros(3), '==';
+ok nanos(3001) != micros(3), '!=';
+
+sub api(TimeUnit:D $time) { is $time.to-days, 4, 'unit as routing parameter'; }
+api(hours(96));
+
+dies-ok { timeunit(:1hhour, :3min) }, 'bad parsing';