Skip to content

Commit

Permalink
Merge pull request #104 from Prakriti-nith/convert_to_array
Browse files Browse the repository at this point in the history
Updated API, added tests, docs, export_html method and generate_html method
  • Loading branch information
Shekharrajak authored Jul 22, 2018
2 parents 8d4f389 + e759f4b commit b3251fc
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 52 deletions.
133 changes: 84 additions & 49 deletions lib/daru/view/adapters/datatables.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'daru/data_tables'
require 'daru'
require 'securerandom'
require 'erb'

module Daru
module View
Expand All @@ -10,80 +11,114 @@ module DatatablesAdapter

# Read : https://datatables.net/ to understand
# the datatables option concept.
# Along with these options, a user can provide an additional option
# html_options[:table_options] to cistomize the generated table
# See the specs of daru-data_tables gem.
#
# TODO : this docs must be improved
# @param data [Array, Daru::DataFrame, Daru::Vector] The data provided
# by the user to generate the datatable
# @param options [Hash] Various options provided by the user to
# incorporate in datatable
# @return [Daru::DataTables::DataTable] Returns the datatble object
#
# @example DataTable
# Set Daru::View.table_library = :googlecharts (or set adapter option)
# (Also set Daru::View.dependent_script(:googlecharts) in web
# frameworks in head tag)
# Formulate the data to visualize
# idx = Daru::Index.new ['Year', 'Sales']
# data_rows = [
# ['2004', 1000],
# ['2005', 1170],
# ['2006', 660],
# ['2007', 1030]
# ]
# df_sale_exp = Daru::DataFrame.rows(data_rows)
# df_sale_exp.vectors = idx
#
# Set the options required
# options1 = {
# html_options: {
# table_options: {
# table_thead: "<thead>
# <tr>
# <th></th>
# <th>C1</th>
# <th>C2</th>
# </tr>
# </thead>",
# width: '90%'
# }
# },
# scrollX: true
# }
# options2 = {searching: false}
#
# Draw the Daru::View::Table object.
# table = Daru::View::Table.new(df_sale_exp, options1)
# table2 = Daru::View::Table.new(df_sale_exp, options2)
# table3 = Daru::View::Table.new(df_sale_exp)
def init_table(data=[], options={}, _user_options={})
# TODO : create data array from the df and vector data. So that
# we can directly use the array.(No need to create df or vector and
# generate the html table using to_html)
if data.is_a?(Array)
data_name = 'series_data'+ SecureRandom.uuid
data =
if data.all? { |e| e.class==Array }
Daru::DataFrame.rows(data, name: data_name)
else
Daru::Vector.new(data, name: data_name)
end
end
# options[:data] = data_in_array unless data_in_array.empty?
@table = Daru::DataTables::DataTable.new(options)
@data = data
@table = Daru::DataTables::DataTable.new(data, options)
@table
end

# @return [String] returns code of the dependent JS and CSS file(s)
def init_script
Daru::DataTables.init_script
end

# @param table [Daru::DataTables::DataTable] table object to access
# daru-data_table methods
# @return [String] script and table (containg thead only) tags of the
# datatable generated
def generate_body(table)
table_opts = {
class: 'display',
cellspacing: '0',
width: '100%',
table_html: @data.to_html_thead + @data.to_html_tbody
}
html_options ={
table_options: table_opts
}
table.to_html(@data.name, html_options)
table.to_html
end

# @param table [Daru::DataTables::DataTable] table object to access
# daru-data_table methods
# @return [void] writes the html code of the datatable to the file
# @example
# table = Daru::View::Table.new(data, options)
# table.export_html_file
def export_html_file(table, path='./table.html')
# TODO
path = File.expand_path(path, Dir.pwd)
str = generate_html(table)
File.write(path, str)
end

# @param table [Daru::DataTables::DataTable] table object to access
# daru-data_table methods
# @return [void] shows the datatable in IRuby notebook
# @example
# table = Daru::View::Table.new(data, options)
# table.show_in_iruby
def show_in_iruby(table)
table.show_in_iruby
end

# @param table [Daru::DataTables::DataTable] table object to access
# daru-data_table methods
# @return [String] returns html code of the datatable generated
def generate_html(table)
# TODO
path = File.expand_path(
'../templates/datatables/static_html.erb', __dir__
)
template = File.read(path)
table_script = generate_body(table)
initial_script = init_script
id = table.element_id
ERB.new(template).result(binding)
end

# @return [void] loads the dependent JS and CSS files in IRuby notebook
# @example
# table = Daru::View::Table.new(data, options)
# table.init_iruby
def init_iruby
Daru::DataTables.init_iruby
end

private

# DataTables accept the data as Array of array.
#
# TODO : I didn't find use case for multi index.
def to_data_array(data_set)
case
when data_set.is_a?(Daru::DataFrame)
return ArgumentError unless data_set.index.is_a?(Daru::Index)
data_set.access_row_tuples_by_indexs(*data_set.index.to_a)
when data_set.is_a?(Daru::Vector)
rows = []
data_set.to_a.each { |a| rows << [a] }
rows
when data_set.is_a?(Array)
data_set
else
raise ArgumentError # TODO: error msg
end
end
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions lib/daru/view/templates/datatables/static_html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html lang='en'>
<head>
<title>DataTable_<%= id %></title>
<%= initial_script %>
</head>
<body>
<%= table_script %>
</body>
</html>
140 changes: 137 additions & 3 deletions spec/adapters/datatables_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
describe Daru::View::Table, 'table using daru-data_tables' do
before { Daru::View.table_library = :datatables }
before(:each) do
@data_vec1 = Daru::Vector.new([1 ,2, 4])
@data_vec1 = Daru::Vector.new([1 ,2, 4], name: :a)
@data_vec2 = Daru::Vector.new([15 ,30, 40])
@data_df = Daru::DataFrame.new(arr1: @data_vec1, arr2: @data_vec2)
@options = {width: 800, height: 720}
@options = {scrollX: true}

@plot = Daru::View::Table.new(@data_df, @options)
end
let(:options) {{width: 800, height: 720}}
let(:options) {{scrollX: true}}
let(:string_array) {["daru", "view"]}
let(:data_array) {[[1, 15], [2, 30], [4, 40]]}
let(:table_string_array) { Daru::View::Table.new(string_array, options) }
let(:table_array) { Daru::View::Table.new(data_array, options) }
let(:table_dv) { Daru::View::Table.new(@data_vec1, @options) }

describe "initialization Tables" do
it "Table class must be Daru::DataTables::DataTable" do
Expand All @@ -35,4 +36,137 @@
expect(table_array.options).to eq options
end
end

describe "#init_script" do
subject(:js) { table_array.init_script }
it "loads correct dependent js and css files" do
expect(js).to match(/jquery-latest.min.js/)
expect(js).to match(/jquery.dataTables.js/)
expect(js).to match(/jquery.dataTables.css/)
end
end

describe "#generate_body" do
context 'when data is set as Daru::DataFrame' do
subject(:js) { @plot.adapter.generate_body(@plot.table) }
it 'generates valid script and table' do
expect(js).to match(/DataTable/)
expect(js).to match(
/scrollX: true, data: \[\[0,1,15\],\[1,2,30\],\[2,4,40\]\]/
)
expect(js).to match(/<th><\/th>/i)
expect(js).to match(/<th>arr1<\/th>/i)
expect(js).to match(/<th>arr2<\/th>/i)
end
end

# In Daru, thead is generated only when the name of the vector is provided
context 'when data is set as Daru::Vector' do
subject(:js) { table_dv.adapter.generate_body(table_dv.table) }
it 'generates valid script and table' do
expect(js).to match(/DataTable/)
expect(js).to match(
/scrollX: true, data: \[\[0,1\],\[1,2\],\[2,4\]\]/
)
expect(js).to match(/<th> <\/th>/i)
expect(js).to match(/<th>a<\/th>/i)
end
end

context 'when data is set as Array' do
subject(:js) {
table_string_array.adapter.generate_body(table_string_array.table)
}
it 'generates valid script and table' do
expect(js).to match(/DataTable/)
expect(js).to match(
/scrollX: true, data: \[\[0,"daru"\],\[1,"view"\]\]/
)
expect(js).to match(/<th><\/th>/i)
expect(js).to match(/<th>Column: 0<\/th>/i)
end
end

context 'when data is set as Array of Arrays' do
subject(:js) {
table_string_array.adapter.generate_body(table_string_array.table)
}
it 'generates valid script and table' do
expect(js).to match(/DataTable/)
expect(js).to match(
/scrollX: true, data: \[\[0,"daru"\],\[1,"view"\]\]/
)
expect(js).to match(/<th><\/th>/i)
expect(js).to match(/<th>Column: 0<\/th>/i)
end
end
end

describe "#export_html_file" do
context 'when large dataset is used' do
before do
array_large = []
for i in 0..50000
array_large << i
end
table_array_large = Daru::View::Table.new(array_large, options)
table_array_large.export_html_file('./plot.html')
@path = File.expand_path('../../plot.html', __dir__)
end
subject(:content) { File.read(@path) }
it "writes correct dependent js and css files" do
expect(content).to match(/jquery-latest.min.js/)
expect(content).to match(/jquery.dataTables.js/)
expect(content).to match(/jquery.dataTables.css/)
end
it "writes a script" do
expect(content).to match(/html/i)
expect(content).to match(/script/i)
end
it "writes server side html code of the DataTable to the file" do
expect(content).to match(
/data_array = \[\[0, 0\], \[1, 1\], \[2, 2\]/
)
expect(content).to match(
/scrollX: true, serverSide: true, ajax:/
)
expect(content).to match(
/function \( data, callback, settings \) {/)
expect(content).to match(/out.push\( data_array\[i\] \);/i)
expect(content).to match(/callback\( \{/i)
end
it "generates a table" do
expect(content).to match(/<th><\/th>/i)
expect(content).to match(/<th>Column: 0<\/th>/i)
end
end

context 'when small dataset is used' do
before do
@plot.export_html_file('./plot.html')
@path = File.expand_path('../../plot.html', __dir__)
end
subject(:content) { File.read(@path) }
it "writes correct dependent js and css files" do
expect(content).to match(/jquery-latest.min.js/)
expect(content).to match(/jquery.dataTables.js/)
expect(content).to match(/jquery.dataTables.css/)
end
it "writes a script" do
expect(content).to match(/html/i)
expect(content).to match(/script/i)
end
it "writes client side html code of the DataTable to the file" do
expect(content).to match(/DataTable/)
expect(content).to match(
/scrollX: true, data: \[\[0,1,15\],\[1,2,30\],\[2,4,40\]\]/
)
end
it "generates a table" do
expect(content).to match(/<th><\/th>/i)
expect(content).to match(/<th>arr1<\/th>/i)
expect(content).to match(/<th>arr2<\/th>/i)
end
end
end
end

0 comments on commit b3251fc

Please sign in to comment.