fitgem 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,18 +1,30 @@
1
1
  module Fitgem
2
2
  class Client
3
-
4
- def user_info(options = {})
5
- get("/user/#{@user_id}/profile.json")
3
+ # Get information aobut current user
4
+ #
5
+ # @param [Hash] opts User information request data
6
+ # @return [Hash] User information
7
+ def user_info(opts={})
8
+ get("/user/#{@user_id}/profile.json", opts)
6
9
  end
7
10
 
8
- # options[:gender] optional Gender; (MALE/FEMALE/NA)
9
- # options[:birthday] optional Date of Birth; in the format yyyy-MM-dd
10
- # options[:height] optional Height
11
- # options[:nickname] optional Nickname
12
- # options[:fullName] optional Full name
13
- # options[:timezone] optional Timezone; in the format "America/Los_Angeles"
14
- def update_user_info(options)
15
- post("/user/#{@user_id}/profile.json", options)
11
+ # Update profile information for current user
12
+ #
13
+ # @param [Hash] opts User profile information
14
+ # @option opts [String] :gender Gender, valid values are MALE, FEMALE, NA
15
+ # @option opts [DateTime, Date, String] :birthday Birthday, in
16
+ # "yyyy-MM-dd" if a String
17
+ # @option opts [Decimal, Integer, String] :height Height, in format
18
+ # "X.XX" if a string
19
+ # @option opts [String] :nickname Nickname
20
+ # @option opts [String] :fullName Full name
21
+ # @option opts [String] :timezone Time zone; in the format
22
+ # "America/Los Angelos"
23
+ #
24
+ # @return [Hash] Hash containing updated profile information
25
+ def update_user_info(opts)
26
+ opts[:birthday] = format_date(opts[:birthday]) if opts[:birthday]
27
+ post("/user/#{@user_id}/profile.json", opts)
16
28
  end
17
29
 
18
30
  end
@@ -1,3 +1,3 @@
1
1
  module Fitgem
2
- VERSION = "0.3.6"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -1,9 +1,14 @@
1
1
  module Fitgem
2
2
  class Client
3
-
4
3
  # ==========================================
5
4
  # Water Retrieval Methods
6
5
  # ==========================================
6
+
7
+ # Get water log entries for the supplied date
8
+ #
9
+ # @param [DateTime, Date, String] date
10
+ # @return [Hash] Hash containing the summary of the days logs, and a
11
+ # list of all individual entries
7
12
  def water_on_date(date)
8
13
  get("/user/#{@user_id}/foods/log/water/date/#{format_date(date)}.json")
9
14
  end
@@ -13,22 +18,33 @@ module Fitgem
13
18
  # Water Logging Methods
14
19
  # ==========================================
15
20
 
16
- # options[:amount] Required
17
- # options[:unit] Optional ("ml", "fl oz" or "cup")
18
- # options[:date] Required yyyy-MM-dd format
19
- def log_water(options)
20
- unless options[:amount] && options[:date]
21
- raise "Must include both an :amount and :date to log water"
21
+ # Log water consumption to fitbit
22
+ #
23
+ # @param [Hash] opts Water consumption data
24
+ # @option opts [Integer, Decimal, String] :amount Amount of water
25
+ # consumed; if String must be in "X.X" format
26
+ # @option opts [String] :unit Unit of water consumed; valid values
27
+ # are ("ml", "fl oz" or "cup")
28
+ # @option opts [DateTime, Date, String] :date Date of water
29
+ # consumption
30
+ #
31
+ # @return [Hash] Summary of logged information
32
+ def log_water(opts)
33
+ unless opts[:amount] && opts[:date]
34
+ raise Fitgem::InvalidArgumentError, "Must include both an :amount and :date to log water"
22
35
  end
23
- post("/user/#{@user_id}/foods/log/water.json",options)
24
- end
25
36
 
26
- # ==========================================
27
- # Water Log Deletion Methods
28
- # ==========================================
37
+ opts[:date] = format_date(opts[:date])
38
+ post("/user/#{@user_id}/foods/log/water.json",opts)
39
+ end
29
40
 
30
- def delete_water_log(log_id)
31
- delete("/user/-/foods/log/water/#{log_id}.json")
41
+ # Delete logged water consumption
42
+ #
43
+ # @param [Integer, String] water_log_id The id of previously logged
44
+ # water consumption
45
+ # @return [Hash] Empty hash denotes success
46
+ def delete_water_log(water_log_id)
47
+ delete("/user/-/foods/log/water/#{water_log_id}.json")
32
48
  end
33
49
  end
34
50
  end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fitgem::Client do
4
+ describe "constructor" do
5
+ it "requires consumer_key" do
6
+ expect {
7
+ opts = { :consumer_secret => "12345" }
8
+ client = Fitgem::Client.new(opts)
9
+ }.to raise_error(Fitgem::InvalidArgumentError, "Missing required options: consumer_key")
10
+ end
11
+
12
+ it "requires consumer_secret" do
13
+ expect {
14
+ opts = { :consumer_key => "12345" }
15
+ client = Fitgem::Client.new(opts)
16
+ }.to raise_error(Fitgem::InvalidArgumentError, "Missing required options: consumer_secret")
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fitgem::Client do
4
+ before(:each) do
5
+ @client = Fitgem::Client.new({
6
+ :consumer_key => '12345',
7
+ :consumer_secret => '67890'
8
+ })
9
+ end
10
+
11
+ describe "#construct_date_range_fragment" do
12
+ it 'should format the correct URI fragment based on a base date and end date' do
13
+ frag = @client.construct_date_range_fragment({:base_date => '2011-03-07', :end_date => '2011-03-14'})
14
+ frag.should == 'date/2011-03-07/2011-03-14'
15
+ end
16
+
17
+ it 'should format the correct URI fragment based on a base date and period' do
18
+ frag = @client.construct_date_range_fragment({:base_date => '2011-03-07', :period => '7d'})
19
+ frag.should == 'date/2011-03-07/7d'
20
+ end
21
+
22
+ it 'should raise an error unless there is a base date AND either a period or an end date' do
23
+ expect {
24
+ @client.construct_date_range_fragment({:base_date => '2011-03-07'})
25
+ }.to raise_error(Fitgem::InvalidTimeRange)
26
+
27
+ expect {
28
+ @client.construct_date_range_fragment({:period => '1y'})
29
+ }.to raise_error(Fitgem::InvalidTimeRange)
30
+
31
+ expect {
32
+ @client.construct_date_range_fragment({:end_date => '2011-03-07', :period => '7d'})
33
+ }.to raise_error(Fitgem::InvalidTimeRange)
34
+ end
35
+ end
36
+
37
+ describe "#format_date" do
38
+ it "accepts DateTime objects" do
39
+ date = DateTime.strptime('2011-03-19','%Y-%m-%d')
40
+ @client.format_date(date).should == '2011-03-19'
41
+ end
42
+
43
+ it "accepts strings in YYYY-MM-DD format" do
44
+ @client.format_date('2011-03-19').should == '2011-03-19'
45
+ end
46
+
47
+ it "accepts the string 'today' to denote the current date" do
48
+ today = Date.today.strftime("%Y-%m-%d")
49
+ @client.format_date('today').should == today
50
+ end
51
+
52
+ it "accepts the string 'yesterday' to denote the day previous to today" do
53
+ yesterday = (Date.today-1).strftime("%Y-%m-%d")
54
+ @client.format_date('yesterday').should == yesterday
55
+ end
56
+
57
+ it "rejects strings that are not in YYY-MM-DD format" do
58
+ date = "2011-3-2"
59
+ expect {
60
+ @client.format_date(date)
61
+ }.to raise_error Fitgem::InvalidDateArgument, "Invalid date (2011-3-2), must be in yyyy-MM-dd format"
62
+ end
63
+
64
+ it "rejects strings are formatted correctly but include non-numeric elements" do
65
+ date = "2011-aa-20"
66
+ expect {
67
+ @client.format_date(date)
68
+ }.to raise_error Fitgem::InvalidDateArgument, "Invalid date (2011-aa-20), must be in yyyy-MM-dd format"
69
+ end
70
+
71
+ it "rejects arguments that are not a Date, Time, DateTime, or String" do
72
+ date = 200
73
+ expect {
74
+ @client.format_date(date)
75
+ }.to raise_error Fitgem::InvalidDateArgument, "Date used must be a date/time object or a string in the format YYYY-MM-DD; supplied argument is a Fixnum"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,173 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ describe Fitgem::Client do
5
+ before(:each) do
6
+ @client = Fitgem::Client.new({:consumer_key => '12345', :consumer_secret => '56789'})
7
+ end
8
+
9
+ describe "#subscriptions" do
10
+ before(:each) do
11
+ @client.stub :get
12
+ end
13
+
14
+ it "calls #make_headers to create the headers for the API call" do
15
+ opts = { :subscriber_id => "5555", :type => :all }
16
+ @client.should_receive(:make_headers).with({:type=>:all, :subscriber_id=>"5555"})
17
+ @client.subscriptions(opts)
18
+ end
19
+
20
+ it "calls #get with the correct url and headers" do
21
+ opts = { :subscriber_id => "5555", :type => :all }
22
+ @client.should_receive(:get).with("/user/-/apiSubscriptions.json", {"X-Fitbit-Subscriber-Id"=>"5555"})
23
+ @client.subscriptions(opts)
24
+ end
25
+ end
26
+
27
+ describe "#create_subscription" do
28
+ before(:each) do
29
+ @resp = OpenStruct.new
30
+ @client.stub(:raw_post).and_return(@resp)
31
+ end
32
+
33
+ it "adds the :use_subscription_id flag and calls #make_headers" do
34
+ opts = { :subscriber_id => "5555", :type => :all, :subscription_id => "320" }
35
+ @client.should_receive(:make_headers).with({ :subscriber_id => "5555", :type => :all, :subscription_id => "320", :use_subscription_id => true })
36
+ @client.create_subscription(opts)
37
+ end
38
+
39
+ it "calls #raw_post with the correct url and headers for :all collection type" do
40
+ opts = { :subscriber_id => "5555", :type => :all, :subscription_id => "320", :use_subscription_id => true }
41
+ @client.should_receive(:raw_post).once.with("/user/-/apiSubscriptions/320.json", "", {"X-Fitbit-Subscriber-Id"=>"5555"})
42
+ @client.create_subscription(opts)
43
+ end
44
+
45
+ it "calls #raw_post with the correct url and headers for :sleep collection type" do
46
+ opts = { :subscriber_id => "5555", :type => :sleep, :subscription_id => "320", :use_subscription_id => true }
47
+ @client.should_receive(:raw_post).once.with("/user/-/sleep/apiSubscriptions/320.json", "", {"X-Fitbit-Subscriber-Id"=>"5555"})
48
+ @client.create_subscription(opts)
49
+ end
50
+
51
+ it "calls #extract_response_body to get the JSON body" do
52
+ opts = { :subscriber_id => "5555", :type => :all, :subscription_id => "320", :use_subscription_id => true }
53
+ @client.should_receive(:extract_response_body)
54
+ @client.create_subscription(opts)
55
+ end
56
+
57
+ it "returns the code and the JSON body in an array" do
58
+ opts = { :subscriber_id => "5555", :type => :all, :subscription_id => "320", :use_subscription_id => true }
59
+ @resp.should_receive(:code)
60
+ @client.create_subscription(opts).should be_a(Array)
61
+ end
62
+ end
63
+
64
+ describe "#remove_subscription" do
65
+ before(:each) do
66
+ @resp = OpenStruct.new
67
+ @client.stub(:raw_delete).and_return(@resp)
68
+ end
69
+
70
+ it "adds the :use_subscription_id flag and calls #make_headers" do
71
+ opts = { :subscriber_id => "5555", :type => :all, :subscription_id => "320" }
72
+ @client.should_receive(:make_headers).with({ :subscriber_id => "5555", :type => :all, :subscription_id => "320", :use_subscription_id => true })
73
+ @client.remove_subscription(opts)
74
+ end
75
+
76
+ it "calls #raw_delete with the correct url and headers for :all collection type" do
77
+ opts = { :subscriber_id => "5555", :type => :all, :subscription_id => "320", :use_subscription_id => true }
78
+ @client.should_receive(:raw_delete).once.with("/user/-/apiSubscriptions/320.json", {"X-Fitbit-Subscriber-Id"=>"5555"})
79
+ @client.remove_subscription(opts)
80
+ end
81
+
82
+ it "calls #extract_response_body to get the JSON body" do
83
+ opts = { :subscriber_id => "5555", :type => :all, :subscription_id => "320", :use_subscription_id => true }
84
+ @client.should_receive(:extract_response_body)
85
+ @client.remove_subscription(opts)
86
+ end
87
+
88
+ it "returns the code and the JSON body in an array" do
89
+ opts = { :subscriber_id => "5555", :type => :all, :subscription_id => "320", :use_subscription_id => true }
90
+ @resp.should_receive(:code)
91
+ @client.remove_subscription(opts).should be_a(Array)
92
+ end
93
+ end
94
+
95
+ describe "#validate_subscription_types" do
96
+ it "raises an exception if an invalid type is passed in" do
97
+ expect {
98
+ @client.send(:validate_subscription_type, :every_single_thing)
99
+ }.to raise_error Fitgem::InvalidArgumentError, "Invalid subscription type (valid values are sleep, body, activities, foods, all)"
100
+ end
101
+
102
+ it "raises an exception if no type is supplied" do
103
+ opts = { :opt1 => 'hello!' }
104
+ expect {
105
+ @client.send(:validate_subscription_type, opts[:type])
106
+ }.to raise_error Fitgem::InvalidArgumentError
107
+ end
108
+ end
109
+
110
+ describe "#make_headers" do
111
+ it "adds the subscriber id header" do
112
+ opts = { :subscriber_id => '5555', :subscription_id => '320-activity' }
113
+ headers = @client.send(:make_headers, opts)
114
+ headers.size.should == 1
115
+ headers['X-Fitbit-Subscriber-Id'].should == "5555"
116
+ end
117
+ end
118
+
119
+ describe "#make_subscription_url" do
120
+ it "creates the correct URL when no specific subscription id is used" do
121
+ opts = { :subscription_id => "320", :type => :all }
122
+ @client.send(:make_subscription_url, opts).should == "/user/-/apiSubscriptions.json"
123
+ end
124
+
125
+ it "creates the correct URL for :all collection types" do
126
+ opts = { :subscription_id => "320", :type => :all, :use_subscription_id => true }
127
+ @client.send(:make_subscription_url, opts).should == "/user/-/apiSubscriptions/320.json"
128
+ end
129
+
130
+ it "creates the correct URL for the :sleep collection type" do
131
+ opts = { :subscription_id => "320", :type => :sleep, :use_subscription_id => true }
132
+ @client.send(:make_subscription_url, opts).should == "/user/-/sleep/apiSubscriptions/320.json"
133
+ end
134
+
135
+ it "creates the correct URL for the :body collection type" do
136
+ opts = { :subscription_id => "320", :type => :body, :use_subscription_id => true }
137
+ @client.send(:make_subscription_url, opts).should == "/user/-/body/apiSubscriptions/320.json"
138
+ end
139
+
140
+ it "creates the correct URL for the :activities collection type" do
141
+ opts = { :subscription_id => "320", :type => :activities, :use_subscription_id => true }
142
+ @client.send(:make_subscription_url, opts).should == "/user/-/activities/apiSubscriptions/320.json"
143
+ end
144
+
145
+ it "creates the correct URL for the :foods collection type" do
146
+ opts = { :subscription_id => "320", :type => :foods, :use_subscription_id => true }
147
+ @client.send(:make_subscription_url, opts).should == "/user/-/foods/apiSubscriptions/320.json"
148
+ end
149
+
150
+ it "validates the supplied subscription type" do
151
+ opts = { :subscription_id => "320" }
152
+ expect { @client.send(:make_subscription_url, opts) }.to raise_error Fitgem::InvalidArgumentError
153
+
154
+ opts[:type] = nil
155
+ expect { @client.send(:make_subscription_url, opts) }.to raise_error Fitgem::InvalidArgumentError
156
+
157
+ opts[:type] = :all
158
+ expect { @client.send(:make_subscription_url, opts) }.not_to raise_error Fitgem::InvalidArgumentError
159
+
160
+ opts[:type] = :activities
161
+ expect { @client.send(:make_subscription_url, opts) }.not_to raise_error Fitgem::InvalidArgumentError
162
+
163
+ opts[:type] = :sleep
164
+ expect { @client.send(:make_subscription_url, opts) }.not_to raise_error Fitgem::InvalidArgumentError
165
+
166
+ opts[:type] = :foods
167
+ expect { @client.send(:make_subscription_url, opts) }.not_to raise_error Fitgem::InvalidArgumentError
168
+
169
+ opts[:type] = :body
170
+ expect { @client.send(:make_subscription_url, opts) }.not_to raise_error Fitgem::InvalidArgumentError
171
+ end
172
+ end
173
+ end
@@ -1,9 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Fitgem do
4
-
5
4
  before do
6
- @client = Fitgem::Client.new
5
+ @client = Fitgem::Client.new({
6
+ :consumer_key => '12345',
7
+ :consumer_secret => '67890'
8
+ })
7
9
  end
8
10
 
9
11
  describe "global settings" do
@@ -31,53 +33,4 @@ describe Fitgem do
31
33
  @client.user_id.should == '-'
32
34
  end
33
35
  end
34
-
35
- describe "data retrieval by time range" do
36
-
37
- it 'should format the correct URI fragment based on a base date and end date' do
38
- frag = @client.construct_date_range_fragment({:base_date => '2011-03-07', :end_date => '2011-03-14'})
39
- frag.should == 'date/2011-03-07/2011-03-14'
40
- end
41
-
42
- it 'should format the correct URI fragment based on a base date and period' do
43
- frag = @client.construct_date_range_fragment({:base_date => '2011-03-07', :period => '7d'})
44
- frag.should == 'date/2011-03-07/7d'
45
- end
46
-
47
- it 'should raise an error unless there is a base date AND either a period or an end date' do
48
- lambda {
49
- @client.construct_date_range_fragment({:base_date => '2011-03-07'})
50
- }.should raise_error(Fitgem::InvalidTimeRange)
51
-
52
- lambda {
53
- @client.construct_date_range_fragment({:period => '1y'})
54
- }.should raise_error(Fitgem::InvalidTimeRange)
55
-
56
- lambda {
57
- @client.construct_date_range_fragment({:end_date => '2011-03-07', :period => '7d'})
58
- }.should raise_error(Fitgem::InvalidTimeRange)
59
- end
60
-
61
- end
62
-
63
- describe "format_date" do
64
- it "accepts DateTime objects" do
65
- date = DateTime.strptime('2011-03-19','%Y-%m-%d')
66
- @client.format_date(date).should == '2011-03-19'
67
- end
68
-
69
- it "accepts strings in YYYY-MM-DD format" do
70
- @client.format_date('2011-03-19').should == '2011-03-19'
71
- end
72
-
73
- it "accepts the string 'today' to denote the current date" do
74
- today = Date.today.strftime("%Y-%m-%d")
75
- @client.format_date('today').should == today
76
- end
77
-
78
- it "accepts the string 'yesterday' to denote the day previous to today" do
79
- yesterday = (Date.today-1).strftime("%Y-%m-%d")
80
- @client.format_date('yesterday').should == yesterday
81
- end
82
- end
83
- end
36
+ end