runby_pace 0.2.50.111 → 0.2.55

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +13 -5
  2. data/.travis.yml +1 -5
  3. data/Gemfile +0 -4
  4. data/README.md +5 -16
  5. data/Rakefile +6 -40
  6. data/bin/_guard-core +16 -17
  7. data/bin/guard +16 -17
  8. data/lib/runby_pace.rb +1 -4
  9. data/lib/runby_pace/{pace_calculator.rb → pace_data.rb} +13 -29
  10. data/lib/runby_pace/pace_range.rb +9 -27
  11. data/lib/runby_pace/pace_time.rb +110 -0
  12. data/lib/runby_pace/run_type.rb +4 -12
  13. data/lib/runby_pace/run_types/all_run_types.template +4 -6
  14. data/lib/runby_pace/run_types/easy_run.rb +10 -31
  15. data/lib/runby_pace/run_types/find_divisor.rb +17 -13
  16. data/lib/runby_pace/run_types/long_run.rb +10 -32
  17. data/lib/runby_pace/version.rb +2 -17
  18. data/runby_pace.gemspec +5 -4
  19. metadata +18 -41
  20. data/.rubocop.yml +0 -10
  21. data/bin/runbypace +0 -15
  22. data/lib/runby_pace/cli/cli.rb +0 -127
  23. data/lib/runby_pace/cli/config.rb +0 -82
  24. data/lib/runby_pace/distance.rb +0 -135
  25. data/lib/runby_pace/distance_unit.rb +0 -89
  26. data/lib/runby_pace/golden_pace_set.rb +0 -50
  27. data/lib/runby_pace/pace.rb +0 -152
  28. data/lib/runby_pace/run_math.rb +0 -14
  29. data/lib/runby_pace/run_types/distance_run.rb +0 -55
  30. data/lib/runby_pace/run_types/fast_tempo_run.rb +0 -23
  31. data/lib/runby_pace/run_types/five_kilometer_race_run.rb +0 -22
  32. data/lib/runby_pace/run_types/mile_race_run.rb +0 -24
  33. data/lib/runby_pace/run_types/slow_tempo_run.rb +0 -22
  34. data/lib/runby_pace/run_types/tempo_run.rb +0 -54
  35. data/lib/runby_pace/run_types/ten_kilometer_race_run.rb +0 -23
  36. data/lib/runby_pace/runby_range.rb +0 -22
  37. data/lib/runby_pace/runby_time.rb +0 -138
  38. data/lib/runby_pace/runby_time_parser.rb +0 -80
  39. data/lib/runby_pace/speed.rb +0 -97
  40. data/lib/runby_pace/speed_range.rb +0 -30
  41. data/lib/runby_pace/utility/parameter_sanitizer.rb +0 -29
  42. data/lib/runby_pace/version.seed +0 -5
  43. data/misc/runbypace_logo.png +0 -0
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Runby
4
-
5
- # Maps a set of 5K race times with their pre-calculated pace recommendations.
6
- # This is useful in testing as well as defining the fastest and slowest supported 5K times.
7
- # GoldenPaceSet could conceivably be used to pre-compute a large number of recommended paces,
8
- # thus reducing runtime CPU overhead.
9
- class GoldenPaceSet
10
- include Enumerable
11
-
12
- attr_reader :paces
13
-
14
- # The fastest 5K time supported by RunbyPace
15
- FASTEST_5K = :'14:00'
16
-
17
- # The slowest 5K time supported by RunbyPace
18
- SLOWEST_5K = :'42:00'
19
-
20
- # @param [Hash] paces_hash is a hash mapping 5K time symbols to times, represented as strings.
21
- # An example paces_hash is {'14:00':'4:00', '15:00':'4:55'}
22
- def initialize(paces_hash)
23
- @paces = {}
24
- paces_hash.each { |five_k_time, recommended_pace| @paces[five_k_time.to_sym] = Pace.new(recommended_pace) }
25
- end
26
-
27
- def each
28
- @paces.each do |h, v|
29
- yield h, v
30
- end
31
- end
32
-
33
- # Returns first/fastest recommended pace in the set
34
- def first
35
- @paces[FASTEST_5K]
36
- end
37
- alias fastest first
38
-
39
- # Return the last/slowest recommended pace in the set
40
- def last
41
- @paces[SLOWEST_5K]
42
- end
43
- alias slowest last
44
-
45
- # Creates and returns a new GoldenPaceSet with only two entries
46
- def self.new_from_endpoints(fastest, slowest)
47
- GoldenPaceSet.new(FASTEST_5K => fastest, SLOWEST_5K => slowest)
48
- end
49
- end
50
- end
@@ -1,152 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Runby
4
- # Represents a pace consisting of a distance and a time in which that distance was covered
5
- class Pace
6
- include Comparable
7
-
8
- attr_reader :time, :distance
9
-
10
- def self.new(time_or_pace, distance = '1K')
11
- return time_or_pace if time_or_pace.is_a? Pace
12
- super
13
- end
14
-
15
- def initialize(time_or_pace, distance = '1K')
16
- case time_or_pace
17
- when RunbyTime
18
- init_from_time time_or_pace, distance
19
- when String
20
- init_from_string time_or_pace, distance
21
- else
22
- raise 'Invalid Time or Pace'
23
- end
24
- freeze
25
- end
26
-
27
- def convert_to(target_distance)
28
- target_distance = Distance.new(target_distance) unless target_distance.is_a?(Distance)
29
- return self if @distance == target_distance
30
- conversion_factor = target_distance / @distance
31
- Pace.new @time * conversion_factor, target_distance
32
- end
33
-
34
- def to_s(format: :short)
35
- leading_one_regex = /^1 ?/
36
- distance_s = @distance.to_s(format: format).gsub(leading_one_regex, '')
37
- case format
38
- when :short then "#{time} p/#{distance_s}"
39
- when :long then "#{time} per #{distance_s}"
40
- else raise "Invalid string format #{format}"
41
- end
42
- end
43
-
44
- def as_speed
45
- total_minutes = @time.total_minutes
46
- multiplier = total_minutes.positive? ? (60 / total_minutes).round(2) : 0
47
- distance = Runby::Distance.new(@distance.uom, multiplier)
48
- Runby::Speed.new distance
49
- end
50
-
51
- def meters_per_minute
52
- total_minutes = @time.total_minutes
53
- return 0 unless total_minutes.positive?
54
- @distance.meters / total_minutes
55
- end
56
-
57
- # @param [String] str is either a long-form pace such as "10:00 per mile" or a short-form pace like "10:00 p/mi"
58
- def self.parse(str)
59
- str = str.to_s.strip.chomp
60
- match = str.match %r{^(?<time>[:\d]*) ?(?: per |p\/)(?<distance>(?:[\d.]+ ?)?\w+)$}
61
- raise "Invalid pace format (#{str})" unless match
62
- time = Runby::RunbyTime.new(match[:time])
63
- distance = Runby::Distance.new(match[:distance])
64
- Pace.new time, distance
65
- end
66
-
67
- def self.try_parse(str)
68
- pace = nil
69
- error_message = nil
70
- warning_message = nil
71
- begin
72
- pace = Pace.parse str
73
- rescue StandardError => ex
74
- error_message = ex.message
75
- end
76
- { pace: pace, error: error_message, warning: warning_message }
77
- end
78
-
79
- def <=>(other)
80
- raise "Unable to compare Runby::Pace to #{other.class}(#{other})" unless [Pace, RunbyTime, String].include? other.class
81
- if other.is_a? Pace
82
- meters_per_minute.round(2) <=> other.meters_per_minute.round(2)
83
- elsif other.is_a? RunbyTime
84
- @time <=> other
85
- elsif other.is_a? String
86
- return 0 if to_s == other || to_s(format: :long) == other
87
- return 0 if @time == other
88
- self <=> try_parse(other)[:pace]
89
- end
90
- end
91
-
92
- def almost_equals?(other_pace, tolerance_time = '00:01')
93
- if other_pace.is_a?(RunbyTime)
94
- return almost_equals?(Pace.new(other_pace, @distance), tolerance_time)
95
- end
96
- if other_pace.is_a?(String)
97
- return almost_equals?(Pace.new(other_pace, @distance), tolerance_time) if other_pace.match?(/^\d?\d:\d\d$/)
98
- other_pace = Pace.parse(other_pace)
99
- end
100
- tolerance = RunbyTime.new(tolerance_time)
101
- fast_end = (self - tolerance)
102
- slow_end = (self + tolerance)
103
- slow_end <= other_pace && other_pace <= fast_end
104
- end
105
-
106
- # @param [Pace, RunbyTime] other
107
- def -(other)
108
- if other.is_a?(Pace)
109
- Pace.new(@time - other.convert_to(@distance).time, @distance)
110
- elsif other.is_a?(RunbyTime)
111
- Pace.new(@time - other, @distance)
112
- end
113
- end
114
-
115
- # @param [Pace, RunbyTime] other
116
- def +(other)
117
- if other.is_a?(Pace)
118
- Pace.new(@time + other.convert_to(@distance).time, @distance)
119
- elsif other.is_a?(RunbyTime)
120
- Pace.new(@time + other, @distance)
121
- end
122
- end
123
-
124
- def distance_covered_over_time(time)
125
- time = Runby.sanitize(time).as(RunbyTime)
126
- if time.total_minutes.zero? || @distance.multiplier.zero?
127
- return Runby::Distance.new(@distance.uom, 0)
128
- end
129
- divisor = @time.total_minutes / time.total_minutes / @distance.multiplier
130
- distance_covered = Runby::Distance.new(@distance.uom, 1 / divisor)
131
- distance_covered
132
- end
133
-
134
- private
135
-
136
- def init_from_string(string, distance = '1K')
137
- pace = Pace.try_parse(string)
138
- if pace[:pace]
139
- @time = pace[:pace].time
140
- @distance = pace[:pace].distance
141
- return
142
- end
143
- @time = Runby::RunbyTime.new string
144
- @distance = Runby::Distance.new distance
145
- end
146
-
147
- def init_from_time(time, distance)
148
- @time = time
149
- @distance = Runby::Distance.new distance
150
- end
151
- end
152
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Runby
4
- # An assortment of mathematical functions related to running.
5
- class RunMath
6
- def self.predict_race_time(race1_distance, race1_time, target_distance)
7
- race1_distance = Runby.sanitize(race1_distance).as(Distance)
8
- race1_time = Runby.sanitize(race1_time).as(RunbyTime)
9
- target_distance = Runby.sanitize(target_distance).as(Distance)
10
-
11
- race1_time * (target_distance / race1_distance)**1.06
12
- end
13
- end
14
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Runby
4
- module RunTypes
5
- # Defines the venerable "distance run", the backbone of any distance running program.
6
- # Most of your runs should be at this pace. Harder than an "easy run" but still conversational.
7
- class DistanceRun < RunType
8
- attr_reader :slow_pace_calculator, :fast_pace_calculator
9
-
10
- def description
11
- 'Distance Run'
12
- end
13
-
14
- def explanation
15
- 'Most of your weekly training should be comprised of Distance Runs. They are faster than easy runs, but you should still be able to carry on a conversation.'
16
- end
17
-
18
- def initialize
19
- @fast_pace_calculator = PaceCalculator.new(GoldenPaces.fast, 3.675)
20
- @slow_pace_calculator = PaceCalculator.new(GoldenPaces.slow, 2.175)
21
- end
22
-
23
- def lookup_pace(five_k_time, distance_units = :km)
24
- fast = @fast_pace_calculator.calc(five_k_time, distance_units)
25
- slow = @slow_pace_calculator.calc(five_k_time, distance_units)
26
- PaceRange.new(fast, slow)
27
- end
28
-
29
- # Used in testing, contains hashes mapping 5K race times with the recommended pace-per-km for this run type.
30
- class GoldenPaces
31
- def self.fast
32
- GoldenPaceSet.new('14:00': '03:44',
33
- '15:00': '03:58',
34
- '20:00': '05:09',
35
- '25:00': '06:18',
36
- '30:00': '07:24',
37
- '35:00': '08:29',
38
- '40:00': '09:33',
39
- '42:00': '09:58')
40
- end
41
-
42
- def self.slow
43
- GoldenPaceSet.new('14:00': '04:17',
44
- '15:00': '04:33',
45
- '20:00': '05:53',
46
- '25:00': '07:09',
47
- '30:00': '08:23',
48
- '35:00': '09:33',
49
- '40:00': '10:42',
50
- '42:00': '11:10')
51
- end
52
- end
53
- end
54
- end
55
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative 'tempo_run'
3
-
4
- module Runby
5
- module RunTypes
6
- # The "fast tempo" pace roughly equates to your half-marathon pace.
7
- # It's a pace you could maintain for about an hour, if pressed.
8
- class FastTempoRun < TempoRun
9
- def description
10
- 'Fast Tempo Run'
11
- end
12
-
13
- def explanation
14
- 'The fast tempo run is an interval workout of 15-25 minutes per repetition. The pace roughly corresponds to that of your half-marathon race pace.'
15
- end
16
-
17
- def lookup_pace(five_k_time, distance_units = :km)
18
- fast = @fast_pace_calculator.calc(five_k_time, distance_units)
19
- PaceRange.new(fast, fast)
20
- end
21
- end
22
- end
23
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Runby
4
- module RunTypes
5
- # Your 5K race pace, which is also useful for running repetitions at this pace
6
- class FiveKilometerRaceRun < RunType
7
- def description
8
- '5K Race Pace'
9
- end
10
-
11
- def explanation
12
- 'The 5K race (~3.1 miles) is an excellent gauge of overall fitness. Running repetitions of varying duration at 5K race pace can boost stroke volume, blood volume, mitochondrial and capillary density, etc.'
13
- end
14
-
15
- def lookup_pace(five_k_time, distance_units = :km)
16
- five_k_time = RunbyTime.new(five_k_time)
17
- pace = Pace.new(five_k_time / 5, '1km').convert_to(distance_units)
18
- PaceRange.new(pace, pace)
19
- end
20
- end
21
- end
22
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Runby
4
- module RunTypes
5
- # Your mile race pace, which is also useful for running repetitions at this pace
6
- class MileRaceRun < RunType
7
- def description
8
- 'Mile Race Pace'
9
- end
10
-
11
- def explanation
12
- 'Repetitions run at a pace you would use to race one mile can increase the stroke volume of your heart, strengthen your lungs, increase the number of capillaries around your intermediate and fast twitch fibers, and increase mitochondrial densities around the same.'
13
- end
14
-
15
- def lookup_pace(five_k_time, distance_units = :km)
16
- five_k_time = RunbyTime.new(five_k_time)
17
- mile = Distance.new('1 mile')
18
- mile_time = RunMath.predict_race_time('5K', five_k_time, mile)
19
- pace = Pace.new(mile_time, mile).convert_to(distance_units)
20
- PaceRange.new(pace, pace)
21
- end
22
- end
23
- end
24
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative 'tempo_run'
3
-
4
- module Runby
5
- module RunTypes
6
- # The "slow tempo" pace roughly equates to your marathon pace.
7
- class SlowTempoRun < TempoRun
8
- def description
9
- 'Slow Tempo Run'
10
- end
11
-
12
- def explanation
13
- 'The slow tempo run is an interval workout of 20-40 minutes per repetition. The pace roughly corresponds to that of your marathon race pace.'
14
- end
15
-
16
- def lookup_pace(five_k_time, distance_units = :km)
17
- slow = @slow_pace_calculator.calc(five_k_time, distance_units)
18
- PaceRange.new(slow, slow)
19
- end
20
- end
21
- end
22
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Runby
4
- module RunTypes
5
- # Combines the fast and slow tempo runs into one convenient range of paces
6
- class TempoRun < RunType
7
- attr_reader :slow_pace_calculator, :fast_pace_calculator
8
-
9
- def description
10
- 'Tempo Run'
11
- end
12
-
13
- def explanation
14
- 'Ran at a comfortably hard pace that you could maintain for about an hour, if pressed. However, tempo runs are interval workouts, so you won\'t run for longer than 15-40 minutes per repetition'
15
- end
16
-
17
- def initialize
18
- @fast_pace_calculator = PaceCalculator.new(GoldenPaces.fast, 4.025)
19
- @slow_pace_calculator = PaceCalculator.new(GoldenPaces.slow, 3.725)
20
- end
21
-
22
- def lookup_pace(five_k_time, distance_units = :km)
23
- fast = @fast_pace_calculator.calc(five_k_time, distance_units)
24
- slow = @slow_pace_calculator.calc(five_k_time, distance_units)
25
- PaceRange.new(fast, slow)
26
- end
27
-
28
- # Used in testing, contains hashes mapping 5K race times with the recommended pace-per-km for this run type.
29
- class GoldenPaces
30
- def self.fast
31
- GoldenPaceSet.new('14:00': '03:07',
32
- '15:00': '03:20',
33
- '20:00': '04:21',
34
- '25:00': '05:20',
35
- '30:00': '06:19',
36
- '35:00': '07:16',
37
- '40:00': '08:12',
38
- '42:00': '08:35')
39
- end
40
-
41
- def self.slow
42
- GoldenPaceSet.new('14:00': '03:18',
43
- '15:00': '03:31',
44
- '20:00': '04:35',
45
- '25:00': '05:37',
46
- '30:00': '06:38',
47
- '35:00': '07:38',
48
- '40:00': '08:36',
49
- '42:00': '08:59')
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Runby
4
- module RunTypes
5
- # Your 10K race pace, which is also useful for running repetitions at this pace
6
- class TenKilometerRaceRun < RunType
7
- def description
8
- '10K Race Pace'
9
- end
10
-
11
- def explanation
12
- 'Repetitions ran at 10K race pace (10 km is about 6.2 miles) are like 5K pace repetitions, but less intense. They elicit many of the same benefits and help increase speed in races from the 10K to the half-marathon.'
13
- end
14
-
15
- def lookup_pace(five_k_time, distance_units = :km)
16
- five_k_time = RunbyTime.new(five_k_time)
17
- ten_k_time = RunMath.predict_race_time('5K', five_k_time, '10K')
18
- pace = Pace.new(ten_k_time / 10, '1km').convert_to(distance_units)
19
- PaceRange.new(pace, pace)
20
- end
21
- end
22
- end
23
- end