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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -2
  3. data/README.md +47 -58
  4. data/lib/strava/api/client.rb +69 -0
  5. data/lib/strava/api/config.rb +40 -0
  6. data/lib/strava/api/cursor.rb +32 -1
  7. data/lib/strava/api/endpoints/activities.rb +197 -57
  8. data/lib/strava/api/endpoints/athletes.rb +64 -8
  9. data/lib/strava/api/endpoints/clubs.rb +24 -59
  10. data/lib/strava/api/endpoints/gears.rb +11 -2
  11. data/lib/strava/api/endpoints/oauth.rb +45 -0
  12. data/lib/strava/api/endpoints/routes.rb +20 -13
  13. data/lib/strava/api/endpoints/segment_efforts.rb +15 -8
  14. data/lib/strava/api/endpoints/segments.rb +74 -21
  15. data/lib/strava/api/endpoints/streams.rb +22 -18
  16. data/lib/strava/api/endpoints/uploads.rb +12 -2
  17. data/lib/strava/api/pagination.rb +25 -0
  18. data/lib/strava/api/ratelimit.rb +34 -0
  19. data/lib/strava/deep_copyable.rb +20 -1
  20. data/lib/strava/errors/fault.rb +32 -0
  21. data/lib/strava/errors/ratelimit_error.rb +35 -0
  22. data/lib/strava/errors/upload_error.rb +55 -0
  23. data/lib/strava/logger.rb +27 -0
  24. data/lib/strava/models/achievement.rb +28 -1
  25. data/lib/strava/models/activity_stats.rb +47 -1
  26. data/lib/strava/models/activity_total.rb +25 -1
  27. data/lib/strava/models/activity_zone.rb +39 -2
  28. data/lib/strava/models/authorization.rb +13 -0
  29. data/lib/strava/models/base_stream.rb +22 -1
  30. data/lib/strava/models/club_event.rb +64 -1
  31. data/lib/strava/models/comment.rb +39 -1
  32. data/lib/strava/models/destination.rb +28 -1
  33. data/lib/strava/models/detailed_activity.rb +203 -2
  34. data/lib/strava/models/detailed_athlete.rb +104 -2
  35. data/lib/strava/models/detailed_club.rb +76 -2
  36. data/lib/strava/models/detailed_gear.rb +45 -2
  37. data/lib/strava/models/detailed_photo.rb +61 -1
  38. data/lib/strava/models/detailed_photos.rb +29 -1
  39. data/lib/strava/models/detailed_segment.rb +89 -2
  40. data/lib/strava/models/detailed_segment_effort.rb +92 -3
  41. data/lib/strava/models/explorer_segment.rb +55 -2
  42. data/lib/strava/models/heart_rate_zone_ranges.rb +29 -1
  43. data/lib/strava/models/kudoser.rb +29 -1
  44. data/lib/strava/models/lap.rb +62 -2
  45. data/lib/strava/models/lat_lng.rb +42 -4
  46. data/lib/strava/models/local_legend.rb +41 -1
  47. data/lib/strava/models/map.rb +31 -0
  48. data/lib/strava/models/meta_activity.rb +15 -2
  49. data/lib/strava/models/meta_athlete.rb +17 -2
  50. data/lib/strava/models/meta_club.rb +15 -1
  51. data/lib/strava/models/mixins/average_speed.rb +81 -3
  52. data/lib/strava/models/mixins/distance.rb +25 -0
  53. data/lib/strava/models/mixins/elapsed_time.rb +18 -0
  54. data/lib/strava/models/mixins/elevation_difference.rb +42 -0
  55. data/lib/strava/models/mixins/elevation_gain.rb +39 -0
  56. data/lib/strava/models/mixins/estimated_moving_time.rb +18 -0
  57. data/lib/strava/models/mixins/http_response.rb +36 -0
  58. data/lib/strava/models/mixins/moving_time.rb +18 -0
  59. data/lib/strava/models/mixins/sport_type.rb +39 -1
  60. data/lib/strava/models/mixins/start_date_local.rb +40 -24
  61. data/lib/strava/models/mixins/time_in_hours.rb +23 -0
  62. data/lib/strava/models/mixins/total_elevation_gain.rb +42 -0
  63. data/lib/strava/models/model.rb +14 -0
  64. data/lib/strava/models/photos_summary.rb +26 -2
  65. data/lib/strava/models/photos_summary_primary.rb +28 -2
  66. data/lib/strava/models/power_zone_ranges.rb +23 -1
  67. data/lib/strava/models/response.rb +18 -0
  68. data/lib/strava/models/route.rb +63 -2
  69. data/lib/strava/models/similar_activities.rb +57 -1
  70. data/lib/strava/models/split.rb +27 -2
  71. data/lib/strava/models/stats_visibility.rb +24 -1
  72. data/lib/strava/models/stream.rb +107 -0
  73. data/lib/strava/models/stream_set.rb +52 -1
  74. data/lib/strava/models/summary_activity.rb +145 -2
  75. data/lib/strava/models/summary_athlete.rb +54 -1
  76. data/lib/strava/models/summary_club.rb +61 -2
  77. data/lib/strava/models/summary_gear.rb +31 -2
  78. data/lib/strava/models/summary_pr_segment_effort.rb +32 -2
  79. data/lib/strava/models/summary_segment.rb +80 -2
  80. data/lib/strava/models/summary_segment_effort.rb +32 -1
  81. data/lib/strava/models/timed_zone_range.rb +24 -1
  82. data/lib/strava/models/token.rb +31 -0
  83. data/lib/strava/models/trend.rb +38 -1
  84. data/lib/strava/models/updatable_activity.rb +36 -1
  85. data/lib/strava/models/upload.rb +50 -1
  86. data/lib/strava/models/waypoint.rb +31 -1
  87. data/lib/strava/models/xoms.rb +35 -1
  88. data/lib/strava/models/zone_range.rb +20 -1
  89. data/lib/strava/models/zones.rb +32 -1
  90. data/lib/strava/oauth/client.rb +107 -19
  91. data/lib/strava/oauth/config.rb +41 -0
  92. data/lib/strava/version.rb +1 -1
  93. data/lib/strava/web/api_response.rb +28 -2
  94. data/lib/strava/web/client.rb +72 -2
  95. data/lib/strava/web/config.rb +40 -0
  96. data/lib/strava/web/connection.rb +39 -0
  97. data/lib/strava/web/raise_response_error.rb +47 -0
  98. data/lib/strava/web/request.rb +56 -0
  99. data/lib/strava/web/response.rb +18 -0
  100. data/lib/strava/webhooks/client.rb +108 -7
  101. data/lib/strava/webhooks/config.rb +44 -0
  102. data/lib/strava/webhooks/models/challenge.rb +40 -0
  103. data/lib/strava/webhooks/models/event.rb +50 -0
  104. data/lib/strava/webhooks/models/subscription.rb +27 -0
  105. data/lib/strava-ruby-client.rb +0 -2
  106. metadata +2 -4
  107. data/lib/strava/models/club_activity.rb +0 -22
  108. data/lib/strava/models/club_athlete.rb +0 -21
@@ -2,11 +2,45 @@
2
2
 
3
3
  module Strava
4
4
  module Models
5
- # Undocumented
5
+ #
6
+ # Represents segment leaderboard achievements (KOM/QOM).
7
+ #
8
+ # Contains information about King of the Mountain (KOM), Queen of the Mountain (QOM),
9
+ # and overall segment records. This model is not documented in the official Strava
10
+ # 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::DetailedActivity
16
+ # @see Strava::Models::Destination
17
+ #
18
+ # @example Accessing XOM (KOM/QOM) information
19
+ # activity = client.activity(1234567890)
20
+ # if activity.xoms
21
+ # puts "KOM: #{activity.xoms.kom}"
22
+ # puts "QOM: #{activity.xoms.qom}"
23
+ # puts "Overall: #{activity.xoms.overall}"
24
+ # if activity.xoms.destination
25
+ # puts "Segment: #{activity.xoms.destination.name}"
26
+ # end
27
+ # end
28
+ #
6
29
  class Xoms < Strava::Models::Response
30
+ # @return [String, Integer, nil] King of the Mountain achievement data
31
+ # @note Not documented by Strava API
7
32
  property 'kom'
33
+
34
+ # @return [String, Integer, nil] Queen of the Mountain achievement data
35
+ # @note Not documented by Strava API
8
36
  property 'qom'
37
+
38
+ # @return [String, Integer, nil] Overall segment record data
39
+ # @note Not documented by Strava API
9
40
  property 'overall'
41
+
42
+ # @return [Destination, nil] Link to the segment where this achievement was earned
43
+ # @note Not documented by Strava API
10
44
  property 'destination', transform_with: ->(v) { Strava::Models::Destination.new(v) }
11
45
  end
12
46
  end
@@ -2,9 +2,28 @@
2
2
 
3
3
  module Strava
4
4
  module Models
5
- # https://developers.strava.com/docs/reference/#api-models-ZoneRange
5
+ #
6
+ # Represents a single training zone range.
7
+ #
8
+ # Training zones define intensity levels for heart rate or power. Each zone
9
+ # has a minimum and maximum value that defines the range for that intensity level.
10
+ #
11
+ # @see https://developers.strava.com/docs/reference/#api-models-ZoneRange Strava API ZoneRange reference
12
+ # @see Strava::Models::HeartRateZoneRanges
13
+ # @see Strava::Models::PowerZoneRanges
14
+ # @see Strava::Models::TimedZoneRange
15
+ #
16
+ # @example Accessing zone ranges
17
+ # zones = client.athlete_zones
18
+ # zones.heart_rate.zones.each_with_index do |zone, i|
19
+ # puts "Zone #{i + 1}: #{zone.min}-#{zone.max} bpm"
20
+ # end
21
+ #
6
22
  class ZoneRange < Strava::Models::Response
23
+ # @return [Integer] Maximum value for this zone (e.g., maximum heart rate or power)
7
24
  property 'max'
25
+
26
+ # @return [Integer] Minimum value for this zone (e.g., minimum heart rate or power)
8
27
  property 'min'
9
28
  end
10
29
  end
@@ -2,9 +2,40 @@
2
2
 
3
3
  module Strava
4
4
  module Models
5
- # https://developers.strava.com/docs/reference/#api-models-Zones
5
+ #
6
+ # Represents an athlete's training zones configuration.
7
+ #
8
+ # Training zones are used to define intensity levels for heart rate and power.
9
+ # These zones help athletes train at specific intensities and track time spent
10
+ # in each zone during activities.
11
+ #
12
+ # @see https://developers.strava.com/docs/reference/#api-models-Zones Strava API Zones reference
13
+ # @see Strava::Models::HeartRateZoneRanges
14
+ # @see Strava::Models::PowerZoneRanges
15
+ # @see Strava::Api::Client#athlete_zones
16
+ #
17
+ # @example Accessing athlete's training zones
18
+ # zones = client.athlete_zones
19
+ #
20
+ # # Heart rate zones
21
+ # if zones.heart_rate
22
+ # zones.heart_rate.zones.each_with_index do |zone, i|
23
+ # puts "HR Zone #{i + 1}: #{zone.min}-#{zone.max} bpm"
24
+ # end
25
+ # end
26
+ #
27
+ # # Power zones
28
+ # if zones.power
29
+ # zones.power.zones.each_with_index do |zone, i|
30
+ # puts "Power Zone #{i + 1}: #{zone.min}-#{zone.max}W"
31
+ # end
32
+ # end
33
+ #
6
34
  class Zones < Strava::Models::Response
35
+ # @return [HeartRateZoneRanges, nil] Heart rate zone configuration with zone ranges
7
36
  property 'heart_rate', transform_with: ->(v) { Strava::Models::HeartRateZoneRanges.new(v) }
37
+
38
+ # @return [PowerZoneRanges, nil] Power zone configuration with zone ranges (for cyclists)
8
39
  property 'power', transform_with: ->(v) { Strava::Models::PowerZoneRanges.new(v) }
9
40
  end
10
41
  end
@@ -2,9 +2,50 @@
2
2
 
3
3
  module Strava
4
4
  module OAuth
5
+ #
6
+ # OAuth client for Strava authentication.
7
+ #
8
+ # This client handles the OAuth 2.0 authentication flow with Strava, including:
9
+ # * Generating authorization URLs
10
+ # * Exchanging authorization codes for access tokens
11
+ # * Refreshing expired access tokens
12
+ #
13
+ # @example Basic OAuth flow
14
+ # client = Strava::OAuth::Client.new(
15
+ # client_id: "your_client_id",
16
+ # client_secret: "your_client_secret"
17
+ # )
18
+ #
19
+ # # Step 1: Get authorization URL
20
+ # url = client.authorize_url(
21
+ # redirect_uri: 'http://localhost:3000/callback',
22
+ # scope: 'read,activity:read_all'
23
+ # )
24
+ # # Redirect user to this URL
25
+ #
26
+ # # Step 2: Exchange code for token
27
+ # token = client.oauth_token(code: params[:code])
28
+ # # Store token.access_token and token.refresh_token
29
+ #
30
+ # # Step 3: Refresh token when expired
31
+ # new_token = client.oauth_token(
32
+ # refresh_token: saved_refresh_token,
33
+ # grant_type: 'refresh_token'
34
+ # )
35
+ #
36
+ # @see https://developers.strava.com/docs/authentication/
37
+ #
5
38
  class Client < Strava::Web::Client
6
39
  attr_accessor(*Config::ATTRIBUTES)
7
40
 
41
+ #
42
+ # Initialize a new OAuth client.
43
+ #
44
+ # @param [Hash] options Configuration options
45
+ # @option options [String] :client_id Strava application client ID (required)
46
+ # @option options [String] :client_secret Strava application client secret (required)
47
+ # @option options [String] :endpoint OAuth endpoint URL (defaults to https://www.strava.com/oauth)
48
+ #
8
49
  def initialize(options = {})
9
50
  Strava::OAuth::Config::ATTRIBUTES.each do |key|
10
51
  send("#{key}=", options[key] || Strava::OAuth.config.send(key))
@@ -13,20 +54,31 @@ module Strava
13
54
  end
14
55
 
15
56
  #
16
- # Obtain the request access URL.
17
- #
18
- # @option options [Object] :redirect_uri
19
- # URL to which the user will be redirected after authentication.
20
- # @option options [Object] :response_type
21
- # Must be code.
22
- # @option options [Object] :approval_prompt
23
- # Prompt behavior, force or auto.
24
- # @option options [Object] :scope
25
- # Requested scopes, as a comma delimited string.
26
- # @option options [Object] :state
27
- # Returned in the redirect URI.
57
+ # Generate the authorization URL for OAuth flow.
58
+ #
59
+ # Creates a URL to redirect users to for Strava authorization. After the user
60
+ # authorizes your application, they will be redirected back to your redirect_uri
61
+ # with an authorization code.
62
+ #
63
+ # @param [Hash] options Authorization parameters
64
+ # @option options [String] :redirect_uri URL where user is redirected after authorization (default: http://localhost)
65
+ # @option options [String] :response_type Must be 'code' (default: 'code')
66
+ # @option options [String] :approval_prompt 'force' to always show approval page, 'auto' to auto-approve (default: 'auto')
67
+ # @option options [String] :scope Comma-delimited string of permissions (default: 'read')
68
+ # Available scopes: read, read_all, profile:read_all, profile:write, activity:read, activity:read_all, activity:write
69
+ # @option options [String] :state Optional value returned in redirect URI for CSRF protection
70
+ #
71
+ # @return [String] Full authorization URL
72
+ #
73
+ # @example Generate authorization URL
74
+ # url = client.authorize_url(
75
+ # redirect_uri: 'https://myapp.com/callback',
76
+ # scope: 'read,activity:read_all,activity:write',
77
+ # state: 'random_state_value'
78
+ # )
79
+ #
28
80
  # @see https://developers.strava.com/docs/authentication/
29
- # @return [String] URL to redirect the user to.
81
+ #
30
82
  def authorize_url(options = {})
31
83
  query = options.merge(
32
84
  client_id: client_id || raise(ArgumentError, 'Missing Strava client id.'),
@@ -40,14 +92,33 @@ module Strava
40
92
  end
41
93
 
42
94
  #
43
- # Complete the authentication process.
95
+ # Exchange authorization code for access token or refresh an expired token.
96
+ #
97
+ # This method handles two OAuth flows:
98
+ # 1. Initial token exchange: Exchange authorization code for access/refresh tokens
99
+ # 2. Token refresh: Use refresh_token to get new access/refresh tokens
100
+ #
101
+ # @param [Hash] options Token request parameters
102
+ # @option options [String] :code Authorization code from redirect (for initial exchange)
103
+ # @option options [String] :refresh_token Refresh token (for token refresh)
104
+ # @option options [String] :grant_type Grant type: 'authorization_code' (default) or 'refresh_token'
105
+ #
106
+ # @return [Strava::Models::Token] Token object with access_token, refresh_token, expires_at, and athlete
107
+ #
108
+ # @example Exchange authorization code for token
109
+ # token = client.oauth_token(code: 'authorization_code_from_redirect')
110
+ # access_token = token.access_token
111
+ # refresh_token = token.refresh_token
112
+ # expires_at = token.expires_at
113
+ #
114
+ # @example Refresh an expired token
115
+ # new_token = client.oauth_token(
116
+ # refresh_token: 'saved_refresh_token',
117
+ # grant_type: 'refresh_token'
118
+ # )
44
119
  #
45
- # @option options [Object] :code
46
- # The code parameter obtained in the redirect.
47
- # @option options [Object] :grant_type
48
- # The grant type for the request.
49
120
  # @see https://developers.strava.com/docs/authentication/
50
- # @return [Hash] Token information.
121
+ #
51
122
  def oauth_token(options = {})
52
123
  query = options.merge(
53
124
  client_id: client_id || raise(ArgumentError, 'Missing Strava client id.'),
@@ -59,10 +130,27 @@ module Strava
59
130
  end
60
131
 
61
132
  class << self
133
+ #
134
+ # Configure the OAuth client with a block.
135
+ #
136
+ # @yield [Config] Yields the configuration module for setup
137
+ # @return [Module] The Config module
138
+ #
139
+ # @example
140
+ # Strava::OAuth::Client.configure do |config|
141
+ # config.client_id = ENV['STRAVA_CLIENT_ID']
142
+ # config.client_secret = ENV['STRAVA_CLIENT_SECRET']
143
+ # end
144
+ #
62
145
  def configure
63
146
  block_given? ? yield(Config) : Config
64
147
  end
65
148
 
149
+ #
150
+ # Returns the current OAuth client configuration.
151
+ #
152
+ # @return [Module] The Config module
153
+ #
66
154
  def config
67
155
  Config
68
156
  end
@@ -2,9 +2,25 @@
2
2
 
3
3
  module Strava
4
4
  module OAuth
5
+ #
6
+ # Configuration module for the OAuth client.
7
+ #
8
+ # This module manages OAuth-specific configuration settings including the
9
+ # OAuth endpoint URL and application credentials (client ID and secret)
10
+ # required for token exchange and refresh operations.
11
+ #
12
+ # @example Configure OAuth client
13
+ # Strava::OAuth.configure do |config|
14
+ # config.client_id = ENV['STRAVA_CLIENT_ID']
15
+ # config.client_secret = ENV['STRAVA_CLIENT_SECRET']
16
+ # end
17
+ #
18
+ # @see https://developers.strava.com/docs/authentication/
19
+ #
5
20
  module Config
6
21
  extend self
7
22
 
23
+ # @return [Array<Symbol>] List of configurable OAuth attributes
8
24
  ATTRIBUTES = %i[
9
25
  endpoint
10
26
  client_id
@@ -13,6 +29,14 @@ module Strava
13
29
 
14
30
  attr_accessor(*Config::ATTRIBUTES)
15
31
 
32
+ #
33
+ # Reset configuration to default values.
34
+ #
35
+ # Sets the endpoint to the default Strava OAuth URL and clears
36
+ # the client credentials.
37
+ #
38
+ # @return [void]
39
+ #
16
40
  def reset
17
41
  self.endpoint = 'https://www.strava.com/oauth'
18
42
  self.client_id = nil
@@ -21,10 +45,27 @@ module Strava
21
45
  end
22
46
 
23
47
  class << self
48
+ #
49
+ # Configure the OAuth client with a block.
50
+ #
51
+ # @yield [Config] Yields the configuration module for setup
52
+ # @return [Module] The Config module
53
+ #
54
+ # @example
55
+ # Strava::OAuth.configure do |config|
56
+ # config.client_id = '12345'
57
+ # config.client_secret = 'your_client_secret'
58
+ # end
59
+ #
24
60
  def configure
25
61
  block_given? ? yield(Config) : Config
26
62
  end
27
63
 
64
+ #
65
+ # Returns the current OAuth configuration.
66
+ #
67
+ # @return [Module] The Config module
68
+ #
28
69
  def config
29
70
  Config
30
71
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Strava
4
- VERSION = '3.0.0.pre.2'
4
+ VERSION = '3.1.0'
5
5
  end
@@ -2,11 +2,37 @@
2
2
 
3
3
  module Strava
4
4
  module Web
5
+ #
6
+ # Wraps an HTTP response with rate limit information.
7
+ #
8
+ # This class provides access to both the raw HTTP response and
9
+ # parsed rate limit data from the response headers.
10
+ #
11
+ # @see Strava::Api::Ratelimit
12
+ # @see Strava::Models::Mixins::HttpResponse
13
+ #
14
+ # @example Accessing response data
15
+ # activity = client.activity(1234567890)
16
+ # api_response = activity.http_response
17
+ #
18
+ # # Access raw HTTP response
19
+ # status = api_response.response.status
20
+ # headers = api_response.response.headers
21
+ #
22
+ # # Access rate limit information
23
+ # puts "Requests remaining: #{api_response.ratelimit.fifteen_minutes_remaining}"
24
+ #
5
25
  class ApiResponse
6
- attr_accessor :response, :ratelimit
26
+ # @return [Faraday::Response] The raw HTTP response
27
+ attr_accessor :response
7
28
 
29
+ # @return [Strava::Api::Ratelimit] Rate limit information extracted from response headers
30
+ attr_accessor :ratelimit
31
+
32
+ #
33
+ # Initialize a new ApiResponse with an HTTP response.
8
34
  #
9
- # @param [Faraday::Response] http_response
35
+ # @param http_response [Faraday::Response] HTTP response from the Strava API
10
36
  #
11
37
  def initialize(http_response)
12
38
  @response = http_response
@@ -2,12 +2,35 @@
2
2
 
3
3
  module Strava
4
4
  module Web
5
+ #
6
+ # Base web client class for making HTTP requests to Strava APIs.
7
+ #
8
+ # This class provides the foundation for all Strava client implementations
9
+ # (API, OAuth, and Webhooks clients). It handles HTTP connection management,
10
+ # request execution, and configuration management.
11
+ #
12
+ # The client includes mixins for connection handling and HTTP request methods,
13
+ # and manages configuration attributes like endpoint URLs, user agents, and
14
+ # authentication tokens.
15
+ #
16
+ # @see Strava::Web::Connection
17
+ # @see Strava::Web::Request
18
+ #
5
19
  class Client
6
20
  include Strava::Web::Connection
7
21
  include Strava::Web::Request
8
22
 
9
23
  attr_accessor(*Config::ATTRIBUTES)
10
24
 
25
+ #
26
+ # Initialize a new client instance.
27
+ #
28
+ # @param options [Hash] Configuration options for the client
29
+ # @option options [String] :endpoint The API endpoint URL
30
+ # @option options [String] :user_agent The user agent string
31
+ # @option options [String] :token The access token for authentication
32
+ # @option options [Logger] :logger Custom logger instance
33
+ #
11
34
  def initialize(options = {})
12
35
  Strava::Web::Config::ATTRIBUTES.each do |key|
13
36
  send("#{key}=", options[key] || Strava::Web.config.send(key))
@@ -15,26 +38,73 @@ module Strava
15
38
  @logger ||= Strava::Logger.logger
16
39
  end
17
40
 
41
+ #
42
+ # Returns the API endpoint URL for this client.
43
+ #
44
+ # @note This method must be implemented by subclasses
45
+ # @raise [NotImplementedError] if not implemented by subclass
46
+ # @return [String] The API endpoint URL
47
+ #
18
48
  def endpoint
19
49
  raise NotImplementedError
20
50
  end
21
51
 
22
52
  class << self
53
+ #
54
+ # Configure the client with a block or return the configuration.
55
+ #
56
+ # @yield [Config] Yields the configuration module for setup
57
+ # @return [Module] The Config module
58
+ #
59
+ # @example Configure the client
60
+ # Strava::Web::Client.configure do |config|
61
+ # config.endpoint = 'https://www.strava.com/api/v3'
62
+ # end
63
+ #
23
64
  def configure
24
65
  block_given? ? yield(Config) : Config
25
66
  end
26
67
 
68
+ #
69
+ # Returns the current configuration.
70
+ #
71
+ # @return [Module] The Config module
72
+ #
27
73
  def config
28
74
  Config
29
75
  end
30
76
  end
31
77
 
78
+ #
79
+ # Parse method arguments that can be either (id, options) or (options).
80
+ #
81
+ # This helper method standardizes the common pattern where Strava API methods
82
+ # accept either a resource ID as the first parameter followed by an options hash,
83
+ # or just an options hash containing an :id key.
84
+ #
85
+ # @param id_or_options [String, Integer, Hash] Either a resource ID or options hash
86
+ # @param options [Hash] Options hash (when first param is an ID)
87
+ #
88
+ # @raise [ArgumentError] if the :id is missing from the options hash
89
+ #
90
+ # @return [Array<(String, Hash)>] Tuple of [id, options]
91
+ #
92
+ # @example With separate ID and options
93
+ # parse_args('12345', {per_page: 10})
94
+ # # => ['12345', {per_page: 10}]
95
+ #
96
+ # @example With ID in options hash
97
+ # parse_args({id: '12345', per_page: 10})
98
+ # # => ['12345', {per_page: 10}]
99
+ #
32
100
  def parse_args(id_or_options, options = {})
33
101
  if id_or_options.is_a?(Hash)
34
- throw ArgumentError.new('Required argument :id missing') if id_or_options[:id].nil?
102
+ raise ArgumentError, 'Required argument :id missing' if id_or_options[:id].nil?
103
+
35
104
  [id_or_options[:id], id_or_options.except(:id)]
36
105
  else
37
- throw ArgumentError.new('Required argument :id missing') if id_or_options.nil?
106
+ raise ArgumentError, 'Required argument :id missing' if id_or_options.nil?
107
+
38
108
  [id_or_options, options]
39
109
  end
40
110
  end
@@ -2,9 +2,24 @@
2
2
 
3
3
  module Strava
4
4
  module Web
5
+ #
6
+ # Configuration module for web client HTTP settings.
7
+ #
8
+ # This module manages HTTP-related configuration settings shared across
9
+ # all Strava web clients (API, OAuth, Webhooks), including proxy settings,
10
+ # SSL certificate validation, timeouts, and logging.
11
+ #
12
+ # @example Configure web client settings
13
+ # Strava::Web.configure do |config|
14
+ # config.user_agent = 'MyApp/1.0'
15
+ # config.timeout = 30
16
+ # config.logger = Logger.new(STDOUT)
17
+ # end
18
+ #
5
19
  module Config
6
20
  extend self
7
21
 
22
+ # @return [Array<Symbol>] List of configurable HTTP attributes
8
23
  ATTRIBUTES = %i[
9
24
  proxy
10
25
  user_agent
@@ -17,6 +32,14 @@ module Strava
17
32
 
18
33
  attr_accessor(*Config::ATTRIBUTES)
19
34
 
35
+ #
36
+ # Reset configuration to default values.
37
+ #
38
+ # Sets the user agent to the default client identifier and clears
39
+ # all optional settings (proxy, SSL certificates, timeouts, logger).
40
+ #
41
+ # @return [void]
42
+ #
20
43
  def reset
21
44
  self.user_agent = "Strava Ruby Client/#{Strava::VERSION}"
22
45
  self.ca_path = nil
@@ -29,10 +52,27 @@ module Strava
29
52
  end
30
53
 
31
54
  class << self
55
+ #
56
+ # Configure the web client with a block.
57
+ #
58
+ # @yield [Config] Yields the configuration module for setup
59
+ # @return [Module] The Config module
60
+ #
61
+ # @example
62
+ # Strava::Web.configure do |config|
63
+ # config.proxy = 'http://proxy.example.com:8080'
64
+ # config.ca_file = '/path/to/ca-bundle.crt'
65
+ # end
66
+ #
32
67
  def configure
33
68
  block_given? ? yield(Config) : Config
34
69
  end
35
70
 
71
+ #
72
+ # Returns the current web client configuration.
73
+ #
74
+ # @return [Module] The Config module
75
+ #
36
76
  def config
37
77
  Config
38
78
  end
@@ -2,13 +2,52 @@
2
2
 
3
3
  module Strava
4
4
  module Web
5
+ #
6
+ # HTTP connection management for Strava web clients.
7
+ #
8
+ # This module provides connection handling and configuration for making HTTP
9
+ # requests to Strava APIs. It sets up a Faraday connection with proper headers,
10
+ # middleware, SSL configuration, and timeout settings.
11
+ #
12
+ # The connection is configured with:
13
+ # - JSON request and response handling
14
+ # - Automatic error raising for failed responses
15
+ # - Optional logging
16
+ # - SSL certificate validation
17
+ # - Request timeouts
18
+ #
19
+ # @api private
20
+ #
5
21
  module Connection
6
22
  private
7
23
 
24
+ #
25
+ # Returns HTTP headers to be included in requests.
26
+ #
27
+ # This method can be overridden in including classes to provide
28
+ # custom headers (e.g., authentication headers).
29
+ #
30
+ # @api private
31
+ # @return [Hash] HTTP headers hash
32
+ #
8
33
  def headers
9
34
  {}
10
35
  end
11
36
 
37
+ #
38
+ # Establishes and returns a Faraday HTTP connection.
39
+ #
40
+ # Creates a memoized Faraday connection configured with:
41
+ # - Base endpoint URL
42
+ # - Custom headers including Accept and User-Agent
43
+ # - Proxy settings if configured
44
+ # - SSL certificate paths
45
+ # - Request timeouts
46
+ # - Middleware stack for multipart, URL encoding, error handling, and JSON parsing
47
+ #
48
+ # @api private
49
+ # @return [Faraday::Connection] Configured Faraday connection instance
50
+ #
12
51
  def connection
13
52
  @connection ||= begin
14
53
  options = {