fitgem 0.3.6 → 0.4.0

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