Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load large set of data #20

Merged
merged 12 commits into from
Jul 22, 2018
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ AllCops:
- 'daru-data_tables.gemspec'
- '**/*.rake'
DisplayCopNames: true
TargetRubyVersion: 2.0
TargetRubyVersion: 2.2

# Preferred codebase style ---------------------------------------------
Layout/ExtraSpacing:
Expand Down
8 changes: 8 additions & 0 deletions lib/daru/data_tables/constants.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# DataTables CSS dependencies
DATATABLES_DEPENDENCIES_CSS = ['jquery.dataTables.css'].freeze

# Dependent DataTables JS constants for IRuby notebook
DATATABLES_DEPENDENCIES_IRUBY = ['jquery.dataTables.js'].freeze

# Dependent DataTables JS constants for web frameworks
DATATABLES_DEPENDENCIES_WEB = ['jquery-latest.min.js', 'jquery.dataTables.js'].freeze
10 changes: 10 additions & 0 deletions lib/daru/data_tables/core_ext/string.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class String
def js_code(true_or_false=true)
@_datatables_js_code = true_or_false
self
end

def js_code?
@_datatables_js_code || false
end
end
68 changes: 65 additions & 3 deletions lib/daru/data_tables/data_table.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,72 @@
module Daru
module DataTables
class DataTable
attr_accessor :html_options, :element_id, :options
def initialize(options={})
attr_accessor :html_options, :element_id, :options, :data
# @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 Initializes the Daru::DataTables::DataTable object
# @example
# vec = Daru::Vector.new([1, 2, 3], name: :a)
# opts = {searching: false}
# table = Daru::DataTables::DataTable.new(vec, opts)
def initialize(data=[], options={})
@element_id = options.delete(:element_id) unless options[:element_id].nil?
@options = options.empty? ? nil : options
@html_options = options.delete(:html_options) unless options[:html_options].nil?
@html_options ||= default_html_options
@data = data
@options = options
@options[:data] = to_data_array(data)
row_number = 0
@options[:data].each do |array|
array.unshift(row_number)
row_number += 1
end
end

private

def default_html_options
table_opts = {
class: 'display',
cellspacing: '0',
width: '100%'
}
html_options = {
table_options: table_opts
}
html_options
end

# DataTables accept the data as Array of array.
#
# TODO : I didn't find use case for Daru::MultiIndex.
def to_data_array(data_set)
case
when data_set.is_a?(Daru::DataFrame)
return ArgumentError unless data_set.index.is_a?(Daru::Index)
rows = data_set.access_row_tuples_by_indexs(*data_set.index.to_a)
convert_to_array_of_array(rows)
when data_set.is_a?(Daru::Vector)
rows = []
data_set.to_a.each { |a| rows << [a] }
rows
when data_set.is_a?(Array)
convert_to_array_of_array(data_set)
else
raise ArgumentError, 'Invalid Argument Passed!'
end
end

def convert_to_array_of_array(rows)
if rows.all? { |row| row.class==Array }
rows
else
tuples = []
rows.each { |row| tuples << [row] }
tuples
end
end
end
end
Expand Down
118 changes: 86 additions & 32 deletions lib/daru/data_tables/display/display.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,57 @@
require_relative 'iruby_notebook'
require_relative '../generate_js/generate_js'
require 'action_view'
require 'daru/data_tables/constants'

module Daru
module DataTables
# dependent script for the library. It must be added in the head tag
# of the web application.
#
# @example
#
# dep_js = DataTables.init_script
#
# use in Rails app : <%=raw dep_js %>
#
def self.init_script(
dependent_js=[
'jquery-latest.min.js', 'jquery.dataTables.js'
],
dependent_css=['jquery.dataTables.css']
# @param dependent_js [Array] dependent js files required
# @return [String] js code of the dependent files
def self.init_javascript(
dependent_js=DATATABLES_DEPENDENCIES_WEB
)
# TODO: there are many js and css files, that must be added for
# more features. Refer: https://datatables.net/download/index
js = ''
js << "\n<script type='text/javascript'>"
js << Daru::DataTables.generate_init_code_js(dependent_js)
js << "\n</script>"
js << "\n<style type='text/css'>"
js << Daru::DataTables.generate_init_code_css(dependent_css)
js << "\n</style>"
js
end

# @param [Array] dependent css files required
# @return [String] CSS code of the dependent file(s)
def self.init_css(
dependent_css=DATATABLES_DEPENDENCIES_CSS
)
css = ''
css << "\n<style type='text/css'>"
css << Daru::DataTables.generate_init_code_css(dependent_css)
css << "\n</style>"
css
end

# dependent script for the library. It must be added in the head tag
# of the web application.
#
# @return [String] code of the dependent css and js file(s)
# @example
#
# dep_js = DataTables.init_script
#
# use in Rails app : <%=raw dep_js %>
def self.init_script
init_code = ''
init_code << init_css
init_code << init_javascript
init_code
end

module Display
# @param dom [String] The ID of the DIV element that the DataTable
# should be rendered in
# @param options [Hash] options provided
# @return [String] js script to render the table
def show_script(dom=SecureRandom.uuid, options={})
script_tag = options.fetch(:script_tag) { true }
if script_tag
Expand All @@ -48,42 +68,76 @@ def show_script(dom=SecureRandom.uuid, options={})
# If table_options is not present then it will assume that table tag is
# already present in the web page source, where we are pasting the
# html code.
# @param id [String] The ID of the DIV element that the DataTable
# should be rendered in
# @param options [Hash] options provided
# @return [String] Generates JavaScript and renders the table in the
# final HTML output.
def to_html(id=nil, options={})
# More things can be added into table_script.erb
path = File.expand_path('../../templates/table_script.erb', __FILE__)
path = File.expand_path('../templates/table_script.erb', __dir__)
template = File.read(path)
id ||= SecureRandom.uuid # TODO: remove it or Use it for table tag.
table_script = show_script(id, script_tag: false)
element_id ||= id
table_script = show_script(element_id, script_tag: false)
html_code = ERB.new(template).result(binding)
# table_options is given. That means table html code is not present in
# the webpage. So it must generate table code with given options.
unless options[:table_options].nil?
options[:table_options][:id] = id
table_thead_tbody = options[:table_options].delete(:table_html)
table_thead_tbody ||= ''
html_code.concat(
content_tag('table', table_thead_tbody.html_safe, options[:table_options])
)
end
table_thead = extract_table
draw_table_thead(element_id, html_code, table_thead)
html_code
end

# @param dom [String] The ID of the DIV element that the DataTable
# should be rendered in
# @return [void] shows the datatable in IRuby notebook
def show_in_iruby(dom=SecureRandom.uuid)
IRuby.html(to_html(dom))
end

# Generates JavaScript and renders the tabke in the final HTML output.
#
# Parameters:
# *element_id [Required] The ID of the DIV element that the table should be rendered in.
# @param element_id [String] The ID of the DIV element that the DataTable
# should be rendered in
# @return [String] returns the javascript of the DataTable
def to_js(element_id)
js = ''
js << "\n<script type='text/javascript'>"
js << draw_js(element_id)
js << "\n</script>"
js
end
end # module Display end

private

def extract_table
return data.to_html_thead unless data.is_a?(Array)
path = File.expand_path('../templates/thead.erb', __dir__)
template = File.read(path)
ERB.new(template).result(binding)
end

def draw_table_thead(element_id, html_code, table_thead)
if html_options && html_options[:table_options]
draw_table_thead_from_html_options(element_id, html_code, table_thead)
# if user provided html_options but not provided html_options[:table_options]
else
html_code.concat(
content_tag(
'table', table_thead.html_safe, id: element_id, class: 'display'
)
)
end
end

def draw_table_thead_from_html_options(element_id, html_code, table_thead)
html_options[:table_options][:id] = element_id
html_options[:table_options][:class] ||= 'display'
table_thead = html_options[:table_options].delete(:table_thead) if
html_options[:table_options][:table_thead]
html_code.concat(
content_tag('table', table_thead.html_safe, html_options[:table_options])
)
end
end

class DataTable
include ActionView::Helpers::TagHelper # to use content_tag
Expand Down
12 changes: 7 additions & 5 deletions lib/daru/data_tables/display/iruby_notebook.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
require 'daru/data_tables/constants'

module Daru
module DataTables
# generate initializing code
def self.generate_init_code_js(dependent_js)
js_dir = File.expand_path('../../js', __FILE__)
path = File.expand_path('../../templates/init.inline.js.erb', __FILE__)
js_dir = File.expand_path('../js', __dir__)
path = File.expand_path('../templates/init.inline.js.erb', __dir__)
template = File.read(path)
ERB.new(template).result(binding)
end

def self.generate_init_code_css(dependent_css)
css_dir = File.expand_path('../../css', __FILE__)
path = File.expand_path('../../templates/init.inline.css.erb', __FILE__)
css_dir = File.expand_path('../css', __dir__)
path = File.expand_path('../templates/init.inline.css.erb', __dir__)
template = File.read(path)
ERB.new(template).result(binding)
end
Expand All @@ -25,7 +27,7 @@ def self.generate_init_code_css(dependent_css)
# DataTables.init_iruby
#
def self.init_iruby(
dependent_js=['jquery.dataTables.js']
dependent_js=DATATABLES_DEPENDENCIES_IRUBY
)
# dependent_css=['jquery.dataTables.css']
# Note: Jquery is dependecy for DataTables.
Expand Down
Loading