strava 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a1efb647025be551ec6e630abf80a97c8e27abbe
4
+ data.tar.gz: 5606afa633091032f33c3063e58de9192b4c0051
5
+ SHA512:
6
+ metadata.gz: dae3f482ababb5ce3cc075dd96a3ddae4f900c9cbd73b72abcfe58a26f5bb9508820268ac1be090189a6369ccc9620d9aa53f44e1d90de9fdbae44405f2c9839
7
+ data.tar.gz: ee1709355ceb9f6b2ddb57fb95ba6c3c910da4b2031ab9e119bc4d24a0071d8a4e79fcd9d31c788e5a17d11ae0c0065a3edef27f69df7e7d4a244d74da507087
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .rbenv-vars
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.3
5
+ - 2.4.1
6
+ before_install: gem install bundler -v 1.14.6
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup=markdown
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in strava.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'redcarpet'
8
+ gem 'pry'
9
+ gem 'pry-byebug'
10
+ gem 'simplecov'
11
+ gem 'benchmark-ips'
12
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Paul Hoffer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,302 @@
1
+ # Strava
2
+
3
+ Interact with [Strava's v3 API](https://strava.github.io/api/). This gem is designed to be fully object oriented, so most interaction is with Strava objects. There is an existing gem [strava-api-v3](https://github.com/jaredholdcroft/strava-api-v3), which has been around much longer and has some extra functionality. It is more functional and typically deals with JSON data.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'strava'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install strava
20
+
21
+ ## API Notes
22
+
23
+ ### Detail Level
24
+
25
+ All Strava resources have a detail level, `{1 => meta, 2 => summary, 3 => detailed}`. Objects will have a `#get_details` method which retrieves the full object details, if supported and not already fetched.
26
+
27
+ ### Pagination
28
+
29
+ Many Strava endpoints support optional pagination. All of these endpoints accept `:page` and `:per_page` options. These can be used like `athlete.activities(page: 3)`. Refer to the [API Coverage](#api-coverage) section for a list of endpoints supporting pagination.
30
+
31
+ All method calls including pagination will trigger an API call and return the items from that call. Any calls without pagination will return all previously downloaded items. If no requests have been made, a request without pagination will be made.
32
+
33
+ ## Functionality
34
+
35
+ ### Configuration
36
+
37
+ This is not necessary, as only the webhooks API requires application information. The values shown below are used by default if not configured manually.
38
+
39
+ ```ruby
40
+ Strava.client_id = ENV['STRAVA_CLIENT_ID']
41
+ Strava.secret = ENV['STRAVA_CLIENT_SECRET']
42
+ ```
43
+
44
+ ### Current Athlete
45
+
46
+ Generally, most of the Strava API is based off the authenticated user. Thus, most of the gem's functionality flows from the athlete class (either authenticated user or another).
47
+
48
+ The quickest way to get started is with the currently authenticated athlete:
49
+
50
+ ```ruby
51
+ ca = Strava::Athlete.current_athlete(access_token) # => Strava::Athlete
52
+ ```
53
+
54
+ There is also a mixin for existing classes (i.e. models). It is agnostic to DBs/adapters/etc, and only requires a method for the access token.
55
+
56
+ ```ruby
57
+ class Account < ApplicationRecord
58
+ include Strava.model as: :athlete, via: :token, id: :strava_id
59
+ end
60
+ ca = Account.find(1).athlete # => Strava::Athlete
61
+ ```
62
+
63
+ This will add an instance method `#athlete` to the `User` class. This returns a `Strava::Athlete`, populating the access token with `User#token` and the user ID with `User#strava_id`. All 3 parameters are optional, and the default parameters are `{ via: :access_token, as: :strava_athlete, id: nil }`.
64
+
65
+ It can also be used to go through another method, for instance, if you have separate user and account models:
66
+
67
+ ```ruby
68
+ class User < ApplicationRecord
69
+ has_one :account
70
+ include Strava.model as: :athlete, via: 'account.token', id: 'account.strava_id'
71
+ end
72
+ ca = User.find(1).athlete # => Strava::Athlete
73
+ ```
74
+
75
+ ### Classes
76
+
77
+ Most use cases won't include manually instantiating classes. Instead, interaction starts with a user and then flows through related objects. If desired, classes can be instantiated, with two requirements:
78
+
79
+ 1. First argument must be either the object ID (string or integer accepted), or a hash with an `'id'` key.
80
+ 1. Either the `token` or `client` keyword argument must be passed. All API interaction requires an access_token, so instantiation does too.
81
+
82
+ ```ruby
83
+ act = Strava::Activity.new(321934, token: '83ebeabdec09f6670863766f792ead24d61fe3f9')
84
+ act = Strava::Activity.new({'id' => 321934}, client: Strava::Client.new('83ebeabdec09f6670863766f792ead24d61fe3f9'))
85
+ ```
86
+
87
+ ## Usage
88
+
89
+ ### Athlete
90
+
91
+ [Strava Docs](https://strava.github.io/api/v3/athlete/)
92
+
93
+ Strava uses the phrase _currently authenticated athlete_ throughout their docs, so we'll use the term _current_ to represent that athlete. With the current athlete from above, we can request data for that athlete. Some APIs can only be made on behalf of the current athlete. See Strava docs for further information.
94
+
95
+ ```ruby
96
+ ca.get_details # => retrieves full representation of the athlete
97
+ ca.email # => "john@applestrava.com"
98
+ ca.firstname # => "John"
99
+ ca.lastname # => "Applestrava"
100
+ ca.stats # => Hash of athlete stats
101
+ ca.zones # => Array of HR/power zones (hash)
102
+ ca.koms # => [Strava::SegmentEffort]
103
+ ca.friends # => [Strava::Athlete]
104
+ ca.followers # => [Strava::Athlete]
105
+ ca.both_following(other_id) # => [Strava::Athlete]
106
+
107
+ # listed in docs other than athlete docs
108
+ ca.clubs # => [Strava::Club]
109
+ ca.routes # => [Strava::Route]
110
+ ca.starred_segments # => [Strava::Segment]
111
+ ```
112
+
113
+ ### Activity
114
+
115
+ [Strava Docs](https://strava.github.io/api/v3/activities/)
116
+
117
+ Strava provides extensive data on activities.
118
+
119
+ ```ruby
120
+ activity = ca.activities.first # => Strava::Activity
121
+ activity.get_details # => retrieves full representation of the activity
122
+ activity.comments # => [Strava::Comment]
123
+ activity.kudos # => [Strava::Kudo]
124
+ activity.photos # => [Strava::Photo]
125
+ activity.related # => [Strava::Activity] activities that were matched as “with this group”
126
+ activity.zones # => Array of HR/Power zones
127
+ activity.laps # => [Strava::Lap]
128
+ activity.streams # => [Strava::StreamSet] Without args, will retrieve time, distance, latlng streams
129
+
130
+ # Strava Partner APIs
131
+ activity.comment(message) # => Create a comment on an activity
132
+ activity.kudo # => Kudo an activity
133
+ ```
134
+
135
+ ### Club
136
+
137
+ [Strava Docs](https://strava.github.io/api/v3/clubs/)
138
+
139
+ ```ruby
140
+ club = ca.clubs.first # => Strava::Club
141
+ club.get_details # => retrieves full representation of the club
142
+ club.activities # => [Strava::Activity]
143
+ club.group_events # => [Strava::GroupEvent]
144
+ club.announcements # => [Strava::ClubAnnouncment]
145
+ club.members # => [Strava::Athlete]
146
+ club.admins # => [Strava::Athlete]
147
+ club.join # => Join the club as current athlete. Returns hash for success or failure
148
+ club.leave # => Leave the club as current athlete. Returns hash for success or failure
149
+ ```
150
+
151
+ ### Group Event
152
+
153
+ [Strava Docs](https://strava.github.io/api/v3/club_group_events/)
154
+
155
+ ```ruby
156
+ ge = club.group_events.first # => Strava::GroupEvent
157
+ ge.get_details # => retrieves full representation of the group event
158
+ ge.athletes # => [Strava::Athlete]
159
+ ge.delete # => Delete group event. Must have edit permissions. Returns hash of success/failure
160
+ ge.join # => Join the event as current athlete. Returns hash of success/failure
161
+ ge.leave # => Leave the event as current athlete. Returns hash of success/failure
162
+ ```
163
+
164
+ ### Gear
165
+
166
+ [Strava Docs](https://strava.github.io/api/v3/gear/)
167
+
168
+ ```ruby
169
+ gear = ca.gear.first # => Strava::Gear
170
+ gear.get_details # => retrieves full representation of the gear
171
+ ```
172
+
173
+ ### Route
174
+
175
+ [Strava Docs](https://strava.github.io/api/v3/routes/)
176
+
177
+ ```ruby
178
+ route = ca.routes.first # => Strava::Route
179
+ route.get_details # => retrieves full representation of the route
180
+ route.streams # => [Strava::StreamSet] Retrieves distance, altitude, latlng streams (no other streams available).
181
+ ```
182
+
183
+ ### Running Race
184
+
185
+ [Strava Docs](https://strava.github.io/api/v3/running_races/)
186
+
187
+ Races are different, as they don't flow from the current athlete. However, the Race APIs still require authentication. As such, there are a couple ways to retrieve races:
188
+
189
+ ```ruby
190
+ # List races via the current athlete. Probably the simplest way.
191
+ races = ca.list_races
192
+
193
+ # List races via the `RunningRace` class. Must provide an API client.
194
+ client = Strava::Client.new('83ebeabdec09f6670863766f792ead24d61fe3f9')
195
+ races = RunningRace.list_races(client)
196
+
197
+ # List races via a client. The gem is designed to minimize interaction with the Client class, but it's available if desired.
198
+ client = Strava::Client.new('83ebeabdec09f6670863766f792ead24d61fe3f9')
199
+ races = client.list_races
200
+
201
+ # All methods accept an optional argument for the year:
202
+ races = ca.list_races(2016)
203
+ races = RunningRace.list_races(client, 2016)
204
+ races = client.list_races(2016)
205
+
206
+ # The only API interaction available for a race is to retrieve more details.
207
+ races.first.get_details # Returns the race, with full representation.
208
+ ```
209
+
210
+ ### Segment
211
+
212
+ [Strava Docs](https://strava.github.io/api/v3/segments/)
213
+
214
+ ```ruby
215
+ segment = ca.starred_segments.first # => Strava::Segment
216
+ segment.get_details # => retrieves full representation of the segment
217
+ segment.efforts # => [Strava::SegmentEffort] Segment efforts for the current athlete
218
+ segment.streams # => [Strava::StreamSet] Retrieves distance, altitude, latlng streams (no other streams available).
219
+ segment.star # => Star the segment, on behalf of current athlete. Returns hash of success/failure.
220
+ segment.unstar # => Unstar the segment, on behalf of current athlete. Returns hash of success/failure.
221
+
222
+ # segment explorer is similar to the running races API. It can be called via a user:
223
+ bounds = '37.821362,-122.505373,37.842038,-122.465977' # => ‘south,west,north,east
224
+ ca.segment_explorer(bounds)
225
+
226
+ # Or via the `Segment` class. Must provide an API client.
227
+ segments = Segment.explorer(client, bounds)
228
+
229
+ # or via a client (discouraged)
230
+ client.segment_explorer(bounds)
231
+ ```
232
+
233
+
234
+ ### Segment Effort
235
+
236
+ [Strava Docs](https://strava.github.io/api/v3/efforts/)
237
+
238
+ ```ruby
239
+ effort = segment.efforts.first # => Strava::SegmentEffort
240
+ effort.get_details # => retrieves full representation of the segment
241
+ effort.streams # => [Strava::StreamSet] Retrieves distance, altitude, latlng streams (no other streams available).
242
+ ```
243
+
244
+ ### StreamSet
245
+
246
+ [Strava Docs](https://strava.github.io/api/v3/streams/)
247
+
248
+ ```ruby
249
+ activity.streams
250
+ activity.streams.all
251
+ ```
252
+
253
+ ### Uploads
254
+
255
+ [Strava Docs](https://strava.github.io/api/v3/uploads/)
256
+
257
+ Uploads haven't been implemented yet :( It will be soon though!
258
+
259
+ ### Auth
260
+
261
+ [Strava Docs](https://strava.github.io/api/v3/oauth/)
262
+
263
+ Auth hasn't been implemented yet :( However, most apps are probably using omniauth, so this is a bit lower on the priority list.
264
+
265
+ ### Webhooks
266
+
267
+ [Strava Docs](https://strava.github.io/api/v3/events/)
268
+
269
+ Webhooks haven't been implemented yet :( It will be soon though!
270
+
271
+ ## TODO
272
+
273
+ 1. Continue adding YARD Documentation
274
+ 1. Add tests
275
+ 1. Submit PRs to existing gem
276
+
277
+ ## Why
278
+
279
+ Comparison to existing gem.
280
+
281
+ Q. Why aren't there tests?
282
+ A. Tests are in progress. Unfortunately, there is no test environment for Strava, and virtually everything is based on hitting their API.
283
+
284
+ Q. Why not contribute to the existing gem?
285
+ A. I'm planning on it! But I also wanted something a bit more OO, and wanted to see what I could come up with.
286
+
287
+
288
+ ## Development
289
+
290
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
291
+
292
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
293
+
294
+ ## Contributing
295
+
296
+ Bug reports and pull requests are welcome on GitHub at https://github.com/phoffer/strava.
297
+
298
+
299
+ ## License
300
+
301
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
302
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "strava"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "pry"
14
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/strava.rb ADDED
@@ -0,0 +1,79 @@
1
+ require 'strava/version'
2
+ require 'strava/error'
3
+ require 'strava/usage'
4
+ require 'strava/client'
5
+ require 'strava/base'
6
+ require 'strava/gear'
7
+ require 'strava/segment'
8
+ require 'strava/segment_effort'
9
+ require 'strava/leaderboard'
10
+ require 'strava/leaderboard_entry'
11
+ require 'strava/athlete'
12
+ require 'strava/route'
13
+ require 'strava/activity'
14
+ require 'strava/stream_set'
15
+ require 'strava/stream'
16
+ require 'strava/lap'
17
+ require 'strava/comment'
18
+ require 'strava/photo'
19
+ require 'strava/club'
20
+ require 'strava/group_event'
21
+ require 'strava/club_announcement'
22
+ require 'strava/running_race'
23
+
24
+ module Strava
25
+
26
+ class << self
27
+ # @return [Integer, String] Strava Application ID
28
+ attr_writer :client_id
29
+ # @return [String] Strava Application secret
30
+ attr_writer :client_secret
31
+
32
+ # Helper for model classes.
33
+ # Allows for convenient instantiation of current athlete.
34
+ # This is completely agnostic to class type, it can be a DB model, a PORO, etc.
35
+ #
36
+ # Usage:
37
+ #
38
+ # class Account < ApplicationRecord
39
+ # include Strava.model as: :athlete, via: :token, id: :strava_id
40
+ # end
41
+ # ca = Account.find(1).athlete # => Strava::Athlete
42
+ #
43
+ # Can also perform lookup through another method:
44
+ #
45
+ # class User < ApplicationRecord
46
+ # has_one :account
47
+ # include Strava.model as: :athlete, via: 'account.token', id: 'account.strava_id'
48
+ # end
49
+ #
50
+ # @param as [Symbol] method to define to return current athlete
51
+ # @param via [Symbol, String] method to lookup access token
52
+ # @param id [Symbol, String] method to lookup Strava ID
53
+ # @return [Module] module to be included in the calling class
54
+ def model(as: :strava_athlete, via: :access_token, id: nil)
55
+ Module.new.tap do |mod|
56
+ str = <<~EOF
57
+ def self.included(base)
58
+ base.send(:define_method, :#{as}) { ::Strava::Athlete.new(#{id ? "{'id' => #{id}}" : '{}' }, token: #{via}, current: true) }
59
+ end
60
+ EOF
61
+ mod.class_eval str
62
+ end
63
+ end
64
+
65
+ # def adapter(name = :httparty)
66
+ # require "strava/adapters/#{name}"
67
+ # Client.include(Adapters.httparty)
68
+ # end
69
+
70
+ # @return [Integer, String] Strava Application ID
71
+ def client_id
72
+ @client_id ||= ENV['STRAVA_CLIENT_ID']
73
+ end
74
+ # @return [String] Strava Application secret
75
+ def client_secret
76
+ @client_secret ||= ENV['STRAVA_CLIENT_SECRET']
77
+ end
78
+ end
79
+ end