teich-hrmparser 0.4.7 → 0.4.8

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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+
data/CHANGELOG.txt CHANGED
@@ -1,3 +1,6 @@
1
+ 0.4.8 - May 23, 2009
2
+ Fixed importing when TCX LAP duration are totally completely incredibly insanely wrong
3
+
1
4
  0.4.6 - May 11th, 2009
2
5
  Added support for Suunto full variables including speed, distance, etc.
3
6
 
data/README.rdoc CHANGED
@@ -39,4 +39,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
39
39
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
40
40
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
41
41
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
42
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 4
3
- :patch: 7
2
+ :patch: 8
4
3
  :major: 0
4
+ :minor: 4
data/hrmparser.gemspec ADDED
@@ -0,0 +1,56 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{hrmparser}
5
+ s.version = "0.4.8"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Oren Teich"]
9
+ s.date = %q{2009-05-24}
10
+ s.description = %q{Parses Polar and Garmin HRM files.}
11
+ s.email = %q{oren@teich.net}
12
+ s.extra_rdoc_files = [
13
+ "README.rdoc"
14
+ ]
15
+ s.files = [
16
+ ".gitignore",
17
+ "CHANGELOG.txt",
18
+ "README.rdoc",
19
+ "Rakefile",
20
+ "VERSION.yml",
21
+ "hrmparser.gemspec",
22
+ "lib/hrmparser.rb",
23
+ "lib/hrmparser/arraymath.rb",
24
+ "lib/hrmparser/importer.rb",
25
+ "lib/hrmparser/importer/garmin.rb",
26
+ "lib/hrmparser/importer/gpx.rb",
27
+ "lib/hrmparser/importer/polar.rb",
28
+ "lib/hrmparser/importer/suunto.rb",
29
+ "lib/hrmparser/trackpoint.rb",
30
+ "lib/hrmparser/workout.rb",
31
+ "spec/arraymath_spec.rb",
32
+ "spec/hrmparser_spec.rb",
33
+ "spec/spec.opts",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/teich/hrmparser}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.3}
40
+ s.summary = %q{Heart Rate Monitor Parser}
41
+ s.test_files = [
42
+ "spec/arraymath_spec.rb",
43
+ "spec/hrmparser_spec.rb",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ else
53
+ end
54
+ else
55
+ end
56
+ end
@@ -11,10 +11,12 @@ module Importer
11
11
  @xml = Hpricot::XML(@data)
12
12
  workout.time = Time.parse((@xml/:Id).innerHTML)
13
13
 
14
- (@xml/:Lap).each do |lap|
15
- f_time = (lap/:TotalTimeSeconds).innerHTML
16
- workout.duration += Float f_time
17
- end
14
+ # Grab the duration from the lap. This _can_ be totally, completly wrong - AKA 10 years long.
15
+ # So if we have trackpoints, we'll replace it down lower
16
+ (@xml/:Lap).each do |lap|
17
+ f_time = (lap/:TotalTimeSeconds).innerHTML
18
+ workout.duration += Float f_time
19
+ end
18
20
 
19
21
  found = false
20
22
  trackpoints = Array.new
@@ -64,6 +66,7 @@ module Importer
64
66
  end
65
67
 
66
68
  if found
69
+ workout.duration = trackpoints.last.time - trackpoints.first.time
67
70
  workout.trackpoints = trackpoints
68
71
  workout.calc_average_speed!
69
72
  workout.calc_altitude_gain!
@@ -31,7 +31,7 @@ module HRMParser
31
31
  start = smoothed_altitude.first
32
32
  smoothed_altitude.each do |alt|
33
33
  diff = alt - start
34
- if (diff > 0)
34
+ if (diff > 0.5)
35
35
  gain += diff
36
36
  end
37
37
  start = alt
@@ -3,196 +3,214 @@ require File.dirname(__FILE__) + '/spec_helper.rb'
3
3
  # Time to add your specs!
4
4
  # http://rspec.info/
5
5
  module HRMParser
6
- describe "TrackPoint" do
7
- context "new trackpoint" do
8
- it "has no variables set" do
9
- hrm = TrackPoint.new
10
- hrm.speed == nil
11
- hrm.distance == nil
12
- hrm.lat.should == nil
13
- hrm.lng.should == nil
14
- hrm.altitude.should == nil
15
- hrm.hr.should == nil
16
- end
17
- end
18
- end
6
+ describe "TrackPoint" do
7
+ context "new trackpoint" do
8
+ it "has no variables set" do
9
+ hrm = TrackPoint.new
10
+ hrm.speed == nil
11
+ hrm.distance == nil
12
+ hrm.lat.should == nil
13
+ hrm.lng.should == nil
14
+ hrm.altitude.should == nil
15
+ hrm.hr.should == nil
16
+ end
17
+ end
18
+ end
19
19
 
20
- describe "Workout" do
21
- context "new workout" do
22
- it "has no variables set" do
23
- workout = Workout.new
24
- workout.distance.should == nil
25
- workout.duration.should == nil
26
- workout.average_hr.should == nil
27
- workout.name.should == nil
28
- workout.file_name.should == nil
29
- end
30
- it "set name through initializer" do
31
- workout = Workout.new(:name => "test workout")
32
- workout.name.should == "test workout"
33
- end
34
- it "can not set average_hr during init" do
35
- workout = Workout.new(:average_hr => 150)
36
- workout.average_hr.should == nil
37
- end
38
- end
20
+ describe "Workout" do
21
+ context "new workout" do
22
+ it "has no variables set" do
23
+ workout = Workout.new
24
+ workout.distance.should == nil
25
+ workout.duration.should == nil
26
+ workout.average_hr.should == nil
27
+ workout.name.should == nil
28
+ workout.file_name.should == nil
29
+ end
30
+ it "set name through initializer" do
31
+ workout = Workout.new(:name => "test workout")
32
+ workout.name.should == "test workout"
33
+ end
34
+ it "can not set average_hr during init" do
35
+ workout = Workout.new(:average_hr => 150)
36
+ workout.average_hr.should == nil
37
+ end
38
+ end
39
39
 
40
- context "Identifies files" do
41
- it "identify file as garmin" do
42
- type = Importer.file_type("spec/samples/small-garmin.TCX")
43
- type.should == "GARMIN_XML"
44
- end
45
- it "identification returns nil if no file specified" do
46
- type = Importer.file_type("")
47
- type.should == nil
48
- end
49
- it "identify file as polar" do
50
- type = Importer.file_type("spec/samples/polarRS400.hrm")
51
- type.should == "POLAR_HRM"
52
- end
53
- end
40
+ context "Identifies files" do
41
+ it "identify file as garmin" do
42
+ type = Importer.file_type("spec/samples/small-garmin.TCX")
43
+ type.should == "GARMIN_XML"
44
+ end
45
+ it "identification returns nil if no file specified" do
46
+ type = Importer.file_type("")
47
+ type.should == nil
48
+ end
49
+ it "identify file as polar" do
50
+ type = Importer.file_type("spec/samples/polarRS400.hrm")
51
+ type.should == "POLAR_HRM"
52
+ end
53
+ end
54
54
 
55
- context "Parse a GPS file" do
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(6382,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
- end
75
-
76
- context "Parse garmin file" do
77
- it "finds workout start time on a short workout" do
78
- filename = "spec/samples/indoor-garmin-405.TCX"
79
- data = File.read(filename)
80
- importer = Importer::Garmin.new(:data => data)
81
- workout = importer.restore
82
- workout.time.should == Time.parse("Fri Aug 22 01:04:55 UTC 2008")
83
- end
84
- it "finds the duration on a short workout" do
85
- filename = "spec/samples/indoor-garmin-405.TCX"
86
- data = File.read(filename)
87
- importer = Importer::Garmin.new(:data => data)
88
- workout = importer.restore
89
- workout.duration.should be_close(755, 1)
90
- end
91
- it "indoor workout has no trackpoints" do
92
- filename = "spec/samples/indoor-garmin-405.TCX"
93
- data = File.read(filename)
94
- importer = Importer::Garmin.new(:data => data)
95
- workout = importer.restore
96
- workout.distance.should be_nil
97
- workout.average_hr.should be_nil
98
- workout.average_speed.should be_nil
99
- workout.altitude_gain.should be_nil
100
- workout.trackpoints.should == {}
101
- end
102
-
103
- # Parsing the full XML is just slow. Commenting out for now.
104
- it "gets workout level settings for outdoor workout" do
105
- filename = "spec/samples/outdoor-garmin-405.TCX"
106
- data = File.read(filename)
107
- importer = Importer::Garmin.new(:data => data)
108
- workout = importer.restore
109
- workout.distance.should be_close(11740, 5)
110
- workout.average_hr.should be_close(149.7, 0.5)
111
- workout.average_speed.should be_close(1.5, 0.2)
112
- workout.altitude_gain.should be_close(580, 25)
113
- end
114
-
115
- it "gets workout level settings for weird distance workout" do
116
- filename = "spec/samples/garmin-405-dies-distance.TCX"
117
- data = File.read(filename)
118
- importer = Importer::Garmin.new(:data => data)
119
- workout = importer.restore
120
- workout.distance.should be_close(9426, 1)
121
- workout.average_hr.should == nil
122
- workout.average_speed.should be_close(6.7, 0.2)
123
- workout.altitude_gain.should be_close(40, 10)
124
- end
125
-
126
- it "doesn't have any 0 in latitude" do
127
- filename = "spec/samples/garmin-405-with-0-0.TCX"
128
- data = File.read(filename)
129
- importer = Importer::Garmin.new(:data => data)
130
- workout = importer.restore
131
- workout.trackpoints.map {|tp| tp.lat.should_not == 0.0}
132
- workout.trackpoints.map {|tp| tp.lat.should_not == "undefined"}
133
- end
134
- end
135
-
136
- context "Parse polar RS400 file" do
137
- it "finds the duration and time" do
138
- filename ="spec/samples/polarRS400.hrm"
139
- data = File.read(filename)
140
- importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
141
- workout = importer.restore
142
- workout.duration.should be_close(3569,1)
143
- workout.time.should == Time.parse("Thu Apr 16 12:01:55 -0700 2009")
144
- end
145
- it "calculates the average heartrate" do
146
- filename ="spec/samples/polarRS400.hrm"
147
- data = File.read(filename)
148
- importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
149
- workout = importer.restore
150
- workout.average_hr.should be_close(145, 1)
151
- end
152
- end
153
- context "Parse a Polar RR file" do
154
- it "calculates the heart rate from RR" do
155
- filename ="spec/samples/polarRS800-RR.hrm"
156
- data = File.read(filename)
157
- importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
158
- workout = importer.restore
159
- workout.trackpoints.each {|tp| tp.hr.should < 220 && tp.hr.should > 30}
160
- workout.average_hr.should be_close(115, 1)
161
- workout.average_speed.should == nil
162
- end
163
- end
164
-
165
- context "Parse a Suunto T6C RR file" do
166
- it "finds the duration and time" do
167
- filename = "spec/samples/suunto-t6-RR-stops.sdf"
168
- data = File.read(filename)
169
- importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
170
- workout = importer.restore
171
- workout.duration.should be_close(4781,1)
172
- workout.time.should == Time.parse("Thu May 07 14:16:07 -0700 2009")
173
- end
174
- it "calculates the average HR & altitude" do
175
- filename = "spec/samples/suunto-t6-RR-stops.sdf"
176
- data = File.read(filename)
177
- importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
178
- workout = importer.restore
179
- workout.average_hr.should be_close(152,1)
180
- workout.average_speed.should == nil
181
- workout.trackpoints.each { |tp| tp.speed.should == nil }
182
- workout.altitude_gain.should be_close(115, 10)
183
- end
184
- it "calculates the speed and distance" do
185
- filename = "spec/samples/suunto-with-cadence-speed-distance.sdf"
186
- data = File.read(filename)
187
- importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
188
- workout = importer.restore
189
- workout.average_hr.should be_close(131,1)
190
- workout.average_speed.should be_close(9.3, 0.1)
191
- workout.altitude_gain.should be_close(70, 10)
192
- workout.distance.should == 124597
193
- end
194
-
195
-
196
- end
197
- end
55
+ context "Parse a GPS file" do
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(6382,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
+ end
84
+
85
+ context "Parse garmin file" do
86
+ it "finds workout start time on a short workout" do
87
+ filename = "spec/samples/indoor-garmin-405.TCX"
88
+ data = File.read(filename)
89
+ importer = Importer::Garmin.new(:data => data)
90
+ workout = importer.restore
91
+ workout.time.should == Time.parse("Fri Aug 22 01:04:55 UTC 2008")
92
+ end
93
+ it "finds the duration on a short workout" do
94
+ filename = "spec/samples/indoor-garmin-405.TCX"
95
+ data = File.read(filename)
96
+ importer = Importer::Garmin.new(:data => data)
97
+ workout = importer.restore
98
+ workout.duration.should be_close(755, 1)
99
+ end
100
+ it "indoor workout has no trackpoints" do
101
+ filename = "spec/samples/indoor-garmin-405.TCX"
102
+ data = File.read(filename)
103
+ importer = Importer::Garmin.new(:data => data)
104
+ workout = importer.restore
105
+ workout.distance.should be_nil
106
+ workout.average_hr.should be_nil
107
+ workout.average_speed.should be_nil
108
+ workout.altitude_gain.should be_nil
109
+ workout.trackpoints.should == {}
110
+ end
111
+
112
+ # Parsing the full XML is just slow. Commenting out for now.
113
+ it "gets workout level settings for outdoor workout" do
114
+ filename = "spec/samples/outdoor-garmin-405.TCX"
115
+ data = File.read(filename)
116
+ importer = Importer::Garmin.new(:data => data)
117
+ workout = importer.restore
118
+ workout.distance.should be_close(11740, 5)
119
+ workout.average_hr.should be_close(149.7, 0.5)
120
+ workout.average_speed.should be_close(1.5, 0.2)
121
+ workout.altitude_gain.should be_close(580, 25)
122
+ end
123
+
124
+ it "gets workout level settings for weird distance workout" do
125
+ filename = "spec/samples/garmin-405-dies-distance.TCX"
126
+ data = File.read(filename)
127
+ importer = Importer::Garmin.new(:data => data)
128
+ workout = importer.restore
129
+ workout.distance.should be_close(9426, 1)
130
+ workout.average_hr.should == nil
131
+ workout.average_speed.should be_close(6.7, 0.2)
132
+ workout.altitude_gain.should be_close(40, 10)
133
+ end
134
+
135
+ it "doesn't have any 0 in latitude" do
136
+ filename = "spec/samples/garmin-405-with-0-0.TCX"
137
+ data = File.read(filename)
138
+ importer = Importer::Garmin.new(:data => data)
139
+ workout = importer.restore
140
+ workout.trackpoints.map {|tp| tp.lat.should_not == 0.0}
141
+ workout.trackpoints.map {|tp| tp.lat.should_not == "undefined"}
142
+ end
143
+
144
+ it "handles files with INSANE duration" do
145
+ filename = "spec/samples/insane-duration.TCX"
146
+ data = File.read(filename)
147
+ importer = Importer::Garmin.new(:data => data)
148
+ workout = importer.restore
149
+ workout.duration.should be_close(4996, 0.2)
150
+ end
151
+ end
152
+
153
+ context "Parse polar RS400 file" do
154
+ it "finds the duration and time" do
155
+ filename ="spec/samples/polarRS400.hrm"
156
+ data = File.read(filename)
157
+ importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
158
+ workout = importer.restore
159
+ workout.duration.should be_close(3569,1)
160
+ workout.time.should == Time.parse("Thu Apr 16 12:01:55 -0700 2009")
161
+ end
162
+ it "calculates the average heartrate" do
163
+ filename ="spec/samples/polarRS400.hrm"
164
+ data = File.read(filename)
165
+ importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
166
+ workout = importer.restore
167
+ workout.average_hr.should be_close(145, 1)
168
+ end
169
+ end
170
+
171
+ context "Parse a Polar RR file" do
172
+ it "calculates the heart rate from RR" do
173
+ filename ="spec/samples/polarRS800-RR.hrm"
174
+ data = File.read(filename)
175
+ importer = Importer::Polar.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
176
+ workout = importer.restore
177
+ workout.trackpoints.each {|tp| tp.hr.should < 220 && tp.hr.should > 30}
178
+ workout.average_hr.should be_close(115, 1)
179
+ workout.average_speed.should == nil
180
+ end
181
+ end
182
+
183
+ context "Parse a Suunto T6C RR file" do
184
+ it "finds the duration and time" do
185
+ filename = "spec/samples/suunto-t6-RR-stops.sdf"
186
+ data = File.read(filename)
187
+ importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
188
+ workout = importer.restore
189
+ workout.duration.should be_close(4781,1)
190
+ workout.time.should == Time.parse("Thu May 07 14:16:07 -0700 2009")
191
+ end
192
+ it "calculates the average HR & altitude" do
193
+ filename = "spec/samples/suunto-t6-RR-stops.sdf"
194
+ data = File.read(filename)
195
+ importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
196
+ workout = importer.restore
197
+ workout.average_hr.should be_close(152,1)
198
+ workout.average_speed.should == nil
199
+ workout.trackpoints.each { |tp| tp.speed.should == nil }
200
+ workout.altitude_gain.should be_close(115, 10)
201
+ end
202
+ it "calculates the speed and distance" do
203
+ filename = "spec/samples/suunto-with-cadence-speed-distance.sdf"
204
+ data = File.read(filename)
205
+ importer = Importer::Suunto.new(:data => data, :time_zone => "Pacific Time (US & Canada)")
206
+ workout = importer.restore
207
+ workout.average_hr.should be_close(131,1)
208
+ workout.average_speed.should be_close(9.3, 0.1)
209
+ workout.altitude_gain.should be_close(75, 15)
210
+ workout.distance.should == 124597
211
+ end
212
+
213
+
214
+ end
215
+ end
198
216
  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.7
4
+ version: 0.4.8
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-05-13 00:00:00 -07:00
12
+ date: 2009-05-24 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -22,10 +22,12 @@ extensions: []
22
22
  extra_rdoc_files:
23
23
  - README.rdoc
24
24
  files:
25
+ - .gitignore
25
26
  - CHANGELOG.txt
26
27
  - README.rdoc
27
28
  - Rakefile
28
29
  - VERSION.yml
30
+ - hrmparser.gemspec
29
31
  - lib/hrmparser.rb
30
32
  - lib/hrmparser/arraymath.rb
31
33
  - lib/hrmparser/importer.rb
@@ -39,7 +41,7 @@ files:
39
41
  - spec/hrmparser_spec.rb
40
42
  - spec/spec.opts
41
43
  - spec/spec_helper.rb
42
- has_rdoc: true
44
+ has_rdoc: false
43
45
  homepage: http://github.com/teich/hrmparser
44
46
  post_install_message:
45
47
  rdoc_options:
@@ -63,7 +65,7 @@ requirements: []
63
65
  rubyforge_project:
64
66
  rubygems_version: 1.2.0
65
67
  signing_key:
66
- specification_version: 2
68
+ specification_version: 3
67
69
  summary: Heart Rate Monitor Parser
68
70
  test_files:
69
71
  - spec/arraymath_spec.rb