tcx 0.1.0 → 0.2.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 +4 -4
 - data/CHANGELOG.md +6 -2
 - data/README.md +30 -5
 - data/lib/tcx/extensions/activity_extension/v2/activity_lap.rb +21 -0
 - data/lib/tcx/extensions/activity_extension/v2/activity_trackpoint.rb +22 -0
 - data/lib/tcx/extensions/activity_extension/v2/base.rb +16 -0
 - data/lib/tcx/extensions/activity_extension/v2/cadence_sensor_type.rb +16 -0
 - data/lib/tcx/extensions/activity_extension/v2.rb +6 -0
 - data/lib/tcx/extensions.rb +3 -0
 - data/lib/tcx/file.rb +30 -0
 - data/lib/tcx/types/abstract_source.rb +7 -0
 - data/lib/tcx/{models → types}/activity.rb +4 -0
 - data/lib/tcx/types/activity_list.rb +21 -0
 - data/lib/tcx/types/application.rb +13 -0
 - data/lib/tcx/types/base.rb +111 -0
 - data/lib/tcx/types/build.rb +10 -0
 - data/lib/tcx/types/build_type.rb +12 -0
 - data/lib/tcx/types/cadence.rb +9 -0
 - data/lib/tcx/types/course_list.rb +21 -0
 - data/lib/tcx/{models → types}/database.rb +22 -0
 - data/lib/tcx/{models/abstract_source.rb → types/device.rb} +5 -2
 - data/lib/tcx/types/duration.rb +10 -0
 - data/lib/tcx/types/extensions_list.rb +9 -0
 - data/lib/tcx/types/heart_rate_as_percent_of_max.rb +9 -0
 - data/lib/tcx/types/heart_rate_bpm.rb +9 -0
 - data/lib/tcx/types/heart_rate_in_beats_per_minute.rb +9 -0
 - data/lib/tcx/{models → types}/lap.rb +5 -1
 - data/lib/tcx/{models → types}/trackpoint.rb +1 -1
 - data/lib/tcx/types/workout_list.rb +21 -0
 - data/lib/tcx/types.rb +43 -0
 - data/lib/tcx/version.rb +1 -1
 - data/lib/tcx.rb +9 -4
 - metadata +51 -41
 - data/lib/tcx/models/activity_list.rb +0 -9
 - data/lib/tcx/models/base.rb +0 -30
 - data/lib/tcx/models/cadence.rb +0 -9
 - data/lib/tcx/models/course_list.rb +0 -9
 - data/lib/tcx/models/duration.rb +0 -6
 - data/lib/tcx/models/extensions.rb +0 -6
 - data/lib/tcx/models/heart_rate_as_percent_of_max.rb +0 -9
 - data/lib/tcx/models/heart_rate_bpm.rb +0 -9
 - data/lib/tcx/models/heart_rate_in_beats_per_minute.rb +0 -9
 - data/lib/tcx/models/value.rb +0 -9
 - data/lib/tcx/models/workout_list.rb +0 -9
 - data/lib/tcx/models.rb +0 -40
 - /data/lib/tcx/{models → types}/course.rb +0 -0
 - /data/lib/tcx/{models → types}/course_folder.rb +0 -0
 - /data/lib/tcx/{models → types}/course_lap.rb +0 -0
 - /data/lib/tcx/{models → types}/course_point.rb +0 -0
 - /data/lib/tcx/{models → types}/course_point_type.rb +0 -0
 - /data/lib/tcx/{models → types}/courses.rb +0 -0
 - /data/lib/tcx/{models → types}/custom_heart_rate_zone.rb +0 -0
 - /data/lib/tcx/{models → types}/folders.rb +0 -0
 - /data/lib/tcx/{models → types}/gender.rb +0 -0
 - /data/lib/tcx/{models → types}/heart_rate_value.rb +0 -0
 - /data/lib/tcx/{models → types}/intensity.rb +0 -0
 - /data/lib/tcx/{models → types}/name_key_reference.rb +0 -0
 - /data/lib/tcx/{models → types}/position.rb +0 -0
 - /data/lib/tcx/{models → types}/predefined_heart_rate_zone.rb +0 -0
 - /data/lib/tcx/{models → types}/sensor_state.rb +0 -0
 - /data/lib/tcx/{models → types}/sport.rb +0 -0
 - /data/lib/tcx/{models → types}/step.rb +0 -0
 - /data/lib/tcx/{models → types}/target.rb +0 -0
 - /data/lib/tcx/{models → types}/track.rb +0 -0
 - /data/lib/tcx/{models → types}/trigger_method.rb +0 -0
 - /data/lib/tcx/{models → types}/version.rb +0 -0
 - /data/lib/tcx/{models → types}/workout.rb +0 -0
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 16a519fa1d9c70b3f319428170d9e52f36a1eaa4baacdd4004d336e35c57d2c6
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 57571958ee9e4182e5c271ebec43639c78b46253e837caf0eb1bbd55b553398c
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 5e1339b4ef3c6817baf72d973d1b00c92b1ad109927a7012892758d27e3140b863786a431ee25b8176130801549edbad992939c3db4dfa853763802d60d36630
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 631de4c6b5e4dabe0c3db3b87255583d4dd30e05cb58425e4e10aa407b2b43136c82c2f3e840cd428d5c16e86b10f89cf25655d13e371b3e8bcdee2ab9357500
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,3 +1,7 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            ### 0. 
     | 
| 
      
 1 
     | 
    
         
            +
            ### 0.2.0 (2025-10-24)
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            *  
     | 
| 
      
 3 
     | 
    
         
            +
            * Added support for writing TCX files - [@dblock](https://github.com/dblock).
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ### 0.1.0 (2025-10-23)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            * Initial public release, generic TCX reader - [@dblock](https://github.com/dblock).
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -3,7 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            [](https://badge.fury.io/rb/tcx)
         
     | 
| 
       4 
4 
     | 
    
         
             
            [](https://github.com/dblock/tcx/actions/workflows/test.yml)
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            A Garmin Training Center XML (TCX) reader  
     | 
| 
      
 6 
     | 
    
         
            +
            A Garmin Training Center XML (TCX) reader and writer. Unlike other libraries such as [tcx_rb](https://github.com/keithdoggett/tcx_rb) or [tcxread](https://github.com/firefly-cpp/tcxread), provides a consistent API by implementing the complete read/write [TCX schema](https://www8.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd) with extensions in a structured and organized way.
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            ## Installation
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
         @@ -17,16 +17,41 @@ Run `bundle install`. 
     | 
|
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
            ## Usage
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
      
 20 
     | 
    
         
            +
            ### Working with Files
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            Read and write TCX files using `Tcx#load_file` and `dump`. 
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
       20 
24 
     | 
    
         
             
            ```ruby
         
     | 
| 
       21 
25 
     | 
    
         
             
            require 'tcx'
         
     | 
| 
       22 
26 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
            tcx = Tcx.load_file(' 
     | 
| 
      
 27 
     | 
    
         
            +
            tcx = Tcx.load_file('activities.tcx') # => Tcx::Database
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            tcx.activities # => [Tcx::Activity], array of Tcx::Activity
         
     | 
| 
      
 30 
     | 
    
         
            +
            tcx.workouts # => [Tcx::Workout]
         
     | 
| 
      
 31 
     | 
    
         
            +
            tcx.courses # => [Tcx::Course]
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            tcx.dump # overwrites activities.tcx
         
     | 
| 
       24 
34 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
            tcx. 
     | 
| 
       26 
     | 
    
         
            -
            ...
         
     | 
| 
      
 35 
     | 
    
         
            +
            tcx.dump('activities2.tcx') # writes to activities2.tcx
         
     | 
| 
       27 
36 
     | 
    
         
             
            ```
         
     | 
| 
       28 
37 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 38 
     | 
    
         
            +
            ### Working with XML Data
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            Directly manipulate TCX data without creating files.
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 43 
     | 
    
         
            +
            data = File.read('activities.tcx') # String
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            tcx = Tcx.load(data) # => Tcx::Database
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            tcx.to_xml # => XML string
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            tcx.dump('activities2.tcx') # writes to activities2.tcx
         
     | 
| 
      
 50 
     | 
    
         
            +
            ```
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            ### Examples
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            See [examples/multiple_running_activities.rb](examples/multiple_running_activities.rb) for a complete working example.
         
     | 
| 
       30 
55 
     | 
    
         | 
| 
       31 
56 
     | 
    
         
             
            ## Upgrading
         
     | 
| 
       32 
57 
     | 
    
         | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Extensions
         
     | 
| 
      
 5 
     | 
    
         
            +
                module ActivityExtension
         
     | 
| 
      
 6 
     | 
    
         
            +
                  module V2
         
     | 
| 
      
 7 
     | 
    
         
            +
                    # LX
         
     | 
| 
      
 8 
     | 
    
         
            +
                    class ActivityLap < Base
         
     | 
| 
      
 9 
     | 
    
         
            +
                      property 'avg_speed', from: 'AvgSpeed', transform_with: lambda(&:to_f)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      property 'max_bike_cadence', from: 'MaxBikeCadence', transform_with: lambda(&:to_i)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      property 'avg_run_cadence', from: 'AvgRunCadence', transform_with: lambda(&:to_i)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      property 'max_run_cadence', from: 'MaxRunCadence', transform_with: lambda(&:to_i)
         
     | 
| 
      
 13 
     | 
    
         
            +
                      property 'steps', from: 'Steps', transform_with: lambda(&:to_i)
         
     | 
| 
      
 14 
     | 
    
         
            +
                      property 'avg_watts', from: 'AvgWatts', transform_with: lambda(&:to_i)
         
     | 
| 
      
 15 
     | 
    
         
            +
                      property 'max_watts', from: 'MaxWatts', transform_with: lambda(&:to_i)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      property 'extensions', from: 'Extensions', transform_with: ->(v) { ExtensionsList.parse(v) }
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Extensions
         
     | 
| 
      
 5 
     | 
    
         
            +
                module ActivityExtension
         
     | 
| 
      
 6 
     | 
    
         
            +
                  module V2
         
     | 
| 
      
 7 
     | 
    
         
            +
                    # TPX
         
     | 
| 
      
 8 
     | 
    
         
            +
                    class ActivityTrackpoint < Base
         
     | 
| 
      
 9 
     | 
    
         
            +
                      property 'speed', from: 'Speed', transform_with: lambda(&:to_f)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      property 'run_cadence', from: 'RunCadence', transform_with: lambda(&:to_i)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      property 'watts', from: 'Watts', transform_with: lambda(&:to_i)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      property 'extensions', from: 'Extensions', transform_with: ->(v) { ExtensionsList.parse(v) }
         
     | 
| 
      
 13 
     | 
    
         
            +
                      property 'cadence_sensor', from: 'CadenceSensor', transform_with: ->(v) { CadenceSensorType.parse(v) }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                      def self.attributes
         
     | 
| 
      
 16 
     | 
    
         
            +
                        ['cadence_sensor']
         
     | 
| 
      
 17 
     | 
    
         
            +
                      end
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Extensions
         
     | 
| 
      
 5 
     | 
    
         
            +
                module ActivityExtension
         
     | 
| 
      
 6 
     | 
    
         
            +
                  module V2
         
     | 
| 
      
 7 
     | 
    
         
            +
                    # LX
         
     | 
| 
      
 8 
     | 
    
         
            +
                    class Base < Tcx::Base
         
     | 
| 
      
 9 
     | 
    
         
            +
                      def self.namespace
         
     | 
| 
      
 10 
     | 
    
         
            +
                        'http://www.garmin.com/xmlschemas/ActivityExtension/v2'
         
     | 
| 
      
 11 
     | 
    
         
            +
                      end
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tcx/file.rb
    ADDED
    
    | 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class File
         
     | 
| 
      
 5 
     | 
    
         
            +
                extend Forwardable
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :file_path
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def_delegators :database, :folders, :activities, :workouts, :courses, :author, :to_xml
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def initialize(file_path = nil)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @file_path = file_path
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def database
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @database ||= if file_path
         
     | 
| 
      
 17 
     | 
    
         
            +
                                  ::File.open(file_path) do |file|
         
     | 
| 
      
 18 
     | 
    
         
            +
                                    xml = Nokogiri::XML(file)
         
     | 
| 
      
 19 
     | 
    
         
            +
                                    Tcx::Database.parse(xml.root)
         
     | 
| 
      
 20 
     | 
    
         
            +
                                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                                else
         
     | 
| 
      
 22 
     | 
    
         
            +
                                  Tcx::Database.new
         
     | 
| 
      
 23 
     | 
    
         
            +
                                end
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def dump(target_path = nil)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  database.dump(target_path)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -7,5 +7,9 @@ module Tcx 
     | 
|
| 
       7 
7 
     | 
    
         
             
                property 'laps', from: 'Lap', transform_with: ->(v) { to_array(v).map { |el| Lap.parse(el) } }
         
     | 
| 
       8 
8 
     | 
    
         
             
                property 'notes', from: 'Notes'
         
     | 
| 
       9 
9 
     | 
    
         
             
                property 'creator', from: 'Creator', transform_with: ->(v) { AbstractSource.parse(v) }
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def self.attributes
         
     | 
| 
      
 12 
     | 
    
         
            +
                  ['sport']
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
       10 
14 
     | 
    
         
             
              end
         
     | 
| 
       11 
15 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class ActivityList < Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                property 'activities', from: 'Activities', transform_with: ->(v) { v.map { |el| Activity.parse(el) } }
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def_delegators :activities, :each, :count
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def self.parse(list)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  ActivityList.new('Activities' => list.xpath('xmlns:Activity'))
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def build_xml(builder)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  activities.each do |activity|
         
     | 
| 
      
 15 
     | 
    
         
            +
                    builder.Activity(activity.attributes) do |activity_builder|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      activity.build_xml(activity_builder)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Application < AbstractSource
         
     | 
| 
      
 5 
     | 
    
         
            +
                property 'build', from: 'Build', transform_with: ->(v) { Build.parse(v) }
         
     | 
| 
      
 6 
     | 
    
         
            +
                property 'lang_id', from: 'LangID'
         
     | 
| 
      
 7 
     | 
    
         
            +
                property 'part_number', from: 'PartNumber'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def attributes
         
     | 
| 
      
 10 
     | 
    
         
            +
                  super.merge('xsi:type' => 'Application_t')
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,111 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Base < Hashie::Trash
         
     | 
| 
      
 5 
     | 
    
         
            +
                include Hashie::Extensions::IgnoreUndeclared
         
     | 
| 
      
 6 
     | 
    
         
            +
                extend Forwardable
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def self.parse(xml)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  if (tt = xml['xsi:type'])
         
     | 
| 
      
 10 
     | 
    
         
            +
                    klass = Tcx.const_get(tt.gsub(/_t$/, ''))
         
     | 
| 
      
 11 
     | 
    
         
            +
                    return klass.parse(xml) if self != klass
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  attributes = xml.attributes.to_h
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  xml.children.each do |child|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    next unless child.is_a?(Nokogiri::XML::Element)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    attributes[child.name] = if attributes.key?(child.name)
         
     | 
| 
      
 20 
     | 
    
         
            +
                                               to_array(attributes[child.name]) + [child]
         
     | 
| 
      
 21 
     | 
    
         
            +
                                             elsif child.children.one? && child.children.first.is_a?(Nokogiri::XML::Text)
         
     | 
| 
      
 22 
     | 
    
         
            +
                                               child.text
         
     | 
| 
      
 23 
     | 
    
         
            +
                                             else
         
     | 
| 
      
 24 
     | 
    
         
            +
                                               child
         
     | 
| 
      
 25 
     | 
    
         
            +
                                             end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  new attributes
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                # Transform an XmlElement into [XmlElement], cannot be used with Array or causes a coercion error
         
     | 
| 
      
 32 
     | 
    
         
            +
                def self.to_array(value)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  value.is_a?(Array) ? value : [value]
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def self.attributes
         
     | 
| 
      
 37 
     | 
    
         
            +
                  []
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def self.namespace
         
     | 
| 
      
 41 
     | 
    
         
            +
                  'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2'
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def self.namespace_definitions
         
     | 
| 
      
 45 
     | 
    
         
            +
                  {
         
     | 
| 
      
 46 
     | 
    
         
            +
                    'xsi:schemaLocation' => 'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd',
         
     | 
| 
      
 47 
     | 
    
         
            +
                    'xmlns' => 'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2',
         
     | 
| 
      
 48 
     | 
    
         
            +
                    'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
         
     | 
| 
      
 49 
     | 
    
         
            +
                    'xmlns:ns2' => 'http://www.garmin.com/xmlschemas/UserProfile/v2',
         
     | 
| 
      
 50 
     | 
    
         
            +
                    'xmlns:ns3' => 'http://www.garmin.com/xmlschemas/ActivityExtension/v2',
         
     | 
| 
      
 51 
     | 
    
         
            +
                    'xmlns:ns4' => 'http://www.garmin.com/xmlschemas/ProfileExtension/v1',
         
     | 
| 
      
 52 
     | 
    
         
            +
                    'xmlns:ns5' => 'http://www.garmin.com/xmlschemas/ActivityGoals/v1'
         
     | 
| 
      
 53 
     | 
    
         
            +
                  }
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def self.xmlns
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @xmlns ||= namespace_definitions.invert
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def attributes
         
     | 
| 
      
 61 
     | 
    
         
            +
                  attribute_values = {}
         
     | 
| 
      
 62 
     | 
    
         
            +
                  self.class.attributes.each do |attribute|
         
     | 
| 
      
 63 
     | 
    
         
            +
                    value = self[attribute]
         
     | 
| 
      
 64 
     | 
    
         
            +
                    next unless value
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    property_name = self.class.inverse_translations.fetch(attribute, attribute)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    attribute_values[property_name] = build_value(value)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                  attribute_values
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                def build_xml(builder)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  (self.class.properties - self.class.attributes).each do |property|
         
     | 
| 
      
 74 
     | 
    
         
            +
                    value = self[property]
         
     | 
| 
      
 75 
     | 
    
         
            +
                    next unless value
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    property_name = self.class.inverse_translations.fetch(property, property)
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    if value.is_a?(Base)
         
     | 
| 
      
 80 
     | 
    
         
            +
                      build_el(builder, property_name, value)
         
     | 
| 
      
 81 
     | 
    
         
            +
                    elsif value.is_a?(Array)
         
     | 
| 
      
 82 
     | 
    
         
            +
                      value.each do |el|
         
     | 
| 
      
 83 
     | 
    
         
            +
                        build_el(builder, property_name, el)
         
     | 
| 
      
 84 
     | 
    
         
            +
                      end
         
     | 
| 
      
 85 
     | 
    
         
            +
                    else
         
     | 
| 
      
 86 
     | 
    
         
            +
                      builder.send(property_name, build_value(value))
         
     | 
| 
      
 87 
     | 
    
         
            +
                    end
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                def build_el(builder, property_name, el)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  attributes = el.attributes if el.is_a?(Base)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  namespace = Base.xmlns[el.class.namespace]&.split(':')&.[](1) if el.is_a?(Base)
         
     | 
| 
      
 94 
     | 
    
         
            +
                  builder = builder[namespace] if namespace
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  builder.send(property_name, attributes) do |property_builder|
         
     | 
| 
      
 97 
     | 
    
         
            +
                    property_builder = property_builder[namespace] if namespace
         
     | 
| 
      
 98 
     | 
    
         
            +
                    el.build_xml(property_builder)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                def build_value(value)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  case value
         
     | 
| 
      
 104 
     | 
    
         
            +
                  when Time
         
     | 
| 
      
 105 
     | 
    
         
            +
                    value.iso8601.gsub('Z', '.000Z')
         
     | 
| 
      
 106 
     | 
    
         
            +
                  else
         
     | 
| 
      
 107 
     | 
    
         
            +
                    value
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
      
 111 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Build < Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                property 'version', from: 'Version', transform_with: ->(v) { Version.parse(v) }
         
     | 
| 
      
 6 
     | 
    
         
            +
                property 'type', from: 'Type', transform_with: ->(v) { BuildType.parse(v) }
         
     | 
| 
      
 7 
     | 
    
         
            +
                property 'time', from: 'Time', transform_with: ->(v) { Time.parse(v) }
         
     | 
| 
      
 8 
     | 
    
         
            +
                property 'builder', from: 'Builder'
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class CourseList < Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                property 'courses', from: 'Courses', transform_with: ->(v) { v.map { |el| Course.parse(el) } }
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def_delegators :courses, :each, :to_a
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def self.parse(list)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  CourseList.new('Courses' => list.xpath('xmlns:Course'))
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def build_xml(builder)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  courses.each do |course|
         
     | 
| 
      
 15 
     | 
    
         
            +
                    builder.Course do |course_builder|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      course.build_xml(course_builder)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -7,5 +7,27 @@ module Tcx 
     | 
|
| 
       7 
7 
     | 
    
         
             
                property 'workouts', from: 'Workouts', transform_with: ->(arr) { WorkoutList.parse(arr) }
         
     | 
| 
       8 
8 
     | 
    
         
             
                property 'courses', from: 'Courses', transform_with: ->(arr) { CourseList.parse(arr) }
         
     | 
| 
       9 
9 
     | 
    
         
             
                property 'author', from: 'Author', transform_with: ->(el) { AbstractSource.parse(el) }
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def self.load(data)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  parse(Nokogiri::XML(data).root)
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def dump(target_path)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  ::File.write(target_path, to_xml)
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def to_xml
         
     | 
| 
      
 20 
     | 
    
         
            +
                  to_xml_builder.to_xml
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                private
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def to_xml_builder
         
     | 
| 
      
 26 
     | 
    
         
            +
                  Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
         
     | 
| 
      
 27 
     | 
    
         
            +
                    xml.TrainingCenterDatabase(Base.namespace_definitions) do |xml|
         
     | 
| 
      
 28 
     | 
    
         
            +
                      build_xml(xml)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
       10 
32 
     | 
    
         
             
              end
         
     | 
| 
       11 
33 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,10 +1,13 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Tcx
         
     | 
| 
       4 
     | 
    
         
            -
              class  
     | 
| 
       5 
     | 
    
         
            -
                property 'name', from: 'Name'
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Device < AbstractSource
         
     | 
| 
       6 
5 
     | 
    
         
             
                property 'unit_id', from: 'UnitId'
         
     | 
| 
       7 
6 
     | 
    
         
             
                property 'product_id', from: 'ProductID'
         
     | 
| 
       8 
7 
     | 
    
         
             
                property 'version', from: 'Version', transform_with: ->(v) { Version.parse(v) }
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def attributes
         
     | 
| 
      
 10 
     | 
    
         
            +
                  super.merge('xsi:type' => 'Device_t')
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
       9 
12 
     | 
    
         
             
              end
         
     | 
| 
       10 
13 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Duration < Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                property 'seconds', from: 'Seconds', transform_with: lambda(&:to_i)
         
     | 
| 
      
 6 
     | 
    
         
            +
                property 'meters', from: 'Meters', transform_with: lambda(&:to_i)
         
     | 
| 
      
 7 
     | 
    
         
            +
                property 'heart_rate', from: 'HeartRate', transform_with: ->(v) { HeartRateValue.parse(v) }
         
     | 
| 
      
 8 
     | 
    
         
            +
                property 'calories', from: 'Calories', transform_with: lambda(&:to_i)
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,9 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class ExtensionsList < Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                # TODO: forward all extension properties up
         
     | 
| 
      
 6 
     | 
    
         
            +
                property 'TPX', transform_with: ->(v) { Tcx::Extensions::ActivityExtension::V2::ActivityTrackpoint.parse(v) }
         
     | 
| 
      
 7 
     | 
    
         
            +
                property 'LX', transform_with: ->(v) { Tcx::Extensions::ActivityExtension::V2::ActivityLap.parse(v) }
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -14,6 +14,10 @@ module Tcx 
     | 
|
| 
       14 
14 
     | 
    
         
             
                property 'trigger_method', from: 'TriggerMethod', transform_with: ->(v) { TriggerMethod.parse(v) }
         
     | 
| 
       15 
15 
     | 
    
         
             
                property 'tracks', from: 'Track', transform_with: ->(v) { to_array(v).map { |el| Track.parse(el) } }
         
     | 
| 
       16 
16 
     | 
    
         
             
                property 'notes', from: 'Notes'
         
     | 
| 
       17 
     | 
    
         
            -
                property 'extensions', from: 'Extensions', transform_with: ->(v) {  
     | 
| 
      
 17 
     | 
    
         
            +
                property 'extensions', from: 'Extensions', transform_with: ->(v) { ExtensionsList.parse(v) }
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def self.attributes
         
     | 
| 
      
 20 
     | 
    
         
            +
                  ['start_time']
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
       18 
22 
     | 
    
         
             
              end
         
     | 
| 
       19 
23 
     | 
    
         
             
            end
         
     | 
| 
         @@ -9,7 +9,7 @@ module Tcx 
     | 
|
| 
       9 
9 
     | 
    
         
             
                property 'heart_rate_bpm', from: 'HeartRateBpm', transform_with: ->(v) { HeartRateInBeatsPerMinute.parse(v) }
         
     | 
| 
       10 
10 
     | 
    
         
             
                property 'cadence', from: 'Cadence', transform_with: ->(v) { Cadence.parse(v) }
         
     | 
| 
       11 
11 
     | 
    
         
             
                property 'sensor_state', from: 'SensorState', transform_with: ->(v) { SensorState.parse(v) }
         
     | 
| 
       12 
     | 
    
         
            -
                property 'extensions', from: 'Extensions', transform_with: ->(v) {  
     | 
| 
      
 12 
     | 
    
         
            +
                property 'extensions', from: 'Extensions', transform_with: ->(v) { ExtensionsList.parse(v) }
         
     | 
| 
       13 
13 
     | 
    
         
             
                # TODO: Extensions/TPX/Speed
         
     | 
| 
       14 
14 
     | 
    
         
             
              end
         
     | 
| 
       15 
15 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tcx
         
     | 
| 
      
 4 
     | 
    
         
            +
              class WorkoutList < Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                property 'workouts', from: 'Workouts', transform_with: ->(v) { v.map { |el| Workout.parse(el) } }
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def_delegators :workouts, :each, :count
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def self.parse(list)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  WorkoutList.new('Workouts' => list.xpath('xmlns:Workout'))
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def build_xml(builder)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  workouts.each do |workout|
         
     | 
| 
      
 15 
     | 
    
         
            +
                    builder.Workout do |workout_builder|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      workout.build_xml(workout_builder)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tcx/types.rb
    ADDED
    
    | 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'types/base'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'types/abstract_source'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative 'types/activity'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'types/activity_list'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative 'types/application'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative 'types/build'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative 'types/build_type'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative 'types/cadence'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require_relative 'types/course'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require_relative 'types/course_folder'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require_relative 'types/course_lap'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require_relative 'types/course_list'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require_relative 'types/course_point'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require_relative 'types/course_point_type'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require_relative 'types/courses'
         
     | 
| 
      
 18 
     | 
    
         
            +
            require_relative 'types/custom_heart_rate_zone'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require_relative 'types/database'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require_relative 'types/device'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require_relative 'types/duration'
         
     | 
| 
      
 22 
     | 
    
         
            +
            require_relative 'types/extensions_list'
         
     | 
| 
      
 23 
     | 
    
         
            +
            require_relative 'types/folders'
         
     | 
| 
      
 24 
     | 
    
         
            +
            require_relative 'types/gender'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require_relative 'types/heart_rate_as_percent_of_max'
         
     | 
| 
      
 26 
     | 
    
         
            +
            require_relative 'types/heart_rate_bpm'
         
     | 
| 
      
 27 
     | 
    
         
            +
            require_relative 'types/heart_rate_in_beats_per_minute'
         
     | 
| 
      
 28 
     | 
    
         
            +
            require_relative 'types/heart_rate_value'
         
     | 
| 
      
 29 
     | 
    
         
            +
            require_relative 'types/intensity'
         
     | 
| 
      
 30 
     | 
    
         
            +
            require_relative 'types/lap'
         
     | 
| 
      
 31 
     | 
    
         
            +
            require_relative 'types/name_key_reference'
         
     | 
| 
      
 32 
     | 
    
         
            +
            require_relative 'types/position'
         
     | 
| 
      
 33 
     | 
    
         
            +
            require_relative 'types/predefined_heart_rate_zone'
         
     | 
| 
      
 34 
     | 
    
         
            +
            require_relative 'types/sensor_state'
         
     | 
| 
      
 35 
     | 
    
         
            +
            require_relative 'types/sport'
         
     | 
| 
      
 36 
     | 
    
         
            +
            require_relative 'types/step'
         
     | 
| 
      
 37 
     | 
    
         
            +
            require_relative 'types/target'
         
     | 
| 
      
 38 
     | 
    
         
            +
            require_relative 'types/track'
         
     | 
| 
      
 39 
     | 
    
         
            +
            require_relative 'types/trackpoint'
         
     | 
| 
      
 40 
     | 
    
         
            +
            require_relative 'types/trigger_method'
         
     | 
| 
      
 41 
     | 
    
         
            +
            require_relative 'types/version'
         
     | 
| 
      
 42 
     | 
    
         
            +
            require_relative 'types/workout'
         
     | 
| 
      
 43 
     | 
    
         
            +
            require_relative 'types/workout_list'
         
     | 
    
        data/lib/tcx/version.rb
    CHANGED
    
    
    
        data/lib/tcx.rb
    CHANGED
    
    | 
         @@ -4,14 +4,19 @@ require 'hashie' 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require 'time'
         
     | 
| 
       5 
5 
     | 
    
         
             
            require 'ruby-enum'
         
     | 
| 
       6 
6 
     | 
    
         
             
            require 'nokogiri'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'forwardable'
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
9 
     | 
    
         
             
            require_relative 'tcx/version'
         
     | 
| 
       9 
     | 
    
         
            -
            require_relative 'tcx/ 
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative 'tcx/types'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require_relative 'tcx/extensions'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require_relative 'tcx/file'
         
     | 
| 
       10 
13 
     | 
    
         | 
| 
       11 
14 
     | 
    
         
             
            module Tcx
         
     | 
| 
       12 
15 
     | 
    
         
             
              def self.load_file(path)
         
     | 
| 
       13 
     | 
    
         
            -
                 
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
      
 16 
     | 
    
         
            +
                Tcx::File.new(path)
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def self.load(data)
         
     | 
| 
      
 20 
     | 
    
         
            +
                Tcx::Database.load(data)
         
     | 
| 
       16 
21 
     | 
    
         
             
              end
         
     | 
| 
       17 
22 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: tcx
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Daniel Doubrovkine
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2025-10- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2025-10-24 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: hashie
         
     | 
| 
         @@ -62,45 +62,55 @@ files: 
     | 
|
| 
       62 
62 
     | 
    
         
             
            - LICENSE.md
         
     | 
| 
       63 
63 
     | 
    
         
             
            - README.md
         
     | 
| 
       64 
64 
     | 
    
         
             
            - lib/tcx.rb
         
     | 
| 
       65 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       66 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       67 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       68 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       69 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       70 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       71 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       72 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       73 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       74 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       75 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       76 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       77 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       78 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       79 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       80 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       81 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       82 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       83 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       84 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       85 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       86 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       87 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       88 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       89 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       90 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       91 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       92 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       93 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       94 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       95 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       96 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       97 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       98 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       99 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       100 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       101 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       102 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
       103 
     | 
    
         
            -
            - lib/tcx/ 
     | 
| 
      
 65 
     | 
    
         
            +
            - lib/tcx/extensions.rb
         
     | 
| 
      
 66 
     | 
    
         
            +
            - lib/tcx/extensions/activity_extension/v2.rb
         
     | 
| 
      
 67 
     | 
    
         
            +
            - lib/tcx/extensions/activity_extension/v2/activity_lap.rb
         
     | 
| 
      
 68 
     | 
    
         
            +
            - lib/tcx/extensions/activity_extension/v2/activity_trackpoint.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
            - lib/tcx/extensions/activity_extension/v2/base.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
            - lib/tcx/extensions/activity_extension/v2/cadence_sensor_type.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
            - lib/tcx/file.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
            - lib/tcx/types.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
            - lib/tcx/types/abstract_source.rb
         
     | 
| 
      
 74 
     | 
    
         
            +
            - lib/tcx/types/activity.rb
         
     | 
| 
      
 75 
     | 
    
         
            +
            - lib/tcx/types/activity_list.rb
         
     | 
| 
      
 76 
     | 
    
         
            +
            - lib/tcx/types/application.rb
         
     | 
| 
      
 77 
     | 
    
         
            +
            - lib/tcx/types/base.rb
         
     | 
| 
      
 78 
     | 
    
         
            +
            - lib/tcx/types/build.rb
         
     | 
| 
      
 79 
     | 
    
         
            +
            - lib/tcx/types/build_type.rb
         
     | 
| 
      
 80 
     | 
    
         
            +
            - lib/tcx/types/cadence.rb
         
     | 
| 
      
 81 
     | 
    
         
            +
            - lib/tcx/types/course.rb
         
     | 
| 
      
 82 
     | 
    
         
            +
            - lib/tcx/types/course_folder.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - lib/tcx/types/course_lap.rb
         
     | 
| 
      
 84 
     | 
    
         
            +
            - lib/tcx/types/course_list.rb
         
     | 
| 
      
 85 
     | 
    
         
            +
            - lib/tcx/types/course_point.rb
         
     | 
| 
      
 86 
     | 
    
         
            +
            - lib/tcx/types/course_point_type.rb
         
     | 
| 
      
 87 
     | 
    
         
            +
            - lib/tcx/types/courses.rb
         
     | 
| 
      
 88 
     | 
    
         
            +
            - lib/tcx/types/custom_heart_rate_zone.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - lib/tcx/types/database.rb
         
     | 
| 
      
 90 
     | 
    
         
            +
            - lib/tcx/types/device.rb
         
     | 
| 
      
 91 
     | 
    
         
            +
            - lib/tcx/types/duration.rb
         
     | 
| 
      
 92 
     | 
    
         
            +
            - lib/tcx/types/extensions_list.rb
         
     | 
| 
      
 93 
     | 
    
         
            +
            - lib/tcx/types/folders.rb
         
     | 
| 
      
 94 
     | 
    
         
            +
            - lib/tcx/types/gender.rb
         
     | 
| 
      
 95 
     | 
    
         
            +
            - lib/tcx/types/heart_rate_as_percent_of_max.rb
         
     | 
| 
      
 96 
     | 
    
         
            +
            - lib/tcx/types/heart_rate_bpm.rb
         
     | 
| 
      
 97 
     | 
    
         
            +
            - lib/tcx/types/heart_rate_in_beats_per_minute.rb
         
     | 
| 
      
 98 
     | 
    
         
            +
            - lib/tcx/types/heart_rate_value.rb
         
     | 
| 
      
 99 
     | 
    
         
            +
            - lib/tcx/types/intensity.rb
         
     | 
| 
      
 100 
     | 
    
         
            +
            - lib/tcx/types/lap.rb
         
     | 
| 
      
 101 
     | 
    
         
            +
            - lib/tcx/types/name_key_reference.rb
         
     | 
| 
      
 102 
     | 
    
         
            +
            - lib/tcx/types/position.rb
         
     | 
| 
      
 103 
     | 
    
         
            +
            - lib/tcx/types/predefined_heart_rate_zone.rb
         
     | 
| 
      
 104 
     | 
    
         
            +
            - lib/tcx/types/sensor_state.rb
         
     | 
| 
      
 105 
     | 
    
         
            +
            - lib/tcx/types/sport.rb
         
     | 
| 
      
 106 
     | 
    
         
            +
            - lib/tcx/types/step.rb
         
     | 
| 
      
 107 
     | 
    
         
            +
            - lib/tcx/types/target.rb
         
     | 
| 
      
 108 
     | 
    
         
            +
            - lib/tcx/types/track.rb
         
     | 
| 
      
 109 
     | 
    
         
            +
            - lib/tcx/types/trackpoint.rb
         
     | 
| 
      
 110 
     | 
    
         
            +
            - lib/tcx/types/trigger_method.rb
         
     | 
| 
      
 111 
     | 
    
         
            +
            - lib/tcx/types/version.rb
         
     | 
| 
      
 112 
     | 
    
         
            +
            - lib/tcx/types/workout.rb
         
     | 
| 
      
 113 
     | 
    
         
            +
            - lib/tcx/types/workout_list.rb
         
     | 
| 
       104 
114 
     | 
    
         
             
            - lib/tcx/version.rb
         
     | 
| 
       105 
115 
     | 
    
         
             
            homepage: http://github.com/dblock/tcx
         
     | 
| 
       106 
116 
     | 
    
         
             
            licenses:
         
     | 
    
        data/lib/tcx/models/base.rb
    DELETED
    
    | 
         @@ -1,30 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Tcx
         
     | 
| 
       4 
     | 
    
         
            -
              class Base < Hashie::Trash
         
     | 
| 
       5 
     | 
    
         
            -
                include Hashie::Extensions::IgnoreUndeclared
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
                def self.parse(xml)
         
     | 
| 
       8 
     | 
    
         
            -
                  attributes = xml.attributes.to_h
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
                  xml.children.each do |child|
         
     | 
| 
       11 
     | 
    
         
            -
                    next unless child.is_a?(Nokogiri::XML::Element)
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                    attributes[child.name] = if attributes.key?(child.name)
         
     | 
| 
       14 
     | 
    
         
            -
                                               to_array(attributes[child.name]) + [child]
         
     | 
| 
       15 
     | 
    
         
            -
                                             elsif child.children.one? && child.children.first.is_a?(Nokogiri::XML::Text)
         
     | 
| 
       16 
     | 
    
         
            -
                                               child.text
         
     | 
| 
       17 
     | 
    
         
            -
                                             else
         
     | 
| 
       18 
     | 
    
         
            -
                                               child
         
     | 
| 
       19 
     | 
    
         
            -
                                             end
         
     | 
| 
       20 
     | 
    
         
            -
                  end
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                  new attributes
         
     | 
| 
       23 
     | 
    
         
            -
                end
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                # Transform an XmlElement into [XmlElement], cannot be used with Array or causes a coercion error
         
     | 
| 
       26 
     | 
    
         
            -
                def self.to_array(value)
         
     | 
| 
       27 
     | 
    
         
            -
                  value.is_a?(Array) ? value : [value]
         
     | 
| 
       28 
     | 
    
         
            -
                end
         
     | 
| 
       29 
     | 
    
         
            -
              end
         
     | 
| 
       30 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/tcx/models/cadence.rb
    DELETED
    
    
    
        data/lib/tcx/models/duration.rb
    DELETED
    
    
    
        data/lib/tcx/models/value.rb
    DELETED
    
    
    
        data/lib/tcx/models.rb
    DELETED
    
    | 
         @@ -1,40 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require_relative 'models/base'
         
     | 
| 
       4 
     | 
    
         
            -
            require_relative 'models/value'
         
     | 
| 
       5 
     | 
    
         
            -
            require_relative 'models/abstract_source'
         
     | 
| 
       6 
     | 
    
         
            -
            require_relative 'models/activity'
         
     | 
| 
       7 
     | 
    
         
            -
            require_relative 'models/activity_list'
         
     | 
| 
       8 
     | 
    
         
            -
            require_relative 'models/cadence'
         
     | 
| 
       9 
     | 
    
         
            -
            require_relative 'models/course'
         
     | 
| 
       10 
     | 
    
         
            -
            require_relative 'models/course_folder'
         
     | 
| 
       11 
     | 
    
         
            -
            require_relative 'models/course_lap'
         
     | 
| 
       12 
     | 
    
         
            -
            require_relative 'models/course_list'
         
     | 
| 
       13 
     | 
    
         
            -
            require_relative 'models/course_point'
         
     | 
| 
       14 
     | 
    
         
            -
            require_relative 'models/course_point_type'
         
     | 
| 
       15 
     | 
    
         
            -
            require_relative 'models/courses'
         
     | 
| 
       16 
     | 
    
         
            -
            require_relative 'models/custom_heart_rate_zone'
         
     | 
| 
       17 
     | 
    
         
            -
            require_relative 'models/database'
         
     | 
| 
       18 
     | 
    
         
            -
            require_relative 'models/duration'
         
     | 
| 
       19 
     | 
    
         
            -
            require_relative 'models/extensions'
         
     | 
| 
       20 
     | 
    
         
            -
            require_relative 'models/folders'
         
     | 
| 
       21 
     | 
    
         
            -
            require_relative 'models/gender'
         
     | 
| 
       22 
     | 
    
         
            -
            require_relative 'models/heart_rate_as_percent_of_max'
         
     | 
| 
       23 
     | 
    
         
            -
            require_relative 'models/heart_rate_bpm'
         
     | 
| 
       24 
     | 
    
         
            -
            require_relative 'models/heart_rate_in_beats_per_minute'
         
     | 
| 
       25 
     | 
    
         
            -
            require_relative 'models/heart_rate_value'
         
     | 
| 
       26 
     | 
    
         
            -
            require_relative 'models/intensity'
         
     | 
| 
       27 
     | 
    
         
            -
            require_relative 'models/lap'
         
     | 
| 
       28 
     | 
    
         
            -
            require_relative 'models/name_key_reference'
         
     | 
| 
       29 
     | 
    
         
            -
            require_relative 'models/position'
         
     | 
| 
       30 
     | 
    
         
            -
            require_relative 'models/predefined_heart_rate_zone'
         
     | 
| 
       31 
     | 
    
         
            -
            require_relative 'models/sensor_state'
         
     | 
| 
       32 
     | 
    
         
            -
            require_relative 'models/sport'
         
     | 
| 
       33 
     | 
    
         
            -
            require_relative 'models/step'
         
     | 
| 
       34 
     | 
    
         
            -
            require_relative 'models/target'
         
     | 
| 
       35 
     | 
    
         
            -
            require_relative 'models/track'
         
     | 
| 
       36 
     | 
    
         
            -
            require_relative 'models/trackpoint'
         
     | 
| 
       37 
     | 
    
         
            -
            require_relative 'models/trigger_method'
         
     | 
| 
       38 
     | 
    
         
            -
            require_relative 'models/version'
         
     | 
| 
       39 
     | 
    
         
            -
            require_relative 'models/workout'
         
     | 
| 
       40 
     | 
    
         
            -
            require_relative 'models/workout_list'
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |