strava-api-v2 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rvmrc +60 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +100 -0
- data/Rakefile +9 -0
- data/lib/strava/base_connection.rb +29 -0
- data/lib/strava/exceptions.rb +7 -0
- data/lib/strava/strava_response.rb +5 -0
- data/lib/strava/v1/clubs_request.rb +20 -0
- data/lib/strava/v1/connection.rb +22 -0
- data/lib/strava/v1/models/athlete.rb +15 -0
- data/lib/strava/v1/models/club.rb +14 -0
- data/lib/strava/v1/models/effort.rb +17 -0
- data/lib/strava/v1/models/ride.rb +23 -0
- data/lib/strava/v1/models/segment.rb +19 -0
- data/lib/strava/v1/models/stream.rb +17 -0
- data/lib/strava/v1/rides_request.rb +60 -0
- data/lib/strava/v1/segments_request.rb +31 -0
- data/lib/strava/v1/streams_request.rb +15 -0
- data/lib/strava/v2/auth_request.rb +17 -0
- data/lib/strava/v2/connection.rb +27 -0
- data/lib/strava/v2/efforts_request.rb +21 -0
- data/lib/strava/v2/models/athlete.rb +15 -0
- data/lib/strava/v2/models/auth.rb +15 -0
- data/lib/strava/v2/models/effort.rb +19 -0
- data/lib/strava/v2/models/segment.rb +26 -0
- data/lib/strava/v2/segments_request.rb +21 -0
- data/lib/strava/version.rb +3 -0
- data/strava-api-v2.gemspec +26 -0
- data/test/auth_test.rb +32 -0
- data/test/clubs_test.rb +31 -0
- data/test/efforts_v2_test.rb +34 -0
- data/test/rides_v1_test.rb +62 -0
- data/test/segments_v1_request_test.rb +39 -0
- data/test/segments_v2_request_test.rb +47 -0
- data/test/stream_test.rb +30 -0
- data/test/test_data.rb +52 -0
- data/test/v1_connection_test.rb +37 -0
- data/test/v2_connection_test.rb +37 -0
- metadata +190 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'strava/v1/models/segment'
|
2
|
+
|
3
|
+
module Strava
|
4
|
+
module V1
|
5
|
+
module SegmentRequest
|
6
|
+
SEGMENT_PARAMS_MAP = {
|
7
|
+
:club_id => :clubId,
|
8
|
+
:athlete_id => :athleteId,
|
9
|
+
:athlete_name => :athleteName,
|
10
|
+
:start_date => :startDate,
|
11
|
+
:end_date => :endDate,
|
12
|
+
:start_id => :startId,
|
13
|
+
:best => :best
|
14
|
+
}
|
15
|
+
|
16
|
+
def efforts_for_segment_path(id)
|
17
|
+
"segments/#{id}/efforts"
|
18
|
+
end
|
19
|
+
|
20
|
+
def segment_with_efforts(id, params = {})
|
21
|
+
final_params = {}
|
22
|
+
params.each_pair do |key, value|
|
23
|
+
raise RequestError.new if SEGMENT_PARAMS_MAP[key].nil?
|
24
|
+
final_params[SEGMENT_PARAMS_MAP[key]] = value
|
25
|
+
end
|
26
|
+
all_json = self.fetch(efforts_for_segment_path(id), final_params)
|
27
|
+
Segment.new(all_json["segment"], all_json["efforts"])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'strava/v2/models/auth'
|
2
|
+
|
3
|
+
module Strava
|
4
|
+
module V2
|
5
|
+
module AuthRequest
|
6
|
+
def login_path
|
7
|
+
'authentication/login'
|
8
|
+
end
|
9
|
+
|
10
|
+
def login(email, password)
|
11
|
+
auth = Auth.new(self.fetch(login_path(), {:email => email, :password => password}))
|
12
|
+
self.set_authorized_user(auth.athlete.id, auth.token)
|
13
|
+
return auth
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'strava/base_connection'
|
3
|
+
require 'strava/exceptions'
|
4
|
+
require 'strava/v2/auth_request'
|
5
|
+
require 'strava/v2/efforts_request'
|
6
|
+
require 'strava/v2/segments_request'
|
7
|
+
|
8
|
+
module Strava
|
9
|
+
module V2
|
10
|
+
class Connection
|
11
|
+
include HTTParty
|
12
|
+
include Strava::BaseConnection
|
13
|
+
include Strava::V2::AuthRequest
|
14
|
+
include Strava::V2::EffortsRequest
|
15
|
+
include Strava::V2::SegmentsRequest
|
16
|
+
|
17
|
+
attr_reader :user_id, :token
|
18
|
+
base_uri 'http://www.strava.com/api/v2'
|
19
|
+
format :json
|
20
|
+
|
21
|
+
def set_authorized_user(user_id, token)
|
22
|
+
@user_id = user_id
|
23
|
+
@token = token
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'strava/v2/models/effort'
|
2
|
+
|
3
|
+
module Strava
|
4
|
+
module V2
|
5
|
+
module EffortsRequest
|
6
|
+
def efforts_path(id)
|
7
|
+
"rides/#{id}/efforts"
|
8
|
+
end
|
9
|
+
|
10
|
+
def segments_for_ride(ride_id)
|
11
|
+
all_json = self.fetch(efforts_path(ride_id), {})
|
12
|
+
|
13
|
+
all_segments = []
|
14
|
+
all_json["efforts"].each { |effort_json|
|
15
|
+
all_segments.push(Segment.new(effort_json["segment"], [effort_json["effort"]]))
|
16
|
+
}
|
17
|
+
all_segments
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'strava/strava_response'
|
2
|
+
|
3
|
+
module Strava
|
4
|
+
module V2
|
5
|
+
class Athlete < StravaResponse
|
6
|
+
attr_reader :id, :name, :agreed_to_terms
|
7
|
+
|
8
|
+
def initialize(json_blob)
|
9
|
+
@id = json_blob["id"]
|
10
|
+
@name = json_blob["name"]
|
11
|
+
@agreed_to_terms = json_blob["agreed_to_terms"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'strava/strava_response'
|
2
|
+
require 'strava/v2/models/athlete'
|
3
|
+
|
4
|
+
module Strava
|
5
|
+
module V2
|
6
|
+
class Auth < StravaResponse
|
7
|
+
attr_reader :token, :athlete
|
8
|
+
|
9
|
+
def initialize(json_blob)
|
10
|
+
@token = json_blob["token"]
|
11
|
+
@athlete = Athlete.new(json_blob["athlete"])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'strava/strava_response'
|
2
|
+
require 'strava/v2/models/segment'
|
3
|
+
|
4
|
+
module Strava
|
5
|
+
module V2
|
6
|
+
class Effort < StravaResponse
|
7
|
+
attr_reader :id, :elapsed_time, :moving_time, :distance
|
8
|
+
|
9
|
+
# Initialize the Effort
|
10
|
+
# ejs - the effort JSON
|
11
|
+
def initialize(ejs)
|
12
|
+
@id = ejs["id"]
|
13
|
+
@elapsed_time = ejs["elapsed_time"]
|
14
|
+
@moving_time = ejs["moving_time"]
|
15
|
+
@distance = ejs["distance"]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'strava/strava_response'
|
2
|
+
require 'strava/v2/models/effort'
|
3
|
+
|
4
|
+
module Strava
|
5
|
+
module V2
|
6
|
+
class Segment < StravaResponse
|
7
|
+
attr_reader :id, :efforts, :name, :climb_category, :start_latlng, :end_latlng, :average_grade
|
8
|
+
|
9
|
+
# include the efforts in the segment, if applicable
|
10
|
+
# jb - the json for the segment
|
11
|
+
# ejb - the json for the efforts, in a list
|
12
|
+
def initialize(jb, ejb)
|
13
|
+
@id = jb["id"]
|
14
|
+
@name = jb["name"]
|
15
|
+
@climb_category = jb["climb_category"]
|
16
|
+
@start_latlng = jb["start_latlng"]
|
17
|
+
@end_latlng = jb["end_latlng"]
|
18
|
+
@average_grade = jb["avg_grade"]
|
19
|
+
@efforts = []
|
20
|
+
ejb.each { |effort_json|
|
21
|
+
@efforts.push(Effort.new(effort_json))
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'strava/v2/models/segment'
|
2
|
+
|
3
|
+
module Strava
|
4
|
+
module V2
|
5
|
+
module SegmentsRequest
|
6
|
+
def segments_and_efforts_for_ride_path(ride_id)
|
7
|
+
"rides/#{ride_id}/efforts"
|
8
|
+
end
|
9
|
+
|
10
|
+
def segments_and_efforts_for_ride(ride_id)
|
11
|
+
all_json = self.fetch(segments_and_efforts_for_ride_path(ride_id), {})
|
12
|
+
all_segments = []
|
13
|
+
all_json["efforts"].each { |effort_json|
|
14
|
+
all_segments.push(Segment.new(effort_json["segment"], [effort_json["effort"]]))
|
15
|
+
}
|
16
|
+
all_segments
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'strava/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "strava-api-v2"
|
8
|
+
spec.version = Strava::VERSION
|
9
|
+
spec.authors = ["Luke StClair"]
|
10
|
+
spec.email = ["secureboot@gmail.com"]
|
11
|
+
spec.description = %q{API to access strava API, v2}
|
12
|
+
spec.summary = %q{Provides access to the strava v1 and v2 apis, which are soon to be deprecated}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "test-unit"
|
24
|
+
spec.add_development_dependency "httparty"
|
25
|
+
spec.add_development_dependency "mocha"
|
26
|
+
end
|
data/test/auth_test.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mocha/setup'
|
3
|
+
require 'strava/v2/connection'
|
4
|
+
require 'strava/exceptions'
|
5
|
+
require 'strava/v2/models/athlete'
|
6
|
+
require 'json'
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))
|
8
|
+
require 'test_data'
|
9
|
+
|
10
|
+
class AuthTest < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@s = Strava::V2::Connection.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_successful_auth
|
17
|
+
email = 'secureboot@gmail.com'
|
18
|
+
password = 'notatallreal'
|
19
|
+
|
20
|
+
Strava::V2::Connection.stubs(:get)
|
21
|
+
.with("/#{@s.login_path}", {:query => {:email => email, :password => password}})
|
22
|
+
.returns(stub(:code => 200, :parsed_response => (JSON.parse TestData.test_login)))
|
23
|
+
result = @s.login(email, password)
|
24
|
+
assert_equal("thetoken", result.token)
|
25
|
+
# make sure the athlete parses out okay.
|
26
|
+
assert result.athlete.is_a?(Strava::V2::Athlete)
|
27
|
+
|
28
|
+
# be sure the auth for the connection gets set
|
29
|
+
assert_equal(7976, @s.user_id)
|
30
|
+
assert_equal("thetoken", @s.token)
|
31
|
+
end
|
32
|
+
end
|
data/test/clubs_test.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mocha/setup'
|
3
|
+
require 'strava/v1/connection'
|
4
|
+
require 'strava/exceptions'
|
5
|
+
require 'strava/v1/models/club'
|
6
|
+
require 'json'
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))
|
8
|
+
require 'test_data'
|
9
|
+
|
10
|
+
class ClubsTest < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@s = Strava::V1::Connection.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_clubs
|
17
|
+
club_name = "mission"
|
18
|
+
|
19
|
+
Strava::V1::Connection.stubs(:get)
|
20
|
+
.with("/clubs", {:query => {:name => club_name}})
|
21
|
+
.returns(stub(:code => 200, :parsed_response => (JSON.parse TestData.test_clubs)))
|
22
|
+
|
23
|
+
clubs = @s.clubs(club_name)
|
24
|
+
|
25
|
+
assert clubs[0].is_a?(Strava::V1::Club)
|
26
|
+
assert_equal(11, clubs.length)
|
27
|
+
first = clubs[0]
|
28
|
+
assert_equal("Mission Cycling", first.name)
|
29
|
+
assert_equal(15, first.id)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mocha/setup'
|
3
|
+
require 'strava/v2/connection'
|
4
|
+
require 'strava/exceptions'
|
5
|
+
require 'strava/v2/models/athlete'
|
6
|
+
require 'json'
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))
|
8
|
+
require 'test_data'
|
9
|
+
|
10
|
+
class EffortsV2Test < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@s = Strava::V2::Connection.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_efforts_for_ride
|
17
|
+
ride_id = 448459
|
18
|
+
Strava::V2::Connection.stubs(:get)
|
19
|
+
.with("/rides/#{ride_id}/efforts", {:query => {}})
|
20
|
+
.returns(stub(:code => 200, :parsed_response => (JSON.parse TestData.test_v2_efforts)))
|
21
|
+
segments = @s.segments_for_ride(ride_id)
|
22
|
+
effort = segments[0].efforts[0]
|
23
|
+
assert effort.is_a?(Strava::V2::Effort)
|
24
|
+
assert_equal(45665444, effort.id)
|
25
|
+
assert_equal(12, segments.length)
|
26
|
+
assert_equal(634, effort.elapsed_time)
|
27
|
+
assert_equal(634, effort.moving_time)
|
28
|
+
assert_equal(5342.8, effort.distance)
|
29
|
+
assert_equal(852034, segments[0].id)
|
30
|
+
assert_equal(1, segments[0].climb_category)
|
31
|
+
assert_equal([37.771132132038474,-122.45532101020217], segments[0].start_latlng)
|
32
|
+
assert_equal(-0.997671, segments[0].average_grade)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mocha/setup'
|
3
|
+
require 'strava/v1/connection'
|
4
|
+
require 'strava/exceptions'
|
5
|
+
require 'strava/v1/models/athlete'
|
6
|
+
require 'json'
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))
|
8
|
+
require 'test_data'
|
9
|
+
|
10
|
+
class RidesV1Test < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@s = Strava::V1::Connection.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_rides_with_no_params
|
17
|
+
Strava::V1::Connection.stubs(:get)
|
18
|
+
.with("/#{@s.rides_path}", {:query => {}})
|
19
|
+
.returns(stub(:code => 200, :parsed_response => (JSON.parse TestData.test_rides_no_params)))
|
20
|
+
result = @s.rides()
|
21
|
+
assert_equal(50, result.length)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_rides_with_invalid_param
|
25
|
+
assert_raise Strava::RequestError do
|
26
|
+
@s.rides({:made_up => "whatever"})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_rides_with_two_valid_params
|
31
|
+
Strava::V1::Connection.stubs(:get)
|
32
|
+
.with("/#{@s.rides_path}", {:query => {:startId => 77563, :offset => 50}})
|
33
|
+
.returns(stub(:code => 200, :parsed_response => (JSON.parse TestData.test_ride_start_id_and_offset)))
|
34
|
+
rides = @s.rides({:start_id => 77563, :offset => 50})
|
35
|
+
|
36
|
+
assert_equal(52127040, rides[0].id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_getting_efforts_for_a_ride
|
40
|
+
ride_id = 77563
|
41
|
+
Strava::V1::Connection.stubs(:get)
|
42
|
+
.with("/rides/#{ride_id}/efforts", {:query => {}})
|
43
|
+
.returns(stub(:code => 200, :parsed_response => (JSON.parse TestData.test_efforts)))
|
44
|
+
ride = @s.ride_with_efforts(ride_id)
|
45
|
+
assert_equal(ride_id, ride.id)
|
46
|
+
assert_equal(5819602, ride.segments[0].efforts[0].id)
|
47
|
+
assert_equal(640366, ride.segments[0].id)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_show_ride_details
|
51
|
+
ride_id = 77563
|
52
|
+
Strava::V1::Connection.stubs(:get)
|
53
|
+
.with("/rides/#{ride_id}", {:query => {}})
|
54
|
+
.returns(stub(:code => 200, :parsed_response => (JSON.parse TestData.test_show_ride_deets)))
|
55
|
+
ride = @s.ride(ride_id)
|
56
|
+
assert_equal(82369.1, ride.distance)
|
57
|
+
assert_equal(1441.02, ride.elevation_gain)
|
58
|
+
assert_equal("02/28/10 San Francisco, CA", ride.name)
|
59
|
+
assert_equal("julianbill", ride.athlete.username)
|
60
|
+
assert_equal(1139, ride.athlete.id)
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mocha/setup'
|
3
|
+
require 'strava/v1/connection'
|
4
|
+
require 'strava/v1/segments_request'
|
5
|
+
require 'strava/exceptions'
|
6
|
+
require 'json'
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))
|
8
|
+
require 'test_data'
|
9
|
+
|
10
|
+
class SegmentsV1RequestTest < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@s = Strava::V1::Connection.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_efforts_for_segment
|
17
|
+
segment_id = 229781
|
18
|
+
|
19
|
+
Strava::V1::Connection.stubs(:get)
|
20
|
+
.with("/segments/#{segment_id}/efforts", {:query => {:best => true}})
|
21
|
+
.returns(stub(:code => 200, :parsed_response => (JSON.parse TestData.test_v1_segment_efforts)))
|
22
|
+
segment = @s.segment_with_efforts(segment_id, {:best => true})
|
23
|
+
assert segment.is_a?(Strava::V1::Segment)
|
24
|
+
assert segment.efforts[0].is_a?(Strava::V1::Effort)
|
25
|
+
assert_equal(segment_id, segment.id)
|
26
|
+
assert_equal(50, segment.efforts.length)
|
27
|
+
first = segment.efforts[0]
|
28
|
+
assert_equal(801006623, first.id)
|
29
|
+
assert_equal(123529, first.athlete.id)
|
30
|
+
assert_equal("jimwhimpey", first.athlete.username)
|
31
|
+
assert_equal("Jim Whimpey", first.athlete.name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_segment_with_bad_param
|
35
|
+
assert_raise Strava::RequestError do
|
36
|
+
@s.segment_with_efforts(12345, {:made_up => "whatever"})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|