teich-hrmparser 0.5.0 → 0.6.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.
- data/CHANGELOG.txt +3 -0
- data/VERSION.yml +1 -1
- data/hrmparser.gemspec +3 -2
- data/lib/hrmparser/importer.rb +10 -0
- data/lib/hrmparser/importer/timex.rb +118 -0
- data/spec/hrmparser_spec.rb +205 -153
- metadata +5 -3
data/CHANGELOG.txt
CHANGED
data/VERSION.yml
CHANGED
data/hrmparser.gemspec
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = %q{hrmparser}
|
|
5
|
-
s.version = "0.
|
|
5
|
+
s.version = "0.6.0"
|
|
6
6
|
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
8
|
s.authors = ["Oren Teich"]
|
|
9
|
-
s.date = %q{2009-
|
|
9
|
+
s.date = %q{2009-08-15}
|
|
10
10
|
s.description = %q{Parses Polar and Garmin HRM files.}
|
|
11
11
|
s.email = %q{oren@teich.net}
|
|
12
12
|
s.extra_rdoc_files = [
|
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
|
26
26
|
"lib/hrmparser/importer/gpx.rb",
|
|
27
27
|
"lib/hrmparser/importer/polar.rb",
|
|
28
28
|
"lib/hrmparser/importer/suunto.rb",
|
|
29
|
+
"lib/hrmparser/importer/timex.rb",
|
|
29
30
|
"lib/hrmparser/trackpoint.rb",
|
|
30
31
|
"lib/hrmparser/workout.rb",
|
|
31
32
|
"spec/arraymath_spec.rb",
|
data/lib/hrmparser/importer.rb
CHANGED
|
@@ -2,6 +2,7 @@ require 'importer/garmin'
|
|
|
2
2
|
require 'importer/polar'
|
|
3
3
|
require 'importer/suunto'
|
|
4
4
|
require 'importer/gpx'
|
|
5
|
+
require 'importer/timex'
|
|
5
6
|
|
|
6
7
|
module Importer
|
|
7
8
|
def Importer.file_type(name)
|
|
@@ -14,6 +15,15 @@ module Importer
|
|
|
14
15
|
return "SUUNTO"
|
|
15
16
|
when /\.gpx$/i
|
|
16
17
|
return "GPX"
|
|
18
|
+
when /\.csv$/i
|
|
19
|
+
f = File.new(name)
|
|
20
|
+
first_line = f.readline
|
|
21
|
+
f.close
|
|
22
|
+
if first_line.chomp == "[Timex Trainer Data File]"
|
|
23
|
+
return "TIMEX"
|
|
24
|
+
else
|
|
25
|
+
return "UNKNOWN CSV"
|
|
26
|
+
end
|
|
17
27
|
end
|
|
18
28
|
end
|
|
19
29
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module Importer
|
|
2
|
+
class Timex
|
|
3
|
+
attr_reader :time_zone
|
|
4
|
+
|
|
5
|
+
def initialize(opts = {:data => nil, :time_zone => "UTC"})
|
|
6
|
+
@data = opts[:data]
|
|
7
|
+
@time_zone = opts[:time_zone]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def restore
|
|
11
|
+
workout = HRMParser::Workout.new(:duration => 0)
|
|
12
|
+
|
|
13
|
+
params = parse_params("session data")
|
|
14
|
+
|
|
15
|
+
dt = DateTime.strptime(params["Sessiondate"], "%d/%m/%Y %H:%M:%S")
|
|
16
|
+
time_for_parse = dt.strftime("%b %d %H:%M:%S @time_zone %Y")
|
|
17
|
+
|
|
18
|
+
workout.time = Time.parse(time_for_parse)
|
|
19
|
+
workout.duration = params["duration"].to_f
|
|
20
|
+
|
|
21
|
+
workout.trackpoints = get_trackpoints(workout.time)
|
|
22
|
+
|
|
23
|
+
workout.calc_average_hr!
|
|
24
|
+
workout.calc_altitude_gain!
|
|
25
|
+
workout.calc_average_speed!
|
|
26
|
+
workout.set_distance_from_trackpoints!
|
|
27
|
+
|
|
28
|
+
return workout
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def parse_params(string)
|
|
36
|
+
hash = {}
|
|
37
|
+
param_block = find_block(string)
|
|
38
|
+
param_block.each do |param|
|
|
39
|
+
# /=/ in case that doesn't work
|
|
40
|
+
key, value = param.split("=", 2)
|
|
41
|
+
key = key.strip unless key.nil?
|
|
42
|
+
value = value.strip unless value.nil?
|
|
43
|
+
hash[key] = value unless key.nil?
|
|
44
|
+
end
|
|
45
|
+
return hash
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def find_block(header)
|
|
49
|
+
found = false
|
|
50
|
+
block = []
|
|
51
|
+
@data.each do |line|
|
|
52
|
+
line.chomp!
|
|
53
|
+
found = false if line =~ /^\[.*\]$/
|
|
54
|
+
block << line if found
|
|
55
|
+
found = true if line =~ /\[#{header}\]/
|
|
56
|
+
end
|
|
57
|
+
return block
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def parse_data(string)
|
|
61
|
+
data = []
|
|
62
|
+
block_text = find_block(string)
|
|
63
|
+
block_text.each do |block_line|
|
|
64
|
+
data << block_line.chomp
|
|
65
|
+
end
|
|
66
|
+
return data
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def get_trackpoints(base_time)
|
|
70
|
+
trackpoints = []
|
|
71
|
+
have_gps = false
|
|
72
|
+
logs = parse_data("recorded")
|
|
73
|
+
fields = logs[0].split(/,/)
|
|
74
|
+
have_gps = true if fields.size > 5
|
|
75
|
+
|
|
76
|
+
for line in logs do
|
|
77
|
+
if have_gps
|
|
78
|
+
if line =~ /^".*"/ then line.gsub!(/"(.*?)"/,'\1') end # remove double-quotes at string beginning & end
|
|
79
|
+
seconds, hr, speed_imperial, distance_imperial, data_flag, lng, lat, altitude, acqs, trueh, magh = line.split(/,/)
|
|
80
|
+
else
|
|
81
|
+
seconds, hr, speed_imperial, distance_imperial, data_flag = line.split(/,/)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
## Convert speed and distance to metric - meters specifically
|
|
86
|
+
distance = distance_imperial.to_f * 1609.344
|
|
87
|
+
speed = speed_imperial.to_f * 0.44704
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
trackpoint = HRMParser::TrackPoint.new
|
|
91
|
+
|
|
92
|
+
points_f = %w[speed distance lat lng altitude]
|
|
93
|
+
points_i = %w[hr]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
points_f.each do |p|
|
|
97
|
+
value = (eval p).to_f
|
|
98
|
+
value = nil if value == 0.0
|
|
99
|
+
trackpoint.send("#{p}=".to_sym, value)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
points_i.each do |p|
|
|
103
|
+
value = (eval p).to_i
|
|
104
|
+
value = nil if value == 0
|
|
105
|
+
trackpoint.send("#{p}=".to_sym, value)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
trackpoint.time = base_time + seconds.to_i
|
|
109
|
+
|
|
110
|
+
trackpoints << trackpoint
|
|
111
|
+
end
|
|
112
|
+
return trackpoints
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
end
|
data/spec/hrmparser_spec.rb
CHANGED
|
@@ -50,197 +50,249 @@ module HRMParser
|
|
|
50
50
|
type = Importer.file_type("spec/samples/polarRS400.hrm")
|
|
51
51
|
type.should == "POLAR_HRM"
|
|
52
52
|
end
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# it "finds the duration, time" do
|
|
57
|
-
# filename = "spec/samples/gps-with-suunto.gpx"
|
|
58
|
-
# data = File.read(filename)
|
|
59
|
-
# importer = Importer::GPX.new(:data => data)
|
|
60
|
-
# workout = importer.restore
|
|
61
|
-
# workout.time.should == Time.parse("Thu May 07 21:32:31 UTC 2009")
|
|
62
|
-
#
|
|
63
|
-
# # Duration is actualy less, but we don't account for stopped time right now
|
|
64
|
-
# workout.duration.should be_close(6284,1)
|
|
65
|
-
# end
|
|
66
|
-
# it "calculates the distance and speed" do
|
|
67
|
-
# filename = "spec/samples/gps-with-suunto.gpx"
|
|
68
|
-
# data = File.read(filename)
|
|
69
|
-
# importer = Importer::GPX.new(:data => data)
|
|
70
|
-
# workout = importer.restore
|
|
71
|
-
# workout.average_speed.should be_close(6.7, 0.2)
|
|
72
|
-
# workout.distance.should be_close(26427, 1)
|
|
73
|
-
# end
|
|
74
|
-
# it "handles files with drops" do
|
|
75
|
-
# filename = "spec/samples/gps-flat-run.gpx"
|
|
76
|
-
# data = File.read(filename)
|
|
77
|
-
# importer = Importer::GPX.new(:data => data)
|
|
78
|
-
# workout = importer.restore
|
|
79
|
-
# workout.average_speed.should be_close(2.9, 0.2)
|
|
80
|
-
# workout.distance.should be_close(11453, 1)
|
|
81
|
-
# workout.altitude_gain.should be_close(325, 10)
|
|
82
|
-
# end
|
|
83
|
-
it "deals with stopping and calculates duration correctly" do
|
|
84
|
-
filename = "spec/samples/gps-with-stops.gpx"
|
|
85
|
-
data = File.read(filename)
|
|
86
|
-
importer = Importer::GPX.new(:data => data)
|
|
87
|
-
workout = importer.restore
|
|
88
|
-
workout.average_speed.should be_close(6.5, 0.2)
|
|
89
|
-
workout.distance.should be_close(5230, 1)
|
|
90
|
-
workout.altitude_gain.should be_close(11, 10)
|
|
91
|
-
workout.duration.should be_close(1149, 1)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
it "deals with stopping and calculates duration correctly" do
|
|
95
|
-
filename = "spec/samples/gps-with-stops-2.gpx"
|
|
96
|
-
data = File.read(filename)
|
|
97
|
-
importer = Importer::GPX.new(:data => data)
|
|
98
|
-
workout = importer.restore
|
|
99
|
-
workout.average_speed.should be_close(5.7, 0.2)
|
|
100
|
-
workout.distance.should be_close(3099, 1)
|
|
101
|
-
workout.altitude_gain.should be_close(24, 10)
|
|
102
|
-
workout.duration.should be_close(564, 1)
|
|
53
|
+
it "identifies timex" do
|
|
54
|
+
type = Importer.file_type("spec/samples/timex/HR.csv")
|
|
55
|
+
type.should == "TIMEX"
|
|
103
56
|
end
|
|
104
|
-
|
|
105
57
|
end
|
|
106
58
|
|
|
107
|
-
# context "Parse
|
|
108
|
-
# it "finds
|
|
109
|
-
# filename = "spec/samples/
|
|
110
|
-
# data = File.read(filename)
|
|
111
|
-
# importer = Importer::Garmin.new(:data => data)
|
|
112
|
-
# workout = importer.restore
|
|
113
|
-
# workout.time.should == Time.parse("Fri Aug 22 01:04:55 UTC 2008")
|
|
114
|
-
# end
|
|
115
|
-
# it "finds the duration on a short workout" do
|
|
116
|
-
# filename = "spec/samples/indoor-garmin-405.TCX"
|
|
59
|
+
# context "Parse a GPS file" do
|
|
60
|
+
# it "finds the duration, time" do
|
|
61
|
+
# filename = "spec/samples/gps-with-suunto.gpx"
|
|
117
62
|
# data = File.read(filename)
|
|
118
|
-
# importer = Importer::
|
|
63
|
+
# importer = Importer::GPX.new(:data => data)
|
|
119
64
|
# workout = importer.restore
|
|
120
|
-
# workout.
|
|
65
|
+
# workout.time.should == Time.parse("Thu May 07 21:32:31 UTC 2009")
|
|
66
|
+
#
|
|
67
|
+
# # Duration is actualy less, but we don't account for stopped time right now
|
|
68
|
+
# workout.duration.should be_close(6284,1)
|
|
121
69
|
# end
|
|
122
|
-
# it "
|
|
123
|
-
# filename = "spec/samples/
|
|
70
|
+
# it "calculates the distance and speed" do
|
|
71
|
+
# filename = "spec/samples/gps-with-suunto.gpx"
|
|
124
72
|
# data = File.read(filename)
|
|
125
|
-
# importer = Importer::
|
|
73
|
+
# importer = Importer::GPX.new(:data => data)
|
|
126
74
|
# workout = importer.restore
|
|
127
|
-
# workout.
|
|
128
|
-
# workout.
|
|
129
|
-
# workout.average_speed.should be_nil
|
|
130
|
-
# workout.altitude_gain.should be_nil
|
|
131
|
-
# workout.trackpoints.should == {}
|
|
75
|
+
# workout.average_speed.should be_close(6.7, 0.2)
|
|
76
|
+
# workout.distance.should be_close(26427, 1)
|
|
132
77
|
# end
|
|
133
|
-
# it "
|
|
134
|
-
# filename = "spec/samples/
|
|
78
|
+
# it "handles files with drops" do
|
|
79
|
+
# filename = "spec/samples/gps-flat-run.gpx"
|
|
135
80
|
# data = File.read(filename)
|
|
136
|
-
# importer = Importer::
|
|
81
|
+
# importer = Importer::GPX.new(:data => data)
|
|
137
82
|
# workout = importer.restore
|
|
138
|
-
# workout.
|
|
139
|
-
# workout.
|
|
140
|
-
# workout.
|
|
141
|
-
# workout.altitude_gain.should be_close(372, 10)
|
|
83
|
+
# workout.average_speed.should be_close(2.9, 0.2)
|
|
84
|
+
# workout.distance.should be_close(11453, 1)
|
|
85
|
+
# workout.altitude_gain.should be_close(325, 10)
|
|
142
86
|
# end
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
# it "gets workout level settings for outdoor workout" do
|
|
146
|
-
# filename = "spec/samples/outdoor-garmin-405.TCX"
|
|
87
|
+
# it "deals with stopping and calculates duration correctly" do
|
|
88
|
+
# filename = "spec/samples/gps-with-stops.gpx"
|
|
147
89
|
# data = File.read(filename)
|
|
148
|
-
# importer = Importer::
|
|
90
|
+
# importer = Importer::GPX.new(:data => data)
|
|
149
91
|
# workout = importer.restore
|
|
150
|
-
# workout.
|
|
151
|
-
# workout.
|
|
152
|
-
# workout.
|
|
153
|
-
# workout.
|
|
92
|
+
# workout.average_speed.should be_close(6.5, 0.2)
|
|
93
|
+
# workout.distance.should be_close(5230, 1)
|
|
94
|
+
# workout.altitude_gain.should be_close(11, 10)
|
|
95
|
+
# workout.duration.should be_close(1149, 1)
|
|
154
96
|
# end
|
|
155
|
-
#
|
|
156
|
-
# it "
|
|
157
|
-
# filename = "spec/samples/
|
|
97
|
+
#
|
|
98
|
+
# it "deals with stopping and calculates duration correctly" do
|
|
99
|
+
# filename = "spec/samples/gps-with-stops-2.gpx"
|
|
158
100
|
# data = File.read(filename)
|
|
159
|
-
# importer = Importer::
|
|
101
|
+
# importer = Importer::GPX.new(:data => data)
|
|
160
102
|
# workout = importer.restore
|
|
161
|
-
# workout.
|
|
162
|
-
# workout.
|
|
163
|
-
# workout.
|
|
164
|
-
# workout.
|
|
103
|
+
# workout.average_speed.should be_close(5.7, 0.2)
|
|
104
|
+
# workout.distance.should be_close(3099, 1)
|
|
105
|
+
# workout.altitude_gain.should be_close(24, 10)
|
|
106
|
+
# workout.duration.should be_close(564, 1)
|
|
165
107
|
# end
|
|
166
|
-
#
|
|
167
|
-
# it "doesn't have any 0 in latitude" do
|
|
168
|
-
# filename = "spec/samples/garmin-405-with-0-0.TCX"
|
|
169
|
-
# data = File.read(filename)
|
|
170
|
-
# importer = Importer::Garmin.new(:data => data)
|
|
171
|
-
# workout = importer.restore
|
|
172
|
-
# workout.trackpoints.map {|tp| tp.lat.should_not == 0.0}
|
|
173
|
-
# workout.trackpoints.map {|tp| tp.lat.should_not == "undefined"}
|
|
174
|
-
# end
|
|
175
|
-
#
|
|
176
|
-
# it "handles files with INSANE duration" do
|
|
177
|
-
# filename = "spec/samples/insane-duration.TCX"
|
|
178
|
-
# data = File.read(filename)
|
|
179
|
-
# importer = Importer::Garmin.new(:data => data)
|
|
180
|
-
# workout = importer.restore
|
|
181
|
-
# workout.duration.should be_close(4996, 0.2)
|
|
182
|
-
# end
|
|
108
|
+
#
|
|
183
109
|
# end
|
|
184
110
|
#
|
|
185
|
-
# context "Parse
|
|
186
|
-
# it "finds
|
|
187
|
-
# filename ="spec/samples/
|
|
111
|
+
# context "Parse garmin file" do
|
|
112
|
+
# it "finds workout start time on a short workout" do
|
|
113
|
+
# filename = "spec/samples/indoor-garmin-405.TCX"
|
|
188
114
|
# data = File.read(filename)
|
|
189
|
-
# importer = Importer::
|
|
115
|
+
# importer = Importer::Garmin.new(:data => data)
|
|
190
116
|
# workout = importer.restore
|
|
191
|
-
# workout.
|
|
192
|
-
# workout.time.should == Time.parse("Thu Apr 16 12:01:55 -0700 2009")
|
|
117
|
+
# workout.time.should == Time.parse("Fri Aug 22 01:04:55 UTC 2008")
|
|
193
118
|
# end
|
|
194
|
-
# it "
|
|
195
|
-
# filename ="spec/samples/
|
|
119
|
+
# it "finds the duration on a short workout" do
|
|
120
|
+
# filename = "spec/samples/indoor-garmin-405.TCX"
|
|
196
121
|
# data = File.read(filename)
|
|
197
|
-
# importer = Importer::
|
|
122
|
+
# importer = Importer::Garmin.new(:data => data)
|
|
198
123
|
# workout = importer.restore
|
|
199
|
-
# workout.
|
|
124
|
+
# workout.duration.should be_close(755, 1)
|
|
200
125
|
# end
|
|
201
|
-
#
|
|
202
|
-
#
|
|
203
|
-
# context "Parse a Polar RR file" do
|
|
204
|
-
# it "calculates the heart rate from RR" do
|
|
205
|
-
# filename ="spec/samples/polarRS800-RR.hrm"
|
|
126
|
+
# it "indoor workout has no trackpoints" do
|
|
127
|
+
# filename = "spec/samples/indoor-garmin-405.TCX"
|
|
206
128
|
# data = File.read(filename)
|
|
207
|
-
# importer = Importer::
|
|
129
|
+
# importer = Importer::Garmin.new(:data => data)
|
|
208
130
|
# workout = importer.restore
|
|
209
|
-
# workout.
|
|
210
|
-
# workout.average_hr.should
|
|
211
|
-
# workout.average_speed.should
|
|
131
|
+
# workout.distance.should be_nil
|
|
132
|
+
# workout.average_hr.should be_nil
|
|
133
|
+
# workout.average_speed.should be_nil
|
|
134
|
+
# workout.altitude_gain.should be_nil
|
|
135
|
+
# workout.trackpoints.should == {}
|
|
212
136
|
# end
|
|
213
|
-
#
|
|
214
|
-
#
|
|
215
|
-
# context "Parse a Suunto T6C RR file" do
|
|
216
|
-
# it "finds the duration and time" do
|
|
217
|
-
# filename = "spec/samples/suunto-t6-RR-stops.sdf"
|
|
137
|
+
# it "parses files with only LAT and LNG" do
|
|
138
|
+
# filename = "spec/samples/garmin-only-lat-lng.tcx"
|
|
218
139
|
# data = File.read(filename)
|
|
219
|
-
# importer = Importer::
|
|
140
|
+
# importer = Importer::Garmin.new(:data => data)
|
|
220
141
|
# workout = importer.restore
|
|
221
|
-
# workout.
|
|
222
|
-
# workout.
|
|
142
|
+
# workout.distance.should be_close(172052, 1)
|
|
143
|
+
# workout.average_hr.should be_nil
|
|
144
|
+
# workout.average_speed.should be_close(5.93, 0.1)
|
|
145
|
+
# workout.altitude_gain.should be_close(372, 10)
|
|
223
146
|
# end
|
|
224
|
-
#
|
|
225
|
-
#
|
|
147
|
+
#
|
|
148
|
+
# # Parsing the full XML is just slow. Commenting out for now.
|
|
149
|
+
# it "gets workout level settings for outdoor workout" do
|
|
150
|
+
# filename = "spec/samples/outdoor-garmin-405.TCX"
|
|
226
151
|
# data = File.read(filename)
|
|
227
|
-
# importer = Importer::
|
|
152
|
+
# importer = Importer::Garmin.new(:data => data)
|
|
228
153
|
# workout = importer.restore
|
|
229
|
-
# workout.
|
|
230
|
-
# workout.
|
|
231
|
-
# workout.
|
|
232
|
-
# workout.altitude_gain.should be_close(
|
|
154
|
+
# workout.distance.should be_close(11740, 5)
|
|
155
|
+
# workout.average_hr.should be_close(149.7, 0.5)
|
|
156
|
+
# workout.average_speed.should be_close(1.5, 0.2)
|
|
157
|
+
# workout.altitude_gain.should be_close(580, 25)
|
|
233
158
|
# end
|
|
234
|
-
#
|
|
235
|
-
#
|
|
159
|
+
#
|
|
160
|
+
# it "gets workout level settings for weird distance workout" do
|
|
161
|
+
# filename = "spec/samples/garmin-405-dies-distance.TCX"
|
|
236
162
|
# data = File.read(filename)
|
|
237
|
-
# importer = Importer::
|
|
163
|
+
# importer = Importer::Garmin.new(:data => data)
|
|
238
164
|
# workout = importer.restore
|
|
239
|
-
# workout.
|
|
240
|
-
# workout.
|
|
241
|
-
# workout.
|
|
242
|
-
# workout.
|
|
165
|
+
# workout.distance.should be_close(9426, 1)
|
|
166
|
+
# workout.average_hr.should == nil
|
|
167
|
+
# workout.average_speed.should be_close(6.7, 0.2)
|
|
168
|
+
# workout.altitude_gain.should be_close(40, 10)
|
|
243
169
|
# end
|
|
170
|
+
#
|
|
171
|
+
# it "doesn't have any 0 in latitude" do
|
|
172
|
+
# filename = "spec/samples/garmin-405-with-0-0.TCX"
|
|
173
|
+
# data = File.read(filename)
|
|
174
|
+
# importer = Importer::Garmin.new(:data => data)
|
|
175
|
+
# workout = importer.restore
|
|
176
|
+
# workout.trackpoints.map {|tp| tp.lat.should_not == 0.0}
|
|
177
|
+
# workout.trackpoints.map {|tp| tp.lat.should_not == "undefined"}
|
|
178
|
+
# end
|
|
179
|
+
#
|
|
180
|
+
# it "handles files with INSANE duration" do
|
|
181
|
+
# filename = "spec/samples/insane-duration.TCX"
|
|
182
|
+
# data = File.read(filename)
|
|
183
|
+
# importer = Importer::Garmin.new(:data => data)
|
|
184
|
+
# workout = importer.restore
|
|
185
|
+
# workout.duration.should be_close(4996, 0.2)
|
|
186
|
+
# end
|
|
244
187
|
# end
|
|
188
|
+
#
|
|
189
|
+
# context "Parse polar RS400 file" do
|
|
190
|
+
# it "finds the duration and time" do
|
|
191
|
+
# filename ="spec/samples/polarRS400.hrm"
|
|
192
|
+
# data = File.read(filename)
|
|
193
|
+
# importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
194
|
+
# workout = importer.restore
|
|
195
|
+
# workout.duration.should be_close(3569,1)
|
|
196
|
+
# workout.time.should == Time.parse("Thu Apr 16 12:01:55 -0700 2009")
|
|
197
|
+
# end
|
|
198
|
+
# it "calculates the average heartrate" do
|
|
199
|
+
# filename ="spec/samples/polarRS400.hrm"
|
|
200
|
+
# data = File.read(filename)
|
|
201
|
+
# importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
202
|
+
# workout = importer.restore
|
|
203
|
+
# workout.average_hr.should be_close(145, 1)
|
|
204
|
+
# end
|
|
205
|
+
# end
|
|
206
|
+
#
|
|
207
|
+
# context "Parse a Polar RR file" do
|
|
208
|
+
# it "calculates the heart rate from RR" do
|
|
209
|
+
# filename ="spec/samples/polarRS800-RR.hrm"
|
|
210
|
+
# data = File.read(filename)
|
|
211
|
+
# importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
212
|
+
# workout = importer.restore
|
|
213
|
+
# workout.trackpoints.each {|tp| tp.hr.should < 220 && tp.hr.should > 30}
|
|
214
|
+
# workout.average_hr.should be_close(115, 1)
|
|
215
|
+
# workout.average_speed.should == nil
|
|
216
|
+
# end
|
|
217
|
+
# end
|
|
218
|
+
#
|
|
219
|
+
# context "Parse a Suunto T6C RR file" do
|
|
220
|
+
# it "finds the duration and time" do
|
|
221
|
+
# filename = "spec/samples/suunto-t6-RR-stops.sdf"
|
|
222
|
+
# data = File.read(filename)
|
|
223
|
+
# importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
224
|
+
# workout = importer.restore
|
|
225
|
+
# workout.duration.should be_close(4781,1)
|
|
226
|
+
# workout.time.should == Time.parse("Thu May 07 14:16:07 -0700 2009")
|
|
227
|
+
# end
|
|
228
|
+
# it "calculates the average HR & altitude" do
|
|
229
|
+
# filename = "spec/samples/suunto-t6-RR-stops.sdf"
|
|
230
|
+
# data = File.read(filename)
|
|
231
|
+
# importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
232
|
+
# workout = importer.restore
|
|
233
|
+
# workout.average_hr.should be_close(152,1)
|
|
234
|
+
# workout.average_speed.should == nil
|
|
235
|
+
# workout.trackpoints.each { |tp| tp.speed.should == nil }
|
|
236
|
+
# workout.altitude_gain.should be_close(115, 10)
|
|
237
|
+
# end
|
|
238
|
+
# it "calculates the speed and distance" do
|
|
239
|
+
# filename = "spec/samples/suunto-with-cadence-speed-distance.sdf"
|
|
240
|
+
# data = File.read(filename)
|
|
241
|
+
# importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
242
|
+
# workout = importer.restore
|
|
243
|
+
# workout.average_hr.should be_close(131,1)
|
|
244
|
+
# workout.average_speed.should be_close(9.3, 0.1)
|
|
245
|
+
# workout.altitude_gain.should be_close(75, 15)
|
|
246
|
+
# workout.distance.should == 124597
|
|
247
|
+
# end
|
|
248
|
+
# end
|
|
249
|
+
|
|
250
|
+
context "Parse Timex CSV" do
|
|
251
|
+
it "handles HR only" do
|
|
252
|
+
filename = "spec/samples/timex/HR.csv"
|
|
253
|
+
data = File.read(filename)
|
|
254
|
+
importer = Importer::Timex.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
255
|
+
workout = importer.restore
|
|
256
|
+
workout.duration.should be_close(3298, 1)
|
|
257
|
+
workout.time.should == Time.parse("Jan 01 09:27:26 -0800 2009")
|
|
258
|
+
workout.average_hr.should be_close(81,1)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
it "does speed and distance" do
|
|
262
|
+
filename = "spec/samples/timex/Speed+Distance.csv"
|
|
263
|
+
data = File.read(filename)
|
|
264
|
+
importer = Importer::Timex.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
265
|
+
workout = importer.restore
|
|
266
|
+
workout.duration.should be_close(2580, 1)
|
|
267
|
+
workout.time.should == Time.parse("Feb 01 08:27:02 -0800 2009")
|
|
268
|
+
workout.average_hr.should == nil
|
|
269
|
+
workout.distance.should be_close(8391, 1)
|
|
270
|
+
workout.average_speed.should be_close(3.2, 0.2)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it "handles a GPS only file" do
|
|
274
|
+
filename = "spec/samples/timex/GPS.csv"
|
|
275
|
+
data = File.read(filename)
|
|
276
|
+
importer = Importer::Timex.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
277
|
+
workout = importer.restore
|
|
278
|
+
workout.duration.should be_close(1937, 1)
|
|
279
|
+
workout.time.should == Time.parse("Jun 01 12:03:12 -0700 2009")
|
|
280
|
+
workout.average_hr.should == nil
|
|
281
|
+
workout.distance.should be_close(6035, 1)
|
|
282
|
+
workout.average_speed.should be_close(3.05, 0.05)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it "handles GPS & HR" do
|
|
286
|
+
filename = "spec/samples/timex/GPS+HR.csv"
|
|
287
|
+
data = File.read(filename)
|
|
288
|
+
importer = Importer::Timex.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
|
|
289
|
+
workout = importer.restore
|
|
290
|
+
workout.duration.should be_close(2677.0, 1)
|
|
291
|
+
workout.time.should == Time.parse("Jul 01 12:00:43 -0700 2009")
|
|
292
|
+
workout.average_hr.should be_close(169,1)
|
|
293
|
+
workout.distance.should be_close(6435, 1)
|
|
294
|
+
workout.average_speed.should be_close(2.34, 0.05)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
245
297
|
end
|
|
246
298
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: teich-hrmparser
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Oren Teich
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2009-
|
|
12
|
+
date: 2009-08-15 00:00:00 -07:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies: []
|
|
15
15
|
|
|
@@ -35,6 +35,7 @@ files:
|
|
|
35
35
|
- lib/hrmparser/importer/gpx.rb
|
|
36
36
|
- lib/hrmparser/importer/polar.rb
|
|
37
37
|
- lib/hrmparser/importer/suunto.rb
|
|
38
|
+
- lib/hrmparser/importer/timex.rb
|
|
38
39
|
- lib/hrmparser/trackpoint.rb
|
|
39
40
|
- lib/hrmparser/workout.rb
|
|
40
41
|
- spec/arraymath_spec.rb
|
|
@@ -43,6 +44,7 @@ files:
|
|
|
43
44
|
- spec/spec_helper.rb
|
|
44
45
|
has_rdoc: false
|
|
45
46
|
homepage: http://github.com/teich/hrmparser
|
|
47
|
+
licenses:
|
|
46
48
|
post_install_message:
|
|
47
49
|
rdoc_options:
|
|
48
50
|
- --charset=UTF-8
|
|
@@ -63,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
63
65
|
requirements: []
|
|
64
66
|
|
|
65
67
|
rubyforge_project:
|
|
66
|
-
rubygems_version: 1.
|
|
68
|
+
rubygems_version: 1.3.5
|
|
67
69
|
signing_key:
|
|
68
70
|
specification_version: 3
|
|
69
71
|
summary: Heart Rate Monitor Parser
|