Module: Vapir::HasRowsAndColumns

Included in:
TBody, Table
Defined in:
lib/vapir-common/elements/elements.rb

Instance Method Summary collapse

Instance Method Details

#[](index) ⇒ Object

Returns the TableRow at the given index. indices start at 1.



701
702
703
# File 'lib/vapir-common/elements/elements.rb', line 701

def [](index)
  rows[index]
end

#cell(first = nil, second = nil) ⇒ Object

returns a TableCell which is a cell of this of this Table or TBody (not in a nested table). takes the usual arguments for specifying what you want - see github.com/vapir/vapir/wiki/Locators



609
610
611
612
613
614
615
616
# File 'lib/vapir-common/elements/elements.rb', line 609

def cell(first=nil, second=nil)
  element_by_howwhat(element_class_for(Vapir::TableCell), first, second, :extra => {:candidates => proc do |container|
    container_object=container.element_object
    object_collection_to_enumerable(container_object.rows).inject([]) do |candidates, row|
      candidates+object_collection_to_enumerable(row.cells).to_a
    end
  end})
end

#cellsObject

returns all of the cells of this table. to get the cells including nested tables, use #table_cells, which is defined on all containers (including Table)



720
721
722
723
724
725
726
727
# File 'lib/vapir-common/elements/elements.rb', line 720

def cells
  ElementCollection.new(self, element_class_for(Vapir::TableCell), extra_for_contained.merge(:candidates => proc do |container|
    container_object=container.element_object
    object_collection_to_enumerable(container_object.rows).inject([]) do |candidates, row|
      candidates+object_collection_to_enumerable(row.cells).to_a
    end
  end))
end

#column_count(index = nil) ⇒ Object

returns the number of columns of the table, either on the row at the given index or (by default) on the first row. takes into account any defined colSpans. returns nil if the table has no rows. (if you want the number of cells - not taking into account colspans - use #cell_count on the row in question)



735
736
737
738
739
740
741
742
743
# File 'lib/vapir-common/elements/elements.rb', line 735

def column_count(index=nil)
  if index
    rows[index].column_count
  elsif row=rows.first
    row.column_count
  else
    nil
  end
end

#column_texts_at(column_index) ⇒ Object

Returns an array containing the text of the cell in the specified index in each row.



758
759
760
761
762
763
# File 'lib/vapir-common/elements/elements.rb', line 758

def column_texts_at(column_index)
  # TODO: since this is named as 'column', not 'cell', shouldn't it return cell_at_column? 
  rows.map do |row|
    row.cells[column_index].text
  end
end

#each_rowObject Also known as: each

iterates through the rows in the table. Yields a TableRow object



692
693
694
695
696
# File 'lib/vapir-common/elements/elements.rb', line 692

def each_row
  rows.each do |row|
    yield row
  end
end

#row(first = nil, second = nil) ⇒ Object

returns a TableRow which is a row of this of this Table or TBody (not in a nested table). takes the usual arguments for specifying what you want - see github.com/vapir/vapir/wiki/Locators



603
604
605
# File 'lib/vapir-common/elements/elements.rb', line 603

def row(first=nil, second=nil)
  element_by_howwhat(element_class_for(Vapir::TableRow), first, second, :extra => {:candidates => :rows})
end

#row_countObject

Returns the number of rows inside the table. does not recurse through nested tables. same as (object).rows.length

if you want the row count including nested tables (which this brokenly used to return) use (object).table_rows.length



710
711
712
# File 'lib/vapir-common/elements/elements.rb', line 710

def row_count
  element_object.rows.length
end

#row_count_excluding_nested_tablesObject

Raises:

  • (NotImplementedError)


714
715
716
# File 'lib/vapir-common/elements/elements.rb', line 714

def row_count_excluding_nested_tables
  raise NotImplementedError, "the method \#row_count_excluding_nested_tables is gone. the \#row_count method now returns the number of rows in this #{self.class}. for the number of rows including nested tables, use [this object].table_rows.length"
end

#row_texts_at(row_index) ⇒ Object

Returns an array of the text of each cell in the row at the given index.



750
751
752
753
754
# File 'lib/vapir-common/elements/elements.rb', line 750

def row_texts_at(row_index)
  rows[row_index].cells.map do |cell|
    cell.text
  end
end

#to_aObject

Returns a 2 dimensional array of text contents of each row and column of the table or tbody.



619
620
621
# File 'lib/vapir-common/elements/elements.rb', line 619

def to_a
  rows.map{|row| row.cells.map{|cell| cell.text.strip}}
end

#to_hashes(options = {}) ⇒ Object

Returns an array of hashes representing this table. This assumes that the table has one row with header information and any number of rows with data. Each element of the array is a hash whose keys are the header values (every hash has the same keys), and whose values correspond to the current row.

+--------------+---------------+
| First Header | Second Header |
| First Data 1 | Second Data 1 |
| First Data 2 | Second Data 2 |
+--------------+---------------+

Given the above table, #to_hashes will return

[{'First Header' => 'First Data 1', 'Second Header' => 'Second Data 1'}, {'First Header' => 'First Data 2', 'Second Header' => 'Second Data 2'}]

This method will correctly account for colSpans and return text from all cells underneath a given header on one row. However, this method makes no attempt to deal with any rowSpans and will probably not work with any table with rowSpans in either the header row or data rows.

options:

  • :header_count (default 1) - the number of rows before the table data start.

  • :header_index (default whatever :header_count is) - the index of the row that contains header data which will be the keys of the hashes returned. (1-indexed)

  • :footer_count (default 0) - the number of rows to discard from the end, being footer information and not table data.

  • :separator (default ‘ ’) - used to join cells when there is more than one cell underneath a header.



649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
# File 'lib/vapir-common/elements/elements.rb', line 649

def to_hashes(options={})
  options=handle_options(options, {:header_count => 1, :footer_count => 0, :separator => ' '}, [:header_index])
  options[:header_index]||=options[:header_count]
  
  col_headings=rows[options[:header_index]].cells.map do |cell|
    {:colSpan => cell.colSpan || 1, :text => cell.text.strip}
  end
  
  body_range=(options[:header_count]+1 .. self.row_count-options[:footer_count])
  return body_range.map do |row_index|
    row=rows[row_index]
    # cells_by_heading will contain an array of arrays of table cells 
    # underneath the col_heading corresponding to cells_by_heading's array index. 
    # if cells do not line up underneath the column heading, exception is raised. 
    cells_by_heading=[]
    curr_heading_index=0
    cols_in_curr_heading=0
    row.cells.each do |cell|
      curr_heading=col_headings[curr_heading_index]
      cells_by_heading[curr_heading_index] ||= []
      cells_by_heading[curr_heading_index] << cell
      cols_in_curr_heading += cell.colSpan || 1
      if cols_in_curr_heading == curr_heading[:colSpan]
        curr_heading_index+=1
        cols_in_curr_heading=0
      elsif cols_in_curr_heading > curr_heading[:colSpan]
        raise "Cells underneath heading #{curr_heading[:text].inspect} do not line up!"
      end # else, we haven't got all the cells under the current heading; keep going
    end
    if curr_heading_index > col_headings.length
      raise "Too many cells for the headings!"
    elsif curr_heading_index < col_headings.length
      raise "Too few cells for the headings!"
    end
    
    col_headings.zip(cells_by_heading).inject({}) do |row_hash, (heading, cells)|
      cell_texts=cells.map(&:text).join(options[:separator]).strip
      row_hash.merge(heading[:text] => cell_texts)
    end
  end
end