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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +41 -57
  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,87 +2,288 @@
2
2
 
3
3
  module Strava
4
4
  module Models
5
- # https://developers.strava.com/docs/reference/#api-models-DetailedActivity
5
+ #
6
+ # Represents a detailed Strava activity.
7
+ #
8
+ # A detailed activity contains all information about a single workout, ride, run,
9
+ # or other athletic pursuit recorded on Strava. This includes basic information
10
+ # (name, type, date), metrics (distance, time, elevation), maps, segments, photos,
11
+ # and social interactions (kudos, comments).
12
+ #
13
+ # This model includes several mixins that provide helper methods for formatting data:
14
+ # * {Mixins::Distance} - distance_s, distance_in_miles, etc.
15
+ # * {Mixins::MovingTime} - moving_time_in_hours_s, etc.
16
+ # * {Mixins::ElapsedTime} - elapsed_time_in_hours_s, etc.
17
+ # * {Mixins::AverageSpeed} - average_speed_s, pace_s, etc.
18
+ # * {Mixins::TotalElevationGain} - total_elevation_gain_s, etc.
19
+ # * {Mixins::SportType} - sport_type_emoji
20
+ #
21
+ # @example Get and display activity details
22
+ # activity = client.activity(1234567890)
23
+ # puts activity.name
24
+ # puts "Distance: #{activity.distance_s}"
25
+ # puts "Time: #{activity.moving_time_in_hours_s}"
26
+ # puts "Pace: #{activity.pace_s}"
27
+ # puts "Elevation: #{activity.total_elevation_gain_s}"
28
+ # puts "URL: #{activity.strava_url}"
29
+ #
30
+ # @see https://developers.strava.com/docs/reference/#api-models-DetailedActivity
31
+ #
6
32
  class DetailedActivity < Strava::Models::Response
33
+ # @return [Integer] Activity ID
7
34
  property 'id'
35
+
36
+ # @return [String, nil] External ID from the original upload source
8
37
  property 'external_id'
38
+
39
+ # @return [Integer, nil] Upload ID
9
40
  property 'upload_id'
41
+
42
+ # @return [MetaAthlete] The athlete who performed the activity
10
43
  property 'athlete', transform_with: ->(v) { Strava::Models::MetaAthlete.new(v) }
44
+
45
+ # @return [String] Activity name
11
46
  property 'name'
47
+
12
48
  include Mixins::Distance
13
49
  include Mixins::MovingTime
14
50
  include Mixins::ElapsedTime
15
51
  include Mixins::AverageSpeed
16
52
  include Mixins::TotalElevationGain
53
+
54
+ # @return [Float, nil] Highest elevation in meters
17
55
  property 'elev_high'
56
+
57
+ # @return [Float, nil] Lowest elevation in meters
18
58
  property 'elev_low'
59
+
19
60
  include Mixins::SportType
61
+
62
+ # @return [Time] Start date and time (UTC)
20
63
  property 'start_date', transform_with: ->(v) { Time.parse(v) }
64
+
21
65
  include Mixins::StartDateLocal
66
+
67
+ # @return [String] Timezone in which the activity was recorded (e.g., '(GMT-08:00) America/Los_Angeles')
22
68
  property 'timezone'
69
+
70
+ # @return [LatLng, nil] Starting coordinates [latitude, longitude]
23
71
  property 'start_latlng', transform_with: ->(v) { Strava::Models::LatLng.new(v) }
72
+
73
+ # @return [LatLng, nil] Ending coordinates [latitude, longitude]
24
74
  property 'end_latlng', transform_with: ->(v) { Strava::Models::LatLng.new(v) }
75
+
76
+ # @return [Integer] Number of achievements (segment PRs, CRs, etc.)
25
77
  property 'achievement_count'
78
+
79
+ # @return [Integer] Number of kudos received
26
80
  property 'kudos_count'
81
+
82
+ # @return [Integer] Number of comments
27
83
  property 'comment_count'
84
+
85
+ # @return [Integer] Number of athletes who participated (group activities)
28
86
  property 'athlete_count'
87
+
88
+ # @return [Integer] Number of photos attached
29
89
  property 'photo_count'
90
+
91
+ # @return [Integer] Total number of photos including Instagram
30
92
  property 'total_photo_count'
93
+
94
+ # @return [Map] Activity map with polyline data
31
95
  property 'map', transform_with: ->(v) { Strava::Models::Map.new(v) }
96
+
97
+ # @return [Boolean] Whether this activity was on a stationary trainer
32
98
  property 'trainer'
99
+
100
+ # @return [Boolean] Whether this activity was a commute
33
101
  property 'commute'
102
+
103
+ # @return [Boolean] Whether this activity was manually entered
34
104
  property 'manual'
105
+
106
+ # @return [Boolean] Whether this activity is set to private
35
107
  property 'private'
108
+
109
+ # @return [Boolean] Whether this activity has been flagged
36
110
  property 'flagged'
111
+
112
+ # @return [Integer, nil] Workout type (e.g., 10 = Race, 11 = Workout)
37
113
  property 'workout_type'
114
+
115
+ # @return [String, nil] Upload ID as a string
38
116
  property 'upload_id_str'
117
+
118
+ # @return [Float] Average speed in meters per second
39
119
  property 'average_speed'
120
+
121
+ # @return [Float] Maximum speed in meters per second
40
122
  property 'max_speed'
123
+
124
+ # @return [Boolean] Whether the authenticated athlete has kudoed this activity
41
125
  property 'has_kudoed'
126
+
127
+ # @return [Boolean] Whether to hide this activity from the home feed
42
128
  property 'hide_from_home'
129
+
130
+ # @return [String, nil] Gear (bike/shoes) ID used for this activity
43
131
  property 'gear_id'
132
+
133
+ # @return [Float, nil] Kilojoules of energy expended
44
134
  property 'kilojoules'
135
+
136
+ # @return [Float, nil] Average power in watts
45
137
  property 'average_watts'
138
+
139
+ # @return [Boolean, nil] Whether the watts are from a power meter (true) or estimated (false)
46
140
  property 'device_watts'
141
+
142
+ # @return [Integer, nil] Maximum power in watts
47
143
  property 'max_watts'
144
+
145
+ # @return [Integer, nil] Weighted average power in watts
48
146
  property 'weighted_average_watts'
147
+
148
+ # @return [String, nil] Activity description
49
149
  property 'description'
150
+
151
+ # @return [PhotosSummary, nil] Summary of activity photos
50
152
  property 'photos', transform_with: ->(v) { Strava::Models::PhotosSummary.new(v) }
153
+
154
+ # @return [SummaryGear, nil] The gear (bike/shoes) used for this activity
51
155
  property 'gear', transform_with: ->(v) { Strava::Models::SummaryGear.new(v) }
156
+
157
+ # @return [Float, nil] Estimated calories burned
52
158
  property 'calories'
159
+
160
+ # @return [Array<DetailedSegmentEffort>] All segment efforts for this activity
53
161
  property 'segment_efforts', transform_with: ->(v) { v.map { |r| Strava::Models::DetailedSegmentEffort.new(r) } }
162
+
163
+ # @return [String, nil] Name of the device used to record the activity
54
164
  property 'device_name'
165
+
166
+ # @return [String, nil] Embed token for the activity
55
167
  property 'embed_token'
168
+
169
+ # @return [Array<Split>] Metric splits (per kilometer)
56
170
  property 'splits_metric', transform_with: ->(v) { v.map { |r| Strava::Models::Split.new(r) } }
171
+
172
+ # @return [Array<Split>] Standard/imperial splits (per mile)
57
173
  property 'splits_standard', transform_with: ->(v) { v.map { |r| Strava::Models::Split.new(r) } }
174
+
175
+ # @return [Array<Lap>] Laps for the activity
58
176
  property 'laps', transform_with: ->(v) { v.map { |r| Strava::Models::Lap.new(r) } }
177
+
178
+ # @return [Array<DetailedSegmentEffort>] Best efforts (e.g., 400m, 1/2 mile, 1k, etc.)
59
179
  property 'best_efforts', transform_with: ->(v) { v.map { |r| Strava::Models::DetailedSegmentEffort.new(r) } }
60
- # undocumented
180
+
181
+ # @note Undocumented in official API
182
+ # @return [Integer, nil] Resource state indicator
61
183
  property 'resource_state'
184
+
185
+ # @note Undocumented in official API
186
+ # @return [Float, nil] UTC offset in seconds
62
187
  property 'utc_offset'
188
+
189
+ # @note Undocumented in official API
190
+ # @return [String, nil] City where the activity took place
63
191
  property 'location_city'
192
+
193
+ # @note Undocumented in official API
194
+ # @return [String, nil] State/province where the activity took place
64
195
  property 'location_state'
196
+
197
+ # @note Undocumented in official API
198
+ # @return [String, nil] Country where the activity took place
65
199
  property 'location_country'
200
+
201
+ # @note Undocumented in official API
202
+ # @return [String, nil] Activity visibility setting (e.g., 'everyone', 'followers_only')
66
203
  property 'visibility'
204
+
205
+ # @note Undocumented in official API
206
+ # @return [Float, nil] Average temperature during the activity in Celsius
67
207
  property 'average_temp'
208
+
209
+ # @note Undocumented in official API
210
+ # @return [Boolean, nil] Whether the activity has heart rate data
68
211
  property 'has_heartrate'
212
+
213
+ # @note Undocumented in official API
214
+ # @return [Float, nil] Average heart rate in beats per minute
69
215
  property 'average_heartrate'
216
+
217
+ # @note Undocumented in official API
218
+ # @return [Float, nil] Maximum heart rate in beats per minute
70
219
  property 'max_heartrate'
220
+
221
+ # @note Undocumented in official API
222
+ # @return [Boolean, nil] Whether the athlete has opted out of heart rate display
71
223
  property 'heartrate_opt_out'
224
+
225
+ # @note Undocumented in official API
226
+ # @return [Boolean, nil] Whether to display the hide heart rate option
72
227
  property 'display_hide_heartrate_option'
228
+
229
+ # @note Undocumented in official API
230
+ # @return [Boolean, nil] Whether the activity was created from an accepted tag
73
231
  property 'from_accepted_tag'
232
+
233
+ # @note Undocumented in official API
234
+ # @return [Integer, nil] Number of personal records achieved in this activity
74
235
  property 'pr_count'
236
+
237
+ # @note Undocumented in official API
238
+ # @return [Integer, nil] Relative effort score (suffer score)
75
239
  property 'suffer_score'
240
+
241
+ # @note Undocumented in official API
242
+ # @return [Integer, nil] Athlete's perceived exertion rating
76
243
  property 'perceived_exertion'
244
+
245
+ # @note Undocumented in official API
246
+ # @return [Boolean, nil] Whether to prefer perceived exertion over calculated metrics
77
247
  property 'prefer_perceived_exertion'
248
+
249
+ # @note Undocumented in official API
250
+ # @return [Array<StatsVisibility>, nil] Stats visibility settings
78
251
  property 'stats_visibility', transform_with: ->(v) { v.map { |r| Strava::Models::StatsVisibility.new(r) } }
252
+
253
+ # @note Undocumented in official API
254
+ # @return [Array<String>, nil] List of available zone types for this activity
79
255
  property 'available_zones'
256
+
257
+ # @note Undocumented in official API
258
+ # @return [SimilarActivities, nil] Information about similar activities
80
259
  property 'similar_activities', transform_with: ->(v) { Strava::Models::SimilarActivities.new(v) }
260
+
261
+ # @note Undocumented in official API
262
+ # @return [Float, nil] Average cadence (RPM for cycling, steps/minute for running)
81
263
  property 'average_cadence'
264
+
265
+ # @note Undocumented in official API
266
+ # @return [Array, nil] List of highlighted athletes who gave kudos
82
267
  property 'highlighted_kudosers'
268
+
269
+ # @note Undocumented in official API
270
+ # @return [Boolean, nil] Whether the athlete has opted out of segment leaderboards
83
271
  property 'segment_leaderboard_opt_out'
272
+
273
+ # @note Undocumented in official API
274
+ # @return [Boolean, nil] Whether the athlete has opted out of all leaderboards
84
275
  property 'leaderboard_opt_out'
85
276
 
277
+ #
278
+ # Returns the Strava web URL for this activity.
279
+ #
280
+ # @return [String] Full URL to view the activity on Strava.com
281
+ #
282
+ # @example
283
+ # activity = client.activity(1234567890)
284
+ # puts activity.strava_url
285
+ # # => "https://www.strava.com/activities/1234567890"
286
+ #
86
287
  def strava_url
87
288
  "https://www.strava.com/activities/#{id}"
88
289
  end
@@ -2,47 +2,149 @@
2
2
 
3
3
  module Strava
4
4
  module Models
5
- # https://developers.strava.com/docs/reference/#api-models-DetailedAthlete
5
+ #
6
+ # Represents detailed information about a Strava athlete.
7
+ #
8
+ # Contains comprehensive profile information including personal details,
9
+ # preferences, gear, clubs, and social connections. This model is typically
10
+ # returned when accessing the authenticated athlete's own profile.
11
+ #
12
+ # @example Get athlete profile
13
+ # athlete = client.athlete
14
+ # puts athlete.name
15
+ # puts "Location: #{athlete.city}, #{athlete.state}, #{athlete.country}"
16
+ # puts "Premium: #{athlete.premium}"
17
+ # puts "Weight: #{athlete.weight}kg"
18
+ # puts athlete.strava_url
19
+ #
20
+ # @see SummaryAthlete
21
+ # @see https://developers.strava.com/docs/reference/#api-models-DetailedAthlete
22
+ #
6
23
  class DetailedAthlete < Strava::Models::Response
24
+ # @return [Integer] Athlete ID
7
25
  property 'id'
26
+
27
+ # @return [Integer] Resource state indicator
8
28
  property 'resource_state'
29
+
30
+ # @return [String] First name
9
31
  property 'firstname'
32
+
33
+ # @return [String] Last name
10
34
  property 'lastname'
35
+
36
+ # @return [String, nil] URL to medium-sized profile picture
11
37
  property 'profile_medium'
38
+
39
+ # @return [String, nil] URL to full-sized profile picture
12
40
  property 'profile'
41
+
42
+ # @return [String, nil] City
13
43
  property 'city'
44
+
45
+ # @return [String, nil] State or province
14
46
  property 'state'
47
+
48
+ # @return [String, nil] Country
15
49
  property 'country'
50
+
51
+ # @return [String] Sex ('M' for male, 'F' for female)
16
52
  property 'sex'
53
+
54
+ # @return [Boolean] Whether the athlete has a premium subscription
17
55
  property 'premium'
56
+
57
+ # @return [Boolean] Whether the athlete has a Summit subscription
18
58
  property 'summit'
59
+
60
+ # @return [Time] When the athlete account was created
19
61
  property 'created_at', transform_with: ->(v) { Time.parse(v) }
62
+
63
+ # @return [Time] When the athlete account was last updated
20
64
  property 'updated_at', transform_with: ->(v) { Time.parse(v) }
65
+
66
+ # @return [Integer] Number of followers
21
67
  property 'follower_count'
68
+
69
+ # @return [Integer] Number of friends (mutual follows)
22
70
  property 'friend_count'
71
+
72
+ # @return [String] Preferred measurement system ('feet' or 'meters')
23
73
  property 'measurement_preference'
74
+
75
+ # @return [Integer, nil] Functional Threshold Power in watts
24
76
  property 'ftp'
77
+
78
+ # @return [Float, nil] Weight in kilograms
25
79
  property 'weight'
80
+
81
+ # @return [Array<SummaryClub>] Clubs the athlete belongs to
26
82
  property 'clubs', transform_with: ->(v) { v.map { |r| Strava::Models::SummaryClub.new(r) } }
83
+
84
+ # @return [Array<SummaryGear>] Bikes registered to this athlete
27
85
  property 'bikes', transform_with: ->(v) { v.map { |r| Strava::Models::SummaryGear.new(r) } }
86
+
87
+ # @return [Array<SummaryGear>] Shoes registered to this athlete
28
88
  property 'shoes', transform_with: ->(v) { v.map { |r| Strava::Models::SummaryGear.new(r) } }
29
- # undocumented
89
+
90
+ # @note Undocumented in official API
91
+ # @return [String, nil] Username/vanity URL
30
92
  property 'username'
93
+
94
+ # @note Undocumented in official API
95
+ # @return [String, nil] Athlete bio/description
31
96
  property 'bio'
97
+
98
+ # @note Undocumented in official API
99
+ # @return [Integer, nil] Badge type identifier
32
100
  property 'badge_type_id'
101
+
102
+ # @note Undocumented in official API
103
+ # @return [String, nil] Relationship status with authenticated athlete ('pending', 'accepted', 'blocked', or nil)
33
104
  property 'friend'
105
+
106
+ # @note Undocumented in official API
107
+ # @return [String, nil] Follower relationship status
34
108
  property 'follower'
109
+
110
+ # @note Undocumented in official API
111
+ # @return [Boolean, nil] Whether this athlete is blocked by the authenticated athlete
35
112
  property 'blocked'
113
+
114
+ # @note Undocumented in official API
115
+ # @return [Boolean, nil] Whether the authenticated athlete can follow this athlete
36
116
  property 'can_follow'
117
+
118
+ # @note Undocumented in official API
119
+ # @return [Integer, nil] Number of mutual friends with the authenticated athlete
37
120
  property 'mutual_friend_count'
121
+
122
+ # @note Undocumented in official API
123
+ # @return [Integer, nil] Athlete type identifier (0 = Cyclist, 1 = Runner)
38
124
  property 'athlete_type'
125
+
126
+ # @note Undocumented in official API
127
+ # @return [String, nil] Preferred date format
39
128
  property 'date_preference'
129
+
130
+ # @note Undocumented in official API
131
+ # @return [Integer, nil] Number of clubs where athlete can post
40
132
  property 'postable_clubs_count'
41
133
 
134
+ #
135
+ # Returns the athlete's full name.
136
+ #
137
+ # @return [String, nil] Full name combining firstname and lastname, or nil if neither exists
138
+ #
42
139
  def name
43
140
  [firstname, lastname].compact.join(' ') if firstname || lastname
44
141
  end
45
142
 
143
+ #
144
+ # Returns the Strava web URL for this athlete's profile.
145
+ #
146
+ # @return [String] Full URL to view the athlete on Strava.com
147
+ #
46
148
  def strava_url
47
149
  "https://www.strava.com/athletes/#{username || id}"
48
150
  end
@@ -2,37 +2,111 @@
2
2
 
3
3
  module Strava
4
4
  module Models
5
- # https://developers.strava.com/docs/reference/#api-models-DetailedClub
5
+ #
6
+ # Represents detailed information about a Strava club.
7
+ #
8
+ # Clubs are groups of athletes on Strava. This model contains comprehensive
9
+ # club information including member counts, location, sport type, and membership
10
+ # status for the authenticated athlete.
11
+ #
12
+ # @example Get club details
13
+ # club = client.club(12345)
14
+ # puts club.name
15
+ # puts "#{club.member_count} members in #{club.city}, #{club.country}"
16
+ # puts "Sport type: #{club.sport_type}"
17
+ # puts "Private: #{club.private}"
18
+ # puts club.strava_url
19
+ #
20
+ # @see SummaryClub
21
+ # @see https://developers.strava.com/docs/reference/#api-models-DetailedClub
22
+ #
6
23
  class DetailedClub < Strava::Models::Response
24
+ # @return [Integer] Club identifier
7
25
  property 'id'
26
+
27
+ # @return [Integer] Resource state indicator (1=meta, 2=summary, 3=detailed)
8
28
  property 'resource_state'
29
+
30
+ # @return [String] Club name
9
31
  property 'name'
32
+
33
+ # @return [String] URL to medium-sized profile picture
10
34
  property 'profile_medium'
35
+
36
+ # @return [String] URL to club cover photo
11
37
  property 'cover_photo'
38
+
39
+ # @return [String] URL to smaller club cover photo
12
40
  property 'cover_photo_small'
41
+
42
+ # @return [String] Primary sport type (e.g., "cycling", "running", "other")
13
43
  property 'sport_type'
44
+
45
+ # @return [Array<String>] List of activity types the club supports
14
46
  property 'activity_types'
47
+
48
+ # @return [String] City where club is located
15
49
  property 'city'
50
+
51
+ # @return [String] State/province where club is located
16
52
  property 'state'
53
+
54
+ # @return [String] Country where club is located
17
55
  property 'country'
56
+
57
+ # @return [Boolean] Whether club is private
18
58
  property 'private'
59
+
60
+ # @return [Integer] Number of club members
19
61
  property 'member_count'
62
+
63
+ # @return [Boolean] Whether club is featured by Strava
20
64
  property 'featured'
65
+
66
+ # @return [Boolean] Whether club is verified by Strava
21
67
  property 'verified'
68
+
69
+ # @return [String] Club URL slug
22
70
  property 'url'
71
+
72
+ # @return [String] Authenticated athlete's membership status (e.g., "member", "pending")
23
73
  property 'membership'
74
+
75
+ # @return [Boolean] Whether authenticated athlete is a club administrator
24
76
  property 'admin'
77
+
78
+ # @return [Boolean] Whether authenticated athlete is the club owner
25
79
  property 'owner'
80
+
81
+ # @return [String] Type of club (e.g., "casual_club", "racing_team", "shop", "company", "other")
26
82
  property 'club_type'
83
+
84
+ # @return [Integer] Number of athletes following this club
27
85
  property 'following_count'
28
- # undocumented
86
+
87
+ # @return [String] URL to full-sized profile picture
29
88
  property 'profile'
89
+
90
+ # @return [String] Icon representing the activity types
30
91
  property 'activity_types_icon'
92
+
93
+ # @return [Array<Integer>] Dimensions of cover photo [width, height]
31
94
  property 'dimensions'
95
+
96
+ # @return [String] Localized sport type string
32
97
  property 'localized_sport_type'
98
+
99
+ # @return [String] Club description text
33
100
  property 'description'
101
+
102
+ # @return [String] Club website URL
34
103
  property 'website'
35
104
 
105
+ #
106
+ # Returns the Strava web URL for this club.
107
+ #
108
+ # @return [String] Full URL to view the club on Strava.com
109
+ #
36
110
  def strava_url
37
111
  "https://www.strava.com/clubs/#{url || id}"
38
112
  end
@@ -2,22 +2,65 @@
2
2
 
3
3
  module Strava
4
4
  module Models
5
- # https://developers.strava.com/docs/reference/#api-models-DetailedGear
5
+ #
6
+ # Represents detailed information about an athlete's equipment/gear.
7
+ #
8
+ # Gear includes bikes, shoes, and other equipment that athletes track mileage on.
9
+ # Each piece of gear has a name, brand, model, and accumulated distance.
10
+ #
11
+ # Includes the Distance mixin for formatting accumulated distance.
12
+ #
13
+ # @example Get gear details
14
+ # gear = client.gear('b12345')
15
+ # puts gear.name
16
+ # puts "#{gear.brand_name} #{gear.model_name}"
17
+ # puts "Total distance: #{gear.distance_s}"
18
+ # puts "Weight: #{gear.weight}g" if gear.weight
19
+ # puts "Retired" if gear.retired
20
+ #
21
+ # @see SummaryGear
22
+ # @see https://developers.strava.com/docs/reference/#api-models-DetailedGear
23
+ #
6
24
  class DetailedGear < Strava::Models::Response
25
+ # @return [String] Gear identifier (e.g., "b12345" for bike, "g12345" for shoes)
7
26
  property 'id'
27
+
28
+ # @return [Integer] Resource state indicator
8
29
  property 'resource_state'
30
+
31
+ # @return [Boolean] Whether this is the athlete's primary gear for this type
9
32
  property 'primary'
33
+
34
+ # @return [String] Gear name/title
10
35
  property 'name'
36
+
11
37
  include Mixins::Distance
38
+
39
+ # @return [String] Brand/manufacturer name
12
40
  property 'brand_name'
41
+
42
+ # @return [String] Model name
13
43
  property 'model_name'
44
+
45
+ # @return [Integer] Frame type identifier (for bikes)
14
46
  property 'frame_type'
47
+
48
+ # @return [String] Gear description/notes
15
49
  property 'description'
16
- # undocumented
50
+
51
+ # @return [String] Nickname for the gear
17
52
  property 'nickname'
53
+
54
+ # @return [Boolean] Whether gear has been retired/is no longer in use
18
55
  property 'retired'
56
+
57
+ # @return [Float] Distance in meters after conversion (likely for imperial users)
19
58
  property 'converted_distance'
59
+
60
+ # @return [Float] Distance threshold for maintenance notifications (in meters)
20
61
  property 'notification_distance'
62
+
63
+ # @return [Float] Weight of the gear in grams
21
64
  property 'weight'
22
65
  end
23
66
  end