fitgem_oauth2 0.0.8 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/fitgem_oauth2.gemspec +7 -7
- data/lib/fitgem_oauth2/activity.rb +100 -73
- data/lib/fitgem_oauth2/body_measurements.rb +104 -37
- data/lib/fitgem_oauth2/client.rb +28 -19
- data/lib/fitgem_oauth2/devices.rb +21 -2
- data/lib/fitgem_oauth2/errors.rb +4 -0
- data/lib/fitgem_oauth2/food.rb +126 -27
- data/lib/fitgem_oauth2/friends.rb +20 -4
- data/lib/fitgem_oauth2/heartrate.rb +37 -35
- data/lib/fitgem_oauth2/sleep.rb +45 -2
- data/lib/fitgem_oauth2/subscriptions.rb +1 -1
- data/lib/fitgem_oauth2/users.rb +1 -1
- data/lib/fitgem_oauth2/utils.rb +32 -28
- data/lib/fitgem_oauth2/version.rb +1 -1
- metadata +11 -13
- data/lib/fitgem_oauth2/steps.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c0baa9844ef7be0f66170042cec30385ab5d2e5
|
4
|
+
data.tar.gz: e1ccdc69b6a1763cf642532dab7494655b075b28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc2840e23217566f0e460b54d4d4ba4c9c88f4251a8ac387e3403aedb6db10d76298cd7db1e244cacc8e232b1431d434b6dbedef79cce1cca3df17571cc7be1a
|
7
|
+
data.tar.gz: 5364ff2b8515a6472cc4246397e39451400138d9aea9977d5e17137f96420e4e4e029f25107be69d41627a7dc8f076a3e0462bc46d70d6a8c50575e1b3171ea3
|
data/fitgem_oauth2.gemspec
CHANGED
@@ -6,17 +6,17 @@ require 'fitgem_oauth2/version'
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = 'fitgem_oauth2'
|
8
8
|
s.version = FitgemOauth2::VERSION
|
9
|
-
s.summary =
|
10
|
-
s.description =
|
11
|
-
s.authors = [
|
9
|
+
s.summary = 'Fitbit API client library'
|
10
|
+
s.description = 'This gem allows requesting data from Fitbit API using OAuth2'
|
11
|
+
s.authors = ['Ankit Gupta']
|
12
12
|
s.email = 'ankit.gupta2801@gmail.com'
|
13
|
-
s.files = %w(fitgem_oauth2.gemspec) + `git ls-files -z`.split("\x0").select { |f| f.start_with?(
|
13
|
+
s.files = %w(fitgem_oauth2.gemspec) + `git ls-files -z`.split("\x0").select { |f| f.start_with?('lib/') }
|
14
14
|
s.homepage = 'http://rubygems.org/gems/fitgem_oauth2'
|
15
15
|
s.license = 'MIT'
|
16
16
|
|
17
17
|
s.add_runtime_dependency 'faraday', '~> 0.9'
|
18
18
|
|
19
|
-
s.add_development_dependency
|
20
|
-
s.add_development_dependency
|
21
|
-
s.add_development_dependency
|
19
|
+
s.add_development_dependency 'rake', '~> 10.5'
|
20
|
+
s.add_development_dependency 'rspec', '~> 3.4'
|
21
|
+
s.add_development_dependency 'factory_girl', '~> 4.5'
|
22
22
|
end
|
@@ -1,128 +1,155 @@
|
|
1
1
|
module FitgemOauth2
|
2
2
|
class Client
|
3
3
|
|
4
|
-
|
5
|
-
# Activities Retrieval Methods
|
6
|
-
# ======================================
|
7
|
-
|
8
|
-
allowed_activity_paths = %w("calories" "caloriesBMR" "steps" "distance" "floors" "elevation" "minutesSedentary" "minutesLightlyActive" "minutesFairlyActive" "minutesVeryActive" "activityCaloriestracker/calories" "tracker/steps" "tracker/distance" "tracker/floors" "tracker/elevation" "tracker/minutesSedentary" "tracker/minutesLightlyActive" "tracker/minutesFairlyActive" "tracker/minutesVeryActive" "tracker/activityCalories")
|
4
|
+
ACTIVITY_RESOURCES = %w(calories caloriesBMR steps distance floors elevation minutesSedentary minutesLightlyActive minutesFairlyActive minutesVeryActive activityCaloriestracker/calories tracker/steps tracker/distance tracker/floors tracker/elevation tracker/minutesSedentary tracker/minutesLightlyActive tracker/minutesFairlyActive tracker/minutesVeryActive tracker/activityCalories)
|
9
5
|
|
10
|
-
|
6
|
+
ACTIVITY_PERIODS = %w(1d 7d 30d 1w 1m 3m 6m 1y max)
|
11
7
|
|
12
|
-
def
|
13
|
-
get_call("
|
8
|
+
def daily_activity_summary(date)
|
9
|
+
get_call("user/#{user_id}/activities/date/#{format_date(date)}.json")
|
14
10
|
end
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
raise FitgemOauth2::InvalidArgumentError, "resource_path should be one of #{allowed_activity_paths}"
|
12
|
+
# ==================================
|
13
|
+
# Activity Time Series
|
14
|
+
# ==================================
|
15
|
+
|
16
|
+
def activity_time_series(resource: nil, start_date: nil, end_date: nil, period: nil)
|
17
|
+
|
18
|
+
unless resource && ACTIVITY_RESOURCES.include?(resource)
|
19
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid resource: #{resource}. Valid resources are #{ACTIVITY_RESOURCES}."
|
25
20
|
end
|
26
|
-
end
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
22
|
+
unless start_date
|
23
|
+
raise FitgemOauth2::InvalidArgumentError, 'Start date must be specified.'
|
24
|
+
end
|
25
|
+
|
26
|
+
if period && end_date
|
27
|
+
raise FitgemOauth2::InvalidArgumentError, 'Both period and end_date are specified. Please specify only one.'
|
33
28
|
end
|
34
|
-
end
|
35
29
|
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
if period && !ACTIVITY_PERIODS.include?(period)
|
31
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid period: #{period}. Valid periods are #{ACTIVITY_PERIODS}."
|
32
|
+
end
|
33
|
+
|
34
|
+
first = format_date(start_date)
|
35
|
+
second = period || format_date(end_date)
|
36
|
+
url = ['user', user_id, 'activities', resource, 'date', first, second].join('/')
|
37
|
+
get_call(url + '.json')
|
39
38
|
end
|
40
39
|
|
41
|
-
# ======================================
|
42
|
-
# Intraday Series
|
43
|
-
# ======================================
|
44
40
|
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
|
42
|
+
def intraday_activity_time_series(resource: nil, start_date: nil, end_date: nil, detail_level: nil,
|
43
|
+
start_time: nil, end_time: nil)
|
44
|
+
|
45
|
+
# converting to symbol to allow developer to use either 'calories' or :calories
|
46
|
+
resource = resource.to_sym
|
47
|
+
|
48
|
+
unless %i[calories steps distance floors elevation].include?(resource)
|
49
|
+
raise FitgemOauth2::InvalidArgumentError,
|
50
|
+
'Must specify resource to fetch intraday time series data for.'\
|
51
|
+
' One of (:calories, :steps, :distance, :floors, or :elevation) is required.'
|
48
52
|
end
|
49
53
|
|
50
|
-
unless
|
51
|
-
raise FitgemOauth2::InvalidArgumentError,
|
54
|
+
unless start_date
|
55
|
+
raise FitgemOauth2::InvalidArgumentError,
|
56
|
+
'Must specify the start_date to fetch intraday time series data'
|
52
57
|
end
|
53
58
|
|
54
|
-
|
55
|
-
|
59
|
+
end_date ||= '1d'
|
60
|
+
|
61
|
+
unless detail_level && %w(1min 15min).include?(detail_level)
|
62
|
+
raise FitgemOauth2::InvalidArgumentError,
|
63
|
+
'Must specify the data resolution to fetch intraday time series data for.'\
|
64
|
+
' One of (\"1d\" or \"15min\") is required.'
|
56
65
|
end
|
57
66
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
else
|
69
|
-
resource_path += "#{resource}/date/#{date}/1d/#{detail_level}.json"
|
67
|
+
resource_path = [
|
68
|
+
'user', @user_id,
|
69
|
+
'activities', resource,
|
70
|
+
'date', format_date(start_date),
|
71
|
+
end_date, detail_level
|
72
|
+
].join('/')
|
73
|
+
|
74
|
+
if start_time || end_time
|
75
|
+
resource_path =
|
76
|
+
[resource_path, 'time', format_time(start_time), format_time(end_time)].join('/')
|
70
77
|
end
|
71
|
-
get_call(resource_path)
|
78
|
+
get_call("#{resource_path}.json")
|
72
79
|
end
|
73
80
|
|
81
|
+
# ======================================
|
82
|
+
# Activity Logging Methods
|
83
|
+
# ======================================
|
84
|
+
|
85
|
+
def log_activity(params)
|
86
|
+
post_call("user/#{user_id}/activities.json", params)
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete_logged_activity(id)
|
90
|
+
delete_call("user/#{user_id}/activities/#{id}.json")
|
91
|
+
end
|
92
|
+
|
93
|
+
def activity_list
|
94
|
+
get_call("user/#{user_id}/activities/list.json")
|
95
|
+
end
|
96
|
+
|
97
|
+
def activity_tcx(id)
|
98
|
+
get_call("user/#{user_id}/activities/#{id}.tcx")
|
99
|
+
end
|
100
|
+
|
101
|
+
|
74
102
|
# ======================================
|
75
103
|
# Activity Types
|
76
104
|
# ======================================
|
77
105
|
def activities
|
78
|
-
get_call("
|
106
|
+
get_call("activities.json")
|
79
107
|
end
|
80
108
|
|
81
109
|
def activity(id)
|
82
|
-
get_call("
|
110
|
+
get_call("activities/#{id}.json")
|
83
111
|
end
|
84
112
|
|
85
113
|
def frequent_activities
|
86
|
-
get_call("
|
114
|
+
get_call("user/#{user_id}/activities/frequent.json")
|
87
115
|
end
|
88
116
|
|
89
117
|
def recent_activities
|
90
|
-
get_call("
|
118
|
+
get_call("user/#{user_id}/activities/recent.json")
|
91
119
|
end
|
92
120
|
|
93
121
|
def favorite_activities
|
94
|
-
get_call("
|
122
|
+
get_call("user/#{user_id}/activities/favorite.json")
|
95
123
|
end
|
96
124
|
|
97
|
-
|
98
|
-
|
99
|
-
# ======================================
|
100
|
-
|
101
|
-
def goals(period)
|
102
|
-
unless period && [:daily, :weekly].include?(period)
|
103
|
-
raise FitgemOauth2::InvalidArgumentError, "Goal period should either be 'daily' or 'weekly'"
|
104
|
-
end
|
125
|
+
def add_favorite_activity(activity_id)
|
126
|
+
post_call("user/#{user_id}/activities/log/favorite/#{activity_id}.json")
|
105
127
|
end
|
106
128
|
|
107
|
-
def
|
108
|
-
|
129
|
+
def remove_favorite_activity(activity_id)
|
130
|
+
delete_call("user/#{user_id}/activities/log/favorite/#{activity_id}.json")
|
109
131
|
end
|
110
132
|
|
111
133
|
# ======================================
|
112
|
-
#
|
134
|
+
# Activity Goals
|
113
135
|
# ======================================
|
114
136
|
|
115
|
-
|
116
|
-
|
117
|
-
|
137
|
+
def goals(period)
|
138
|
+
unless period && %w(daily weekly).include?(period)
|
139
|
+
raise FitgemOauth2::InvalidArgumentError, "Goal period should either be 'daily' or 'weekly'"
|
140
|
+
end
|
141
|
+
get_call("user/#{user_id}/activities/goals/#{period}.json")
|
118
142
|
end
|
119
143
|
|
120
|
-
def
|
121
|
-
|
144
|
+
def update_activity_goals(period, params)
|
145
|
+
unless period && %w(daily weekly).include?(period)
|
146
|
+
raise FitgemOauth2::InvalidArgumentError, "Goal period should either be 'daily' or 'weekly'"
|
147
|
+
end
|
148
|
+
post_call("user/#{user_id}/activities/goals/#{period}.json", params)
|
122
149
|
end
|
123
150
|
|
124
|
-
def
|
125
|
-
|
151
|
+
def lifetime_stats
|
152
|
+
get_call("user/#{user_id}/activities.json")
|
126
153
|
end
|
127
154
|
end
|
128
155
|
end
|
@@ -1,68 +1,135 @@
|
|
1
1
|
module FitgemOauth2
|
2
2
|
class Client
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
FAT_PERIODS = %w(1d 7d 1w 1m)
|
4
|
+
WEIGHT_PERIODS = %w(1d 7d 30d 1w 1m)
|
5
|
+
BODY_GOALS = %w(fat weight)
|
6
|
+
BODY_TIME_SERIES_PERIODS = %w(1d 7d 30d 1w 1m 3m 6m 1y max)
|
7
|
+
|
6
8
|
# ======================================
|
7
|
-
# Boday Fat
|
9
|
+
# Boday Fat
|
8
10
|
# ======================================
|
9
11
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
12
|
+
def body_fat_logs(start_date: nil, end_date: nil, period: nil)
|
13
|
+
unless start_date
|
14
|
+
raise FitgemOauth2::InvalidArgumentError, 'must specify start_date'
|
15
|
+
end
|
16
|
+
url = ['user', user_id, 'body/log/fat/date', format_date(start_date)].join('/')
|
17
|
+
if end_date
|
18
|
+
url = [url, format_date(end_date)].join('/')
|
19
|
+
end
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
21
|
+
if period
|
22
|
+
if FAT_PERIODS.include?(period)
|
23
|
+
url = [url, period].join('/')
|
24
|
+
else
|
25
|
+
raise FitgemOauth2::InvalidArgumentError, "period must be one in #{FAT_PERIODS}"
|
26
|
+
end
|
19
27
|
end
|
28
|
+
|
29
|
+
url = url + '.json'
|
30
|
+
|
31
|
+
get_call(url)
|
20
32
|
end
|
21
33
|
|
22
|
-
def
|
23
|
-
|
34
|
+
def log_body_fat(params)
|
35
|
+
post_call("user/#{user_id}/body/log/fat.json", params)
|
24
36
|
end
|
25
37
|
|
38
|
+
def delete_logged_body_fat(id)
|
39
|
+
delete_call("user/#{user_id}/body/log/fat/#{id}.json")
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
# ==================================
|
44
|
+
# Body Time Series
|
45
|
+
# ==================================
|
46
|
+
|
47
|
+
def body_time_series(resource: nil, start_date: nil, end_date: nil, period: nil)
|
48
|
+
unless resource && start_date
|
49
|
+
raise FitgemOauth2::InvalidArgumentError, 'resource and start_date are required parameters. Please specify both.'
|
50
|
+
end
|
51
|
+
|
52
|
+
url = ['user', user_id, 'body', resource, 'date', format_date(start_date)].join('/')
|
53
|
+
|
54
|
+
second = ''
|
55
|
+
if end_date && period
|
56
|
+
raise FitgemOauth2::InvalidArgumentError, 'Please specify either period or end date, not both.'
|
57
|
+
end
|
58
|
+
|
59
|
+
if period
|
60
|
+
if BODY_TIME_SERIES_PERIODS.include?(period)
|
61
|
+
second = period
|
62
|
+
else
|
63
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid Period. Body time series period must be in #{BODY_TIME_SERIES_PERIODS}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
if end_date
|
68
|
+
second = format_date(end_date)
|
69
|
+
end
|
70
|
+
|
71
|
+
url = [url, second].join('/')
|
72
|
+
|
73
|
+
get_call(url + '.json')
|
74
|
+
end
|
75
|
+
|
76
|
+
|
26
77
|
# ======================================
|
27
|
-
# Body Goals
|
78
|
+
# Body Goals
|
28
79
|
# ======================================
|
29
|
-
|
30
|
-
def
|
31
|
-
if type &&
|
32
|
-
get_call("
|
80
|
+
|
81
|
+
def body_goals(type)
|
82
|
+
if type && BODY_GOALS.include?(type)
|
83
|
+
get_call("user/#{user_id}/body/log/#{type}/goal.json")
|
33
84
|
else
|
34
|
-
raise FitgemOauth2::InvalidArgumentError, "goal type
|
85
|
+
raise FitgemOauth2::InvalidArgumentError, "invalid goal type : #{type}. must be one of #{BODY_GOALS}"
|
35
86
|
end
|
36
87
|
end
|
37
88
|
|
89
|
+
def update_body_fat_goal(params)
|
90
|
+
post_call("user/#{user_id}/body/log/fat/goal.json", params)
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_weight_goal(params)
|
94
|
+
post_call("user/#{user_id}/body/log/weight/goal.json", params)
|
95
|
+
end
|
96
|
+
|
38
97
|
# ======================================
|
39
|
-
# Body Weight
|
98
|
+
# Body Weight
|
40
99
|
# ======================================
|
41
100
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
101
|
+
def weight_logs(start_date: nil, end_date: nil, period: nil)
|
102
|
+
unless start_date
|
103
|
+
raise FitgemOauth2::InvalidArgumentError, 'start_date not specified.'
|
104
|
+
end
|
45
105
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
106
|
+
if period && end_date
|
107
|
+
raise FitgemOauth2::InvalidArgumentError, 'both end_date and period specified. please provide only one.'
|
108
|
+
end
|
109
|
+
|
110
|
+
if period
|
111
|
+
unless WEIGHT_PERIODS.include?(period)
|
112
|
+
raise FitgemOauth2::InvalidArgumentError, "valid period not specified. please choose a period from #{WEIGHT_PERIODS}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
first = format_date(start_date)
|
117
|
+
url = ['user', user_id, 'body/log/weight/date', first].join('/')
|
118
|
+
if period || end_date
|
119
|
+
second = period || format_date(end_date)
|
120
|
+
url = [url, second].join('/')
|
51
121
|
end
|
52
|
-
end
|
53
122
|
|
54
|
-
|
55
|
-
get_call("1/user/#{@user_id}/body/log/weight/date/#{format_date(start_date)}/#{format_date(end_date)}.json")
|
123
|
+
get_call(url + '.json')
|
56
124
|
end
|
57
125
|
|
58
126
|
|
59
|
-
|
60
|
-
|
61
|
-
return period && fat_periods.include?(period)
|
127
|
+
def log_weight(params)
|
128
|
+
post_call("user/#{user_id}/body/log/weight.json", params)
|
62
129
|
end
|
63
130
|
|
64
|
-
def
|
65
|
-
|
131
|
+
def delete_logged_weight(id)
|
132
|
+
delete_call("user/#{user_id}/body/log/weight/#{id}.json")
|
66
133
|
end
|
67
134
|
|
68
135
|
end
|
data/lib/fitgem_oauth2/client.rb
CHANGED
@@ -6,7 +6,6 @@ require 'fitgem_oauth2/food.rb'
|
|
6
6
|
require 'fitgem_oauth2/friends.rb'
|
7
7
|
require 'fitgem_oauth2/heartrate.rb'
|
8
8
|
require 'fitgem_oauth2/sleep.rb'
|
9
|
-
require 'fitgem_oauth2/steps.rb'
|
10
9
|
require 'fitgem_oauth2/subscriptions.rb'
|
11
10
|
require 'fitgem_oauth2/users.rb'
|
12
11
|
require 'fitgem_oauth2/utils.rb'
|
@@ -19,6 +18,7 @@ module FitgemOauth2
|
|
19
18
|
class Client
|
20
19
|
|
21
20
|
DEFAULT_USER_ID = '-'
|
21
|
+
API_VERSION = '1'
|
22
22
|
|
23
23
|
attr_reader :client_id
|
24
24
|
attr_reader :client_secret
|
@@ -36,33 +36,36 @@ module FitgemOauth2
|
|
36
36
|
@token = opts[:token]
|
37
37
|
@user_id = (opts[:user_id] || DEFAULT_USER_ID)
|
38
38
|
|
39
|
-
@connection = Faraday.new(
|
39
|
+
@connection = Faraday.new('https://api.fitbit.com')
|
40
40
|
end
|
41
41
|
|
42
42
|
def refresh_access_token(refresh_token)
|
43
43
|
response = connection.post('/oauth2/token') do |request|
|
44
44
|
encoded = Base64.strict_encode64("#{@client_id}:#{@client_secret}")
|
45
45
|
request.headers['Authorization'] = "Basic #{encoded}"
|
46
|
-
request.headers['Content-Type'] =
|
47
|
-
request.params['grant_type'] =
|
46
|
+
request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
47
|
+
request.params['grant_type'] = 'refresh_token'
|
48
48
|
request.params['refresh_token'] = refresh_token
|
49
49
|
end
|
50
|
-
|
50
|
+
JSON.parse(response.body)
|
51
51
|
end
|
52
52
|
|
53
53
|
def get_call(url)
|
54
|
+
url = "#{API_VERSION}/#{url}"
|
54
55
|
response = connection.get(url) { |request| set_headers(request) }
|
55
|
-
|
56
|
+
parse_response(response)
|
56
57
|
end
|
57
58
|
|
58
59
|
def post_call(url, params = {})
|
60
|
+
url = "#{API_VERSION}/#{url}"
|
59
61
|
response = connection.post(url, params) { |request| set_headers(request) }
|
60
|
-
|
62
|
+
parse_response(response)
|
61
63
|
end
|
62
64
|
|
63
65
|
def delete_call(url)
|
66
|
+
url = "#{API_VERSION}/#{url}"
|
64
67
|
response = connection.delete(url) { |request| set_headers(request) }
|
65
|
-
|
68
|
+
parse_response(response)
|
66
69
|
end
|
67
70
|
|
68
71
|
private
|
@@ -70,21 +73,27 @@ module FitgemOauth2
|
|
70
73
|
|
71
74
|
def set_headers(request)
|
72
75
|
request.headers['Authorization'] = "Bearer #{token}"
|
73
|
-
request.headers['Content-Type'] =
|
76
|
+
request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
74
77
|
end
|
75
78
|
|
76
79
|
def parse_response(response)
|
77
|
-
headers_to_keep =
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
80
|
+
headers_to_keep = %w(fitbit-rate-limit-limit fitbit-rate-limit-remaining fitbit-rate-limit-reset)
|
81
|
+
|
82
|
+
error_handler = {
|
83
|
+
200 => lambda { JSON.parse(response.body).merge!(response.headers.slice(*headers_to_keep)) },
|
84
|
+
400 => lambda { raise FitgemOauth2::BadRequestError },
|
85
|
+
401 => lambda { raise FitgemOauth2::UnauthorizedError },
|
86
|
+
403 => lambda { raise FitgemOauth2::ForbiddenError },
|
87
|
+
404 => lambda { raise FitgemOauth2::NotFoundError },
|
88
|
+
500..599 => lambda { raise FitgemOauth2::ServerError }
|
89
|
+
}
|
90
|
+
|
91
|
+
fn = error_handler.detect { |k , _| k === response.status }
|
92
|
+
if fn === nil
|
93
|
+
raise StandardError, "Unexpected response status #{response.status}"
|
94
|
+
else
|
95
|
+
fn.last.call
|
86
96
|
end
|
87
97
|
end
|
88
|
-
|
89
98
|
end
|
90
99
|
end
|
@@ -1,11 +1,30 @@
|
|
1
1
|
module FitgemOauth2
|
2
2
|
class Client
|
3
|
+
|
4
|
+
# ==================================
|
5
|
+
# Devices
|
6
|
+
# ==================================
|
3
7
|
def devices
|
4
|
-
get_call("
|
8
|
+
get_call("user/#{user_id}/devices.json")
|
5
9
|
end
|
6
10
|
|
11
|
+
# ==================================
|
12
|
+
# Alarams
|
13
|
+
# ==================================
|
7
14
|
def alarms(tracker_id)
|
8
|
-
get_call("
|
15
|
+
get_call("user/#{user_id}/devices/tracker/#{tracker_id}/alarms.json")
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_alarm(tracker_id, params)
|
19
|
+
post_call("user/#{user_id}/devices/tracker/#{tracker_id}/alarms.json", params)
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_alarm(tracker_id, alarm_id, params)
|
23
|
+
post_call("user/#{user_id}/devices/tracker/#{tracker_id}/alarms/#{alarm_id}.json", params)
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_alarm(tracker_id, alarm_id)
|
27
|
+
delete_call("user/#{user_id}/devices/tracker/#{tracker_id}/alarms/#{alarm_id}.json")
|
9
28
|
end
|
10
29
|
end
|
11
30
|
end
|
data/lib/fitgem_oauth2/errors.rb
CHANGED
data/lib/fitgem_oauth2/food.rb
CHANGED
@@ -1,58 +1,157 @@
|
|
1
1
|
module FitgemOauth2
|
2
2
|
class Client
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
FOOD_SERIES_RESOURCES = %w( caloriesIn water )
|
5
|
+
FOOD_SERIES_PERIODS = %w( 1d 7d 30d 1w 1m 3m 6m 1y max )
|
6
|
+
|
7
|
+
|
8
|
+
# ==================================
|
9
|
+
# Food or Water Series
|
10
|
+
# ==================================
|
11
|
+
|
12
|
+
|
13
|
+
def food_series(resource: nil, start_date: nil, end_date: nil, period: nil)
|
14
|
+
|
15
|
+
unless FOOD_SERIES_RESOURCES.include?(resource)
|
16
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid resource: #{resource}. Specify a valid resource from #{FOOD_SERIES_RESOURCES}"
|
17
|
+
end
|
18
|
+
|
19
|
+
if end_date && period
|
20
|
+
raise FitgemOauth2::InvalidArgumentError, 'Provide only one of end_date and period.'
|
21
|
+
end
|
22
|
+
|
23
|
+
if !end_date && !period
|
24
|
+
raise FitgemOauth2::InvalidArgumentError, 'Provide at least one of end_date and period.'
|
25
|
+
end
|
26
|
+
|
27
|
+
url = ['user', user_id, 'foods/log', resource, 'date', start_date].join('/')
|
28
|
+
|
29
|
+
if period
|
30
|
+
unless FOOD_SERIES_PERIODS.include?(period)
|
31
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid period: #{period}. Specify a valid period from #{FOOD_SERIES_PERIODS}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
second = period || format_date(end_date)
|
36
|
+
url = [url, second].join('/')
|
37
|
+
|
38
|
+
get_call(url + '.json')
|
5
39
|
end
|
6
40
|
|
7
|
-
|
8
|
-
|
41
|
+
# ==================================
|
42
|
+
# Collection data
|
43
|
+
# ==================================
|
44
|
+
|
45
|
+
def food_goals
|
46
|
+
get_call("user/#{user_id}/foods/log/goal.json")
|
9
47
|
end
|
10
48
|
|
11
|
-
def
|
12
|
-
get_call("
|
49
|
+
def food_logs(date)
|
50
|
+
get_call("user/#{user_id}/foods/log/date/#{format_date(date)}.json")
|
51
|
+
end
|
52
|
+
|
53
|
+
def water_logs(date)
|
54
|
+
get_call("user/#{user_id}/foods/log/water/date/#{format_date(date)}.json")
|
13
55
|
end
|
14
56
|
|
15
57
|
def water_goal
|
16
|
-
get_call("
|
58
|
+
get_call("user/#{user_id}/foods/log/water/goal.json")
|
17
59
|
end
|
18
60
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
61
|
+
def log_food(params)
|
62
|
+
post_call("user/#{user_id}/foods/log.json", params)
|
63
|
+
end
|
22
64
|
|
23
|
-
|
24
|
-
|
25
|
-
|
65
|
+
def update_food_log(food_log_id, params)
|
66
|
+
post_call("user/#{user_id}/foods/log/#{food_log_id}.json", params)
|
67
|
+
end
|
26
68
|
|
27
|
-
|
28
|
-
|
29
|
-
|
69
|
+
def log_water(params)
|
70
|
+
post_call("user/#{user_id}/foods/log/water.json", params)
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_food_goal(params)
|
74
|
+
post_call("user/#{user_id}/foods/log/goal.json", params)
|
75
|
+
end
|
30
76
|
|
31
|
-
|
77
|
+
def update_water_goal(params)
|
78
|
+
post_call("user/#{user_id}/foods/log/water/goal.json", params)
|
79
|
+
end
|
32
80
|
|
81
|
+
def delete_food_log(food_log_id)
|
82
|
+
delete_call("user/#{user_id}/foods/log/#{food_log_id}.json")
|
33
83
|
end
|
34
84
|
|
35
|
-
def
|
36
|
-
|
85
|
+
def update_water_log(water_log_id, params)
|
86
|
+
post_call("user/#{user_id}/foods/log/water/#{water_log_id}.json", params)
|
87
|
+
end
|
37
88
|
|
38
|
-
|
39
|
-
|
40
|
-
|
89
|
+
def delete_water_log(water_log_id)
|
90
|
+
delete_call("user/#{user_id}/foods/log/water/#{water_log_id}.json")
|
91
|
+
end
|
92
|
+
|
93
|
+
# ==================================
|
94
|
+
# Collection Metadata
|
95
|
+
# ==================================
|
96
|
+
|
97
|
+
def add_favorite_food(food_id)
|
98
|
+
post_call("user/#{user_id}/foods/log/favorite/#{food_id}.json")
|
99
|
+
end
|
100
|
+
|
101
|
+
def delete_favorite_food(food_id)
|
102
|
+
delete_call("user/#{user_id}/foods/log/favorite/#{food_id}.json")
|
103
|
+
end
|
104
|
+
|
105
|
+
def recent_foods
|
106
|
+
get_call("user/#{user_id}/foods/recent.json")
|
107
|
+
end
|
108
|
+
|
109
|
+
def favorite_foods
|
110
|
+
get_call("user/#{user_id}/foods/log/favorite.json")
|
111
|
+
end
|
41
112
|
|
42
|
-
|
113
|
+
def frequent_foods
|
114
|
+
get_call("user/#{user_id}/foods/log/frequent.json")
|
115
|
+
end
|
116
|
+
|
117
|
+
def meals
|
118
|
+
get_call("user/#{user_id}/meals.json")
|
119
|
+
end
|
120
|
+
|
121
|
+
def create_meal(params)
|
122
|
+
post_call("user/#{user_id}/meals.json", params)
|
123
|
+
end
|
124
|
+
|
125
|
+
def meal(meal_id)
|
126
|
+
get_call("user/#{user_id}/meals/#{meal_id}.json")
|
127
|
+
end
|
128
|
+
|
129
|
+
def update_meal(meal_id, params)
|
130
|
+
post_call("user/#{user_id}/meals/#{meal_id}.json", params)
|
131
|
+
end
|
132
|
+
|
133
|
+
def delete_meal(meal_id)
|
134
|
+
delete_call("user/#{user_id}/meals/#{meal_id}.json")
|
135
|
+
end
|
136
|
+
|
137
|
+
def create_food(params)
|
138
|
+
post_call("user/#{user_id}/foods.json", params)
|
139
|
+
end
|
43
140
|
|
141
|
+
def delete_food(food_id)
|
142
|
+
delete_call("user/#{user_id}/foods/#{food_id}.json")
|
44
143
|
end
|
45
144
|
|
46
145
|
def food(id)
|
47
|
-
get_call("
|
146
|
+
get_call("foods/#{id}.json")
|
48
147
|
end
|
49
148
|
|
50
149
|
def food_units
|
51
|
-
get_call(
|
150
|
+
get_call('foods/units.json')
|
52
151
|
end
|
53
152
|
|
54
|
-
def
|
55
|
-
|
153
|
+
def search_foods(params)
|
154
|
+
post_call('foods/search.json', params)
|
56
155
|
end
|
57
156
|
end
|
58
157
|
end
|
@@ -1,19 +1,35 @@
|
|
1
1
|
module FitgemOauth2
|
2
2
|
class Client
|
3
3
|
def friends
|
4
|
-
get_call("
|
4
|
+
get_call("user/#{user_id}/friends.json")
|
5
5
|
end
|
6
6
|
|
7
7
|
def friends_leaderboard
|
8
|
-
get_call("
|
8
|
+
get_call("user/#{user_id}/friends/leaderboard.json")
|
9
|
+
end
|
10
|
+
|
11
|
+
# ==================================
|
12
|
+
# Friend Invitations
|
13
|
+
# ==================================
|
14
|
+
|
15
|
+
def invite_friend(params)
|
16
|
+
post_call("user/#{user_id}/friends/invitations.json", params)
|
9
17
|
end
|
10
18
|
|
11
19
|
def friend_invitations
|
12
|
-
get_call("
|
20
|
+
get_call("user/#{user_id}/friends/invitations.json")
|
13
21
|
end
|
14
22
|
|
23
|
+
def respond_to_invitation(from_user_id, params)
|
24
|
+
post_call("user/#{user_id}/friends/invitations/#{from_user_id}.json", params)
|
25
|
+
end
|
26
|
+
|
27
|
+
# ==================================
|
28
|
+
# Badges
|
29
|
+
# ==================================
|
30
|
+
|
15
31
|
def badges
|
16
|
-
get_call("
|
32
|
+
get_call("user/#{user_id}/badges.json")
|
17
33
|
end
|
18
34
|
end
|
19
35
|
end
|
@@ -1,53 +1,55 @@
|
|
1
1
|
module FitgemOauth2
|
2
2
|
class Client
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
end
|
4
|
+
HR_PERIODS = %w(1d 7d 30d 1w 1m)
|
5
|
+
HR_DETAIL_LEVELS = %w(1sec 1min)
|
7
6
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
raise InvalidArgumentError, "period should be one of #{periods}"
|
7
|
+
def heartrate_time_series(start_date: nil, end_date: nil, period: nil)
|
8
|
+
unless start_date
|
9
|
+
raise FitgemOauth2::InvalidArgumentError, 'Start date not provided.'
|
12
10
|
end
|
13
|
-
get_call("1/user/#{@user_id}/activities/heart/date/#{format_date(date)}/#{period}.json")
|
14
|
-
end
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
if end_date && period
|
13
|
+
raise FitgemOauth2::InvalidArgumentError, 'Both end_date and period specified. Specify only one.'
|
14
|
+
end
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
unless detail_level && detail_levels.include?(detail_level)
|
23
|
-
raise InvalidArgumentError, "detail level should be one of #{detail_levels}"
|
16
|
+
if !end_date && !period
|
17
|
+
raise FitgemOauth2::InvalidArgumentError, 'Neither end_date nor period specified. Specify at least one.'
|
24
18
|
end
|
25
|
-
get_call("/1/user/#{@user_id}/activities/heart/date/#{format_date(start_date)}/#{format_date(end_date)}/#{detail_level}.json")
|
26
|
-
end
|
27
19
|
|
28
|
-
|
29
|
-
|
30
|
-
unless detail_level && detail_levels.include?(detail_level)
|
31
|
-
raise InvalidArgumentError, "detail level should be one of #{detail_levels}"
|
20
|
+
if period && !HR_PERIODS.include?(period)
|
21
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid period: #{period}. Valid periods are #{HR_PERIODS}."
|
32
22
|
end
|
33
|
-
|
23
|
+
|
24
|
+
second = period || format_date(end_date)
|
25
|
+
|
26
|
+
url = ['user', user_id, 'activities/heart/date', format_date(start_date), second].join('/')
|
27
|
+
|
28
|
+
get_call(url + '.json')
|
34
29
|
end
|
35
30
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
raise InvalidArgumentError, "detail level should be one of #{detail_levels}"
|
31
|
+
def intraday_heartrate_time_series(start_date: nil, end_date: nil, detail_level: nil, start_time: nil, end_time: nil)
|
32
|
+
unless start_date
|
33
|
+
raise FitgemOauth2::InvalidArgumentError, 'Start date not provided.'
|
40
34
|
end
|
41
|
-
get_call("1/user/#{@user_id}/activities/heart/date/#{format_date(start_date)}/1d/#{detail_level}.json")
|
42
|
-
end
|
43
35
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
36
|
+
unless detail_level && HR_DETAIL_LEVELS.include?(detail_level)
|
37
|
+
raise FitgemOauth2::InvalidArgumentError, "Please specify the defail level. Detail level should be one of #{HR_DETAIL_LEVELS}."
|
38
|
+
end
|
39
|
+
|
40
|
+
end_date = format_date(end_date) || '1d'
|
41
|
+
|
42
|
+
url = ['user', user_id, 'activities/heart/date', format_date(start_date), end_date, detail_level].join('/')
|
43
|
+
|
44
|
+
if (start_time && !end_time) || (end_time && !start_time)
|
45
|
+
raise FitgemOauth2::InvalidArgumentError, 'Either specify both the start_time and end_time or specify neither.'
|
46
|
+
end
|
47
|
+
|
48
|
+
if start_time && end_time
|
49
|
+
url = [url, 'time', format_time(start_time), format_time(end_time)].join('/')
|
48
50
|
end
|
49
|
-
get_call("1/user/#{@user_id}/activities/heart/date/#{format_date(start_date)}/1d/#{detail_level}/time/#{start_time}/#{end_time}.json")
|
50
|
-
end
|
51
51
|
|
52
|
+
get_call(url + '.json')
|
53
|
+
end
|
52
54
|
end
|
53
55
|
end
|
data/lib/fitgem_oauth2/sleep.rb
CHANGED
@@ -2,8 +2,51 @@ module FitgemOauth2
|
|
2
2
|
|
3
3
|
class Client
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
SLEEP_RESOURCES = %w(startTime timeInBed minutesAsleep awakeningsCount minutesAwake minutesToFallAsleep minutesAfterWakeup efficiency)
|
6
|
+
SLEEP_PERIODS = %w(1d 7d 30d 1w 1m 3m 6m 1y max)
|
7
|
+
|
8
|
+
def sleep_logs(date)
|
9
|
+
get_call("user/#{user_id}/sleep/date/#{format_date(date)}.json")
|
10
|
+
end
|
11
|
+
|
12
|
+
def sleep_goal
|
13
|
+
get_call("user/#{user_id}/sleep/goal.json")
|
14
|
+
end
|
15
|
+
|
16
|
+
def update_sleep_goal(params)
|
17
|
+
post_call("user/#{user_id}/sleep/goal.json", params)
|
18
|
+
end
|
19
|
+
|
20
|
+
def sleep_time_series(resource: nil, start_date: nil, end_date: nil, period: nil)
|
21
|
+
unless start_date
|
22
|
+
raise FitgemOauth2::InvalidArgumentError, 'Start date not provided.'
|
23
|
+
end
|
24
|
+
|
25
|
+
unless resource && SLEEP_RESOURCES.include?(resource)
|
26
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid resource: #{resource}. Valid resources are #{SLEEP_RESOURCES}."
|
27
|
+
end
|
28
|
+
|
29
|
+
if period && end_date
|
30
|
+
raise FitgemOauth2::InvalidArgumentError, 'Both end_date and period specified. Specify only one.'
|
31
|
+
end
|
32
|
+
|
33
|
+
if period && !SLEEP_PERIODS.include?(period)
|
34
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid period: #{period}. Valid periods are #{SLEEP_PERIODS}."
|
35
|
+
end
|
36
|
+
|
37
|
+
second = period || format_date(end_date)
|
38
|
+
|
39
|
+
url = ['user', user_id, 'sleep', resource, 'date', format_date(start_date), second].join('/')
|
40
|
+
|
41
|
+
get_call(url + '.json')
|
42
|
+
end
|
43
|
+
|
44
|
+
def log_sleep(params)
|
45
|
+
post_call("user/#{user_id}/sleep.json", params)
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete_logged_sleep(log_id)
|
49
|
+
delete_call("user/#{user_id}/sleep/#{log_id}.json")
|
7
50
|
end
|
8
51
|
|
9
52
|
end
|
@@ -21,7 +21,7 @@ module FitgemOauth2
|
|
21
21
|
type = opts[ :type ] || :all
|
22
22
|
subscription_id = opts[:subscription_id]
|
23
23
|
|
24
|
-
url = [ '
|
24
|
+
url = [ 'user', user_id ]
|
25
25
|
url << type unless type == :all
|
26
26
|
url << 'apiSubscriptions'
|
27
27
|
url << subscription_id if subscription_id
|
data/lib/fitgem_oauth2/users.rb
CHANGED
data/lib/fitgem_oauth2/utils.rb
CHANGED
@@ -1,38 +1,42 @@
|
|
1
1
|
module FitgemOauth2
|
2
2
|
class Client
|
3
|
-
|
4
|
-
# Format any of a variety of date types into the formatted string
|
5
|
-
# required when using the fitbit API.
|
6
|
-
#
|
7
|
-
# The date parameter can take several different kind of objects: a
|
8
|
-
# DateTime object, a Date object, a Time object or a String object. Furthermore,
|
9
|
-
# the string object may be either the date in a preformatted string
|
10
|
-
# ("yyyy-MM-dd"), or it may be the string values "today" or
|
11
|
-
# "tomorrow".
|
12
|
-
#
|
13
|
-
# @param [DateTime, Date, Time, String] date The object to format into a
|
14
|
-
# date string
|
15
|
-
# @raise [Fitgem::InvalidDateArgument] Raised when the object is
|
16
|
-
# not a DateTime, Date, Time or a valid (yyyy-MM-dd) String object
|
17
|
-
# @return [String] Date in "yyyy-MM-dd" string format
|
3
|
+
|
18
4
|
def format_date(date)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
5
|
+
|
6
|
+
if !date
|
7
|
+
return nil
|
8
|
+
end
|
9
|
+
|
10
|
+
valid_semantic_date = %w(today yesterday).include? date
|
11
|
+
valid_date_string = ((date =~ /\d{4}\-\d{2}\-\d{2}/) == 0)
|
12
|
+
if valid_date_string
|
13
|
+
date
|
14
|
+
elsif valid_semantic_date
|
15
|
+
date_from_semantic(date)
|
31
16
|
elsif Date === date || Time === date || DateTime === date
|
32
|
-
|
17
|
+
date.strftime('%Y-%m-%d')
|
33
18
|
else
|
34
19
|
raise FitgemOauth2::InvalidDateArgument, "Date used must be a date/time object or a string in the format YYYY-MM-DD; supplied argument is a #{date.class}"
|
35
20
|
end
|
36
21
|
end
|
22
|
+
|
23
|
+
def format_time(time)
|
24
|
+
if ( (time =~ /\d{2}:\d{2}/) == 0)
|
25
|
+
time
|
26
|
+
elsif DateTime === time || Time === time
|
27
|
+
time.strftime('%H:%M')
|
28
|
+
else
|
29
|
+
raise FitgemOauth2::InvalidTimeArgument, "Time used must be a DateTime/Time object or a string in the format hh:mm; supplied argument is a #{time.class}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def date_from_semantic(semantic)
|
35
|
+
if semantic === 'yesterday'
|
36
|
+
(Date.today-1).strftime('%Y-%m-%d')
|
37
|
+
elsif semantic == 'today'
|
38
|
+
Date.today.strftime('%Y-%m-%d')
|
39
|
+
end
|
40
|
+
end
|
37
41
|
end
|
38
42
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fitgem_oauth2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ankit Gupta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -25,47 +25,47 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '10.5'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '10.5'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '4
|
47
|
+
version: '3.4'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '4
|
54
|
+
version: '3.4'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: factory_girl
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '4.5'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '4.5'
|
69
69
|
description: This gem allows requesting data from Fitbit API using OAuth2
|
70
70
|
email: ankit.gupta2801@gmail.com
|
71
71
|
executables: []
|
@@ -83,7 +83,6 @@ files:
|
|
83
83
|
- lib/fitgem_oauth2/friends.rb
|
84
84
|
- lib/fitgem_oauth2/heartrate.rb
|
85
85
|
- lib/fitgem_oauth2/sleep.rb
|
86
|
-
- lib/fitgem_oauth2/steps.rb
|
87
86
|
- lib/fitgem_oauth2/subscriptions.rb
|
88
87
|
- lib/fitgem_oauth2/users.rb
|
89
88
|
- lib/fitgem_oauth2/utils.rb
|
@@ -113,4 +112,3 @@ signing_key:
|
|
113
112
|
specification_version: 4
|
114
113
|
summary: Fitbit API client library
|
115
114
|
test_files: []
|
116
|
-
has_rdoc:
|