ruby-fitbit 0.2.3 → 0.3.1
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/README.rdoc +4 -3
- data/VERSION +1 -1
- data/bin/ruby-fitbit +15 -8
- data/fixtures/vcr_cassettes/fitbit_get_data.yml +5255 -0
- data/lib/ruby-fitbit.rb +102 -18
- data/ruby-fitbit.gemspec +3 -2
- data/test/test_ruby-fitbit.rb +32 -13
- metadata +4 -3
data/lib/ruby-fitbit.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'mechanize'
|
3
3
|
require 'nokogiri'
|
4
|
+
require 'json'
|
4
5
|
|
5
6
|
class RubyFitbit
|
6
7
|
|
7
|
-
attr_reader :calories, :steps, :miles_walked, :sedentary_active, :lightly_active, :fairly_active, :very_active
|
8
|
-
|
9
8
|
#TODO change tests so reader isn't needed
|
10
9
|
attr_reader :logged_in
|
11
10
|
|
@@ -15,10 +14,8 @@ class RubyFitbit
|
|
15
14
|
@agent = WWW::Mechanize.new #{|a| a.log = Logger.new(STDERR) } #turn on if debugging
|
16
15
|
@logged_in = false
|
17
16
|
@cached_data = {}
|
18
|
-
get_data
|
19
17
|
end
|
20
18
|
|
21
|
-
#todo only login once
|
22
19
|
def login
|
23
20
|
unless @logged_in
|
24
21
|
page = @agent.get 'https://www.fitbit.com/login'
|
@@ -37,6 +34,93 @@ class RubyFitbit
|
|
37
34
|
end
|
38
35
|
end
|
39
36
|
|
37
|
+
def submit_food_log(options = {})
|
38
|
+
login
|
39
|
+
|
40
|
+
date = options.fetch(:date) {Time.now}
|
41
|
+
date = get_fitbit_date_format(date)
|
42
|
+
meal_type = options.fetch(:meal_type){'7'}
|
43
|
+
food_id = options[:food_id]
|
44
|
+
food = options[:food]
|
45
|
+
raise "food_id or food required to submit food log" unless food_id || food
|
46
|
+
unless food_id
|
47
|
+
food_recommendation = get_food_items(food)
|
48
|
+
if food_recommendation.length > 0
|
49
|
+
food_recommendation = food_recommendation.first
|
50
|
+
food = food_recommendation['name']
|
51
|
+
food_id = food_recommendation['id']
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
unit_id = options[:unit_id]
|
56
|
+
unit = options[:unit]
|
57
|
+
raise "unit_id or unit required to submit food log" unless unit_id || unit
|
58
|
+
unless unit_id
|
59
|
+
unit_id = get_unit_id_for_unit(unit)
|
60
|
+
end
|
61
|
+
|
62
|
+
page = @agent.get 'http://www.fitbit.com/foods/log'
|
63
|
+
|
64
|
+
form = page.forms[1]
|
65
|
+
|
66
|
+
form.action="/foods/log/foodLog?apiFormat=htmljson&log=on&date=#{date}"
|
67
|
+
form.foodId = food_id
|
68
|
+
form.foodselectinput = food
|
69
|
+
form.unitId = unit_id
|
70
|
+
form.quantityselectinput = unit
|
71
|
+
form.quantityConsumed = unit
|
72
|
+
form.mealTypeId = meal_type
|
73
|
+
|
74
|
+
result = @agent.submit(form, form.buttons.first)
|
75
|
+
end
|
76
|
+
|
77
|
+
def get_unit_id_for_unit(unit)
|
78
|
+
unit_id = nil
|
79
|
+
unit_type = unit.match(/\d+ (.*)/)[1]
|
80
|
+
|
81
|
+
type_map = {'oz' => '226',
|
82
|
+
'lb' => '180',
|
83
|
+
'gram' => '147',
|
84
|
+
'kilogram' => '389',
|
85
|
+
'roll' => '290',
|
86
|
+
'serving' => '304',
|
87
|
+
'link' => '188',
|
88
|
+
'piece' => '251',
|
89
|
+
'fl oz' => '128',
|
90
|
+
'ml' => '209',
|
91
|
+
'tsp' => '364',
|
92
|
+
'tbsp' => '349',
|
93
|
+
'cup' => '91',
|
94
|
+
'pint' => '256',
|
95
|
+
'slice' => '311',
|
96
|
+
'liter' => '189',
|
97
|
+
'quart' => '279',
|
98
|
+
'entree' => '117',
|
99
|
+
'portion' => '270'
|
100
|
+
}
|
101
|
+
|
102
|
+
unit_id = type_map[unit_type]
|
103
|
+
unit_id
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_food_items(food="Coffe")
|
107
|
+
login
|
108
|
+
result = @agent.get "http://www.fitbit.com/solr/food/select?q=#{food}&wt=foodjson&qt=food"
|
109
|
+
foods = JSON.parse(result.body).first[1]["foods"]
|
110
|
+
foods
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_eaten_calories(date = Time.now)
|
114
|
+
login
|
115
|
+
|
116
|
+
date = get_fitbit_date_format(date).gsub('-','/')
|
117
|
+
page = @agent.get "https://www.fitbit.com/foods/log/#{date}"
|
118
|
+
calories_data = page.search("//div[@id='dailyTotals']").first
|
119
|
+
calories_xml = calories_data.to_xml
|
120
|
+
calories_text = calories_data.text
|
121
|
+
{:calories_xml => calories_xml, :calories_text => calories_text}
|
122
|
+
end
|
123
|
+
|
40
124
|
def get_data(date = Time.now)
|
41
125
|
login
|
42
126
|
|
@@ -45,21 +129,21 @@ class RubyFitbit
|
|
45
129
|
|
46
130
|
page = @agent.get "https://www.fitbit.com/#{date}"
|
47
131
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
132
|
+
calories = page.search("//div[@class='data']").search("span").children[0].text
|
133
|
+
steps = page.search("//div[@class='data']").search("span").children[2].text.strip
|
134
|
+
miles_walked = page.search("//div[@class='data']").search("span").children[3].text.strip
|
135
|
+
sedentary_active = page.search("//div[@class='sedentary caption']/div[@class='number']").text.strip
|
136
|
+
lightly_active = page.search("//div[@class='lightly caption']/div[@class='number']").text.strip
|
137
|
+
fairly_active = page.search("//div[@class='caption fairly']/div[@class='number']").text.strip
|
138
|
+
very_active = page.search("//div[@class='caption very']/div[@class='number']").text.strip
|
55
139
|
data = {}
|
56
|
-
data['calories'] =
|
57
|
-
data['steps'] =
|
58
|
-
data['miles_walked'] =
|
59
|
-
data['sedentary_active'] =
|
60
|
-
data['lightly_active'] =
|
61
|
-
data['fairly_active'] =
|
62
|
-
data['very_active'] =
|
140
|
+
data['calories'] = calories.to_i
|
141
|
+
data['steps'] = steps.to_i
|
142
|
+
data['miles_walked'] = miles_walked.to_f
|
143
|
+
data['sedentary_active'] = sedentary_active
|
144
|
+
data['lightly_active'] = lightly_active
|
145
|
+
data['fairly_active'] = fairly_active
|
146
|
+
data['very_active'] = very_active
|
63
147
|
@cached_data[date] = data
|
64
148
|
data
|
65
149
|
end
|
data/ruby-fitbit.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ruby-fitbit}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Dan Mayer"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-14}
|
13
13
|
s.default_executable = %q{ruby-fitbit}
|
14
14
|
s.description = %q{This is a Ruby API for Fitbit.com, currently scraping, but soon will use the officail API (when released)}
|
15
15
|
s.email = %q{Danmayer@gmail.com}
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
28
|
"bin/ruby-fitbit",
|
29
|
+
"fixtures/vcr_cassettes/fitbit_get_data.yml",
|
29
30
|
"lib/ruby-fitbit.rb",
|
30
31
|
"ruby-fitbit.gemspec",
|
31
32
|
"test/helper.rb",
|
data/test/test_ruby-fitbit.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
require File.expand_path('./helper', File.dirname(__FILE__))
|
2
2
|
require 'webmock/test_unit'
|
3
|
-
|
3
|
+
require 'vcr'
|
4
4
|
require 'ruby-fitbit'
|
5
5
|
require 'mocha'
|
6
6
|
|
7
7
|
class TestRubyFitbit < Test::Unit::TestCase
|
8
8
|
include WebMock
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
VCR.config do |c|
|
11
|
+
c.cassette_library_dir = 'fixtures/vcr_cassettes'
|
12
|
+
c.http_stubbing_library = :webmock
|
13
|
+
end
|
14
14
|
|
15
15
|
#TODO this is a mess it took awhile to figure out a way to make the tests work at all clean this up
|
16
16
|
|
@@ -62,7 +62,9 @@ END
|
|
62
62
|
data = File.read("./test/responses/data.txt")
|
63
63
|
response = "#{HEADERS} #{data}"
|
64
64
|
|
65
|
-
|
65
|
+
date = Time.now()
|
66
|
+
date = date.strftime("%Y/%m/%d")
|
67
|
+
stub_request(:get, "https://www.fitbit.com/#{date}").to_return(response)
|
66
68
|
|
67
69
|
RubyFitbit.any_instance.stubs(:login)
|
68
70
|
fitbit = RubyFitbit.new("fake@fake.com","pass")
|
@@ -70,15 +72,32 @@ END
|
|
70
72
|
@logged_in = val
|
71
73
|
end
|
72
74
|
fitbit.set_logged_in(true)
|
75
|
+
data = fitbit.get_data
|
73
76
|
|
74
|
-
assert_equal
|
75
|
-
assert_equal
|
76
|
-
assert_equal
|
77
|
-
assert_equal "16hrs 58min",
|
78
|
-
assert_equal "1hr 42min",
|
79
|
-
assert_equal "1hr 51min",
|
80
|
-
assert_equal "17min",
|
77
|
+
assert_equal 1928, data['calories'], "wrong calories"
|
78
|
+
assert_equal 7821, data['steps'], "wrong steps"
|
79
|
+
assert_equal 3.38, data['miles_walked'], "wrong miles"
|
80
|
+
assert_equal "16hrs 58min", data['sedentary_active'], "wrong sedentary"
|
81
|
+
assert_equal "1hr 42min", data['lightly_active'], "wrong lightly"
|
82
|
+
assert_equal "1hr 51min", data['fairly_active'], "wrong fairly"
|
83
|
+
assert_equal "17min", data['very_active'], "wrong very"
|
84
|
+
end
|
85
|
+
|
86
|
+
should "use VCR successfully" do
|
87
|
+
fitbit = nil
|
88
|
+
data = nil
|
89
|
+
VCR.use_cassette('fitbit_get_data', :record => :new_episodes) do
|
90
|
+
fitbit = RubyFitbit.new("fake@fake.com","fake")
|
91
|
+
data = fitbit.get_data(Time.parse("2010/08/03"))
|
92
|
+
end
|
81
93
|
|
94
|
+
assert_equal 2084, data['calories'], "wrong calories"
|
95
|
+
assert_equal 10018, data['steps'], "wrong steps"
|
96
|
+
assert_equal 4.61, data['miles_walked'], "wrong miles"
|
97
|
+
assert_equal "18hrs 26min", data['sedentary_active'], "wrong sedentary"
|
98
|
+
assert_equal "1hr 17min", data['lightly_active'], "wrong lightly"
|
99
|
+
assert_equal "1hr 29min", data['fairly_active'], "wrong fairly"
|
100
|
+
assert_equal "42min", data['very_active'], "wrong very"
|
82
101
|
end
|
83
102
|
|
84
103
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
- 2
|
8
7
|
- 3
|
9
|
-
|
8
|
+
- 1
|
9
|
+
version: 0.3.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Dan Mayer
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-10-14 00:00:00 -04:00
|
18
18
|
default_executable: ruby-fitbit
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- Rakefile
|
89
89
|
- VERSION
|
90
90
|
- bin/ruby-fitbit
|
91
|
+
- fixtures/vcr_cassettes/fitbit_get_data.yml
|
91
92
|
- lib/ruby-fitbit.rb
|
92
93
|
- ruby-fitbit.gemspec
|
93
94
|
- test/helper.rb
|