fitgem 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,17 +1,27 @@
1
1
  module Fitgem
2
2
  class Client
3
-
4
3
  # ==========================================
5
4
  # Friend Retrieval Methods
6
5
  # ==========================================
6
+
7
+ # Get a list of the current user's friends
8
+ #
9
+ # @return [Array] List of friends, each of which is a Hash
10
+ # containing friend information
7
11
  def friends
8
12
  get("/user/#{@user_id}/friends.json")
9
13
  end
10
14
 
15
+ # Get the weekly leaderboard of friends' activities
16
+ #
17
+ # @return [Hash] Friends' information
11
18
  def weekly_leaderboard
12
19
  leaderboard('7d')
13
20
  end
14
21
 
22
+ # Get the monthly leaderboard of friends' activities
23
+ #
24
+ # @return [Hash] Friends' information
15
25
  def monthly_leaderboard
16
26
  leaderboard('30d')
17
27
  end
@@ -19,20 +29,41 @@ module Fitgem
19
29
  # ==========================================
20
30
  # Invitation Management Methods
21
31
  # ==========================================
22
- def invite_friend(options)
23
- unless options[:email] || options[:user_id]
24
- raise InvalidArgumentError.new "add_friend hash argument must include :email or :user_id"
32
+
33
+ # Create an invite for a user to connect with the current user as a friend
34
+ #
35
+ # In order to invite a user, either an :email or a valid :userId
36
+ # must be supplied in the +opts+ param hash.
37
+ #
38
+ # @param [Hash] opts The invite data
39
+ # @option opts [String] :email Email address of user to invite
40
+ # @option opts [String] :userId User ID of the user to invite
41
+ #
42
+ # @return [Hash]
43
+ def invite_friend(opts)
44
+ unless opts[:email] || opts[:user_id]
45
+ raise InvalidArgumentError.new "invite_friend hash argument must include :email or :user_id"
25
46
  end
26
47
  translated_options = {}
27
- translated_options[:invitedUserEmail] = options[:email] if options[:email]
28
- translated_options[:invitedUserId] = options[:user_id] if options[:user_id]
48
+ translated_options[:invitedUserEmail] = opts[:email] if opts[:email]
49
+ translated_options[:invitedUserId] = opts[:user_id] if opts[:user_id]
29
50
  post("/user/#{@user_id}/friends/invitations.json", translated_options)
30
51
  end
31
52
 
53
+ # Accept a friend invite
54
+ #
55
+ # @param [String] requestor_id The ID of the requestor that sent the
56
+ # friend request
57
+ # @return [Hash]
32
58
  def accept_invite(requestor_id)
33
59
  respond_to_invite(requestor_id, true)
34
60
  end
35
61
 
62
+ # Decline a friend invite
63
+ #
64
+ # @param [String] requestor_id The ID of the requestor that sent the
65
+ # friend request
66
+ # @return [Hash]
36
67
  def decline_invite(requestor_id)
37
68
  respond_to_invite(requestor_id, false)
38
69
  end
@@ -40,7 +71,7 @@ module Fitgem
40
71
  private
41
72
 
42
73
  def leaderboard(range)
43
- get("/user/#{@user_id}/friends/leaderboard/#{range}.json")
74
+ get("/user/#{@user_id}/friends/leaders/#{range}.json")
44
75
  end
45
76
 
46
77
  def respond_to_invite(requestor_id, does_accept)
@@ -48,4 +79,4 @@ module Fitgem
48
79
  post("/user/#{@user_id}/friends/invitations/#{requestor_id}.json", options)
49
80
  end
50
81
  end
51
- end
82
+ end
@@ -1,7 +1,19 @@
1
1
  module Fitgem
2
2
  class Client
3
-
4
- # Should return date as YYYY-MM-DD
3
+ # Format any of a variety of date types into the formatted string
4
+ # required when using the fitbit API.
5
+ #
6
+ # The date parameter can take several different kind of objects: a
7
+ # DateTime object, a Date object, a Time object or a String object. Furthermore,
8
+ # the string object may be either the date in a preformatted string
9
+ # ("yyyy-MM-dd"), or it may be the string values "today" or
10
+ # "tomorrow".
11
+ #
12
+ # @param [DateTime, Date, Time, String] date The object to format into a
13
+ # date string
14
+ # @raise [Fitgem::InvalidDateArgument] Raised when the object is
15
+ # not a DateTime, Date, Time or a valid (yyyy-MM-dd) String object
16
+ # @return [String] Date in "yyyy-MM-dd" string format
5
17
  def format_date(date)
6
18
  if date.is_a? String
7
19
  case date
@@ -10,14 +22,16 @@ module Fitgem
10
22
  when 'yesterday'
11
23
  return (Date.today-1).strftime("%Y-%m-%d")
12
24
  else
25
+ unless date =~ /\d{4}\-\d{2}\-\d{2}/
26
+ raise Fitgem::InvalidDateArgument, "Invalid date (#{date}), must be in yyyy-MM-dd format"
27
+ end
13
28
  return date
14
29
  end
15
30
  elsif Date === date || Time === date || DateTime === date
16
31
  return date.strftime("%Y-%m-%d")
17
32
  else
18
- 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}"
33
+ raise Fitgem::InvalidDateArgument, "Date used must be a date/time object or a string in the format YYYY-MM-DD; supplied argument is a #{date.class}"
19
34
  end
20
35
  end
21
-
22
36
  end
23
- end
37
+ end
@@ -1,47 +1,126 @@
1
1
  module Fitgem
2
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)
3
+ SUBSCRIBABLE_TYPES = [:sleep, :body, :activities, :foods, :all]
4
+
5
+ # Get a list of all subscriptions
6
+ #
7
+ # @param [Hash] opts Subscription query data
8
+ # @option opts [Integer, String] :type The type of subscription (valid
9
+ # values are :activities, :foods, :sleep, :body, and :all). REQUIRED
10
+ #
11
+ # @return [Hash] Hash contain subscription information
12
+ # @since v0.4.0
13
+ def subscriptions(opts)
14
+ get make_subscription_url(opts), make_headers(opts)
10
15
  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
- delete(url, headers)
16
+
17
+ # Creates a notification subscription
18
+ #
19
+ # @note You must check the HTTP response code to check the status of the request to add a subscription. See {https://wiki.fitbit.com/display/API/Subscriptions-API} for information about what the codes mean.
20
+ #
21
+ # @param [Hash] opts The notification subscription data
22
+ # @option opts [Symbol] :type The type of subscription (valid
23
+ # values are :activities, :foods, :sleep, :body, and :all). REQUIRED
24
+ # @option opts [Integer, String] :subscriptionId The subscription id
25
+ #
26
+ # @return [Integer, Hash] An array containing the HTTP response code and
27
+ # a hash containing confirmation information for the subscription.
28
+ # @since v0.4.0
29
+ def create_subscription(opts)
30
+ resp = raw_post make_subscription_url(opts), EMPTY_BODY, make_headers(opts.merge({:use_subscription_id => true}))
31
+ [resp.code, extract_response_body(resp)]
24
32
  end
25
-
33
+
34
+ # Removes a notification subscription
35
+ #
36
+ # @note You must check the HTTP response code to check the status of the request to remove a subscription. See {https://wiki.fitbit.com/display/API/Subscriptions-API} for information about what the codes mean.
37
+ #
38
+ # @param [Hash] opts The notification subscription data
39
+ # @option opts [Symbol] :type The type of subscription to remove;
40
+ # valid values are :activities, :foods, :sleep, :body, and :all).
41
+ # REQUIRED
42
+ # @option opts [Integer, String] :subscription_id The id of the
43
+ # subscription to remove.
44
+ # @option opts [Inteter, Stri)g] :subscriber_id The subscriber id of the client
45
+ # application, created via {http://dev.fitbit.com}
46
+ #
47
+ # @return [Integer, Hash] An array containing the HTTP response code and
48
+ # a hash containing confirmation information for the subscription.
49
+ # @since v0.4.0
50
+ def remove_subscription(opts)
51
+ resp = raw_delete make_subscription_url(opts), make_headers(opts.merge({:use_subscription_id => true}))
52
+ [resp.code, extract_response_body(resp)]
53
+ end
54
+
26
55
  protected
27
-
28
- def finalize_subscription_url(base_url, options={})
29
- url = base_url
30
- if options[:subscription_id]
31
- url += "/#{options[:subscription_id]}"
56
+
57
+ # Ensures that the type supplied is valid
58
+ #
59
+ # @param [Symbol] subscription_type The type of subscription;
60
+ # valid values are (:sleep, :body, :activities, :foods, and
61
+ # :all)
62
+ # @raise [Fitgem::InvalidArgumentError] Raised if the supplied type
63
+ # is not valid
64
+ # @return [Boolean]
65
+ def validate_subscription_type(subscription_type)
66
+ unless subscription_type && SUBSCRIBABLE_TYPES.include?(subscription_type)
67
+ raise Fitgem::InvalidArgumentError, "Invalid subscription type (valid values are #{SUBSCRIBABLE_TYPES.join(', ')})"
32
68
  end
33
- if options[:subscription_response_format]
34
- url += ".#{options[:subscription_response_format]}"
35
- else
36
- url += ".json"
69
+ true
70
+ end
71
+
72
+ # Create the headers hash for subscription management calls
73
+ #
74
+ # This method both adds approriate headers given what is in the
75
+ # options hash, as well as removes extraneous hash entries that are
76
+ # not needed in the headers of the request sent to the API.
77
+ #
78
+ # @param [Hash] opts The options for header creation
79
+ # @option opts [String] :subscriber_id The subscriber id of the client
80
+ # application, created via {http://dev.fitbit.com}
81
+ # @return [Hash] The headers has to pass to the get/post/put/delete
82
+ # methods
83
+ def make_headers(opts)
84
+ headers = opts.dup
85
+ if opts[:subscriber_id]
86
+ headers['X-Fitbit-Subscriber-Id'] = opts[:subscriber_id]
87
+ headers.delete :subscriber_id
37
88
  end
38
- url
89
+
90
+ headers.delete :subscription_id if headers[:subscription_id]
91
+ headers.delete :type if headers[:type]
92
+ headers.delete :use_subscription_id if headers[:use_subscription_id]
93
+
94
+ headers
39
95
  end
40
-
41
- def post_subscription(base_url, options)
42
- url = finalize_subscription_url(base_url, options)
43
- post(url, options)
96
+
97
+ # Create the subscription management API url
98
+ #
99
+ # @param [Hash] opts The options on how to construct the
100
+ # subscription API url
101
+ # @option opts [Symbol] :type The type of subscription;
102
+ # valid values are (:sleep, :body, :activities, :foods, and
103
+ # :all)
104
+ # @option opts [Symbol] :use_subscription_id If true, then
105
+ # opts[:subscription_id] will be used in url construction
106
+ # @option opts [String] :subscription_id The id of the subscription
107
+ # that the URL is for
108
+ # @return [String] The url to use for subscription management
109
+ def make_subscription_url(opts)
110
+ validate_subscription_type opts[:type]
111
+ path = if opts[:type] == :all
112
+ ""
113
+ else
114
+ "/"+opts[:type].to_s
115
+ end
116
+ url = "/user/#{@user_id}#{path}/apiSubscriptions"
117
+ if opts[:use_subscription_id]
118
+ unless opts[:subscription_id]
119
+ raise Fitgem::InvalidArgumentError, "Must include options[:subscription_id]"
120
+ end
121
+ url += "/#{opts[:subscription_id]}"
122
+ end
123
+ url += ".json"
44
124
  end
45
-
46
125
  end
47
126
  end
@@ -1,12 +1,50 @@
1
1
  module Fitgem
2
2
  class Client
3
-
4
3
  # ==========================================
5
4
  # Sleep Retrieval Methods
6
5
  # ==========================================
6
+
7
+ # Get sleep data for specified date
8
+ #
9
+ # @param [DateTime, Date, String] date
10
+ # @return [Array] List of sleep items for the supplied date
7
11
  def sleep_on_date(date)
8
12
  get("/user/#{@user_id}/sleep/date/#{format_date(date)}.json")
9
13
  end
10
14
 
15
+ # ==========================================
16
+ # Sleep Logging Methods
17
+ # ==========================================
18
+
19
+ # Log sleep data to fitbit for current user
20
+ #
21
+ # All aspects of the options hash are REQUIRED.
22
+ #
23
+ # @param [Hash] opts Sleep data to log
24
+ # @option opts [String] :startTime Hours and minutes in the format "HH:mm"
25
+ # @option opts [Integer, String] :duration Sleep duration, in miliseconds
26
+ # @option opts [DateTime, Date, String] :date Sleep log entry date;
27
+ # if a string it must be in the yyyy-MM-dd format, or the values
28
+ # 'today' or 'tomorrow'
29
+ #
30
+ # @return [Hash] Summary of the logged sleep data
31
+ #
32
+ # @since v0.4.0
33
+ def log_sleep(opts)
34
+ post("/user/#{@user_id}/sleep.json", opts)
35
+ end
36
+
37
+ # Delete logged sleep data
38
+ #
39
+ # The sleep log id is the one returned when sleep data is recorded
40
+ # via {#log_sleep}.
41
+ #
42
+ # @param [Integer, String] Sleep log id
43
+ # @return [Hash] Empty hash denotes successful deletion
44
+ #
45
+ # @since v0.4.0
46
+ def delete_sleep_log(sleep_log_id)
47
+ delete("/user/#{@user_id}/sleep/#{sleep_log_id}.json")
48
+ end
11
49
  end
12
- end
50
+ end
@@ -5,47 +5,63 @@ module Fitgem
5
5
  # :base_date and :end_date OR by using :base_date and a :period
6
6
  # (supported periods are 1d, 7d, 30d, 1w, 1m, 3m, 6m, 1y, max)
7
7
  #
8
- # Supported values for resource_path are:
8
+ # Supported values for +resource_path+ are:
9
+ #
9
10
  # Food:
10
- # /foods/log/caloriesIn
11
+ # /foods/log/caloriesIn
12
+ # /foods/log/water
11
13
  #
12
14
  # Activity:
13
- # /activities/log/calories
14
- # /activities/log/steps
15
- # /activities/log/distance
16
- # /activities/log/floors
17
- # /activities/log/elevation
18
- # /activities/log/minutesSedentary
19
- # /activities/log/minutesLightlyActive
20
- # /activities/log/minutesFairlyActive
21
- # /activities/log/minutesVeryActive
22
- # /activities/log/activeScore
23
- # /activities/log/activityCalories
15
+ # /activities/log/calories
16
+ # /activities/log/steps
17
+ # /activities/log/distance
18
+ # /activities/log/floors
19
+ # /activities/log/elevation
20
+ # /activities/log/minutesSedentary
21
+ # /activities/log/minutesLightlyActive
22
+ # /activities/log/minutesFairlyActive
23
+ # /activities/log/minutesVeryActive
24
+ # /activities/log/activeScore
25
+ # /activities/log/activityCalories
24
26
  #
25
27
  # Sleep:
26
- # /sleep/minutesAsleep
27
- # /sleep/minutesAwake
28
- # /sleep/awakeningsCount
29
- # /sleep/timeInBed
28
+ # /sleep/startTime
29
+ # /sleep/timeInBed
30
+ # /sleep/minutesAsleep
31
+ # /sleep/awakeningsCount
32
+ # /sleep/minutesAwake
33
+ # /sleep/minutesToFallAsleep
34
+ # /sleep/minutesAfterWakeup
35
+ # /sleep/efficiency
30
36
  #
31
37
  # Body:
32
- # /body/weight
33
- # /body/bmi
34
- # /body/fat
38
+ # /body/weight
39
+ # /body/bmi
40
+ # /body/fat
41
+ #
42
+ # @param [String] resource_path The resource path to get data for
43
+ # (see note above)
44
+ # @param [Hash] opts The options to specify date ranges, etc.
45
+ # @option opts [DateTime, Date, String] :base_date The start date of the period
46
+ # @option opts [DateTime, Date, String] :end_date The end date of the period
47
+ # @option opts [String] :period The period (valid values: 1d, 7d, 30d, 1w, 1m, 3m, 6m, 1y, max)
35
48
  #
36
- # Examples
49
+ # @return [Hash] Hash containing an array of objects that match your
50
+ # request
37
51
  #
38
- # * To get the floors traveled for the week of October 24th
39
- # data_by_time_range("/activities/log/floors", {:base_date => "2011-10-24", :period => "7d"})
52
+ # @example To get the floors traveled for the week of October 24th
53
+ # data_by_time_range("/activities/log/floors", {:base_date => "2011-10-24", :period => "7d"})
40
54
  #
41
- # * To get all of the body weight logs from April 3rd until July 27th
42
- # data_by_time_range("/body/weight", {:base_date => "2011-03-03", :end_date => "2011-07-27"})
55
+ # @example To get all of the body weight logs from April 3rd until July 27th
56
+ # data_by_time_range("/body/weight", {:base_date => "2011-03-03", :end_date => "2011-07-27"})
43
57
  #
44
- def data_by_time_range(resource_path, options)
45
- range_str = construct_date_range_fragment(options)
46
- get("/user/#{@user_id}#{resource_path}/#{range_str}.json")
58
+ def data_by_time_range(resource_path, opts)
59
+ range = construct_date_range_fragment(opts)
60
+ get("/user/#{@user_id}#{resource_path}/#{range}.json")
47
61
  end
48
62
 
63
+ # protected
64
+
49
65
  def construct_date_range_fragment(options)
50
66
  range_str = "date/"
51
67
  if options[:base_date] && options[:period]
@@ -57,6 +73,6 @@ module Fitgem
57
73
  end
58
74
  range_str
59
75
  end
60
-
76
+
61
77
  end
62
78
  end
@@ -1,53 +1,90 @@
1
1
  module Fitgem
2
+ # Enumeration of valid unit systems that can be sent to fitbit
3
+ #
4
+ # Set the {Fitgem::Client#api_unit_system} property to one of
5
+ # these values to set the unit system used for all subsequent
6
+ # API calls.
7
+ #
8
+ # See {https://wiki.fitbit.com/display/API/API-Unit-System} for
9
+ # more information on how the various unit systems are used.
2
10
  class ApiUnitSystem
11
+ # US Units
12
+ #
13
+ # Used by default in fitgem
14
+ #
15
+ # @return [String]
3
16
  def self.US
4
17
  "en_US"
5
18
  end
6
19
 
20
+ # UK Units
21
+ #
22
+ # @return [String]
7
23
  def self.UK
8
- "en_UK"
24
+ "en_GB"
9
25
  end
10
26
 
27
+ # Metric Units
28
+ #
29
+ # @return [String]
11
30
  def self.METRIC
12
31
  ""
13
32
  end
14
33
  end
15
34
 
35
+ # Enumeration of available distance units that may be used when
36
+ # logging measurements or activities that involve distance.
37
+ #
38
+ # See {https://wiki.fitbit.com/display/API/API-Distance-Unit} for
39
+ # more information about using distance units.
16
40
  class ApiDistanceUnit
41
+ # @return [String]
17
42
  def self.centimeters
18
43
  "Centimeter"
19
44
  end
20
45
 
46
+ # @return [String]
21
47
  def self.feet
22
48
  "Foot"
23
49
  end
24
50
 
51
+ # @return [String]
25
52
  def self.inches
26
53
  "Inch"
27
54
  end
28
55
 
56
+ # @return [String]
29
57
  def self.kilometers
30
58
  "Kilometer"
31
59
  end
32
60
 
61
+ # @return [String]
33
62
  def self.meters
34
63
  "Meter"
35
64
  end
36
65
 
66
+ # @return [String]
37
67
  def self.miles
38
68
  "Mile"
39
69
  end
40
70
 
71
+ # @return [String]
41
72
  def self.millimeters
42
73
  "Millimeter"
43
74
  end
44
75
 
76
+ # Steps are only valid distance units when logging walking or
77
+ # running activities. The distance is computed from the stride
78
+ # length the user provides.
79
+ #
80
+ # @return [String]
45
81
  def self.steps
46
82
  "Steps"
47
83
  end
48
84
 
85
+ # @return [String]
49
86
  def self.yards
50
87
  "Yards"
51
88
  end
52
89
  end
53
- end
90
+ end