fitgem 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ test*.rb
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm ruby-1.9.2-p0@fitbit
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fitgem.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Zachery Moneypenny
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,112 @@
1
+ # Fitgem #
2
+
3
+ Provides access to fitbit.com data through their OAuth/REST API. Without user authentication, any data that the a fitbit.com user has denoted as 'public' can be gathered. If a user logs in via OAuth then all exposed data can be gathered.
4
+
5
+ The fitbit.com API is currently (March 2011) in BETA and is under development to extend its reach. Since it is early in the lifecycle of the API I expect this gem to go through a number of revisions as we attempt to match the functionality of their platform.
6
+
7
+ # Usage #
8
+
9
+ If you've ever done any oauth client programming then the model will appear familiar. Your first step, if haven't already, is to visit [https://dev.fitbit.com/](https://dev.fitbit.com/) and register your application to get your __consumer key__ and __consumer secret__ and set your __callback URL__, if appropriate for your app. There's more documentation at the site so I won't belabor it here.
10
+
11
+ Below I've included two sample scripts that use Fitgem::Client to retrieve data. One shows how to do the initial authorization _without_ doing the callback; the other shows how to use saved values from that initial authorization to reconnect with the API and get subsequent information.
12
+
13
+ require 'fitgem'
14
+
15
+ consumer_key = 'your-app-consumer-key'
16
+ consumer_secret = 'your-app-consumer-secret'
17
+
18
+ client = Fitgem::Client.new({:consumer_key => consumer_key, :consumer_secret => consumer_secret})
19
+
20
+ request_token = client.request_token
21
+ token = request_token.token
22
+ secret = request_token.secret
23
+
24
+ puts "Go to http://www.fitbit.com/oauth/authorize?oauth_token=#{token} and then enter the verifier code below and hit Enter"
25
+ verifier = gets.chomp
26
+
27
+ access_token = client.authorize(token, secret, { :oauth_verifier => verifier })
28
+
29
+ puts "Verifier is: "+verifier
30
+ puts "Token is: "+access_token.token
31
+ puts "Secret is: "+access_token.secret
32
+
33
+ After running this and successfully connecting with verifier string that is displayed by the Fitgem site, you can reconnect using the script below. To do so, take the token and secret that were printed out from the script above and paste them in where appropriate. In this example we are using the client to get the
34
+
35
+ require 'fitgem'
36
+
37
+ consumer_key = 'your-app-consumer-key'
38
+ consumer_secret = 'your-app-consumer-secret'
39
+ token = 'token-received-in-above-script'
40
+ secret = 'secret-received-in-above-script'
41
+ user_id = 'your-user-id' # may be similar to '12345N'
42
+
43
+ client = Fitgem::Client.new({:consumer_key => consumer_key, :consumer_secret => consumer_secret, :token => token, :secret => secret, :user_id => user_id})
44
+ access_token = client.reconnect(token, secret)
45
+ p client.user_info
46
+
47
+ You can use this script to learn about the data structures that are returned from different API calls. Since this library always retrieves JSON responses and then parses it into Ruby structures, you can interrogate the response data with simple calls to hashes.
48
+
49
+ ## Usage in a Rails Application ##
50
+
51
+ We've started to develop an example app using the fitgem client. See [https://github.com/whazzmaster/fitgem-client](https://github.com/whazzmaster/fitgem-client) for more information.
52
+
53
+ # Subscriptions #
54
+
55
+ The Fitbit API allows for you to set up notification subscription so that when values change (via automatic syncs with the fitbit device) your applications can be notified automatically. You can set up a default subscription callback URL via the [Fitbit dev site](https://dev.fitbit.com/ 'Fitbit Developer Site') and then use the Subscriptions API to add or remove subscriptions for individual users.
56
+
57
+ __Currently, notification management is experimental in this gem__. We've built up code to add and remove specific types of subscriptions (foods, activities, sleep, body) but there seems to be some server-side issues with creating general, all-purpose subscriptions.
58
+
59
+ The docs are very fuzzy on subscription support at the moment; we definitely plan on extending this support once the backend has matured (or the online docs have improved).
60
+
61
+ # FAQs #
62
+
63
+ ## What About ruby-fitbit? ##
64
+
65
+ There is a good looking gem called [ruby-fitbit](https://github.com/danmayer/ruby-fitbit "ruby-fitbit") that
66
+ also aims to collect data from the site. It was created before they released their REST API and uses screen-scraping to gather the data rather than through their API. I looked into forking it and refactoring
67
+ to use the new API but after looking through the code I felt it would be more of a total rewrite and so decided
68
+ to create a new gem that I could design from scratch.
69
+
70
+ ## Why the Name Change? ##
71
+
72
+ It turns out that Fitbit.com does not want people to create libraries or applications that incorporate the name 'fitbit'. So, on May 12th I changed the name of the project/gem from 'fitbit' to 'fitgem'.
73
+
74
+
75
+ # Changelog #
76
+
77
+ * 12 May, 2011:
78
+ * Changed name and all references of this project from 'fitbit' to 'fitgem'
79
+ * 11 April, 2011:
80
+ * Fixed an issue where blank user id's are used and an error is thrown.
81
+ * Added support for creating/removing subscriptions (this support is experimental for now, more tests coming)
82
+ * 24 March, 2011:
83
+ * Added logging of activities and foods
84
+ * Added ability to add favorite activities and foods
85
+ * Added ability to delete logged activities and foods, and remove favorite activities and foods
86
+ * Refactored data_by_time_range for more testability
87
+ * Added ability to query devices
88
+ * 19 March, 2011:
89
+ * Updated auth client to support first-time auth and reconnections (if you have previously been authorized and received token/secret).
90
+ * Added 'named' retrieval of activities and foods (recent_, favorite_, frequent_)
91
+ * Added ability to log weight back to the site using the API
92
+ * 18 March, 2001: First revision. Supports the auth process via oauth, and retrieval of user info and activities.
93
+
94
+ # Notice #
95
+
96
+ To be clear: __I am not employed by fitbit.com__. I created this library to assist other ruby developers in creating interesting applications on top of fitbit.com's data store and device data stream.
97
+
98
+ # Contributing to fitgem #
99
+
100
+ The Fitbit REST API is in BETA right now, and so it will quite likely change over time (though I can't be sure whether it will be additive change or change of the non-backwards-compatible variety). I aim to keep as up-to-date as I can but if you absolutely need functionality that isn't included here, feel free to fork and implement it, then send me a pull request.
101
+
102
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
103
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
104
+ * Fork the project
105
+ * Start a feature/bugfix branch
106
+ * Commit and push until you are happy with your contribution
107
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
108
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
109
+
110
+ ### Copyright ###
111
+
112
+ Copyright (c) 2011 Zachery Moneypenny. See LICENSE.txt for further details.
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ $:.push File.join(File.dirname(__FILE__), '.', 'lib')
4
+
5
+ require 'fitgem'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "fitgem"
9
+ s.version = Fitgem::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.authors = ["Zachery Moneypenny"]
12
+ s.email = ["fitgem@whazzmaster.com"]
13
+ s.homepage = "http://github.com/whazzmaster/fitgem"
14
+ s.summary = %q{OAuth client library to the data on fitbit.com}
15
+ s.description = %q{A client library to send and retrieve workout/weight data from fitbit.com}
16
+
17
+ s.rubyforge_project = "fitgem"
18
+ s.add_dependency "oauth"
19
+ s.add_development_dependency "rspec"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+ end
@@ -0,0 +1,8 @@
1
+ require 'json'
2
+ require 'oauth'
3
+
4
+ require 'fitgem/client'
5
+
6
+ module Fitgem
7
+ VERSION = "0.2.1"
8
+ end
@@ -0,0 +1,59 @@
1
+ module Fitgem
2
+ class Client
3
+
4
+ # ==========================================
5
+ # Activity Retrieval Methods
6
+ # ==========================================
7
+ def activities_on_date(date)
8
+ get("/user/#{@user_id}/activities/date/#{format_date(date)}.json")
9
+ end
10
+
11
+ def frequent_activities()
12
+ get("/user/#{@user_id}/activities/frequent.json")
13
+ end
14
+
15
+ def recent_activities()
16
+ get("/user/#{@user_id}/activities/recent.json")
17
+ end
18
+
19
+ def favorite_activities()
20
+ get("/user/#{@user_id}/activities/favorite.json")
21
+ end
22
+
23
+ def activity(id, options ={})
24
+ get("/activities/#{id}.json")
25
+ end
26
+
27
+ # ==========================================
28
+ # Activity Update Methods
29
+ # ==========================================
30
+
31
+ # The following values are REQUIRED when logging an activity:
32
+ # options[:activityId] => The activity id
33
+ # options[:durationMillis] => Activity duration in milliseconds
34
+ # options[:distance] => Distance covered during activity date
35
+ # options[:startTime] => Activity start time hours and minutes in the format HH:mm
36
+ # The following values are OPTIONAL when logging an activity:
37
+ # options[:date] => set to today's date when not provided
38
+ def log_activity(options)
39
+ post("/user/#{@user_id}/activities.json", options)
40
+ end
41
+
42
+ def add_favorite_activity(activity_id)
43
+ post("/user/#{@user_id}/activities/log/favorite/#{activity_id}.json")
44
+ end
45
+
46
+ # ==========================================
47
+ # Activity Removal Methods
48
+ # ==========================================
49
+
50
+ def delete_logged_activity(activity_log_id)
51
+ delete("/user/#{@user_id}/activities/#{activity_log_id}.json")
52
+ end
53
+
54
+ def remove_favorite_activity(activity_id)
55
+ delete("/user/#{@user_id}/activities/log/favorite/#{activity_id}.json")
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,91 @@
1
+ require 'fitgem/helpers'
2
+ require 'fitgem/errors'
3
+ require 'fitgem/users'
4
+ require 'fitgem/activities'
5
+ require 'fitgem/units'
6
+ require 'fitgem/foods'
7
+ require 'fitgem/weight'
8
+ require 'fitgem/time_range'
9
+ require 'fitgem/devices'
10
+ require 'fitgem/notifications'
11
+ require 'date'
12
+ require 'uri'
13
+
14
+ module Fitgem
15
+ class Client
16
+
17
+ attr_accessor :api_version
18
+ attr_accessor :api_unit_system
19
+ attr_accessor :user_id
20
+
21
+ def initialize(options = {})
22
+ @consumer_key = options[:consumer_key]
23
+ @consumer_secret = options[:consumer_secret]
24
+ @token = options[:token]
25
+ @secret = options[:secret]
26
+ @proxy = options[:proxy]
27
+ @user_id = options[:user_id] || "-"
28
+ @api_unit_system = Fitgem::ApiUnitSystem.US
29
+ @api_version = "1"
30
+ end
31
+
32
+ def authorize(token, secret, options = {})
33
+ request_token = OAuth::RequestToken.new(
34
+ consumer, token, secret
35
+ )
36
+ @access_token = request_token.get_access_token(options)
37
+ @token = @access_token.token
38
+ @secret = @access_token.secret
39
+ @access_token
40
+ end
41
+
42
+ def reconnect(token, secret)
43
+ @token = token
44
+ @secret = secret
45
+ access_token
46
+ end
47
+
48
+ def request_token(options={})
49
+ consumer.get_request_token(options)
50
+ end
51
+
52
+ def authentication_request_token(options={})
53
+ consumer.options[:authorize_path] = '/oauth/authenticate'
54
+ request_token(options)
55
+ end
56
+
57
+ private
58
+
59
+ def consumer
60
+ @consumer ||= OAuth::Consumer.new(
61
+ @consumer_key,
62
+ @consumer_secret,
63
+ { :site => 'http://api.fitbit.com', :request_endpoint => @proxy }
64
+ )
65
+ end
66
+
67
+ def access_token
68
+ @access_token ||= OAuth::AccessToken.new(consumer, @token, @secret)
69
+ end
70
+
71
+ def get(path, headers={})
72
+ headers.merge!("User-Agent" => "fitgem gem v#{Fitgem::VERSION}", "Accept-Language" => @api_unit_system)
73
+ oauth_response = access_token.get("/#{@api_version}#{path}", headers)
74
+ JSON.parse(oauth_response.body)
75
+ end
76
+
77
+ def post(path, body='', headers={})
78
+ headers.merge!("User-Agent" => "fitgem gem v#{Fitgem::VERSION}", "Accept-Language" => @api_unit_system)
79
+ oauth_response = access_token.post("/#{@api_version}#{path}", body, headers)
80
+ JSON.parse(oauth_response.body)
81
+ end
82
+
83
+ def delete(path, headers={})
84
+ p path
85
+ p headers
86
+ headers.merge!("User-Agent" => "fitgem gem v#{Fitgem::VERSION}", "Accept-Language" => @api_unit_system)
87
+ oauth_response = access_token.delete("/#{@api_version}#{path}", headers)
88
+ JSON.parse(oauth_response.body)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,17 @@
1
+ module Fitgem
2
+ class Client
3
+
4
+ # ==========================================
5
+ # Device Retrieval Methods
6
+ # ==========================================
7
+
8
+ def devices
9
+ get("/user/#{@user_id}/devices.json")
10
+ end
11
+
12
+ def device_info(device_id)
13
+ get("/user/#{@user_id}/devices/#{device_id}.json")
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ module Fitgem
2
+ class InvalidArgumentError < ArgumentError
3
+ end
4
+
5
+ class UserIdError < Exception
6
+ end
7
+
8
+ class InvalidTimeRange < ArgumentError
9
+ end
10
+ end
@@ -0,0 +1,63 @@
1
+ module Fitgem
2
+ class Client
3
+
4
+ # ==========================================
5
+ # Food Retrieval Methods
6
+ # ==========================================
7
+
8
+ def foods_on_date(date)
9
+ get("/user/#{@user_id}/foods/log/date/#{format_date(date)}.json")
10
+ end
11
+
12
+ def recent_foods()
13
+ get("/user/#{@user_id}/foods/log/recent.json")
14
+ end
15
+
16
+ def frequent_foods()
17
+ get("/user/#{@user_id}/foods/log/frequent.json")
18
+ end
19
+
20
+ def favorite_foods()
21
+ get("/user/#{@user_id}/foods/log/favorite.json")
22
+ end
23
+
24
+ def foods_units()
25
+ get("/foods/units.json")
26
+ end
27
+
28
+ def find_food(query_string)
29
+ get("/foods/search.json?query=#{URI.escape(query_string)}")
30
+ end
31
+
32
+ # ==========================================
33
+ # Food Update Methods
34
+ # ==========================================
35
+
36
+ # Send the following required ID's in the options hash:
37
+ # options[:foodId] => ID of the food to log
38
+ # options[:mealTypeId] => ID of the meal to log the food for
39
+ # options[:unitId] => ID of the unit to log with the food
40
+ # (typically retrieved via a previous call to get Foods (all, recent, frequent, favorite) or Food Units. )
41
+ # options[:amount] => Amount consumed of the selected unit; a floating point number
42
+ # options[:date] => Log date in the format yyyy-MM-dd
43
+ def log_food(options)
44
+ post("/user/#{@user_id}/foods/log.json", options)
45
+ end
46
+
47
+ def add_favorite_food(food_id)
48
+ post("/user/#{@user_id}/foods/log/favorite/#{food_id}.json")
49
+ end
50
+
51
+ # ==========================================
52
+ # Food Removal Methods
53
+ # ==========================================
54
+
55
+ def delete_logged_food(food_log_id)
56
+ delete("/user/#{@user_id}/foods/log/#{food_log_id}.json")
57
+ end
58
+
59
+ def remove_favorite_food(food_id)
60
+ delete("/user/#{@user_id}/foods/favorite/#{food_id}.json")
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,16 @@
1
+ module Fitgem
2
+ class Client
3
+
4
+ # Should return date as YYYY-MM-DD
5
+ def format_date(date)
6
+ if date.is_a? String
7
+ return date
8
+ elsif Date === date || Time === date || DateTime === date
9
+ return date.strftime("%Y-%m-%d")
10
+ else
11
+ raise Fitgem::InvalidArgumentError, "Date used must be a date/time object or a string in the format YYYY=MM-DD; current argument is a #{date.class}"
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,52 @@
1
+ module Fitgem
2
+ class Client
3
+
4
+ def create_subscription(options={})
5
+ unless options[:type] && [:sleep,:body,:activities,:foods].include?(options[:type])
6
+ raise Error, 'Must include options[:type] (values are :activities, :foods, :sleep, and :body)'
7
+ end
8
+ base_url = "/user/#{@user_id}/#{options[:type].to_s}/apiSubscriptions"
9
+ post_subscription(base_url, options)
10
+ end
11
+
12
+ def remove_subscription(options={})
13
+ unless options[:type] && [:sleep,:body,:activities,:foods].include?(options[:type])
14
+ raise Error, 'Must include options[:type] (values are :activities, :foods, :sleep, and :body)'
15
+ end
16
+ unless options[:subscription_id]
17
+ raise Error, "Must include options[:subscription_id] to delete a subscription"
18
+ end
19
+ base_url = "/user/#{@user_id}/#{options[:type].to_s}/apiSubscriptions"
20
+ url = finalize_subscription_url(base_url, options)
21
+ headers = {}
22
+ headers['X-Fitgem-Subscriber-Id'] = options[:subscriber_id] if options[:subscriber_id]
23
+ begin
24
+ delete(url, headers)
25
+ rescue TypeError
26
+ # Deleting a subscription returns a nil response, which causes a TypeError
27
+ # when the oauth library tries to parse it.
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ def finalize_subscription_url(base_url, options={})
34
+ url = base_url
35
+ if options[:subscription_id]
36
+ url += "/#{options[:subscription_id]}"
37
+ end
38
+ if options[:subscription_response_format]
39
+ url += ".#{options[:subscription_response_format]}"
40
+ else
41
+ url += ".json"
42
+ end
43
+ url
44
+ end
45
+
46
+ def post_subscription(base_url, options)
47
+ url = finalize_subscription_url(base_url, options)
48
+ post(url, options)
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,53 @@
1
+ module Fitgem
2
+ class Client
3
+
4
+ # Gets historical resource data in the time range specified by
5
+ # options param. The time range can either be specified by
6
+ # :base_date and :end_date OR by using :base_date and a :period
7
+ # (supported periods are 1d, 7d, 30d, 1w, 1m, 3m, 6m, 1y, max)
8
+ #
9
+ # Example values for resource_path are below:
10
+ #
11
+ # Food:
12
+ # /foods/log/caloriesIn
13
+ #
14
+ # Activity:
15
+ # /activities/log/calories
16
+ # /activities/log/steps
17
+ # /activities/log/distance
18
+ # /activities/log/minutesSedentary
19
+ # /activities/log/minutesLightlyActive
20
+ # /activities/log/minutesFairlyActive
21
+ # /activities/log/minutesVeryActive
22
+ # /activities/log/activeScore
23
+ # /activities/log/activityCalories
24
+ #
25
+ # Sleep:
26
+ # /sleep/minutesAsleep
27
+ # /sleep/minutesAwake
28
+ # /sleep/awakeningsCount
29
+ # /sleep/timeInBed
30
+ #
31
+ # Body:
32
+ # /body/weight
33
+ # /body/bmi
34
+ # /body/fat
35
+ def data_by_time_range(resource_path, options)
36
+ range_str = construct_date_range_fragment(options)
37
+ get("/user/#{@user_id}#{resource_path}/#{range_str}.json")
38
+ end
39
+
40
+ def construct_date_range_fragment(options)
41
+ range_str = "date/"
42
+ if options[:base_date] && options[:period]
43
+ range_str += "#{options[:base_date]}/#{options[:period]}"
44
+ elsif options[:base_date] && options[:end_date]
45
+ range_str += "#{options[:base_date]}/#{options[:end_date]}"
46
+ else
47
+ raise Fitgem::InvalidTimeRange, "Must supply either base_date and period OR base_date and end_date"
48
+ end
49
+ range_str
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,15 @@
1
+ module Fitgem
2
+ class ApiUnitSystem
3
+ def self.US
4
+ "en_US"
5
+ end
6
+
7
+ def self.UK
8
+ "en_UK"
9
+ end
10
+
11
+ def self.METRIC
12
+ ""
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Fitgem
2
+ class Client
3
+
4
+ def user_info(options = {})
5
+ get("/user/#{@user_id}/profile.json")
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Fitgem
2
+ class Client
3
+
4
+ # ==========================================
5
+ # Weight Update Methods
6
+ # ==========================================
7
+
8
+ def log_weight(weight, date, options={})
9
+ post("/user/#{@user_id}/body/weight.json", options.merge(:weight => weight, :date => format_date(date)))
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fitgem do
4
+
5
+ before do
6
+ @client = Fitgem::Client.new
7
+ end
8
+
9
+ describe "global settings" do
10
+ it 'should expose the api_version' do
11
+ @client.api_version.should == "1"
12
+ end
13
+
14
+ it 'should all clients to set a new api version' do
15
+ @client.api_version = "2"
16
+ @client.api_version.should == "2"
17
+ end
18
+
19
+ it 'should default to the US unit system' do
20
+ @client.api_unit_system.should == Fitgem::ApiUnitSystem.US
21
+ end
22
+
23
+ it 'should allow the unit system to be set to other types' do
24
+ @client.api_unit_system = Fitgem::ApiUnitSystem.UK
25
+ @client.api_unit_system.should == Fitgem::ApiUnitSystem.UK
26
+ @client.api_unit_system = Fitgem::ApiUnitSystem.METRIC
27
+ @client.api_unit_system.should == Fitgem::ApiUnitSystem.METRIC
28
+ end
29
+
30
+ it 'should default to a user id of \'-\', the currently-logged in user' do
31
+ @client.user_id.should == '-'
32
+ end
33
+ end
34
+
35
+ describe "data retrieval by time range" do
36
+
37
+ it 'should format the correct URI fragment based on a base date and end date' do
38
+ frag = @client.construct_date_range_fragment({:base_date => '2011-03-07', :end_date => '2011-03-14'})
39
+ frag.should == 'date/2011-03-07/2011-03-14'
40
+ end
41
+
42
+ it 'should format the correct URI fragment based on a base date and period' do
43
+ frag = @client.construct_date_range_fragment({:base_date => '2011-03-07', :period => '7d'})
44
+ frag.should == 'date/2011-03-07/7d'
45
+ end
46
+
47
+ it 'should raise an error unless there is a base date AND either a period or an end date' do
48
+ lambda {
49
+ @client.construct_date_range_fragment({:base_date => '2011-03-07'})
50
+ }.should raise_error(Fitgem::InvalidTimeRange)
51
+
52
+ lambda {
53
+ @client.construct_date_range_fragment({:period => '1y'})
54
+ }.should raise_error(Fitgem::InvalidTimeRange)
55
+
56
+ lambda {
57
+ @client.construct_date_range_fragment({:end_date => '2011-03-07', :period => '7d'})
58
+ }.should raise_error(Fitgem::InvalidTimeRange)
59
+ end
60
+
61
+ end
62
+
63
+ describe "format_date" do
64
+ it 'should accept DateTime objects' do
65
+ date = DateTime.strptime('2011-03-19','%Y-%m-%d')
66
+ @client.format_date(date).should == '2011-03-19'
67
+ end
68
+
69
+ it 'should accept strings in YYYY-MM-DD format' do
70
+ @client.format_date('2011-03-19').should == '2011-03-19'
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'fitgem'
5
+
6
+ RSpec.configure do |config|
7
+ config.mock_with :rspec
8
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fitgem
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.2.1
6
+ platform: ruby
7
+ authors:
8
+ - Zachery Moneypenny
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-12 00:00:00 -05:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: oauth
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: rspec
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
+ description: A client library to send and retrieve workout/weight data from fitbit.com
39
+ email:
40
+ - fitgem@whazzmaster.com
41
+ executables: []
42
+
43
+ extensions: []
44
+
45
+ extra_rdoc_files: []
46
+
47
+ files:
48
+ - .gitignore
49
+ - .rvmrc
50
+ - Gemfile
51
+ - LICENSE
52
+ - README.md
53
+ - Rakefile
54
+ - fitgem.gemspec
55
+ - lib/fitgem.rb
56
+ - lib/fitgem/activities.rb
57
+ - lib/fitgem/client.rb
58
+ - lib/fitgem/devices.rb
59
+ - lib/fitgem/errors.rb
60
+ - lib/fitgem/foods.rb
61
+ - lib/fitgem/helpers.rb
62
+ - lib/fitgem/notifications.rb
63
+ - lib/fitgem/time_range.rb
64
+ - lib/fitgem/units.rb
65
+ - lib/fitgem/users.rb
66
+ - lib/fitgem/weight.rb
67
+ - spec/fitgem_spec.rb
68
+ - spec/spec_helper.rb
69
+ has_rdoc: true
70
+ homepage: http://github.com/whazzmaster/fitgem
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options: []
75
+
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ requirements: []
91
+
92
+ rubyforge_project: fitgem
93
+ rubygems_version: 1.5.2
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: OAuth client library to the data on fitbit.com
97
+ test_files:
98
+ - spec/fitgem_spec.rb
99
+ - spec/spec_helper.rb