y_fantasy 0.1.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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.pryrc +8 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +20 -0
  5. data/.standard.yml +2 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +3 -0
  8. data/Gemfile +5 -0
  9. data/Gemfile.lock +220 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +41 -0
  12. data/Rakefile +12 -0
  13. data/exe/y_fantasy +9 -0
  14. data/lib/y_fantasy/api/authentication.rb +177 -0
  15. data/lib/y_fantasy/api/client.rb +84 -0
  16. data/lib/y_fantasy/api/subresource_param_builder.rb +138 -0
  17. data/lib/y_fantasy/api/url_builder.rb +91 -0
  18. data/lib/y_fantasy/cli.rb +46 -0
  19. data/lib/y_fantasy/concerns/subresourceable.rb +87 -0
  20. data/lib/y_fantasy/ref/nfl.rb +57 -0
  21. data/lib/y_fantasy/resources/base_resource.rb +117 -0
  22. data/lib/y_fantasy/resources/base_subresource.rb +31 -0
  23. data/lib/y_fantasy/resources/game/game_week.rb +26 -0
  24. data/lib/y_fantasy/resources/game/position_type.rb +20 -0
  25. data/lib/y_fantasy/resources/game.rb +136 -0
  26. data/lib/y_fantasy/resources/group/settings.rb +53 -0
  27. data/lib/y_fantasy/resources/group/standings.rb +11 -0
  28. data/lib/y_fantasy/resources/group.rb +76 -0
  29. data/lib/y_fantasy/resources/league/scoreboard.rb +12 -0
  30. data/lib/y_fantasy/resources/league/settings.rb +51 -0
  31. data/lib/y_fantasy/resources/league/standings.rb +25 -0
  32. data/lib/y_fantasy/resources/league.rb +187 -0
  33. data/lib/y_fantasy/resources/pickem_team/pick.rb +31 -0
  34. data/lib/y_fantasy/resources/pickem_team/week_pick.rb +28 -0
  35. data/lib/y_fantasy/resources/pickem_team.rb +98 -0
  36. data/lib/y_fantasy/resources/player/draft_analysis.rb +26 -0
  37. data/lib/y_fantasy/resources/player/ownership_percentage.rb +26 -0
  38. data/lib/y_fantasy/resources/player/stat_collection.rb +32 -0
  39. data/lib/y_fantasy/resources/player.rb +157 -0
  40. data/lib/y_fantasy/resources/shared_subresources/draft_result.rb +39 -0
  41. data/lib/y_fantasy/resources/shared_subresources/matchup.rb +61 -0
  42. data/lib/y_fantasy/resources/shared_subresources/roster_position.rb +38 -0
  43. data/lib/y_fantasy/resources/shared_subresources/stat.rb +16 -0
  44. data/lib/y_fantasy/resources/shared_subresources/stat_category.rb +22 -0
  45. data/lib/y_fantasy/resources/shared_subresources/stat_modifier.rb +10 -0
  46. data/lib/y_fantasy/resources/shared_subresources/stat_winner.rb +8 -0
  47. data/lib/y_fantasy/resources/team/manager.rb +23 -0
  48. data/lib/y_fantasy/resources/team/roster.rb +18 -0
  49. data/lib/y_fantasy/resources/team/standings.rb +33 -0
  50. data/lib/y_fantasy/resources/team/stat_collection.rb +38 -0
  51. data/lib/y_fantasy/resources/team.rb +175 -0
  52. data/lib/y_fantasy/subresource_validator.rb +67 -0
  53. data/lib/y_fantasy/transformations/base_transform.rb +62 -0
  54. data/lib/y_fantasy/transformations/collection_transformer.rb +22 -0
  55. data/lib/y_fantasy/transformations/default_transformer.rb +22 -0
  56. data/lib/y_fantasy/transformations/game/position_types_transformer.rb +21 -0
  57. data/lib/y_fantasy/transformations/game_transformer.rb +54 -0
  58. data/lib/y_fantasy/transformations/group_transformer.rb +39 -0
  59. data/lib/y_fantasy/transformations/instantiator.rb +25 -0
  60. data/lib/y_fantasy/transformations/key_unwrapper.rb +12 -0
  61. data/lib/y_fantasy/transformations/league/scoreboard_transformer.rb +21 -0
  62. data/lib/y_fantasy/transformations/league/settings_transformer.rb +25 -0
  63. data/lib/y_fantasy/transformations/league/standings_transformer.rb +22 -0
  64. data/lib/y_fantasy/transformations/league_transformer.rb +57 -0
  65. data/lib/y_fantasy/transformations/matchups_transformer.rb +22 -0
  66. data/lib/y_fantasy/transformations/pickem_team/week_picks_transformer.rb +29 -0
  67. data/lib/y_fantasy/transformations/pickem_team_transformer.rb +41 -0
  68. data/lib/y_fantasy/transformations/player/ownership_percentage_transformer.rb +21 -0
  69. data/lib/y_fantasy/transformations/player/stats_transformer.rb +32 -0
  70. data/lib/y_fantasy/transformations/player_transformer.rb +34 -0
  71. data/lib/y_fantasy/transformations/stat_categories_transformer.rb +19 -0
  72. data/lib/y_fantasy/transformations/stat_modifiers_transformer.rb +19 -0
  73. data/lib/y_fantasy/transformations/t.rb +44 -0
  74. data/lib/y_fantasy/transformations/team/manager_transformer.rb +19 -0
  75. data/lib/y_fantasy/transformations/team/roster_transformer.rb +27 -0
  76. data/lib/y_fantasy/transformations/team/standings_transformer.rb +42 -0
  77. data/lib/y_fantasy/transformations/team/stats_transformer.rb +30 -0
  78. data/lib/y_fantasy/transformations/team_transformer.rb +54 -0
  79. data/lib/y_fantasy/transformations/user_transformer.rb +17 -0
  80. data/lib/y_fantasy/transformations.rb +54 -0
  81. data/lib/y_fantasy/version.rb +5 -0
  82. data/lib/y_fantasy.rb +36 -0
  83. data/sig/y_fantasy.rbs +4 -0
  84. data/y_fantasy.gemspec +49 -0
  85. metadata +364 -0
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YFantasy
4
+ module Api
5
+ class SubresourceParamBuilder
6
+ SUBRESOURCE_MAP = {
7
+ draft_results: :draftresults,
8
+ ownership_percentage: :percent_owned,
9
+ team_standings: :standings
10
+ }
11
+
12
+ PLAYER_FILTERS = [
13
+ :count,
14
+ :position,
15
+ :search,
16
+ :sort,
17
+ :sort_type,
18
+ :start,
19
+ :status
20
+ ].freeze
21
+
22
+ def initialize(subresources = [], **options)
23
+ @regular_subs, @nested_subs = normalize_subresources(subresources)
24
+ @week = options.delete(:week)
25
+ @player_filters = set_player_filters(options)
26
+ @options = options
27
+ end
28
+
29
+ def build
30
+ @params = +""
31
+ add_regular_subresource_segments
32
+ add_nested_subresource_segments
33
+ add_subresource_keys
34
+ add_week
35
+ add_player_filters
36
+ @params
37
+ end
38
+
39
+ private
40
+
41
+ def add_regular_subresource_segments
42
+ return if @regular_subs.none?
43
+
44
+ if @regular_subs.one? && @nested_subs.none?
45
+ @params.concat("/#{@regular_subs.first}")
46
+ elsif @regular_subs.size > 1 && @regular_subs.include?(:players) && !@player_filters.empty?
47
+ non_player_subs = @regular_subs.select { |sub| sub != :players }
48
+ @params.concat(";out=#{non_player_subs.join(",")}").concat("/players")
49
+ else
50
+ @params.concat(";out=#{@regular_subs.join(",")}")
51
+ end
52
+ end
53
+
54
+ def add_nested_subresource_segments
55
+ return if @nested_subs.none?
56
+
57
+ if @nested_subs.one?
58
+ key = @nested_subs.first.keys.first
59
+ val = @nested_subs.first[key]
60
+
61
+ @params.concat("/#{key}")
62
+ @params.concat("/#{val}") if val.is_a?(Symbol)
63
+ @params.concat("/#{val.keys.first}/#{val.values.first}") if val.is_a?(Hash)
64
+ @params.concat(";out=#{val.join(",")}") if val.is_a?(Array)
65
+ else
66
+ raise self.class::Error.new("Not possible to construct a URL with 2+ sets of nested subresources: #{@nested_subs}")
67
+ end
68
+ end
69
+
70
+ def add_subresource_keys
71
+ return unless options_include_subresource_keys?
72
+
73
+ @options.each_pair do |k, v|
74
+ k_str = Transformations::T.pluralize(k.to_s.sub("_keys", ""))
75
+ if @params.include?("/#{k_str}")
76
+ @params.sub!(k_str, "#{k_str};#{k}=#{v.join(",")}")
77
+ end
78
+ end
79
+ end
80
+
81
+ def options_include_subresource_keys?
82
+ @options.keys.map(&:to_s).any? { |s| s.end_with?("_keys") }
83
+ end
84
+
85
+ def add_week
86
+ return if @week.nil?
87
+
88
+ case @params
89
+ when /\/(roster|scoreboard)/
90
+ @params.sub!(/\/(?<res>roster|scoreboard)/, "/\\k<res>;week=#{@week}")
91
+ when /\/matchups/
92
+ @params.sub!("matchups", "matchups;weeks=#{@week}")
93
+ when /\/stats/
94
+ @params.sub!("stats", "stats;type=week;week=#{@week}")
95
+ end
96
+ end
97
+
98
+ def add_player_filters
99
+ return if @player_filters.empty? || !@params.match?(/players/)
100
+
101
+ player_params = +""
102
+ @player_filters.each { |k, v| player_params.concat(k.to_s, "=", v.to_s, ";") }
103
+ player_params.slice!(-1)
104
+ @params.sub!("players", "players;#{player_params}")
105
+ end
106
+
107
+ def set_player_filters(options)
108
+ options.each_with_object({}) do |(k, v), h|
109
+ h[k] = v if PLAYER_FILTERS.include?(k)
110
+ end
111
+ end
112
+
113
+ def normalize_subresources(subs)
114
+ @regular_subs = []
115
+ @nested_subs = []
116
+
117
+ subs.each do |sub|
118
+ if sub.is_a?(Symbol)
119
+ @regular_subs << (SUBRESOURCE_MAP[sub] || sub)
120
+ end
121
+
122
+ if sub.is_a?(Hash)
123
+ sub.each_pair do |key, nested_subs|
124
+ nested_subs = Transformations::T.wrap_in_array(nested_subs)
125
+ nested_subs = nested_subs.map { |nested_sub| SUBRESOURCE_MAP[nested_sub] || nested_sub }
126
+ @nested_subs << (nested_subs.one? ? {key => nested_subs.first} : {key => nested_subs})
127
+ end
128
+ end
129
+ end
130
+
131
+ [@regular_subs, @nested_subs]
132
+ end
133
+
134
+ class Error < StandardError
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YFantasy
4
+ module Api
5
+ class UrlBuilder
6
+ # NOTE: Could also make an id_params method and use it like `league_ids=`
7
+ # Key example (game_id.l (for league).league_id): <league_key>79.l.31399</league_key>
8
+ # ID example (last part of key) <league_id>31399</league_id>
9
+ # valid urls:
10
+ # /games;game_keys=79/leagues;league_keys=79.l.31399
11
+ # /games;game_keys=79/leagues;league_ids=31399
12
+ # /game/79/leagues;league_keys=79.l.31399
13
+ # /game/79/leagues;league_ids=31399
14
+
15
+ # invalid urls:
16
+ # /games;game_keys=79/league/31399
17
+ # /games;game_keys=79/league/79.l.31399
18
+ # /game/79/league/79.l.31399
19
+ # /game/79/league/31399
20
+
21
+ BASE_URL = "https://fantasysports.yahooapis.com/fantasy/v2"
22
+ CURRENT_USER_URL = "#{BASE_URL}/users;use_login=1"
23
+
24
+ def initialize(resource, keys: [], game_codes: [], subresources: [], **options)
25
+ @options = options
26
+ @url = options[:scope_to_user] ? CURRENT_USER_URL.dup : BASE_URL.dup
27
+ @resource = override_resource(resource.to_s)
28
+ @keys = Array(keys).map(&:to_s)
29
+ @game_codes = Array(game_codes).map(&:to_s)
30
+ @subresources = Array(subresources)
31
+ end
32
+
33
+ def build
34
+ validate_args!
35
+ singular_resource? ? build_resource_url : build_collection_url
36
+ return @url if @subresources.empty?
37
+
38
+ params = SubresourceParamBuilder.new(@subresources, **@options).build
39
+ @url.concat(params)
40
+ end
41
+
42
+ private
43
+
44
+ def override_resource(resource)
45
+ return "team" if resource == "pickem_team"
46
+ return "teams" if resource == "pickem_teams"
47
+
48
+ resource
49
+ end
50
+
51
+ def build_resource_url
52
+ @url.concat("/", @resource, "/", @keys.first)
53
+ end
54
+
55
+ def build_collection_url
56
+ @url.concat("/", @resource, collection_params)
57
+ end
58
+
59
+ def collection_params
60
+ if @resource == "games" && !@game_codes.empty?
61
+ return ";game_codes=#{@game_codes.join(",")}"
62
+ end
63
+
64
+ return "" if @keys.compact.empty?
65
+
66
+ ";#{singularize(@resource)}_keys=#{@keys.join(",")}"
67
+ end
68
+
69
+ def singular_resource?
70
+ singularize(@resource) == @resource
71
+ end
72
+
73
+ def singularize(resource)
74
+ Transformations::T.singularize(resource)
75
+ end
76
+
77
+ def validate_args!
78
+ if !@game_codes.empty? && !@keys.empty?
79
+ raise self.class::Error.new("Cannot build URL with both keys and game_codes")
80
+ end
81
+
82
+ if !@game_codes.empty? && @resource != "games"
83
+ raise self.class::Error.new("`game_codes` can only be used with Games collection")
84
+ end
85
+ end
86
+
87
+ class Error < StandardError
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ module YFantasy
6
+ class CLI < Thor
7
+ include Thor::Actions
8
+
9
+ desc "version", "Prints the YFantasy gem version"
10
+ def version
11
+ require "y_fantasy/version"
12
+ puts YFantasy::VERSION
13
+ end
14
+
15
+ desc "nfl_teams", "Prints Yahoo NFL team information"
16
+ def nfl_teams
17
+ require "y_fantasy/ref/nfl"
18
+
19
+ YFantasy::Ref::Nfl::TEAM_KEY_MAP.each_with_index do |(key, team), idx|
20
+ if idx.zero?
21
+ puts format("%-15s %-15s %-10s %-10s", "City", "Team Name", "Abbrev", "Yahoo Key")
22
+ puts "-" * 55
23
+ end
24
+ puts format("%-15s %-15s %-10s %-10s", team[:city], team[:team_name], team[:abbrev], key)
25
+ end
26
+ end
27
+
28
+ desc "help", "Prints this help message"
29
+ def help
30
+ puts self.class.help
31
+ end
32
+
33
+ no_commands do
34
+ def self.help
35
+ <<~HELP
36
+ Usage: y_fantasy [command] [options]
37
+
38
+ Commands:
39
+ version - Prints the YFantasy gem version
40
+ nfl_teams - Prints Yahoo NFL team information
41
+ help - Prints this help message
42
+ HELP
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YFantasy
4
+ module Subresourceable
5
+ def self.included(base)
6
+ base.include(InstanceMethods)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module InstanceMethods
11
+ def fetched_subresources
12
+ @fetched_subresources ||= Set.new
13
+ end
14
+
15
+ def add_fetched_subresources(subresources = [])
16
+ # Using wrap_in_array here because Array() will convert a hash to array
17
+ Transformations::T.wrap_in_array(subresources).each do |subresource|
18
+ case subresource
19
+ when Symbol
20
+ fetched_subresources << subresource
21
+ when Hash
22
+ key = subresource.keys.first
23
+ fetched_subresources << key
24
+ sub_instances = Transformations::T.wrap_in_array(send(key))
25
+ sub_instances&.each do |sub_instance|
26
+ sub_instance.add_fetched_subresources(subresource[key])
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ module ClassMethods
34
+ # TODO: may not need these first 3 methods if the subresource_tree works the way I want it to
35
+ def primary_subresources
36
+ @primary_subresources ||= []
37
+ end
38
+
39
+ def dependent_subresources
40
+ @dependent_subresources ||= []
41
+ end
42
+
43
+ def subresources
44
+ primary_subresources | dependent_subresources
45
+ end
46
+
47
+ def has_subresource(sub, klass:)
48
+ check_inheritance # This smells
49
+ klass.dependent? ? (dependent_subresources << sub) : (primary_subresources << sub)
50
+ add_to_subresource_tree(sub, klass)
51
+
52
+ define_method(sub) do
53
+ ivar = :"@#{sub}"
54
+ value = instance_variable_get(ivar)
55
+ return value if (value && value != []) || fetched_subresources.include?(sub)
56
+
57
+ value = instance_variable_set(ivar, self.class.fetch_subresource(key, sub))
58
+ add_fetched_subresources(sub)
59
+ value
60
+ end
61
+ end
62
+
63
+ def fetch_subresource(key, subresource)
64
+ resource = find(key, with: [subresource])
65
+ resource.send(subresource)
66
+ end
67
+
68
+ def add_to_subresource_tree(subresource, klass)
69
+ @subresource_tree ||= {}
70
+ @subresource_tree[subresource] = klass.subresources
71
+ end
72
+
73
+ def subresource_tree
74
+ @subresource_tree || {}
75
+ end
76
+
77
+ def check_inheritance
78
+ return if superclass == YFantasy::BaseResource || superclass == YFantasy::BaseSubresource
79
+
80
+ raise YFantasy::Subresourceable::Error.new("#{self} does not inherit from BaseResource")
81
+ end
82
+ end
83
+
84
+ class Error < StandardError
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YFantasy
4
+ module Ref
5
+ module Nfl
6
+ TEAM_KEY_MAP = {
7
+ "nfl.t.1": {key: "nfl.t.1", abbrev: "atl", city: "Atlanta", team_name: "Falcons"},
8
+ "nfl.t.2": {key: "nfl.t.2", abbrev: "buf", city: "Buffalo", team_name: "Bills"},
9
+ "nfl.t.3": {key: "nfl.t.3", abbrev: "chi", city: "Chicago", team_name: "Bears"},
10
+ "nfl.t.4": {key: "nfl.t.4", abbrev: "cin", city: "Cincinnati", team_name: "Bengals"},
11
+ "nfl.t.5": {key: "nfl.t.5", abbrev: "cle", city: "Cleveland", team_name: "Browns"},
12
+ "nfl.t.6": {key: "nfl.t.6", abbrev: "dal", city: "Dallas", team_name: "Cowboys"},
13
+ "nfl.t.7": {key: "nfl.t.7", abbrev: "den", city: "Denver", team_name: "Broncos"},
14
+ "nfl.t.8": {key: "nfl.t.8", abbrev: "det", city: "Detroit", team_name: "Lions"},
15
+ "nfl.t.9": {key: "nfl.t.9", abbrev: "gb", city: "Green Bay", team_name: "Packers"},
16
+ "nfl.t.10": {key: "nfl.t.10", abbrev: "ten", city: "Tennessee", team_name: "Titans"},
17
+ "nfl.t.11": {key: "nfl.t.11", abbrev: "ind", city: "Indianapolis", team_name: "Colts"},
18
+ "nfl.t.12": {key: "nfl.t.12", abbrev: "kc", city: "Kansas City", team_name: "Chiefs"},
19
+ "nfl.t.13": {key: "nfl.t.13", abbrev: "lv", city: "Las Vegas", team_name: "Rakeyers"},
20
+ "nfl.t.14": {key: "nfl.t.14", abbrev: "lar", city: "Los Angeles", team_name: "Rams"},
21
+ "nfl.t.15": {key: "nfl.t.15", abbrev: "mia", city: "Miami", team_name: "Dolphins"},
22
+ "nfl.t.16": {key: "nfl.t.16", abbrev: "min", city: "Minnesota", team_name: "Vikings"},
23
+ "nfl.t.17": {key: "nfl.t.17", abbrev: "ne", city: "New England", team_name: "Patriots"},
24
+ "nfl.t.18": {key: "nfl.t.18", abbrev: "no", city: "New Orleans", team_name: "Saints"},
25
+ "nfl.t.19": {key: "nfl.t.19", abbrev: "nyg", city: "New York", team_name: "Giants"},
26
+ "nfl.t.20": {key: "nfl.t.20", abbrev: "nyj", city: "New York", team_name: "Jets"},
27
+ "nfl.t.21": {key: "nfl.t.21", abbrev: "phi", city: "Philadelphia", team_name: "Eagles"},
28
+ "nfl.t.22": {key: "nfl.t.22", abbrev: "ari", city: "Arizona", team_name: "Cardinals"},
29
+ "nfl.t.23": {key: "nfl.t.23", abbrev: "pit", city: "Pittsburgh", team_name: "Steelers"},
30
+ "nfl.t.24": {key: "nfl.t.24", abbrev: "lac", city: "Los Angeles", team_name: "Chargers"},
31
+ "nfl.t.25": {key: "nfl.t.25", abbrev: "sf", city: "San Francisco", team_name: "49ers"},
32
+ "nfl.t.26": {key: "nfl.t.26", abbrev: "sea", city: "Seattle", team_name: "Seahawks"},
33
+ "nfl.t.27": {key: "nfl.t.27", abbrev: "tb", city: "Tampa Bay", team_name: "Buccaneers"},
34
+ "nfl.t.28": {key: "nfl.t.28", abbrev: "was", city: "Washington", team_name: "Commanders"},
35
+ "nfl.t.29": {key: "nfl.t.29", abbrev: "car", city: "Carolina", team_name: "Panthers"},
36
+ "nfl.t.30": {key: "nfl.t.30", abbrev: "jax", city: "Jacksonville", team_name: "Jaguars"},
37
+ "nfl.t.33": {key: "nfl.t.33", abbrev: "bal", city: "Baltimore", team_name: "Ravens"},
38
+ "nfl.t.34": {key: "nfl.t.34", abbrev: "hou", city: "Houston", team_name: "Texans"}
39
+ }
40
+
41
+ def team(key)
42
+ TEAM_KEY_MAP.fetch(key.to_sym, nil)
43
+ end
44
+ module_function :team
45
+
46
+ # TODO: Work in progress...
47
+ STAT_MAP = {
48
+ 0 => "Games Played",
49
+ 8 => "Rush Att",
50
+ 9 => "Rush Yds",
51
+ 11 => "Rec",
52
+ 12 => "Rec Yds",
53
+ 13 => "Rec TD"
54
+ }
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YFantasy
4
+ # @abstract Base class for all "primary" Yahoo Fantasy Sports API resources.
5
+ # @note Primary resources are those with a Yahoo Key/ID, that can be referenced in a Yahoo Fantasy API URL.
6
+ # This includes Game, League, Team, Player, Group, and PickemTeam.
7
+ class BaseResource
8
+ extend Forwardable
9
+ extend Dry::Initializer[undefined: false]
10
+ include Subresourceable
11
+
12
+ # Error class for BaseResource exceptions
13
+ class Error < StandardError
14
+ end
15
+
16
+ # CLASS METHODS
17
+ class << self
18
+ # Finds all resources of the current type
19
+ # @param keys [Array<String, Symbol, Integer>] Keys to find resources by
20
+ # @param with [Array<Symbol>, Symbol] Subresources to include with the response
21
+ # @param scope_to_user [Boolean] Whether to scope the request to the authenticated user
22
+ # @return [Array<BaseResource>] Collection of resources
23
+ def find_all(keys = [], with: [], scope_to_user: false)
24
+ keys = Array(keys)
25
+ subresources = Transformations::T.wrap_in_array(with)
26
+ data = YFantasy::Api::Client.get(
27
+ collection_name, keys: keys, subresources: subresources, scope_to_user: scope_to_user
28
+ )
29
+ resources = Transformations::CollectionTransformer.new(collection_name).call(data)
30
+ resources.each { |resource| resource.add_fetched_subresources(subresources) }
31
+ resources
32
+ end
33
+
34
+ # Finds a single resource by key
35
+ # @param key [String, Symbol, Integer] The key to find the resource by
36
+ # @param with [Array<Symbol>, Symbol] Subresources to include with the response
37
+ # @param options [Hash] Additional options for the request
38
+ # @return [BaseResource] The requested resource
39
+ # @raise [Error] If invalid options are provided
40
+ def find(key, with: [], **options)
41
+ validate_options(options)
42
+ subresources = Transformations::T.wrap_in_array(with)
43
+ SubresourceValidator.validate!(self, subresources)
44
+ # TODO: Remove
45
+ # puts "\n YFantasy::Api::Client.get('#{resource_name}', '#{key}', #{subresources}, #{options}) \n"
46
+
47
+ data = YFantasy::Api::Client.get(resource_name, keys: key, subresources: subresources, **options)
48
+ resource = Transformations.transformer_for(resource_name).call(data)
49
+ resource.add_fetched_subresources(subresources)
50
+ resource
51
+ end
52
+
53
+ # Always returns false for primary resources (anything that inherits from BaseResource)
54
+ # @return [Boolean] False by default.
55
+ def dependent?
56
+ false
57
+ end
58
+
59
+ # Returns the resource name as a symbol
60
+ # @return [Symbol, nil] The resource name or nil if this is the BaseResource
61
+ def resource_name
62
+ return if base_resource?
63
+
64
+ to_s.split("::").last.scan(/[A-Z][a-z]+/).join("_").downcase.to_sym
65
+ end
66
+
67
+ # Returns the collection name (aka pluralized resource name)
68
+ # @return [Symbol, nil] The collection name or nil if this is the BaseResource
69
+ def collection_name
70
+ return if base_resource?
71
+
72
+ :"#{resource_name}s"
73
+ end
74
+
75
+ private
76
+
77
+ # Determines if this is the base resource class
78
+ # @return [Boolean] True if this is the BaseResource class
79
+ def base_resource?
80
+ self == YFantasy::BaseResource
81
+ end
82
+
83
+ # Creates a transformer that instantiates a single object of the given class
84
+ # @param klass [Class] The class to instantiate
85
+ # @return [Transformations::Instantiator] A transformer that instantiates the class
86
+ def instance_of(klass)
87
+ Transformations::Instantiator.new(klass)
88
+ end
89
+
90
+ # Creates a transformer that instantiates an array of objects of the given class
91
+ # @param klass [Class] The class to instantiate
92
+ # @return [Transformations::Instantiator] A transformer that instantiates an array of the class
93
+ def array_of(klass)
94
+ Transformations::Instantiator.new(klass, collection: true)
95
+ end
96
+
97
+ # Validates options hash for API requests
98
+ # @param options [Hash] Options hash to validate
99
+ # @raise [Error] If invalid options are provided
100
+ def validate_options(options)
101
+ return unless options[:scope_to_user]
102
+
103
+ raise Error.new("`scope_to_user` is not valid when requesting a single resource. Use `.find_all`.")
104
+ end
105
+ end
106
+
107
+ # INSTANCE METHODS
108
+
109
+ # Returns the key of the resource
110
+ # @return [Object, nil] The resource key or nil if not applicable
111
+ def key
112
+ if (name = self.class.resource_name)
113
+ public_send(:"#{name}_key")
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YFantasy
4
+ class BaseSubresource
5
+ extend Dry::Initializer[undefined: false]
6
+ include Subresourceable
7
+
8
+ class << self
9
+ def dependent?
10
+ true
11
+ end
12
+
13
+ def resource_name
14
+ return if self == YFantasy::BaseSubresource
15
+
16
+ to_s.split("::").last.scan(/[A-Z][a-z]+/).join("_").downcase.to_sym
17
+ end
18
+
19
+ def find(resource_name, key)
20
+ data = YFantasy::Api::Client.get(resource_name, keys: key)
21
+ Transformations.transformer_for(resource_name).call(data)
22
+ end
23
+
24
+ private
25
+
26
+ def array_of(klass)
27
+ Transformations::Instantiator.new(klass, collection: true)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YFantasy
4
+ class Game
5
+ # Represents a week in a fantasy game schedule
6
+ class GameWeek < BaseSubresource
7
+ # --- REQUIRED ATTRIBUTES ----------------------------------------------------------------------------------------
8
+
9
+ # @!attribute [r] week
10
+ # @return [Integer] the week number
11
+ option :week, type: Types::Coercible::Integer
12
+
13
+ # @!attribute [r] display_name
14
+ # @return [String] the week number as a string
15
+ option :display_name
16
+
17
+ # @!attribute [r] start
18
+ # @return [Date] week start date
19
+ option :start, type: Types::Params::Date
20
+
21
+ # @!attribute [r] end
22
+ # @return [Date] week end date
23
+ option :end, type: Types::Params::Date
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YFantasy
4
+ class Game
5
+ # Represents a position type within a fantasy game
6
+ class PositionType < BaseSubresource
7
+ # --- REQUIRED ATTRIBUTES ----------------------------------------------------------------------------------------
8
+
9
+ # @!attribute [r] type
10
+ # @return [String] position type abbreviation
11
+ # @example "O", "K", "DT"
12
+ option :type
13
+
14
+ # @!attribute [r] display_name
15
+ # @return [String] full name of the position type
16
+ # @example "Offense", "Kickers", "Defense/Special Teams"
17
+ option :display_name
18
+ end
19
+ end
20
+ end