codenamev-baseball-stats 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: e68b76699a7b187eca62f659bc71d0b31fb4ac06
4
+ data.tar.gz: 042a059cee664f3e48d39b540b99bd7299dba664
5
+ SHA512:
6
+ metadata.gz: dfb71a29b8e9f88d6d7dd382367204a2d3aa160613f80744adc4a7d298e0178a9220702ddaf4e0e6a1f6d7c2c6d04346d3a4ea8bf423524b1b7f8316bc376376
7
+ data.tar.gz: 8541554cefc58a772afd0ef0700e7c4004ca4ca00fc23f2ac9c52b9d0fbabfe3d50d28fe355518a82e3d3202b74fb8408eba73df631ab2369efb608300d40537
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ **/.~lock.*
2
+ **/.DS_STORE
3
+ *.gem
4
+ *.rbc
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
20
+ db/*.sqlite3
21
+ log/*.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in baseball-stats.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Valentino
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Valentino
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,32 @@
1
+ # BaseballStats
2
+
3
+ Baseball player statistical analysis
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'codenamev-baseball-stats'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install codenamev-baseball-stats
18
+
19
+ ## Usage
20
+
21
+ After installing the gem, running `baseball_stats` from the command-line will
22
+ display the results to the following excersize:
23
+
24
+ 1. Most improved batting average from 2009 to 2010
25
+ 2. Slugging percentage for all players on the Oakland A's in 2007
26
+ 3. Who was the AL and NL tripple crown winner for 2011 and 2012. If no one won
27
+ the crown should be "(No winner)"
28
+
29
+ ## NOTES
30
+
31
+ The first run of the command imports two fairly large CSV files with sample
32
+ data into an SQLite3 database. This may take up to 5 minutes depending on your machine.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+ require 'active_record'
5
+ require 'active_record_migrations'
6
+ require 'baseball_stats/database'
7
+
8
+ Dir[File.join(File.dirname(__FILE__),'lib/tasks/*.rake')].each { |f| load f }
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+ ActiveRecordMigrations.load_tasks
12
+
13
+ task :environment do
14
+ BaseballStats::Database.connection
15
+ end
16
+
17
+ task :default => [:spec]
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'baseball_stats/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "codenamev-baseball-stats"
8
+ spec.version = BaseballStats::VERSION
9
+ spec.authors = ["Valentino Stoll"]
10
+ spec.email = ["valentino@reenhanced.com"]
11
+ spec.description = %q{Generates baseball player statistics}
12
+ spec.summary = %q{Generates baseball player statistics}
13
+ spec.homepage = "https://github.com/codenamev/baseball-stats"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activerecord", "~> 4.1.6"
22
+ spec.add_dependency "active_record_migrations", "~> 4.1.6.1"
23
+ spec.add_dependency "colorize", "~> 0.7.3"
24
+ spec.add_dependency "sqlite3", "~> 1.3.9"
25
+ spec.add_dependency "table_print", "~> 1.1.5"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.3"
28
+ spec.add_development_dependency "database_cleaner"
29
+ spec.add_development_dependency "factory_girl"
30
+ spec.add_development_dependency "faker"
31
+ spec.add_development_dependency "pry"
32
+ spec.add_development_dependency "rake"
33
+ spec.add_development_dependency "rspec"
34
+ spec.add_development_dependency "shoulda-matchers"
35
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'baseball_stats'
4
+
5
+ puts "Analyzing sample data..."
6
+ BaseballStats.seed_data
7
+
8
+ puts "1) Most improved batting average from 2009 to 2010: ".colorize(:green)
9
+ puts "\t#{BaseballStats.most_improved_player(2010)}\n"
10
+
11
+ puts "2) Slugging percentage for all players on the Oakland A's in 2007:".colorize(:green)
12
+ tp BaseballStats.slugging_percentage_for_team_and_year('OAK', 2007)
13
+
14
+ puts "\n3) AL Tripple crown winner for 2011: ".colorize(:green)
15
+ puts "\t#{BaseballStats.tripple_crown_winner(2011, 'AL')}\n"
16
+
17
+ puts "\n3) AL Tripple crown winner for 2012: ".colorize(:green)
18
+ puts "\t#{BaseballStats.tripple_crown_winner(2012, 'AL')}\n"
19
+
20
+ puts "\n3) NL Tripple crown winner for 2011: ".colorize(:green)
21
+ puts "\t#{BaseballStats.tripple_crown_winner(2011, 'NL')}\n"
22
+
23
+ puts "\n3) NL Tripple crown winner for 2012: ".colorize(:green)
24
+ puts "\t#{BaseballStats.tripple_crown_winner(2012, 'NL')}\n"
data/db/config.yml ADDED
@@ -0,0 +1,12 @@
1
+ all: &all
2
+ adapter: sqlite3
3
+ pool: 5
4
+ timeout: 5000
5
+
6
+ development:
7
+ <<: *all
8
+ database: db/development.sqlite3
9
+
10
+ test:
11
+ <<: *all
12
+ database: db/test.sqlite3
@@ -0,0 +1,27 @@
1
+ class CreateBattings < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :battings do |t|
4
+ t.string :player_id
5
+ t.integer :year_id
6
+ t.string :league
7
+ t.string :team_id
8
+ t.string :appearances
9
+ t.integer :at_bats
10
+ t.integer :runs_scored
11
+ t.integer :hits
12
+ t.integer :doubles
13
+ t.integer :triples
14
+ t.integer :home_runs
15
+ t.integer :runs_batted_in
16
+ t.integer :stolen_bases
17
+ t.integer :times_caught_stealing
18
+ end
19
+
20
+ add_index :battings, :player_id
21
+ add_index :battings, :year_id
22
+ end
23
+
24
+ def self.down
25
+ drop_table :battings
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ class CreatePlayers < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :players do |t|
4
+ t.string :player_id
5
+ t.integer :birth_year
6
+ t.string :first_name
7
+ t.string :last_name
8
+ end
9
+
10
+ add_index :players, :player_id
11
+ end
12
+
13
+ def self.down
14
+ drop_table :players
15
+ end
16
+ end
data/db/schema.rb ADDED
@@ -0,0 +1,45 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 20141029204424) do
15
+
16
+ create_table "battings", force: true do |t|
17
+ t.string "player_id"
18
+ t.integer "year_id"
19
+ t.string "league"
20
+ t.string "team_id"
21
+ t.string "appearances"
22
+ t.integer "at_bats"
23
+ t.integer "runs_scored"
24
+ t.integer "hits"
25
+ t.integer "doubles"
26
+ t.integer "triples"
27
+ t.integer "home_runs"
28
+ t.integer "runs_batted_in"
29
+ t.integer "stolen_bases"
30
+ t.integer "times_caught_stealing"
31
+ end
32
+
33
+ add_index "battings", ["player_id"], name: "index_battings_on_player_id"
34
+ add_index "battings", ["year_id"], name: "index_battings_on_year_id"
35
+
36
+ create_table "players", force: true do |t|
37
+ t.string "player_id"
38
+ t.integer "birth_year"
39
+ t.string "first_name"
40
+ t.string "last_name"
41
+ end
42
+
43
+ add_index "players", ["player_id"], name: "index_players_on_player_id"
44
+
45
+ end
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+ require 'sqlite3'
4
+ require 'colorize'
5
+ require 'table_print'
6
+
7
+ require "baseball_stats/database"
8
+ require "baseball_stats/batting"
9
+ require "baseball_stats/player"
10
+ require "baseball_stats/import"
11
+ require "baseball_stats/version"
12
+
13
+ module BaseballStats
14
+ include Import
15
+ include Database
16
+
17
+ extend self
18
+
19
+ def most_improved_player(year)
20
+ battings_for_year = Batting.with_batting_average.where('year_id = ? AND at_bats >= 200', year).order(player_id: :asc)
21
+ battings_for_previous_year = Batting.with_batting_average.where('year_id = ? AND at_bats >= 200', year-1).order(player_id: :asc)
22
+
23
+ most_improved_batting_average = 0.0
24
+ most_improved_player = nil
25
+
26
+ battings_for_year.each do |batting|
27
+ next unless prev_year_batting = battings_for_previous_year.where(player_id: batting.player_id).first
28
+ improvement = batting.batting_average - prev_year_batting.batting_average
29
+ next unless improvement > most_improved_batting_average
30
+ most_improved_batting_average = batting.batting_average
31
+ most_improved_player = batting.player_id
32
+ end
33
+
34
+ Player.where(player_id: most_improved_player).first
35
+ end
36
+
37
+ def slugging_percentage_for_team_and_year(team_id, year)
38
+ battings_for_team = Batting.includes(:player).with_slugging_percentage.where(team_id: team_id, year_id: year)
39
+ battings_for_team.collect {|batting|
40
+ { player: batting.player_name, slugging_percentage: "#{(batting.slugging_percentage.to_f * 100).round(2)}%" }
41
+ }
42
+ end
43
+
44
+ def tripple_crown_winner(year, league)
45
+ highest_batting_average = Batting.with_batting_average.tripple_crown_eligible.where(year_id: year, league: league).order('batting_average DESC').first
46
+ most_home_runs = Batting.tripple_crown_eligible.where(year_id: year, league: league).order(home_runs: :desc).first
47
+ most_rbis = Batting.tripple_crown_eligible.where(year_id: year, league: league).order(runs_batted_in: :desc).first
48
+
49
+ if highest_batting_average and most_home_runs and most_rbis and
50
+ highest_batting_average.player_id == most_home_runs.player_id and highest_batting_average.player_id == most_rbis.player_id
51
+ most_rbis.player
52
+ else
53
+ '(No winner)'
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,16 @@
1
+ require 'baseball_stats/database'
2
+
3
+ module BaseballStats
4
+ @connection = Database.connection
5
+
6
+ class Batting < ::ActiveRecord::Base
7
+ self.table_name = 'battings'
8
+
9
+ belongs_to :player, primary_key: :player_id
10
+ delegate :name, to: :player, prefix: true, allow_nil: true
11
+
12
+ scope :tripple_crown_eligible, -> { where('battings.at_bats >= 400') }
13
+ scope :with_batting_average, -> { select('battings.*, ((battings.hits * 1.0) / battings.at_bats) AS batting_average') }
14
+ scope :with_slugging_percentage, -> { select('battings.*, ((((battings.hits - battings.doubles - battings.triples - battings.home_runs) + (2*battings.doubles) + (3*battings.triples) + (4*battings.home_runs))* 1.0) / battings.at_bats) AS slugging_percentage') }
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+ require 'sqlite3'
4
+ require 'logger'
5
+ require 'yaml'
6
+
7
+ module BaseballStats
8
+ module Database
9
+ include ActiveRecord::Tasks
10
+
11
+ DEFAULT_ENV = "development".freeze
12
+
13
+ @env = nil
14
+ @logger = nil
15
+ @connection = nil
16
+ @configuration = YAML::load(IO.read('db/config.yml')).freeze
17
+ @root_path = File.expand_path('../../..', __FILE__).freeze
18
+ @db_dir = File.join(@root_path, 'db').freeze
19
+ @migrations_paths = [File.join(@root_path, 'db/migrate')].freeze
20
+
21
+ attr_accessor :configuration, :db_dir, :migrations_paths
22
+
23
+ extend self
24
+
25
+ def env
26
+ @env = ENV['APP_ENV'] || DEFAULT_ENV
27
+ end
28
+
29
+ def connection
30
+ ::ActiveRecord::Base.logger = Logger.new("log/#{self.env}.log")
31
+ ::ActiveRecord::Base.establish_connection(configuration[self.env])
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'csv'
4
+ require "baseball_stats/batting"
5
+ require "baseball_stats/player"
6
+
7
+ # Require all migration files
8
+ Dir[File.expand_path('../../../db/migrate/*.rb', __FILE__)].each {|f| require f }
9
+
10
+ module BaseballStats::Import
11
+ extend self
12
+
13
+ SEED_BATTINGS_CSV = File.expand_path('../../../sample_data/battings.csv', __FILE__)
14
+ SEED_PLAYERS_CSV = File.expand_path('../../../sample_data/players.csv', __FILE__)
15
+
16
+ def seed_data
17
+ import_battings_from_csv(SEED_BATTINGS_CSV)
18
+ import_players_from_csv(SEED_PLAYERS_CSV)
19
+ end
20
+
21
+ def import_battings_from_csv(csv_file)
22
+ CreateBattings.up unless ActiveRecord::Base.connection.table_exists?('battings')
23
+ CSV.foreach(csv_file, headers: true, header_converters: :symbol) do |batting|
24
+ new_batting = BaseballStats::Batting.find_or_create_by(player_id: batting[:player_id], year_id: batting[:year_id])
25
+ new_batting.league = batting[:league]
26
+ new_batting.team_id = batting[:team_id]
27
+ new_batting.appearances = batting[:appearances]
28
+ new_batting.at_bats = batting[:at_bats]
29
+ new_batting.runs_scored = batting[:runs_scored]
30
+ new_batting.hits = batting[:hits]
31
+ new_batting.doubles = batting[:doubles]
32
+ new_batting.triples = batting[:triples]
33
+ new_batting.home_runs = batting[:home_runs]
34
+ new_batting.runs_batted_in = batting[:runs_batted_in]
35
+ new_batting.stolen_bases = batting[:stolen_bases]
36
+ new_batting.times_caught_stealing = batting[:times_caught_stealing]
37
+ new_batting.save!
38
+ end
39
+ end
40
+
41
+ def import_players_from_csv(csv_file)
42
+ CreatePlayers.up unless ActiveRecord::Base.connection.table_exists?('players')
43
+ CSV.foreach(csv_file, headers: true, header_converters: :symbol) do |player|
44
+ new_player = BaseballStats::Player.find_or_create_by(player_id: player[:player_id])
45
+ new_player.birth_year = player[:birth_year]
46
+ new_player.first_name = player[:name_first]
47
+ new_player.last_name = player[:name_last]
48
+ new_player.save!
49
+ end
50
+ end
51
+ end