Class: EwsDataReader

Inherits:
Object
  • Object
show all
Defined in:
lib/udise_school_report_reader/ews_data_reader.rb

Constant Summary collapse

GRADES =
[
  'Pre-Pri.', 'Class I', 'Class II', 'Class III', 'Class IV', 'Class V',
  'Class VI', 'Class VII', 'Class VIII', 'Class IX', 'Class X', 'Class XI', 'Class XII'
]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(csv_path) ⇒ EwsDataReader

Returns a new instance of EwsDataReader.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/udise_school_report_reader/ews_data_reader.rb', line 9

def initialize(csv_path)
  @csv_path = csv_path
  @rows = Hash.new { |h, k| h[k] = [] }
  
  # Group cells by rect_y and rect_x
  CSV.foreach(@csv_path, headers: true) do |cell|
    next unless cell['page'] == '1'

    rect_y = cell['rect_y'].to_f
    @rows[rect_y] << cell
  end

  # Find the title row
  @title_row = @rows.find { |_, cells| cells.any? { |cell| cell&.dig('text')&.include?('Total no. of Economically Weaker Section*(EWS) students Enrolled in Schools') } }
  
  title_y = @title_row&.first
  return unless title_y

  # Get all rows below title in descending order
  rows_after_title = @rows.select { |y, _| y < title_y.to_f }
                         .sort_by(&:first)
                         .reverse

  # Get the next 3 rows after title
  return unless rows_after_title.size >= 3
  
  @grades_row = rows_after_title[0].last
  @bg_row = rows_after_title[1].last
  @values_row = rows_after_title[2].last

  # Sort cells within each row by x coordinate
  [@grades_row, @bg_row].each do |row|
    next unless row
    row.sort_by! { |cell| cell['text_x'].to_f }
  end

  # For values row, ensure we have a value for each B/G pair
  if @values_row && @bg_row
    sorted_values = []
    @bg_row.each_slice(2) do |b, g|
      b_x = b['text_x'].to_f
      g_x = g['text_x'].to_f
      
      # Find or create value for boys
      b_val = @values_row.find { |cell| (cell['text_x'].to_f - b_x).abs < 10.0 }
      b_val ||= { 'text' => '-', 'text_x' => b_x }
      sorted_values << b_val
      
      # Find or create value for girls
      g_val = @values_row.find { |cell| (cell['text_x'].to_f - g_x).abs < 10.0 }
      g_val ||= { 'text' => '-', 'text_x' => g_x }
      sorted_values << g_val
    end
    @values_row = sorted_values
  end

  # Normalize empty values to "-"
  @values_row&.each { |cell| cell['text'] = '-' if cell['text'].strip.empty? }

  # Ensure we have all grades
  found_grades = @grades_row.map { |cell| cell['text'] }
  missing_grades = GRADES - found_grades
  if missing_grades.any?
    # Removed puts statement
  end
end

Class Method Details

.read(csv_path) ⇒ Object



7
# File 'lib/udise_school_report_reader/ews_data_reader.rb', line 7

def self.read(csv_path) = new(csv_path).read

Instance Method Details

#readObject



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/udise_school_report_reader/ews_data_reader.rb', line 76

def read
  return nil unless @grades_row && @bg_row && @values_row

  # Group B,G pairs, ensuring we have complete pairs
  bg_pairs = {}
  @bg_row.each_slice(2) do |pair|
    next unless pair.size == 2 && pair[0] && pair[1]  # Skip incomplete pairs
    b, g = pair
    x_mid = (b['text_x'].to_f + g['text_x'].to_f) / 2
    bg_pairs[x_mid] = [b, g]
  end

  # Match numbers to pairs
  {
    grade_rows: @grades_row,
    bg_pairs: bg_pairs,
    ews_numbers: match_numbers_to_pairs(@values_row, bg_pairs),
  }
end