castle-log 0.0.1
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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +6 -0
- data/castle-log.gemspec +25 -0
- data/data/long-flight.csv +2853 -0
- data/data/multi-line-notes.csv +4607 -0
- data/data/multi-session-1.csv +972 -0
- data/data/multi-session-2.csv +5457 -0
- data/data/sample-1.csv +584 -0
- data/lib/castle/log/file.rb +87 -0
- data/lib/castle/log/session.rb +24 -0
- data/lib/castle/log/version.rb +5 -0
- data/lib/castle/log.rb +3 -0
- data/spec/file_spec.rb +55 -0
- data/spec/session_spec.rb +23 -0
- data/spec/spec_helper.rb +19 -0
- metadata +122 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Castle
|
4
|
+
module Log
|
5
|
+
|
6
|
+
# Represents a single Castle data logger file.
|
7
|
+
class File
|
8
|
+
|
9
|
+
attr_reader :date_saved
|
10
|
+
|
11
|
+
# @return [String] Notes at the beginning of the file
|
12
|
+
attr_reader :notes
|
13
|
+
|
14
|
+
# @return [Array<Session>] Sessions contained in this file
|
15
|
+
attr_reader :sessions
|
16
|
+
|
17
|
+
def initialize uri
|
18
|
+
@sessions = []
|
19
|
+
|
20
|
+
open(uri, 'rb') do |file|
|
21
|
+
|
22
|
+
i = 0
|
23
|
+
in_comment = false
|
24
|
+
lines = file.readlines.map(&:strip).group_by do |line|
|
25
|
+
if line.start_with?('#') && !in_comment
|
26
|
+
in_comment = true
|
27
|
+
i += 1
|
28
|
+
elsif !line.start_with?('#') && in_comment
|
29
|
+
in_comment = false
|
30
|
+
end
|
31
|
+
i
|
32
|
+
end
|
33
|
+
|
34
|
+
# session 1 has some extra metadata, scrape that out first
|
35
|
+
notes = lines[1].select { |line| line.start_with?('# Note') }
|
36
|
+
meta = lines[1].select { |line| line.start_with?('# Graph Data') }
|
37
|
+
|
38
|
+
@sessions = extract_sessions(lines)
|
39
|
+
|
40
|
+
@notes = (notes.map { |line| /Note -(?<note>.*)$/.match(line)[:note].strip }).join("\n")
|
41
|
+
|
42
|
+
# TODO validate expected number of sessions from meta
|
43
|
+
# TODO extract date_saved
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
rescue
|
48
|
+
raise ArgumentError, 'File does not appear to be an Castle data log'
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def extract_sessions line_hash
|
54
|
+
|
55
|
+
keys = line_hash.keys.sort!
|
56
|
+
keys.map do |session_index|
|
57
|
+
lines = line_hash[session_index]
|
58
|
+
start = lines.select { |line| line.start_with?('# Start Of Session') }
|
59
|
+
reset = lines.select { |line| line.start_with?('# Reset Source') }
|
60
|
+
tick = /Sample Time: (?<tick>\d+.\d+)/.match(start[0])[:tick].strip.to_f
|
61
|
+
source = /\(Cause of reset\): (?<source>.*)/.match(reset[0])[:source].strip
|
62
|
+
|
63
|
+
# XXX can we use CSV for this instead?
|
64
|
+
|
65
|
+
# strip out comment rows
|
66
|
+
raw_rows = lines.reject { |line| line.start_with?('#') }
|
67
|
+
|
68
|
+
# pop off header rows
|
69
|
+
headers = raw_rows.shift.split(',').map(&:strip)
|
70
|
+
booleans = raw_rows.shift.split(',').map(&:strip) # XXX unused, what is this?
|
71
|
+
|
72
|
+
# split the rows up and flip them into columns of data
|
73
|
+
columns = (raw_rows.map { |row| row.split(',').map(&:strip) }).transpose
|
74
|
+
|
75
|
+
# build the data hash as expected by the session
|
76
|
+
data = (columns.each_with_index.map { |column, idx| { headers[idx] => column } }).reduce({}, :merge)
|
77
|
+
|
78
|
+
Session.new(tick, source, data)
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Castle
|
2
|
+
module Log
|
3
|
+
|
4
|
+
# Represents a single session from a Castle data logger file.
|
5
|
+
class Session
|
6
|
+
|
7
|
+
attr_reader :tick
|
8
|
+
|
9
|
+
attr_reader :source
|
10
|
+
|
11
|
+
def initialize tick, source, data
|
12
|
+
@tick = tick
|
13
|
+
@source = source
|
14
|
+
@data = data
|
15
|
+
end
|
16
|
+
|
17
|
+
def duration
|
18
|
+
tick * @data.values[0].length
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
data/lib/castle/log.rb
ADDED
data/spec/file_spec.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Castle::Log::File do
|
4
|
+
|
5
|
+
context 'data file long-flight.csv' do
|
6
|
+
|
7
|
+
subject { Castle::Log::File.new(data_file('long-flight.csv')) }
|
8
|
+
|
9
|
+
it { should have(1).sessions }
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'data file multi-line-notes.csv' do
|
14
|
+
|
15
|
+
subject { Castle::Log::File.new(data_file('multi-line-notes.csv')) }
|
16
|
+
|
17
|
+
it { should have(1).sessions }
|
18
|
+
|
19
|
+
it 'should have a multi-line note field' do
|
20
|
+
subject.notes.split("\n").should have(3).lines
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'data file multi-session-1.csv' do
|
26
|
+
|
27
|
+
subject { Castle::Log::File.new(data_file('multi-session-1.csv')) }
|
28
|
+
|
29
|
+
it { should have(5).sessions }
|
30
|
+
|
31
|
+
its(:notes) { should eql('Agri-duck 14 sep 12') }
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'data file multi-session-2.csv' do
|
36
|
+
|
37
|
+
subject { Castle::Log::File.new(data_file('multi-session-2.csv')) }
|
38
|
+
|
39
|
+
it { should have(7).sessions }
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'data file sample-1.csv' do
|
44
|
+
|
45
|
+
subject { Castle::Log::File.new(data_file('sample-1.csv')) }
|
46
|
+
|
47
|
+
it { should have(1).sessions }
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should raise on bad input' do
|
52
|
+
expect { Castle::Log::File.new(__FILE__) }.to raise_error
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Castle::Log::Session do
|
4
|
+
|
5
|
+
context 'data file long-flight.csv' do
|
6
|
+
|
7
|
+
let(:file) { Castle::Log::File.new(data_file('long-flight.csv')) }
|
8
|
+
|
9
|
+
subject { file }
|
10
|
+
|
11
|
+
it { should have(1).sessions }
|
12
|
+
|
13
|
+
context 'session 1' do
|
14
|
+
|
15
|
+
subject { file.sessions[0] }
|
16
|
+
|
17
|
+
its(:duration) { should be_within(0.1).of(569.2) }
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'castle/log'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
6
|
+
config.run_all_when_everything_filtered = true
|
7
|
+
config.filter_run :focus
|
8
|
+
|
9
|
+
# Run specs in random order to surface order dependencies. If you find an
|
10
|
+
# order dependency and want to debug it, you can fix the order by providing
|
11
|
+
# the seed, which is printed after each run.
|
12
|
+
# --seed 1234
|
13
|
+
config.order = 'random'
|
14
|
+
end
|
15
|
+
|
16
|
+
def data_file(name)
|
17
|
+
path = Pathname.new("#{File.dirname(__FILE__)}/../data/#{name}")
|
18
|
+
path.realpath
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: castle-log
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nick Veys
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ci_reporter
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.4
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.8.4
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.12'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.12'
|
69
|
+
description: Read and interpret Castle Creations data log files.
|
70
|
+
email:
|
71
|
+
- nick@codelever.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- castle-log.gemspec
|
82
|
+
- data/long-flight.csv
|
83
|
+
- data/multi-line-notes.csv
|
84
|
+
- data/multi-session-1.csv
|
85
|
+
- data/multi-session-2.csv
|
86
|
+
- data/sample-1.csv
|
87
|
+
- lib/castle/log.rb
|
88
|
+
- lib/castle/log/file.rb
|
89
|
+
- lib/castle/log/session.rb
|
90
|
+
- lib/castle/log/version.rb
|
91
|
+
- spec/file_spec.rb
|
92
|
+
- spec/session_spec.rb
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
homepage: ''
|
95
|
+
licenses:
|
96
|
+
- MIT
|
97
|
+
metadata: {}
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 2.0.3
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Castle Creations data log file reader
|
118
|
+
test_files:
|
119
|
+
- spec/file_spec.rb
|
120
|
+
- spec/session_spec.rb
|
121
|
+
- spec/spec_helper.rb
|
122
|
+
has_rdoc:
|