fitgem 0.5.1 → 0.5.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.
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