Class: PostRunner::Activity
- Inherits:
-
Object
- Object
- PostRunner::Activity
- Defined in:
- lib/postrunner/Activity.rb
Constant Summary collapse
- ActivityTypes =
{ 'generic' => 'Generic', 'running' => 'Running', 'cycling' => 'Cycling', 'transition' => 'Transition', 'fitness_equipment' => 'Fitness Equipment', 'swimming' => 'Swimming', 'basketball' => 'Basketball', 'soccer' => 'Soccer', 'tennis' => 'Tennis', 'american_football' => 'American Football', 'walking' => 'Walking', 'cross_country_skiing' => 'Cross Country Skiing', 'alpine_skiing' => 'Alpine Skiing', 'snowboarding' => 'Snowboarding', 'rowing' => 'Rowing', 'mountaineering' => 'Mountaneering', 'hiking' => 'Hiking', 'multisport' => 'Multisport', 'paddling' => 'Paddling', 'all' => 'All' }
- ActivitySubTypes =
{ 'generic' => 'Generic', 'treadmill' => 'Treadmill', 'street' => 'Street', 'trail' => 'Trail', 'track' => 'Track', 'spin' => 'Spin', 'indoor_cycling' => 'Indoor Cycling', 'road' => 'Road', 'mountain' => 'Mountain', 'downhill' => 'Downhill', 'recumbent' => 'Recumbent', 'cyclocross' => 'Cyclocross', 'hand_cycling' => 'Hand Cycling', 'track_cycling' => 'Track Cycling', 'indoor_rowing' => 'Indoor Rowing', 'elliptical' => 'Elliptical', 'stair_climbing' => 'Stair Climbing', 'lap_swimming' => 'Lap Swimming', 'open_water' => 'Open Water', 'flexibility_training' => 'Flexibility Training', 'strength_training' => 'Strength Training', 'warm_up' => 'Warm up', 'match' => 'Match', 'exercise' => 'Excersize', 'challenge' => 'Challenge', 'indoor_skiing' => 'Indoor Skiing', 'cardio_training' => 'Cardio Training', 'all' => 'All' }
- @@CachedActivityValues =
This is a list of variables that provide data from the fit file. To speed up access to it, we cache the data in the activity database.
%w( sport sub_sport timestamp total_distance total_timer_time avg_speed )
- @@CachedAttributes =
We also store some additional information in the archive index.
@@CachedActivityValues + %w( fit_file name norecord )
- @@Schemata =
{ 'long_date' => Schema.new('long_date', 'Date', { :func => 'timestamp', :column_alignment => :left, :format => 'date_with_weekday' }), 'sub_type' => Schema.new('sub_type', 'Subtype', { :func => 'activity_sub_type', :column_alignment => :left }), 'type' => Schema.new('type', 'Type', { :func => 'activity_type', :column_alignment => :left }) }
Instance Attribute Summary collapse
-
#db ⇒ Object
readonly
Returns the value of attribute db.
-
#fit_activity ⇒ Object
readonly
Returns the value of attribute fit_activity.
-
#fit_file ⇒ Object
readonly
Returns the value of attribute fit_file.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Instance Method Summary collapse
- #activity_sub_type ⇒ Object
- #activity_type ⇒ Object
- #check ⇒ Object
- #distance(timestamp, unit_system) ⇒ Object
- #dump(filter) ⇒ Object
-
#encode_with(coder) ⇒ Object
This method is called during Activity::to_yaml() calls.
- #events ⇒ Object
- #generate_html_view ⇒ Object
-
#has_records? ⇒ Boolean
Return true if this activity generated any personal records.
-
#init_with(coder) ⇒ Object
This method is called during YAML::load() to initialize the class objects.
-
#initialize(db, fit_file, fit_activity, name = nil) ⇒ Activity
constructor
A new instance of Activity.
-
#late_init(db) ⇒ Object
YAML::load() does not call initialize().
- #query(key) ⇒ Object
- #register_records ⇒ Object
- #rename(name) ⇒ Object
- #set(attribute, value) ⇒ Object
- #show ⇒ Object
- #sources ⇒ Object
- #summary ⇒ Object
Constructor Details
#initialize(db, fit_file, fit_activity, name = nil) ⇒ Activity
Returns a new instance of Activity.
101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/postrunner/Activity.rb', line 101 def initialize(db, fit_file, fit_activity, name = nil) @fit_file = fit_file @fit_activity = fit_activity @name = name || fit_file @unset_variables = [] late_init(db) @@CachedActivityValues.each do |v| v_str = "@#{v}" instance_variable_set(v_str, fit_activity.send(v)) self.class.send(:attr_reader, v.to_sym) end end |
Instance Attribute Details
#db ⇒ Object (readonly)
Returns the value of attribute db.
26 27 28 |
# File 'lib/postrunner/Activity.rb', line 26 def db @db end |
#fit_activity ⇒ Object (readonly)
Returns the value of attribute fit_activity.
26 27 28 |
# File 'lib/postrunner/Activity.rb', line 26 def fit_activity @fit_activity end |
#fit_file ⇒ Object (readonly)
Returns the value of attribute fit_file.
26 27 28 |
# File 'lib/postrunner/Activity.rb', line 26 def fit_file @fit_file end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
26 27 28 |
# File 'lib/postrunner/Activity.rb', line 26 def name @name end |
Instance Method Details
#activity_sub_type ⇒ Object
381 382 383 |
# File 'lib/postrunner/Activity.rb', line 381 def activity_sub_type ActivitySubTypes[@sub_sport] || 'Undefined' end |
#activity_type ⇒ Object
377 378 379 |
# File 'lib/postrunner/Activity.rb', line 377 def activity_type ActivityTypes[@sport] || 'Undefined' end |
#check ⇒ Object
132 133 134 135 136 |
# File 'lib/postrunner/Activity.rb', line 132 def check generate_html_view register_records Log.info "FIT file #{@fit_file} is OK" end |
#distance(timestamp, unit_system) ⇒ Object
385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/postrunner/Activity.rb', line 385 def distance(, unit_system) @fit_activity = load_fit_file unless @fit_activity @fit_activity.records.each do |record| if record. >= unit = { :metric => 'km', :statute => 'mi'}[unit_system] value = record.get_as('distance', unit) return '-' unless value return "#{'%.2f %s' % [value, unit]}" end end '-' end |
#dump(filter) ⇒ Object
138 139 140 |
# File 'lib/postrunner/Activity.rb', line 138 def dump(filter) @fit_activity = load_fit_file(filter) end |
#encode_with(coder) ⇒ Object
This method is called during Activity::to_yaml() calls. It’s being used to prevent some instance variables from being saved in the YAML file. Only attributes that are listed in @@CachedAttributes are being saved.
171 172 173 174 175 176 177 178 179 |
# File 'lib/postrunner/Activity.rb', line 171 def encode_with(coder) instance_variables.each do |a| name_with_at = a.to_s name_without_at = name_with_at[1..-1] next unless @@CachedAttributes.include?(name_without_at) coder[name_without_at] = instance_variable_get(name_with_at) end end |
#events ⇒ Object
200 201 202 203 |
# File 'lib/postrunner/Activity.rb', line 200 def events @fit_activity = load_fit_file unless @fit_activity puts EventList.new(self, @db.cfg[:unit_system]).to_s end |
#generate_html_view ⇒ Object
372 373 374 375 |
# File 'lib/postrunner/Activity.rb', line 372 def generate_html_view @fit_activity = load_fit_file unless @fit_activity ActivityView.new(self, @db.cfg[:unit_system]) end |
#has_records? ⇒ Boolean
Return true if this activity generated any personal records.
368 369 370 |
# File 'lib/postrunner/Activity.rb', line 368 def has_records? !@db.records.activity_records(self).empty? end |
#init_with(coder) ⇒ Object
This method is called during YAML::load() to initialize the class objects. The initialize() is NOT called during YAML::load(). Any additional initialization work is done in late_init().
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/postrunner/Activity.rb', line 145 def init_with(coder) @unset_variables = [] @@CachedAttributes.each do |name_without_at| # Create attr_readers for cached variables. self.class.send(:attr_reader, name_without_at.to_sym) if coder.map.include?(name_without_at) # The YAML file has a value for the instance variable. So just set # it. instance_variable_set('@' + name_without_at, coder[name_without_at]) else if @@CachedActivityValues.include?(name_without_at) @unset_variables << name_without_at elsif name_without_at == 'norecord' @norecord = false else Log.fatal "Don't know how to initialize the instance variable " + "#{name_without_at}." end end end end |
#late_init(db) ⇒ Object
YAML::load() does not call initialize(). We don’t have all attributes stored in the YAML file, so we need to make sure these are properly set after a YAML::load().
118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/postrunner/Activity.rb', line 118 def late_init(db) @db = db @html_file = File.join(@db.cfg[:html_dir], "#{@fit_file[0..-5]}.html") @unset_variables.each do |name_without_at| # The YAML file does not yet have the instance variable cached. # Load the Activity data and extract the value to set the instance # variable. @fit_activity = load_fit_file unless @fit_activity instance_variable_set('@' + name_without_at, @fit_activity.send(name_without_at)) end end |
#query(key) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/postrunner/Activity.rb', line 181 def query(key) unless @@Schemata.include?(key) raise ArgumentError, "Unknown key '#{key}' requested in query" end schema = @@Schemata[key] if schema.func value = send(schema.func) else unless instance_variable_defined?(key) raise ArgumentError, "Don't know how to query '#{key}'" end value = instance_variable_get(key) end QueryResult.new(value, schema) end |
#register_records ⇒ Object
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/postrunner/Activity.rb', line 262 def register_records # If we have the @norecord flag set, we ignore this Activity for the # record collection. return if @norecord distance_record = 0.0 distance_record_sport = nil # Array with popular distances (in meters) in ascending order. record_distances = nil # Speed records for popular distances (seconds hashed by distance in # meters) speed_records = {} segment_start_time = @fit_activity.sessions[0].start_time segment_start_distance = 0.0 sport = nil = nil last_distance = nil @fit_activity.records.each do |record| if record..nil? # All records must have a valid timestamp Log.warn "Found a record without a valid timestamp" return end if record.distance.nil? # All records must have a valid distance mark or the activity does # not qualify for a personal record. Log.warn "Found a record at #{record.} without a " + "valid distance" return end unless sport # If the Activity has sport set to 'multisport' or 'all' we pick up # the sport from the FIT records. Otherwise, we just use whatever # sport the Activity provides. if @sport == 'multisport' || @sport == 'all' sport = record.activity_type else sport = @sport end return unless PersonalRecords::SpeedRecordDistances.include?(sport) record_distances = PersonalRecords::SpeedRecordDistances[sport]. keys.sort end segment_start_distance = record.distance unless segment_start_distance segment_start_time = record. unless segment_start_time # Total distance covered in this segment so far segment_distance = record.distance - segment_start_distance # Check if we have reached the next popular distance. if record_distances.first && segment_distance >= record_distances.first segment_duration = record. - segment_start_time # The distance may be somewhat larger than a popular distance. We # normalize the time to the norm distance. norm_duration = segment_duration / segment_distance * record_distances.first # Save the time for this distance. speed_records[record_distances.first] = { :time => norm_duration, :sport => sport } # Switch to the next popular distance. record_distances.shift end # We've reached the end of a segment if the sport type changes, we # detect a pause of more than 30 seconds or when we've reached the # last record. if (record.activity_type && sport && record.activity_type != sport) || ( && (record. - ) > 30) || record.equal?(@fit_activity.records.last) # Check for a total distance record if segment_distance > distance_record distance_record = segment_distance distance_record_sport = sport end # Prepare for the next segment in this Activity segment_start_distance = nil segment_start_time = nil sport = nil end = record. last_distance = record.distance end # Store the found records start_time = @fit_activity.sessions[0]. if distance_record_sport @db.records.register_result(self, distance_record_sport, distance_record, nil, start_time) end speed_records.each do |dist, info| @db.records.register_result(self, info[:sport], dist, info[:time], start_time) end end |
#rename(name) ⇒ Object
224 225 226 227 |
# File 'lib/postrunner/Activity.rb', line 224 def rename(name) @name = name generate_html_view end |
#set(attribute, value) ⇒ Object
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/postrunner/Activity.rb', line 229 def set(attribute, value) case attribute when 'name' @name = value when 'type' @fit_activity = load_fit_file unless @fit_activity unless ActivityTypes.values.include?(value) Log.fatal "Unknown activity type '#{value}'. Must be one of " + ActivityTypes.values.join(', ') end @sport = ActivityTypes.invert[value] # Since the activity changes the records from this Activity need to be # removed and added again. @db.records.delete_activity(self) register_records when 'subtype' unless ActivitySubTypes.values.include?(value) Log.fatal "Unknown activity subtype '#{value}'. Must be one of " + ActivitySubTypes.values.join(', ') end @sub_sport = ActivitySubTypes.invert[value] when 'norecord' unless %w( true false).include?(value) Log.fatal "norecord must either be 'true' or 'false'" end @norecord = value == 'true' else Log.fatal "Unknown activity attribute '#{attribute}'. Must be one of " + 'name, type or subtype' end generate_html_view end |
#show ⇒ Object
205 206 207 208 209 |
# File 'lib/postrunner/Activity.rb', line 205 def show generate_html_view #unless File.exists?(@html_file) @db.show_in_browser(@html_file) end |
#sources ⇒ Object
211 212 213 214 |
# File 'lib/postrunner/Activity.rb', line 211 def sources @fit_activity = load_fit_file unless @fit_activity puts DataSources.new(self, @db.cfg[:unit_system]).to_s end |
#summary ⇒ Object
216 217 218 219 220 221 222 |
# File 'lib/postrunner/Activity.rb', line 216 def summary @fit_activity = load_fit_file unless @fit_activity puts ActivitySummary.new(self, @db.cfg[:unit_system], { :name => @name, :type => activity_type, :sub_type => activity_sub_type }).to_s end |