# frozen_string_literal: true module Runby # Represents a pace consisting of a distance and a time in which that distance was covered class Pace include Comparable attr_reader :time, :distance def self.new(time_or_pace, distance = '1K') return time_or_pace if time_or_pace.is_a? Pace super end def initialize(time_or_pace, distance = '1K') case time_or_pace when RunbyTime init_from_time time_or_pace, distance when String init_from_string time_or_pace, distance else raise 'Invalid Time or Pace' end freeze end def convert_to(target_distance) target_distance = Distance.new(target_distance) unless target_distance.is_a?(Distance) return self if @distance == target_distance conversion_factor = target_distance / @distance Pace.new @time * conversion_factor, target_distance end def to_s(format: :short) leading_one_regex = /^1 ?/ distance_s = @distance.to_s(format: format).gsub(leading_one_regex, '') case format when :short then "#{time} p/#{distance_s}" when :long then "#{time} per #{distance_s}" end end def as_speed total_minutes = @time.total_minutes multiplier = total_minutes.positive? ? (60 / total_minutes).round(2) : 0 distance = Runby::Distance.new(@distance.uom, multiplier) Runby::Speed.new distance end def meters_per_minute total_minutes = @time.total_minutes return 0 unless total_minutes.positive? @distance.meters / total_minutes end # @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" def self.parse(str) str = str.to_s.strip.chomp match = str.match %r{^(?