module IRuby module LaTeX extend self def vector(v) x = 'c' * v.size y = v.map(&:to_s).join(' & ') "$$\\left(\\begin{array}{#{x}} #{y} \\end{array}\\right)$$" end def matrix(m, row_count, column_count) s = "$$\\left(\\begin{array}{#{'c' * column_count}}\n" (0...row_count).each do |i| s << ' ' << m[i,0].to_s (1...column_count).each do |j| s << '&' << m[i,j].to_s end s << "\\\\\n" end s << "\\end{array}\\right)$$" end end module HTML extend self 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 = '' if header1 && options[:header] != false table << '' << header1.map {|k| "" }.join table << "" << header2.map {|k| "" }.join if keys2 table << '' end row_block(table, rows1, keys1, keys2) if rows2 table << " 1 ? " colspan='#{keys1.size}'" : ''}>⋮" table << " 1 ? " colspan='#{keys2.size}'" : ''}>⋮" if keys2 table << '' row_block(table, rows2, keys1, keys2) end table << '
#{cell k}#{cell k}
' end private def cell(obj) obj.respond_to?(:to_html) ? obj.to_html : obj end def elem(row, k) cell((row[k] rescue nil)) end def row_block(table, rows, keys1, keys2) cols = keys1.size cols += keys2.size + 1 if keys2 rows.each_with_index do |row, i| table << '' if row.respond_to?(:map) row_html = keys1.map {|k| "#{elem row, k}" }.join if keys2 row_html << " 1 ? " rowspan='#{rows.size}'" : ''}>…" if i == 0 row_html << keys2.map {|k| "#{elem row, k}" }.join end if row_html.empty? table << " 1 ? " colspan='#{cols}'" : ''}>" else table << row_html end else table << " 1 ? " colspan='#{cols}'" : ''}>#{cell row}" end table << '' end end end end