fit4ruby 3.3.0 → 3.8.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.
- checksums.yaml +5 -5
- data/Gemfile.lock +30 -6
- data/fit4ruby.gemspec +4 -2
- data/lib/fit4ruby/Activity.rb +145 -58
- data/lib/fit4ruby/BDFieldNameTranslator.rb +36 -0
- data/lib/fit4ruby/DeviceInfo.rb +37 -0
- data/lib/fit4ruby/FDR_DevField_Extension.rb +81 -0
- data/lib/fit4ruby/FieldDescription.rb +26 -8
- data/lib/fit4ruby/FileId.rb +2 -1
- data/lib/fit4ruby/FitDataRecord.rb +86 -33
- data/lib/fit4ruby/FitDefinition.rb +11 -4
- data/lib/fit4ruby/FitDefinitionField.rb +6 -6
- data/lib/fit4ruby/FitDefinitionFieldBase.rb +15 -6
- data/lib/fit4ruby/FitDeveloperDataFieldDefinition.rb +1 -1
- data/lib/fit4ruby/FitFile.rb +2 -0
- data/lib/fit4ruby/FitMessageRecord.rb +26 -21
- data/lib/fit4ruby/FitRecord.rb +2 -1
- data/lib/fit4ruby/FitTypeDefs.rb +2 -2
- data/lib/fit4ruby/GlobalFitDictionaries.rb +278 -22
- data/lib/fit4ruby/GlobalFitMessage.rb +84 -14
- data/lib/fit4ruby/GlobalFitMessages.rb +104 -10
- data/lib/fit4ruby/Lap.rb +38 -3
- data/lib/fit4ruby/Length.rb +53 -0
- data/lib/fit4ruby/Record.rb +11 -2
- data/lib/fit4ruby/version.rb +1 -1
- data/spec/FitFile_spec.rb +233 -89
- metadata +43 -13
data/lib/fit4ruby/Lap.rb
CHANGED
@@ -12,20 +12,37 @@
|
|
12
12
|
|
13
13
|
require 'fit4ruby/FitDataRecord'
|
14
14
|
require 'fit4ruby/RecordAggregator'
|
15
|
+
require 'fit4ruby/FDR_DevField_Extension'
|
15
16
|
|
16
17
|
module Fit4Ruby
|
17
18
|
|
18
19
|
class Lap < FitDataRecord
|
19
20
|
|
20
21
|
include RecordAggregator
|
22
|
+
include FDR_DevField_Extension
|
21
23
|
|
22
|
-
attr_reader :records
|
24
|
+
attr_reader :records, :lengths
|
23
25
|
|
24
|
-
|
26
|
+
# Create a new Lap object.
|
27
|
+
# @param top_level_record [FitDataRecord] Top level record that is Lap
|
28
|
+
# belongs to.
|
29
|
+
# @param records [Array of Records] Records to associate with the Lap.
|
30
|
+
# @param lengths [Array of Lengths] Lengths to associate with the Lap.
|
31
|
+
# @param first_length_index [Fixnum] Index of the first Length in this Lap.
|
32
|
+
# @param previous_lap [Lap] Previous Lap on same Session.
|
33
|
+
# @param field_values [Hash] Hash that provides initial values for certain
|
34
|
+
# fields.
|
35
|
+
def initialize(top_level_record, records, previous_lap, field_values,
|
36
|
+
first_length_index, lengths)
|
25
37
|
super('lap')
|
38
|
+
@top_level_record = top_level_record
|
39
|
+
@lengths = lengths
|
26
40
|
@meta_field_units['avg_stride_length'] = 'm'
|
27
41
|
@records = records
|
28
42
|
@previous_lap = previous_lap
|
43
|
+
@lengths.each { |length| @records += length.records }
|
44
|
+
@first_length_index = first_length_index
|
45
|
+
@num_lengths = @lengths.length
|
29
46
|
|
30
47
|
if previous_lap && previous_lap.records && previous_lap.records.last
|
31
48
|
# Set the start time of the new lap to the timestamp of the last record
|
@@ -40,13 +57,31 @@ module Fit4Ruby
|
|
40
57
|
@total_elapsed_time = records.last.timestamp - @start_time
|
41
58
|
end
|
42
59
|
|
60
|
+
# Create instance variables for developer fields
|
61
|
+
create_dev_field_instance_variables
|
62
|
+
|
43
63
|
set_field_values(field_values)
|
44
64
|
end
|
45
65
|
|
46
|
-
def check(index)
|
66
|
+
def check(index, activity)
|
47
67
|
unless @message_index == index
|
48
68
|
Log.fatal "message_index must be #{index}, not #{@message_index}"
|
49
69
|
end
|
70
|
+
|
71
|
+
return if @num_lengths.zero?
|
72
|
+
|
73
|
+
unless @first_length_index
|
74
|
+
Log.fatal 'first_length_index is not set'
|
75
|
+
end
|
76
|
+
|
77
|
+
@first_length_index.upto(@first_length_index - @num_lengths) do |i|
|
78
|
+
if (length = activity.lengths[i])
|
79
|
+
@lengths << length
|
80
|
+
else
|
81
|
+
Log.fatal "Lap references length #{i} which is not contained in "
|
82
|
+
"the FIT file."
|
83
|
+
end
|
84
|
+
end
|
50
85
|
end
|
51
86
|
|
52
87
|
# Compute the average stride length for this Session.
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = Length.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
10
|
+
# published by the Free Software Foundation.
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'fit4ruby/FitDataRecord'
|
14
|
+
require 'fit4ruby/RecordAggregator'
|
15
|
+
|
16
|
+
module Fit4Ruby
|
17
|
+
|
18
|
+
class Length < FitDataRecord
|
19
|
+
|
20
|
+
include RecordAggregator
|
21
|
+
|
22
|
+
attr_reader :records
|
23
|
+
|
24
|
+
def initialize(records, previous_length, field_values)
|
25
|
+
super('length')
|
26
|
+
@records = records
|
27
|
+
@previous_length = previous_length
|
28
|
+
|
29
|
+
if previous_length && previous_length.records && previous_length.records.last
|
30
|
+
# Set the start time of the new length to the timestamp of the last record
|
31
|
+
# of the previous length.
|
32
|
+
@start_time = previous_length.records.last.timestamp
|
33
|
+
elsif records.first
|
34
|
+
# Or to the timestamp of the first record.
|
35
|
+
@start_time = records.first.timestamp
|
36
|
+
end
|
37
|
+
|
38
|
+
if records.last
|
39
|
+
@total_elapsed_time = records.last.timestamp - @start_time
|
40
|
+
end
|
41
|
+
|
42
|
+
set_field_values(field_values)
|
43
|
+
end
|
44
|
+
|
45
|
+
def check(index)
|
46
|
+
unless @message_index == index
|
47
|
+
Log.fatal "message_index must be #{index}, not #{@message_index}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/lib/fit4ruby/Record.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = Record.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2014, 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -11,6 +11,7 @@
|
|
11
11
|
#
|
12
12
|
|
13
13
|
require 'fit4ruby/FitDataRecord'
|
14
|
+
require 'fit4ruby/FDR_DevField_Extension'
|
14
15
|
|
15
16
|
module Fit4Ruby
|
16
17
|
|
@@ -18,13 +19,21 @@ module Fit4Ruby
|
|
18
19
|
# of primary measurements that are associated with a certain timestamp.
|
19
20
|
class Record < FitDataRecord
|
20
21
|
|
22
|
+
include FDR_DevField_Extension
|
23
|
+
|
21
24
|
# Create a new Record object.
|
25
|
+
# @param fit_entity The FitEntity this record belongs to
|
22
26
|
# @param field_values [Hash] Hash that provides initial values for certain
|
23
27
|
# fields.
|
24
|
-
def initialize(field_values = {})
|
28
|
+
def initialize(top_level_record, field_values = {})
|
25
29
|
super('record')
|
30
|
+
@top_level_record = top_level_record
|
26
31
|
@meta_field_units['pace'] = 'min/km'
|
27
32
|
@meta_field_units['run_cadence'] = 'spm'
|
33
|
+
|
34
|
+
# Create instance variables for developer fields
|
35
|
+
create_dev_field_instance_variables
|
36
|
+
|
28
37
|
set_field_values(field_values)
|
29
38
|
end
|
30
39
|
|
data/lib/fit4ruby/version.rb
CHANGED
data/spec/FitFile_spec.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FitFile_spec.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2014, 2015, 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -12,107 +12,251 @@
|
|
12
12
|
|
13
13
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
14
|
|
15
|
+
#require "super_diff/rspec"
|
15
16
|
require 'fit4ruby'
|
16
17
|
|
17
18
|
ENV['TZ'] = 'UTC'
|
18
19
|
|
19
20
|
describe Fit4Ruby do
|
20
|
-
|
21
21
|
before(:each) do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
22
|
+
File.delete(fit_file) if File.exist?(fit_file)
|
23
|
+
expect(File.exist?(fit_file)).to be false
|
24
|
+
end
|
25
|
+
|
26
|
+
after(:each) { File.delete(fit_file) }
|
27
|
+
|
28
|
+
let(:fit_file) { 'test.fit' }
|
29
|
+
# Round the timestamp to seconds. This is what the file format can store. A
|
30
|
+
# higher resolution would create errors during comparions.
|
31
|
+
let(:timestamp) { Time.at(Time.now.to_i) }
|
32
|
+
let(:user_data) do
|
33
|
+
{
|
34
|
+
:age => 33, :height => 1.78, :weight => 73.0,
|
35
|
+
:gender => 'male', :activity_class => 4.0,
|
36
|
+
:max_hr => 178
|
37
|
+
}
|
38
|
+
end
|
39
|
+
let(:user_profile) do
|
40
|
+
{
|
41
|
+
:friendly_name => 'Fast Runner',
|
42
|
+
:gender => 'male',
|
43
|
+
:age => 33,
|
44
|
+
:height => 1.78,
|
45
|
+
:weight => 73.0,
|
46
|
+
:resting_heart_rate => 43
|
47
|
+
}
|
48
|
+
end
|
49
|
+
def device_info_fenix3(ts)
|
50
|
+
{
|
51
|
+
:timestamp => ts,
|
52
|
+
:device_index => 0, :manufacturer => 'garmin',
|
53
|
+
:garmin_product => 'fenix3',
|
54
|
+
:serial_number => 123456789
|
55
|
+
}
|
56
|
+
end
|
57
|
+
def device_info_fenix3_gps(ts)
|
58
|
+
{
|
59
|
+
:timestamp => ts,
|
60
|
+
:device_index => 1, :manufacturer => 'garmin',
|
61
|
+
:garmin_product => 'fenix3_gps'
|
62
|
+
}
|
63
|
+
end
|
64
|
+
def device_info_hrm_run(ts, bs = 'ok')
|
65
|
+
{
|
66
|
+
:timestamp => ts,
|
67
|
+
:device_index => 2, :manufacturer => 'garmin',
|
68
|
+
:garmin_product => 'hrm_run',
|
69
|
+
:battery_status => bs
|
70
|
+
}
|
71
|
+
end
|
72
|
+
def device_info_sdm4(ts)
|
73
|
+
{
|
74
|
+
:timestamp => timestamp,
|
75
|
+
:device_index => 3, :manufacturer => 'garmin',
|
76
|
+
:garmin_product => 'sdm4',
|
77
|
+
:battery_status => 'ok'
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'running activity' do
|
82
|
+
let(:activity) do
|
83
|
+
ts = timestamp
|
84
|
+
a = Fit4Ruby::Activity.new
|
85
|
+
a.total_timer_time = 30 * 60.0
|
86
|
+
a.new_user_data(user_data)
|
87
|
+
a.new_user_profile(user_profile)
|
88
|
+
|
89
|
+
a.new_event({ :event => 'timer', :event_type => 'start_time' })
|
90
|
+
a.new_device_info(device_info_fenix3(ts))
|
91
|
+
a.new_device_info(device_info_fenix3_gps(ts))
|
92
|
+
a.new_device_info(device_info_hrm_run(ts))
|
93
|
+
a.new_device_info(device_info_sdm4(ts))
|
94
|
+
a.new_data_sources({ :timestamp => ts, :distance => 1,
|
95
|
+
:speed => 1, :cadence => 3, :elevation => 1,
|
96
|
+
:heart_rate => 2 })
|
97
|
+
laps = 0
|
98
|
+
0.upto(a.total_timer_time / 60) do |mins|
|
99
|
+
ts += 60
|
100
|
+
a.new_record({
|
101
|
+
:timestamp => ts,
|
102
|
+
:position_lat => 51.5512 - mins * 0.0008,
|
103
|
+
:position_long => 11.647 + mins * 0.002,
|
104
|
+
:distance => 200.0 * mins,
|
105
|
+
:altitude => (100 + mins * 0.5).to_i,
|
106
|
+
:speed => 3.1,
|
107
|
+
:vertical_oscillation => 9 + mins * 0.02,
|
108
|
+
:stance_time => 235.0 * mins * 0.01,
|
109
|
+
:stance_time_percent => 32.0,
|
110
|
+
:heart_rate => 140 + mins,
|
111
|
+
:cadence => 75,
|
112
|
+
:activity_type => 'running',
|
113
|
+
:fractional_cadence => (mins % 2) / 2.0
|
114
|
+
})
|
115
|
+
|
116
|
+
if mins > 0 && mins % 5 == 0
|
117
|
+
a.new_lap({ :timestamp => ts, :sport => 'running',
|
118
|
+
:message_index => laps, :total_cycles => 195 })
|
119
|
+
laps += 1
|
120
|
+
end
|
121
|
+
end
|
122
|
+
a.new_session({ :timestamp => ts, :sport => 'running' })
|
123
|
+
a.new_event({ :timestamp => ts, :event => 'recovery_time',
|
124
|
+
:event_type => 'marker',
|
125
|
+
:recovery_time => 2160 })
|
126
|
+
a.new_event({ :timestamp => ts, :event => 'vo2max',
|
127
|
+
:event_type => 'marker', :vo2max => 52 })
|
128
|
+
a.new_event({ :timestamp => ts, :event => 'timer',
|
129
|
+
:event_type => 'stop_all' })
|
130
|
+
ts += 1
|
131
|
+
a.new_device_info(device_info_fenix3(ts))
|
132
|
+
a.new_device_info(device_info_fenix3_gps(ts))
|
133
|
+
a.new_device_info(device_info_hrm_run(ts, 'low'))
|
134
|
+
a.new_device_info(device_info_sdm4(ts))
|
135
|
+
ts += 120
|
136
|
+
a.new_event({ :timestamp => ts, :event => 'recovery_hr',
|
137
|
+
:event_type => 'marker', :recovery_hr => 132 })
|
138
|
+
|
139
|
+
a.aggregate
|
140
|
+
a
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should write an Activity FIT file and read it back' do
|
144
|
+
Fit4Ruby.write(fit_file, activity)
|
145
|
+
expect(File.exist?(fit_file)).to be true
|
66
146
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
147
|
+
b = Fit4Ruby.read(fit_file)
|
148
|
+
expect(b.laps.count).to eq 6
|
149
|
+
expect(b.lengths.count).to eq 0
|
150
|
+
expect(b.export).to eq(activity.export)
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'swimming activity' do
|
156
|
+
let(:activity) do
|
157
|
+
ts = timestamp
|
158
|
+
laps = 0
|
159
|
+
lengths = 0
|
160
|
+
a = Fit4Ruby::Activity.new
|
161
|
+
|
162
|
+
a.total_timer_time = 30 * 60.0
|
163
|
+
a.new_device_info(device_info_fenix3(ts))
|
164
|
+
|
165
|
+
0.upto(a.total_timer_time / 60) do |mins|
|
166
|
+
ts += 60
|
167
|
+
if mins > 0 && mins % 5 == 0
|
168
|
+
a.new_lap({ :timestamp => ts, :sport => 'swimming',
|
169
|
+
:message_index => laps, :total_cycles => 195 })
|
170
|
+
laps += 1
|
171
|
+
|
172
|
+
a.new_length({ :timestamp => ts, :event => 'length',
|
173
|
+
:message_index => lengths, :total_strokes => 45 })
|
174
|
+
lengths += 1
|
175
|
+
end
|
71
176
|
end
|
177
|
+
a.aggregate
|
178
|
+
a
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should write an Activity FIT file and read it back' do
|
182
|
+
Fit4Ruby.write(fit_file, activity)
|
183
|
+
expect(File.exist?(fit_file)).to be true
|
184
|
+
|
185
|
+
b = Fit4Ruby.read(fit_file)
|
186
|
+
expect(b.laps.count).to eq 6
|
187
|
+
expect(b.lengths.count).to eq 6
|
188
|
+
expect(b.laps.select { |l| l.sport == 'swimming' }.count).to eq 6
|
189
|
+
expect(b.lengths.select { |l| l.total_strokes == 45 }.count).to eq 6
|
190
|
+
expect(b.export).to eq(activity.export)
|
72
191
|
end
|
73
|
-
|
74
|
-
a.new_event({ :timestamp => ts, :event => 'recovery_time',
|
75
|
-
:event_type => 'marker',
|
76
|
-
:recovery_time => 2160 })
|
77
|
-
a.new_event({ :timestamp => ts, :event => 'vo2max',
|
78
|
-
:event_type => 'marker', :vo2max => 52 })
|
79
|
-
a.new_event({ :timestamp => ts, :event => 'timer',
|
80
|
-
:event_type => 'stop_all' })
|
81
|
-
ts += 1
|
82
|
-
a.new_device_info({ :timestamp => ts,
|
83
|
-
:device_index => 0, :manufacturer => 'garmin',
|
84
|
-
:garmin_product => 'fenix3',
|
85
|
-
:serial_number => 123456789 })
|
86
|
-
a.new_device_info({ :timestamp => ts,
|
87
|
-
:device_index => 1, :manufacturer => 'garmin',
|
88
|
-
:garmin_product => 'fenix3_gps'})
|
89
|
-
a.new_device_info({ :timestamp => ts,
|
90
|
-
:device_index => 2, :manufacturer => 'garmin',
|
91
|
-
:garmin_product => 'hrm_run',
|
92
|
-
:battery_status => 'low' })
|
93
|
-
a.new_device_info({ :timestamp => ts,
|
94
|
-
:device_index => 3, :manufacturer => 'garmin',
|
95
|
-
:garmin_product => 'sdm4',
|
96
|
-
:battery_status => 'ok' })
|
97
|
-
ts += 120
|
98
|
-
a.new_event({ :timestamp => ts, :event => 'recovery_hr',
|
99
|
-
:event_type => 'marker', :recovery_hr => 132 })
|
100
|
-
|
101
|
-
a.aggregate
|
102
|
-
|
103
|
-
@activity = a
|
192
|
+
|
104
193
|
end
|
105
194
|
|
106
|
-
|
107
|
-
|
195
|
+
context 'activity with developer fields' do
|
196
|
+
let(:activity) do
|
197
|
+
ts = timestamp
|
198
|
+
laps = 0
|
199
|
+
lengths = 0
|
200
|
+
a = Fit4Ruby::Activity.new
|
108
201
|
|
109
|
-
|
110
|
-
|
111
|
-
|
202
|
+
a.total_timer_time = 30 * 60.0
|
203
|
+
a.new_device_info(device_info_fenix3(ts))
|
204
|
+
a.new_developer_data_id({
|
205
|
+
application_id: [ 24, 251, 44, 240, 26, 75, 67, 13,
|
206
|
+
173, 102, 152, 140, 132, 116, 33, 244 ],
|
207
|
+
application_version: 77
|
208
|
+
})
|
209
|
+
a.new_field_description({
|
210
|
+
developer_data_index: 0,
|
211
|
+
field_definition_number: 0,
|
212
|
+
fit_base_type_id: 132,
|
213
|
+
field_name: 'Power',
|
214
|
+
units: 'Watts',
|
215
|
+
native_mesg_num: 20,
|
216
|
+
native_field_num: 7
|
217
|
+
})
|
218
|
+
a.new_data_sources({ :timestamp => ts, :distance => 1,
|
219
|
+
:speed => 1, :cadence => 3, :elevation => 1,
|
220
|
+
:heart_rate => 2 })
|
221
|
+
laps = 0
|
222
|
+
0.upto(a.total_timer_time / 60) do |mins|
|
223
|
+
ts += 60
|
224
|
+
a.new_record({
|
225
|
+
:timestamp => ts,
|
226
|
+
:position_lat => 51.5512 - mins * 0.0008,
|
227
|
+
:position_long => 11.647 + mins * 0.002,
|
228
|
+
:distance => 200.0 * mins,
|
229
|
+
:altitude => (100 + mins * 0.5).to_i,
|
230
|
+
:speed => 3.1,
|
231
|
+
:vertical_oscillation => 9 + mins * 0.02,
|
232
|
+
:stance_time => 235.0 * mins * 0.01,
|
233
|
+
:stance_time_percent => 32.0,
|
234
|
+
:heart_rate => 140 + mins,
|
235
|
+
:cadence => 75,
|
236
|
+
:activity_type => 'running',
|
237
|
+
:fractional_cadence => (mins % 2) / 2.0,
|
238
|
+
:Power_18FB2CF01A4B430DAD66988C847421F4 => 240
|
239
|
+
})
|
112
240
|
|
113
|
-
|
114
|
-
|
115
|
-
|
241
|
+
if mins > 0 && mins % 5 == 0
|
242
|
+
a.new_lap({ :timestamp => ts, :sport => 'running',
|
243
|
+
:message_index => laps, :total_cycles => 195 })
|
244
|
+
laps += 1
|
245
|
+
end
|
246
|
+
end
|
247
|
+
a.aggregate
|
248
|
+
a
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should write an Activity FIT file and read it back' do
|
252
|
+
Fit4Ruby.write(fit_file, activity)
|
253
|
+
expect(File.exist?(fit_file)).to be true
|
254
|
+
|
255
|
+
# This currently does not work as the saving of developer fields is not
|
256
|
+
# yet implemented.
|
257
|
+
#b = Fit4Ruby.read(fit_file)
|
258
|
+
#expect(b.export).to eq(activity.export)
|
259
|
+
end
|
116
260
|
end
|
117
261
|
|
118
262
|
end
|