jumbotron 0.1.5 → 0.1.7

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: 31fa4d11ab93d13b5e6db4ab799f05f69b6153067ceb0894677e07bd785c27a3
4
- data.tar.gz: 2f660fdbdf85bb67f9212c6c8c55b6bc9f49a2699c643070a5496946d8894259
3
+ metadata.gz: 59e55efb1ece4d237011869ce7416fd4cda99a2e95feb914c21e93a3f23aecaa
4
+ data.tar.gz: 2199925a6f4a46d2db581c63e2a5eb55b81a26483195a396a4b7c111ae41bee1
5
5
  SHA512:
6
- metadata.gz: ee10748cd68f85baa4c3774ef6f7fbcd4c6376f76927a442a8e4ce1b4e28e34c56f7c6355af29545ba1306f7367e37499a56dbdb00f990e413aea020cf37079e
7
- data.tar.gz: 30e89a701a8dc935ac6d0d4aeffc61d982b6a800d97f86ac43035a23d4ac480bd60485c6c8e96093eaef022b128693ccf0b663b63716dab53385bce0e79ea174
6
+ metadata.gz: ae7c4b2c06eed8291bafcb279940f0ca45ad5b33a62cc5970a5c1d353eae0c4d8bde4173e62811d13dade3038107940a828f37b2b3e1c1d6a7f2c118f62d5447
7
+ data.tar.gz: 8ecd32a04d755e5eb0422fccbb98b10beead9f3b88de8f8e885f2b8e4f458af6a672d1bdf9a63040b88e352186cea328565263dff18d001298b1a0cf97389748
@@ -66,6 +66,21 @@ module Jumbotron
66
66
  INTERRUPTED_LIFECYCLES.include?(game.lifecycle)
67
67
  }
68
68
 
69
+ # Bounded post-final scoreboard re-observation when post-game record is still
70
+ # missing (Strategy B). Stops after window or once post_game is persisted.
71
+ policy :post_final_record,
72
+ type: :post_final_game_update,
73
+ cadence: Cadence.new(every: 15, unit: :minute),
74
+ eligible: lambda { |game, now:|
75
+ return false unless game.lifecycle == "completed"
76
+ return false if game.changed_at.nil? || game.changed_at < now - 6.hours
77
+
78
+ participants = game.game_participants
79
+ return false if participants.empty?
80
+
81
+ participants.any? { |participant| participant.record_summary_post_game.blank? }
82
+ }
83
+
69
84
  policy :far_future_lines,
70
85
  type: :future_line_update,
71
86
  cadence: Cadence.new(every: 1, unit: :week),
@@ -80,11 +80,14 @@ module Jumbotron
80
80
  raise TransformError, "venue id required" if venue.id.blank?
81
81
  raise TransformError, "venue name required" if venue.full_name.blank?
82
82
 
83
+ address = venue.respond_to?(:address) ? venue.address : nil
83
84
  Canonical::VenueInput.new(
84
85
  provider_identities: [
85
86
  Canonical::ProviderIdentityRef.new(provider: "espn", namespace: "venue", id: venue.id.to_s)
86
87
  ],
87
- name: venue.full_name.to_s
88
+ name: venue.full_name.to_s,
89
+ city: address&.city.presence,
90
+ region: address&.state.presence
88
91
  )
89
92
  end
90
93
  private_class_method :transform_venue
@@ -103,13 +106,23 @@ module Jumbotron
103
106
  Canonical::ProviderIdentityRef.new(provider: "espn", namespace: "team", id: team.id.to_s)
104
107
  ],
105
108
  team_name: name.to_s,
109
+ team_nickname: TeamNickname.resolve(team),
110
+ team_abbreviation: team.abbreviation.presence,
106
111
  role: competitor.home_away.to_s,
107
112
  score: coerce_score(competitor.score),
108
- result: coerce_result(competitor.winner, lifecycle)
113
+ result: coerce_result(competitor.winner, lifecycle),
114
+ record_summary: total_record_summary(competitor)
109
115
  )
110
116
  end
111
117
  private_class_method :transform_participant
112
118
 
119
+ def self.total_record_summary(competitor)
120
+ records = competitor.respond_to?(:records) ? Array(competitor.records) : []
121
+ total = records.find { |record| record.type.to_s == "total" }
122
+ total&.summary.presence
123
+ end
124
+ private_class_method :total_record_summary
125
+
113
126
  def self.coerce_score(raw)
114
127
  return nil if raw.nil? || raw == ""
115
128
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jumbotron
4
+ module Adapters
5
+ module Espn
6
+ module NflHelpers
7
+ # Maps ESPN team identity fields into canonical nickname without parsing display_name.
8
+ # Precedence: nickname → name → short_display_name (provider fields only).
9
+ module TeamNickname
10
+ def self.resolve(team)
11
+ return nil if team.nil?
12
+
13
+ team.nickname.presence || team.name.presence || team.short_display_name.presence
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -24,7 +24,9 @@ module Jumbotron
24
24
  provider_identities: [
25
25
  Canonical::ProviderIdentityRef.new(provider: "espn", namespace: "team", id: team.id.to_s)
26
26
  ],
27
- name: name.to_s
27
+ name: name.to_s,
28
+ nickname: TeamNickname.resolve(team),
29
+ abbreviation: team.abbreviation.presence
28
30
  )
29
31
  end
30
32
  private_class_method :transform_team
@@ -13,6 +13,7 @@ module Jumbotron
13
13
  field :winner, type: Support.types.boolean, nullable: true
14
14
  field :order, type: Support.types.integer, nullable: true
15
15
  field :team, type: Team::Result, required: true
16
+ field :records, type: Support.types.array(CompetitorRecord::Result), nullable: true
16
17
  end
17
18
 
18
19
  def self.call(payload)
@@ -25,10 +26,22 @@ module Jumbotron
25
26
  score: coerce_score(Support.payload.fetch(payload, "score")),
26
27
  winner: Support.payload.fetch(payload, "winner"),
27
28
  order: Support.payload.fetch(payload, "order"),
28
- team: Support.nest("team", Support.payload.fetch(payload, "team")) { |raw| Team.call(raw) }
29
+ team: Support.nest("team", Support.payload.fetch(payload, "team")) { |raw| Team.call(raw) },
30
+ records: map_records(Support.payload.fetch(payload, "records"))
29
31
  )
30
32
  end
31
33
 
34
+ def self.map_records(raw)
35
+ return nil if raw.equal?(Support.missing) || raw.nil?
36
+
37
+ Array(raw).each_with_index.map do |item, index|
38
+ CompetitorRecord.call(item)
39
+ rescue CommandTower::Clients::Errors::DeserializationError => e
40
+ raise CommandTower::Deserializers::Clients::Errors.prefix(e, "records[#{index}]")
41
+ end
42
+ end
43
+ private_class_method :map_records
44
+
32
45
  def self.coerce_id(raw)
33
46
  return raw if raw.equal?(Support.missing) || raw.nil? || raw.is_a?(String)
34
47
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jumbotron
4
+ module Deserializers
5
+ module Clients
6
+ module Espn
7
+ class CompetitorRecord
8
+ class Result < CommandTower::Deserializers::Clients::Result
9
+ field :type, type: Support.types.string, required: true
10
+ field :summary, type: Support.types.string, required: true
11
+ field :name, type: Support.types.string, nullable: true
12
+ end
13
+
14
+ def self.call(payload)
15
+ Support.ensure_hash!(payload, label: "competitor.record")
16
+
17
+ Result.build!(
18
+ type: Support.payload.fetch(payload, "type"),
19
+ summary: Support.payload.fetch(payload, "summary"),
20
+ name: Support.payload.fetch(payload, "name")
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -12,6 +12,7 @@ module Jumbotron
12
12
  field :display_name, type: Support.types.string, required: true
13
13
  field :short_display_name, type: Support.types.string, nullable: true
14
14
  field :name, type: Support.types.string, nullable: true
15
+ field :nickname, type: Support.types.string, nullable: true
15
16
  field :location, type: Support.types.string, nullable: true
16
17
  end
17
18
 
@@ -25,6 +26,7 @@ module Jumbotron
25
26
  display_name: Support.payload.fetch(payload, "displayName"),
26
27
  short_display_name: Support.payload.fetch(payload, "shortDisplayName"),
27
28
  name: Support.payload.fetch(payload, "name"),
29
+ nickname: Support.payload.fetch(payload, "nickname"),
28
30
  location: Support.payload.fetch(payload, "location")
29
31
  )
30
32
  end
@@ -9,6 +9,7 @@ module Jumbotron
9
9
  field :id, type: Support.types.string, required: true
10
10
  field :full_name, type: Support.types.string, required: true
11
11
  field :indoor, type: Support.types.boolean, nullable: true
12
+ field :address, type: VenueAddress::Result, nullable: true
12
13
  end
13
14
 
14
15
  def self.call(payload)
@@ -17,10 +18,18 @@ module Jumbotron
17
18
  Result.build!(
18
19
  id: coerce_id(Support.payload.fetch(payload, "id")),
19
20
  full_name: Support.payload.fetch(payload, "fullName"),
20
- indoor: Support.payload.fetch(payload, "indoor")
21
+ indoor: Support.payload.fetch(payload, "indoor"),
22
+ address: map_address(Support.payload.fetch(payload, "address"))
21
23
  )
22
24
  end
23
25
 
26
+ def self.map_address(raw)
27
+ return nil if raw.equal?(Support.missing) || raw.nil?
28
+
29
+ VenueAddress.call(raw)
30
+ end
31
+ private_class_method :map_address
32
+
24
33
  def self.coerce_id(raw)
25
34
  return raw if raw.equal?(Support.missing) || raw.nil? || raw.is_a?(String)
26
35
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jumbotron
4
+ module Deserializers
5
+ module Clients
6
+ module Espn
7
+ class VenueAddress
8
+ class Result < CommandTower::Deserializers::Clients::Result
9
+ field :city, type: Support.types.string, nullable: true
10
+ field :state, type: Support.types.string, nullable: true
11
+ field :country, type: Support.types.string, nullable: true
12
+ end
13
+
14
+ def self.call(payload)
15
+ Support.ensure_hash!(payload, label: "venue.address")
16
+
17
+ Result.build!(
18
+ city: Support.payload.fetch(payload, "city"),
19
+ state: Support.payload.fetch(payload, "state"),
20
+ country: Support.payload.fetch(payload, "country")
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -4,17 +4,41 @@ module Jumbotron
4
4
  module Canonical
5
5
  ProviderIdentityRef = Data.define(:provider, :namespace, :id)
6
6
 
7
- TeamInput = Data.define(:provider_identities, :name)
7
+ TeamInput = Data.define(:provider_identities, :name, :nickname, :abbreviation) do
8
+ def initialize(provider_identities:, name:, nickname: nil, abbreviation: nil)
9
+ super
10
+ end
11
+ end
8
12
 
9
- VenueInput = Data.define(:provider_identities, :name)
13
+ VenueInput = Data.define(:provider_identities, :name, :city, :region) do
14
+ def initialize(provider_identities:, name:, city: nil, region: nil)
15
+ super
16
+ end
17
+ end
10
18
 
11
19
  ParticipantInput = Data.define(
12
20
  :provider_identities,
13
21
  :team_name,
14
22
  :role,
15
23
  :score,
16
- :result
17
- )
24
+ :result,
25
+ :team_nickname,
26
+ :team_abbreviation,
27
+ :record_summary
28
+ ) do
29
+ def initialize(
30
+ provider_identities:,
31
+ team_name:,
32
+ role:,
33
+ score:,
34
+ result:,
35
+ team_nickname: nil,
36
+ team_abbreviation: nil,
37
+ record_summary: nil
38
+ )
39
+ super
40
+ end
41
+ end
18
42
 
19
43
  ScheduleGroupInput = Data.define(:kind, :number, :name)
20
44
 
@@ -19,9 +19,21 @@ module Jumbotron
19
19
  :season_phase,
20
20
  :kind
21
21
  )
22
- Team = Data.define(:id, :name, :key)
23
- Venue = Data.define(:id, :name)
24
- Participant = Data.define(:role, :score, :result, :team)
22
+ Team = Data.define(:id, :name, :nickname, :key, :abbreviation) do
23
+ def initialize(id:, name:, key:, nickname: nil, abbreviation: nil)
24
+ super(id:, name:, nickname:, key:, abbreviation:)
25
+ end
26
+ end
27
+ Venue = Data.define(:id, :name, :city, :region) do
28
+ def initialize(id:, name:, city: nil, region: nil)
29
+ super
30
+ end
31
+ end
32
+ Participant = Data.define(:role, :score, :result, :team, :record) do
33
+ def initialize(role:, score:, result:, team:, record: nil)
34
+ super
35
+ end
36
+ end
25
37
  GameSegment = Data.define(:kind, :number)
26
38
  # Clock label text. Name is canonical/public contract, not Kernel#display.
27
39
  GameClock = Data.define(:mode, :seconds, :display) # rubocop:disable Lint/DataDefineOverride
@@ -8,6 +8,7 @@ module Jumbotron
8
8
  future_game_update
9
9
  live_game_update
10
10
  interrupted_game_update
11
+ post_final_game_update
11
12
  ].freeze
12
13
 
13
14
  validate :adapter_id, required: true
@@ -20,7 +20,7 @@ module Jumbotron
20
20
  end
21
21
 
22
22
  games = Game.where(league_id: league.id)
23
- .includes(:season, :season_phase, :schedule_group)
23
+ .includes(:season, :season_phase, :schedule_group, :game_participants)
24
24
  .select { |game| policy.eligible?(game, now: now) }
25
25
 
26
26
  context.league = league
@@ -13,7 +13,9 @@ module Jumbotron
13
13
  team_result = UpsertTeam.call(
14
14
  team_input: Jumbotron::Canonical::TeamInput.new(
15
15
  provider_identities: participant_input.provider_identities,
16
- name: participant_input.team_name
16
+ name: participant_input.team_name,
17
+ nickname: participant_input.team_nickname,
18
+ abbreviation: participant_input.team_abbreviation
17
19
  ),
18
20
  observed_at: observed_at,
19
21
  change_set: change_set
@@ -45,16 +47,18 @@ module Jumbotron
45
47
  end
46
48
 
47
49
  def create_new!(team)
48
- gp = game.game_participants.create!(
50
+ attrs = {
49
51
  team: team,
50
52
  role: participant_input.role,
51
53
  score: participant_input.score,
52
54
  result: participant_input.result,
53
55
  observed_at: observed_at,
54
56
  changed_at: observed_at
55
- )
57
+ }.merge(initial_record_attrs)
58
+ gp = game.game_participants.create!(attrs)
56
59
  change_set.record(subject: gp, attribute: "role", previous: nil, new_value: gp.role)
57
60
  change_set.record(subject: gp, attribute: "score", previous: nil, new_value: gp.score)
61
+ record_create_history!(gp)
58
62
  gp
59
63
  end
60
64
 
@@ -77,11 +81,96 @@ module Jumbotron
77
81
  participant.public_send("#{key}=", value)
78
82
  material = true
79
83
  end
84
+ material |= apply_record_snapshots!(participant)
80
85
  participant.observed_at = observed_at
81
86
  participant.changed_at = observed_at if material
82
87
  participant.save!
83
88
  participant
84
89
  end
90
+
91
+ def initial_record_attrs
92
+ summary = participant_input.record_summary
93
+ return {} if summary.blank?
94
+
95
+ attrs = {
96
+ record_summary_current: summary,
97
+ record_observed_at: observed_at
98
+ }
99
+ if game.lifecycle == "completed"
100
+ attrs[:record_summary_post_game] = summary
101
+ elsif game.lifecycle != "cancelled"
102
+ attrs[:record_summary_entering] = summary
103
+ end
104
+ attrs
105
+ end
106
+
107
+ def record_create_history!(participant)
108
+ %i[
109
+ record_summary_entering
110
+ record_summary_current
111
+ record_summary_post_game
112
+ ].each do |attr|
113
+ value = participant.public_send(attr)
114
+ next if value.blank?
115
+
116
+ change_set.record(subject: participant, attribute: attr.to_s, previous: nil, new_value: value)
117
+ end
118
+ end
119
+
120
+ def apply_record_snapshots!(participant)
121
+ summary = participant_input.record_summary
122
+ return false if summary.blank?
123
+
124
+ material = false
125
+ if participant.record_summary_current != summary
126
+ change_set.record(
127
+ subject: participant,
128
+ attribute: "record_summary_current",
129
+ previous: participant.record_summary_current,
130
+ new_value: summary
131
+ )
132
+ participant.record_summary_current = summary
133
+ material = true
134
+ end
135
+ participant.record_observed_at = observed_at
136
+
137
+ if game.lifecycle == "completed"
138
+ material |= apply_post_game_record!(participant, summary)
139
+ elsif game.lifecycle != "cancelled"
140
+ material |= assign_entering_record!(participant, summary)
141
+ end
142
+ material
143
+ end
144
+
145
+ def assign_entering_record!(participant, summary) # rubocop:disable Naming/PredicateMethod
146
+ return false if participant.record_summary_entering == summary
147
+
148
+ change_set.record(
149
+ subject: participant,
150
+ attribute: "record_summary_entering",
151
+ previous: participant.record_summary_entering,
152
+ new_value: summary
153
+ )
154
+ participant.record_summary_entering = summary
155
+ true
156
+ end
157
+
158
+ # Authoritative post-game only: never invent W–L; if total still equals
159
+ # entering on a completed observation, leave post_game nil (Strategy B).
160
+ def apply_post_game_record!(participant, summary) # rubocop:disable Naming/PredicateMethod
161
+ entering = participant.record_summary_entering
162
+ return false if entering.present? && summary == entering
163
+ return false if participant.record_summary_post_game == summary
164
+
165
+ change_set.record(
166
+ subject: participant,
167
+ attribute: "record_summary_post_game",
168
+ previous: participant.record_summary_post_game,
169
+ new_value: summary
170
+ )
171
+ participant.record_summary_post_game = summary
172
+ true
173
+ end
85
174
  end
86
175
  end
87
176
  end
@@ -57,6 +57,8 @@ module Jumbotron
57
57
  team.name = team_input.name
58
58
  team.changed_at = observed_at
59
59
  end
60
+ apply_nickname!(team)
61
+ apply_abbreviation!(team)
60
62
  # key is immutable after assignment — never regenerate from name or provider id
61
63
  team.observed_at = observed_at
62
64
  team.save!
@@ -66,15 +68,61 @@ module Jumbotron
66
68
  def create_new!
67
69
  team = Team.create!(
68
70
  name: team_input.name,
71
+ nickname: team_input.nickname,
72
+ abbreviation: team_input.abbreviation,
69
73
  key: allocate_key!(team_input.name),
70
74
  observed_at: observed_at,
71
75
  changed_at: observed_at
72
76
  )
73
77
  change_set.record(subject: team, attribute: "name", previous: nil, new_value: team.name)
74
78
  change_set.record(subject: team, attribute: "key", previous: nil, new_value: team.key)
79
+ if team.nickname.present?
80
+ change_set.record(
81
+ subject: team,
82
+ attribute: "nickname",
83
+ previous: nil,
84
+ new_value: team.nickname
85
+ )
86
+ end
87
+ if team.abbreviation.present?
88
+ change_set.record(
89
+ subject: team,
90
+ attribute: "abbreviation",
91
+ previous: nil,
92
+ new_value: team.abbreviation
93
+ )
94
+ end
75
95
  team
76
96
  end
77
97
 
98
+ def apply_nickname!(team)
99
+ return if team_input.nickname.nil?
100
+ return if team.nickname == team_input.nickname
101
+
102
+ change_set.record(
103
+ subject: team,
104
+ attribute: "nickname",
105
+ previous: team.nickname,
106
+ new_value: team_input.nickname
107
+ )
108
+ team.nickname = team_input.nickname
109
+ team.changed_at = observed_at
110
+ end
111
+
112
+ def apply_abbreviation!(team)
113
+ return if team_input.abbreviation.nil?
114
+ return if team.abbreviation == team_input.abbreviation
115
+
116
+ change_set.record(
117
+ subject: team,
118
+ attribute: "abbreviation",
119
+ previous: team.abbreviation,
120
+ new_value: team_input.abbreviation
121
+ )
122
+ team.abbreviation = team_input.abbreviation
123
+ team.changed_at = observed_at
124
+ end
125
+
78
126
  def allocate_key!(name)
79
127
  base = Jumbotron::TeamKey.normalize(name)
80
128
  return base unless Team.exists?(key: base)
@@ -52,6 +52,7 @@ module Jumbotron
52
52
 
53
53
  def update_existing!(venue_id)
54
54
  venue = Venue.lock.find(venue_id)
55
+ material = false
55
56
  if venue.name != venue_input.name
56
57
  change_set.record(
57
58
  subject: venue,
@@ -60,8 +61,10 @@ module Jumbotron
60
61
  new_value: venue_input.name
61
62
  )
62
63
  venue.name = venue_input.name
63
- venue.changed_at = observed_at
64
+ material = true
64
65
  end
66
+ material |= apply_location!(venue)
67
+ venue.changed_at = observed_at if material
65
68
  venue.observed_at = observed_at
66
69
  venue.save!
67
70
  venue
@@ -70,13 +73,42 @@ module Jumbotron
70
73
  def create_new!
71
74
  venue = Venue.create!(
72
75
  name: venue_input.name,
76
+ city: venue_input.city,
77
+ region: venue_input.region,
73
78
  observed_at: observed_at,
74
79
  changed_at: observed_at
75
80
  )
76
81
  change_set.record(subject: venue, attribute: "name", previous: nil, new_value: venue.name)
82
+ if venue.city.present?
83
+ change_set.record(subject: venue, attribute: "city", previous: nil, new_value: venue.city)
84
+ end
85
+ if venue.region.present?
86
+ change_set.record(subject: venue, attribute: "region", previous: nil, new_value: venue.region)
87
+ end
77
88
  venue
78
89
  end
79
90
 
91
+ def apply_location!(venue)
92
+ material = false
93
+ {
94
+ city: venue_input.city,
95
+ region: venue_input.region
96
+ }.each do |key, value|
97
+ next if value.nil?
98
+ next if venue.public_send(key) == value
99
+
100
+ change_set.record(
101
+ subject: venue,
102
+ attribute: key.to_s,
103
+ previous: venue.public_send(key),
104
+ new_value: value
105
+ )
106
+ venue.public_send("#{key}=", value)
107
+ material = true
108
+ end
109
+ material
110
+ end
111
+
80
112
  def recover_after_race!
81
113
  ref = venue_input.provider_identities.first
82
114
  identity = ProviderIdentity.find_by!(
@@ -61,7 +61,12 @@ module Jumbotron
61
61
  def build_venue(venue)
62
62
  return if venue.nil?
63
63
 
64
- Jumbotron::Public::Venue.new(id: venue.id, name: venue.name)
64
+ Jumbotron::Public::Venue.new(
65
+ id: venue.id,
66
+ name: venue.name,
67
+ city: venue.city,
68
+ region: venue.region
69
+ )
65
70
  end
66
71
 
67
72
  def build_participant(participant)
@@ -69,14 +74,28 @@ module Jumbotron
69
74
  role: participant.role,
70
75
  score: participant.score,
71
76
  result: participant.result,
77
+ record: resolve_presentation_record(participant),
72
78
  team: Jumbotron::Public::Team.new(
73
79
  id: participant.team.id,
74
80
  name: participant.team.name,
75
- key: participant.team.key
81
+ nickname: participant.team.nickname,
82
+ key: participant.team.key,
83
+ abbreviation: participant.team.abbreviation
76
84
  )
77
85
  )
78
86
  end
79
87
 
88
+ # Lifecycle-resolved game-time record for presentation. Never falls back to
89
+ # entering when completed post-game is missing.
90
+ def resolve_presentation_record(participant)
91
+ case game.lifecycle
92
+ when "scheduled", "in_progress", "postponed", "suspended"
93
+ participant.record_summary_entering
94
+ when "completed"
95
+ participant.record_summary_post_game
96
+ end
97
+ end
98
+
80
99
  def map_currents(lines)
81
100
  return [] unless Array(includes).include?(:current_lines)
82
101
 
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddNicknameToJumbotronTeams < ActiveRecord::Migration[8.0]
4
+ def change
5
+ add_column :jumbotron_teams, :nickname, :string
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddGamePresentationContractFields < ActiveRecord::Migration[8.0]
4
+ def change
5
+ change_table :jumbotron_game_participants, bulk: true do |t|
6
+ t.string :record_summary_entering
7
+ t.string :record_summary_current
8
+ t.string :record_summary_post_game
9
+ t.datetime :record_observed_at
10
+ end
11
+
12
+ change_table :jumbotron_venues, bulk: true do |t|
13
+ t.string :city
14
+ t.string :region
15
+ end
16
+
17
+ add_column :jumbotron_teams, :abbreviation, :string
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jumbotron
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.7"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jumbotron
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - matt-taylor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-27 00:00:00.000000000 Z
11
+ date: 2026-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: command_tower
@@ -65,6 +65,7 @@ files:
65
65
  - app/adapters/jumbotron/adapters/espn/nfl_helpers/progress.rb
66
66
  - app/adapters/jumbotron/adapters/espn/nfl_helpers/scoreboard.rb
67
67
  - app/adapters/jumbotron/adapters/espn/nfl_helpers/season_phase.rb
68
+ - app/adapters/jumbotron/adapters/espn/nfl_helpers/team_nickname.rb
68
69
  - app/adapters/jumbotron/adapters/espn/nfl_helpers/teams.rb
69
70
  - app/adapters/jumbotron/adapters/line_acquisition.rb
70
71
  - app/adapters/jumbotron/adapters/operation.rb
@@ -90,6 +91,7 @@ files:
90
91
  - app/deserializers/jumbotron/deserializers/clients/espn/competition_odds/side_quote.rb
91
92
  - app/deserializers/jumbotron/deserializers/clients/espn/competition_odds/team_odds.rb
92
93
  - app/deserializers/jumbotron/deserializers/clients/espn/competitor.rb
94
+ - app/deserializers/jumbotron/deserializers/clients/espn/competitor_record.rb
93
95
  - app/deserializers/jumbotron/deserializers/clients/espn/event.rb
94
96
  - app/deserializers/jumbotron/deserializers/clients/espn/scoreboard/get.rb
95
97
  - app/deserializers/jumbotron/deserializers/clients/espn/season.rb
@@ -98,6 +100,7 @@ files:
98
100
  - app/deserializers/jumbotron/deserializers/clients/espn/team.rb
99
101
  - app/deserializers/jumbotron/deserializers/clients/espn/teams/get.rb
100
102
  - app/deserializers/jumbotron/deserializers/clients/espn/venue.rb
103
+ - app/deserializers/jumbotron/deserializers/clients/espn/venue_address.rb
101
104
  - app/deserializers/jumbotron/deserializers/clients/espn/week.rb
102
105
  - app/deserializers/jumbotron/deserializers/public/game.rb
103
106
  - app/deserializers/jumbotron/deserializers/public/game_ids.rb
@@ -206,6 +209,8 @@ files:
206
209
  - db/migrate/20260814000001_create_jumbotron_line_observations.rb
207
210
  - db/migrate/20260820000001_add_progress_to_jumbotron_games.rb
208
211
  - db/migrate/20260827150001_add_key_to_jumbotron_teams.rb
212
+ - db/migrate/20260828180001_add_nickname_to_jumbotron_teams.rb
213
+ - db/migrate/20260828220001_add_game_presentation_contract_fields.rb
209
214
  - docs/testing.md
210
215
  - docs/upgrades/0.1.2.md
211
216
  - docs/upgrades/0.1.3.md