feat: training zones in miles, %HRmax fallback, and miles input (v1.11.0) - #81
Merged
Conversation
Accepting race names made every non-Numeric input fall through to the
RACE_DISTANCES lookup, so numeric strings that worked in v1.10.0 ('10',
'21.0975') started raising "Unknown race". Parse the input with
Float(..., exception: false) first and only treat unparseable input as a
race name.
The 0.001 km match window is narrower than the rounding runners use for mile distances, so 3.1, 6.2, 13.1 and 26.2 mi were all rejected — only 6-decimal conversions matched. Match with a relative tolerance (0.5% of the standard distance, 1 m floor) and report the rejected input in the unit it was given instead of always saying "km".
The unit: and distance_unit: keywords raised a bare ArgumentError, which escapes `rescue Calcpace::Error` and contradicts the documented error hierarchy. Both keyword lookups now raise Calcpace::UnsupportedUnitError, which gained an optional list of supported units for a clear message. Unit keywords are also normalized with to_s.downcase.to_sym, so 'MI' works and nil raises the same UnsupportedUnitError instead of a NoMethodError.
estimate_detailed_vo2max accepted a negative distance whenever elevation_gain_m was large enough to make the equivalent flat distance positive; check it right after normalization. Docs: HR_ZONE_BOUNDARIES is shared by Karvonen and %HRmax zones, so its comment no longer claims Karvonen only; document that distance_unit: is ignored for race names in training_paces_from_race and age_grade; list UnsupportedUnitError in the README and record the behaviour changes of this release in the CHANGELOG.
Two truths for the mile length coexisted: pace bands used 1609.344 while the converter table used the truncated 1.60934, so a single call could disagree with itself about how long a mile is, and the drift ate 10% of the age-grading match tolerance. Distance, speed, and race-distance factors now derive from one constant. Also folds in the rest of the review: distance_unit alongside a race name raises instead of being silently ignored, race-name lookup normalizes in one place (whitespace and case now tolerated everywhere, with one message wording), and ParameterLists keeps a ceiling of 6 instead of ignoring keyword arguments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Training Zones II — completes the
TrainingZonesmodule and adds imperial input support across the gem, unblocking the pending "zones in the UI" work on calcpace_web.training_pacesandtraining_paces_from_raceacceptunit: :mifor output per mile (default stays:km). Sanity-checked against Daniels VDOT 50: T-pace 04:15/km ↔ 06:51/mi.hr_zones_from_max(hr_max:): five heart-rate zones from max HR only (classic %HRmax model, 50–100%) — fallback when resting HR is unknown. Prefer Karvonenhr_zoneswhenhr_restis available.training_paces_from_race:'10k','marathon','5mile', ... resolved viaRACE_DISTANCES, matchingpredict_time/race_pace. Also fixes a silent trap:'10k'previously "worked" viaString#to_f, while'5mile'became 5.0 km.distance_unit: :mikeyword on the five km-bound methods (estimate_vo2max,estimate_detailed_vo2max,age_grade,age_grade_percent,training_paces_from_race) via a sharednormalize_distance_kmhelper reusingDistance::MI_TO_KM. Calculator methods (pace,time,velocity) stay unit-agnostic by design.Fully backward compatible (new kwargs default to current behavior). Version bumped to 1.11.0 with CHANGELOG and README updates.
Test plan
bundle exec rake)Metrics/ParameterLists.CountKeywordArgs: false)