module IRuby::HTML

Public Instance Methods

table(obj, maxrows: 15, maxcols: 15, **options) click to toggle source
# File lib/iruby/formatter.rb, line 27
def table(obj, maxrows: 15, maxcols: 15, **options)
  raise ArgumentError, 'Invalid :maxrows' if maxrows && maxrows < 3
  raise ArgumentError, 'Invalid :maxcols' if maxcols && maxcols < 3

  return obj unless obj.respond_to?(:each)

  rows = []

  if obj.respond_to?(:keys)
    # Hash of Arrays
    header = obj.keys
    keys = (0...obj.keys.size).to_a
    cols = obj.values.map {|x| [x].flatten(1) }
    num_rows = cols.map(&:size).max
    rows = []
    (0...num_rows).each do |i|
      rows << []
      (0...cols.size).each do |j|
        rows[i][j] = cols[j][i]
      end
    end
  else
    keys = nil
    array_size = 0

    obj.each do |row|
      if row.respond_to?(:keys)
        # Array of Hashes
        keys ||= Set.new
        keys.merge(row.keys)
      elsif row.respond_to?(:map)
        # Array of Arrays
        array_size = row.size if array_size < row.size
      end
      rows << row
    end

    if keys
      header = keys.to_a
      keys.merge(0...array_size)
    else
      keys = 0...array_size
    end
    keys = keys.to_a
  end

  header ||= keys if options[:header]

  rows1, rows2 = rows, nil
  keys1, keys2 = keys, nil
  header1, header2 = header, nil

  if maxcols && keys.size > maxcols
    keys1 = keys[0...maxcols / 2]
    keys2 = keys[-maxcols / 2...-1]
    if header
      header1 = header[0...maxcols / 2]
      header2 = header[-maxcols / 2...-1]
    end
  end

  if maxrows && rows.size > maxrows
    rows1 = rows[0...maxrows / 2]
    rows2 = rows[-maxrows / 2...-1]
  end

  table = '<table>'

  if header1 && options[:header] != false
    table << '<tr>' << header1.map {|k| "<th>#{cell k}</th>" }.join
    table << "<th>&#8230;</th>" << header2.map {|k| "<th>#{cell k}</th>" }.join if keys2
    table << '</tr>'
  end

  row_block(table, rows1, keys1, keys2)

  if rows2
    table << "<tr><td#{keys1.size > 1 ? " colspan='#{keys1.size}'" : ''}>&#8942;</td>"
    table << "<td>&#8945;</td><td#{keys2.size > 1 ? " colspan='#{keys2.size}'" : ''}>&#8942;</td>" if keys2
    table << '</tr>'

    row_block(table, rows2, keys1, keys2)
  end

  table << '</table>'
end

Private Instance Methods

cell(obj) click to toggle source
# File lib/iruby/formatter.rb, line 116
def cell(obj)
  obj.respond_to?(:to_html) ? obj.to_html : obj
end
elem(row, k) click to toggle source
# File lib/iruby/formatter.rb, line 120
def elem(row, k)
  cell((row[k] rescue nil))
end
row_block(table, rows, keys1, keys2) click to toggle source
# File lib/iruby/formatter.rb, line 124
def row_block(table, rows, keys1, keys2)
  cols = keys1.size
  cols += keys2.size + 1 if keys2
  rows.each_with_index do |row, i|
    table << '<tr>'
    if row.respond_to?(:map)
      row_html = keys1.map {|k| "<td>#{elem row, k}</td>" }.join
      if keys2
        row_html << "<td#{rows.size > 1 ? " rowspan='#{rows.size}'" : ''}>&#8230;</td>" if i == 0
        row_html << keys2.map {|k| "<td>#{elem row, k}</td>" }.join
      end
      if row_html.empty?
        table << "<td#{cols > 1 ? " colspan='#{cols}'" : ''}></td>"
      else
        table << row_html
      end
    else
      table << "<td#{cols > 1 ? " colspan='#{cols}'" : ''}>#{cell row}</td>"
    end
    table << '</tr>'
  end
end