|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +module IrtRuby |
| 4 | + # Validates response data accepted by IRT model constructors. |
| 5 | + # @api private |
| 6 | + module ResponseDataValidator |
| 7 | + module_function |
| 8 | + |
| 9 | + def validate!(data) |
| 10 | + raise ArgumentError, "response data must be a Matrix or array of arrays" unless valid_data_container?(data) |
| 11 | + |
| 12 | + data_array = data.to_a |
| 13 | + |
| 14 | + raise ArgumentError, "response data must have at least one row" unless data_array.any? |
| 15 | + |
| 16 | + validate_rows!(data_array) |
| 17 | + validate_values!(data_array) |
| 18 | + |
| 19 | + data_array |
| 20 | + end |
| 21 | + |
| 22 | + def validate_rows!(data_array) |
| 23 | + first_row = data_array.first |
| 24 | + |
| 25 | + raise ArgumentError, "response data must be a Matrix or array of arrays" unless first_row.is_a?(Array) |
| 26 | + |
| 27 | + expected_columns = first_row.size |
| 28 | + raise ArgumentError, "response data must have at least one column" if expected_columns.zero? |
| 29 | + |
| 30 | + data_array.each_with_index do |row, index| |
| 31 | + row_number = index + 1 |
| 32 | + raise ArgumentError, "response data row #{row_number} 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 #{row_number} 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_response?(value) |
| 44 | + |
| 45 | + raise ArgumentError, |
| 46 | + "response data contains invalid value #{value.inspect} at row #{row_index + 1}, column #{column_index + 1}; allowed values are 0, 1, and nil" |
| 47 | + end |
| 48 | + end |
| 49 | + end |
| 50 | + |
| 51 | + def valid_response?(value) |
| 52 | + value.nil? || value.eql?(0) || value.eql?(1) |
| 53 | + end |
| 54 | + |
| 55 | + def valid_data_container?(data) |
| 56 | + data.is_a?(Array) || (defined?(::Matrix) && data.is_a?(::Matrix)) |
| 57 | + end |
| 58 | + end |
| 59 | +end |
0 commit comments