fitgem 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ pkg/*
5
5
  .yardoc/*
6
6
  test*.rb
7
7
  *.dmp
8
+ .fitgem.yml
data/changelog.md CHANGED
@@ -3,12 +3,42 @@
3
3
 
4
4
  # fitgem changelog
5
5
 
6
- ## v0.4.0
6
+ ## v0.5.2
7
+
8
+ #### 2012-03-04 Zachery Moneypenny <fitgem@whazzmaster.com>
9
+
10
+ * Added new <tt>symbolize_keys</tt> helper method for turning the string-key based return hashes into symbol-key based ones
11
+ * Added new <tt>label_for_measurement</tt> helper method to get the correct unit measurement label given a measurement type and the current user's ApiUnitSystem setting
12
+ * Added specs
13
+ * Added new <tt>connected?</tt> method on Fitgem::Client that will report whether API calls may be made
14
+ * Added <tt>InvalidUnitSystem</tt> error and <tt>InvalidMeasurementType</tt> error
15
+ * Fixed a small issue where date values were not being formatted correctly in calls to <tt>log_body_measurements</tt>
16
+
17
+ ## v0.5.1
18
+
19
+ #### 2012-01-24 Zachery Moneypenny <fitgem@whazzmaster.com>
20
+
21
+ * Fix for creating and removing data subscriptions
22
+ * Updated specs
23
+
24
+ ## v0.5.0
25
+
26
+ #### 2012-01-22 Zachery Moneypenny <fitgem@whazzmaster.com>
27
+
28
+ * Added view/log/delete access for blood pressure data
29
+ * Added view/log/delete access for glucose data
30
+ * Added view/log/delete access for heart rate data
31
+ * Added updated time series documentation for new endpoints
32
+ * Updated temporal information in the readme
33
+ * Added unit tests for <tt>format_time</tt> method
34
+ * Updated copyright date
35
+
36
+ ## v0.4.0
7
37
 
8
38
  #### 2011-11-29 Zachery Moneypenny <fitgem@whazzmaster.com>
9
39
 
10
40
  * Added YARD documentation to thoroughly document code
11
- * DEPRECATED: <tt>Fitgem::Client#log_weight</tt> method, use <tt>Fitgem::Client#log_body_measurements</tt> instead.
41
+ * DEPRECATED: <tt>Fitgem::Client#log_weight</tt> method, use <tt>Fitgem::Client#log_body_measurements</tt> instead.
12
42
  The new method allows you to log more than weight (bicep size, body fat %, etc.)
13
43
  * Added <tt>Fitgem::FoodFormType</tt> to be used in calls to <tt>Fitgem::Client#create_food</tt>
14
44
  * Added <tt>Fitgem::Client#log_sleep</tt> to log sleep data to fitbit
@@ -25,7 +25,7 @@ module Fitgem
25
25
  # an integer or a string in "X.XX'" format
26
26
  # @param [DateTime, String] date The date the weight should be
27
27
  # logged, as either a DateTime or a String in "yyyy-MM-dd" format
28
- # @return [Hash]
28
+ # @return [Hash]
29
29
  #
30
30
  # @deprecated {#log_body_measurements} should be used instead of
31
31
  # log_weight
@@ -35,7 +35,7 @@ module Fitgem
35
35
 
36
36
  # Log body measurements to fitbit for the current user
37
37
  #
38
- # At least ONE measurement item is REQUIRED in the call, as well as the
38
+ # At least ONE measurement item is REQUIRED in the call, as well as the
39
39
  # date. All measurement values to be logged for the user must be either an
40
40
  # Integer, a Decimal value, or a String in "X.XX" format. The
41
41
  # measurement units used for the supplied measurements are based on
@@ -54,13 +54,15 @@ module Fitgem
54
54
  # @option opts [Integer, Decimal, String] :bicep Bicep measurement
55
55
  # @option opts [DateTime, Date, String] :date Date to log measurements
56
56
  # for; provided either as a DateTime, Date, or a String in
57
- # "yyyy-MM-dd" format
57
+ # "yyyy-MM-dd" format
58
58
  #
59
59
  # @return [Hash] Hash containing the key +:body+ with an inner hash
60
60
  # of all of the logged measurements
61
61
  #
62
62
  # @since v0.4.0
63
63
  def log_body_measurements(opts)
64
+ # Update the date (if exists)
65
+ opts[:date] = format_date(opts[:date]) if opts[:date]
64
66
  post("/user/#{@user_id}/body.json", opts)
65
67
  end
66
68
  end
data/lib/fitgem/client.rb CHANGED
@@ -150,6 +150,13 @@ module Fitgem
150
150
  access_token
151
151
  end
152
152
 
153
+ # Get the current state of the client
154
+ #
155
+ # @return True if api calls may be made, false if not
156
+ def connected?
157
+ !@access_token.nil?
158
+ end
159
+
153
160
  # Get an oauth request token
154
161
  #
155
162
  # @param [Hash] opts Request token request data; can be used to
data/lib/fitgem/errors.rb CHANGED
@@ -13,4 +13,13 @@ module Fitgem
13
13
 
14
14
  class InvalidTimeRange < InvalidArgumentError
15
15
  end
16
+
17
+ class InvalidUnitSystem < InvalidArgumentError
18
+ end
19
+
20
+ class InvalidMeasurementType < InvalidArgumentError
21
+ end
22
+
23
+ class ConnectionRequiredError < Exception
24
+ end
16
25
  end
@@ -63,5 +63,122 @@ module Fitgem
63
63
  raise Fitgem::InvalidTimeArgument, "Date used must be a valid time object or a string in the format HH:mm; supplied argument is a #{time.class}"
64
64
  end
65
65
  end
66
+
67
+ # Fetch the correct label for the desired measurement unit.
68
+ #
69
+ # The general use case for this method is that you are using the client for
70
+ # a specific user, and wish to get the correct labels for the unit measurements
71
+ # returned for that user.
72
+ #
73
+ # A secondary use case is that you wish to get the label for a measurement given a unit
74
+ # system that you supply (by setting the Fitgem::Client.api_unit_system attribute).
75
+ #
76
+ # In order for this method to get the correct value for the current user's preferences,
77
+ # the client must have the ability to make API calls. If you respect_user_unit_preferences
78
+ # is passed as 'true' (or left as the default value) and the client cannot make API calls
79
+ # then an error will be raised by the method.
80
+ #
81
+ # @param [Symbol] measurement_type The measurement type to fetch the label for
82
+ # @param [Boolean] respect_user_unit_preferences Should the method fetch the current user's
83
+ # specific measurement preferences and use those (true), or use the value set on Fitgem::Client.api_unit_system (false)
84
+ # @raise [Fitgem::ConnectionRequiredError] Raised when respect_user_unit_preferences is true but the
85
+ # client is not capable of making API calls.
86
+ # @raise [Fitgem::InvalidUnitSystem] Raised when the current value of Fitgem::Client.api_unit_system
87
+ # is not one of [ApiUnitSystem.US, ApiUnitSystem.UK, ApiUnitSystem.METRIC]
88
+ # @raise [Fitgem::InvalidMeasurementType] Raised when the supplied measurement_type is not one of
89
+ # [:duration, :distance, :elevation, :height, :weight, :measurements, :liquids, :blood_glucose]
90
+ # @return [String] The string label corresponding to the measurement type and
91
+ # current api_unit_system.
92
+ def label_for_measurement(measurement_type, respect_user_unit_preferences=true)
93
+ unless [:duration, :distance, :elevation, :height, :weight, :measurements, :liquids, :blood_glucose].include?(measurement_type)
94
+ raise InvalidMeasurementType, "Supplied measurement_type parameter must be one of [:duration, :distance, :elevation, :height, :weight, :measurements, :liquids, :blood_glucose], current value is :#{measurement_type}"
95
+ end
96
+
97
+ selected_unit_system = api_unit_system
98
+
99
+ if respect_user_unit_preferences
100
+ unless connected?
101
+ raise ConnectionRequiredError, "No connection to Fitbit API; one is required when passing respect_user_unit_preferences=true"
102
+ end
103
+ # Cache the unit systems for the current user
104
+ @unit_systems ||= self.user_info['user'].select {|key, value| key =~ /Unit$/ }
105
+
106
+ case measurement_type
107
+ when :distance
108
+ selected_unit_system = @unit_systems["distanceUnit"]
109
+ when :height
110
+ selected_unit_system = @unit_systems["heightUnit"]
111
+ when :liquids
112
+ selected_unit_system = @unit_systems["waterUnit"]
113
+ when :weight
114
+ selected_unit_system = @unit_systems["weightUnit"]
115
+ when :blood_glucose
116
+ selected_unit_system = @unit_systems["glucoseUnit"]
117
+ else
118
+ selected_unit_system = api_unit_system
119
+ end
120
+ end
121
+
122
+ # Fix the METRIC system difference
123
+ selected_unit_system = Fitgem::ApiUnitSystem.METRIC if selected_unit_system == "METRIC"
124
+
125
+ # Ensure the target unit system is one that we know about
126
+ unless [ApiUnitSystem.US, ApiUnitSystem.UK, ApiUnitSystem.METRIC].include?(selected_unit_system)
127
+ raise InvalidUnitSystem, "The select unit system must be one of [ApiUnitSystem.US, ApiUnitSystem.UK, ApiUnitSystem.METRIC], current value is #{selected_unit_system}"
128
+ end
129
+
130
+ unit_mappings[selected_unit_system][measurement_type]
131
+ end
132
+
133
+ # Recursively turns arrays and hashes into symbol-key based
134
+ # structures.
135
+ #
136
+ # @param [Array, Hash] The structure to symbolize keys for
137
+ # @return A new structure with the keys symbolized
138
+ def self.symbolize_keys(obj)
139
+ case obj
140
+ when Array
141
+ obj.inject([]){|res, val|
142
+ res << case val
143
+ when Hash, Array
144
+ symbolize_keys(val)
145
+ else
146
+ val
147
+ end
148
+ res
149
+ }
150
+ when Hash
151
+ obj.inject({}){|res, (key, val)|
152
+ nkey = case key
153
+ when String
154
+ key.to_sym
155
+ else
156
+ key
157
+ end
158
+ nval = case val
159
+ when Hash, Array
160
+ symbolize_keys(val)
161
+ else
162
+ val
163
+ end
164
+ res[nkey] = nval
165
+ res
166
+ }
167
+ else
168
+ obj
169
+ end
170
+ end
171
+
172
+ protected
173
+
174
+ # Defined mappings for unit measurements to labels
175
+ def unit_mappings
176
+ {
177
+ ApiUnitSystem.US => { :duration => "milliseconds", :distance => "miles", :elevation => "feet", :height => "inches", :weight => "pounds", :measurements => "inches", :liquids => "fl oz", :blood_glucose => "mg/dL" },
178
+ ApiUnitSystem.UK => { :duration => "milliseconds", :distance => "kilometers", :elevation => "meters", :height => "centimeters", :weight => "stone", :measurements => "centimeters", :liquids => "mL", :blood_glucose => "mmol/l" },
179
+ ApiUnitSystem.METRIC => { :duration => "milliseconds", :distance => "kilometers", :elevation => "meters", :height => "centimeters", :weight => "kilograms", :measurements => "centimeters", :liquids => "mL", :blood_glucose => "mmol/l" }
180
+ }
181
+ end
182
+
66
183
  end
67
184
  end
@@ -1,3 +1,3 @@
1
1
  module Fitgem
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.2"
3
3
  end
@@ -124,4 +124,87 @@ describe Fitgem::Client do
124
124
  }.to raise_error Fitgem::InvalidTimeArgument
125
125
  end
126
126
  end
127
+
128
+ describe "#label_for_measurement" do
129
+ it "accepts the supported Fitgem::ApiUnitSystem values" do
130
+ @client.api_unit_system = Fitgem::ApiUnitSystem.US
131
+ @client.label_for_measurement :duration, false
132
+ @client.api_unit_system = Fitgem::ApiUnitSystem.UK
133
+ @client.label_for_measurement :duration, false
134
+ @client.api_unit_system = Fitgem::ApiUnitSystem.METRIC
135
+ @client.label_for_measurement :duration, false
136
+ end
137
+
138
+ it "raises an InvalidUnitSystem error if the Fitgem::Client.api_unit_system value is invalid" do
139
+ expect {
140
+ @client.api_unit_system = "something else entirely"
141
+ @client.label_for_measurement :duration, false
142
+ }.to raise_error Fitgem::InvalidUnitSystem
143
+ end
144
+
145
+ it "accepts the supported values for the measurement_type parameter" do
146
+ @client.label_for_measurement :duration, false
147
+ @client.label_for_measurement :distance, false
148
+ @client.label_for_measurement :elevation, false
149
+ @client.label_for_measurement :height, false
150
+ @client.label_for_measurement :weight, false
151
+ @client.label_for_measurement :measurements, false
152
+ @client.label_for_measurement :liquids, false
153
+ @client.label_for_measurement :blood_glucose, false
154
+ end
155
+
156
+ it "raises an InvalidMeasurementType error if the measurement_type parameter is invalid" do
157
+ expect {
158
+ @client.label_for_measurement :homina, false
159
+ }.to raise_error Fitgem::InvalidMeasurementType
160
+ end
161
+
162
+ it "returns the correct values when the unit system is Fitgem::ApiUnitSystem.US" do
163
+ @client.api_unit_system = Fitgem::ApiUnitSystem.US
164
+ @client.label_for_measurement(:duration, false).should == "milliseconds"
165
+ @client.label_for_measurement(:distance, false).should == "miles"
166
+ @client.label_for_measurement(:elevation, false).should == "feet"
167
+ @client.label_for_measurement(:height, false).should == "inches"
168
+ @client.label_for_measurement(:weight, false).should == "pounds"
169
+ @client.label_for_measurement(:measurements, false).should == "inches"
170
+ @client.label_for_measurement(:liquids, false).should == "fl oz"
171
+ @client.label_for_measurement(:blood_glucose, false).should == "mg/dL"
172
+ end
173
+
174
+ it "returns the correct values when the unit system is Fitgem::ApiUnitSystem.UK" do
175
+ @client.api_unit_system = Fitgem::ApiUnitSystem.UK
176
+ @client.label_for_measurement(:duration, false).should == "milliseconds"
177
+ @client.label_for_measurement(:distance, false).should == "kilometers"
178
+ @client.label_for_measurement(:elevation, false).should == "meters"
179
+ @client.label_for_measurement(:height, false).should == "centimeters"
180
+ @client.label_for_measurement(:weight, false).should == "stone"
181
+ @client.label_for_measurement(:measurements, false).should == "centimeters"
182
+ @client.label_for_measurement(:liquids, false).should == "mL"
183
+ @client.label_for_measurement(:blood_glucose, false).should == "mmol/l"
184
+ end
185
+
186
+ it "returns the correct values when the unit system is Fitgem::ApiUnitSystem.METRIC" do
187
+ @client.api_unit_system = Fitgem::ApiUnitSystem.METRIC
188
+ @client.label_for_measurement(:duration, false).should == "milliseconds"
189
+ @client.label_for_measurement(:distance, false).should == "kilometers"
190
+ @client.label_for_measurement(:elevation, false).should == "meters"
191
+ @client.label_for_measurement(:height, false).should == "centimeters"
192
+ @client.label_for_measurement(:weight, false).should == "kilograms"
193
+ @client.label_for_measurement(:measurements, false).should == "centimeters"
194
+ @client.label_for_measurement(:liquids, false).should == "mL"
195
+ @client.label_for_measurement(:blood_glucose, false).should == "mmol/l"
196
+ end
197
+
198
+ context "when respecting the user's unit measurement preferences" do
199
+ before(:each) do
200
+ @client.stub(:connected?).and_return(true)
201
+ @client.stub(:user_info).and_return({"user" => {"distanceUnit"=>"en_GB", "glucoseUnit"=>"en_GB", "heightUnit"=>"en_GB", "waterUnit"=>"METRIC", "weightUnit"=>"en_GB"}})
202
+ end
203
+
204
+ it "returns the correct overridden measurement label" do
205
+ @client.api_unit_system = Fitgem::ApiUnitSystem.US
206
+ @client.label_for_measurement(:distance).should == "kilometers"
207
+ end
208
+ end
209
+ end
127
210
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fitgem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-24 00:00:00.000000000 Z
12
+ date: 2012-03-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: oauth
16
- requirement: &70336813924980 !ruby/object:Gem::Requirement
16
+ requirement: &70237035564320 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70336813924980
24
+ version_requirements: *70237035564320
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70336813924560 !ruby/object:Gem::Requirement
27
+ requirement: &70237035563860 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70336813924560
35
+ version_requirements: *70237035563860
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70336813960400 !ruby/object:Gem::Requirement
38
+ requirement: &70237035563440 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70336813960400
46
+ version_requirements: *70237035563440
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: guard
49
- requirement: &70336813959180 !ruby/object:Gem::Requirement
49
+ requirement: &70237035624880 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70336813959180
57
+ version_requirements: *70237035624880
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: guard-rspec
60
- requirement: &70336813957720 !ruby/object:Gem::Requirement
60
+ requirement: &70237035623600 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70336813957720
68
+ version_requirements: *70237035623600
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rb-fsevent
71
- requirement: &70336813956900 !ruby/object:Gem::Requirement
71
+ requirement: &70237035622140 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70336813956900
79
+ version_requirements: *70237035622140
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: growl
82
- requirement: &70336813956040 !ruby/object:Gem::Requirement
82
+ requirement: &70237035621320 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70336813956040
90
+ version_requirements: *70237035621320
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: yard
93
- requirement: &70336813954640 !ruby/object:Gem::Requirement
93
+ requirement: &70237035620560 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70336813954640
101
+ version_requirements: *70237035620560
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rdiscount
104
- requirement: &70336813953360 !ruby/object:Gem::Requirement
104
+ requirement: &70237035618860 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,7 +109,7 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70336813953360
112
+ version_requirements: *70237035618860
113
113
  description: A client library to send and retrieve workout, weight, and diet data
114
114
  from fitbit.com
115
115
  email:
@@ -168,7 +168,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
168
168
  version: '0'
169
169
  segments:
170
170
  - 0
171
- hash: -4091779949925866203
171
+ hash: 4572625795194822459
172
172
  required_rubygems_version: !ruby/object:Gem::Requirement
173
173
  none: false
174
174
  requirements:
@@ -177,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
177
  version: '0'
178
178
  segments:
179
179
  - 0
180
- hash: -4091779949925866203
180
+ hash: 4572625795194822459
181
181
  requirements: []
182
182
  rubyforge_project: fitgem
183
183
  rubygems_version: 1.8.10