|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +module IrtRuby |
| 4 | + # Validates response data accepted by IRT model constructors. |
| 5 | + module ResponseDataValidator |
| 6 | + VALID_RESPONSES = [0, 1, nil].freeze |
| 7 | + |
| 8 | + module_function |
| 9 | + |
| 10 | + def validate!(data) |
| 11 | + raise ArgumentError, "response data must be a Matrix or array of arrays" unless data.respond_to?(:to_a) |
| 12 | + |
| 13 | + data_array = data.to_a |
| 14 | + |
| 15 | + raise ArgumentError, "response data must have at least one row" unless data_array.is_a?(Array) && data_array.any? |
| 16 | + |
| 17 | + validate_rows!(data_array) |
| 18 | + validate_values!(data_array) |
| 19 | + |
| 20 | + data_array |
| 21 | + end |
| 22 | + |
| 23 | + def validate_rows!(data_array) |
| 24 | + first_row = data_array.first |
| 25 | + |
| 26 | + raise ArgumentError, "response data must be a Matrix or array of arrays" unless first_row.is_a?(Array) |
| 27 | + |
| 28 | + expected_columns = first_row.size |
| 29 | + raise ArgumentError, "response data must have at least one column" if expected_columns.zero? |
| 30 | + |
| 31 | + data_array.each_with_index do |row, index| |
| 32 | + raise ArgumentError, "response data row #{index} must be an Array" unless row.is_a?(Array) |
| 33 | + |
| 34 | + next if row.size == expected_columns |
| 35 | + |
| 36 | + raise ArgumentError, "response data must be rectangular; row #{index} has #{row.size} columns, expected #{expected_columns}" |
| 37 | + end |
| 38 | + end |
| 39 | + |
| 40 | + def validate_values!(data_array) |
| 41 | + data_array.each_with_index do |row, row_index| |
| 42 | + row.each_with_index do |value, column_index| |
| 43 | + next if VALID_RESPONSES.include?(value) |
| 44 | + |
| 45 | + raise ArgumentError, |
| 46 | + "response data contains invalid value #{value.inspect} at row #{row_index}, column #{column_index}; allowed values are 0, 1, and nil" |
| 47 | + end |
| 48 | + end |
| 49 | + end |
| 50 | + end |
| 51 | +end |
0 commit comments