runkeeper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.dev ADDED
@@ -0,0 +1,3 @@
1
+ export RUBYLIB=`pwd`/lib
2
+ export RUBYOPT=rubygems
3
+ export PATH=`pwd`/bin:$PATH
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ vendor
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in runkeeper.gemspec
4
+ gemspec
@@ -0,0 +1,9 @@
1
+ # Runkeeper API Client
2
+ ## Work in progress - accepting patches
3
+
4
+ ## Example
5
+ user = Runkeeper.new("user token")
6
+ puts user.name
7
+ activity = user.new_activity(:duration => 60, :type => "Swimming", :distance => 1000
8
+ activity.save
9
+ puts user.activity_url(activity)
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'runkeeper'
3
+ require 'runkeeper/token_generator'
4
+
5
+ Runkeeper::Connection.authorize
@@ -0,0 +1,22 @@
1
+ require 'httparty'
2
+ require 'json'
3
+
4
+ class Runkeeper
5
+ require 'runkeeper/version'
6
+
7
+ autoload 'Connection', 'runkeeper/connection'
8
+ autoload 'User', 'runkeeper/user'
9
+ autoload 'Activity', 'runkeeper/activity'
10
+ autoload 'Configuration', 'runkeeper/configuration'
11
+
12
+ private :initialize
13
+
14
+ def self.new(token)
15
+ Runkeeper::User.new(token)
16
+ end
17
+
18
+ def self.configure
19
+ yield Configuration
20
+ end
21
+
22
+ end
@@ -0,0 +1,54 @@
1
+ class Runkeeper
2
+
3
+ class Activity
4
+ attr_reader :connection, :url
5
+ attr_reader :type, :start_time, :total_distance, :duration, :average_heart_rate, :total_calories, :notes, :path, :post_to_facebook, :post_to_twitter
6
+
7
+ def initialize(connection, attrs)
8
+ @connection = connection
9
+ @attrs = attrs
10
+ attrs.each do |k,v|
11
+ instance_variable_set("@#{k}", v)
12
+ end
13
+ end
14
+
15
+ def save
16
+ @save_response = connection.save_activity(to_hash)
17
+ end
18
+
19
+ def id
20
+ @save_response && @save_response.headers['location'][/\d+$/]
21
+ end
22
+
23
+ def formatted_start_time
24
+ start_time.strftime("%a, %d %b %Y %H:%M:%S")
25
+ end
26
+
27
+ def to_hash
28
+ main = {
29
+ :type => type,
30
+ :start_time => formatted_start_time,
31
+ :duration => duration
32
+ }
33
+ main.merge! optional_attrs
34
+ end
35
+
36
+ def optional_attrs
37
+ h = {}
38
+ [
39
+ :total_distance,
40
+ :average_heart_rate,
41
+ :total_calories,
42
+ :notes,
43
+ :path,
44
+ :post_to_facebook,
45
+ :post_to_twitter
46
+ ].each do |method_name|
47
+ v = send(method_name)
48
+ h[method_name] = v if v
49
+ end
50
+ h
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,24 @@
1
+ class Runkeeper
2
+
3
+ module Configuration
4
+ extend self
5
+ attr_writer :client_id, :client_secret, :authorization_url, :access_token_url
6
+
7
+ def client_id
8
+ @client_id || ENV['CLIENT_ID']
9
+ end
10
+
11
+ def client_secret
12
+ @client_secret || ENV['CLIENT_SECRET']
13
+ end
14
+
15
+ def authorization_url
16
+ @authorization_url || ENV['AUTHORIZATION_URL']
17
+ end
18
+
19
+ def access_token_url
20
+ @access_token_url || ENV['ACCESS_TOKEN_URL']
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,71 @@
1
+ class Runkeeper
2
+
3
+ class Connection
4
+ include HTTParty
5
+ base_uri "http://api.runkeeper.com"
6
+ format :json
7
+ debug_output
8
+
9
+ ACCEPT_HEADERS = {
10
+ :user => "application/vnd.com.runkeeper.User+json",
11
+ :fitness_activities => "application/vnd.com.runkeeper.FitnessActivityFeed+json",
12
+ :past_activities => "application/vnd.com.runkeeper.FitnessActivity+json",
13
+ :records => "application/vnd.com.runkeeper.Records+json",
14
+ :profile => "application/vnd.com.runkeeper.Profile+json",
15
+ :new_activity => "application/vnd.com.runkeeper.NewFitnessActivity+json"
16
+ }
17
+
18
+ attr_reader :token, :user_response
19
+
20
+ def initialize(token)
21
+ @token = token
22
+ @auth_header = {"Authorization" => "Bearer #{token}"}
23
+ user
24
+ end
25
+
26
+ def user
27
+ @user_response = self.class.get('/user', :headers => headers(:user))
28
+ end
29
+
30
+ def profile
31
+ self.class.get(user_response['profile'], :headers => headers(:profile))
32
+ end
33
+
34
+ def fitness_activities
35
+ self.class.get(user_response['fitness_activities'], :headers => headers(:fitness_activities))
36
+ end
37
+
38
+ def past_activities
39
+ self.class.get(user_response['fitness_activities'], :headers => headers(:past_activities))
40
+ end
41
+
42
+ def records
43
+ self.class.get(user_response['records'], :headers => headers(:records))
44
+ end
45
+
46
+ def save_activity(hash)
47
+ self.class.post(user_response['fitness_activities'], :headers => headers(:new_activity), :body => hash.to_json)
48
+ end
49
+
50
+ def self.post_authorization(code, uri)
51
+ response = post(Configuration.access_token_url, :query => {
52
+ :grant_type => 'authorization_code',
53
+ :code => code,
54
+ :client_id => Configuration.client_id,
55
+ :client_secret => Configuration.client_secret,
56
+ :redirect_uri => uri
57
+ })
58
+ response['access_token']
59
+ end
60
+
61
+ private
62
+
63
+ def headers(resource)
64
+ @auth_header.merge(
65
+ "Accept" => ACCEPT_HEADERS[resource],
66
+ "Content-Type" => ACCEPT_HEADERS[resource]
67
+ )
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,78 @@
1
+ begin
2
+ require 'rack'
3
+ require 'launchy'
4
+ rescue LoadError
5
+ puts "rack and launchy are required"
6
+ end
7
+
8
+ class Runkeeper
9
+ class AuthorizationServer
10
+ class App
11
+ attr_reader :code, :env, :server
12
+
13
+ def initialize(server)
14
+ @server = server
15
+ end
16
+
17
+ def call(env)
18
+ @env = env
19
+ if params['code']
20
+ @code = params['code']
21
+ [200, { 'Content-Type' => 'text/html' }, ['Check the console for your token.']]
22
+ else
23
+ [404, { 'Content-Type' => 'text/html' }, ['']]
24
+ end
25
+ end
26
+
27
+ def params
28
+ @params ||= begin
29
+ ary = env['QUERY_STRING'].split('&').map {|s| s.split('=', 2)}
30
+ Hash[*ary.flatten]
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ def app
37
+ @app ||= App.new(self)
38
+ end
39
+
40
+ def has_code?
41
+ !code.nil?
42
+ end
43
+
44
+ def code
45
+ app.code
46
+ end
47
+
48
+ def uri
49
+ @uri ||= URI.parse('http://localhost:8989')
50
+ end
51
+
52
+ def server
53
+ @server ||= Rack::Server.new :app => app, :Port => uri.port, :server => 'webrick'
54
+ end
55
+
56
+ def start
57
+ server.start
58
+ end
59
+
60
+ def stop
61
+ server.server.shutdown
62
+ end
63
+ end
64
+
65
+ class Connection
66
+
67
+ def self.authorize
68
+ server = Runkeeper::AuthorizationServer.new
69
+ uri = URI.parse(Configuration.authorization_url)
70
+ uri.query = "client_id=#{Configuration.client_id}&response_type=code&redirect_uri=#{server.uri}"
71
+ Launchy.open(uri.to_s)
72
+ t1 = Thread.new { server.start }
73
+ t1.join(0.5) until server.has_code?
74
+ server.stop
75
+ puts "Access Token: #{post_authorization(server.code, server.uri)}"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,47 @@
1
+ class Runkeeper
2
+
3
+ class User
4
+ attr_reader :connection, :token
5
+
6
+ def initialize(token)
7
+ @token = token
8
+ @connection = Connection.new(token)
9
+ end
10
+
11
+ # Profile methods
12
+ [:name, :location, :athlete_type, :goal, :gender, :birthday, :elite, :profile, :small_picture, :normal_picture, :medium_picture, :large_picture].each do |method_name|
13
+ define_method method_name do
14
+ user_profile[method_name.to_s]
15
+ end
16
+ end
17
+ alias elite? elite
18
+
19
+ def id
20
+ connection.user_response['userID']
21
+ end
22
+
23
+ def fitness_activities
24
+ connection.fitness_activities
25
+ end
26
+
27
+ def past_activities
28
+ connection.past_activities
29
+ end
30
+
31
+ def new_activity(attrs={})
32
+ Activity.new(connection, attrs)
33
+ end
34
+
35
+ def activity_url(activity)
36
+ File.join(profile, "activity", activity.id)
37
+ end
38
+
39
+ private
40
+
41
+ def user_profile
42
+ @user_profile ||= connection.profile
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,3 @@
1
+ class Runkeeper
2
+ VERSION = "0.0.1".freeze
3
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "runkeeper/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "runkeeper"
7
+ s.version = Runkeeper::VERSION.dup
8
+ s.authors = ["Sandro Turriate"]
9
+ s.email = ["sandro.turriate@gmail.com"]
10
+ s.homepage = "http://github.com/sandro/runkeeper"
11
+ s.summary = %q(Runkeeper API client.)
12
+ s.description = %q(Runkeeper API client.)
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+ s.add_dependency "httparty"
19
+ s.add_development_dependency 'rack'
20
+ s.add_development_dependency 'launchy'
21
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: runkeeper
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Sandro Turriate
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-07-09 00:00:00 -06:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: httparty
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: launchy
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id003
49
+ description: Runkeeper API client.
50
+ email:
51
+ - sandro.turriate@gmail.com
52
+ executables:
53
+ - token_generator
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - .dev
60
+ - .gitignore
61
+ - .rvmrc
62
+ - Gemfile
63
+ - README.markdown
64
+ - Rakefile
65
+ - bin/token_generator
66
+ - lib/runkeeper.rb
67
+ - lib/runkeeper/activity.rb
68
+ - lib/runkeeper/configuration.rb
69
+ - lib/runkeeper/connection.rb
70
+ - lib/runkeeper/token_generator.rb
71
+ - lib/runkeeper/user.rb
72
+ - lib/runkeeper/version.rb
73
+ - runkeeper.gemspec
74
+ has_rdoc: true
75
+ homepage: http://github.com/sandro/runkeeper
76
+ licenses: []
77
+
78
+ post_install_message:
79
+ rdoc_options: []
80
+
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ requirements: []
96
+
97
+ rubyforge_project:
98
+ rubygems_version: 1.6.2
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Runkeeper API client.
102
+ test_files: []
103
+