fit_parser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +15 -0
  5. data/Gemfile.lock +105 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.md +27 -0
  8. data/Rakefile +38 -0
  9. data/lib/fit_parser/file/data.rb +99 -0
  10. data/lib/fit_parser/file/definition.rb +120 -0
  11. data/lib/fit_parser/file/definitions.rb +705 -0
  12. data/lib/fit_parser/file/header.rb +18 -0
  13. data/lib/fit_parser/file/record.rb +37 -0
  14. data/lib/fit_parser/file/record_header.rb +27 -0
  15. data/lib/fit_parser/file/type.rb +41 -0
  16. data/lib/fit_parser/file/types.rb +954 -0
  17. data/lib/fit_parser/file.rb +29 -0
  18. data/lib/fit_parser/version.rb +3 -0
  19. data/lib/fit_parser.rb +19 -0
  20. data/spec/file/data_spec.rb +111 -0
  21. data/spec/file/definition_spec.rb +26 -0
  22. data/spec/file/definitions_spec.rb +81 -0
  23. data/spec/file/header_spec.rb +28 -0
  24. data/spec/file/record_header_spec.rb +20 -0
  25. data/spec/file/record_spec.rb +56 -0
  26. data/spec/file/type_spec.rb +99 -0
  27. data/spec/file/types_spec.rb +100 -0
  28. data/spec/file_spec.rb +21 -0
  29. data/spec/fit_spec.rb +10 -0
  30. data/spec/spec_helper.rb +19 -0
  31. data/spec/support/examples/file/full_file_with_wrong_crc.fit +0 -0
  32. data/spec/support/examples/file/header +0 -0
  33. data/spec/support/examples/file/header_14b.fit +0 -0
  34. data/spec/support/examples/record/data_record_2.fit +0 -0
  35. data/spec/support/examples/record/data_record_2bis.fit +0 -0
  36. data/spec/support/examples/record/definition_record +0 -0
  37. data/spec/support/examples/record/definition_record_2.fit +0 -0
  38. data/spec/support/examples/record/message/data_dynamic_fields.fit +0 -0
  39. data/spec/support/examples/record/message/data_field_array.fit +0 -0
  40. data/spec/support/examples/record/message/data_file_capabilities_activities.fit +0 -0
  41. data/spec/support/examples/record/message/data_file_capabilities_settings.fit +0 -0
  42. data/spec/support/examples/record/message/definition +0 -0
  43. data/spec/support/examples/record/message/definition_dynamic_fields.fit +0 -0
  44. data/spec/support/examples/record/message/definition_field_array.fit +0 -0
  45. data/spec/support/examples/record/message/definition_file_capabilities.fit +0 -0
  46. data/spec/support/examples/record/normal_header +1 -0
  47. metadata +230 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b05bf2d5657adbb182fca9609bce59fae622691f
4
+ data.tar.gz: b51f41aec70c9ac14711301307a3b1eb9ae7dcfc
5
+ SHA512:
6
+ metadata.gz: a88073111711d6c8e3af8a9cb875b2250c97f5bcd792a4ab658ca0a3fcaf647851ef2f848553b1a8d43188206b3db45534968367fd6461e552bf9b05dd9677e9
7
+ data.tar.gz: 59565392d47774c0d862cc37c7691c21c8f1562bbb3ea3aa3c2cc77f24472131ed6f8532840063d31ccba3f1c3da6bfb5531f6412e0ad82367e4857215abfbaf
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "bindata", "~> 2.1.0"
4
+ gem "activesupport", "~> 4.2.0"
5
+
6
+ group :development do
7
+ gem "rspec"
8
+ gem "rspec-its"
9
+ gem "yard"
10
+ gem "bundler"
11
+ gem "jeweler"
12
+ gem "simplecov"
13
+ gem "i18n"
14
+ gem "pry"
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,105 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (4.2.0)
5
+ i18n (~> 0.7)
6
+ json (~> 1.7, >= 1.7.7)
7
+ minitest (~> 5.1)
8
+ thread_safe (~> 0.3, >= 0.3.4)
9
+ tzinfo (~> 1.1)
10
+ addressable (2.3.7)
11
+ bindata (2.1.0)
12
+ builder (3.2.2)
13
+ coderay (1.1.0)
14
+ descendants_tracker (0.0.4)
15
+ thread_safe (~> 0.3, >= 0.3.1)
16
+ diff-lcs (1.2.5)
17
+ docile (1.1.5)
18
+ faraday (0.9.1)
19
+ multipart-post (>= 1.2, < 3)
20
+ git (1.2.9.1)
21
+ github_api (0.12.3)
22
+ addressable (~> 2.3)
23
+ descendants_tracker (~> 0.0.4)
24
+ faraday (~> 0.8, < 0.10)
25
+ hashie (>= 3.3)
26
+ multi_json (>= 1.7.5, < 2.0)
27
+ nokogiri (~> 1.6.3)
28
+ oauth2
29
+ hashie (3.4.0)
30
+ highline (1.6.21)
31
+ i18n (0.7.0)
32
+ jeweler (2.0.1)
33
+ builder
34
+ bundler (>= 1.0)
35
+ git (>= 1.2.5)
36
+ github_api
37
+ highline (>= 1.6.15)
38
+ nokogiri (>= 1.5.10)
39
+ rake
40
+ rdoc
41
+ json (1.8.2)
42
+ jwt (1.2.1)
43
+ method_source (0.8.2)
44
+ mini_portile (0.6.2)
45
+ minitest (5.5.1)
46
+ multi_json (1.10.1)
47
+ multi_xml (0.5.5)
48
+ multipart-post (2.0.0)
49
+ nokogiri (1.6.6.2)
50
+ mini_portile (~> 0.6.0)
51
+ oauth2 (1.0.0)
52
+ faraday (>= 0.8, < 0.10)
53
+ jwt (~> 1.0)
54
+ multi_json (~> 1.3)
55
+ multi_xml (~> 0.5)
56
+ rack (~> 1.2)
57
+ pry (0.10.1)
58
+ coderay (~> 1.1.0)
59
+ method_source (~> 0.8.1)
60
+ slop (~> 3.4)
61
+ rack (1.6.0)
62
+ rake (10.4.2)
63
+ rdoc (4.2.0)
64
+ json (~> 1.4)
65
+ rspec (3.2.0)
66
+ rspec-core (~> 3.2.0)
67
+ rspec-expectations (~> 3.2.0)
68
+ rspec-mocks (~> 3.2.0)
69
+ rspec-core (3.2.0)
70
+ rspec-support (~> 3.2.0)
71
+ rspec-expectations (3.2.0)
72
+ diff-lcs (>= 1.2.0, < 2.0)
73
+ rspec-support (~> 3.2.0)
74
+ rspec-its (1.1.0)
75
+ rspec-core (>= 3.0.0)
76
+ rspec-expectations (>= 3.0.0)
77
+ rspec-mocks (3.2.0)
78
+ diff-lcs (>= 1.2.0, < 2.0)
79
+ rspec-support (~> 3.2.0)
80
+ rspec-support (3.2.1)
81
+ simplecov (0.9.1)
82
+ docile (~> 1.1.0)
83
+ multi_json (~> 1.0)
84
+ simplecov-html (~> 0.8.0)
85
+ simplecov-html (0.8.0)
86
+ slop (3.6.0)
87
+ thread_safe (0.3.4)
88
+ tzinfo (1.2.2)
89
+ thread_safe (~> 0.1)
90
+ yard (0.8.7.6)
91
+
92
+ PLATFORMS
93
+ ruby
94
+
95
+ DEPENDENCIES
96
+ activesupport (~> 4.2.0)
97
+ bindata (~> 2.1.0)
98
+ bundler
99
+ i18n
100
+ jeweler
101
+ pry
102
+ rspec
103
+ rspec-its
104
+ simplecov
105
+ yard
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Jeff Wallace
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # fit
2
+
3
+ A ruby gem for parsing [fit files](http://www.thisisant.com/pages/products/fit-sdk). It makes heavy use of the [bindata gem](http://bindata.rubyforge.org/).
4
+
5
+ ## Example usage
6
+
7
+ ```ruby
8
+ require 'fit'
9
+
10
+ fit_file = Fit.load_file(ARGV[0])
11
+
12
+ records = fit_file.records.select{ |r| r.content.record_type != :definition }.map{ |r| r.content }
13
+ ```
14
+
15
+ ## Contributing to fit
16
+
17
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
18
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
19
+ * Fork the project
20
+ * Start a feature/bugfix branch
21
+ * Commit and push until you are happy with your contribution
22
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
23
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
24
+
25
+ ## Copyright
26
+
27
+ Copyright (c) 2011 Jeff Wallace. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ require './lib/fit_parser/version'
16
+ Jeweler::Tasks.new do |gem|
17
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
18
+ gem.name = "fit_parser"
19
+ gem.version = FitParser::VERSION
20
+ gem.homepage = "http://github.com/zhublik/fit_parser"
21
+ gem.license = "MIT"
22
+ gem.summary = ""
23
+ gem.description = ""
24
+ gem.email = "dima.mescheryakov@gmail.com"
25
+ gem.authors = ["Dima Mescheryakov"]
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.pattern = 'spec/**/*_spec.rb'
33
+ end
34
+
35
+ task :default => :spec
36
+
37
+ require 'yard'
38
+ YARD::Rake::YardocTask.new
@@ -0,0 +1,99 @@
1
+ module FitParser
2
+ class File
3
+ class Data < BinData::Record
4
+
5
+ class_attribute :global_message_number, :instance_writer => false
6
+
7
+ def self.generate(definition)
8
+ msg_num = definition.global_message_number.snapshot
9
+ type = Definitions.get_name(msg_num) || "data_record_#{msg_num}"
10
+
11
+ Class.new(self) do
12
+ self.global_message_number = msg_num
13
+
14
+ endian definition.endianness
15
+
16
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
17
+ def record_type
18
+ :#{type}
19
+ end
20
+ RUBY
21
+
22
+ definition.fields.each do |field|
23
+ code = ""
24
+
25
+ # in case the field size is a multiple of the field length, we must build an array
26
+ if (field.type != "string" and field.size > field.length)
27
+ code << "array :#{field.raw_name}, :type => :#{field.type}, :initial_length => #{field.size/field.length}\n"
28
+ else
29
+ # string are not null terminated when they have exactly the lenght of the field
30
+ code << "#{field.type} :#{field.raw_name}"
31
+ if field.type == "string"
32
+ code << ", :read_length => #{field.size}, :trim_padding => true"
33
+ end
34
+ code << "\n"
35
+ end
36
+
37
+ code << "def #{field.name}\n"
38
+
39
+ if field.scale && field.scale != 1
40
+ code << "scale = #{field.scale.inspect}.0\n"
41
+ else
42
+ code << "scale = nil\n"
43
+ end
44
+
45
+ if field.dyn_data
46
+ code << "dyn = #{field.dyn_data}\n"
47
+ else
48
+ code << "dyn = nil\n"
49
+ end
50
+ code << <<-RUBY
51
+ get_value #{field.raw_name}.snapshot, '#{field.real_type}', scale, dyn
52
+ end
53
+ RUBY
54
+
55
+ class_eval code , __FILE__, __LINE__ + 1
56
+ end
57
+
58
+ private
59
+ # return the dynamic value if relevant
60
+ # otherwise, it returns value (scaled if necessary)
61
+ def get_value raw_value, raw_type, raw_scale, dyn_data
62
+ val = get_dyn_value(dyn_data, raw_value)
63
+ return val unless val.nil?
64
+ if raw_scale
65
+ if raw_value.is_a? Enumerable
66
+ raw_value.map { |elt| elt / raw_scale }
67
+ else
68
+ raw_value / raw_scale
69
+ end
70
+ else
71
+ get_real_value raw_type, raw_value
72
+ end
73
+ end
74
+
75
+ # return the value based on real type
76
+ def get_real_value( real_type, raw_value)
77
+ type = Type.get_type(real_type.to_sym)
78
+ # TODO: manage case where an array is returned
79
+ type ? type.value(raw_value) : raw_value
80
+ end
81
+
82
+ def get_dyn_value dyn_data, raw_value
83
+ return nil if dyn_data.nil?
84
+ dyn_data.each do |key, dyn|
85
+ # make sure method exist before calling send (all fields are not always defined)
86
+ if( self.respond_to?("raw_#{dyn[:ref_field_name]}") &&
87
+ dyn[:ref_field_values].include?(self.send("raw_#{dyn[:ref_field_name]}")))
88
+ return get_real_value(dyn[:type], raw_value)
89
+ end
90
+ end
91
+ nil
92
+ end
93
+
94
+ end
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,120 @@
1
+ module FitParser
2
+ class File
3
+ class Definition < BinData::Record
4
+
5
+ class Field < BinData::Record
6
+ hide :reserved_bits
7
+
8
+ uint8 :field_definition_number
9
+ uint8 :field_size
10
+ bit1 :endian_ability
11
+ bit2 :reserved_bits
12
+ bit5 :base_type_number
13
+
14
+ def data
15
+ @data ||= Definitions.get_field(parent.parent.global_message_number.snapshot,
16
+ field_definition_number.snapshot) ||
17
+ { :name => "field_#{field_definition_number.snapshot}", :scale => nil }
18
+ end
19
+
20
+ def dyn_data
21
+ @dyn_data ||= Definitions.get_dynamic_fields(parent.parent.global_message_number.snapshot,
22
+ field_definition_number.snapshot)
23
+ end
24
+
25
+ def name
26
+ data[:name]
27
+ end
28
+
29
+ def raw_name
30
+ "raw_#{name}"
31
+ end
32
+
33
+ def scale
34
+ data[:scale]
35
+ end
36
+
37
+ def real_type
38
+ data[:type]
39
+ end
40
+
41
+ def type
42
+ case base_type_number.snapshot
43
+ when 0 # enum
44
+ build_int_type 8, false
45
+ when 1
46
+ build_int_type 8, true
47
+ when 2
48
+ build_int_type 8, false
49
+ when 3
50
+ build_int_type 16, true
51
+ when 4
52
+ build_int_type 16, false
53
+ when 5
54
+ build_int_type 32, true
55
+ when 6
56
+ build_int_type 32, false
57
+ when 7
58
+ # some cases found where string has the max field length
59
+ # and is therefore not null terminated
60
+ @length = 1
61
+ "string"
62
+ when 8
63
+ @length = 4
64
+ "float"
65
+ when 9
66
+ @length = 8
67
+ "double"
68
+ when 10 # uint8z
69
+ build_int_type 8, false
70
+ when 11 # uint16z
71
+ build_int_type 16, false
72
+ when 12 # uint32z
73
+ build_int_type 32, false
74
+ when 13 # array of bytes
75
+ build_int_type 8, false
76
+ else
77
+ raise "Can't map base_type_number #{base_type_number} to a data type"
78
+ end
79
+ end
80
+
81
+ # field_size is in byte
82
+ def size
83
+ field_size
84
+ end
85
+
86
+ # return the length in byte of the given type
87
+ def length
88
+ @length
89
+ end
90
+
91
+ private
92
+
93
+ def build_int_type(length, signed)
94
+ # @length is in byte not in bits, so divide by 8
95
+ @length = length/8
96
+ (signed ? '' : 'u') << 'int' << length.to_s
97
+ end
98
+ end
99
+
100
+ skip :length => 1
101
+ bit8 :architecture
102
+ choice :global_message_number, :selection => :architecture do
103
+ uint16le 0
104
+ uint16be 1
105
+ end
106
+ bit8 :field_count
107
+ array :fields, :type => Field, :initial_length => :field_count
108
+
109
+ def endianness
110
+ architecture.snapshot == 0 ? :little : :big
111
+ end
112
+
113
+ def record_type
114
+ :definition
115
+ end
116
+
117
+ end
118
+ end
119
+ end
120
+