strava-ruby-client 3.0.0 → 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 +14 -0
- data/README.md +41 -57
- 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,12 +3,21 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Api
|
|
5
5
|
module Endpoints
|
|
6
|
+
#
|
|
7
|
+
# API endpoints for Strava routes.
|
|
8
|
+
#
|
|
9
|
+
# Routes are manually-created paths on Strava that can be used for planning.
|
|
10
|
+
# Routes can be exported in GPX or TCX format and can include waypoints,
|
|
11
|
+
# elevation data, and other metadata.
|
|
12
|
+
#
|
|
13
|
+
# @see https://developers.strava.com/docs/reference/#api-Routes
|
|
14
|
+
#
|
|
6
15
|
module Routes
|
|
7
16
|
#
|
|
8
17
|
# Returns a GPX file of the route.
|
|
9
18
|
#
|
|
10
|
-
# @
|
|
11
|
-
#
|
|
19
|
+
# @param id_or_options [String, Integer, Hash] Either a route ID or a hash of options including :id
|
|
20
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
12
21
|
#
|
|
13
22
|
def export_route_gpx(id_or_options, options = {})
|
|
14
23
|
id, options = parse_args(id_or_options, options)
|
|
@@ -16,10 +25,10 @@ module Strava
|
|
|
16
25
|
end
|
|
17
26
|
|
|
18
27
|
#
|
|
19
|
-
# Returns a
|
|
28
|
+
# Returns a TCX file of the route.
|
|
20
29
|
#
|
|
21
|
-
# @
|
|
22
|
-
#
|
|
30
|
+
# @param id_or_options [String, Integer, Hash] Either a route ID or a hash of options including :id
|
|
31
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
23
32
|
#
|
|
24
33
|
def export_route_tcx(id_or_options, options = {})
|
|
25
34
|
id, options = parse_args(id_or_options, options)
|
|
@@ -29,8 +38,8 @@ module Strava
|
|
|
29
38
|
#
|
|
30
39
|
# Returns a route using its identifier.
|
|
31
40
|
#
|
|
32
|
-
# @
|
|
33
|
-
#
|
|
41
|
+
# @param id_or_options [String, Integer, Hash] Either a route ID or a hash of options including :id
|
|
42
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
34
43
|
#
|
|
35
44
|
def route(id_or_options, options = {})
|
|
36
45
|
id, options = parse_args(id_or_options, options)
|
|
@@ -40,12 +49,10 @@ module Strava
|
|
|
40
49
|
#
|
|
41
50
|
# Returns a list of the routes created by the authenticated athlete using their athlete ID.
|
|
42
51
|
#
|
|
43
|
-
# @
|
|
44
|
-
#
|
|
45
|
-
# @option options [Integer] :page
|
|
46
|
-
#
|
|
47
|
-
# @option options [Integer] :per_page
|
|
48
|
-
# Number of items per page. Defaults to 30.
|
|
52
|
+
# @param id_or_options [String, Integer, Hash] Either an athlete ID or a hash of options including :id
|
|
53
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
54
|
+
# @option options [Integer] :page Page number
|
|
55
|
+
# @option options [Integer] :per_page Number of items per page. Defaults to 30
|
|
49
56
|
#
|
|
50
57
|
def athlete_routes(id_or_options, options = {}, &block)
|
|
51
58
|
id, options = parse_args(id_or_options, options)
|
|
@@ -3,12 +3,21 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Api
|
|
5
5
|
module Endpoints
|
|
6
|
+
#
|
|
7
|
+
# API endpoints for Strava segment efforts.
|
|
8
|
+
#
|
|
9
|
+
# Segment efforts represent an athlete's attempt on a specific segment during an
|
|
10
|
+
# activity. Each time an activity passes through a segment, a segment effort is
|
|
11
|
+
# created with details like elapsed time, distance, and ranking information.
|
|
12
|
+
#
|
|
13
|
+
# @see https://developers.strava.com/docs/reference/#api-SegmentEfforts
|
|
14
|
+
#
|
|
6
15
|
module SegmentEfforts
|
|
7
16
|
#
|
|
8
17
|
# Returns a segment effort from an activity that is owned by the authenticated athlete.
|
|
9
18
|
#
|
|
10
|
-
# @
|
|
11
|
-
#
|
|
19
|
+
# @param id_or_options [String, Integer, Hash] Either a segment effort ID or a hash of options including :id
|
|
20
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
12
21
|
#
|
|
13
22
|
def segment_effort(id_or_options, options = {})
|
|
14
23
|
id, options = parse_args(id_or_options, options)
|
|
@@ -18,12 +27,10 @@ module Strava
|
|
|
18
27
|
#
|
|
19
28
|
# Returns a set of the authenticated athlete's segment efforts for a given segment.
|
|
20
29
|
#
|
|
21
|
-
# @
|
|
22
|
-
#
|
|
23
|
-
# @option options [Integer] :page
|
|
24
|
-
#
|
|
25
|
-
# @option options [Integer] :per_page
|
|
26
|
-
# Number of items per page. Defaults to 30.
|
|
30
|
+
# @param id_or_options [String, Integer, Hash] Either a segment ID or a hash of options including :id
|
|
31
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
32
|
+
# @option options [Integer] :page Page number
|
|
33
|
+
# @option options [Integer] :per_page Number of items per page. Defaults to 30
|
|
27
34
|
#
|
|
28
35
|
def segment_efforts(id_or_options, options = {}, &block)
|
|
29
36
|
id, options = parse_args(id_or_options, options)
|
|
@@ -3,21 +3,40 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Api
|
|
5
5
|
module Endpoints
|
|
6
|
+
#
|
|
7
|
+
# API endpoints for Strava segments.
|
|
8
|
+
#
|
|
9
|
+
# Segments are specific sections of road or trail where athletes can compete for time.
|
|
10
|
+
# This module provides methods for exploring, retrieving, and starring segments.
|
|
11
|
+
#
|
|
12
|
+
# @see https://developers.strava.com/docs/reference/#api-Segments
|
|
13
|
+
#
|
|
6
14
|
module Segments
|
|
7
15
|
#
|
|
8
|
-
#
|
|
16
|
+
# Explore segments in a geographic area.
|
|
9
17
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# @option options [
|
|
15
|
-
#
|
|
16
|
-
# @option options [Integer] :
|
|
17
|
-
#
|
|
18
|
+
# Returns the top 10 segments matching a specified query within a rectangular
|
|
19
|
+
# geographic boundary. Useful for discovering popular segments in an area.
|
|
20
|
+
#
|
|
21
|
+
# @param [Hash] options Search parameters
|
|
22
|
+
# @option options [Array<Float>] :bounds Required. Rectangular boundary as [sw_lat, sw_lng, ne_lat, ne_lng]
|
|
23
|
+
# @option options [String] :activity_type Activity type: 'running' or 'riding'
|
|
24
|
+
# @option options [Integer] :min_cat Minimum climbing category (0-5)
|
|
25
|
+
# @option options [Integer] :max_cat Maximum climbing category (0-5)
|
|
26
|
+
#
|
|
27
|
+
# @return [Array<Strava::Models::ExplorerSegment>] Array of segments
|
|
28
|
+
#
|
|
29
|
+
# @example Explore segments in an area
|
|
30
|
+
# segments = client.explore_segments(
|
|
31
|
+
# bounds: [40.7,-74.0,40.8,-73.9],
|
|
32
|
+
# activity_type: 'running'
|
|
33
|
+
# )
|
|
34
|
+
#
|
|
35
|
+
# @see https://developers.strava.com/docs/reference/#api-Segments-exploreSegments
|
|
18
36
|
#
|
|
19
37
|
def explore_segments(options = {})
|
|
20
|
-
|
|
38
|
+
raise ArgumentError, 'Required argument :bounds missing' if options[:bounds].nil?
|
|
39
|
+
|
|
21
40
|
bounds = options[:bounds]
|
|
22
41
|
bounds = bounds.map(&:to_s).join(',') if bounds.is_a?(Array)
|
|
23
42
|
get('segments/explore', options.merge(bounds: bounds))['segments'].map do |row|
|
|
@@ -28,10 +47,21 @@ module Strava
|
|
|
28
47
|
#
|
|
29
48
|
# List of the authenticated athlete's starred segments.
|
|
30
49
|
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
50
|
+
# Returns a paginated list of segments that the authenticated athlete has starred.
|
|
51
|
+
# Starred segments are favorites that the athlete wants to track their performance on.
|
|
52
|
+
#
|
|
53
|
+
# @param options [Hash] Pagination options
|
|
54
|
+
# @option options [Integer] :page Page number
|
|
55
|
+
# @option options [Integer] :per_page Number of items per page. Defaults to 30
|
|
56
|
+
#
|
|
57
|
+
# @yield [SummarySegment] Yields each segment in the paginated results
|
|
58
|
+
# @return [Array<SummarySegment>, Cursor] Array of starred segments or Cursor for iteration
|
|
59
|
+
#
|
|
60
|
+
# @example List all starred segments
|
|
61
|
+
# starred = client.starred_segments
|
|
62
|
+
# starred.each do |segment|
|
|
63
|
+
# puts "#{segment.name}: #{segment.distance_s}"
|
|
64
|
+
# end
|
|
35
65
|
#
|
|
36
66
|
def starred_segments(options = {}, &block)
|
|
37
67
|
paginate 'segments/starred', options, Strava::Models::SummarySegment, &block
|
|
@@ -40,8 +70,17 @@ module Strava
|
|
|
40
70
|
#
|
|
41
71
|
# Returns the specified segment.
|
|
42
72
|
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
73
|
+
# Retrieves detailed information about a specific segment including location,
|
|
74
|
+
# elevation profile, and the athlete's personal records on that segment.
|
|
75
|
+
#
|
|
76
|
+
# @param id_or_options [String, Integer, Hash] Either a segment ID or a hash of options including :id
|
|
77
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
78
|
+
#
|
|
79
|
+
# @return [DetailedSegment] The detailed segment information
|
|
80
|
+
#
|
|
81
|
+
# @example Get a segment by ID
|
|
82
|
+
# segment = client.segment(229781)
|
|
83
|
+
# puts "#{segment.name}: #{segment.distance_s} with #{segment.average_grade}% grade"
|
|
45
84
|
#
|
|
46
85
|
def segment(id_or_options, options = {})
|
|
47
86
|
id, options = parse_args(id_or_options, options)
|
|
@@ -51,14 +90,28 @@ module Strava
|
|
|
51
90
|
#
|
|
52
91
|
# Stars/Unstars the given segment for the authenticated athlete.
|
|
53
92
|
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
93
|
+
# Adds or removes a segment from the athlete's starred/favorite segments.
|
|
94
|
+
# Starred segments appear in the athlete's starred segments list and can
|
|
95
|
+
# be used to track performance over time.
|
|
96
|
+
#
|
|
97
|
+
# @param id_or_options [String, Integer, Hash] Either a segment ID or a hash of options including :id
|
|
98
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
99
|
+
# @option options [Boolean] :starred If true, star the segment; if false, unstar the segment (required)
|
|
100
|
+
#
|
|
101
|
+
# @return [DetailedSegment] The updated segment with new starred status
|
|
102
|
+
#
|
|
103
|
+
# @raise [ArgumentError] If :starred option is not provided
|
|
104
|
+
#
|
|
105
|
+
# @example Star a segment
|
|
106
|
+
# segment = client.star_segment(229781, starred: true)
|
|
107
|
+
#
|
|
108
|
+
# @example Unstar a segment
|
|
109
|
+
# segment = client.star_segment(229781, starred: false)
|
|
58
110
|
#
|
|
59
111
|
def star_segment(id_or_options, options = {})
|
|
60
112
|
id, options = parse_args(id_or_options, options)
|
|
61
|
-
|
|
113
|
+
raise ArgumentError, 'Required argument :starred missing' if options[:starred].nil?
|
|
114
|
+
|
|
62
115
|
Strava::Models::DetailedSegment.new(put("segments/#{id}/starred", options))
|
|
63
116
|
end
|
|
64
117
|
end
|
|
@@ -3,16 +3,24 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Api
|
|
5
5
|
module Endpoints
|
|
6
|
+
#
|
|
7
|
+
# API endpoints for Strava streams.
|
|
8
|
+
#
|
|
9
|
+
# Streams represent the raw data of uploaded activities. They can be thought of
|
|
10
|
+
# as a collection of time series data, where each data point is sampled at a
|
|
11
|
+
# specific time or distance. Available stream types include altitude, cadence,
|
|
12
|
+
# distance, heartrate, latlng, moving, power, temp, time, and velocity.
|
|
13
|
+
#
|
|
14
|
+
# @see https://developers.strava.com/docs/reference/#api-Streams
|
|
15
|
+
#
|
|
6
16
|
module Streams
|
|
7
17
|
#
|
|
8
18
|
# Returns the given activity's streams.
|
|
9
19
|
#
|
|
10
|
-
# @
|
|
11
|
-
#
|
|
12
|
-
# @option options [Array
|
|
13
|
-
#
|
|
14
|
-
# @option options [Boolean] :key_by_type
|
|
15
|
-
# Must be true.
|
|
20
|
+
# @param id_or_options [String, Integer, Hash] Either an activity ID or a hash of options including :id
|
|
21
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
22
|
+
# @option options [Array<String>] :keys Desired stream types (e.g., ['time', 'latlng', 'distance', 'altitude'])
|
|
23
|
+
# @option options [Boolean] :key_by_type Must be true
|
|
16
24
|
#
|
|
17
25
|
def activity_streams(id_or_options, options = {})
|
|
18
26
|
id, options = parse_args(id_or_options, options)
|
|
@@ -25,12 +33,10 @@ module Strava
|
|
|
25
33
|
#
|
|
26
34
|
# Returns a set of streams for a segment effort completed by the authenticated athlete.
|
|
27
35
|
#
|
|
28
|
-
# @
|
|
29
|
-
#
|
|
30
|
-
# @option options [Array
|
|
31
|
-
#
|
|
32
|
-
# @option options [Boolean] :key_by_type
|
|
33
|
-
# Must be true.
|
|
36
|
+
# @param id_or_options [String, Integer, Hash] Either a segment effort ID or a hash of options including :id
|
|
37
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
38
|
+
# @option options [Array<String>] :keys The types of streams to return
|
|
39
|
+
# @option options [Boolean] :key_by_type Must be true
|
|
34
40
|
#
|
|
35
41
|
def segment_effort_streams(id_or_options, options = {})
|
|
36
42
|
id, options = parse_args(id_or_options, options)
|
|
@@ -43,12 +49,10 @@ module Strava
|
|
|
43
49
|
#
|
|
44
50
|
# Returns the given segment's streams.
|
|
45
51
|
#
|
|
46
|
-
# @
|
|
47
|
-
#
|
|
48
|
-
# @option options [Array
|
|
49
|
-
#
|
|
50
|
-
# @option options [Boolean] :key_by_type
|
|
51
|
-
# Must be true.
|
|
52
|
+
# @param id_or_options [String, Integer, Hash] Either a segment ID or a hash of options including :id
|
|
53
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
54
|
+
# @option options [Array<String>] :keys The types of streams to return
|
|
55
|
+
# @option options [Boolean] :key_by_type Must be true
|
|
52
56
|
#
|
|
53
57
|
def segment_streams(id_or_options, options = {})
|
|
54
58
|
id, options = parse_args(id_or_options, options)
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Api
|
|
5
5
|
module Endpoints
|
|
6
|
+
#
|
|
7
|
+
# API endpoints for Strava uploads.
|
|
8
|
+
#
|
|
9
|
+
# Uploads allow you to create activities by uploading activity files in various
|
|
10
|
+
# formats such as FIT, TCX, and GPX. After uploading, the file is processed
|
|
11
|
+
# asynchronously and you can check the upload status to determine when the
|
|
12
|
+
# activity has been created.
|
|
13
|
+
#
|
|
14
|
+
# @see https://developers.strava.com/docs/reference/#api-Uploads
|
|
15
|
+
#
|
|
6
16
|
module Uploads
|
|
7
17
|
#
|
|
8
18
|
# Uploads a new data file to create an activity from.
|
|
@@ -29,8 +39,8 @@ module Strava
|
|
|
29
39
|
#
|
|
30
40
|
# Returns an upload for a given identifier.
|
|
31
41
|
#
|
|
32
|
-
# @
|
|
33
|
-
#
|
|
42
|
+
# @param id_or_options [String, Integer, Hash] Either an upload ID or a hash of options including :id
|
|
43
|
+
# @param options [Hash] Additional options (if first parameter is an ID)
|
|
34
44
|
#
|
|
35
45
|
def upload(id_or_options, options = {})
|
|
36
46
|
id, options = parse_args(id_or_options, options)
|
|
@@ -41,16 +41,41 @@ module Strava
|
|
|
41
41
|
@collection.size
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
#
|
|
45
|
+
# Iterates over each item in the paginated collection.
|
|
46
|
+
#
|
|
47
|
+
# @yield [Object] Yields each item in the collection
|
|
48
|
+
# @return [void]
|
|
49
|
+
#
|
|
44
50
|
def each
|
|
45
51
|
@collection.each { |c| yield c if block_given? }
|
|
46
52
|
end
|
|
47
53
|
|
|
48
54
|
private
|
|
49
55
|
|
|
56
|
+
#
|
|
57
|
+
# Delegates missing methods to the underlying collection.
|
|
58
|
+
#
|
|
59
|
+
# Allows the Pagination object to respond to array methods by
|
|
60
|
+
# forwarding them to the internal collection array.
|
|
61
|
+
#
|
|
62
|
+
# @api private
|
|
63
|
+
# @param method_symbol [Symbol] The method name to forward
|
|
64
|
+
# @param args [Array] Arguments to pass to the method
|
|
65
|
+
# @return [Object] Result from the delegated method
|
|
66
|
+
#
|
|
50
67
|
def method_missing(method_symbol, ...)
|
|
51
68
|
@collection.send(method_symbol, ...)
|
|
52
69
|
end
|
|
53
70
|
|
|
71
|
+
#
|
|
72
|
+
# Checks if the underlying collection responds to a method.
|
|
73
|
+
#
|
|
74
|
+
# @api private
|
|
75
|
+
# @param method_name [Symbol] The method name to check
|
|
76
|
+
# @param include_private [Boolean] Whether to include private methods
|
|
77
|
+
# @return [Boolean] true if the collection responds to the method
|
|
78
|
+
#
|
|
54
79
|
def respond_to_missing?(method_name, include_private = false)
|
|
55
80
|
super
|
|
56
81
|
end
|
data/lib/strava/api/ratelimit.rb
CHANGED
|
@@ -2,7 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Api
|
|
5
|
+
#
|
|
6
|
+
# Handles Strava API rate limit information from HTTP responses.
|
|
7
|
+
#
|
|
8
|
+
# Strava enforces rate limits on API requests with two windows:
|
|
9
|
+
# - 15-minute window: 600 requests per 15 minutes (short-term limit)
|
|
10
|
+
# - Daily window: 30,000 requests per day (long-term limit)
|
|
11
|
+
#
|
|
12
|
+
# This class extracts and provides easy access to rate limit data from
|
|
13
|
+
# HTTP response headers.
|
|
14
|
+
#
|
|
15
|
+
# @see Strava::Web::ApiResponse
|
|
16
|
+
# @see https://developers.strava.com/docs/rate-limits/ Strava API Rate Limiting documentation
|
|
17
|
+
#
|
|
18
|
+
# @example Checking rate limits after an API call
|
|
19
|
+
# activity = client.activity(1234567890)
|
|
20
|
+
# ratelimit = activity.http_response.ratelimit
|
|
21
|
+
#
|
|
22
|
+
# puts "15-minute limit: #{ratelimit.fifteen_minutes_limit}"
|
|
23
|
+
# puts "15-minute usage: #{ratelimit.fifteen_minutes_usage}"
|
|
24
|
+
# puts "15-minute remaining: #{ratelimit.fifteen_minutes_remaining}"
|
|
25
|
+
#
|
|
26
|
+
# puts "Daily limit: #{ratelimit.total_day}"
|
|
27
|
+
# puts "Daily usage: #{ratelimit.total_day_usage}"
|
|
28
|
+
# puts "Daily remaining: #{ratelimit.total_day_remaining}"
|
|
29
|
+
#
|
|
30
|
+
# if ratelimit.exceeded?
|
|
31
|
+
# puts "Rate limit exceeded!"
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
5
34
|
class Ratelimit
|
|
35
|
+
#
|
|
36
|
+
# Initialize a new Ratelimit instance from an HTTP response.
|
|
37
|
+
#
|
|
38
|
+
# @param response [Faraday::Response] HTTP response containing rate limit headers
|
|
39
|
+
#
|
|
6
40
|
def initialize(response)
|
|
7
41
|
@response = response
|
|
8
42
|
@headers = response.headers
|
data/lib/strava/deep_copyable.rb
CHANGED
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
|
+
#
|
|
5
|
+
# Mixin module for deep copying objects.
|
|
6
|
+
#
|
|
7
|
+
# This module provides a helper method for creating deep copies of objects
|
|
8
|
+
# using Ruby's Marshal serialization. Unlike shallow cloning (which only
|
|
9
|
+
# duplicates the top-level object), deep copying recursively duplicates all
|
|
10
|
+
# nested objects and collections.
|
|
11
|
+
#
|
|
12
|
+
# This is particularly useful when working with model objects that contain
|
|
13
|
+
# nested hashes or arrays, ensuring modifications to the copy don't affect
|
|
14
|
+
# the original object.
|
|
15
|
+
#
|
|
16
|
+
# @example Deep copying a nested hash
|
|
17
|
+
# include Strava::DeepCopyable
|
|
18
|
+
# original = {a: {b: [1, 2, 3]}}
|
|
19
|
+
# copy = deep_copy(original)
|
|
20
|
+
# copy[:a][:b] << 4
|
|
21
|
+
# original[:a][:b] # => [1, 2, 3] (unchanged)
|
|
22
|
+
#
|
|
4
23
|
module DeepCopyable
|
|
5
24
|
#
|
|
6
|
-
# Ruby's way of creating a true deep copy/clone
|
|
25
|
+
# Ruby's way of creating a true deep copy/clone.
|
|
7
26
|
#
|
|
8
27
|
# @param [Object] obj of any kind
|
|
9
28
|
#
|
data/lib/strava/errors/fault.rb
CHANGED
|
@@ -2,15 +2,47 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Errors
|
|
5
|
+
#
|
|
6
|
+
# Base error class for Strava API client errors.
|
|
7
|
+
#
|
|
8
|
+
# This exception is raised when the Strava API returns an error response.
|
|
9
|
+
# It extends Faraday::ClientError and provides convenient access to the
|
|
10
|
+
# error message, response headers, and detailed error information from
|
|
11
|
+
# the API response body.
|
|
12
|
+
#
|
|
13
|
+
# @see Faraday::ClientError
|
|
14
|
+
#
|
|
5
15
|
class Fault < ::Faraday::ClientError
|
|
16
|
+
#
|
|
17
|
+
# Returns the error message from the API response.
|
|
18
|
+
#
|
|
19
|
+
# Extracts the message from the response body if available,
|
|
20
|
+
# otherwise falls back to the parent class message.
|
|
21
|
+
#
|
|
22
|
+
# @return [String] The error message
|
|
23
|
+
#
|
|
6
24
|
def message
|
|
7
25
|
response[:body]['message'] || super
|
|
8
26
|
end
|
|
9
27
|
|
|
28
|
+
#
|
|
29
|
+
# Returns the HTTP response headers.
|
|
30
|
+
#
|
|
31
|
+
# @return [Hash] The response headers hash
|
|
32
|
+
#
|
|
10
33
|
def headers
|
|
11
34
|
response[:headers]
|
|
12
35
|
end
|
|
13
36
|
|
|
37
|
+
#
|
|
38
|
+
# Returns detailed error information from the API response.
|
|
39
|
+
#
|
|
40
|
+
# The Strava API may return an 'errors' array in the response body
|
|
41
|
+
# containing detailed information about validation errors or other
|
|
42
|
+
# specific error conditions.
|
|
43
|
+
#
|
|
44
|
+
# @return [Array, nil] Array of error details, or nil if not present
|
|
45
|
+
#
|
|
14
46
|
def errors
|
|
15
47
|
response[:body]['errors']
|
|
16
48
|
end
|
|
@@ -2,22 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Errors
|
|
5
|
+
#
|
|
6
|
+
# Exception raised when API rate limits are exceeded.
|
|
7
|
+
#
|
|
8
|
+
# Strava enforces rate limits on API requests to prevent abuse. When your
|
|
9
|
+
# application exceeds these limits (either per 15 minutes or per day), the
|
|
10
|
+
# API returns a 429 Too Many Requests response, which triggers this exception.
|
|
11
|
+
#
|
|
12
|
+
# This error includes rate limit information extracted from the response headers,
|
|
13
|
+
# allowing you to determine current usage and when limits will reset.
|
|
14
|
+
#
|
|
15
|
+
# @see Strava::Api::Ratelimit
|
|
16
|
+
# @see https://developers.strava.com/docs/rate-limits/
|
|
17
|
+
#
|
|
5
18
|
class RatelimitError < ::Faraday::ClientError
|
|
19
|
+
# @return [Strava::Api::Ratelimit] Rate limit information from response headers
|
|
6
20
|
attr_reader :ratelimit
|
|
7
21
|
|
|
22
|
+
#
|
|
23
|
+
# Initialize a new rate limit error.
|
|
24
|
+
#
|
|
25
|
+
# @param env [Faraday::Env] The Faraday request environment
|
|
26
|
+
# @param response [Hash] The HTTP response hash
|
|
27
|
+
#
|
|
8
28
|
def initialize(env, response)
|
|
9
29
|
@ratelimit = Strava::Api::Ratelimit.new(env.response)
|
|
10
30
|
super(response)
|
|
11
31
|
end
|
|
12
32
|
|
|
33
|
+
#
|
|
34
|
+
# Returns the error message from the API response.
|
|
35
|
+
#
|
|
36
|
+
# @return [String] The error message
|
|
37
|
+
#
|
|
13
38
|
def message
|
|
14
39
|
response[:body]['message'] || super
|
|
15
40
|
end
|
|
16
41
|
|
|
42
|
+
#
|
|
43
|
+
# Returns the HTTP response headers.
|
|
44
|
+
#
|
|
45
|
+
# @return [Hash] The response headers hash
|
|
46
|
+
#
|
|
17
47
|
def headers
|
|
18
48
|
response[:headers]
|
|
19
49
|
end
|
|
20
50
|
|
|
51
|
+
#
|
|
52
|
+
# Returns detailed error information from the API response.
|
|
53
|
+
#
|
|
54
|
+
# @return [Array, nil] Array of error details, or nil if not present
|
|
55
|
+
#
|
|
21
56
|
def errors
|
|
22
57
|
response[:body]['errors']
|
|
23
58
|
end
|
|
@@ -2,29 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Errors
|
|
5
|
+
#
|
|
6
|
+
# Exception raised when an activity upload fails.
|
|
7
|
+
#
|
|
8
|
+
# When uploading activity files (FIT, TCX, GPX) to Strava, the API processes
|
|
9
|
+
# the file asynchronously and may encounter errors during processing. This
|
|
10
|
+
# exception is raised when the upload fails, and includes information about
|
|
11
|
+
# the upload status and error details.
|
|
12
|
+
#
|
|
13
|
+
# The error provides access to the upload model, which contains detailed
|
|
14
|
+
# information about what went wrong during the upload processing.
|
|
15
|
+
#
|
|
16
|
+
# @see Strava::Models::Upload
|
|
17
|
+
# @see https://developers.strava.com/docs/reference/#api-Uploads
|
|
18
|
+
#
|
|
5
19
|
class UploadError < ::Faraday::ClientError
|
|
20
|
+
#
|
|
21
|
+
# Returns the HTTP response status code.
|
|
22
|
+
#
|
|
23
|
+
# @return [Integer] The HTTP status code
|
|
24
|
+
#
|
|
6
25
|
def status
|
|
7
26
|
response[:status]
|
|
8
27
|
end
|
|
9
28
|
|
|
29
|
+
#
|
|
30
|
+
# Returns the HTTP response headers.
|
|
31
|
+
#
|
|
32
|
+
# @return [Hash] The response headers hash
|
|
33
|
+
#
|
|
10
34
|
def headers
|
|
11
35
|
response[:headers]
|
|
12
36
|
end
|
|
13
37
|
|
|
38
|
+
#
|
|
39
|
+
# Returns the error message from the upload response.
|
|
40
|
+
#
|
|
41
|
+
# Extracts the error message from the response body's 'error' field,
|
|
42
|
+
# or falls back to the parent class message if not available.
|
|
43
|
+
#
|
|
44
|
+
# @return [String] The error message
|
|
45
|
+
#
|
|
14
46
|
def message
|
|
15
47
|
body[:error] || super
|
|
16
48
|
end
|
|
17
49
|
|
|
50
|
+
#
|
|
51
|
+
# Returns the upload processing status from the response.
|
|
52
|
+
#
|
|
53
|
+
# The upload status indicates where in the processing pipeline the
|
|
54
|
+
# upload failed (e.g., 'error', 'processing', 'ready').
|
|
55
|
+
#
|
|
56
|
+
# @return [String] The upload status
|
|
57
|
+
#
|
|
18
58
|
def error_status
|
|
19
59
|
body[:status]
|
|
20
60
|
end
|
|
21
61
|
|
|
62
|
+
#
|
|
63
|
+
# Returns the upload model containing detailed upload information.
|
|
64
|
+
#
|
|
65
|
+
# The upload model includes fields like id, external_id, error,
|
|
66
|
+
# status, and activity_id (if the upload succeeded before encountering
|
|
67
|
+
# an error).
|
|
68
|
+
#
|
|
69
|
+
# @return [Strava::Models::Upload] The upload model
|
|
70
|
+
#
|
|
22
71
|
def upload
|
|
23
72
|
@upload ||= Strava::Models::Upload.new(body)
|
|
24
73
|
end
|
|
25
74
|
|
|
26
75
|
private
|
|
27
76
|
|
|
77
|
+
#
|
|
78
|
+
# Returns the response body with indifferent access.
|
|
79
|
+
#
|
|
80
|
+
# @api private
|
|
81
|
+
# @return [HashWithIndifferentAccess] The response body hash
|
|
82
|
+
#
|
|
28
83
|
def body
|
|
29
84
|
(response[:body] || {}).with_indifferent_access
|
|
30
85
|
end
|
data/lib/strava/logger.rb
CHANGED
|
@@ -3,7 +3,34 @@
|
|
|
3
3
|
require 'logger'
|
|
4
4
|
|
|
5
5
|
module Strava
|
|
6
|
+
#
|
|
7
|
+
# Default logger for the Strava client library.
|
|
8
|
+
#
|
|
9
|
+
# Extends the standard Ruby Logger class and provides a default logger
|
|
10
|
+
# instance configured to output warnings and errors to STDOUT. The logger
|
|
11
|
+
# can be customized via the Web configuration to control HTTP request/response
|
|
12
|
+
# logging.
|
|
13
|
+
#
|
|
14
|
+
# @example Using the default logger
|
|
15
|
+
# Strava::Logger.logger.info('Making API request')
|
|
16
|
+
#
|
|
17
|
+
# @example Customizing the logger
|
|
18
|
+
# Strava::Web.configure do |config|
|
|
19
|
+
# config.logger = Logger.new('strava.log')
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# @see Logger
|
|
23
|
+
#
|
|
6
24
|
class Logger < ::Logger
|
|
25
|
+
#
|
|
26
|
+
# Returns the default logger instance.
|
|
27
|
+
#
|
|
28
|
+
# Creates a memoized logger that outputs to STDOUT with a default
|
|
29
|
+
# log level of WARN. This logger is used by default for HTTP request
|
|
30
|
+
# logging unless overridden in the configuration.
|
|
31
|
+
#
|
|
32
|
+
# @return [Strava::Logger] The default logger instance
|
|
33
|
+
#
|
|
7
34
|
def self.logger
|
|
8
35
|
@logger ||= begin
|
|
9
36
|
logger = new $stdout
|