lib/runby_pace/pace.rb in runby_pace-0.6.113 vs lib/runby_pace/pace.rb in runby_pace-0.6.114
- old
+ new
@@ -4,15 +4,19 @@
include Comparable
attr_reader :time, :distance
def initialize(time_or_pace, distance = '1K')
- if time_or_pace.is_a? Pace
- init_from_clone time_or_pace
- else
- @time = Runby::RunbyTime.new(time_or_pace)
- @distance = Runby::Distance.new(distance)
+ case time_or_pace
+ when Pace
+ return init_from_clone time_or_pace
+ when RunbyTime
+ return init_from_time time_or_pace, distance
+ when String
+ return init_from_string time_or_pace, distance
+ else
+ raise 'Invalid Time or Pace'
end
end
def to_s(format: :short)
distance_s = @distance.to_s(format: format)
@@ -28,30 +32,53 @@
multiplier = (60 / @time.total_minutes).round(2)
distance = Runby::Distance.new(@distance.uom, multiplier)
Runby::Speed.new distance
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
+ if str.match(/^(?<time>[:\d]*) ?(?: per |p\/)(?<distance>(?:[\d.]+ ?)?\w+)$/)
+ time = Runby::RunbyTime.new($~[:time])
+ distance = Runby::Distance.new($~[:distance])
+ Pace.new time, distance
+ else
+ raise "Invalid pace format (#{str})"
+ end
+ end
+
+ def self.try_parse(str)
+ pace, error_message = nil, warning_message = nil
+ begin
+ pace = Pace.parse str
+ rescue StandardError => ex
+ error_message = ex.message
+ end
+ { pace: pace, error: error_message, warning: warning_message }
+ end
+
def <=>(other)
if other.is_a? Pace
- return nil unless @distance == other.distance
+ raise 'Comparing paces of different distances is not currently supported' unless @distance == other.distance
@time <=> other.time
elsif other.is_a? RunbyTime
@time <=> other.time
elsif other.is_a? String
- # TODO: Parse as Pace when Pace.parse is available
- @time <=> RunbyTime.parse(other)
+ return 0 if to_s == other || to_s(format: :long) == other
+ return 0 if @time == other
+ self <=> try_parse(other)[:pace]
end
end
def almost_equals?(other_pace, tolerance_time = '00:01')
return @time.almost_equals?(other_pace, tolerance_time) if other_pace.is_a?(RunbyTime)
if other_pace.is_a?(String)
- # TODO: Get parsing working
+ return @time.almost_equals?(other_pace, tolerance_time) if other_pace =~ /^\d\d:\d\d$/
other_pace = Pace.parse(other_pace)
end
tolerance = RunbyTime.new(tolerance_time)
- self >= (other_pace - tolerance) && self <= (other_pace + tolerance)
+ (self - tolerance) <= other_pace && (self + tolerance) >= other_pace
end
# @param [Pace, RunbyTime] other
def -(other)
if other.is_a?(Pace)
@@ -83,8 +110,24 @@
def init_from_clone(other_pace)
raise "#{other_pace} is not a Runby::Pace" unless other_pace.is_a? Pace
@time = other_pace.time
@distance = other_pace.distance
+ end
+
+ def init_from_string(string, distance = '1K')
+ pace = Pace.try_parse(string)
+ if pace[:pace]
+ @time = pace[:pace].time
+ @distance = pace[:pace].distance
+ return
+ end
+ @time = Runby::RunbyTime.new string
+ @distance = Runby::Distance.new distance
+ end
+
+ def init_from_time(time, distance)
+ @time = time
+ @distance = Runby::Distance.new distance
end
end
end