strava-ruby-client 3.0.0.pre.2 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -2
- data/README.md +47 -58
- data/lib/strava/api/client.rb +69 -0
- data/lib/strava/api/config.rb +40 -0
- data/lib/strava/api/cursor.rb +32 -1
- data/lib/strava/api/endpoints/activities.rb +197 -57
- data/lib/strava/api/endpoints/athletes.rb +64 -8
- data/lib/strava/api/endpoints/clubs.rb +24 -59
- data/lib/strava/api/endpoints/gears.rb +11 -2
- data/lib/strava/api/endpoints/oauth.rb +45 -0
- data/lib/strava/api/endpoints/routes.rb +20 -13
- data/lib/strava/api/endpoints/segment_efforts.rb +15 -8
- data/lib/strava/api/endpoints/segments.rb +74 -21
- data/lib/strava/api/endpoints/streams.rb +22 -18
- data/lib/strava/api/endpoints/uploads.rb +12 -2
- data/lib/strava/api/pagination.rb +25 -0
- data/lib/strava/api/ratelimit.rb +34 -0
- data/lib/strava/deep_copyable.rb +20 -1
- data/lib/strava/errors/fault.rb +32 -0
- data/lib/strava/errors/ratelimit_error.rb +35 -0
- data/lib/strava/errors/upload_error.rb +55 -0
- data/lib/strava/logger.rb +27 -0
- data/lib/strava/models/achievement.rb +28 -1
- data/lib/strava/models/activity_stats.rb +47 -1
- data/lib/strava/models/activity_total.rb +25 -1
- data/lib/strava/models/activity_zone.rb +39 -2
- data/lib/strava/models/authorization.rb +13 -0
- data/lib/strava/models/base_stream.rb +22 -1
- data/lib/strava/models/club_event.rb +64 -1
- data/lib/strava/models/comment.rb +39 -1
- data/lib/strava/models/destination.rb +28 -1
- data/lib/strava/models/detailed_activity.rb +203 -2
- data/lib/strava/models/detailed_athlete.rb +104 -2
- data/lib/strava/models/detailed_club.rb +76 -2
- data/lib/strava/models/detailed_gear.rb +45 -2
- data/lib/strava/models/detailed_photo.rb +61 -1
- data/lib/strava/models/detailed_photos.rb +29 -1
- data/lib/strava/models/detailed_segment.rb +89 -2
- data/lib/strava/models/detailed_segment_effort.rb +92 -3
- data/lib/strava/models/explorer_segment.rb +55 -2
- data/lib/strava/models/heart_rate_zone_ranges.rb +29 -1
- data/lib/strava/models/kudoser.rb +29 -1
- data/lib/strava/models/lap.rb +62 -2
- data/lib/strava/models/lat_lng.rb +42 -4
- data/lib/strava/models/local_legend.rb +41 -1
- data/lib/strava/models/map.rb +31 -0
- data/lib/strava/models/meta_activity.rb +15 -2
- data/lib/strava/models/meta_athlete.rb +17 -2
- data/lib/strava/models/meta_club.rb +15 -1
- data/lib/strava/models/mixins/average_speed.rb +81 -3
- data/lib/strava/models/mixins/distance.rb +25 -0
- data/lib/strava/models/mixins/elapsed_time.rb +18 -0
- data/lib/strava/models/mixins/elevation_difference.rb +42 -0
- data/lib/strava/models/mixins/elevation_gain.rb +39 -0
- data/lib/strava/models/mixins/estimated_moving_time.rb +18 -0
- data/lib/strava/models/mixins/http_response.rb +36 -0
- data/lib/strava/models/mixins/moving_time.rb +18 -0
- data/lib/strava/models/mixins/sport_type.rb +39 -1
- data/lib/strava/models/mixins/start_date_local.rb +40 -24
- data/lib/strava/models/mixins/time_in_hours.rb +23 -0
- data/lib/strava/models/mixins/total_elevation_gain.rb +42 -0
- data/lib/strava/models/model.rb +14 -0
- data/lib/strava/models/photos_summary.rb +26 -2
- data/lib/strava/models/photos_summary_primary.rb +28 -2
- data/lib/strava/models/power_zone_ranges.rb +23 -1
- data/lib/strava/models/response.rb +18 -0
- data/lib/strava/models/route.rb +63 -2
- data/lib/strava/models/similar_activities.rb +57 -1
- data/lib/strava/models/split.rb +27 -2
- data/lib/strava/models/stats_visibility.rb +24 -1
- data/lib/strava/models/stream.rb +107 -0
- data/lib/strava/models/stream_set.rb +52 -1
- data/lib/strava/models/summary_activity.rb +145 -2
- data/lib/strava/models/summary_athlete.rb +54 -1
- data/lib/strava/models/summary_club.rb +61 -2
- data/lib/strava/models/summary_gear.rb +31 -2
- data/lib/strava/models/summary_pr_segment_effort.rb +32 -2
- data/lib/strava/models/summary_segment.rb +80 -2
- data/lib/strava/models/summary_segment_effort.rb +32 -1
- data/lib/strava/models/timed_zone_range.rb +24 -1
- data/lib/strava/models/token.rb +31 -0
- data/lib/strava/models/trend.rb +38 -1
- data/lib/strava/models/updatable_activity.rb +36 -1
- data/lib/strava/models/upload.rb +50 -1
- data/lib/strava/models/waypoint.rb +31 -1
- data/lib/strava/models/xoms.rb +35 -1
- data/lib/strava/models/zone_range.rb +20 -1
- data/lib/strava/models/zones.rb +32 -1
- data/lib/strava/oauth/client.rb +107 -19
- data/lib/strava/oauth/config.rb +41 -0
- data/lib/strava/version.rb +1 -1
- data/lib/strava/web/api_response.rb +28 -2
- data/lib/strava/web/client.rb +72 -2
- data/lib/strava/web/config.rb +40 -0
- data/lib/strava/web/connection.rb +39 -0
- data/lib/strava/web/raise_response_error.rb +47 -0
- data/lib/strava/web/request.rb +56 -0
- data/lib/strava/web/response.rb +18 -0
- data/lib/strava/webhooks/client.rb +108 -7
- data/lib/strava/webhooks/config.rb +44 -0
- data/lib/strava/webhooks/models/challenge.rb +40 -0
- data/lib/strava/webhooks/models/event.rb +50 -0
- data/lib/strava/webhooks/models/subscription.rb +27 -0
- data/lib/strava-ruby-client.rb +0 -2
- metadata +2 -4
- data/lib/strava/models/club_activity.rb +0 -22
- data/lib/strava/models/club_athlete.rb +0 -21
|
@@ -2,27 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
+
#
|
|
6
|
+
# Represents geographic coordinates (latitude/longitude).
|
|
7
|
+
#
|
|
8
|
+
# This is a helper class for working with geographic coordinates in Strava data.
|
|
9
|
+
# Coordinates are stored as an array [latitude, longitude] and can be accessed
|
|
10
|
+
# via helper methods or array syntax.
|
|
11
|
+
#
|
|
12
|
+
# @example Accessing coordinates
|
|
13
|
+
# activity = client.activity(1234567890)
|
|
14
|
+
# start = activity.start_latlng
|
|
15
|
+
# puts "Latitude: #{start.lat}"
|
|
16
|
+
# puts "Longitude: #{start.lng}"
|
|
17
|
+
# puts "Array: #{start.to_a.inspect}" # [40.7128, -74.0060]
|
|
18
|
+
#
|
|
19
|
+
# @example Creating coordinates
|
|
20
|
+
# coords = Strava::Models::LatLng.new([40.7128, -74.0060])
|
|
21
|
+
# coords.lat # => 40.7128
|
|
22
|
+
# coords.lng # => -74.0060
|
|
23
|
+
#
|
|
5
24
|
class LatLng
|
|
25
|
+
# @return [Array<Float>] Coordinates as [latitude, longitude]
|
|
6
26
|
attr_accessor :latlng
|
|
7
27
|
|
|
28
|
+
#
|
|
29
|
+
# Initialize with coordinates.
|
|
30
|
+
#
|
|
31
|
+
# @param latlng [Array<Float>, nil] Coordinates as [latitude, longitude]
|
|
32
|
+
#
|
|
33
|
+
def initialize(latlng = nil)
|
|
34
|
+
@latlng = latlng
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @return [Float, nil] Latitude
|
|
8
38
|
def lat
|
|
9
39
|
@latlng[0]
|
|
10
40
|
end
|
|
11
41
|
|
|
42
|
+
# @return [Float, nil] Longitude
|
|
12
43
|
def lng
|
|
13
44
|
@latlng[1]
|
|
14
45
|
end
|
|
15
46
|
|
|
47
|
+
# @param value [Float] Latitude value
|
|
16
48
|
def lat=(value)
|
|
17
49
|
@latlng ||= [nil, nil]
|
|
18
50
|
@latlng[0] = value
|
|
19
51
|
end
|
|
20
52
|
|
|
53
|
+
# @param value [Float] Longitude value
|
|
21
54
|
def lng=(value)
|
|
22
55
|
@latlng ||= [nil, nil]
|
|
23
56
|
@latlng[1] = value
|
|
24
57
|
end
|
|
25
58
|
|
|
59
|
+
#
|
|
60
|
+
# Compare with another LatLng or Array.
|
|
61
|
+
#
|
|
62
|
+
# @param other [LatLng, Array] Object to compare with
|
|
63
|
+
# @return [Boolean] true if coordinates are equal
|
|
64
|
+
#
|
|
26
65
|
def ==(other)
|
|
27
66
|
case other
|
|
28
67
|
when LatLng
|
|
@@ -34,6 +73,7 @@ module Strava
|
|
|
34
73
|
end
|
|
35
74
|
end
|
|
36
75
|
|
|
76
|
+
# @return [Array<Float>] Coordinates as array [latitude, longitude]
|
|
37
77
|
def to_a
|
|
38
78
|
@latlng
|
|
39
79
|
end
|
|
@@ -41,19 +81,17 @@ module Strava
|
|
|
41
81
|
alias to_h to_a
|
|
42
82
|
alias as_json to_a
|
|
43
83
|
|
|
84
|
+
# @return [String] JSON representation
|
|
44
85
|
def to_json(*args)
|
|
45
86
|
as_json.to_json(args)
|
|
46
87
|
end
|
|
47
88
|
|
|
89
|
+
# @return [String] String representation of coordinates
|
|
48
90
|
def inspect
|
|
49
91
|
@latlng.inspect
|
|
50
92
|
end
|
|
51
93
|
|
|
52
94
|
alias to_s inspect
|
|
53
|
-
|
|
54
|
-
def initialize(latlng = nil)
|
|
55
|
-
@latlng = latlng
|
|
56
|
-
end
|
|
57
95
|
end
|
|
58
96
|
end
|
|
59
97
|
end
|
|
@@ -2,14 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents Local Legend status on a segment.
|
|
7
|
+
#
|
|
8
|
+
# Local Legends are athletes with the most efforts on a segment in the last 90 days.
|
|
9
|
+
# This model contains information about the current local legend for a segment.
|
|
10
|
+
# This model is not documented in the official Strava API reference.
|
|
11
|
+
#
|
|
12
|
+
# @note This model is not documented by Strava API documentation. Properties
|
|
13
|
+
# are inferred from API responses.
|
|
14
|
+
#
|
|
15
|
+
# @see Strava::Models::DetailedSegment
|
|
16
|
+
#
|
|
17
|
+
# @example Accessing local legend information
|
|
18
|
+
# segment = client.segment(1234567)
|
|
19
|
+
# if segment.local_legend
|
|
20
|
+
# legend = segment.local_legend
|
|
21
|
+
# puts "Local Legend: #{legend.title}"
|
|
22
|
+
# puts "Athlete ID: #{legend.athlete_id}"
|
|
23
|
+
# puts "#{legend.effort_description} (#{legend.effort_count} efforts)"
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
6
26
|
class LocalLegend < Strava::Models::Response
|
|
27
|
+
# @return [Integer, nil] ID of the athlete who is the local legend
|
|
28
|
+
# @note Not documented by Strava API
|
|
7
29
|
property 'athlete_id'
|
|
30
|
+
|
|
31
|
+
# @return [String, nil] Title or name of the local legend
|
|
32
|
+
# @note Not documented by Strava API
|
|
8
33
|
property 'title'
|
|
34
|
+
|
|
35
|
+
# @return [String, nil] URL to the athlete's profile picture
|
|
36
|
+
# @note Not documented by Strava API
|
|
9
37
|
property 'profile'
|
|
38
|
+
|
|
39
|
+
# @return [String, nil] Description of the effort count (e.g., "X efforts in the last 90 days")
|
|
40
|
+
# @note Not documented by Strava API
|
|
10
41
|
property 'effort_description'
|
|
42
|
+
|
|
43
|
+
# @return [Integer, nil] Number of efforts by this athlete in the qualifying period
|
|
44
|
+
# @note Not documented by Strava API
|
|
11
45
|
property 'effort_count'
|
|
46
|
+
|
|
47
|
+
# @return [Hash, nil] Detailed effort count data
|
|
48
|
+
# @note Not documented by Strava API
|
|
12
49
|
property 'effort_counts'
|
|
50
|
+
|
|
51
|
+
# @return [Destination, nil] Link to related resource
|
|
52
|
+
# @note Not documented by Strava API
|
|
13
53
|
property 'destination'
|
|
14
54
|
end
|
|
15
55
|
end
|
data/lib/strava/models/map.rb
CHANGED
|
@@ -2,10 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
+
#
|
|
6
|
+
# Represents a map with polyline data for an activity, route, or segment.
|
|
7
|
+
#
|
|
8
|
+
# Maps contain encoded polyline data that represents the geographic path.
|
|
9
|
+
# The polyline format uses Google's encoded polyline algorithm which can
|
|
10
|
+
# be decoded using libraries like the 'polylines' gem.
|
|
11
|
+
#
|
|
12
|
+
# @example Decode and use polyline data
|
|
13
|
+
# require 'polylines'
|
|
14
|
+
#
|
|
15
|
+
# activity = client.activity(1234567890)
|
|
16
|
+
# map = activity.map
|
|
17
|
+
#
|
|
18
|
+
# # Decode the summary polyline
|
|
19
|
+
# decoded = Polylines::Decoder.decode_polyline(map.summary_polyline)
|
|
20
|
+
# start_point = decoded.first # [latitude, longitude]
|
|
21
|
+
# end_point = decoded.last
|
|
22
|
+
#
|
|
23
|
+
# # Use with Google Maps Static API
|
|
24
|
+
# url = "https://maps.googleapis.com/maps/api/staticmap?" \
|
|
25
|
+
# "path=enc:#{CGI.escape(map.summary_polyline)}&size=800x800"
|
|
26
|
+
#
|
|
27
|
+
# @see https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
|
28
|
+
#
|
|
5
29
|
class Map < Strava::Models::Response
|
|
30
|
+
# @return [String] Map identifier
|
|
6
31
|
property 'id'
|
|
32
|
+
|
|
33
|
+
# @return [String] Google polyline encoding of the route (lower resolution)
|
|
7
34
|
property 'summary_polyline'
|
|
35
|
+
|
|
36
|
+
# @return [Integer] Resource state indicator
|
|
8
37
|
property 'resource_state'
|
|
38
|
+
|
|
39
|
+
# @return [String] Google polyline encoding of the route (higher resolution)
|
|
9
40
|
property 'polyline'
|
|
10
41
|
end
|
|
11
42
|
end
|
|
@@ -2,11 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents minimal activity information (meta level).
|
|
7
|
+
#
|
|
8
|
+
# Meta models contain only essential identifying information.
|
|
9
|
+
# Used in contexts where only basic activity reference is needed.
|
|
10
|
+
#
|
|
11
|
+
# @see SummaryActivity
|
|
12
|
+
# @see DetailedActivity
|
|
13
|
+
# @see https://developers.strava.com/docs/reference/#api-models-MetaActivity
|
|
14
|
+
#
|
|
6
15
|
class MetaActivity < Strava::Models::Response
|
|
16
|
+
# @return [Integer] Activity identifier
|
|
7
17
|
property 'id'
|
|
8
|
-
|
|
18
|
+
|
|
19
|
+
# @return [Integer] Resource state indicator (1=meta)
|
|
9
20
|
property 'resource_state'
|
|
21
|
+
|
|
22
|
+
# @return [String] Activity visibility (e.g., "everyone", "followers_only", "only_me")
|
|
10
23
|
property 'visibility'
|
|
11
24
|
end
|
|
12
25
|
end
|
|
@@ -2,12 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents minimal athlete information (meta level).
|
|
7
|
+
#
|
|
8
|
+
# Meta models contain only essential identifying information without
|
|
9
|
+
# detailed data. Used in contexts where only basic athlete reference is needed.
|
|
10
|
+
#
|
|
11
|
+
# @see SummaryAthlete
|
|
12
|
+
# @see DetailedAthlete
|
|
13
|
+
# @see https://developers.strava.com/docs/reference/#api-models-MetaAthlete
|
|
14
|
+
#
|
|
6
15
|
class MetaAthlete < Strava::Models::Response
|
|
16
|
+
# @return [Integer, nil] Athlete identifier (may be nil for privacy)
|
|
7
17
|
property 'id'
|
|
8
|
-
|
|
18
|
+
|
|
19
|
+
# @return [Integer] Resource state indicator (1=meta)
|
|
9
20
|
property 'resource_state'
|
|
21
|
+
|
|
22
|
+
# @return [String, nil] Athlete's first name
|
|
10
23
|
property 'firstname'
|
|
24
|
+
|
|
25
|
+
# @return [String, nil] Athlete's last name
|
|
11
26
|
property 'lastname'
|
|
12
27
|
end
|
|
13
28
|
end
|
|
@@ -2,10 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents minimal club information (meta level).
|
|
7
|
+
#
|
|
8
|
+
# Meta models contain only essential identifying information.
|
|
9
|
+
# Used in contexts where only basic club reference is needed.
|
|
10
|
+
#
|
|
11
|
+
# @see SummaryClub
|
|
12
|
+
# @see DetailedClub
|
|
13
|
+
# @see https://developers.strava.com/docs/reference/#api-models-MetaClub
|
|
14
|
+
#
|
|
6
15
|
class MetaClub < Strava::Models::Response
|
|
16
|
+
# @return [Integer] Club identifier
|
|
7
17
|
property 'id'
|
|
18
|
+
|
|
19
|
+
# @return [Integer] Resource state indicator (1=meta)
|
|
8
20
|
property 'resource_state'
|
|
21
|
+
|
|
22
|
+
# @return [String] Club name
|
|
9
23
|
property 'name'
|
|
10
24
|
end
|
|
11
25
|
end
|
|
@@ -3,54 +3,132 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides average speed and pace conversion methods.
|
|
8
|
+
#
|
|
9
|
+
# This mixin adds the average_speed property (stored in meters per second)
|
|
10
|
+
# and provides helper methods to convert it to various speed and pace formats.
|
|
11
|
+
# Pace is the inverse of speed (time per distance) and is commonly used for running.
|
|
12
|
+
#
|
|
13
|
+
# @example Using speed and pace helpers
|
|
14
|
+
# activity = client.activity(1234567890)
|
|
15
|
+
# puts activity.average_speed # => 3.5 (m/s)
|
|
16
|
+
# puts activity.average_speed_s # => "12.6km/h"
|
|
17
|
+
# puts activity.average_speed_miles_per_hour_s # => "7.8mph"
|
|
18
|
+
# puts activity.pace_per_kilometer_s # => "4m45s/km"
|
|
19
|
+
# puts activity.pace_per_mile_s # => "7m40s/mi"
|
|
20
|
+
#
|
|
6
21
|
module AverageSpeed
|
|
7
22
|
extend ActiveSupport::Concern
|
|
8
23
|
|
|
9
24
|
included do
|
|
25
|
+
# @return [Float] Average speed in meters per second
|
|
10
26
|
property 'average_speed'
|
|
11
27
|
end
|
|
12
28
|
|
|
13
|
-
#
|
|
29
|
+
#
|
|
30
|
+
# Returns average speed in meters per second (same as average_speed).
|
|
31
|
+
#
|
|
32
|
+
# @return [Float] Average speed in m/s
|
|
33
|
+
#
|
|
34
|
+
# @note Always in meters per second, even in imperial splits
|
|
35
|
+
#
|
|
14
36
|
def average_speed_meters_per_second
|
|
15
37
|
average_speed
|
|
16
38
|
end
|
|
17
39
|
|
|
40
|
+
#
|
|
41
|
+
# Returns pace per mile.
|
|
42
|
+
#
|
|
43
|
+
# @return [String, nil] Pace formatted as "Xm%Ys/mi" (e.g., "7m30s/mi")
|
|
44
|
+
#
|
|
18
45
|
def pace_per_mile_s
|
|
19
46
|
convert_meters_per_second_to_pace average_speed, :mi
|
|
20
47
|
end
|
|
21
48
|
|
|
49
|
+
#
|
|
50
|
+
# Returns pace per 100 yards (swimming).
|
|
51
|
+
#
|
|
52
|
+
# @return [String, nil] Pace formatted as "XmYs/100yd"
|
|
53
|
+
#
|
|
22
54
|
def pace_per_100_yards_s
|
|
23
55
|
convert_meters_per_second_to_pace average_speed, :'100yd'
|
|
24
56
|
end
|
|
25
57
|
|
|
58
|
+
#
|
|
59
|
+
# Returns pace per 100 meters (swimming).
|
|
60
|
+
#
|
|
61
|
+
# @return [String, nil] Pace formatted as "XmYs/100m"
|
|
62
|
+
#
|
|
26
63
|
def pace_per_100_meters_s
|
|
27
64
|
convert_meters_per_second_to_pace average_speed, :'100m'
|
|
28
65
|
end
|
|
29
66
|
|
|
67
|
+
#
|
|
68
|
+
# Returns pace per kilometer.
|
|
69
|
+
#
|
|
70
|
+
# @return [String, nil] Pace formatted as "XmYs/km" (e.g., "4m30s/km")
|
|
71
|
+
#
|
|
30
72
|
def pace_per_kilometer_s
|
|
31
73
|
convert_meters_per_second_to_pace average_speed, :km
|
|
32
74
|
end
|
|
33
75
|
|
|
76
|
+
#
|
|
77
|
+
# Returns average speed in kilometers per hour.
|
|
78
|
+
#
|
|
79
|
+
# @return [String, nil] Speed formatted as "X.Xkm/h"
|
|
80
|
+
#
|
|
34
81
|
def average_speed_kilometer_per_hour_s
|
|
35
82
|
return unless average_speed&.positive?
|
|
36
83
|
|
|
37
84
|
format('%.1fkm/h', average_speed * 3.6)
|
|
38
85
|
end
|
|
39
86
|
|
|
87
|
+
#
|
|
88
|
+
# Returns average speed in miles per hour.
|
|
89
|
+
#
|
|
90
|
+
# @return [String, nil] Speed formatted as "X.Xmph"
|
|
91
|
+
#
|
|
40
92
|
def average_speed_miles_per_hour_s
|
|
41
93
|
return unless average_speed&.positive?
|
|
42
94
|
|
|
43
95
|
format('%.1fmph', average_speed * 2.23694)
|
|
44
96
|
end
|
|
45
97
|
|
|
98
|
+
#
|
|
99
|
+
# Returns default formatted average speed (kilometers per hour).
|
|
100
|
+
#
|
|
101
|
+
# @return [String, nil] Speed formatted as "X.Xkm/h"
|
|
102
|
+
#
|
|
46
103
|
def average_speed_s
|
|
47
104
|
average_speed_kilometer_per_hour_s
|
|
48
105
|
end
|
|
49
106
|
|
|
107
|
+
#
|
|
108
|
+
# Returns default formatted pace (per kilometer).
|
|
109
|
+
#
|
|
110
|
+
# @return [String, nil] Pace formatted as "XmYs/km"
|
|
111
|
+
#
|
|
112
|
+
def pace_s
|
|
113
|
+
pace_per_kilometer_s
|
|
114
|
+
end
|
|
115
|
+
|
|
50
116
|
private
|
|
51
117
|
|
|
52
|
-
#
|
|
53
|
-
#
|
|
118
|
+
#
|
|
119
|
+
# Converts speed in meters per second to pace (time per distance).
|
|
120
|
+
#
|
|
121
|
+
# Pace is calculated as the inverse of speed. For example, running at 3.33 m/s
|
|
122
|
+
# equals a 5:00/km pace (1000m / 3.33m/s = 300 seconds = 5 minutes).
|
|
123
|
+
#
|
|
124
|
+
# @param speed [Float, nil] Speed in meters per second
|
|
125
|
+
# @param unit [Symbol] Unit for pace calculation (:mi, :km, :'100yd', :'100m')
|
|
126
|
+
# @return [String, nil] Formatted pace string or nil if speed is nil/zero
|
|
127
|
+
#
|
|
128
|
+
# @see http://yizeng.me/2017/02/25/convert-speed-to-pace-programmatically-using-ruby
|
|
129
|
+
#
|
|
130
|
+
# @api private
|
|
131
|
+
#
|
|
54
132
|
def convert_meters_per_second_to_pace(speed, unit = :mi)
|
|
55
133
|
return unless speed&.positive?
|
|
56
134
|
|
|
@@ -3,57 +3,82 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides distance conversion and formatting methods.
|
|
8
|
+
#
|
|
9
|
+
# This mixin is included in models that have a distance property, such as
|
|
10
|
+
# activities, laps, segments, and routes. It provides helper methods to
|
|
11
|
+
# convert and format distances in various units.
|
|
12
|
+
#
|
|
13
|
+
# @example Using distance helpers
|
|
14
|
+
# activity = client.activity(1234567890)
|
|
15
|
+
# puts activity.distance # => 10000.0 (meters)
|
|
16
|
+
# puts activity.distance_s # => "10.0km"
|
|
17
|
+
# puts activity.distance_in_miles_s # => "6.21mi"
|
|
18
|
+
# puts activity.distance_in_yards_s # => "10936.1yd"
|
|
19
|
+
#
|
|
6
20
|
module Distance
|
|
7
21
|
extend ActiveSupport::Concern
|
|
8
22
|
|
|
9
23
|
included do
|
|
24
|
+
# @return [Float] Distance in meters
|
|
10
25
|
property 'distance'
|
|
11
26
|
end
|
|
12
27
|
|
|
28
|
+
# @return [Float] Distance in meters
|
|
13
29
|
def distance_in_meters
|
|
14
30
|
distance
|
|
15
31
|
end
|
|
16
32
|
|
|
33
|
+
# @return [Float] Distance in feet
|
|
17
34
|
def distance_in_feet
|
|
18
35
|
distance * 3.28084
|
|
19
36
|
end
|
|
20
37
|
|
|
38
|
+
# @return [Float] Distance in miles
|
|
21
39
|
def distance_in_miles
|
|
22
40
|
distance_in_meters * 0.00062137
|
|
23
41
|
end
|
|
24
42
|
|
|
43
|
+
# @return [String, nil] Formatted distance in miles (e.g., "6.21mi")
|
|
25
44
|
def distance_in_miles_s
|
|
26
45
|
return unless distance&.positive?
|
|
27
46
|
|
|
28
47
|
format('%gmi', format('%.2f', distance_in_miles))
|
|
29
48
|
end
|
|
30
49
|
|
|
50
|
+
# @return [Float] Distance in yards
|
|
31
51
|
def distance_in_yards
|
|
32
52
|
distance_in_meters * 1.09361
|
|
33
53
|
end
|
|
34
54
|
|
|
55
|
+
# @return [String, nil] Formatted distance in yards (e.g., "10936.1yd")
|
|
35
56
|
def distance_in_yards_s
|
|
36
57
|
return unless distance&.positive?
|
|
37
58
|
|
|
38
59
|
format('%gyd', format('%.1f', distance_in_yards))
|
|
39
60
|
end
|
|
40
61
|
|
|
62
|
+
# @return [String, nil] Formatted distance in meters (e.g., "10000m")
|
|
41
63
|
def distance_in_meters_s
|
|
42
64
|
return unless distance&.positive?
|
|
43
65
|
|
|
44
66
|
format('%gm', format('%d', distance_in_meters))
|
|
45
67
|
end
|
|
46
68
|
|
|
69
|
+
# @return [Float] Distance in kilometers
|
|
47
70
|
def distance_in_kilometers
|
|
48
71
|
distance_in_meters / 1000
|
|
49
72
|
end
|
|
50
73
|
|
|
74
|
+
# @return [String, nil] Formatted distance in kilometers (e.g., "10.0km")
|
|
51
75
|
def distance_in_kilometers_s
|
|
52
76
|
return unless distance&.positive?
|
|
53
77
|
|
|
54
78
|
format('%gkm', format('%.2f', distance_in_kilometers))
|
|
55
79
|
end
|
|
56
80
|
|
|
81
|
+
# @return [String, nil] Default formatted distance (same as distance_in_kilometers_s)
|
|
57
82
|
def distance_s
|
|
58
83
|
distance_in_kilometers_s
|
|
59
84
|
end
|
|
@@ -3,14 +3,32 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides elapsed time formatting methods.
|
|
8
|
+
#
|
|
9
|
+
# Elapsed time is the total time from start to finish of an activity, including
|
|
10
|
+
# stopped/paused time. This mixin adds the elapsed_time property and a helper
|
|
11
|
+
# method to format it as hours/minutes/seconds.
|
|
12
|
+
#
|
|
13
|
+
# @example Using elapsed time helpers
|
|
14
|
+
# activity = client.activity(1234567890)
|
|
15
|
+
# puts activity.elapsed_time # => 4200 (seconds)
|
|
16
|
+
# puts activity.elapsed_time_in_hours_s # => "1h10m"
|
|
17
|
+
#
|
|
6
18
|
module ElapsedTime
|
|
7
19
|
extend ActiveSupport::Concern
|
|
8
20
|
include TimeInHours
|
|
9
21
|
|
|
10
22
|
included do
|
|
23
|
+
# @return [Integer] Total elapsed time in seconds (includes stopped time)
|
|
11
24
|
property 'elapsed_time'
|
|
12
25
|
end
|
|
13
26
|
|
|
27
|
+
#
|
|
28
|
+
# Returns formatted elapsed time as hours, minutes, and seconds.
|
|
29
|
+
#
|
|
30
|
+
# @return [String, nil] Formatted time string (e.g., "1h23m45s", "45m30s", "30s")
|
|
31
|
+
#
|
|
14
32
|
def elapsed_time_in_hours_s
|
|
15
33
|
time_in_hours_s elapsed_time
|
|
16
34
|
end
|
|
@@ -3,33 +3,75 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides elevation difference conversion and formatting methods.
|
|
8
|
+
#
|
|
9
|
+
# Elevation difference represents the net elevation change (can be positive
|
|
10
|
+
# or negative) for a split or segment. This differs from elevation_gain which
|
|
11
|
+
# only counts upward movement.
|
|
12
|
+
#
|
|
13
|
+
# This mixin adds the elevation_difference property and helper methods to
|
|
14
|
+
# convert and format it in meters or feet.
|
|
15
|
+
#
|
|
16
|
+
# @example Using elevation difference helpers
|
|
17
|
+
# split = activity.splits_metric.first
|
|
18
|
+
# puts split.elevation_difference # => -15.2 (meters, downhill)
|
|
19
|
+
# puts split.elevation_difference_s # => "-15.2m"
|
|
20
|
+
# puts split.elevation_difference_in_feet_s # => "-49.9ft"
|
|
21
|
+
#
|
|
6
22
|
module ElevationDifference
|
|
7
23
|
extend ActiveSupport::Concern
|
|
8
24
|
|
|
9
25
|
included do
|
|
26
|
+
# @return [Float] Net elevation difference in meters (positive = uphill, negative = downhill)
|
|
10
27
|
property 'elevation_difference'
|
|
11
28
|
end
|
|
12
29
|
|
|
30
|
+
#
|
|
31
|
+
# Returns elevation difference in feet.
|
|
32
|
+
#
|
|
33
|
+
# @return [Float] Elevation difference in feet
|
|
34
|
+
#
|
|
13
35
|
def elevation_difference_in_feet
|
|
14
36
|
elevation_difference * 3.28084
|
|
15
37
|
end
|
|
16
38
|
|
|
39
|
+
#
|
|
40
|
+
# Returns elevation difference in meters (same as elevation_difference).
|
|
41
|
+
#
|
|
42
|
+
# @return [Float] Elevation difference in meters
|
|
43
|
+
#
|
|
17
44
|
def elevation_difference_in_meters
|
|
18
45
|
elevation_difference
|
|
19
46
|
end
|
|
20
47
|
|
|
48
|
+
#
|
|
49
|
+
# Returns formatted elevation difference in meters.
|
|
50
|
+
#
|
|
51
|
+
# @return [String, nil] Formatted elevation (e.g., "15.2m" or "-15.2m")
|
|
52
|
+
#
|
|
21
53
|
def elevation_difference_in_meters_s
|
|
22
54
|
return if elevation_difference.nil?
|
|
23
55
|
|
|
24
56
|
format('%gm', format('%.1f', elevation_difference_in_meters))
|
|
25
57
|
end
|
|
26
58
|
|
|
59
|
+
#
|
|
60
|
+
# Returns formatted elevation difference in feet.
|
|
61
|
+
#
|
|
62
|
+
# @return [String, nil] Formatted elevation (e.g., "49.9ft" or "-49.9ft")
|
|
63
|
+
#
|
|
27
64
|
def elevation_difference_in_feet_s
|
|
28
65
|
return if elevation_difference.nil?
|
|
29
66
|
|
|
30
67
|
format('%gft', format('%.1f', elevation_difference_in_feet))
|
|
31
68
|
end
|
|
32
69
|
|
|
70
|
+
#
|
|
71
|
+
# Returns default formatted elevation difference (meters).
|
|
72
|
+
#
|
|
73
|
+
# @return [String, nil] Formatted elevation (e.g., "15.2m" or "-15.2m")
|
|
74
|
+
#
|
|
33
75
|
def elevation_difference_s
|
|
34
76
|
elevation_difference_in_meters_s
|
|
35
77
|
end
|
|
@@ -3,33 +3,72 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides elevation gain conversion and formatting methods.
|
|
8
|
+
#
|
|
9
|
+
# Elevation gain represents the total upward elevation change during an activity.
|
|
10
|
+
# This mixin adds the elevation_gain property and helper methods to convert
|
|
11
|
+
# and format it in meters or feet.
|
|
12
|
+
#
|
|
13
|
+
# @example Using elevation gain helpers
|
|
14
|
+
# route = client.route(1234567)
|
|
15
|
+
# puts route.elevation_gain # => 450.5 (meters)
|
|
16
|
+
# puts route.elevation_gain_s # => "450.5m"
|
|
17
|
+
# puts route.elevation_gain_in_feet_s # => "1478.0ft"
|
|
18
|
+
#
|
|
6
19
|
module ElevationGain
|
|
7
20
|
extend ActiveSupport::Concern
|
|
8
21
|
|
|
9
22
|
included do
|
|
23
|
+
# @return [Float] Elevation gain in meters
|
|
10
24
|
property 'elevation_gain'
|
|
11
25
|
end
|
|
12
26
|
|
|
27
|
+
#
|
|
28
|
+
# Returns elevation gain in feet.
|
|
29
|
+
#
|
|
30
|
+
# @return [Float] Elevation gain in feet
|
|
31
|
+
#
|
|
13
32
|
def elevation_gain_in_feet
|
|
14
33
|
elevation_gain * 3.28084
|
|
15
34
|
end
|
|
16
35
|
|
|
36
|
+
#
|
|
37
|
+
# Returns elevation gain in meters (same as elevation_gain).
|
|
38
|
+
#
|
|
39
|
+
# @return [Float] Elevation gain in meters
|
|
40
|
+
#
|
|
17
41
|
def elevation_gain_in_meters
|
|
18
42
|
elevation_gain
|
|
19
43
|
end
|
|
20
44
|
|
|
45
|
+
#
|
|
46
|
+
# Returns formatted elevation gain in meters.
|
|
47
|
+
#
|
|
48
|
+
# @return [String, nil] Formatted elevation (e.g., "450.5m")
|
|
49
|
+
#
|
|
21
50
|
def elevation_gain_in_meters_s
|
|
22
51
|
return if elevation_gain.nil?
|
|
23
52
|
|
|
24
53
|
format('%gm', format('%.1f', elevation_gain_in_meters))
|
|
25
54
|
end
|
|
26
55
|
|
|
56
|
+
#
|
|
57
|
+
# Returns formatted elevation gain in feet.
|
|
58
|
+
#
|
|
59
|
+
# @return [String, nil] Formatted elevation (e.g., "1478.0ft")
|
|
60
|
+
#
|
|
27
61
|
def elevation_gain_in_feet_s
|
|
28
62
|
return if elevation_gain.nil?
|
|
29
63
|
|
|
30
64
|
format('%gft', format('%.1f', elevation_gain_in_feet))
|
|
31
65
|
end
|
|
32
66
|
|
|
67
|
+
#
|
|
68
|
+
# Returns default formatted elevation gain (meters).
|
|
69
|
+
#
|
|
70
|
+
# @return [String, nil] Formatted elevation (e.g., "450.5m")
|
|
71
|
+
#
|
|
33
72
|
def elevation_gain_s
|
|
34
73
|
elevation_gain_in_meters_s
|
|
35
74
|
end
|