fitgem 0.3.6 → 0.4.0

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.
@@ -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