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.
@@ -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
@@ -0,0 +1,5 @@
1
+ module Castle
2
+ module Log
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
data/lib/castle/log.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'castle/log/file'
2
+ require 'castle/log/session'
3
+ require 'castle/log/version'
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
@@ -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: