jeti-log 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 04da93b8a9eabaf8b587c469631301aae286f207
4
- data.tar.gz: ca2a8bca18917c71bf88541e41812e3bbcbd7e55
3
+ metadata.gz: de49fe101044ddafde5ef329ef51cafa420d3be5
4
+ data.tar.gz: b002d696dd02ae2e55ce77e8bee898f4d1e14300
5
5
  SHA512:
6
- metadata.gz: 25a3bcee62b232c6eec9e18a52e4a90d79d123986df5a953dda412a6f402175f2255606c75bd866cde5ffd8a9fd07a563225b0cf8cdb87302a2b6544a3fb205a
7
- data.tar.gz: 3a589b209b0f5733b4b18741477accdf875fe8d699ecee6a034cbf970fed0cd79de70dea70f5d8b3483d80c54da86d8183db882b9d2439aeaaa34ec662c148e8
6
+ metadata.gz: c7336c1217fb00756ac9eaad2dae1a37235e521f990ed8c5234ba901ebb864b158b19f3e50527e4c1c2e9ae1f5c2b27050ea17eb70c04126fbab710c19eae126
7
+ data.tar.gz: 56b6bd68b68c69ede250932309c8bc6763cf13787652b7ab50b4cdaac548b1ce6e3d2cd17da9f9ebe0202041a2a8b21b547ceea112e333540702043e3b1d8afb
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --format progress
@@ -0,0 +1,4 @@
1
+ AllCops:
2
+ Include:
3
+ - 'lib/**/*.rb'
4
+ - 'spec/**/*.rb'
@@ -1,6 +1,7 @@
1
1
  rvm:
2
- - 1.9.3
3
- - 2.0.0
2
+ - 2.1.10
3
+ - 2.2.5
4
+ - 2.3.1
4
5
 
5
6
  notifications:
6
7
  disabled: true
data/Rakefile CHANGED
@@ -1,6 +1,11 @@
1
1
  #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
2
+ require 'bundler/gem_tasks'
3
3
  require 'rspec/core/rake_task'
4
4
 
5
5
  RSpec::Core::RakeTask.new('spec')
6
- task :default => :spec
6
+ task default: :spec
7
+
8
+ if ENV['GENERATE_REPORTS'] == 'true'
9
+ require 'ci/reporter/rake/rspec'
10
+ task spec: 'ci:setup:rspec'
11
+ end
@@ -4,28 +4,33 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'jeti/log/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "jeti-log"
7
+ spec.name = 'jeti-log'
8
8
  spec.version = Jeti::Log::VERSION
9
- spec.authors = ["Nick Veys"]
10
- spec.email = ["nick@codelever.com"]
9
+ spec.authors = ['Nick Veys']
10
+ spec.email = ['nick@codelever.com']
11
11
  spec.description = %q{Read and interpret Jeti telemetry log files.}
12
12
  spec.summary = %q{Jeti telemetry log file reader}
13
- spec.homepage = ""
14
- spec.license = "MIT"
13
+ spec.homepage = 'http://github.com/code-lever/jeti-log'
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_development_dependency 'awesome_print'
22
- spec.add_development_dependency 'bundler', '~> 1.3'
23
- spec.add_development_dependency 'ci_reporter', '= 1.8.4'
22
+ spec.add_development_dependency 'bundler', '~> 1.8'
23
+ spec.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
24
24
  spec.add_development_dependency 'rake', '~> 10.0'
25
- spec.add_development_dependency 'rspec', '~> 2.13'
25
+ spec.add_development_dependency 'rspec', '~> 3.3'
26
+ spec.add_development_dependency 'rspec-collection_matchers'
27
+ spec.add_development_dependency 'rspec-its'
28
+ spec.add_development_dependency 'rubocop'
29
+ spec.add_development_dependency 'rubocop-checkstyle_formatter'
26
30
  spec.add_development_dependency 'simplecov'
27
31
  spec.add_development_dependency 'simplecov-gem-adapter'
28
32
  spec.add_development_dependency 'simplecov-rcov'
33
+ spec.add_development_dependency 'yard'
29
34
 
30
35
  spec.add_dependency 'ruby_kml', '~> 0.1'
31
36
  end
@@ -1,20 +1,12 @@
1
- module Jeti; module Log; module Data;
1
+ module Jeti; module Log; module Data
2
2
 
3
3
  class CompositeDatasetBuilder
4
4
 
5
5
  def self.build(file, clazz, device, primary, *others)
6
- primaries = if primary.is_a? Array
7
- file.value_dataset(device, primary[0], primary[1])
8
- else
9
- file.value_dataset(device, primary)
10
- end
6
+ primaries = file.value_dataset(device, primary)
11
7
 
12
8
  other_data = others.map do |other|
13
- if other.is_a? Array
14
- file.value_dataset(device, other[0], other[1])
15
- else
16
- file.value_dataset(device, other)
17
- end
9
+ file.value_dataset(device, other)
18
10
  end
19
11
 
20
12
  primaries.map do |raw|
@@ -1,4 +1,4 @@
1
- module Jeti; module Log; module Data;
1
+ module Jeti; module Log; module Data
2
2
 
3
3
  class MezonData
4
4
 
@@ -33,10 +33,8 @@ module Jeti; module Log; module Data;
33
33
  class MezonDataBuilder
34
34
 
35
35
  def self.build(file)
36
- div10 = ->(val) { val / 10.0 }
37
- CompositeDatasetBuilder.build(file, MezonData, /Mezon/i, [/U Battery/, div10],
38
- /I Battery/, [/U BEC/, div10], /I BEC/, /Capacity/,
39
- /Revolution/, /Temp/, /Run Time/, /PWM/)
36
+ CompositeDatasetBuilder.build(file, MezonData, /Mezon/i, /U Battery/, /I Battery/,
37
+ /U BEC/, /I BEC/, /Capacity/, /Revolution/, /Temp/, /Run Time/, /PWM/)
40
38
  end
41
39
 
42
40
  end
@@ -1,4 +1,4 @@
1
- module Jeti; module Log; module Data;
1
+ module Jeti; module Log; module Data
2
2
 
3
3
  class MGPSData
4
4
 
@@ -1,4 +1,4 @@
1
- module Jeti; module Log; module Data;
1
+ module Jeti; module Log; module Data
2
2
 
3
3
  class MuiData
4
4
 
@@ -19,9 +19,7 @@ module Jeti; module Log; module Data;
19
19
  class MuiDataBuilder
20
20
 
21
21
  def self.build(file)
22
- div10 = ->(val) { val / 10.0 }
23
- CompositeDatasetBuilder.build(file, MuiData, /MUI/, [/Voltage/, div10],
24
- [/Current/, div10], /Capacity/, /Run time/)
22
+ CompositeDatasetBuilder.build(file, MuiData, /MUI/, /Voltage/, /Current/, /Capacity/, /Run time/)
25
23
  end
26
24
 
27
25
  end
@@ -1,4 +1,4 @@
1
- module Jeti; module Log; module Data;
1
+ module Jeti; module Log; module Data
2
2
 
3
3
  class RxData
4
4
 
@@ -19,8 +19,7 @@ module Jeti; module Log; module Data;
19
19
  class RxDataBuilder
20
20
 
21
21
  def self.build(file)
22
- div100 = ->(val) { val / 100.0 }
23
- CompositeDatasetBuilder.build(file, RxData, /Rx/, [/U Rx/, div100], /A1/, /A2/, /Q/)
22
+ CompositeDatasetBuilder.build(file, RxData, /Rx/, /U Rx/, /A1/, /A2/, /Q/)
24
23
  end
25
24
 
26
25
  end
@@ -1,4 +1,4 @@
1
- module Jeti; module Log; module Data;
1
+ module Jeti; module Log; module Data
2
2
 
3
3
  class TxData
4
4
 
@@ -1,4 +1,4 @@
1
- module Jeti; module Log;
1
+ module Jeti; module Log
2
2
 
3
3
  class Entry
4
4
 
@@ -24,7 +24,7 @@ module Jeti; module Log;
24
24
  raw = detail(sensor_id)
25
25
  case raw[1]
26
26
  when '0','1','4','8'
27
- raw[3].to_i
27
+ format_float(raw[2].to_i, raw[3].to_i)
28
28
  when '5'
29
29
  min = (raw[3].to_i & 0xFF00) >> 8
30
30
  sec = (raw[3].to_i & 0x00FF)
@@ -56,6 +56,13 @@ module Jeti; module Log;
56
56
  degrees * (((dec >> 1) & 1) == 1 ? -1 : 1)
57
57
  end
58
58
 
59
- end
59
+ def format_float(factor, val)
60
+ if val > 0xFFFFFF
61
+ # negative values
62
+ val = val - 0xFFFFFFFF
63
+ end
60
64
 
65
+ val * (10 ** -factor)
66
+ end
67
+ end
61
68
  end; end
@@ -1,214 +1,230 @@
1
1
  require 'open-uri'
2
2
  require 'ruby_kml'
3
3
 
4
- module Jeti; module Log;
4
+ module Jeti
5
5
 
6
- class File
6
+ module Log
7
7
 
8
- attr_reader :name
8
+ class File
9
9
 
10
- # Determines if the file at the given URI is a Jeti telemetry log file.
11
- #
12
- # @param uri URI to file to read
13
- # @return [Jeti::Log::File] loaded file if the file is a Jeti log file, nil otherwise
14
- def self.jeti?(uri)
15
- File.new(uri) rescue nil
16
- end
10
+ attr_reader :name
11
+
12
+ # Determines if the file at the given URI is a Jeti telemetry log file.
13
+ #
14
+ # @param uri URI to file to read
15
+ # @return [Jeti::Log::File] loaded file if the file is a Jeti log file, nil otherwise
16
+ def self.jeti?(uri)
17
+ File.new(uri) rescue nil
18
+ end
17
19
 
18
- def initialize(uri)
20
+ def initialize(uri)
19
21
 
20
- open(uri, 'rb') do |file|
21
- lines = file.readlines.map(&:strip).group_by do |line|
22
- line.start_with?('#') ? :comments : :rows
23
- end
24
- @name = /^#(.*)/.match(lines.fetch(:comments, ['# Unknown']).first)[1].strip
25
-
26
- @headers = []
27
- @entries = []
28
- lines[:rows].each_with_object(';').map(&:split).each do |line|
29
- if '000000000' == line.first
30
- if line.length == 4
31
- line << ''
32
- elsif line.length == 5
33
- # do nothing
22
+ open(uri, 'rb') do |file|
23
+ lines = file.readlines.map(&:strip).group_by do |line|
24
+ line.start_with?('#') ? :comments : :rows
25
+ end
26
+ @name = /^#(.*)/.match(lines.fetch(:comments, ['# Unknown']).first)[1].strip
27
+
28
+ @headers = []
29
+ @entries = []
30
+ lines[:rows].each_with_object(';').map(&:split).each do |line|
31
+ if '000000000' == line.first
32
+ if line.length == 4
33
+ line << ''
34
+ elsif line.length == 5
35
+ # do nothing
36
+ else
37
+ raise RuntimeError, "Unexpected header length (#{line.length})"
38
+ end
39
+ @headers << Header.new(line[0], line[1], line[2..4])
34
40
  else
35
- raise RuntimeError, "Unexpected header length (#{line.length})"
41
+ @entries << Entry.new(line[0], line[1], line[2..-1])
36
42
  end
37
- @headers << Header.new(line[0], line[1], line[2..4])
38
- else
39
- @entries << Entry.new(line[0], line[1], line[2..-1])
40
43
  end
44
+
45
+ raise RuntimeError, 'No headers found in log file' if @headers.empty?
46
+ raise RuntimeError, 'No entries found in log file' if @entries.empty?
41
47
  end
42
48
 
43
- raise RuntimeError, 'No headers found in log file' if @headers.empty?
44
- raise RuntimeError, 'No entries found in log file' if @entries.empty?
49
+ rescue => e
50
+ raise ArgumentError, "File does not appear to be a Jeti log (#{e})"
45
51
  end
46
52
 
47
- rescue => e
48
- raise ArgumentError, "File does not appear to be a Jeti log (#{e})"
49
- end
50
-
51
- # Gets the duration of the session, in seconds.
52
- #
53
- # @return [Float] duration of the session, in seconds
54
- def duration
55
- (@entries.last.time - @entries.first.time) / 1000.0
56
- end
53
+ # Gets the duration of the session, in seconds.
54
+ #
55
+ # @return [Float] duration of the session, in seconds
56
+ def duration
57
+ (@entries.last.time - @entries.first.time) / 1000.0
58
+ end
57
59
 
58
- def mgps_data?
59
- device_present?(/MGPS/)
60
- end
60
+ def mgps_data?
61
+ device_present?(/MGPS/)
62
+ end
61
63
 
62
- def mgps_data
63
- @mgps_data ||= Data::MGPSDataBuilder.build(self)
64
- end
64
+ def mgps_data
65
+ @mgps_data ||= Data::MGPSDataBuilder.build(self)
66
+ end
65
67
 
66
- def mezon_data?
67
- device_present?(/Mezon/i)
68
- end
68
+ def mezon_data?
69
+ device_present?(/Mezon/i)
70
+ end
69
71
 
70
- def mezon_data
71
- @mezon_data ||= Data::MezonDataBuilder.build(self)
72
- end
72
+ def mezon_data
73
+ @mezon_data ||= Data::MezonDataBuilder.build(self)
74
+ end
73
75
 
74
- def mui_data?
75
- device_present?(/MUI/)
76
- end
76
+ def mui_data?
77
+ device_present?(/MUI/)
78
+ end
77
79
 
78
- def mui_data
79
- @mui_data ||= Data::MuiDataBuilder.build(self)
80
- end
80
+ def mui_data
81
+ @mui_data ||= Data::MuiDataBuilder.build(self)
82
+ end
81
83
 
82
- def rx_data?
83
- device_present?(/Rx/)
84
- end
84
+ def rx_data?
85
+ device_present?(/Rx/)
86
+ end
85
87
 
86
- def rx_data
87
- @rx_data ||= Data::RxDataBuilder.build(self)
88
- end
88
+ def rx_data
89
+ @rx_data ||= Data::RxDataBuilder.build(self)
90
+ end
89
91
 
90
- def tx_data?
91
- device_present?(/Tx/)
92
- end
92
+ def tx_data?
93
+ device_present?(/Tx/)
94
+ end
93
95
 
94
- def tx_data
95
- @tx_data ||= Data::TxDataBuilder.build(self)
96
- end
96
+ def tx_data
97
+ @tx_data ||= Data::TxDataBuilder.build(self)
98
+ end
97
99
 
98
- # Determines if KML methods can be called for this session.
99
- #
100
- # @return [Boolean] true if KML can be generated for this session, false otherwise
101
- def to_kml?
102
- mgps_data?
103
- end
100
+ # Determines if KML methods can be called for this session.
101
+ #
102
+ # @return [Boolean] true if KML can be generated for this session, false otherwise
103
+ def to_kml?
104
+ mgps_data?
105
+ end
104
106
 
105
- # Converts the session into a KML document containing a placemark.
106
- #
107
- # @param file_options [Hash] hash containing options for file
108
- # @param placemark_options [Hash] hash containing options for placemark
109
- # @return [String] KML document for the session
110
- # @see #to_kml_file file options
111
- # @see #to_kml_placemark placemark options
112
- def to_kml(file_options = {}, placemark_options = {})
113
- raise RuntimeError, 'No coordinates available for KML generation' unless to_kml?
114
- to_kml_file(file_options, placemark_options).render
115
- end
107
+ # Converts the session into a KML document containing a placemark.
108
+ #
109
+ # @param file_options [Hash] hash containing options for file
110
+ # @param placemark_options [Hash] hash containing options for placemark
111
+ # @return [String] KML document for the session
112
+ # @see #to_kml_file file options
113
+ # @see #to_kml_placemark placemark options
114
+ def to_kml(file_options = {}, placemark_options = {})
115
+ raise RuntimeError, 'No coordinates available for KML generation' unless to_kml?
116
+ to_kml_file(file_options, placemark_options).render
117
+ end
116
118
 
117
- # Converts the session into a KMLFile containing a placemark.
118
- #
119
- # @param file_options [Hash] hash containing options for file
120
- # @option file_options [String] :name name option of KML::Document
121
- # @option file_options [String] :description name option of KML::Document
122
- # @option file_options [String] :style_id id option of KML::Style
123
- # @param placemark_options [Hash] hash containing options for placemark
124
- # @return [KMLFile] file for the session
125
- # @see #to_kml_placemark placemark options
126
- def to_kml_file(file_options = {}, placemark_options = {})
127
- raise RuntimeError, 'No coordinates available for KML generation' unless to_kml?
128
- options = apply_default_file_options(file_options)
129
-
130
- kml = KMLFile.new
131
- kml.objects << KML::Document.new(
132
- :name => options[:name],
133
- :description => options[:description],
134
- :styles => [
135
- KML::Style.new(
136
- :id => options[:style_id],
137
- :line_style => KML::LineStyle.new(:color => '7F00FFFF', :width => 4),
138
- :poly_style => KML::PolyStyle.new(:color => '7F00FF00')
139
- )
119
+ # Converts the session into a KMLFile containing a placemark.
120
+ #
121
+ # @param file_options [Hash] hash containing options for file
122
+ # @option file_options [String] :name name option of KML::Document
123
+ # @option file_options [String] :description name option of KML::Document
124
+ # @option file_options [String] :style_id id option of KML::Style
125
+ # @param placemark_options [Hash] hash containing options for placemark
126
+ # @return [KMLFile] file for the session
127
+ # @see #to_kml_placemark placemark options
128
+ def to_kml_file(file_options = {}, placemark_options = {})
129
+ raise RuntimeError, 'No coordinates available for KML generation' unless to_kml?
130
+ options = apply_default_file_options(file_options)
131
+
132
+ kml = KMLFile.new
133
+ kml.objects << KML::Document.new(
134
+ name: options[:name],
135
+ description: options[:description],
136
+ styles: [
137
+ KML::Style.new(
138
+ id: options[:style_id],
139
+ line_style: KML::LineStyle.new(color: '7F00FFFF', width: 4),
140
+ poly_style: KML::PolyStyle.new(color: '7F00FF00')
141
+ )
140
142
  ],
141
- :features => [ to_kml_placemark(placemark_options) ]
142
- )
143
- kml
144
- end
143
+ features: [ to_kml_placemark(placemark_options) ]
144
+ )
145
+ kml
146
+ end
145
147
 
146
- # Converts the session into a KML::Placemark containing GPS coordinates.
147
- #
148
- # @param options [Hash] hash containing options for placemark
149
- # @option options [String] :altitude_mode altitude_mode option of KML::LineString
150
- # @option options [Boolean] :extrude extrude option of KML::LineString
151
- # @option options [String] :name name option of KML::Placemark
152
- # @option options [String] :style_url style_url option of KML::Placemark
153
- # @option options [Boolean] :tessellate tessellate option of KML::LineString
154
- # @return [KML::Placemark] placemark for the session
155
- def to_kml_placemark(options = {})
156
- raise RuntimeError, 'No coordinates available for KML generation' unless to_kml?
157
- options = apply_default_placemark_options(options)
158
-
159
- coords = mgps_data.map { |l| [l.longitude, l.latitude, l.altitude] }
160
- KML::Placemark.new(
161
- :name => options[:name],
162
- :style_url => options[:style_url],
163
- :geometry => KML::LineString.new(
164
- :altitude_mode => options[:altitude_mode],
165
- :extrude => options[:extrude],
166
- :tessellate => options[:tessellate],
167
- :coordinates => coords.map { |c| c.join(',') }.join(' ')
148
+ # Converts the session into a KML::Placemark containing GPS coordinates.
149
+ #
150
+ # @param options [Hash] hash containing options for placemark
151
+ # @option options [String] :altitude_mode altitude_mode option of KML::LineString
152
+ # @option options [Boolean] :extrude extrude option of KML::LineString
153
+ # @option options [String] :name name option of KML::Placemark
154
+ # @option options [String] :style_url style_url option of KML::Placemark
155
+ # @option options [Boolean] :tessellate tessellate option of KML::LineString
156
+ # @return [KML::Placemark] placemark for the session
157
+ def to_kml_placemark(options = {})
158
+ raise RuntimeError, 'No coordinates available for KML generation' unless to_kml?
159
+ options = apply_default_placemark_options(options)
160
+
161
+ coords = mgps_data.map { |l| [l.longitude, l.latitude, l.altitude] }
162
+ KML::Placemark.new(
163
+ name: options[:name],
164
+ style_url: options[:style_url],
165
+ geometry: KML::LineString.new(
166
+ altitude_mode: options[:altitude_mode],
167
+ extrude: options[:extrude],
168
+ tessellate: options[:tessellate],
169
+ coordinates: coords.map { |c| c.join(',') }.join(' ')
168
170
  )
169
- )
170
- end
171
+ )
172
+ end
171
173
 
172
- def value_dataset(device, sensor, modifier = ->(val) { val })
173
- headers, entries = headers_and_entries_for_device(device)
174
- sensor_id = (headers.select { |h| sensor =~ h.name })[0].sensor_id
175
- entries.reject! { |e| e.detail(sensor_id).nil? }
176
- entries.map { |e| [e.time, modifier.call(e.value(sensor_id))] }
177
- end
174
+ def value_dataset(device, sensor)
175
+ headers, entries = headers_and_entries_for_device(device)
176
+ sensor_id = (headers.select { |h| sensor =~ h.name })[0].sensor_id
177
+ entries.reject! { |e| e.detail(sensor_id).nil? }
178
+ entries.map { |e| [e.time, e.value(sensor_id)] }
179
+ end
178
180
 
179
- private
181
+ def headers(id = nil)
182
+ return @headers if id.nil?
183
+ return @headers.select { |h| h.id == id }
184
+ end
180
185
 
181
- def apply_default_file_options options
182
- options = { :name => 'Jeti MGPS Path' }.merge(options)
183
- options = { :description => 'Session paths for GPS log data' }.merge(options)
184
- options = { :style_id => 'default-poly-style' }.merge(options)
185
- options
186
- end
186
+ def device_present?(device)
187
+ @headers.any? { |h| device =~ h.name }
188
+ # XXX improve, make sure there are entries
189
+ end
187
190
 
188
- def apply_default_placemark_options options
189
- options = { :altitude_mode => 'absolute' }.merge(options)
190
- options = { :extrude => true }.merge(options)
191
- options = { :name => "Session (#{duration.round(1)}s)" }.merge(options)
192
- options = { :style_url => '#default-poly-style' }.merge(options)
193
- options = { :tessellate => true }.merge(options)
194
- options
195
- end
191
+ def sensor_present?(device, sensor)
192
+ headers, _entries = headers_and_entries_for_device(device)
193
+ sensor_headers = (headers.select { |h| sensor =~ h.name })
196
194
 
197
- def device_present?(device)
198
- @headers.any? { |h| device =~ h.name }
199
- # XXX improve, make sure there are entries
200
- end
195
+ return sensor_headers.count > 0 && sensor_headers.first.sensor_id
196
+ end
197
+
198
+ private
201
199
 
202
- def headers_and_entries_for_device(device)
203
- headers = @headers.select { |h| device =~ h.name }
204
- return [[],[]] if headers.empty?
200
+ def apply_default_file_options(options)
201
+ options = { name: 'Jeti MGPS Path' }.merge(options)
202
+ options = { description: 'Session paths for GPS log data' }.merge(options)
203
+ options = { style_id: 'default-poly-style' }.merge(options)
204
+ options
205
+ end
206
+
207
+ def apply_default_placemark_options(options)
208
+ options = { altitude_mode: 'absolute' }.merge(options)
209
+ options = { extrude: true }.merge(options)
210
+ options = { name: "Session (#{duration.round(1)}s)" }.merge(options)
211
+ options = { style_url: '#default-poly-style' }.merge(options)
212
+ options = { tessellate: true }.merge(options)
213
+ options
214
+ end
215
+
216
+ def headers_and_entries_for_device(device)
217
+ headers = @headers.select { |h| device =~ h.name }
218
+ return [[],[]] if headers.empty?
219
+
220
+ id = headers.first.id
221
+ headers = @headers.select { |h| h.id == id }
222
+ entries = @entries.select { |e| e.id == id }
223
+ [headers, entries]
224
+ end
205
225
 
206
- id = headers.first.id
207
- headers = @headers.select { |h| h.id == id }
208
- entries = @entries.select { |e| e.id == id }
209
- [headers, entries]
210
226
  end
211
227
 
212
228
  end
213
229
 
214
- end; end
230
+ end