concept2-data-parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1879f7982a7337c27edd455ba39c1353fb66e51b
4
+ data.tar.gz: 128deb1c4762a504c9835ad509510327cd11421e
5
+ SHA512:
6
+ metadata.gz: bfbf3711c132ff290986a2d7fb969288b67de0905dcd0b2168f39160a96b3e70d5dcf822398ab7d7fa10881c6b55e12e80e15152cb7c1496adacbf15ef2c69d3
7
+ data.tar.gz: 412d8a438df5ee7ae04f6dc8a76d17bbb9f85ed80b64f661018fc7b709d5535a0f9779e98ceba26282c726296dcf40c1a4e1f7228435f8030c99218a6619ff0f
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ .DS_Store
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in concept2-data-parser.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Henry Poydar
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # Concept2 Data Parser
2
+
3
+ Compiles a 6k erg test 500m splits spreadsheet from Concept2 stroke data files
4
+
5
+ ## Installation
6
+
7
+ Install it yourself as:
8
+
9
+ $ gem install concept2-data-parser
10
+
11
+ ## Usage
12
+
13
+ TODO: Write usage instructions here
14
+
15
+ ## Development
16
+
17
+ - Use with any distance erg test
18
+ - Error handling with bad files
19
+
20
+ ## Contributing
21
+
22
+ 1. Fork it ( https://github.com/hpoydar/concept2-data-parser/fork )
23
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
24
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
25
+ 4. Push to the branch (`git push origin my-new-feature`)
26
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.pattern = "test/*_test.rb"
7
+ end
8
+
9
+ task default: [:test]
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+
7
+ require 'concept2/data/parser'
8
+
9
+ if ARGV.empty?
10
+ puts "Please pass in a data file"
11
+ exit
12
+ end
13
+
14
+ parser = Concept2::Data::Parser.new(ARGV.first)
15
+ parser.write_file!
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'concept2/data/parser/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "concept2-data-parser"
8
+ spec.version = Concept2::Data::Parser::VERSION
9
+ spec.authors = ["Henry Poydar"]
10
+ spec.email = ["hpoydar@gmail.com"]
11
+ spec.summary = %q{Compiles a 6k erg test 500m splits spreadsheet from Concept2 stroke data files}
12
+ spec.homepage = "https://github.com/hpoydar/concept2-data-parser"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_runtime_dependency 'chronic_duration', '~> 0.10.6'
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency 'minitest', '~> 5.5.0'
24
+ end
@@ -0,0 +1,7 @@
1
+ module Concept2
2
+ module Data
3
+ class Parser
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,106 @@
1
+ require "concept2/data/parser/version"
2
+ require "csv"
3
+ require 'chronic_duration'
4
+
5
+ module Concept2
6
+ module Data
7
+ class Parser
8
+
9
+ attr_accessor :rowers
10
+
11
+ def initialize(file)
12
+ @file = file
13
+ @raw = nil
14
+ @rowers = [] # Array of arrays where we'll store everything
15
+
16
+ read_file
17
+ compile_totals!
18
+ toss_empties!
19
+ compile_splits!
20
+ end
21
+
22
+ def write_file!(file="#{File.basename(@file)}-formatted.csv")
23
+ headers = ["Name", "Time", "Avg. Split", "Avg. SPM"]
24
+ 12.times do |i|
25
+ headers << "#{(i+1)*500}m Split"
26
+ headers << "#{(i+1)*500}m SPM"
27
+ end
28
+ CSV.open(file, "wb") do |csv|
29
+ csv << headers
30
+ rowers.each do |rower|
31
+ res = []
32
+ res << rower[:name]
33
+ res << rower[:overall_time]
34
+ res << rower[:overall_split]
35
+ res << rower[:overall_stroke_rate]
36
+ 12.times do |i|
37
+ res << rower[:splits][i]
38
+ res << rower[:stroke_rates][i]
39
+ end
40
+ csv << res
41
+ end
42
+ end
43
+ end
44
+
45
+ protected
46
+
47
+ def read_file
48
+ CSV.foreach(@file, headers: true) do |csv|
49
+ if !csv['PM3'].nil?
50
+ @rowers << {name: csv['PM3'], data: []}
51
+ end
52
+ @rowers[@rowers.size-1][:data] << [
53
+ csv['Time'].to_f,
54
+ csv['Meters'].to_f,
55
+ csv['Stroke_Rate'].to_i]
56
+ end
57
+ end
58
+
59
+ def compile_totals!
60
+ @rowers.each do |rower|
61
+ rower[:overall_time] = ChronicDuration.output(
62
+ rower[:data].last[0].round(1), format: :chrono)
63
+ rower[:overall_stroke_rate] = average_stroke_rate(
64
+ rower[:data].map {|n| n[2] })
65
+ rower[:overall_split] = split_time(rower[:data].last[0], 6000.0)
66
+ end
67
+ end
68
+
69
+ def compile_splits!
70
+ @rowers.each do |rower|
71
+ idxs = []
72
+ 12.times do |i|
73
+ idx_val = rower[:data].map {|r| r[1] }.
74
+ min_by { |v| (v-(500*(i+1))).abs }
75
+ idxs << rower[:data].index {|r| r[1] == idx_val }
76
+ end
77
+ rower[:stroke_rates] = []
78
+ rower[:splits] = []
79
+ prev_idx = 0
80
+ idxs.each do |idx|
81
+ rower[:stroke_rates] << average_stroke_rate(
82
+ rower[:data][prev_idx..idx].map {|n| n[2] })
83
+ rower[:splits] << split_time(
84
+ rower[:data][idx][0] - rower[:data][prev_idx][0])
85
+ prev_idx = idx
86
+ end
87
+ end
88
+ end
89
+
90
+ def toss_empties!
91
+ @rowers = @rowers.select {|r| r[:overall_stroke_rate] != 0 }
92
+ end
93
+
94
+ def average_stroke_rate(stroke_array)
95
+ stroke_array.inject(:+) / stroke_array.size
96
+ end
97
+
98
+ def split_time(secs, distance=500.0)
99
+ ChronicDuration.output(
100
+ ((secs * 500.0) / distance).round(1), format: :chrono)
101
+ end
102
+
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,55 @@
1
+ require "test_helper"
2
+
3
+ class Concept2DataParserTest < Minitest::Test
4
+
5
+ describe "parsing data" do
6
+ def setup
7
+ @fixture = File.join(File.dirname(__FILE__),
8
+ 'fixtures/6k-stroke-data.txt')
9
+ @parser = Concept2::Data::Parser.new(@fixture)
10
+ end
11
+
12
+ it "creates raw data for each rower" do
13
+ assert_equal 4, @parser.rowers.size
14
+ end
15
+
16
+ it "records the name of each rower" do
17
+ assert_equal %w(Snell Cheuse McCormick Keefe),
18
+ @parser.rowers.map {|r| r[:name] }
19
+ end
20
+ end
21
+
22
+ describe "compiling data" do
23
+ def setup
24
+ @fixture = File.join(File.dirname(__FILE__),
25
+ 'fixtures/6k-stroke-data.txt')
26
+ @parser = Concept2::Data::Parser.new(@fixture)
27
+ end
28
+
29
+ it "compiles the overall time" do
30
+ assert_equal ["26:17.5", "26:15", "27:00.9", "25:52"],
31
+ @parser.rowers.map {|r| r[:overall_time] }
32
+ end
33
+
34
+ it "compiles the overall stroke rate" do
35
+ assert_equal [26, 24, 26, 23],
36
+ @parser.rowers.map {|r| r[:overall_stroke_rate] }
37
+ end
38
+
39
+ it "compiles the overall 500m split" do
40
+ assert_equal ["2:11.5", "2:11.3", "2:15.1", "2:09.3"],
41
+ @parser.rowers.map {|r| r[:overall_split] }
42
+ end
43
+
44
+ it "compiles 500m split average stroke rate" do
45
+ assert_equal [28, 25, 25, 24, 25, 25, 26, 25, 26, 26, 27, 29],
46
+ @parser.rowers[0][:stroke_rates]
47
+ end
48
+
49
+ it "compiles 500m splits" do
50
+ assert_equal ["2:03.5", "2:12.5", "2:14", "2:15", "2:15", "2:14.5", "2:13", "2:14", "2:10", "2:10.4", "2:10.5", "2:04.6"],
51
+ @parser.rowers[0][:splits]
52
+ end
53
+ end
54
+
55
+ end