From aa1c00e83a59af17507ec25a9557b420f1ca70dd Mon Sep 17 00:00:00 2001 From: luckyLukec Date: Wed, 28 Sep 2022 19:27:58 +0200 Subject: [PATCH 01/10] Redesigned Interval class and new Speed class --- Gemfile | 1 + Gemfile.lock | 6 + examples/run_example.rb | 14 +- examples/save_training_to_file.rb | 6 +- feature_diagram/ast-tdl.svg | 1746 +++++++++++++++++++++++++++++ lib/ast.rb | 29 +- lib/interval.rb | 40 +- lib/{session.rb => speed.rb} | 28 +- lib/sport.rb | 13 + 9 files changed, 1846 insertions(+), 37 deletions(-) create mode 100644 feature_diagram/ast-tdl.svg rename lib/{session.rb => speed.rb} (52%) create mode 100644 lib/sport.rb diff --git a/Gemfile b/Gemfile index d0b2648..00aa35d 100644 --- a/Gemfile +++ b/Gemfile @@ -6,3 +6,4 @@ source 'https://rubygems.org' gemspec gem 'rake', '~> 13.0' +gem 'ruby-enum' diff --git a/Gemfile.lock b/Gemfile.lock index 5df52d9..7bf029d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,12 @@ PATH GEM remote: https://rubygems.org/ specs: + concurrent-ruby (1.1.10) + i18n (1.12.0) + concurrent-ruby (~> 1.0) rake (13.0.6) + ruby-enum (0.9.0) + i18n PLATFORMS x64-mingw-ucrt @@ -15,6 +20,7 @@ PLATFORMS DEPENDENCIES ast-tdl! rake (~> 13.0) + ruby-enum BUNDLED WITH 2.3.7 diff --git a/examples/run_example.rb b/examples/run_example.rb index ca55806..10edd1c 100644 --- a/examples/run_example.rb +++ b/examples/run_example.rb @@ -1,25 +1,25 @@ # frozen_string_literal: true -require 'ast-tdl' +require_relative '../lib/ast-tdl' # Training description in AST-TDL domain specific language. -training = Ast.build('My first training') do - session('Short swimming session') do - sport :swim +training = Ast.build do + speed('Short swimming session') do + sport Sport::RUNNING info :"Very easy training" average_heart_rate :"130" total_duration :"30" end - session('Bike ride') do - sport :cycling + speed('Bike ride') do + sport Sport::CYCLING info :"Endurance ride with intervals" average_heart_rate :"140" total_duration :"120" end interval('Sample interval') do - sport :cycling + sport Sport::CYCLING info :Moderate speed_duration :"5" recovery_duration :"5" diff --git a/examples/save_training_to_file.rb b/examples/save_training_to_file.rb index 19e5c83..fe394c2 100644 --- a/examples/save_training_to_file.rb +++ b/examples/save_training_to_file.rb @@ -4,14 +4,14 @@ # Training description in AST-TDL domain specific language. training = Ast.build('My first training') do - session('Short swimming session') do + speed('Short swimming session') do sport :swim info :"Very easy training" - average_heart_rate :"130" + average_heart_rate :"130s" total_duration :"30" end - session('Bike ride') do + speed('Bike ride') do sport :cycling info :"Endurance ride with intervals" average_heart_rate :"140" diff --git a/feature_diagram/ast-tdl.svg b/feature_diagram/ast-tdl.svg new file mode 100644 index 0000000..d3fc5ea --- /dev/null +++ b/feature_diagram/ast-tdl.svg @@ -0,0 +1,1746 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + Training + + + + + + + + + + + + + + Total duration + + + + + Average heart rate + + + + + Sport + + + + + Name + + + + + Info + + + + + + Speed + + + + + + + + + + + + + + + + + + + Interval + + + + + + Recovery duration + + + + + Speed +duration + + + + + Sport + + + + + Name + + + + + Info + + + + + Recovery heart rate + + + + + Speed +heart rate + + + + + Repetitions + + + + + Type + + + + + + + + Name + + + Power + + + Series + + Series + + + + Intensity + + + + Series + + Repetitions + + + + + + + + Name + + + + + + diff --git a/lib/ast.rb b/lib/ast.rb index 0caec90..7e5bf84 100644 --- a/lib/ast.rb +++ b/lib/ast.rb @@ -2,7 +2,8 @@ require 'json' require_relative 'interval' -require_relative 'session' +require_relative 'speed' +require_relative 'sport' ## # This module is intended to be used for building trainings @@ -11,10 +12,9 @@ module Ast ## # Building a new training from the domain specific language. # Params: - # +name+:: the name of the training # +block+:: training data - def self.build(name, &block) - training = Training.new(name) + def self.build(&block) + training = Training.new() training.instance_eval(&block) training end @@ -26,21 +26,20 @@ class Training # Initialization method for the +Training+ class. # Params: # +name+:: the name of the training - def initialize(name) - @name = name - @session = [] + def initialize() + @speed = [] @interval = [] end ## - # Building a new session from the domain specific language. + # Building a new speed session from the domain specific language. # Params: - # +name+:: the name of the session - # +block+:: session data - def session(name, &block) - training_type = Session.new(name) + # +name+:: the name of the speed session + # +block+:: speed session data + def speed(name, &block) + training_type = Speed.new(name) training_type.instance_eval(&block) - @session << training_type + @speed << training_type end ## @@ -57,7 +56,7 @@ def interval(name, &block) ## # Converting a training to a string. def to_s - "#{@name} #{@session[0]}" + "#{@name} #{@speed[0]}" end ## @@ -65,7 +64,7 @@ def to_s def json training_json = { name: @name, - session: @session.collect(&:to_hash), + speed: @speed.collect(&:to_hash), interval: @interval.collect(&:to_hash) } JSON.pretty_generate(training_json) diff --git a/lib/interval.rb b/lib/interval.rb index d25bed6..f7b4070 100644 --- a/lib/interval.rb +++ b/lib/interval.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +require_relative 'sport' + + ## # This class represents an interval. class Interval @@ -24,6 +27,8 @@ def initialize(name) # Params: # +type+:: the type of the sport def sport(type) + raise 'The sport name has to be from the Sport class collection.' unless Sport.values.include? type + @sport = type end @@ -40,7 +45,12 @@ def info(message) # Params: # +speed_duration+:: the duration of the speed segment in minutes def speed_duration(speed_duration) - @speed_duration = speed_duration.to_s.to_i + speed_duration_str = speed_duration.to_s + speed_duration_int = speed_duration.to_s.to_i + raise 'The given speed duration is not an integer.' if speed_duration_str != speed_duration_str.to_i.to_s + raise 'The speed duration has to be 1 minute at least.' if speed_duration_int < 1 + + @speed_duration = speed_duration_int end ## @@ -48,7 +58,12 @@ def speed_duration(speed_duration) # Params: # +recovery_duration+:: the duration of the recovery segment in minutes def recovery_duration(recovery_duration) - @recovery_duration = recovery_duration.to_s.to_i + recovery_duration_str = recovery_duration.to_s + recovery_duration_int = recovery_duration.to_s.to_i + raise 'The given recovery duration is not an integer.' if recovery_duration_str != recovery_duration_str.to_i.to_s + raise 'The recovery duration has to be 1 minute at least.' if recovery_duration_int < 1 + + @recovery_duration = recovery_duration_int end ## @@ -56,7 +71,12 @@ def recovery_duration(recovery_duration) # Params: # +speed_heart_rate+:: the average speed heart rate in bpm def speed_heart_rate(speed_heart_rate) - @speed_heart_rate = speed_heart_rate.to_s.to_i + speed_hr_str = speed_heart_rate.to_s + speed_hr_int = speed_heart_rate.to_s.to_i + raise 'The given average heart rate is not an integer.' if speed_hr_str != speed_hr_str.to_i.to_s + raise 'The speed heart rate should be between 60 and 205 bpm.' if speed_hr_int < 60 || speed_hr_int > 205 + + @speed_heart_rate = speed_hr_int end ## @@ -64,7 +84,12 @@ def speed_heart_rate(speed_heart_rate) # Params: # +recovery_heart_rate+:: the average speed heart rate in bpm def recovery_heart_rate(recovery_heart_rate) - @recovery_heart_rate = recovery_heart_rate.to_s.to_i + recovery_hr_str = recovery_heart_rate.to_s + recovery_hr_int = recovery_heart_rate.to_s.to_i + raise 'The given average heart rate is not an integer.' if recovery_hr_str != recovery_hr_str.to_i.to_s + raise 'The recovery heart rate should be between 60 and 205 bpm.' if recovery_hr_int < 60 || recovery_hr_int > 205 + + @recovery_heart_rate = recovery_hr_int end ## @@ -72,7 +97,12 @@ def recovery_heart_rate(recovery_heart_rate) # Params: # +repetitions+:: number of interval repetitions def repetitions(repetitions) - @repetitions = repetitions.to_s.to_i + repetitions_str = repetitions.to_s + repetitions_int = repetitions.to_s.to_i + raise 'The given number of repetitions is not an integer.' if repetitions_str != repetitions_str.to_i.to_s + raise 'The minimum number of repetitions is 1.' if repetitions_int < 1 + + @repetitions = repetitions_int end ## diff --git a/lib/session.rb b/lib/speed.rb similarity index 52% rename from lib/session.rb rename to lib/speed.rb index 5a83a5a..95a99b9 100644 --- a/lib/session.rb +++ b/lib/speed.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true +require_relative 'sport' + ## -# This class represents a session. -class Session +# This class represents a speed training session. +class Speed ## - # Initialization method for the +Session+ class. + # Initialization method for the +Speed+ class. # Params: - # +name+:: the name of the session + # +name+:: the name of the speed session def initialize(name) @name = name @sport = '' @@ -20,6 +22,8 @@ def initialize(name) # Params: # +type+:: the type of the sport def sport(type) + raise 'The sport name has to be from the Sport class collection.' unless Sport.values.include? type + @sport = type end @@ -36,7 +40,12 @@ def info(message) # Params: # +heart_rate+:: the average heart rate in bpm def average_heart_rate(heart_rate) - @average_heart_rate = heart_rate.to_s.to_i + heart_rate_str = heart_rate.to_s + heart_rate_int = heart_rate.to_s.to_i + raise 'The given average heart rate is not an integer.' if heart_rate_str != heart_rate_str.to_i.to_s + raise 'The average heart rate should be between 60 and 205 bpm.' if heart_rate_int < 60 || heart_rate_int > 205 + + @average_heart_rate = heart_rate_int end ## @@ -44,11 +53,16 @@ def average_heart_rate(heart_rate) # Params: # +duration+:: the duration in minutes def total_duration(duration) - @total_duration = duration.to_s.to_i + duration_str = duration.to_s + duration_int = duration.to_s.to_i + raise 'The given average heart rate is not an integer.' if duration_str != duration_str.to_i.to_s + raise 'The duration has to be 1 minute at least.' if duration_int < 1 + + @duration = duration_int end ## - # Converting a session to a string. + # Converting a speed session to a string. def to_s "#{@sport} #{@info}" end diff --git a/lib/sport.rb b/lib/sport.rb new file mode 100644 index 0000000..f9f4e9c --- /dev/null +++ b/lib/sport.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'ruby-enum' + +## +# This class represents a collection of sports. +class Sport + include Ruby::Enum + + define :CYCLING, 'cycling' + define :RUNNING, 'running' + define :SWIMMING, 'swimming' +end From 728b4be5a124b41b82caf537331ecf66037cf080 Mon Sep 17 00:00:00 2001 From: luckyLukec Date: Thu, 29 Sep 2022 14:16:18 +0200 Subject: [PATCH 02/10] Power trainings support --- examples/run_example.rb | 42 +- examples/save_training_to_file.rb | 46 +- feature_diagram/ast-tdl.svg | 829 ++++++++++++++++-------------- lib/ast.rb | 30 +- lib/interval.rb | 1 - lib/power.rb | 55 ++ lib/series.rb | 57 ++ lib/speed.rb | 4 +- lib/sport.rb | 2 + trainings/training.json | 49 ++ 10 files changed, 684 insertions(+), 431 deletions(-) create mode 100644 lib/power.rb create mode 100644 lib/series.rb create mode 100644 trainings/training.json diff --git a/examples/run_example.rb b/examples/run_example.rb index 10edd1c..ef38e8d 100644 --- a/examples/run_example.rb +++ b/examples/run_example.rb @@ -4,30 +4,42 @@ # Training description in AST-TDL domain specific language. training = Ast.build do - speed('Short swimming session') do - sport Sport::RUNNING - info :"Very easy training" - average_heart_rate :"130" - total_duration :"30" + speed('Swimming with the dolphins') do + sport Sport::SWIMMING + info :"Very easy training" + average_heart_rate :"130" + total_duration :"30" end - speed('Bike ride') do - sport Sport::CYCLING - info :"Endurance ride with intervals" - average_heart_rate :"140" - total_duration :"120" + speed('Cross the country') do + sport Sport::CYCLING + info :"Endurance ride" + average_heart_rate :"140" + total_duration :"120" end - interval('Sample interval') do - sport Sport::CYCLING - info :Moderate - speed_duration :"5" - recovery_duration :"5" + interval('Following Emil Zatopek') do + sport Sport::RUNNING + info :Hard + speed_duration :"1" + recovery_duration :"1" speed_heart_rate :"180" recovery_heart_rate :"90" repetitions :"10" type :fixed end + + power('As strong as an ox') do + sport Sport::WEIGHT_LIFTING + series('Little ox') do + intensity :"5" + repetitions :"20" + end + series('Big ox') do + intensity :"10" + repetitions :"80" + end + end end # Printing JSON-ized training to the console. diff --git a/examples/save_training_to_file.rb b/examples/save_training_to_file.rb index fe394c2..89ee885 100644 --- a/examples/save_training_to_file.rb +++ b/examples/save_training_to_file.rb @@ -1,33 +1,45 @@ # frozen_string_literal: true -require 'ast-tdl' +require_relative '../lib/ast-tdl' # Training description in AST-TDL domain specific language. -training = Ast.build('My first training') do - speed('Short swimming session') do - sport :swim - info :"Very easy training" - average_heart_rate :"130s" - total_duration :"30" +training = Ast.build do + speed('Swimming with the dolphins') do + sport Sport::SWIMMING + info :"Very easy training" + average_heart_rate :"130" + total_duration :"30" end - speed('Bike ride') do - sport :cycling - info :"Endurance ride with intervals" - average_heart_rate :"140" - total_duration :"120" + speed('Cross the country') do + sport Sport::CYCLING + info :"Endurance ride" + average_heart_rate :"140" + total_duration :"120" end - interval('Sample interval') do - sport :cycling - info :Moderate - speed_duration :"5" - recovery_duration :"5" + interval('Following Emil Zatopek') do + sport Sport::RUNNING + info :Hard + speed_duration :"1" + recovery_duration :"1" speed_heart_rate :"180" recovery_heart_rate :"90" repetitions :"10" type :fixed end + + power('As strong as an ox') do + sport Sport::WEIGHT_LIFTING + series('Little ox') do + intensity :"5" + repetitions :"20" + end + series('Big ox') do + intensity :"10" + repetitions :"80" + end + end end # Saving JSON-ized training to a file. diff --git a/feature_diagram/ast-tdl.svg b/feature_diagram/ast-tdl.svg index d3fc5ea..875d08b 100644 --- a/feature_diagram/ast-tdl.svg +++ b/feature_diagram/ast-tdl.svg @@ -7,9 +7,9 @@ xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="728.95142mm" - height="245.00839mm" - viewBox="0 0 728.9514 245.00839" + width="694.95184mm" + height="245.00858mm" + viewBox="0 0 694.95183 245.00857" version="1.1" id="svg8" inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" @@ -829,6 +829,30 @@ width="32.60688" height="20.980658" id="rect1773" /> + + + + + + + + + - - - - - - - - Total duration - - - - - Average heart rate - - - - - Sport - - - - - Name - - + id="g1130" + transform="translate(-188.32451,-1.637887)"> + + Total duration + + + + + Average heart rate + + + + + Sport + + + + + Name + + + + + Info + + + + id="g1083"> Info - - - - - - Speed - - + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.05556px;line-height:1;font-family:Bahnschrift;-inkscape-font-specification:Bahnschrift;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1">Speed + - - + id="g3535" + transform="translate(-6.176667,-72.247697)"> Name + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.05556px;line-height:1;font-family:Bahnschrift;-inkscape-font-specification:Bahnschrift;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1">Intensity + + + Series Power + transform="translate(414.56078,283.51841)">Repetitions + style="vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#3434b0;stroke-width:1.00419;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="path1098-1-2-5-8-4" + cx="504.94543" + cy="276.92017" + rx="2.4979036" + ry="2.4979055" /> + + + + + + + Name + + + + + - Series + id="g1383"> Series + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.05556px;line-height:1;font-family:Bahnschrift;-inkscape-font-specification:Bahnschrift;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1">Name - - - Intensity - - - - Series - - Repetitions - - - - - - - - Name - - + + Power + + + + + Sport + + + + + Series + + diff --git a/lib/ast.rb b/lib/ast.rb index 7e5bf84..a094fe3 100644 --- a/lib/ast.rb +++ b/lib/ast.rb @@ -2,6 +2,7 @@ require 'json' require_relative 'interval' +require_relative 'power' require_relative 'speed' require_relative 'sport' @@ -26,9 +27,10 @@ class Training # Initialization method for the +Training+ class. # Params: # +name+:: the name of the training - def initialize() + def initialize @speed = [] @interval = [] + @power = [] end ## @@ -53,19 +55,37 @@ def interval(name, &block) @interval << interval_data end + ## + # Building a new power session from the domain specific language. + # Params: + # +name+:: the name of the power session + # +block+:: power session data + def power(name, &block) + power_data = Power.new(name) + power_data.instance_eval(&block) + @power << power_data + end + ## # Converting a training to a string. def to_s - "#{@name} #{@speed[0]}" + speed_number = @speed.length + interval_number = @interval.length + power_number = @power.length + + "TRAINING DATA:\n"\ + "Speed sessions: #{speed_number}\n"\ + "Interval sessions: #{interval_number}\n"\ + "Power sessions: #{power_number}\n\n" end ## # Converting a training to a JSON-ized string. def json training_json = { - name: @name, speed: @speed.collect(&:to_hash), - interval: @interval.collect(&:to_hash) + interval: @interval.collect(&:to_hash), + power: @power.collect(&:to_hash) } JSON.pretty_generate(training_json) end @@ -75,7 +95,7 @@ def json # Params: # +filename+:: the desired name of the file def save_to_file(filename) - f = File.open(filename, 'w') + f = File.open("../trainings/#{filename}", 'w') f.puts(json) f.close end diff --git a/lib/interval.rb b/lib/interval.rb index f7b4070..f497c0e 100644 --- a/lib/interval.rb +++ b/lib/interval.rb @@ -2,7 +2,6 @@ require_relative 'sport' - ## # This class represents an interval. class Interval diff --git a/lib/power.rb b/lib/power.rb new file mode 100644 index 0000000..d72bd82 --- /dev/null +++ b/lib/power.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require_relative 'series' +require_relative 'sport' + +## +# This class represents a power training session. +class Power + ## + # Initialization method for the +Power+ class. + # Params: + # +name+:: the name of the power session + def initialize(name) + @name = name + @series = [] + @sport = '' + end + + ## + # Building a new series from the domain specific language. + # Params: + # +name+:: the name of the series + # +block+:: power session data + def series(name, &block) + series_data = Series.new(name) + series_data.instance_eval(&block) + @series << series_data + end + + ## + # Adding a sport type to the object. + # Params: + # +type+:: the type of the sport + def sport(type) + raise 'The sport name has to be from the Sport class collection.' unless Sport.values.include? type + + @sport = type + end + + ## + # Converting a speed session to a string. + def to_s + @name + end + + ## + # Converting a session to a JSON-ized string. + def to_hash + { + name: @name, + sport: @sport, + series: @series.collect(&:to_hash) + } + end +end diff --git a/lib/series.rb b/lib/series.rb new file mode 100644 index 0000000..f6ee067 --- /dev/null +++ b/lib/series.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +## +# This class represents a series in power training session. +class Series + ## + # Initialization method for the +Series+ class. + # Params: + # +name+:: the name of the series + def initialize(name) + @name = name + @intensity = 0 + @repetitions = 0 + end + + ## + # Adding an intensity in the range [1, 10] to the series. + # Params: + # +intensity+:: intensity level + def intensity(intensity) + intensity_str = intensity.to_s + intensity_int = intensity.to_s.to_i + raise 'The given intensity level is not an integer.' if intensity_str != intensity_str.to_i.to_s + raise 'The intensity level should be between 1 and 10.' if intensity_int < 1 || intensity_int > 10 + + @intensity = intensity_int + end + + ## + # Adding a number of repetitions to the object. + # Params: + # +repetitions+:: number of repetitions inside of a series + def repetitions(repetitions) + repetitions_str = repetitions.to_s + repetitions_int = repetitions.to_s.to_i + raise 'The given number of repetitions is not an integer.' if repetitions_str != repetitions_str.to_i.to_s + raise 'The minimum number of repetitions is 1.' if repetitions_int < 1 + + @repetitions = repetitions_int + end + + ## + # Converting a speed session to a string. + def to_s + @name + end + + ## + # Converting a session to a JSON-ized string. + def to_hash + { + name: @name, + intensity: @intensity, + repetitions: @repetitions + } + end +end diff --git a/lib/speed.rb b/lib/speed.rb index 95a99b9..33e6978 100644 --- a/lib/speed.rb +++ b/lib/speed.rb @@ -58,7 +58,7 @@ def total_duration(duration) raise 'The given average heart rate is not an integer.' if duration_str != duration_str.to_i.to_s raise 'The duration has to be 1 minute at least.' if duration_int < 1 - @duration = duration_int + @total_duration = duration_int end ## @@ -74,7 +74,7 @@ def to_hash name: @name, sport: @sport, average_heart_rate: @average_heart_rate, - total_duration: @total_duration, + total_duration: @total_duration } hash[:info] = @info if @info != '' diff --git a/lib/sport.rb b/lib/sport.rb index f9f4e9c..1853d45 100644 --- a/lib/sport.rb +++ b/lib/sport.rb @@ -10,4 +10,6 @@ class Sport define :CYCLING, 'cycling' define :RUNNING, 'running' define :SWIMMING, 'swimming' + define :CROSS_COUNTRY_SKIING, 'cross country skiing' + define :WEIGHT_LIFTING, 'weight lifting' end diff --git a/trainings/training.json b/trainings/training.json new file mode 100644 index 0000000..1eda02e --- /dev/null +++ b/trainings/training.json @@ -0,0 +1,49 @@ +{ + "speed": [ + { + "name": "Swimming with the dolphins", + "sport": "swimming", + "average_heart_rate": 130, + "total_duration": 30, + "info": "Very easy training" + }, + { + "name": "Cross the country", + "sport": "cycling", + "average_heart_rate": 140, + "total_duration": 120, + "info": "Endurance ride" + } + ], + "interval": [ + { + "name": "Following Emil Zatopek", + "sport": "running", + "info": "Hard", + "speed_duration": 1, + "recovery_duration": 1, + "speed_heart_rate": 180, + "recovery_heart_rate": 90, + "repetitions": 10, + "type": "fixed" + } + ], + "power": [ + { + "name": "As strong as an ox", + "sport": "weight lifting", + "series": [ + { + "name": "Little ox", + "intensity": 5, + "repetitions": 20 + }, + { + "name": "Big ox", + "intensity": 10, + "repetitions": 80 + } + ] + } + ] +} From 629ff9b2eed681f64a6c89d4a19030923a947eae Mon Sep 17 00:00:00 2001 From: luckyLukec Date: Thu, 29 Sep 2022 14:18:22 +0200 Subject: [PATCH 03/10] Small fix --- feature_diagram/ast-tdl.svg | 1793 ----------------------------------- 1 file changed, 1793 deletions(-) delete mode 100644 feature_diagram/ast-tdl.svg diff --git a/feature_diagram/ast-tdl.svg b/feature_diagram/ast-tdl.svg deleted file mode 100644 index 875d08b..0000000 --- a/feature_diagram/ast-tdl.svg +++ /dev/null @@ -1,1793 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - Training - - - - - - - - - - - - - Total duration - - - - - Average heart rate - - - - - Sport - - - - - Name - - - - - Info - - - - - - Speed - - - - - - - - - - - - - - - - - - Interval - - - - - - Recovery duration - - - - - Speed -duration - - - - - Sport - - - - - Name - - - - - Info - - - - - Recovery heart rate - - - - - Speed -heart rate - - - - - Repetitions - - - - - Type - - - - - - Intensity - - - - Series - - Repetitions - - - - - - - - Name - - - - - - - - Name - - - - - Power - - - - - Sport - - - - - Series - - - - From af3ab09471fa23d9b07a822db62fd0abad595fc3 Mon Sep 17 00:00:00 2001 From: luckyLukec Date: Thu, 29 Sep 2022 14:19:38 +0200 Subject: [PATCH 04/10] Small fix --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index e3200e0..96d7b82 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,6 @@ build-iPhoneSimulator/ # Used by RuboCop. Remote config files pulled in from inherit_from directive. # .rubocop-https?--* + + +/feature_diagram \ No newline at end of file From 4dc374cde47a9bc631852a5b1f4103f8e97e991a Mon Sep 17 00:00:00 2001 From: luckyLukec Date: Thu, 29 Sep 2022 14:37:21 +0200 Subject: [PATCH 05/10] Refreshed and enhanced Rake test --- test/test_ast_tdl.rb | 239 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 216 insertions(+), 23 deletions(-) diff --git a/test/test_ast_tdl.rb b/test/test_ast_tdl.rb index d242ae0..71caf35 100644 --- a/test/test_ast_tdl.rb +++ b/test/test_ast_tdl.rb @@ -9,51 +9,244 @@ class AstTdlTest < Minitest::Test ## # Example training getter. def self.training - Ast.build('My first training') do - session('Short swimming session') do - sport :swim - info :"Very easy training" - average_heart_rate :"130" - total_duration :"30" + Ast.build do + speed('Swimming with the dolphins') do + sport Sport::SWIMMING + info :"Very easy training" + average_heart_rate :"130" + total_duration :"30" end - session('Bike ride') do - sport :cycling - info :"Endurance ride with intervals" - average_heart_rate :"140" - total_duration :"120" + speed('Cross the country') do + sport Sport::CYCLING + info :"Endurance ride" + average_heart_rate :"140" + total_duration :"120" end - interval('Sample interval') do - sport :cycling - info :Moderate - speed_duration :"5" - recovery_duration :"5" + interval('Following Emil Zatopek') do + sport Sport::RUNNING + info :Hard + speed_duration :"1" + recovery_duration :"1" speed_heart_rate :"180" recovery_heart_rate :"90" repetitions :"10" + type :fixed + end + + power('As strong as an ox') do + sport Sport::WEIGHT_LIFTING + series('Little ox') do + intensity :"5" + repetitions :"20" + end + series('Big ox') do + intensity :"10" + repetitions :"80" + end end end end + ################################################################################################################ + # FIRST SPEED + ################################################################################################################ ## - # Name test. - def test_name + # First speed session name test. + def test_first_session_name training = JSON.parse(AstTdlTest.training.json) - assert_equal training['name'], 'My first training' + assert_equal training['speed'][0]['name'], 'Swimming with the dolphins' end ## - # First session sport type test. + # First speed session sport type test. def test_first_session_sport_type training = JSON.parse(AstTdlTest.training.json) - assert_equal training['session'][0]['sport'], 'swim' + assert_equal training['speed'][0]['sport'], 'swimming' end ## - # First session info message test. + # First speed session info message test. def test_first_session_info_message training = JSON.parse(AstTdlTest.training.json) - assert_equal training['session'][0]['info'], 'Very easy training' + assert_equal training['speed'][0]['info'], 'Very easy training' + end + + ## + # First speed session average heart rate test. + def test_first_session_average_heart_rate + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['speed'][0]['average_heart_rate'], 130 + end + + ## + # First speed session total duration test. + def test_first_session_total_duration + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['speed'][0]['total_duration'], 30 + end + + ################################################################################################################ + # SECOND SPEED + ################################################################################################################ + ## + # Second speed session name test. + def test_second_session_name + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['speed'][1]['name'], 'Cross the country' + end + + ## + # Second speed session sport type test. + def test_second_session_sport_type + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['speed'][1]['sport'], 'cycling' + end + + ## + # Second speed session info message test. + def test_second_session_info_message + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['speed'][1]['info'], 'Endurance ride' + end + + ## + # Second speed session average heart rate test. + def test_second_session_average_heart_rate + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['speed'][1]['average_heart_rate'], 140 + end + + ## + # Second speed session total duration test. + def test_second_session_total_duration + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['speed'][1]['total_duration'], 120 + end + + ################################################################################################################ + # FIRST INTERVAL + ################################################################################################################ + ## + # First interval session name test. + def test_first_interval_name + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['name'], 'Following Emil Zatopek' + end + + ## + # First interval session sport type test. + def test_first_interval_sport_type + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['sport'], 'running' + end + + ## + # First interval session info message test. + def test_first_interval_info_message + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['info'], 'Hard' + end + + ## + # First interval session speed duration test. + def test_first_interval_speed_duration + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['speed_duration'], 1 + end + + ## + # First interval session recovery duration test. + def test_first_interval_recovery_duration + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['recovery_duration'], 1 + end + + ## + # First interval session speed heart rate test. + def test_first_interval_speed_heart_rate + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['speed_heart_rate'], 180 + end + + ## + # First interval session recovery heart rate test. + def test_first_interval_recovery_heart_rate + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['recovery_heart_rate'], 90 + end + + ## + # First interval sesion repetitions test. + def test_first_interval_repetitions + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['repetitions'], 10 + end + + ## + # First interval sesion type test. + def test_first_interval_type + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['interval'][0]['type'], 'fixed' + end + + ################################################################################################################ + # FIRST POWER + ################################################################################################################ + ## + # First power session name test. + def test_first_power_name + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['power'][0]['name'], 'As strong as an ox' + end + + ## + # First power session sport type test. + def test_first_power_sport_type + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['power'][0]['sport'], 'weight lifting' + end + + ## + # First power session first series name test. + def test_first_power_first_series_name + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['power'][0]['series'][0]['name'], 'Little ox' + end + + ## + # First power session first series intensity test. + def test_first_power_first_series_intensity + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['power'][0]['series'][0]['intensity'], 5 + end + + ## + # First power session first series repetitions test. + def test_first_power_first_series_repetitions + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['power'][0]['series'][0]['repetitions'], 20 + end + + ## + # First power session second series name test. + def test_first_power_second_series_name + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['power'][0]['series'][1]['name'], 'Big ox' + end + + ## + # First power session second series intensity test. + def test_first_power_second_series_intensity + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['power'][0]['series'][1]['intensity'], 10 + end + + ## + # First power session second series repetitions test. + def test_first_power_second_series_repetitions + training = JSON.parse(AstTdlTest.training.json) + assert_equal training['power'][0]['series'][1]['repetitions'], 80 end end From 957cce82ead98933691349e29c6c6e718cdf3703 Mon Sep 17 00:00:00 2001 From: luckyLukac <73126820+luckyLukac@users.noreply.github.com> Date: Thu, 29 Sep 2022 14:42:14 +0200 Subject: [PATCH 06/10] Update README.md --- README.md | 93 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 323fa1f..27586bb 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ast-dsl is intended to be a small DSL for practical definition and description of sports training that can be automatically or manually defined and used in conjunction with Artificial Sport Trainer. ## Feature diagram -![scheme](https://raw.githubusercontent.com/firefly-cpp/ast-tdl/main/.github/img/ast-tdl-feature.png) +![ast-tdl](https://user-images.githubusercontent.com/73126820/193033601-6c94b328-30a4-4b25-86a3-0fb81cebca3d.png) ## Installation $ gem install ast-tdl @@ -18,53 +18,82 @@ Training Description Language (TDL) is implemented in Ruby. Currently, the descr ## Examples ```ruby -Ast.build('My first training') do - session('Short swimming session') do - sport :swim - info :"Very easy training" - average_heart_rate :"130" - total_duration :"30" +Ast.build do + speed('Swimming with the dolphins') do + sport Sport::SWIMMING + info :"Very easy training" + average_heart_rate :"130" + total_duration :"30" end - session('Bike ride') do - sport :cycling - info :"Endurance ride with intervals" - average_heart_rate :"140" - total_duration :"120" + speed('Cross the country') do + sport Sport::CYCLING + info :"Endurance ride" + average_heart_rate :"140" + total_duration :"120" end - interval('Sample interval') do - sport :cycling - info :Moderate - speed_duration :"5" - recovery_duration :"5" + interval('Following Emil Zatopek') do + sport Sport::RUNNING + info :Hard + speed_duration :"1" + recovery_duration :"1" speed_heart_rate :"180" recovery_heart_rate :"90" repetitions :"10" + type :fixed end + + power('As strong as an ox') do + sport Sport::WEIGHT_LIFTING + series('Little ox') do + intensity :"5" + repetitions :"20" + end + series('Big ox') do + intensity :"10" + repetitions :"80" + end + end +end +``` + +### Speed session +```ruby +speed('Cross the country') do + sport Sport::CYCLING + info :"Endurance ride" + average_heart_rate :"140" + total_duration :"120" end ``` -### Session +### Interval session ```ruby -session('Bike ride') do - sport :cycling - info :"Endurance ride with intervals" - average_heart_rate :"140" - total_duration :"120" +interval('Following Emil Zatopek') do + sport Sport::RUNNING + info :Hard + speed_duration :"1" + recovery_duration :"1" + speed_heart_rate :"180" + recovery_heart_rate :"90" + repetitions :"10" + type :fixed end ``` -### Interval +### Power session ```ruby -interval('Sample interval') do - sport :cycling - info :Moderate - speed_duration :"5" - recovery_duration :"5" - speed_heart_rate :"180" - recovery_heart_rate :"90" - repetitions :"10" +power('As strong as an ox') do + sport Sport::WEIGHT_LIFTING + series('Little ox') do + intensity :"5" + repetitions :"20" + end + series('Big ox') do + intensity :"10" + repetitions :"80" + end end ``` From 28b3a4676668dcbd060df9ca1c2a3cef8ba21e44 Mon Sep 17 00:00:00 2001 From: luckyLukec Date: Thu, 29 Sep 2022 18:37:58 +0200 Subject: [PATCH 07/10] Removed unnecessary file --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 96d7b82..e06586e 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,5 @@ build-iPhoneSimulator/ # .rubocop-https?--* -/feature_diagram \ No newline at end of file +/feature_diagram +*.gemspec \ No newline at end of file From 47d62da9e3f9ced6fabfb59aa35166a6b73060c0 Mon Sep 17 00:00:00 2001 From: luckyLukec Date: Thu, 29 Sep 2022 18:40:47 +0200 Subject: [PATCH 08/10] Removed unnecessary file --- .gitignore | 2 +- ast-tdl.gemspec | 28 ---------------------------- 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 ast-tdl.gemspec diff --git a/.gitignore b/.gitignore index e06586e..508c612 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -*.gem *.rbc /.config /coverage/ @@ -57,4 +56,5 @@ build-iPhoneSimulator/ /feature_diagram +*.gem *.gemspec \ No newline at end of file diff --git a/ast-tdl.gemspec b/ast-tdl.gemspec deleted file mode 100644 index 0a3c1fc..0000000 --- a/ast-tdl.gemspec +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -Gem::Specification.new do |spec| - spec.name = 'ast-tdl' - spec.version = '0.1.1' - spec.license = 'MIT' - spec.authors = %w[firefly-cpp luckyLukac] - spec.email = ['iztok@iztok-jr-fister.eu', 'luka.lukac@student.um.si'] - - spec.summary = 'An experimental and minimalistic Training Description Language for Artificial Sport Trainer' - spec.homepage = 'https://github.com/firefly-cpp/ast-tdl' - spec.required_ruby_version = '>= 2.6.0' - - spec.metadata['homepage_uri'] = spec.homepage - spec.metadata['source_code_uri'] = 'https://github.com/firefly-cpp/ast-tdl' - spec.metadata['changelog_uri'] = 'https://github.com/firefly-cpp/ast-tdl' - - spec.require_paths = ['lib'] - - spec.files = [ - 'LICENSE', - 'README.md', - 'lib/ast.rb', - 'lib/interval.rb', - 'lib/session.rb', - 'lib/ast-tdl.rb' - ] -end From df84f1edb221b8121fe1a7487e6aaa9201c8776a Mon Sep 17 00:00:00 2001 From: luckyLukac <73126820+luckyLukac@users.noreply.github.com> Date: Thu, 29 Sep 2022 19:16:30 +0200 Subject: [PATCH 09/10] Update README.md --- README.md | 75 +++++++++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 27586bb..d455005 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,36 @@ ## Motivation ast-dsl is intended to be a small DSL for practical definition and description of sports training that can be automatically or manually defined and used in conjunction with Artificial Sport Trainer. +According to sports theory, three major types of sports trainings exist: +- speed trainings, +- interval trainings and +- power trainings. + +Speed trainings are intended for supplying an athlete with energy, coordination and power adaptation. This type of sports training is often used by middle-distance athletes, as they can be very useful for enhancing their performance. + +Interval training has been described for the first time by Reindell and Roskamm, however, it was popularized by the famous Chech athlete Emil Zatopek. This type of training consists of a speed phase that is followed by a recovery phase. This sequence is repeated for several times where the number of repetitions depends on interval training plan. + +Power trainings have been proven to be an effective method for increasing muscle mass. Consequently, in most cases they are used at extreme sports, such as weight lifting, where the lactate amount in blood is significant. + ## Feature diagram ![ast-tdl](https://user-images.githubusercontent.com/73126820/193033601-6c94b328-30a4-4b25-86a3-0fb81cebca3d.png) ## Installation - $ gem install ast-tdl +```sh +$ gem install ast-tdl +``` ## Language description -Training Description Language (TDL) is implemented in Ruby. Currently, the description of sports training sessions and intervals is now supported. Those contain various data, such as duration, average heart rate, sport type, and many more. +Training Description Language (TDL) is implemented in Ruby. All three major training types (speed, interval and power) can be described in TDL. + +Speed training sessions are described with their name, sport type, proposed average heart rate and total duration, while the additional information is optional. + +Interval training sessions, as well as their speed counterparts, are described with their name, type of sport and optional information. However, heart rate and duration of intervals are described separately for both speed and recovery phase. Additionally, number of repetitions and interval training type are also described along with forementioned features. + +Power training sessions are described with their names and sport types, but opposed to speed and interval they are described with series, which are furtherly described with their name, intensity level from 1 to 10 and number of repetitions. ## Examples +### Example of a sports training ```ruby Ast.build do speed('Swimming with the dolphins') do @@ -47,55 +67,17 @@ Ast.build do power('As strong as an ox') do sport Sport::WEIGHT_LIFTING series('Little ox') do - intensity :"5" - repetitions :"20" + intensity: :"5" + repetitions :"20" end series('Big ox') do - intensity :"10" - repetitions :"80" + intensity :"10" + repetitions :"80" end end end ``` - -### Speed session -```ruby -speed('Cross the country') do - sport Sport::CYCLING - info :"Endurance ride" - average_heart_rate :"140" - total_duration :"120" -end -``` - -### Interval session -```ruby -interval('Following Emil Zatopek') do - sport Sport::RUNNING - info :Hard - speed_duration :"1" - recovery_duration :"1" - speed_heart_rate :"180" - recovery_heart_rate :"90" - repetitions :"10" - type :fixed -end -``` - -### Power session -```ruby -power('As strong as an ox') do - sport Sport::WEIGHT_LIFTING - series('Little ox') do - intensity :"5" - repetitions :"20" - end - series('Big ox') do - intensity :"10" - repetitions :"80" - end -end -``` +The description of the sports training consists of four sessions: two speed sessions, one interval sesssion and one power session. The first, swimming speed session is relatively easy, as the planned heart rate throughout the whole session is prescribed to be 130 bpm, and it lasts for half an hour. The next, cycling speed session is described as a 2-hour endurance ride with the prescribed average heart rate of 140 bpm. The third session is a hard, running interval training. It consists of 10 fixed intervals, where speed phase and recovery duration are 1 minute each. The proposed heart rate during speed phases is set at 180 bpm, while in recovery phases it is set to half the speed heart rate: 90 bpm. The final, weight lifting power session consists of two series, the first being of middle intensity with 20 repetitions and the second being of extreme intensity with 80 repetitions. ## License This package is distributed under the MIT License. This license can be found online at . @@ -104,5 +86,6 @@ This package is distributed under the MIT License. This license can be found onl This framework is provided as-is, and there are no guarantees that it fits your purposes or that it is bug-free. Use it at your own risk! ## References - Fister Jr, I., Fister, I., Iglesias, A., Galvez, A., Deb, S., & Fister, D. (2021). On deploying the Artificial Sport Trainer into practice. arXiv preprint [arXiv:2109.13334](https://arxiv.org/abs/2109.13334). + +Lukač, L. (2022). Aplikacija koncepta digitalnega dvojčka v športu [online]. University of Maribor, Faculty of Electrical Engineering and Computer Science. [Access: 29th September, 2022]. From 306afe58244d03a049689f4787f5b56678d2e23f Mon Sep 17 00:00:00 2001 From: luckyLukec Date: Thu, 29 Sep 2022 19:24:00 +0200 Subject: [PATCH 10/10] Small bugfix --- .gitignore | 3 +-- ast-tdl.gemspec | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 ast-tdl.gemspec diff --git a/.gitignore b/.gitignore index 508c612..ec8a8e5 100644 --- a/.gitignore +++ b/.gitignore @@ -56,5 +56,4 @@ build-iPhoneSimulator/ /feature_diagram -*.gem -*.gemspec \ No newline at end of file +*.gem \ No newline at end of file diff --git a/ast-tdl.gemspec b/ast-tdl.gemspec new file mode 100644 index 0000000..0a3c1fc --- /dev/null +++ b/ast-tdl.gemspec @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +Gem::Specification.new do |spec| + spec.name = 'ast-tdl' + spec.version = '0.1.1' + spec.license = 'MIT' + spec.authors = %w[firefly-cpp luckyLukac] + spec.email = ['iztok@iztok-jr-fister.eu', 'luka.lukac@student.um.si'] + + spec.summary = 'An experimental and minimalistic Training Description Language for Artificial Sport Trainer' + spec.homepage = 'https://github.com/firefly-cpp/ast-tdl' + spec.required_ruby_version = '>= 2.6.0' + + spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['source_code_uri'] = 'https://github.com/firefly-cpp/ast-tdl' + spec.metadata['changelog_uri'] = 'https://github.com/firefly-cpp/ast-tdl' + + spec.require_paths = ['lib'] + + spec.files = [ + 'LICENSE', + 'README.md', + 'lib/ast.rb', + 'lib/interval.rb', + 'lib/session.rb', + 'lib/ast-tdl.rb' + ] +end