mlb 0.9.0 → 0.11.0
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 +4 -4
- data/CHANGELOG.md +22 -1
- data/LICENSE.txt +1 -1
- data/README.md +329 -32
- data/lib/mlb/affiliates.rb +28 -0
- data/lib/mlb/alumni.rb +30 -0
- data/lib/mlb/attendance.rb +28 -0
- data/lib/mlb/attendance_record.rb +157 -0
- data/lib/mlb/award.rb +126 -0
- data/lib/mlb/awards.rb +32 -0
- data/lib/mlb/baseball_stat.rb +65 -0
- data/lib/mlb/baseball_stats.rb +12 -0
- data/lib/mlb/boxscore.rb +81 -0
- data/lib/mlb/boxscore_team_stats.rb +210 -0
- data/lib/mlb/client.rb +71 -1
- data/lib/mlb/coaches.rb +28 -0
- data/lib/mlb/code_description_type.rb +45 -0
- data/lib/mlb/collection.rb +48 -0
- data/lib/mlb/comparable_by_attribute.rb +56 -0
- data/lib/mlb/conference.rb +39 -0
- data/lib/mlb/conferences.rb +33 -0
- data/lib/mlb/connection.rb +130 -7
- data/lib/mlb/context_metrics.rb +90 -0
- data/lib/mlb/division.rb +26 -6
- data/lib/mlb/divisions.rb +24 -18
- data/lib/mlb/draft.rb +83 -0
- data/lib/mlb/draft_pick.rb +155 -0
- data/lib/mlb/error_handler.rb +21 -1
- data/lib/mlb/errors/bad_gateway.rb +6 -1
- data/lib/mlb/errors/bad_request.rb +1 -0
- data/lib/mlb/errors/client_error.rb +1 -0
- data/lib/mlb/errors/connection_exception.rb +1 -0
- data/lib/mlb/errors/error.rb +1 -0
- data/lib/mlb/errors/forbidden.rb +1 -0
- data/lib/mlb/errors/gateway_timeout.rb +6 -1
- data/lib/mlb/errors/gone.rb +1 -0
- data/lib/mlb/errors/http_error.rb +22 -2
- data/lib/mlb/errors/internal_server_error.rb +1 -0
- data/lib/mlb/errors/network_error.rb +6 -1
- data/lib/mlb/errors/not_acceptable.rb +1 -0
- data/lib/mlb/errors/not_found.rb +1 -0
- data/lib/mlb/errors/payload_too_large.rb +1 -0
- data/lib/mlb/errors/retryable.rb +15 -0
- data/lib/mlb/errors/server_error.rb +1 -0
- data/lib/mlb/errors/service_unavailable.rb +6 -1
- data/lib/mlb/errors/too_many_redirects.rb +1 -0
- data/lib/mlb/errors/too_many_requests.rb +6 -1
- data/lib/mlb/errors/unauthorized.rb +1 -0
- data/lib/mlb/errors/unprocessable_entity.rb +1 -0
- data/lib/mlb/event_type.rb +61 -0
- data/lib/mlb/event_types.rb +12 -0
- data/lib/mlb/free_agent.rb +78 -0
- data/lib/mlb/free_agents.rb +34 -0
- data/lib/mlb/game_changes.rb +87 -0
- data/lib/mlb/game_content.rb +251 -0
- data/lib/mlb/game_data.rb +155 -0
- data/lib/mlb/game_pace.rb +173 -0
- data/lib/mlb/game_status.rb +94 -0
- data/lib/mlb/game_statuses.rb +12 -0
- data/lib/mlb/game_type.rb +98 -0
- data/lib/mlb/game_types.rb +12 -0
- data/lib/mlb/handedness.rb +30 -9
- data/lib/mlb/high_low.rb +121 -0
- data/lib/mlb/hit_trajectories.rb +12 -0
- data/lib/mlb/hit_trajectory.rb +6 -0
- data/lib/mlb/home_run_derby.rb +285 -0
- data/lib/mlb/id_description_type.rb +44 -0
- data/lib/mlb/inning_score.rb +87 -0
- data/lib/mlb/job.rb +58 -0
- data/lib/mlb/job_type.rb +39 -0
- data/lib/mlb/job_types.rb +12 -0
- data/lib/mlb/jobs.rb +87 -0
- data/lib/mlb/language.rb +48 -0
- data/lib/mlb/languages.rb +12 -0
- data/lib/mlb/leader.rb +79 -0
- data/lib/mlb/leaders.rb +68 -0
- data/lib/mlb/league.rb +97 -14
- data/lib/mlb/league_leader_type.rb +21 -0
- data/lib/mlb/league_leader_types.rb +12 -0
- data/lib/mlb/leagues.rb +24 -18
- data/lib/mlb/linescore.rb +342 -0
- data/lib/mlb/linescore_teams.rb +89 -0
- data/lib/mlb/live_feed.rb +130 -0
- data/lib/mlb/logical_event.rb +17 -0
- data/lib/mlb/logical_events.rb +12 -0
- data/lib/mlb/metric.rb +48 -0
- data/lib/mlb/metrics.rb +12 -0
- data/lib/mlb/people_changes.rb +34 -0
- data/lib/mlb/personnel.rb +28 -0
- data/lib/mlb/pitch_code.rb +90 -0
- data/lib/mlb/pitch_codes.rb +12 -0
- data/lib/mlb/pitch_type.rb +6 -0
- data/lib/mlb/pitch_types.rb +12 -0
- data/lib/mlb/platform.rb +30 -0
- data/lib/mlb/platforms.rb +12 -0
- data/lib/mlb/play.rb +300 -0
- data/lib/mlb/play_by_play.rb +52 -0
- data/lib/mlb/player.rb +186 -0
- data/lib/mlb/player_game_stats.rb +350 -0
- data/lib/mlb/player_stat.rb +70 -0
- data/lib/mlb/players.rb +42 -11
- data/lib/mlb/position.rb +68 -0
- data/lib/mlb/positions.rb +12 -0
- data/lib/mlb/postseason_schedule.rb +41 -0
- data/lib/mlb/postseason_series.rb +54 -0
- data/lib/mlb/redirect_handler.rb +80 -21
- data/lib/mlb/request_builder.rb +33 -2
- data/lib/mlb/review_reason.rb +6 -0
- data/lib/mlb/review_reasons.rb +12 -0
- data/lib/mlb/roster.rb +16 -12
- data/lib/mlb/roster_entry.rb +38 -0
- data/lib/mlb/roster_type.rb +39 -0
- data/lib/mlb/roster_types.rb +12 -0
- data/lib/mlb/schedule.rb +33 -0
- data/lib/mlb/schedule_date.rb +37 -0
- data/lib/mlb/schedule_event_type.rb +25 -0
- data/lib/mlb/schedule_event_types.rb +12 -0
- data/lib/mlb/scheduled_game.rb +321 -0
- data/lib/mlb/season.rb +74 -0
- data/lib/mlb/season_date_info.rb +4 -0
- data/lib/mlb/seasons.rb +36 -0
- data/lib/mlb/single_team_stats.rb +33 -0
- data/lib/mlb/situation_code.rb +116 -0
- data/lib/mlb/situation_codes.rb +12 -0
- data/lib/mlb/skies.rb +12 -0
- data/lib/mlb/sky.rb +6 -0
- data/lib/mlb/sport.rb +18 -5
- data/lib/mlb/sport_players.rb +30 -0
- data/lib/mlb/sports.rb +17 -7
- data/lib/mlb/standings.rb +47 -0
- data/lib/mlb/standings_record.rb +108 -0
- data/lib/mlb/standings_type.rb +25 -0
- data/lib/mlb/standings_types.rb +12 -0
- data/lib/mlb/stat_group.rb +21 -0
- data/lib/mlb/stat_groups.rb +12 -0
- data/lib/mlb/stat_type.rb +21 -0
- data/lib/mlb/stat_types.rb +12 -0
- data/lib/mlb/stat_values.rb +158 -0
- data/lib/mlb/stats.rb +41 -0
- data/lib/mlb/status.rb +17 -0
- data/lib/mlb/streaks.rb +184 -0
- data/lib/mlb/team.rb +66 -7
- data/lib/mlb/team_history.rb +28 -0
- data/lib/mlb/team_leader.rb +59 -0
- data/lib/mlb/team_leaders.rb +45 -0
- data/lib/mlb/team_record.rb +285 -0
- data/lib/mlb/team_stat.rb +50 -0
- data/lib/mlb/team_stats.rb +52 -0
- data/lib/mlb/teams.rb +28 -18
- data/lib/mlb/tied_games.rb +32 -0
- data/lib/mlb/transaction.rb +128 -0
- data/lib/mlb/transactions.rb +11 -6
- data/lib/mlb/uniforms.rb +97 -0
- data/lib/mlb/utils.rb +45 -0
- data/lib/mlb/venue.rb +10 -0
- data/lib/mlb/venues.rb +28 -18
- data/lib/mlb/version.rb +2 -1
- data/lib/mlb/win_probability.rb +64 -0
- data/lib/mlb/wind_direction.rb +6 -0
- data/lib/mlb/wind_directions.rb +12 -0
- data/lib/mlb.rb +64 -0
- data/sig/equalizer.rbs +3 -0
- data/sig/mlb.rbs +1972 -103
- data/sig/shale.rbs +29 -0
- metadata +137 -14
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require "equalizer"
|
|
2
|
+
require "shale"
|
|
3
|
+
|
|
4
|
+
module MLB
|
|
5
|
+
# Base class for simple code/description value objects from the MLB Stats API.
|
|
6
|
+
# These represent enumerated types that consist of a code identifier and
|
|
7
|
+
# human-readable description (e.g., pitch types, wind directions, sky conditions).
|
|
8
|
+
#
|
|
9
|
+
# @api private
|
|
10
|
+
# @abstract Subclass and define specific domain semantics
|
|
11
|
+
class CodeDescriptionType < Shale::Mapper
|
|
12
|
+
include Equalizer.new(:code)
|
|
13
|
+
|
|
14
|
+
# @!attribute [rw] code
|
|
15
|
+
# Returns the type code identifier
|
|
16
|
+
# @api public
|
|
17
|
+
# @example
|
|
18
|
+
# instance.code #=> "SL"
|
|
19
|
+
# @return [String] the type code identifier
|
|
20
|
+
attribute :code, Shale::Type::String
|
|
21
|
+
|
|
22
|
+
# @!attribute [rw] description
|
|
23
|
+
# Returns the human-readable description
|
|
24
|
+
# @api public
|
|
25
|
+
# @example
|
|
26
|
+
# instance.description #=> "Slider"
|
|
27
|
+
# @return [String] the human-readable description
|
|
28
|
+
attribute :description, Shale::Type::String
|
|
29
|
+
|
|
30
|
+
json do
|
|
31
|
+
map "code", to: :code
|
|
32
|
+
map "description", to: :description
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Returns a string representation of the object
|
|
36
|
+
#
|
|
37
|
+
# @api public
|
|
38
|
+
# @example
|
|
39
|
+
# pitch_type.to_s #=> "SL (Slider)"
|
|
40
|
+
# @return [String] string representation
|
|
41
|
+
def to_s
|
|
42
|
+
"#{code} (#{description})"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "shale"
|
|
2
|
+
|
|
3
|
+
module MLB
|
|
4
|
+
# Base class for simple collection endpoints that only need an .all method.
|
|
5
|
+
# Provides a class macro to define the endpoint, item type, and attribute name,
|
|
6
|
+
# eliminating repetitive boilerplate across 20+ similar collection classes.
|
|
7
|
+
#
|
|
8
|
+
# @api private
|
|
9
|
+
class Collection < Shale::Mapper
|
|
10
|
+
class << self
|
|
11
|
+
# Returns the API endpoint for this collection
|
|
12
|
+
#
|
|
13
|
+
# @api private
|
|
14
|
+
# @return [String] the API endpoint
|
|
15
|
+
attr_reader :endpoint
|
|
16
|
+
|
|
17
|
+
# Returns the collection attribute name
|
|
18
|
+
#
|
|
19
|
+
# @api private
|
|
20
|
+
# @return [Symbol] the collection attribute name
|
|
21
|
+
attr_reader :collection_name
|
|
22
|
+
|
|
23
|
+
# Configures the collection with endpoint and item type
|
|
24
|
+
#
|
|
25
|
+
# @api private
|
|
26
|
+
# @param endpoint [String] the API endpoint to fetch from
|
|
27
|
+
# @param item_type [Class] the Shale::Mapper class for individual items
|
|
28
|
+
# @param collection_name [Symbol] the attribute name for the collection
|
|
29
|
+
# @return [void]
|
|
30
|
+
def collection(endpoint:, item_type:, collection_name:)
|
|
31
|
+
@endpoint = endpoint
|
|
32
|
+
@collection_name = collection_name
|
|
33
|
+
attribute collection_name, item_type, collection: true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Retrieves all items from this collection
|
|
37
|
+
#
|
|
38
|
+
# @api public
|
|
39
|
+
# @example
|
|
40
|
+
# MLB::Sports.all #=> [#<MLB::Sport id=1 name="Major League Baseball">, ...]
|
|
41
|
+
# @return [Array] the list of items
|
|
42
|
+
def all
|
|
43
|
+
response = CLIENT.get(endpoint)
|
|
44
|
+
from_json("{\"#{collection_name}\":#{response}}").public_send(collection_name)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module MLB
|
|
2
|
+
# Provides comparison behavior for model classes by a specified attribute.
|
|
3
|
+
# Handles nil values gracefully by placing them at the end when sorting.
|
|
4
|
+
#
|
|
5
|
+
# @api private
|
|
6
|
+
# @example
|
|
7
|
+
# class Award < Shale::Mapper
|
|
8
|
+
# include Comparable
|
|
9
|
+
# include MLB::ComparableByAttribute
|
|
10
|
+
#
|
|
11
|
+
# def comparable_attribute = :sort_order
|
|
12
|
+
# end
|
|
13
|
+
module ComparableByAttribute
|
|
14
|
+
# Compares this object with another by the comparable attribute
|
|
15
|
+
#
|
|
16
|
+
# @api public
|
|
17
|
+
# @example
|
|
18
|
+
# award1 <=> award2 #=> -1
|
|
19
|
+
# @param other [Object] the object to compare with
|
|
20
|
+
# @return [Integer, nil] -1, 0, 1, or nil if not comparable
|
|
21
|
+
def <=>(other)
|
|
22
|
+
return nil unless other.is_a?(self.class) || is_a?(other.class)
|
|
23
|
+
|
|
24
|
+
compare_values(
|
|
25
|
+
public_send(comparable_attribute),
|
|
26
|
+
other.public_send(comparable_attribute)
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# Returns the attribute name used for comparison
|
|
33
|
+
#
|
|
34
|
+
# @api private
|
|
35
|
+
# @abstract Override in including class
|
|
36
|
+
# @return [Symbol] the attribute name
|
|
37
|
+
def comparable_attribute
|
|
38
|
+
raise NotImplementedError
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Compares two values, treating nil as greater than any value
|
|
42
|
+
#
|
|
43
|
+
# @api private
|
|
44
|
+
# @param self_val [Object, nil] the value from self
|
|
45
|
+
# @param other_val [Object, nil] the value from other
|
|
46
|
+
# @return [Integer] -1, 0, or 1
|
|
47
|
+
def compare_values(self_val, other_val)
|
|
48
|
+
case [self_val, other_val]
|
|
49
|
+
in [nil, nil] then 0
|
|
50
|
+
in [nil, _] then 1
|
|
51
|
+
in [_, nil] then -1
|
|
52
|
+
else self_val <=> other_val
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "equalizer"
|
|
2
|
+
require "shale"
|
|
3
|
+
require_relative "league"
|
|
4
|
+
require_relative "sport"
|
|
5
|
+
|
|
6
|
+
module MLB
|
|
7
|
+
# Represents a conference
|
|
8
|
+
class Conference < Shale::Mapper
|
|
9
|
+
include Equalizer.new(:id)
|
|
10
|
+
|
|
11
|
+
attribute :id, Shale::Type::Integer
|
|
12
|
+
attribute :name, Shale::Type::String
|
|
13
|
+
attribute :link, Shale::Type::String
|
|
14
|
+
attribute :abbreviation, Shale::Type::String
|
|
15
|
+
attribute :has_wildcard, Shale::Type::Boolean
|
|
16
|
+
attribute :league, League
|
|
17
|
+
attribute :sport, Sport
|
|
18
|
+
attribute :name_short, Shale::Type::String
|
|
19
|
+
|
|
20
|
+
# Checks if the conference has a wildcard
|
|
21
|
+
#
|
|
22
|
+
# @api public
|
|
23
|
+
# @example
|
|
24
|
+
# conference.wildcard? #=> true
|
|
25
|
+
# @return [Boolean] whether the conference has a wildcard
|
|
26
|
+
def wildcard? = has_wildcard
|
|
27
|
+
|
|
28
|
+
json do
|
|
29
|
+
map "id", to: :id
|
|
30
|
+
map "name", to: :name
|
|
31
|
+
map "link", to: :link
|
|
32
|
+
map "abbreviation", to: :abbreviation
|
|
33
|
+
map "hasWildcard", to: :has_wildcard
|
|
34
|
+
map "league", to: :league
|
|
35
|
+
map "sport", to: :sport
|
|
36
|
+
map "nameShort", to: :name_short
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require "shale"
|
|
2
|
+
require_relative "conference"
|
|
3
|
+
|
|
4
|
+
module MLB
|
|
5
|
+
# Collection of conferences from the MLB Stats API
|
|
6
|
+
class Conferences < Shale::Mapper
|
|
7
|
+
attribute :conferences, Conference, collection: true
|
|
8
|
+
|
|
9
|
+
# Retrieves all conferences
|
|
10
|
+
#
|
|
11
|
+
# @api public
|
|
12
|
+
# @example
|
|
13
|
+
# MLB::Conferences.all
|
|
14
|
+
# @return [Array<Conference>] list of all conferences
|
|
15
|
+
def self.all
|
|
16
|
+
response = CLIENT.get("conferences")
|
|
17
|
+
from_json(response).conferences
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Finds a conference by ID
|
|
21
|
+
#
|
|
22
|
+
# @api public
|
|
23
|
+
# @example
|
|
24
|
+
# MLB::Conferences.find(301)
|
|
25
|
+
# @param conference [Integer, Conference] the conference ID or Conference object
|
|
26
|
+
# @return [Conference, nil] the conference if found
|
|
27
|
+
def self.find(conference)
|
|
28
|
+
params = {conferenceId: Utils.extract_id(conference)}
|
|
29
|
+
response = CLIENT.get("conferences?#{Utils.build_query(params)}")
|
|
30
|
+
from_json(response).conferences.first
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/mlb/connection.rb
CHANGED
|
@@ -5,15 +5,25 @@ require "uri"
|
|
|
5
5
|
require_relative "errors/network_error"
|
|
6
6
|
|
|
7
7
|
module MLB
|
|
8
|
+
# Manages HTTP connections to the MLB Stats API
|
|
8
9
|
class Connection
|
|
9
10
|
extend Forwardable
|
|
10
11
|
|
|
12
|
+
# Default host for API requests
|
|
11
13
|
DEFAULT_HOST = "statsapi.mlb.com".freeze
|
|
14
|
+
# Default port for HTTPS connections
|
|
12
15
|
DEFAULT_PORT = 443
|
|
16
|
+
# Default connection open timeout in seconds
|
|
13
17
|
DEFAULT_OPEN_TIMEOUT = 60 # seconds
|
|
18
|
+
# Default read timeout in seconds
|
|
14
19
|
DEFAULT_READ_TIMEOUT = 60 # seconds
|
|
20
|
+
# Default write timeout in seconds
|
|
15
21
|
DEFAULT_WRITE_TIMEOUT = 60 # seconds
|
|
22
|
+
# Default debug output destination
|
|
16
23
|
DEFAULT_DEBUG_OUTPUT = File.open(File::NULL, "w")
|
|
24
|
+
# HTTPS scheme identifier
|
|
25
|
+
HTTPS_SCHEME = "https".freeze
|
|
26
|
+
# Network errors that trigger a NetworkError exception
|
|
17
27
|
NETWORK_ERRORS = [
|
|
18
28
|
Errno::ECONNREFUSED,
|
|
19
29
|
Errno::ECONNRESET,
|
|
@@ -22,33 +32,135 @@ module MLB
|
|
|
22
32
|
OpenSSL::SSL::SSLError
|
|
23
33
|
].freeze
|
|
24
34
|
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
# Returns the connection open timeout in seconds
|
|
36
|
+
#
|
|
37
|
+
# @api public
|
|
38
|
+
# @example
|
|
39
|
+
# connection.open_timeout #=> 60
|
|
40
|
+
# @return [Integer] the connection open timeout in seconds
|
|
41
|
+
attr_accessor :open_timeout
|
|
42
|
+
|
|
43
|
+
# @!method open_timeout=(value)
|
|
44
|
+
# Sets the connection open timeout in seconds
|
|
45
|
+
# @api public
|
|
46
|
+
# @example
|
|
47
|
+
# connection.open_timeout = 30
|
|
48
|
+
# @param value [Integer] the timeout in seconds
|
|
49
|
+
# @return [Integer] the timeout in seconds
|
|
50
|
+
|
|
51
|
+
# Returns the read timeout in seconds
|
|
52
|
+
#
|
|
53
|
+
# @api public
|
|
54
|
+
# @example
|
|
55
|
+
# connection.read_timeout #=> 60
|
|
56
|
+
# @return [Integer] the read timeout in seconds
|
|
57
|
+
attr_accessor :read_timeout
|
|
58
|
+
|
|
59
|
+
# @!method read_timeout=(value)
|
|
60
|
+
# Sets the read timeout in seconds
|
|
61
|
+
# @api public
|
|
62
|
+
# @example
|
|
63
|
+
# connection.read_timeout = 30
|
|
64
|
+
# @param value [Integer] the timeout in seconds
|
|
65
|
+
# @return [Integer] the timeout in seconds
|
|
66
|
+
|
|
67
|
+
# Returns the write timeout in seconds
|
|
68
|
+
#
|
|
69
|
+
# @api public
|
|
70
|
+
# @example
|
|
71
|
+
# connection.write_timeout #=> 60
|
|
72
|
+
# @return [Integer] the write timeout in seconds
|
|
73
|
+
attr_accessor :write_timeout
|
|
74
|
+
|
|
75
|
+
# @!method write_timeout=(value)
|
|
76
|
+
# Sets the write timeout in seconds
|
|
77
|
+
# @api public
|
|
78
|
+
# @example
|
|
79
|
+
# connection.write_timeout = 30
|
|
80
|
+
# @param value [Integer] the timeout in seconds
|
|
81
|
+
# @return [Integer] the timeout in seconds
|
|
82
|
+
|
|
83
|
+
# Returns the IO object for debug output
|
|
84
|
+
#
|
|
85
|
+
# @api public
|
|
86
|
+
# @example
|
|
87
|
+
# connection.debug_output #=> #<File:/dev/null>
|
|
88
|
+
# @return [IO] the IO object for debug output
|
|
89
|
+
attr_accessor :debug_output
|
|
90
|
+
|
|
91
|
+
# @!method debug_output=(value)
|
|
92
|
+
# Sets the IO object for debug output
|
|
93
|
+
# @api public
|
|
94
|
+
# @example
|
|
95
|
+
# connection.debug_output = $stderr
|
|
96
|
+
# @param value [IO] the IO object for debug output
|
|
97
|
+
# @return [IO] the IO object for debug output
|
|
98
|
+
|
|
99
|
+
# Returns the proxy URL
|
|
100
|
+
#
|
|
101
|
+
# @api public
|
|
102
|
+
# @example
|
|
103
|
+
# connection.proxy_url #=> "http://proxy.example.com:8080"
|
|
104
|
+
# @return [String, nil] the proxy URL
|
|
105
|
+
attr_reader :proxy_url
|
|
106
|
+
|
|
107
|
+
# Returns the parsed proxy URI
|
|
108
|
+
#
|
|
109
|
+
# @api public
|
|
110
|
+
# @example
|
|
111
|
+
# connection.proxy_uri #=> #<URI::HTTP http://proxy.example.com:8080>
|
|
112
|
+
# @return [URI::HTTP, nil] the parsed proxy URI
|
|
113
|
+
attr_reader :proxy_uri
|
|
27
114
|
|
|
28
115
|
def_delegator :proxy_uri, :host, :proxy_host
|
|
29
116
|
def_delegator :proxy_uri, :port, :proxy_port
|
|
30
117
|
def_delegator :proxy_uri, :user, :proxy_user
|
|
31
118
|
def_delegator :proxy_uri, :password, :proxy_pass
|
|
32
119
|
|
|
120
|
+
# Initializes a new Connection instance
|
|
121
|
+
#
|
|
122
|
+
# @api public
|
|
123
|
+
# @example
|
|
124
|
+
# connection = MLB::Connection.new
|
|
125
|
+
# @param open_timeout [Integer] the connection open timeout in seconds
|
|
126
|
+
# @param read_timeout [Integer] the read timeout in seconds
|
|
127
|
+
# @param write_timeout [Integer] the write timeout in seconds
|
|
128
|
+
# @param debug_output [IO] the IO object for debug output
|
|
129
|
+
# @param proxy_url [String, nil] the proxy URL
|
|
33
130
|
def initialize(open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT,
|
|
34
131
|
write_timeout: DEFAULT_WRITE_TIMEOUT, debug_output: DEFAULT_DEBUG_OUTPUT, proxy_url: nil)
|
|
35
132
|
@open_timeout = open_timeout
|
|
36
133
|
@read_timeout = read_timeout
|
|
37
134
|
@write_timeout = write_timeout
|
|
38
135
|
@debug_output = debug_output
|
|
39
|
-
self.proxy_url = proxy_url
|
|
136
|
+
self.proxy_url = proxy_url if proxy_url
|
|
40
137
|
end
|
|
41
138
|
|
|
139
|
+
# Performs an HTTP request
|
|
140
|
+
#
|
|
141
|
+
# @api public
|
|
142
|
+
# @example
|
|
143
|
+
# connection.perform(request: request)
|
|
144
|
+
# @param request [Net::HTTPRequest] the HTTP request to perform
|
|
145
|
+
# @return [Net::HTTPResponse] the HTTP response
|
|
146
|
+
# @raise [NetworkError] if a network error occurs
|
|
42
147
|
def perform(request:)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
http_client =
|
|
46
|
-
http_client.use_ssl = request.uri.scheme.eql?("https")
|
|
148
|
+
uri = request.uri
|
|
149
|
+
http_client = build_http_client(uri.host || DEFAULT_HOST, uri.port || DEFAULT_PORT)
|
|
150
|
+
http_client.use_ssl = uri.scheme.eql?(HTTPS_SCHEME)
|
|
47
151
|
http_client.request(request)
|
|
48
152
|
rescue *NETWORK_ERRORS => e
|
|
49
153
|
raise NetworkError, "Network error: #{e}"
|
|
50
154
|
end
|
|
51
155
|
|
|
156
|
+
# Sets the proxy URL
|
|
157
|
+
#
|
|
158
|
+
# @api public
|
|
159
|
+
# @example
|
|
160
|
+
# connection.proxy_url = "http://proxy.example.com:8080"
|
|
161
|
+
# @param proxy_url [String] the proxy URL
|
|
162
|
+
# @return [void]
|
|
163
|
+
# @raise [ArgumentError] if the proxy URL is invalid
|
|
52
164
|
def proxy_url=(proxy_url)
|
|
53
165
|
@proxy_url = proxy_url
|
|
54
166
|
proxy_uri = URI(proxy_url)
|
|
@@ -59,6 +171,12 @@ module MLB
|
|
|
59
171
|
|
|
60
172
|
private
|
|
61
173
|
|
|
174
|
+
# Builds an HTTP client instance
|
|
175
|
+
#
|
|
176
|
+
# @api private
|
|
177
|
+
# @param host [String] the host to connect to
|
|
178
|
+
# @param port [Integer] the port to connect to
|
|
179
|
+
# @return [Net::HTTP] the configured HTTP client
|
|
62
180
|
def build_http_client(host = DEFAULT_HOST, port = DEFAULT_PORT)
|
|
63
181
|
http_client = if proxy_uri
|
|
64
182
|
Net::HTTP.new(host, port, proxy_host, proxy_port, proxy_user, proxy_pass)
|
|
@@ -68,6 +186,11 @@ module MLB
|
|
|
68
186
|
configure_http_client(http_client)
|
|
69
187
|
end
|
|
70
188
|
|
|
189
|
+
# Configures an HTTP client with timeout settings
|
|
190
|
+
#
|
|
191
|
+
# @api private
|
|
192
|
+
# @param http_client [Net::HTTP] the HTTP client to configure
|
|
193
|
+
# @return [Net::HTTP] the configured HTTP client
|
|
71
194
|
def configure_http_client(http_client)
|
|
72
195
|
http_client.tap do |c|
|
|
73
196
|
c.open_timeout = open_timeout
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require "shale"
|
|
2
|
+
|
|
3
|
+
module MLB
|
|
4
|
+
# Represents sacrifice fly probability for a specific field zone
|
|
5
|
+
class SacFlyProbability < Shale::Mapper
|
|
6
|
+
include Equalizer.new(:probability)
|
|
7
|
+
|
|
8
|
+
# @!attribute [rw] probability
|
|
9
|
+
# Returns the probability of a sacrifice fly to this field zone
|
|
10
|
+
# @api public
|
|
11
|
+
# @example
|
|
12
|
+
# sac_fly.probability #=> 0.25
|
|
13
|
+
# @return [Float] probability value between 0 and 1
|
|
14
|
+
attribute :probability, Shale::Type::Float
|
|
15
|
+
|
|
16
|
+
json do
|
|
17
|
+
map "probability", to: :probability
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Provides real-time context metrics for a game including win probability
|
|
22
|
+
# and sacrifice fly probabilities by field zone
|
|
23
|
+
#
|
|
24
|
+
# Context metrics are useful for understanding game state and
|
|
25
|
+
# making predictions about likely outcomes.
|
|
26
|
+
class ContextMetrics < Shale::Mapper
|
|
27
|
+
# @!attribute [rw] home_win_probability
|
|
28
|
+
# Returns the home team's probability of winning
|
|
29
|
+
# @api public
|
|
30
|
+
# @example
|
|
31
|
+
# metrics.home_win_probability #=> 0.52
|
|
32
|
+
# @return [Float] probability value between 0 and 1
|
|
33
|
+
attribute :home_win_probability, Shale::Type::Float
|
|
34
|
+
|
|
35
|
+
# @!attribute [rw] away_win_probability
|
|
36
|
+
# Returns the away team's probability of winning
|
|
37
|
+
# @api public
|
|
38
|
+
# @example
|
|
39
|
+
# metrics.away_win_probability #=> 0.48
|
|
40
|
+
# @return [Float] probability value between 0 and 1
|
|
41
|
+
attribute :away_win_probability, Shale::Type::Float
|
|
42
|
+
|
|
43
|
+
# @!attribute [rw] left_field_sac_fly_probability
|
|
44
|
+
# Returns sacrifice fly probability for left field
|
|
45
|
+
# @api public
|
|
46
|
+
# @example
|
|
47
|
+
# metrics.left_field_sac_fly_probability.probability #=> 0.25
|
|
48
|
+
# @return [SacFlyProbability] left field sac fly metrics
|
|
49
|
+
attribute :left_field_sac_fly_probability, SacFlyProbability
|
|
50
|
+
|
|
51
|
+
# @!attribute [rw] center_field_sac_fly_probability
|
|
52
|
+
# Returns sacrifice fly probability for center field
|
|
53
|
+
# @api public
|
|
54
|
+
# @example
|
|
55
|
+
# metrics.center_field_sac_fly_probability.probability #=> 0.30
|
|
56
|
+
# @return [SacFlyProbability] center field sac fly metrics
|
|
57
|
+
attribute :center_field_sac_fly_probability, SacFlyProbability
|
|
58
|
+
|
|
59
|
+
# @!attribute [rw] right_field_sac_fly_probability
|
|
60
|
+
# Returns sacrifice fly probability for right field
|
|
61
|
+
# @api public
|
|
62
|
+
# @example
|
|
63
|
+
# metrics.right_field_sac_fly_probability.probability #=> 0.35
|
|
64
|
+
# @return [SacFlyProbability] right field sac fly metrics
|
|
65
|
+
attribute :right_field_sac_fly_probability, SacFlyProbability
|
|
66
|
+
|
|
67
|
+
json do
|
|
68
|
+
map "homeWinProbability", to: :home_win_probability
|
|
69
|
+
map "awayWinProbability", to: :away_win_probability
|
|
70
|
+
map "leftFieldSacFlyProbability", to: :left_field_sac_fly_probability
|
|
71
|
+
map "centerFieldSacFlyProbability", to: :center_field_sac_fly_probability
|
|
72
|
+
map "rightFieldSacFlyProbability", to: :right_field_sac_fly_probability
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Retrieves context metrics for a specific game
|
|
76
|
+
#
|
|
77
|
+
# @api public
|
|
78
|
+
# @example Using a game primary key
|
|
79
|
+
# MLB::ContextMetrics.find(game: 745571)
|
|
80
|
+
# @example Using a ScheduledGame object
|
|
81
|
+
# MLB::ContextMetrics.find(game: scheduled_game)
|
|
82
|
+
# @param game [Integer, #game_pk] game ID or object responding to #game_pk
|
|
83
|
+
# @return [ContextMetrics] the context metrics for the game
|
|
84
|
+
def self.find(game:)
|
|
85
|
+
game_pk = game.respond_to?(:game_pk) ? game.game_pk : game
|
|
86
|
+
response = CLIENT.get("game/#{game_pk}/contextMetrics")
|
|
87
|
+
from_json(response)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/lib/mlb/division.rb
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
+
require "equalizer"
|
|
1
2
|
require "shale"
|
|
3
|
+
require_relative "comparable_by_attribute"
|
|
2
4
|
require_relative "league"
|
|
3
5
|
require_relative "sport"
|
|
4
6
|
|
|
5
7
|
module MLB
|
|
8
|
+
# Represents a division (e.g., AL East, NL West)
|
|
6
9
|
class Division < Shale::Mapper
|
|
7
10
|
include Comparable
|
|
11
|
+
include ComparableByAttribute
|
|
12
|
+
include Equalizer.new(:id)
|
|
13
|
+
|
|
14
|
+
# Returns the attribute used for sorting
|
|
15
|
+
#
|
|
16
|
+
# @api private
|
|
17
|
+
# @return [Symbol] the attribute used for comparison
|
|
18
|
+
def comparable_attribute = :sort_order
|
|
8
19
|
|
|
9
20
|
attribute :id, Shale::Type::Integer
|
|
10
21
|
attribute :name, Shale::Type::String
|
|
@@ -18,8 +29,21 @@ module MLB
|
|
|
18
29
|
attribute :sort_order, Shale::Type::Integer
|
|
19
30
|
attribute :active, Shale::Type::Boolean
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
|
|
32
|
+
# Checks if the division is active
|
|
33
|
+
#
|
|
34
|
+
# @api public
|
|
35
|
+
# @example
|
|
36
|
+
# division.active? #=> true
|
|
37
|
+
# @return [Boolean] whether the division is active
|
|
38
|
+
def active? = active
|
|
39
|
+
|
|
40
|
+
# Checks if the division has a wildcard
|
|
41
|
+
#
|
|
42
|
+
# @api public
|
|
43
|
+
# @example
|
|
44
|
+
# division.wildcard? #=> true
|
|
45
|
+
# @return [Boolean] whether the division has a wildcard
|
|
46
|
+
def wildcard? = has_wildcard
|
|
23
47
|
|
|
24
48
|
json do
|
|
25
49
|
map "id", to: :id
|
|
@@ -34,9 +58,5 @@ module MLB
|
|
|
34
58
|
map "sortOrder", to: :sort_order
|
|
35
59
|
map "active", to: :active
|
|
36
60
|
end
|
|
37
|
-
|
|
38
|
-
def <=>(other)
|
|
39
|
-
sort_order <=> other.sort_order
|
|
40
|
-
end
|
|
41
61
|
end
|
|
42
62
|
end
|
data/lib/mlb/divisions.rb
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
1
|
require "shale"
|
|
2
|
-
require "uri"
|
|
3
|
-
require_relative "sport"
|
|
4
2
|
require_relative "division"
|
|
5
3
|
|
|
6
4
|
module MLB
|
|
5
|
+
# Collection of divisions from the MLB Stats API
|
|
7
6
|
class Divisions < Shale::Mapper
|
|
8
|
-
attribute :copyright, Shale::Type::String
|
|
9
7
|
attribute :divisions, Division, collection: true
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
# Retrieves all divisions
|
|
10
|
+
#
|
|
11
|
+
# @api public
|
|
12
|
+
# @example
|
|
13
|
+
# MLB::Divisions.all
|
|
14
|
+
# @param sport [Integer, Sport] the sport ID or Sport object
|
|
15
|
+
# @return [Array<Division>] list of all divisions
|
|
16
|
+
def self.all(sport: Utils::DEFAULT_SPORT_ID)
|
|
17
|
+
params = {sportId: Utils.extract_id(sport)}
|
|
18
|
+
response = CLIENT.get("divisions?#{Utils.build_query(params)}")
|
|
19
|
+
from_json(response).divisions.sort
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
# Finds a division by ID
|
|
23
|
+
#
|
|
24
|
+
# @api public
|
|
25
|
+
# @example
|
|
26
|
+
# MLB::Divisions.find(201)
|
|
27
|
+
# @param division [Integer, Division] the division ID or Division object
|
|
28
|
+
# @param sport [Integer, Sport] the sport ID or Sport object
|
|
29
|
+
# @return [Division, nil] the division if found
|
|
30
|
+
def self.find(division, sport: Utils::DEFAULT_SPORT_ID)
|
|
31
|
+
params = {sportId: Utils.extract_id(sport)}
|
|
32
|
+
response = CLIENT.get("divisions/#{Utils.extract_id(division)}?#{Utils.build_query(params)}")
|
|
33
|
+
from_json(response).divisions.min_by { |d| d.sort_order || 0 }
|
|
28
34
|
end
|
|
29
35
|
end
|
|
30
36
|
end
|