sleeper_api 1.6.0 → 1.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0375caa5f944f2f083cdc8cec7672f44fc9219969e8e733bde441c377e16ede4
4
- data.tar.gz: a1d54df90f2ff3ba533d11756993513eca6bae884f1a1fc0e57e51d9be84fa12
3
+ metadata.gz: da00a42dc3d3fa73feab8e1c2278f0cdcf7a274b12709c540c2f988782828269
4
+ data.tar.gz: 8b2fc35f6dd3a3b546cafae1679ac0dbca75193d7886fcb12b57c5bf616da667
5
5
  SHA512:
6
- metadata.gz: ba5338528abf3a7c924dd9fdfd7dbf6440a1ac75debc3426cca4d580520a65ce7986075c2d8a6709305a5e57720c08a9b0749710e83b46381628b2991bab702b
7
- data.tar.gz: 84ff6c0503398ca629009b1976dfd2ead6a9594d63eabdf97fb0056ed29d3b4965e8f2a4d17091c1e6d02560c1b28f469afeffeacaccc36acb7b394c3415dc2a
6
+ metadata.gz: c953ad4e95e986db6ef5f6f559a7cf464a9cdeaf98ccf83e4cb25f1e99008152066e5b15ad7b852de444a13fafd81b795d6b338b5ced2cebe3e9710223aa966a
7
+ data.tar.gz: 4ccdabb09c1bd25a39e7f32ce6cd97c58b5237b8c18f9a030aa3d9307f26b0f736cd63cf6f3f9cfb6381305aa0f9b0b8cc038431f06bd52d37f3c74bb5edb75d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ ## [1.8.0] - 2026-10-02
2
+
3
+ ### Added
4
+
5
+ - **`Client#player_news(player_id, sport: "nfl", limit: 10)`** fetches one
6
+ player's recent news from the undocumented
7
+ `api.sleeper.com/players/{sport}/{id}/news`, newest first: RotoWire,
8
+ FantasyPros and RotoBaller items with a `metadata` title, description and
9
+ usually an analysis. Measured 2026-10-02: Sleeper returns at most 10 whatever
10
+ the limit, there is no paging, and an unknown id answers `200` with `[]`. The
11
+ path exists on the web host only.
12
+
13
+ ## [1.7.0] - 2026-10-02
14
+
15
+ ### Added
16
+
17
+ - **`Client#player(player_id, sport: "nfl")`** fetches one player from the
18
+ undocumented `/v1/players/{sport}/{id}`: the same fields as a catalog row, in
19
+ about 1.2 KB rather than the 14.6 MB `#get_players` downloads. It is live and
20
+ uncached, so it is the way to read an `injury_status` or `depth_chart_order`
21
+ fresher than a nightly catalog.
22
+ - **`SleeperApi::PlayerNotFound`, a subclass of `SleeperApi::Error`.** An
23
+ unknown player id is a `404`, checked live 2026-10-02, unlike an unknown
24
+ user's `200` and `null`. Any other failure is still a plain
25
+ `SleeperApi::Error`.
26
+
1
27
  ## [1.6.0] - 2026-09-28
2
28
 
3
29
  ### Added
data/CLAUDE.md CHANGED
@@ -70,7 +70,7 @@ Four layers, with a deliberate split between HTTP and modeling:
70
70
 
71
71
  **Guard nil defensively.** Sleeper omits fields freely — users without `metadata`, rosters without `players`, matchups without `points`. Real leagues hit these; the spec fixtures often don't. Use `&.dig` rather than `[]` on anything nested off an API response.
72
72
 
73
- **Never fan out `get_players`.** It's a multi-megabyte payload of every NFL player. It's cached for 24h in an ivar on the client instance — which means the cache dies with the client. Consumers holding a short-lived client re-download it every time.
73
+ **Never fan out `get_players`.** It's a multi-megabyte payload of every NFL player. It's cached for 24h in an ivar on the client instance — which means the cache dies with the client. Consumers holding a short-lived client re-download it every time. For one player, `#player(id)` fetches `/v1/players/nfl/{id}` live (~1.2 KB, undocumented, uncached); an unknown id is a **404** there, not the `200`/`null` an unknown user gets, and becomes `PlayerNotFound`. `#player_news(id)` is that player's news on `WEB_HOST` only (`.app` 404s the path): at most 10 items whatever `limit` says, and an unknown id is `200` with `[]`, not a 404.
74
74
 
75
75
  ### Undocumented endpoints carry undocumented vocabularies
76
76
 
data/README.md CHANGED
@@ -243,10 +243,20 @@ Access player data with automatic caching:
243
243
  # Get all players (cached for 24 hours)
244
244
  players = client.get_players
245
245
 
246
- # Find specific player
246
+ # Find specific player (reads the cached catalog above)
247
247
  player = client.get_player_by_id("1234")
248
248
  puts "#{player['first_name']} #{player['last_name']} - #{player['position']}"
249
249
 
250
+ # One player, live and uncached: ~1.2 KB instead of the whole catalog.
251
+ # Use it for a fresher injury_status or depth_chart_order than the catalog has.
252
+ fresh = client.player("1234")
253
+ puts "#{fresh['injury_status']} (#{fresh['injury_body_part']})"
254
+
255
+ # One player's recent news, newest first (at most 10, from api.sleeper.com)
256
+ client.player_news("1234").each do |item|
257
+ puts "#{item['source']}: #{item.dig('metadata', 'title')}"
258
+ end
259
+
250
260
  # Get trending players
251
261
  trending_adds = client.trending_players(type: "add", limit: 10)
252
262
  trending_drops = client.trending_players(type: "drop", limit: 10)
@@ -370,6 +380,8 @@ end
370
380
 
371
381
  - SleeperApi::UserNotFound - a subclass of SleeperApi::Error: no Sleeper user has that identifier. Permanent, so rescue it before SleeperApi::Error if you retry the rest
372
382
 
383
+ - SleeperApi::PlayerNotFound - a subclass of SleeperApi::Error: `client.player` was given an id Sleeper does not have. Permanent, like UserNotFound
384
+
373
385
  - ArgumentError - Invalid parameters passed to methods
374
386
 
375
387
  ## Performance Considerations
@@ -472,6 +472,35 @@ module SleeperApi
472
472
  get_players(sport)[player_id]
473
473
  end
474
474
 
475
+ # Fetch one player, live: about 1.2 KB where #get_players is 14.6 MB, and
476
+ # not cached. Undocumented; same fields as a catalog row.
477
+ #
478
+ # Sleeper answers an unknown id with 404, unlike an unknown user's 200 and
479
+ # null, and that 404 becomes {SleeperApi::PlayerNotFound}.
480
+ #
481
+ # @param player_id [String] Player ID
482
+ # @param sport [String] Sport code (default: "nfl")
483
+ # @return [HTTParty::Response] The player's raw data
484
+ # @raise [SleeperApi::PlayerNotFound] If no player has that ID
485
+ def player(player_id, sport: "nfl")
486
+ make_request(path("v1", "players", sport, player_id),
487
+ not_found: -> { PlayerNotFound.new("No Sleeper player #{player_id.to_s.inspect}") })
488
+ end
489
+
490
+ # One player's recent news, newest first: RotoWire, FantasyPros and
491
+ # RotoBaller items, each with a `metadata` title, description and usually
492
+ # an analysis. Undocumented and on WEB_HOST only; Sleeper returns at most
493
+ # 10 whatever the limit, and an unknown id answers 200 with [].
494
+ #
495
+ # @param player_id [String] Player ID
496
+ # @param sport [String] Sport code (default: "nfl")
497
+ # @param limit [Integer] How many items, up to 10
498
+ # @return [HTTParty::Response] The items, newest first
499
+ def player_news(player_id, sport: "nfl", limit: 10)
500
+ query = URI.encode_www_form(limit: limit)
501
+ make_request("#{path("players", sport, player_id, "news")}?#{query}", host: WEB_HOST)
502
+ end
503
+
475
504
  private
476
505
 
477
506
  # Every request path is built here, from escaped segments. An unescaped
@@ -503,9 +532,11 @@ module SleeperApi
503
532
  #
504
533
  # @param path [String] API endpoint path
505
534
  # @param host [String, nil] a different host, e.g. WEB_HOST
535
+ # @param not_found [Proc, nil] builds the error a 404 raises, for an
536
+ # endpoint where 404 means "no such thing" rather than a failure
506
537
  # @return [HTTParty::Response]
507
538
  # @raise [SleeperApi::Error] On HTTP errors or timeouts
508
- def make_request(path, host: nil)
539
+ def make_request(path, host: nil, not_found: nil)
509
540
  named = host ? "#{host}#{path}" : path
510
541
  options = { timeout: @config.timeout }
511
542
  options[:base_uri] = host if host
@@ -519,6 +550,8 @@ module SleeperApi
519
550
  response
520
551
  else
521
552
  @config.logger&.error("Failed to fetch #{named}: #{response.code}")
553
+ raise not_found.call if not_found && response.code == 404
554
+
522
555
  raise SleeperApi::Error, "Failed to fetch #{named}: #{response.code}"
523
556
  end
524
557
  rescue Net::OpenTimeout, Net::ReadTimeout => e
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SleeperApi
4
- VERSION = "1.6.0"
4
+ VERSION = "1.8.0"
5
5
  end
data/lib/sleeper_api.rb CHANGED
@@ -13,6 +13,9 @@ module SleeperApi
13
13
  # Error — retrying will not help — so a caller can rescue it on its own.
14
14
  class UserNotFound < Error; end
15
15
 
16
+ # The id names no Sleeper player. Permanent, like UserNotFound.
17
+ class PlayerNotFound < Error; end
18
+
16
19
  class << self
17
20
  attr_writer :configuration
18
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sleeper_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eruity1