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
|
@@ -3,14 +3,32 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides estimated moving time formatting methods.
|
|
8
|
+
#
|
|
9
|
+
# Estimated moving time is Strava's prediction of how long it will take
|
|
10
|
+
# to complete a route based on distance, elevation, and typical speeds.
|
|
11
|
+
# This is commonly used for routes.
|
|
12
|
+
#
|
|
13
|
+
# @example Using estimated moving time helpers
|
|
14
|
+
# route = client.route(1234567)
|
|
15
|
+
# puts route.estimated_moving_time # => 5400 (seconds)
|
|
16
|
+
# puts route.estimated_moving_time_in_hours_s # => "1h30m"
|
|
17
|
+
#
|
|
6
18
|
module EstimatedMovingTime
|
|
7
19
|
extend ActiveSupport::Concern
|
|
8
20
|
include TimeInHours
|
|
9
21
|
|
|
10
22
|
included do
|
|
23
|
+
# @return [Integer] Estimated moving time in seconds
|
|
11
24
|
property 'estimated_moving_time'
|
|
12
25
|
end
|
|
13
26
|
|
|
27
|
+
#
|
|
28
|
+
# Returns formatted estimated moving time as hours, minutes, and seconds.
|
|
29
|
+
#
|
|
30
|
+
# @return [String, nil] Formatted time string (e.g., "1h23m45s", "45m30s", "30s")
|
|
31
|
+
#
|
|
14
32
|
def estimated_moving_time_in_hours_s
|
|
15
33
|
time_in_hours_s estimated_moving_time
|
|
16
34
|
end
|
|
@@ -3,17 +3,53 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides access to HTTP response data and rate limit information.
|
|
8
|
+
#
|
|
9
|
+
# This mixin is included in Response (the base class for most API models)
|
|
10
|
+
# and provides access to the underlying HTTP response, which contains
|
|
11
|
+
# important metadata like rate limit information.
|
|
12
|
+
#
|
|
13
|
+
# @example Checking rate limits
|
|
14
|
+
# activity = client.activity(1234567890)
|
|
15
|
+
# ratelimit = activity.http_response.ratelimit
|
|
16
|
+
#
|
|
17
|
+
# puts "15-min limit: #{ratelimit.fifteen_minutes_limit}"
|
|
18
|
+
# puts "15-min used: #{ratelimit.fifteen_minutes_usage}"
|
|
19
|
+
# puts "15-min remaining: #{ratelimit.fifteen_minutes_remaining}"
|
|
20
|
+
#
|
|
21
|
+
# puts "Daily limit: #{ratelimit.daily_limit}"
|
|
22
|
+
# puts "Daily used: #{ratelimit.daily_usage}"
|
|
23
|
+
# puts "Daily remaining: #{ratelimit.daily_remaining}"
|
|
24
|
+
#
|
|
25
|
+
# @see Strava::Web::ApiResponse
|
|
26
|
+
# @see Strava::Api::Ratelimit
|
|
27
|
+
#
|
|
6
28
|
module HttpResponse
|
|
7
29
|
extend ActiveSupport::Concern
|
|
8
30
|
|
|
9
31
|
included do
|
|
32
|
+
# @return [Hash] Raw input data including HTTP response
|
|
33
|
+
# @api private
|
|
10
34
|
attr_reader :input
|
|
11
35
|
|
|
36
|
+
#
|
|
37
|
+
# Initializes the model with input data.
|
|
38
|
+
#
|
|
39
|
+
# @param obj [Hash] Input data including 'http_response' key
|
|
40
|
+
#
|
|
41
|
+
# @api private
|
|
42
|
+
#
|
|
12
43
|
def initialize(obj)
|
|
13
44
|
@input = obj
|
|
14
45
|
super
|
|
15
46
|
end
|
|
16
47
|
|
|
48
|
+
#
|
|
49
|
+
# Returns the HTTP response wrapper with rate limit information.
|
|
50
|
+
#
|
|
51
|
+
# @return [Strava::Web::ApiResponse] API response wrapper
|
|
52
|
+
#
|
|
17
53
|
def http_response
|
|
18
54
|
@http_response ||= Strava::Web::ApiResponse.new(input['http_response'])
|
|
19
55
|
end
|
|
@@ -3,14 +3,32 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides moving time formatting methods.
|
|
8
|
+
#
|
|
9
|
+
# Moving time is the time spent actually moving during an activity, excluding
|
|
10
|
+
# stopped time. This mixin adds the moving_time property and a helper method
|
|
11
|
+
# to format it as hours/minutes/seconds.
|
|
12
|
+
#
|
|
13
|
+
# @example Using moving time helpers
|
|
14
|
+
# activity = client.activity(1234567890)
|
|
15
|
+
# puts activity.moving_time # => 3665 (seconds)
|
|
16
|
+
# puts activity.moving_time_in_hours_s # => "1h1m5s"
|
|
17
|
+
#
|
|
6
18
|
module MovingTime
|
|
7
19
|
extend ActiveSupport::Concern
|
|
8
20
|
include TimeInHours
|
|
9
21
|
|
|
10
22
|
included do
|
|
23
|
+
# @return [Integer] Moving time in seconds (excludes stopped time)
|
|
11
24
|
property 'moving_time'
|
|
12
25
|
end
|
|
13
26
|
|
|
27
|
+
#
|
|
28
|
+
# Returns formatted moving time as hours, minutes, and seconds.
|
|
29
|
+
#
|
|
30
|
+
# @return [String, nil] Formatted time string (e.g., "1h23m45s", "45m30s", "30s")
|
|
31
|
+
#
|
|
14
32
|
def moving_time_in_hours_s
|
|
15
33
|
time_in_hours_s moving_time
|
|
16
34
|
end
|
|
@@ -3,14 +3,39 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides sport type handling and sport-specific formatting.
|
|
8
|
+
#
|
|
9
|
+
# This mixin adds the sport_type property and provides sport-aware formatting
|
|
10
|
+
# for distance and pace. For example, swimming activities display distance in
|
|
11
|
+
# meters and pace per 100m, while other activities use kilometers and pace per km.
|
|
12
|
+
#
|
|
13
|
+
# Also provides emoji representations for various sport types.
|
|
14
|
+
#
|
|
15
|
+
# @example Using sport type helpers
|
|
16
|
+
# activity = client.activity(1234567890)
|
|
17
|
+
# puts activity.sport_type # => "Run"
|
|
18
|
+
# puts activity.distance_s # => "10.0km" (or "500m" for swim)
|
|
19
|
+
# puts activity.pace_s # => "4m30s/km" (or "1m20s/100m" for swim)
|
|
20
|
+
# puts activity.sport_type_emoji # => "🏃"
|
|
21
|
+
#
|
|
6
22
|
module SportType
|
|
7
23
|
extend ActiveSupport::Concern
|
|
8
24
|
|
|
9
25
|
included do
|
|
10
|
-
#
|
|
26
|
+
# @return [String] Activity sport type (e.g., "Run", "Ride", "Swim", "Hike")
|
|
27
|
+
# @note This replaces the deprecated 'type' property
|
|
11
28
|
property 'sport_type'
|
|
12
29
|
end
|
|
13
30
|
|
|
31
|
+
#
|
|
32
|
+
# Returns distance formatted appropriately for the sport type.
|
|
33
|
+
#
|
|
34
|
+
# Swimming activities display distance in meters, while all other
|
|
35
|
+
# activities use kilometers.
|
|
36
|
+
#
|
|
37
|
+
# @return [String, nil] Formatted distance
|
|
38
|
+
#
|
|
14
39
|
def distance_s
|
|
15
40
|
if sport_type == 'Swim'
|
|
16
41
|
distance_in_meters_s
|
|
@@ -19,6 +44,14 @@ module Strava
|
|
|
19
44
|
end
|
|
20
45
|
end
|
|
21
46
|
|
|
47
|
+
#
|
|
48
|
+
# Returns pace formatted appropriately for the sport type.
|
|
49
|
+
#
|
|
50
|
+
# Swimming activities display pace per 100 meters, while all other
|
|
51
|
+
# activities use pace per kilometer.
|
|
52
|
+
#
|
|
53
|
+
# @return [String, nil] Formatted pace
|
|
54
|
+
#
|
|
22
55
|
def pace_s
|
|
23
56
|
case sport_type
|
|
24
57
|
when 'Swim'
|
|
@@ -28,6 +61,11 @@ module Strava
|
|
|
28
61
|
end
|
|
29
62
|
end
|
|
30
63
|
|
|
64
|
+
#
|
|
65
|
+
# Returns an emoji representing the sport type.
|
|
66
|
+
#
|
|
67
|
+
# @return [String, nil] Emoji character or nil if no emoji for this sport
|
|
68
|
+
#
|
|
31
69
|
def sport_type_emoji
|
|
32
70
|
case sport_type
|
|
33
71
|
when 'AlpineSki' then '⛷️'
|
|
@@ -3,16 +3,40 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides local start date/time with timezone handling.
|
|
8
|
+
#
|
|
9
|
+
# This mixin adds the start_date_local property and handles proper timezone
|
|
10
|
+
# conversion. The offset is calculated from the difference between start_date
|
|
11
|
+
# (UTC) and start_date_local, which correctly accounts for daylight saving
|
|
12
|
+
# time (unlike Strava's 'timezone' property, which only reflects the zone's
|
|
13
|
+
# standard GMT offset).
|
|
14
|
+
#
|
|
15
|
+
# This is particularly important for activities that cross timezone boundaries
|
|
16
|
+
# or for displaying times in the athlete's local timezone.
|
|
17
|
+
#
|
|
18
|
+
# @example Using local start date
|
|
19
|
+
# activity = client.activity(1234567890)
|
|
20
|
+
# puts activity.start_date # => 2024-01-15 14:30:00 UTC
|
|
21
|
+
# puts activity.start_date_local # => 2024-01-15 09:30:00 -0500
|
|
22
|
+
#
|
|
6
23
|
module StartDateLocal
|
|
7
24
|
extend ActiveSupport::Concern
|
|
8
25
|
|
|
9
26
|
included do
|
|
10
27
|
property 'start_date_local', transform_with: ->(v) { ::Time.parse(v) }
|
|
11
28
|
|
|
29
|
+
#
|
|
30
|
+
# Returns the start date/time in the local timezone.
|
|
31
|
+
#
|
|
32
|
+
# Constructs a Time object with the offset calculated from the difference
|
|
33
|
+
# between start_date and start_date_local.
|
|
34
|
+
#
|
|
35
|
+
# @return [Time] Start date/time with local timezone
|
|
36
|
+
#
|
|
12
37
|
def start_date_local
|
|
13
38
|
extracted_datetime = self['start_date_local']
|
|
14
|
-
|
|
15
|
-
timezone_shift = conditional_timezone(extracted_datetime)
|
|
39
|
+
timezone_shift = calculate_timezone(extracted_datetime)
|
|
16
40
|
::Time.new(extracted_datetime.year,
|
|
17
41
|
extracted_datetime.month,
|
|
18
42
|
extracted_datetime.day,
|
|
@@ -24,37 +48,29 @@ module Strava
|
|
|
24
48
|
|
|
25
49
|
private
|
|
26
50
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
#
|
|
52
|
+
# Determines the timezone offset for the start date.
|
|
53
|
+
#
|
|
54
|
+
# Calculates the offset from the difference between start_date (UTC)
|
|
55
|
+
# and start_date_local. This is used instead of Strava's 'timezone'
|
|
56
|
+
# property, which reflects the zone's standard GMT offset and does
|
|
57
|
+
# not account for daylight saving time.
|
|
58
|
+
#
|
|
59
|
+
# @param extracted_datetime [Time] The parsed start_date_local value
|
|
60
|
+
# @return [String] Timezone offset string (e.g., "-05:00")
|
|
61
|
+
#
|
|
62
|
+
# @api private
|
|
63
|
+
#
|
|
41
64
|
def calculate_timezone(extracted_datetime)
|
|
42
65
|
if start_date == extracted_datetime
|
|
43
66
|
timezone_diff_shift_string(0, '-')
|
|
44
67
|
elsif extracted_datetime < start_date
|
|
45
68
|
timezone_diff_shift_string((extracted_datetime - start_date), '-')
|
|
46
|
-
elsif extracted_datetime > start_date
|
|
47
|
-
timezone_diff_shift_string((extracted_datetime - start_date), '+')
|
|
48
69
|
else
|
|
49
|
-
|
|
70
|
+
timezone_diff_shift_string((extracted_datetime - start_date), '+')
|
|
50
71
|
end
|
|
51
72
|
end
|
|
52
73
|
|
|
53
|
-
def timezone_shift_string(operator)
|
|
54
|
-
diff_hours = timezone.split(operator).last.to_i
|
|
55
|
-
"#{operator}#{format_int_leading_zero(diff_hours)}:00"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
74
|
def timezone_diff_shift_string(time_diff, operator)
|
|
59
75
|
diff_hours = (time_diff.abs / 3600).to_i
|
|
60
76
|
"#{operator}#{format_int_leading_zero(diff_hours)}:00"
|
|
@@ -3,11 +3,34 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides time formatting helper methods.
|
|
8
|
+
#
|
|
9
|
+
# This is a utility mixin used by other time-related mixins (MovingTime, ElapsedTime, etc.)
|
|
10
|
+
# to format seconds into a human-readable hours/minutes/seconds string.
|
|
11
|
+
#
|
|
12
|
+
# @example Time formatting
|
|
13
|
+
# time_in_hours_s(3665) # => "1h1m5s"
|
|
14
|
+
# time_in_hours_s(125) # => "2m5s"
|
|
15
|
+
# time_in_hours_s(45) # => "45s"
|
|
16
|
+
# time_in_hours_s(7200) # => "2h"
|
|
17
|
+
#
|
|
6
18
|
module TimeInHours
|
|
7
19
|
extend ActiveSupport::Concern
|
|
8
20
|
|
|
9
21
|
private
|
|
10
22
|
|
|
23
|
+
#
|
|
24
|
+
# Converts time in seconds to formatted string with hours, minutes, and seconds.
|
|
25
|
+
#
|
|
26
|
+
# Only includes non-zero components. For example, if there are no hours,
|
|
27
|
+
# the result will be "23m45s" instead of "0h23m45s".
|
|
28
|
+
#
|
|
29
|
+
# @param time [Integer, nil] Time in seconds
|
|
30
|
+
# @return [String, nil] Formatted time string or nil if time is nil
|
|
31
|
+
#
|
|
32
|
+
# @api private
|
|
33
|
+
#
|
|
11
34
|
def time_in_hours_s(time)
|
|
12
35
|
return unless time
|
|
13
36
|
|
|
@@ -3,33 +3,75 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
5
|
module Mixins
|
|
6
|
+
#
|
|
7
|
+
# Provides total elevation gain conversion and formatting methods.
|
|
8
|
+
#
|
|
9
|
+
# Total elevation gain represents the cumulative upward elevation change
|
|
10
|
+
# during an activity. This is distinct from elevation_gain - this property
|
|
11
|
+
# is typically used for activities while elevation_gain is used for routes.
|
|
12
|
+
#
|
|
13
|
+
# This mixin adds the total_elevation_gain property and helper methods to
|
|
14
|
+
# convert and format it in meters or feet.
|
|
15
|
+
#
|
|
16
|
+
# @example Using total elevation gain helpers
|
|
17
|
+
# activity = client.activity(1234567890)
|
|
18
|
+
# puts activity.total_elevation_gain # => 725.3 (meters)
|
|
19
|
+
# puts activity.total_elevation_gain_s # => "725.3m"
|
|
20
|
+
# puts activity.total_elevation_gain_in_feet_s # => "2379.6ft"
|
|
21
|
+
#
|
|
6
22
|
module TotalElevationGain
|
|
7
23
|
extend ActiveSupport::Concern
|
|
8
24
|
|
|
9
25
|
included do
|
|
26
|
+
# @return [Float] Total elevation gain in meters
|
|
10
27
|
property 'total_elevation_gain'
|
|
11
28
|
end
|
|
12
29
|
|
|
30
|
+
#
|
|
31
|
+
# Returns total elevation gain in feet.
|
|
32
|
+
#
|
|
33
|
+
# @return [Float] Total elevation gain in feet
|
|
34
|
+
#
|
|
13
35
|
def total_elevation_gain_in_feet
|
|
14
36
|
total_elevation_gain * 3.28084
|
|
15
37
|
end
|
|
16
38
|
|
|
39
|
+
#
|
|
40
|
+
# Returns total elevation gain in meters (same as total_elevation_gain).
|
|
41
|
+
#
|
|
42
|
+
# @return [Float] Total elevation gain in meters
|
|
43
|
+
#
|
|
17
44
|
def total_elevation_gain_in_meters
|
|
18
45
|
total_elevation_gain
|
|
19
46
|
end
|
|
20
47
|
|
|
48
|
+
#
|
|
49
|
+
# Returns formatted total elevation gain in meters.
|
|
50
|
+
#
|
|
51
|
+
# @return [String, nil] Formatted elevation (e.g., "725.3m")
|
|
52
|
+
#
|
|
21
53
|
def total_elevation_gain_in_meters_s
|
|
22
54
|
return if total_elevation_gain.nil?
|
|
23
55
|
|
|
24
56
|
format('%gm', format('%.1f', total_elevation_gain_in_meters))
|
|
25
57
|
end
|
|
26
58
|
|
|
59
|
+
#
|
|
60
|
+
# Returns formatted total elevation gain in feet.
|
|
61
|
+
#
|
|
62
|
+
# @return [String, nil] Formatted elevation (e.g., "2379.6ft")
|
|
63
|
+
#
|
|
27
64
|
def total_elevation_gain_in_feet_s
|
|
28
65
|
return if total_elevation_gain.nil?
|
|
29
66
|
|
|
30
67
|
format('%gft', format('%.1f', total_elevation_gain_in_feet))
|
|
31
68
|
end
|
|
32
69
|
|
|
70
|
+
#
|
|
71
|
+
# Returns default formatted total elevation gain (meters).
|
|
72
|
+
#
|
|
73
|
+
# @return [String, nil] Formatted elevation (e.g., "725.3m")
|
|
74
|
+
#
|
|
33
75
|
def total_elevation_gain_s
|
|
34
76
|
total_elevation_gain_in_meters_s
|
|
35
77
|
end
|
data/lib/strava/models/model.rb
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
|
+
#
|
|
5
|
+
# Base model class for all Strava models.
|
|
6
|
+
#
|
|
7
|
+
# This class extends Hashie::Trash to provide a flexible data structure
|
|
8
|
+
# for Strava API responses. All model classes in the library inherit from this.
|
|
9
|
+
#
|
|
10
|
+
# Features:
|
|
11
|
+
# * Ignores undeclared properties from API responses
|
|
12
|
+
# * Provides hash-like access to properties
|
|
13
|
+
# * Supports property transformations
|
|
14
|
+
#
|
|
15
|
+
# @see Strava::Models::Response
|
|
16
|
+
# @see https://github.com/hashie/hashie
|
|
17
|
+
#
|
|
4
18
|
class Model < Hashie::Trash
|
|
5
19
|
include Hashie::Extensions::IgnoreUndeclared
|
|
6
20
|
end
|
|
@@ -2,10 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents summary photo information for an activity.
|
|
7
|
+
#
|
|
8
|
+
# Contains basic information about photos attached to an activity,
|
|
9
|
+
# including the count and primary photo reference.
|
|
10
|
+
#
|
|
11
|
+
# @see https://developers.strava.com/docs/reference/#api-models-PhotosSummary Strava API PhotosSummary reference
|
|
12
|
+
# @see Strava::Models::PhotosSummaryPrimary
|
|
13
|
+
# @see Strava::Models::SummaryActivity
|
|
14
|
+
#
|
|
15
|
+
# @example Accessing activity photo summary
|
|
16
|
+
# activity = client.activity(1234567890)
|
|
17
|
+
# if activity.photos && activity.photos.count > 0
|
|
18
|
+
# puts "This activity has #{activity.photos.count} photo(s)"
|
|
19
|
+
# if activity.photos.primary
|
|
20
|
+
# puts "Primary photo: #{activity.photos.primary.urls}"
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
6
24
|
class PhotosSummary < Strava::Models::Response
|
|
25
|
+
# @return [Integer] Total number of photos attached to the activity
|
|
7
26
|
property 'count'
|
|
8
|
-
|
|
27
|
+
|
|
28
|
+
# @return [Boolean, nil] Whether to use the primary photo for display
|
|
29
|
+
# @note Not documented by Strava API
|
|
30
|
+
property 'use_primary_photo'
|
|
31
|
+
|
|
32
|
+
# @return [PhotosSummaryPrimary, nil] The primary/featured photo reference
|
|
9
33
|
property 'primary', transform_with: ->(v) { Strava::Models::PhotosSummaryPrimary.new(v) }
|
|
10
34
|
end
|
|
11
35
|
end
|
|
@@ -2,13 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents the primary photo reference in a photos summary.
|
|
7
|
+
#
|
|
8
|
+
# Contains identification and URL information for the primary photo
|
|
9
|
+
# of an activity.
|
|
10
|
+
#
|
|
11
|
+
# @see https://developers.strava.com/docs/reference/#api-models-PhotosSummary_primary Strava API PhotosSummary_primary reference
|
|
12
|
+
# @see Strava::Models::PhotosSummary
|
|
13
|
+
#
|
|
14
|
+
# @example Accessing primary photo URLs
|
|
15
|
+
# activity = client.activity(1234567890)
|
|
16
|
+
# if activity.photos&.primary
|
|
17
|
+
# photo = activity.photos.primary
|
|
18
|
+
# puts "Photo ID: #{photo.id}"
|
|
19
|
+
# puts "Source: #{photo.source}"
|
|
20
|
+
# puts "URLs: #{photo.urls}"
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
6
23
|
class PhotosSummaryPrimary < Strava::Models::Response
|
|
24
|
+
# @return [Integer, nil] Unique identifier for the photo
|
|
7
25
|
property 'id'
|
|
26
|
+
|
|
27
|
+
# @return [Integer] Source of the photo (1=native Strava upload, 2=Instagram)
|
|
8
28
|
property 'source'
|
|
29
|
+
|
|
30
|
+
# @return [String] Unique identifier string for the photo
|
|
9
31
|
property 'unique_id'
|
|
32
|
+
|
|
33
|
+
# @return [Hash] Hash containing URLs to different sizes of the photo
|
|
10
34
|
property 'urls'
|
|
11
|
-
|
|
35
|
+
|
|
36
|
+
# @return [Integer, nil] Type of media (1=photo, 2=video)
|
|
37
|
+
# @note Not documented by Strava API
|
|
12
38
|
property 'media_type'
|
|
13
39
|
end
|
|
14
40
|
end
|
|
@@ -2,8 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents an athlete's power zone configuration.
|
|
7
|
+
#
|
|
8
|
+
# Power zones define intensity levels based on watts output. These are
|
|
9
|
+
# typically used for cycling training and are often based on FTP
|
|
10
|
+
# (Functional Threshold Power).
|
|
11
|
+
#
|
|
12
|
+
# @see https://developers.strava.com/docs/reference/#api-models-PowerZoneRanges Strava API PowerZoneRanges reference
|
|
13
|
+
# @see Strava::Models::ZoneRange
|
|
14
|
+
# @see Strava::Models::Zones
|
|
15
|
+
#
|
|
16
|
+
# @example Accessing power zones
|
|
17
|
+
# zones = client.athlete_zones
|
|
18
|
+
#
|
|
19
|
+
# if zones.power
|
|
20
|
+
# zones.power.zones.each_with_index do |zone, i|
|
|
21
|
+
# puts "Power Zone #{i + 1}: #{zone.min}-#{zone.max}W"
|
|
22
|
+
# end
|
|
23
|
+
# else
|
|
24
|
+
# puts "No power zones configured"
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
6
27
|
class PowerZoneRanges < Strava::Models::Response
|
|
28
|
+
# @return [Array<ZoneRange>] Array of power zone ranges in watts
|
|
7
29
|
property 'zones', transform_with: ->(v) { v.map { |r| Strava::Models::ZoneRange.new(r) } }
|
|
8
30
|
end
|
|
9
31
|
end
|
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
+
#
|
|
6
|
+
# Base response model for all API responses.
|
|
7
|
+
#
|
|
8
|
+
# This class serves as the parent for all model classes that represent API responses.
|
|
9
|
+
# It includes the HttpResponse mixin which provides access to HTTP response data
|
|
10
|
+
# including rate limit information.
|
|
11
|
+
#
|
|
12
|
+
# Most API models inherit from this class to gain access to the http_response method,
|
|
13
|
+
# which can be used to inspect rate limits and other response metadata.
|
|
14
|
+
#
|
|
15
|
+
# @example Accessing rate limit information
|
|
16
|
+
# activity = client.activity(1234567890)
|
|
17
|
+
# ratelimit = activity.http_response.ratelimit
|
|
18
|
+
# puts "Remaining requests: #{ratelimit.fifteen_minutes_remaining}"
|
|
19
|
+
#
|
|
20
|
+
# @see Mixins::HttpResponse
|
|
21
|
+
# @see Strava::Api::Ratelimit
|
|
22
|
+
#
|
|
5
23
|
class Response < Model
|
|
6
24
|
include Mixins::HttpResponse
|
|
7
25
|
end
|
data/lib/strava/models/route.rb
CHANGED
|
@@ -2,28 +2,89 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents a Strava route.
|
|
7
|
+
#
|
|
8
|
+
# Routes are planned courses that athletes can follow for activities.
|
|
9
|
+
# They include map data, waypoints, and estimated moving time. Routes can
|
|
10
|
+
# be exported as GPX or TCX files for use with GPS devices.
|
|
11
|
+
#
|
|
12
|
+
# Includes helper mixins for formatting distance, elevation gain, and time.
|
|
13
|
+
#
|
|
14
|
+
# @example Get and display route information
|
|
15
|
+
# route = client.route(1234567)
|
|
16
|
+
# puts route.name
|
|
17
|
+
# puts route.description
|
|
18
|
+
# puts "Distance: #{route.distance_s}"
|
|
19
|
+
# puts "Elevation gain: #{route.elevation_gain_s}"
|
|
20
|
+
# puts "Estimated time: #{route.estimated_moving_time_in_hours_s}"
|
|
21
|
+
#
|
|
22
|
+
# @example Export route as GPX
|
|
23
|
+
# gpx_data = client.export_route_gpx(route.id)
|
|
24
|
+
# File.write('route.gpx', gpx_data)
|
|
25
|
+
#
|
|
26
|
+
# @see Strava::Api::Client#route
|
|
27
|
+
# @see Strava::Api::Client#export_route_gpx
|
|
28
|
+
# @see Strava::Api::Client#export_route_tcx
|
|
29
|
+
# @see https://developers.strava.com/docs/reference/#api-models-Route
|
|
30
|
+
#
|
|
6
31
|
class Route < Strava::Models::Response
|
|
32
|
+
# @return [SummaryAthlete] The athlete who created this route
|
|
7
33
|
property 'athlete', transform_with: ->(v) { Strava::Models::SummaryAthlete.new(v) }
|
|
34
|
+
|
|
35
|
+
# @return [String, nil] Route description
|
|
8
36
|
property 'description'
|
|
37
|
+
|
|
9
38
|
include Mixins::Distance
|
|
10
39
|
include Mixins::ElevationGain
|
|
40
|
+
|
|
41
|
+
# @return [Integer] Route ID
|
|
11
42
|
property 'id'
|
|
43
|
+
|
|
44
|
+
# @return [String] Route ID as a string
|
|
12
45
|
property 'id_str'
|
|
46
|
+
|
|
47
|
+
# @return [Map] Route map with polyline data
|
|
13
48
|
property 'map', transform_with: ->(v) { Strava::Models::Map.new(v) }
|
|
49
|
+
|
|
50
|
+
# @return [String] Route name
|
|
14
51
|
property 'name'
|
|
52
|
+
|
|
53
|
+
# @return [Boolean] Whether this route is private
|
|
15
54
|
property 'private'
|
|
55
|
+
|
|
56
|
+
# @return [Boolean] Whether this route has been starred by the authenticated athlete
|
|
16
57
|
property 'starred'
|
|
58
|
+
|
|
59
|
+
# @return [Time] Timestamp for the route
|
|
17
60
|
property 'timestamp', transform_with: ->(v) { Time.at(v) }
|
|
61
|
+
|
|
62
|
+
# @return [Integer] Route type (1 = Ride, 2 = Run)
|
|
18
63
|
property 'type'
|
|
64
|
+
|
|
65
|
+
# @return [Integer] Route sub-type for additional categorization
|
|
19
66
|
property 'sub_type'
|
|
67
|
+
|
|
68
|
+
# @return [Time] When the route was created
|
|
20
69
|
property 'created_at', transform_with: ->(v) { Time.parse(v) }
|
|
70
|
+
|
|
71
|
+
# @return [Time] When the route was last updated
|
|
21
72
|
property 'updated_at', transform_with: ->(v) { Time.parse(v) }
|
|
73
|
+
|
|
22
74
|
include Mixins::EstimatedMovingTime
|
|
75
|
+
|
|
76
|
+
# @return [Array<SummarySegment>] Segments along this route
|
|
23
77
|
property 'segments', transform_with: ->(v) { v.map { |r| Strava::Models::SummarySegment.new(r) } }
|
|
78
|
+
|
|
79
|
+
# @return [Array<Waypoint>] Waypoints along this route
|
|
24
80
|
property 'waypoints', transform_with: ->(v) { v.map { |r| Strava::Models::Waypoint.new(r) } }
|
|
25
|
-
|
|
81
|
+
|
|
82
|
+
# @note Undocumented in official API
|
|
83
|
+
# @return [Hash, nil] URLs to map images at various sizes
|
|
26
84
|
property 'map_urls'
|
|
85
|
+
|
|
86
|
+
# @note Undocumented in official API
|
|
87
|
+
# @return [Integer, nil] Resource state indicator
|
|
27
88
|
property 'resource_state'
|
|
28
89
|
end
|
|
29
90
|
end
|