From 22837ebc36dd4f638481ef0a7ec199bb961a46e3 Mon Sep 17 00:00:00 2001 From: mgifos Date: Wed, 26 Dec 2018 21:04:30 +0100 Subject: [PATCH] Detect workout definition type automatically #42 --- README.md | 13 +++++++------ .../com.github.mgifos.workouts/model/Workout.scala | 11 +++++++++-- .../github/mgifos/workouts/model/WorkoutSpec.scala | 7 ++++++- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 73c1564..d76964f 100644 --- a/README.md +++ b/README.md @@ -71,21 +71,19 @@ quick-plan schedule -n 2018-04-29 -x -e your-mail-address@example.com ultra-80k- ## Workout notation The reserved keywords of the notation are: workout, warmup, cooldown, run, bike, go, repeat, recover and lap-button. -**``** := `
+` +**``** := `
()+` -**`
`** := `: ` - -**``** := (running | cycling | custom) +**`
`** := `[running | cycling | custom]: ` **``** := `[\u0020-\u007F]+` (printable ascii characters) -**``** := `- ` +**``** := `- ` **``** := ` | ` **``** := `(warmup | cooldown | run | bike | go | recover): [@ ]` -**``** := `repeat: ( - )+` +**``** := `repeat: ()+` (with each r. step, depth is increased by 1 - check ``) **``** := ` | | lap-button` @@ -117,6 +115,9 @@ The reserved keywords of the notation are: workout, warmup, cooldown, run, bike, **``** := `[\r\n]` +**``** := `\s{depth * 2}` (depends on depth parameter related to the repetion step / starts from 0) + + ## Unit of measurements (metric vs imperial) As Garmin supports metric and imperial measurement systems, quick-plan can do this as well. There are two ways of usage: diff --git a/src/main/scala/com.github.mgifos.workouts/model/Workout.scala b/src/main/scala/com.github.mgifos.workouts/model/Workout.scala index 4463c6f..89cf035 100644 --- a/src/main/scala/com.github.mgifos.workouts/model/Workout.scala +++ b/src/main/scala/com.github.mgifos.workouts/model/Workout.scala @@ -41,9 +41,9 @@ case class WorkoutNote(note: String) extends Workout object Workout { private val WorkoutType = "(running|cycling|custom)" - private val WorkoutHeader = raw"""^$WorkoutType:\s([\u0020-\u007F]+)(([\r\n]+\s*\-\s[a-z]+:.*)*)$$""".r + private val WorkoutHeader = raw"""^$WorkoutType?:\s*([\u0020-\u007F]+)(([\r\n]+\s*\-\s[a-z]+:.*)*)$$""".r private val NextStepRx = """^((-\s\w*:\s.*)(([\r\n]+\s{1,}-\s.*)*))(([\s].*)*)$""".r - private val PossibleWorkoutHeader = raw"""^\s*$WorkoutType\s*:\s*.*(([\r\n]+\s*.*)*)$$""".r + private val PossibleWorkoutHeader = raw"""^\s*$WorkoutType?\s*:\s*.*(([\r\n]+\s*.*)*)$$""".r def parse(text: String)(implicit msys: MeasurementSystems.MeasurementSystem): Workout = { def loop(w: WorkoutDef, steps: String): Workout = steps match { @@ -58,12 +58,19 @@ object Workout { case _ => WorkoutStepFailure(text, steps.trim) } text match { + case WorkoutHeader(null, name, steps, _) => loop(WorkoutDef(detectSport(steps), name), steps.trim) case WorkoutHeader(sport, name, steps, _) => loop(WorkoutDef(sport, name), steps.trim) case PossibleWorkoutHeader(t, _, cause) => WorkoutDefFailure(`type` = t, text, if (cause == null) "" else cause.trim) case _ => WorkoutNote(text) } } + def detectSport(steps: String): String = steps match { + case x if x.contains("- run") => "running" + case x if x.contains("- bike") => "cycling" + case _ => "custom" + } + def sportId(sport: String) = sport match { case "running" => 1 case "cycling" => 2 diff --git a/src/test/scala/com/github/mgifos/workouts/model/WorkoutSpec.scala b/src/test/scala/com/github/mgifos/workouts/model/WorkoutSpec.scala index fbb0bda..eaa3702 100644 --- a/src/test/scala/com/github/mgifos/workouts/model/WorkoutSpec.scala +++ b/src/test/scala/com/github/mgifos/workouts/model/WorkoutSpec.scala @@ -18,7 +18,7 @@ class WorkoutSpec extends WordSpec with Matchers { */ val testWO = "running: run-fast\n- warmup: 10:00\n- repeat: 2\n - run: 1500m @ 4:30-5:00\n - recover: 01:30 @ z2\n- cooldown: lap-button" - "Workout parser should" should { + "Workout parser" should { "parse notes correctly" in { Workout.parse("") shouldBe a[WorkoutNote] @@ -111,6 +111,11 @@ class WorkoutSpec extends WordSpec with Matchers { ) ) } + + "be able to detect workout type automatically" in { + val test = Seq("run", "bike", "go").map(step => s": detect\n- $step: 2km") + test.map(Workout.parse(_).asInstanceOf[WorkoutDef].sport) shouldBe Seq("running", "cycling", "custom") + } } "Workout should" should {