runkeeper 0.0.1

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.
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
+