Implement CharacterProcessor
Process character data from deck
This commit is contained in:
parent
d6ca8e8e90
commit
3378e7114f
2 changed files with 141 additions and 0 deletions
89
app/services/processors/character_processor.rb
Normal file
89
app/services/processors/character_processor.rb
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Processors
|
||||
##
|
||||
# CharacterProcessor processes an array of character data and creates GridCharacter records.
|
||||
#
|
||||
# @example
|
||||
# processor = Processors::CharacterProcessor.new(party, transformed_characters_array)
|
||||
# processor.process
|
||||
class CharacterProcessor < BaseProcessor
|
||||
def initialize(party, data, type = :normal, options = {})
|
||||
super(party, data, options)
|
||||
@party = party
|
||||
@data = data
|
||||
end
|
||||
|
||||
##
|
||||
# Processes character data.
|
||||
#
|
||||
# Iterates over each character hash in +data+ and creates a new GridCharacter record.
|
||||
# Expects each character hash to include keys such as :id, :position, :uncap, etc.
|
||||
#
|
||||
# @return [void]
|
||||
def process
|
||||
unless @data.is_a?(Hash)
|
||||
Rails.logger.error "[CHARACTER] Invalid data format: expected a Hash, got #{@data.class}"
|
||||
return
|
||||
end
|
||||
|
||||
unless @data.key?('deck') && @data['deck'].key?('npc')
|
||||
Rails.logger.error '[CHARACTER] Missing npc data in deck JSON'
|
||||
return
|
||||
end
|
||||
|
||||
@data = @data.with_indifferent_access
|
||||
characters_data = @data['deck']['npc']
|
||||
|
||||
grid_characters = process_characters(characters_data)
|
||||
grid_characters.each do |grid_character|
|
||||
begin
|
||||
grid_character.save!
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
Rails.logger.error "[CHARACTER] Failed to create GridCharacter: #{e.record.errors.full_messages.join(', ')}"
|
||||
end
|
||||
end
|
||||
|
||||
rescue StandardError => e
|
||||
raise e
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_characters(characters_data)
|
||||
characters_data.map do |key, raw_character|
|
||||
next if raw_character.nil? || raw_character['param'].nil? || raw_character['master'].nil?
|
||||
|
||||
position = key.to_i - 1
|
||||
|
||||
# Find the Character record by its granblue_id.
|
||||
character_id = raw_character.dig('master', 'id')
|
||||
character = Character.find_by(granblue_id: character_id)
|
||||
|
||||
unless character
|
||||
Rails.logger.error "[CHARACTER] Character not found with id #{character_id}"
|
||||
next
|
||||
end
|
||||
|
||||
# The deck doesn't have Awakening data, so use the default
|
||||
awakening = Awakening.where(slug: 'character-balanced').first
|
||||
grid_character = GridCharacter.create(
|
||||
party_id: @party.id,
|
||||
character_id: character.id,
|
||||
uncap_level: raw_character.dig('param', 'evolution').to_i,
|
||||
transcendence_step: raw_character.dig('param', 'phase').to_i,
|
||||
position: position,
|
||||
perpetuity: raw_character.dig('param', 'has_npcaugment_constant'),
|
||||
awakening: awakening
|
||||
)
|
||||
|
||||
grid_character
|
||||
end.compact
|
||||
end
|
||||
|
||||
# Converts a value to a boolean.
|
||||
def parse_boolean(val)
|
||||
val.to_s.downcase == 'true'
|
||||
end
|
||||
end
|
||||
end
|
||||
52
spec/services/processors/character_processor_spec.rb
Normal file
52
spec/services/processors/character_processor_spec.rb
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Processors::CharacterProcessor, type: :model do
|
||||
before(:each) do
|
||||
@party = create(:party)
|
||||
end
|
||||
|
||||
# Use canonical data loaded via canonical.rb.
|
||||
let(:deck_data) do
|
||||
file_path = Rails.root.join('spec', 'fixtures', 'deck_sample2.json')
|
||||
JSON.parse(File.read(file_path))
|
||||
end
|
||||
|
||||
subject! { described_class.new(@party, deck_data, language: 'en') }
|
||||
|
||||
context 'with valid character data' do
|
||||
it 'creates the correct number of GridCharacter records' do
|
||||
expect { subject.process }.to change(GridCharacter, :count).by(5)
|
||||
end
|
||||
|
||||
it 'creates GridCharacters with the correct attributes' do
|
||||
subject.process
|
||||
grid_chars = GridCharacter.where(party_id: @party.id).order(:position)
|
||||
|
||||
# We assume the processor uses the character id from raw_data.
|
||||
expect(grid_chars[0].character.granblue_id).to eq(deck_data.dig('deck', 'npc', '1', 'master', 'id'))
|
||||
expect(grid_chars[3].uncap_level).to eq(deck_data.dig('deck', 'npc', '4', 'param', 'evolution').to_i)
|
||||
expect(grid_chars[4].position).to eq(4)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid character data' do
|
||||
let(:deck_data) { 'invalid data' }
|
||||
it 'does not create any GridCharacter and logs an error containing "CHARACTER"' do
|
||||
expect { subject.process }.not_to change(GridCharacter, :count)
|
||||
|
||||
begin
|
||||
subject.process
|
||||
rescue StandardError
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
after(:each) do |example|
|
||||
if example.exception
|
||||
puts "\nDEBUG [CharacterProcessor]: #{example.full_description} failed with error: #{example.exception.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue