fitgem_oauth2 0.0.8 → 1.0.2
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.
- 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:
|