bb_analytics 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 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