Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Return DateTime objects instead of strings from temporal methods #10

Open
wants to merge 5 commits into from

1 participant

@adammck

This is a fairly major change, which breaks backwards compatibility (albeit in an easily-fixable way). So if it seems useful, please check it carefully before merging.

Currently, the time-related accessors like FitnessActivitiesFeed::Item#start_time return strings straight from RunKeeper. They look something like "Thu, 15 Sep 2011 13:28:59". This is fine for displaying as-is, but not a lot of use for anything else. This patch intercepts the values before they're stored (in the Model#populate_from_hash! method), and coerces them into DateTime objects.

The implementation is a little more complex than it needs to be, because I've tried to model it after Hashie::Extensions::Coercion, so we can easily replace this minimal solution with theirs, once a stable release is available. Faraday already uses Hashie, so it isn't a new dependency.

Coercion looks like (from weight_feed.rb):

hash_attr_accessor :timestamp, :weight, :uri # etc
coerce_key :timestamp, HealthGraph::DateTime

The HealthGraph::DateTime class is just a wrapper around ::DateTime which knows how to parse RunKeeper-style timestamps. Any class with a coerce method can be used.

adammck added some commits
@adammck adammck Coerce weight timestamps to DateTime objects. d2cb4e0
@adammck adammck Coerce sleep timestamps into DateTime objects.
This is (obviously) very similar to the previous commit. I'm just going
to get all of the timestamps working, then refactor this into a helper.
8c93f34
@adammck adammck Coerce activity start times into DateTime objects. 9a1d05b
@adammck adammck Refactor DateTime coercion into helper.
This is a modified reimplementation of Hashie::Extensions::Coercion.
I used the same coerce_key API, so when Hashie 2.0 comes around, this
helper can be removed.

See: https://github.com/intridea/hashie/blob/master/lib/hashie/extensions/coercion.rb
0f8a8f9
@adammck adammck Add datetime.rb to gemspec. 57f36ea
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 10, 2012
  1. @adammck
  2. @adammck

    Coerce sleep timestamps into DateTime objects.

    adammck authored
    This is (obviously) very similar to the previous commit. I'm just going
    to get all of the timestamps working, then refactor this into a helper.
  3. @adammck
  4. @adammck

    Refactor DateTime coercion into helper.

    adammck authored
    This is a modified reimplementation of Hashie::Extensions::Coercion.
    I used the same coerce_key API, so when Hashie 2.0 comes around, this
    helper can be removed.
    
    See: https://github.com/intridea/hashie/blob/master/lib/hashie/extensions/coercion.rb
Commits on May 11, 2012
  1. @adammck

    Add datetime.rb to gemspec.

    adammck authored
This page is out of date. Refresh to see the latest.
View
3  health_graph.gemspec
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Kenny Ma"]
- s.date = "2012-05-09"
+ s.date = "2012-05-11"
s.description = "This is a wrapper for RunKeeper Health Graph RESTful API."
s.email = "kenny@kennyma.me"
s.extra_rdoc_files = [
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
"lib/health_graph/api.rb",
"lib/health_graph/authentication.rb",
"lib/health_graph/configuration.rb",
+ "lib/health_graph/datetime.rb",
"lib/health_graph/model.rb",
"lib/health_graph/models/fitness_activities_feed.rb",
"lib/health_graph/models/fitness_activity_delete.rb",
View
1  lib/health_graph.rb
@@ -3,6 +3,7 @@
require 'faraday_middleware'
require 'health_graph/configuration'
require 'health_graph/authentication'
+require 'health_graph/datetime'
require 'health_graph/api'
require 'health_graph/model'
require 'health_graph/models/user'
View
9 lib/health_graph/datetime.rb
@@ -0,0 +1,9 @@
+require "date"
+
+module HealthGraph
+ class DateTime < ::DateTime
+ def self.coerce value
+ strptime value, "%a, %d %b %Y %H:%M:%S"
+ end
+ end
+end
View
25 lib/health_graph/model.rb
@@ -23,13 +23,35 @@ def hash_attr_accessor(*symbols)
end
end
end
+
+ def coerce_key(key, into)
+ define_method "unpack_#{key}" do |value|
+ if value.is_a? into
+ value
+
+ elsif into.respond_to? :coerce
+ into.coerce value
+
+ else
+ into.new value
+ end
+ end
+ end
end
def populate_from_hash!(hash)
return unless hash
- hash.each do |key, value|
+ hash.each do |key, raw_value|
+ unpack_method = "unpack_#{key}"
set_attr_method = "#{key}="
+
+ value = if respond_to?(unpack_method)
+ self.__send__(unpack_method, raw_value)
+ else
+ raw_value
+ end
+
unless value.nil?
if respond_to?(set_attr_method)
self.__send__(set_attr_method, value)
@@ -37,6 +59,5 @@ def populate_from_hash!(hash)
end
end
end
-
end
end
View
17 lib/health_graph/models/fitness_activities_feed.rb
@@ -8,17 +8,26 @@ class Item
include Model
hash_attr_accessor :type, :start_time, :total_distance, :duration, :uri
-
+ coerce_key :start_time, HealthGraph::DateTime
+
def initialize(hash)
populate_from_hash! hash
- end
+ end
end
-
+
def initialize(access_token, path, params = {})
self.access_token = access_token
response = get path, HealthGraph.accept_headers[:fitness_activity_feed], params
self.body = response.body
populate_from_hash! self.body
- end
+ end
+
+ protected
+
+ def unpack_items value
+ value.map do |hash|
+ Item.new hash
+ end
+ end
end
end
View
17 lib/health_graph/models/sleep_feed.rb
@@ -8,10 +8,11 @@ class Item
include Model
hash_attr_accessor :timestamp, :total_sleep, :times_woken, :rem, :deep, :light, :awake, :uri
-
+ coerce_key :timestamp, HealthGraph::DateTime
+
def initialize(hash)
populate_from_hash! hash
- end
+ end
end
def initialize(access_token, path)
@@ -19,6 +20,14 @@ def initialize(access_token, path)
response = get path, HealthGraph.accept_headers[:sleep_feed]
self.body = response.body
populate_from_hash! self.body
- end
+ end
+
+ protected
+
+ def unpack_items value
+ value.map do |hash|
+ Item.new hash
+ end
+ end
end
-end
+end
View
29 lib/health_graph/models/weight_feed.rb
@@ -1,24 +1,33 @@
module HealthGraph
class WeightFeed
include Model
-
+
hash_attr_accessor :items
-
+
class Item
include Model
-
+
hash_attr_accessor :timestamp, :weight, :free_mass, :mass_weight, :fat_percent, :bmi, :uri
-
- def initialize(hash)
+ coerce_key :timestamp, HealthGraph::DateTime
+
+ def initialize(hash)
populate_from_hash! hash
- end
+ end
end
-
+
def initialize(access_token, path)
self.access_token = access_token
response = get path, HealthGraph.accept_headers[:weight_feed]
self.body = response.body
- populate_from_hash! self.body
- end
+ populate_from_hash! self.body
+ end
+
+ protected
+
+ def unpack_items value
+ value.map do |hash|
+ Item.new hash
+ end
+ end
end
-end
+end
View
103 test/health_graph/test_fitness_activities_feed.rb
@@ -30,71 +30,53 @@ class TestFitnessActivitiesFeed < Test::Unit::TestCase
end
should "get body" do
- expected = {"items"=>
- [{"duration"=>7920,
- "total_distance"=>62764.416,
- "start_time"=>"Thu, 15 Sep 2011 13:28:59",
- "type"=>"Cycling",
- "uri"=>"/fitnessActivities/52367938"},
- {"duration"=>1080,
- "total_distance"=>2574.9504,
- "start_time"=>"Thu, 15 Sep 2011 08:00:00",
- "type"=>"Walking",
- "uri"=>"/fitnessActivities/52367984"},
- {"duration"=>2880,
- "total_distance"=>7402.9824,
- "start_time"=>"Wed, 14 Sep 2011 20:00:00",
- "type"=>"Running",
- "uri"=>"/fitnessActivities/52368041"},
- {"duration"=>3060,
- "total_distance"=>7724.8512,
- "start_time"=>"Tue, 13 Sep 2011 20:00:00",
- "type"=>"Running",
- "uri"=>"/fitnessActivities/52368120"},
- {"duration"=>4500,
- "total_distance"=>5632.704,
- "start_time"=>"Tue, 13 Sep 2011 08:00:00",
- "type"=>"Running",
- "uri"=>"/fitnessActivities/52126193"}],
- "size"=>5}
-
+ expected = {
+ "items" => [
+ {
+ "duration" => 7920,
+ "total_distance" => 62764.416,
+ "start_time" => "Thu, 15 Sep 2011 13:28:59",
+ "type" => "Cycling",
+ "uri" => "/fitnessActivities/52367938"
+ }, {
+ "duration"=>1080,
+ "total_distance"=>2574.9504,
+ "start_time" => "Thu, 15 Sep 2011 08:00:00",
+ "type" => "Walking",
+ "uri" => "/fitnessActivities/52367984"
+ }, {
+ "duration"=>2880,
+ "total_distance"=>7402.9824,
+ "start_time" => "Wed, 14 Sep 2011 20:00:00",
+ "type" => "Running",
+ "uri" => "/fitnessActivities/52368041"
+ }, {
+ "duration"=>3060,
+ "total_distance"=>7724.8512,
+ "start_time" => "Tue, 13 Sep 2011 20:00:00",
+ "type" => "Running",
+ "uri" => "/fitnessActivities/52368120"
+ }, {
+ "duration"=>4500,
+ "total_distance"=>5632.704,
+ "start_time" => "Tue, 13 Sep 2011 08:00:00",
+ "type" => "Running",
+ "uri" => "/fitnessActivities/52126193"
+ }
+ ],
+ "size"=>5
+ }
+
assert_equal expected, @user.fitness_activities.body
end
context "item" do
- should "get items" do
- expected = [{"duration"=>7920,
- "total_distance"=>62764.416,
- "start_time"=>"Thu, 15 Sep 2011 13:28:59",
- "type"=>"Cycling",
- "uri"=>"/fitnessActivities/52367938"},
- {"duration"=>1080,
- "total_distance"=>2574.9504,
- "start_time"=>"Thu, 15 Sep 2011 08:00:00",
- "type"=>"Walking",
- "uri"=>"/fitnessActivities/52367984"},
- {"duration"=>2880,
- "total_distance"=>7402.9824,
- "start_time"=>"Wed, 14 Sep 2011 20:00:00",
- "type"=>"Running",
- "uri"=>"/fitnessActivities/52368041"},
- {"duration"=>3060,
- "total_distance"=>7724.8512,
- "start_time"=>"Tue, 13 Sep 2011 20:00:00",
- "type"=>"Running",
- "uri"=>"/fitnessActivities/52368120"},
- {"duration"=>4500,
- "total_distance"=>5632.704,
- "start_time"=>"Tue, 13 Sep 2011 08:00:00",
- "type"=>"Running",
- "uri"=>"/fitnessActivities/52126193"}]
-
- assert_equal expected, @user.fitness_activities.items
+ should "get five items" do
assert_equal 5, @user.fitness_activities.items.size
end
-
+
should "get start time" do
- assert_equal "Thu, 15 Sep 2011 13:28:59", @user.fitness_activities.items[0].start_time
+ assert_equal DateTime.new(2011, 9, 15, 13, 28, 59), @user.fitness_activities.items[0].start_time
end
should "get duration" do
@@ -108,11 +90,10 @@ class TestFitnessActivitiesFeed < Test::Unit::TestCase
should "get type" do
assert_not_equal nil, @user.fitness_activities.items[0].type
end
-
+
should "get uri" do
assert_not_equal nil, @user.fitness_activities.items[0].uri
- end
-
+ end
end
end
end
View
50 test/health_graph/test_sleep_feed.rb
@@ -21,40 +21,40 @@ class TestSleepFeed < Test::Unit::TestCase
end
should "get body" do
- expected = {"items"=>
- [{"timestamp"=>"Thu, 22 Sep 2011 00:00:00",
- "total_sleep"=>822,
- "uri"=>"/sleep/6253947"},
- {"timestamp"=>"Thu, 22 Sep 2011 00:00:00",
- "uri"=>"/sleep/6253948",
- "times_woken"=>29}],
- "size"=>2}
-
+ expected = {
+ "items" => [
+ {
+ "timestamp" => "Thu, 22 Sep 2011 00:00:00",
+ "total_sleep" => 822,
+ "uri" => "/sleep/6253947"
+ }, {
+ "timestamp" => "Thu, 22 Sep 2011 00:00:00",
+ "uri" => "/sleep/6253948",
+ "times_woken" => 29
+ }
+ ],
+ "size" => 2
+ }
+
assert_equal expected, @user.sleep.body
end
-
+
context "item" do
- should "get items" do
- expected = [{"timestamp"=>"Thu, 22 Sep 2011 00:00:00",
- "total_sleep"=>822,
- "uri"=>"/sleep/6253947"},
- {"timestamp"=>"Thu, 22 Sep 2011 00:00:00",
- "uri"=>"/sleep/6253948",
- "times_woken"=>29}]
-
- assert_equal expected, @user.sleep.items
+ should "get two items" do
assert_equal 2, @user.sleep.items.size
end
-
+
should "get timestamp" do
- assert_equal "Thu, 22 Sep 2011 00:00:00", @user.sleep.items[0].timestamp
+ assert_equal DateTime.new(2011, 9, 22, 0, 0, 0), @user.sleep.items[0].timestamp
end
-
- should "get time sleep" do
+
+ should "get total sleep" do
assert_equal 822, @user.sleep.items[0].total_sleep
+ assert_equal nil, @user.sleep.items[1].total_sleep
end
-
- should "get time woken" do
+
+ should "get times woken" do
+ assert_equal nil, @user.sleep.items[0].times_woken
assert_equal 29, @user.sleep.items[1].times_woken
end
View
28 test/health_graph/test_weight_feed.rb
@@ -21,33 +21,31 @@ class TestWeightFeed < Test::Unit::TestCase
end
should "get body" do
- expected = {"items"=>
- [{"timestamp"=>"Mon, 10 Oct 2011 01:31:47",
+ expected = {
+ "items"=>[{
+ "timestamp"=>"Mon, 10 Oct 2011 01:31:47",
"weight"=>63.502931853253,
- "uri"=>"/weight/6626834"}],
- "size"=>1}
-
+ "uri"=>"/weight/6626834"
+ }],
+ "size"=>1
+ }
+
assert_equal expected, @user.weight.body
end
context "item" do
- should "get one item" do
- expected = [{"timestamp"=>"Mon, 10 Oct 2011 01:31:47",
- "weight"=>63.502931853253,
- "uri"=>"/weight/6626834"}]
-
- assert_equal expected, @user.weight.items
+ should "get one item" do
assert_equal 1, @user.weight.items.size
end
-
+
should "get timestamp" do
- assert_equal "Mon, 10 Oct 2011 01:31:47", @user.weight.items[0].timestamp
+ assert_equal DateTime.new(2011, 10, 10, 1, 31, 47), @user.weight.items[0].timestamp
end
-
+
should "get weight" do
assert_equal 63.502931853253, @user.weight.items[0].weight
end
-
+
should "get uri" do
assert_equal "/weight/6626834", @user.weight.items[0].uri
end
View
1  test/helper.rb
@@ -1,6 +1,7 @@
require 'simplecov'
SimpleCov.start
+require 'date'
require 'test/unit'
require 'shoulda'
require 'webmock/test_unit'
Something went wrong with that request. Please try again.