bb_analytics 0.0.1

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: 9a3ac7a2bb7cef6a44843224c7b86d9bf7222295
4
+ data.tar.gz: 96301c15766b1a5f3e15bef1970f8b4daddc0bc0
5
+ SHA512:
6
+ metadata.gz: 5d8a3ffef20afa037a0cb796e32b750f6a06a229154301a4967534c38cf65e579c5ed1c2ebaced40abb713242ba7d1419b6e3d5d73fb0f619baed2c4108a1e27
7
+ data.tar.gz: f82167185a8430410817183d30b3c9032135b9bd9d65719a5e619d3bdc5a1088b2a3bc13f29442c035892ecf3e97e4848629fa0db56857fa299dc89ee367e9df
data/.gitignore ADDED
@@ -0,0 +1,53 @@
1
+ # rcov generated
2
+ coverage
3
+ coverage.data
4
+
5
+ # rdoc generated
6
+ rdoc
7
+
8
+ # yard generated
9
+ doc
10
+ .yardoc
11
+
12
+ # bundler
13
+ .bundle
14
+
15
+ # jeweler generated
16
+ pkg
17
+
18
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
19
+ #
20
+ # * Create a file at ~/.gitignore
21
+ # * Include files you want ignored
22
+ # * Run: git config --global core.excludesfile ~/.gitignore
23
+ #
24
+ # After doing this, these files will be ignored in all your git projects,
25
+ # saving you from having to 'pollute' every project you touch with them
26
+ #
27
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
28
+ #
29
+ # For MacOS:
30
+ #
31
+ #.DS_Store
32
+
33
+ # For TextMate
34
+ #*.tmproj
35
+ #tmtags
36
+
37
+ # For emacs:
38
+ #*~
39
+ #\#*
40
+ #.\#*
41
+
42
+ # For vim:
43
+ #*.swp
44
+
45
+ # For redcar:
46
+ #.redcar
47
+
48
+ # For rubinius:
49
+ #*.rbc
50
+
51
+ # For rvm:
52
+ .ruby-gemset
53
+ .ruby-version
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,60 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bb_analytics (0.0.1)
5
+ gli (= 2.9.0)
6
+ sqlite3
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ aruba (0.5.4)
12
+ childprocess (>= 0.3.6)
13
+ cucumber (>= 1.1.1)
14
+ rspec-expectations (>= 2.7.0)
15
+ builder (3.2.2)
16
+ childprocess (0.5.1)
17
+ ffi (~> 1.0, >= 1.0.11)
18
+ cucumber (1.3.11)
19
+ builder (>= 2.1.2)
20
+ diff-lcs (>= 1.1.3)
21
+ gherkin (~> 2.12)
22
+ multi_json (>= 1.7.5, < 2.0)
23
+ multi_test (>= 0.0.2)
24
+ diff-lcs (1.2.5)
25
+ docile (1.1.3)
26
+ ffi (1.9.3)
27
+ gherkin (2.12.2)
28
+ multi_json (~> 1.3)
29
+ gli (2.9.0)
30
+ json (1.8.1)
31
+ multi_json (1.8.4)
32
+ multi_test (0.0.3)
33
+ rake (10.1.1)
34
+ rdoc (4.1.1)
35
+ json (~> 1.4)
36
+ rspec (2.14.1)
37
+ rspec-core (~> 2.14.0)
38
+ rspec-expectations (~> 2.14.0)
39
+ rspec-mocks (~> 2.14.0)
40
+ rspec-core (2.14.8)
41
+ rspec-expectations (2.14.5)
42
+ diff-lcs (>= 1.1.3, < 2.0)
43
+ rspec-mocks (2.14.6)
44
+ simplecov (0.8.2)
45
+ docile (~> 1.1.0)
46
+ multi_json
47
+ simplecov-html (~> 0.8.0)
48
+ simplecov-html (0.8.0)
49
+ sqlite3 (1.3.9)
50
+
51
+ PLATFORMS
52
+ ruby
53
+
54
+ DEPENDENCIES
55
+ aruba
56
+ bb_analytics!
57
+ rake
58
+ rdoc
59
+ rspec
60
+ simplecov
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+
2
+ # bb_analytics
3
+
4
+ A simple baseball analytics tool built on top of the GLI platform, which mean it follows
5
+ the standard CLI pattern of taking commands (like git).
6
+
7
+ ## Install
8
+
9
+ ```shell
10
+ $ gem install bb_analytics
11
+ ```
12
+ bb_analytics requires sqlite3, so you'll have to meet the prerquisites for that install.
13
+
14
+ ## How-to
15
+
16
+ Typing `$ bb_analytics help` will render a list of commands and options:
17
+
18
+ ```shell
19
+ NAME
20
+ bb_analytics - A simple baseball analytics tool
21
+
22
+ SYNOPSIS
23
+ bb_analytics [global options] command [command options] [arguments...]
24
+
25
+ VERSION
26
+ 0.0.1
27
+
28
+ GLOBAL OPTIONS
29
+ --help - Show this message
30
+ --version - Display the program version
31
+
32
+ COMMANDS
33
+ clear - Clear all imported data
34
+ help - Shows a list of commands or help for one command
35
+ import - Import a data file
36
+ most_improved - List the most improved players for a supplied time period
37
+ team_slugging_percentage - Team slugging percentage
38
+ triple_crown_winner - Find the tripple crown winner for a given year
39
+ ```
40
+ Before querying for analytics, you'll have to import data from csv. The import command
41
+ tolerates csv files that define player identities and files that define yearly statistics.
42
+
43
+ For help with any command, just type `bb_analytics help <command name>`.
data/README.rdoc ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+ require 'cucumber'
6
+ require 'cucumber/rake/task'
7
+ Rake::RDocTask.new do |rd|
8
+ rd.main = "README.rdoc"
9
+ rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
10
+ rd.title = 'Your application title'
11
+ end
12
+
13
+ spec = eval(File.read('bb_analytics.gemspec'))
14
+
15
+ Gem::PackageTask.new(spec) do |pkg|
16
+ end
17
+
18
+ require 'rspec/core'
19
+ require 'rspec/core/rake_task'
20
+ RSpec::Core::RakeTask.new(:spec) do |spec|
21
+ spec.pattern = FileList['spec/**/*_spec.rb']
22
+ end
23
+
24
+ desc "Code coverage detail"
25
+ task :simplecov do
26
+ ENV['COVERAGE'] = "true"
27
+ Rake::Task['spec'].execute
28
+ end
29
+
30
+ task :default => :spec
@@ -0,0 +1,26 @@
1
+ # Ensure we require the local version and not one we might have installed already
2
+ require File.join([File.dirname(__FILE__),'lib','bb_analytics','version.rb'])
3
+ spec = Gem::Specification.new do |s|
4
+ s.name = 'bb_analytics'
5
+ s.version = BbAnalytics::VERSION
6
+ s.author = 'Kevin Beddingfield'
7
+ s.description = "a simple baseball analytics tool"
8
+ s.email = 'kevin.beddingfield@gmail.com'
9
+ s.homepage = 'http://mambasystems.net'
10
+ s.platform = Gem::Platform::RUBY
11
+ s.summary = 'A simple baseball analytics tool'
12
+ s.files = `git ls-files`.split(" ")
13
+ s.require_paths << 'lib'
14
+ s.has_rdoc = true
15
+ s.extra_rdoc_files = ['README.rdoc','bb_analytics.rdoc']
16
+ s.rdoc_options << '--title' << 'bb_analytics' << '--main' << 'README.rdoc' << '-ri'
17
+ s.bindir = 'bin'
18
+ s.executables << 'bb_analytics'
19
+ s.add_development_dependency('rake')
20
+ s.add_development_dependency('rdoc')
21
+ s.add_development_dependency('aruba')
22
+ s.add_development_dependency('rspec')
23
+ s.add_development_dependency('simplecov')
24
+ s.add_runtime_dependency('sqlite3')
25
+ s.add_runtime_dependency('gli','2.9.0')
26
+ end
data/bb_analytics.rdoc ADDED
@@ -0,0 +1,5 @@
1
+ = bb_analytics
2
+
3
+ Generate this with
4
+ bb_analytics rdoc
5
+ After you have described your command line interface
data/bin/bb_analytics ADDED
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+
4
+ =begin
5
+ begin # XXX: Remove this begin/rescue before distributing your app
6
+ require 'bb_analytics'
7
+ rescue LoadError
8
+ STDERR.puts "In development, you need to use `bundle exec bin/bb_analytics` to run your app"
9
+ STDERR.puts "At install-time, RubyGems will make sure lib, etc. are in the load path"
10
+ STDERR.puts "Feel free to remove this message from bin/bb_analytics now"
11
+ exit 64
12
+ end
13
+ =end
14
+
15
+ include GLI::App
16
+
17
+ program_desc 'A simple baseball analytics tool'
18
+
19
+ version BbAnalytics::VERSION
20
+
21
+ desc 'Import a data file'
22
+ arg_name '"file location"'
23
+ command :import do |c|
24
+ c.action do |global_options,options,args|
25
+ args.each do |arg|
26
+ puts "reading #{arg}"
27
+ importer = Importer.new(arg)
28
+
29
+ puts "loading players..."
30
+ importer.save_baseball_players
31
+
32
+ puts "checking for stats..."
33
+ importer.save_stats_for_year
34
+
35
+ puts "import of #{arg} complete!"
36
+ end
37
+ end
38
+ end
39
+
40
+ desc 'Clear all imported data'
41
+ command :clear do |c|
42
+ c.action do |global_options,options,args|
43
+ DataStore.instance.clear_data
44
+ puts "import data is cleared!"
45
+ end
46
+ end
47
+
48
+ desc 'Find the tripple crown winner for a given year'
49
+ command :triple_crown_winner do |c|
50
+ c.desc 'the year to evaluate'
51
+ c.default_value '2012'
52
+ c.arg_name 'year'
53
+ c.flag [:y,:year]
54
+ c.desc 'minimum at bats'
55
+ c.default_value '600'
56
+ c.arg_name 'min-at-bats'
57
+ c.flag [:'min-at-bats']
58
+ c.action do |global_options,options,args|
59
+ winner = StatsForYear.find_triple_crown_winner(options[:year], options[:'min-at-bats'])
60
+ if winner.nil?
61
+ puts "there was no triple crown winner in #{options[:year]}"
62
+ else
63
+ player = winner.baseball_player
64
+ puts "#{player.first_name} #{player.last_name} won the triple crown in #{options[:year]}"
65
+ end
66
+ end
67
+ end
68
+
69
+ desc 'List the most improved players for a supplied time period'
70
+ command :most_improved do |c|
71
+ c.desc 'accepted values are batting_average and fantasy_points'
72
+ c.default_value 'batting_average'
73
+ c.flag :category
74
+ c.desc 'starting year (inclusive)'
75
+ c.default_value '2009'
76
+ c.flag :starting_year
77
+ c.desc 'ending year (inclusive)'
78
+ c.default_value '2010'
79
+ c.flag :ending_year
80
+ c.action do |global_options,options,args|
81
+ if options[:category] == 'batting_average'
82
+ player_ids = StatsForYear.most_improved_batting_average options[:starting_year], options[:ending_year]
83
+ elsif options[:category] == 'fantasy_points'
84
+ player_ids = StatsForYear.most_improved_fantasy_points options[:starting_year], options[:ending_year]
85
+ else
86
+ puts 'Please specify a valid category (batting_average, fantasy_points)'
87
+ return
88
+ end
89
+ if player_ids
90
+ player_ids.each do |player_id|
91
+ player = BaseballPlayer.find_by_external_id player_id
92
+ puts "#{player.first_name} #{player.last_name}"
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ desc 'Team slugging percentage'
99
+ command :team_slugging_percentage do |c|
100
+ c.desc 'the year to evaluate'
101
+ c.default_value '2007'
102
+ c.arg_name 'year'
103
+ c.flag [:y,:year]
104
+ c.desc 'team abbreviation'
105
+ c.default_value 'OAK'
106
+ c.arg_name 'team'
107
+ c.flag [:'team']
108
+ c.action do |global_options,options,args|
109
+ teammates = StatsForYear.find_team_for_year options[:year], options[:team]
110
+ teammates.each do |teammate|
111
+ player = teammate.baseball_player
112
+ puts "#{player.first_name} #{player.last_name} - slugging percentage: #{'%.3f' % (teammate.slugging_percentage * 0.001)}" if teammate.slugging_percentage.present?
113
+ end
114
+ end
115
+ end
116
+
117
+ pre do |global,command,options,args|
118
+ Dir.mkdir("#{ENV['HOME']}/.bb_analytics") if !Dir.entries("#{ENV['HOME']}").include?('.bb_analytics');
119
+ true
120
+ end
121
+
122
+ post do |global,command,options,args|
123
+ # Post logic here
124
+ # Use skips_post before a command to skip this
125
+ # block on that command only
126
+ end
127
+
128
+ on_error do |exception|
129
+ true
130
+ end
131
+
132
+ exit run(ARGV)
@@ -0,0 +1,45 @@
1
+ class BaseballPlayer
2
+ attr_accessor :external_id, :birth_year, :first_name, :last_name
3
+
4
+ def save
5
+ # first see if we can update an existing record
6
+ DataStore.instance.db.execute("select * from baseball_players where external_id = ?",
7
+ [self.external_id]) do |row|
8
+ DataStore.instance.db.execute "update baseball_players set birth_year = ?, first_name = ?, last_name = ? where external_id = ?",
9
+ [(self.birth_year.present? ? self.birth_year : row[1]),
10
+ (self.first_name.present? ? self.first_name : row[2]),
11
+ (self.last_name.present? ? self.last_name : row[3]),
12
+ self.external_id]
13
+ return
14
+ end
15
+
16
+ # if not, just insert
17
+ DataStore.instance.db.execute "insert into baseball_players values (?,?,?,?)",
18
+ [self.external_id,
19
+ self.birth_year,
20
+ self.first_name,
21
+ self.last_name]
22
+ end
23
+
24
+ def reload
25
+ DataStore.instance.db.execute("select * from baseball_players where external_id = ?",
26
+ [self.external_id]) do |row|
27
+ self.birth_year = row[1]
28
+ self.first_name = row[2]
29
+ self.last_name = row[3]
30
+ end
31
+ self
32
+ end
33
+
34
+ def self.find_by_external_id external_id
35
+ player = BaseballPlayer.new
36
+ DataStore.instance.db.execute("select * from baseball_players where external_id = ?",
37
+ [external_id]) do |row|
38
+ player.external_id = row[0]
39
+ player.birth_year = row[1]
40
+ player.first_name = row[2]
41
+ player.last_name = row[3]
42
+ end
43
+ player
44
+ end
45
+ end
@@ -0,0 +1,61 @@
1
+ require 'sqlite3'
2
+ require 'singleton'
3
+
4
+ class DataStore
5
+ include Singleton
6
+
7
+ attr_accessor :db
8
+
9
+ def initialize
10
+ self.setup_db
11
+ end
12
+
13
+ def db=(db)
14
+ # try and create tables - will error if they exist (which is okay)
15
+ @db = db
16
+ begin
17
+ @db.execute <<-SQL
18
+ create table baseball_players (
19
+ external_id varchar(50),
20
+ birth_year int,
21
+ first_name varchar(50),
22
+ last_name varchar(50)
23
+ );
24
+ SQL
25
+ @db.execute <<-SQL
26
+ create table stats_for_years (
27
+ player_external_id varchar(50),
28
+ year int,
29
+ team varchar(3),
30
+ games int,
31
+ at_bats int,
32
+ runs int,
33
+ hits int,
34
+ doubles int,
35
+ triples int,
36
+ home_runs int,
37
+ runs_batted_in int,
38
+ stolen_bases int,
39
+ caught_stealing int,
40
+ batting_average int,
41
+ slugging_percentage int,
42
+ fantasy_points int
43
+ );
44
+ SQL
45
+ rescue
46
+ end
47
+ end
48
+
49
+ def clear_data
50
+ File.delete(db_location) rescue nil
51
+ #self.setup_db
52
+ end
53
+
54
+ def setup_db
55
+ self.db = SQLite3::Database.new self.db_location rescue nil
56
+ end
57
+
58
+ def db_location
59
+ "#{ENV['HOME']}/.bb_analytics/bba.db"
60
+ end
61
+ end
@@ -0,0 +1,58 @@
1
+ require 'csv'
2
+
3
+ class Importer
4
+ attr_accessor :csv
5
+
6
+ def initialize(csv_file=nil)
7
+ if csv_file
8
+ @csv ||= {}
9
+ CSV.foreach(csv_file, headers: true, header_converters: :symbol, converters: :all) do |row|
10
+ @csv[row.fields[0]] ||= []
11
+ @csv[row.fields[0]] << Hash[row.headers[1..-1].zip(row.fields[1..-1])]
12
+ end
13
+ end
14
+ end
15
+
16
+ def save_baseball_players
17
+ @csv.keys.map do |key|
18
+ csv[key].each do |bp|
19
+ player = BaseballPlayer.new
20
+ player.external_id = key
21
+ player.birth_year = bp[:birthyear]
22
+ player.first_name = bp[:namefirst]
23
+ player.last_name = bp[:namelast]
24
+ player.save
25
+ player
26
+ end
27
+ end
28
+ end
29
+
30
+ def save_stats_for_year
31
+ @csv.keys.each do |key|
32
+ csv[key].each do |year|
33
+ stats = StatsForYear.new
34
+ stats.player_external_id = key
35
+ stats.year = year[:yearid]
36
+ stats.team = year[:teamid]
37
+ stats.games = year[:g]
38
+ stats.at_bats = year[:ab]
39
+ stats.runs = year[:r]
40
+ stats.hits = year[:h]
41
+ stats.doubles = year[:'2b']
42
+ stats.triples = year[:'3b']
43
+ stats.home_runs = year[:hr]
44
+ stats.runs_batted_in = year[:rbi]
45
+ stats.stolen_bases = year[:sb]
46
+ stats.caught_stealing = year[:cs]
47
+
48
+ stats.calculate_batting_average!
49
+ stats.calculate_slugging_percentage!
50
+ stats.calculate_fantasy_points!
51
+
52
+ stats.save if stats.year.present?
53
+ stats
54
+ end
55
+ end
56
+ end
57
+
58
+ end