Skip to content

Instantly share code, notes, and snippets.

@krzysztofzablocki
Created January 15, 2015 17:14
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save krzysztofzablocki/f5f597f04b2efcb711c7 to your computer and use it in GitHub Desktop.
Save krzysztofzablocki/f5f597f04b2efcb711c7 to your computer and use it in GitHub Desktop.
mfp.rb
require 'mechanize'
require 'moving_average'
mechanize = Mechanize.new
login_page = mechanize.get 'https://www.myfitnesspal.com/account/login'
form = login_page.forms.first
# noinspection RubyResolve
form.field_with(id: 'username').value = "username"
form.field_with(id: 'password').value = "pass"
form.submit
days_to_query = 27
weight_report = mechanize.get("http://www.myfitnesspal.com/reports/results/progress/1/#{days_to_query}.json")
calories_report = mechanize.get("http://www.myfitnesspal.com/reports/results/nutrition/Calories/#{days_to_query}.json")
weights = JSON.parse(weight_report.body)["data"]
calories = JSON.parse(calories_report.body)["data"]
avg_calories = calories.map { |hash| hash['total'] }.reject { |x| x == 0 }.instance_eval { reduce(:+) / size.to_f }
puts "Calories: #{ avg_calories }"
weight_values = weights.map { |hash| hash['total'] }
smoothed_weights = []
weight_values.count.times do |idx|
smoothed_weights.push(
if idx > 1
weight_values[0, idx + 1].smma.round(1)
else
weight_values[idx]
end
)
end
weight_change = weight_values.first - weight_values.last
weight_in_calories = weight_change * 7700
weight = weight_values.last
observed_tdee = avg_calories + weight_in_calories / weights.count
protein = weight * 2
fats = weight * 0.8
carbs = (observed_tdee - (protein*4 + fats * 9))/4
puts "Observed TDEE is #{observed_tdee}"
puts "protein = #{protein} g"
puts "fat = #{fats} g"
puts "carbs = #{carbs} g"
@subdigital
Copy link

The instance_eval is a bit smelly. What is the return value of the calories.map step? (guessing it's a list of floats)

@subdigital
Copy link

Stylistically, I'd probably do averages externally from the array class and avoid instance_eval altogether. It's not always wrong, but usually only used for DSLs.

def avg(xs)
  return xs.inject(:+) / xs.length
end

avg_calories = avg calories.map { |hash| hash['total'] }.reject { |x| x == 0 }

@subdigital
Copy link

(didn't say this above, but thanks for this! will be using this to extract my own data)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment