Class: Fit::File::Data

Inherits:
BinData::Record
  • Object
show all
Defined in:
lib/fit/file/data.rb

Class Method Summary collapse

Class Method Details

.generate(definition) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/fit/file/data.rb', line 7

def self.generate(definition)
  msg_num = definition.global_message_number.snapshot
  type = Definitions.get_name(msg_num) || "data_record_#{msg_num}"

  Class.new(self) do
    self.global_message_number = msg_num

    endian definition.endianness

    class_eval <<-RUBY, __FILE__, __LINE__ + 1
      def record_type
        :#{type}
      end
    RUBY

    definition.fields.each do |field|
      code = ""

      # in case the field size is a multiple of the field length, we must build an array
      if (field.type != "string" and field.size > field.length)
        code << "array :#{field.raw_name}, :type => :#{field.type}, :initial_length => #{field.size/field.length}\n"
      else
        # string are not null terminated when they have exactly the lenght of the field
        code << "#{field.type} :#{field.raw_name}"
        if field.type == "string"
          code << ", :read_length => #{field.size}, :trim_padding => true"
        end
        code << "\n"
      end

      code << "def #{field.name}\n"

      if field.scale && field.scale != 1
        code << "scale = #{field.scale.inspect}.0\n"
      else
        code << "scale = nil\n"
      end

      if field.dyn_data
        code << "dyn = #{field.dyn_data}\n"
      else
        code << "dyn = nil\n"
      end
      code << <<-RUBY
          get_value #{field.raw_name}.snapshot, '#{field.real_type}', scale, dyn
        end
      RUBY

      class_eval code , __FILE__, __LINE__ + 1
    end

    private
   # return the dynamic value if relevant
      # otherwise, it returns value (scaled if necessary)
      def get_value raw_value, raw_type, raw_scale, dyn_data
        val = get_dyn_value(dyn_data, raw_value)
        return val unless val.nil?
        if raw_scale
          if raw_value.is_a? Enumerable
            raw_value.map { |elt| elt / raw_scale }
          else
            raw_value / raw_scale
          end
        else
          get_real_value raw_type, raw_value
        end
      end

      # return the value based on real type
      def get_real_value( real_type, raw_value)
        type = Type.get_type(real_type.to_sym)
        # TODO: manage case where an array is returned
        type ? type.value(raw_value) : raw_value
      end

      def get_dyn_value dyn_data, raw_value
        return nil if dyn_data.nil?
        dyn_data.each do |key, dyn|
          # make sure method exist before calling send (all fields are not always defined)
          if( self.respond_to?("raw_#{dyn[:ref_field_name]}") &&
              dyn[:ref_field_values].include?(self.send("raw_#{dyn[:ref_field_name]}")))
            return get_real_value(dyn[:type], raw_value)
          end
        end
        nil
      end

  end
end