active-list 4.2.4 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/VERSION +1 -1
- data/{lib → app}/assets/images/active-list.png +0 -0
- data/app/assets/images/active-list.svg +415 -0
- data/{lib/assets/javascripts/active-list.jquery.js → app/assets/javascripts/active_list.jquery.js} +2 -2
- data/app/assets/stylesheets/active_list.css.scss +7 -0
- data/{lib/active-list/compass/stylesheets/active-list/_background.scss → app/assets/stylesheets/active_list/background.scss} +10 -8
- data/{lib/active-list/compass/stylesheets/active-list/_minimal.scss → app/assets/stylesheets/active_list/minimal.scss} +16 -16
- data/{lib/active-list/compass/stylesheets/active-list/_theme.scss → app/assets/stylesheets/active_list/theme.scss} +37 -37
- data/lib/active-list.rb +1 -37
- data/lib/active_list.rb +43 -0
- data/lib/active_list/action_pack.rb +46 -0
- data/lib/active_list/definition.rb +17 -0
- data/lib/active_list/definition/abstract_column.rb +54 -0
- data/lib/active_list/definition/action_column.rb +76 -0
- data/lib/active_list/definition/association_column.rb +80 -0
- data/lib/active_list/definition/attribute_column.rb +58 -0
- data/lib/active_list/definition/check_box_column.rb +17 -0
- data/lib/active_list/definition/data_column.rb +88 -0
- data/lib/active_list/definition/empty_column.rb +10 -0
- data/lib/active_list/definition/field_column.rb +20 -0
- data/lib/active_list/definition/status_column.rb +10 -0
- data/lib/active_list/definition/table.rb +159 -0
- data/lib/active_list/definition/text_field_column.rb +10 -0
- data/lib/active_list/exporters.rb +28 -0
- data/lib/active_list/exporters/abstract_exporter.rb +55 -0
- data/lib/active_list/exporters/csv_exporter.rb +32 -0
- data/lib/active_list/exporters/excel_csv_exporter.rb +38 -0
- data/lib/active_list/exporters/open_document_spreadsheet_exporter.rb +82 -0
- data/lib/active_list/generator.rb +122 -0
- data/lib/active_list/generator/finder.rb +150 -0
- data/lib/active_list/helpers.rb +33 -0
- data/lib/{active-list → active_list}/rails/engine.rb +3 -2
- data/lib/active_list/renderers.rb +25 -0
- data/lib/active_list/renderers/abstract_renderer.rb +29 -0
- data/lib/active_list/renderers/simple_renderer.rb +356 -0
- metadata +74 -55
- data/lib/active-list/action_pack.rb +0 -48
- data/lib/active-list/columns/action_column.rb +0 -83
- data/lib/active-list/columns/data_column.rb +0 -151
- data/lib/active-list/columns/field_column.rb +0 -29
- data/lib/active-list/compass/stylesheets/_active-list.scss +0 -7
- data/lib/active-list/definition.rb +0 -103
- data/lib/active-list/exporters.rb +0 -71
- data/lib/active-list/exporters/csv_exporter.rb +0 -30
- data/lib/active-list/exporters/excel_csv_exporter.rb +0 -36
- data/lib/active-list/exporters/open_document_spreadsheet_exporter.rb +0 -81
- data/lib/active-list/finder.rb +0 -134
- data/lib/active-list/generator.rb +0 -88
- data/lib/active-list/renderers.rb +0 -28
- data/lib/active-list/renderers/simple_renderer.rb +0 -335
- data/lib/assets/stylesheets/active-list.css.scss +0 -7
@@ -0,0 +1,28 @@
|
|
1
|
+
# require 'active_support/core_ext/module/attribute_accessors'
|
2
|
+
module ActiveList
|
3
|
+
|
4
|
+
module Exporters
|
5
|
+
|
6
|
+
def self.hash
|
7
|
+
ActiveList.exporters
|
8
|
+
end
|
9
|
+
|
10
|
+
autoload :AbstractExporter, 'active_list/exporters/abstract_exporter'
|
11
|
+
autoload :OpenDocumentSpreadsheetExporter, 'active_list/exporters/open_document_spreadsheet_exporter'
|
12
|
+
autoload :CsvExporter, 'active_list/exporters/csv_exporter'
|
13
|
+
autoload :ExcelCsvExporter, 'active_list/exporters/excel_csv_exporter'
|
14
|
+
end
|
15
|
+
|
16
|
+
mattr_reader :exporters
|
17
|
+
@@exporters = {}
|
18
|
+
|
19
|
+
def self.register_exporter(name, exporter)
|
20
|
+
raise ArgumentError.new("ActiveList::Exporters::AbstractExporter expected (got #{exporter.name}/#{exporter.ancestors.inspect})") unless exporter < ActiveList::Exporters::AbstractExporter
|
21
|
+
@@exporters[name] = exporter
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
ActiveList.register_exporter(:ods, ActiveList::Exporters::OpenDocumentSpreadsheetExporter)
|
27
|
+
ActiveList.register_exporter(:csv, ActiveList::Exporters::CsvExporter)
|
28
|
+
ActiveList.register_exporter(:xcsv, ActiveList::Exporters::ExcelCsvExporter)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveList
|
2
|
+
|
3
|
+
module Exporters
|
4
|
+
|
5
|
+
class AbstractExporter
|
6
|
+
|
7
|
+
attr_reader :table, :generator
|
8
|
+
|
9
|
+
def initialize(generator)
|
10
|
+
@generator = generator
|
11
|
+
@table = generator.table
|
12
|
+
end
|
13
|
+
|
14
|
+
def file_extension
|
15
|
+
"txt"
|
16
|
+
end
|
17
|
+
|
18
|
+
def mime_type
|
19
|
+
Mime::TEXT
|
20
|
+
end
|
21
|
+
|
22
|
+
def send_data_code
|
23
|
+
raise NotImplementedError, "#{self.class.name}#format_data_code is not implemented."
|
24
|
+
end
|
25
|
+
|
26
|
+
def columns_headers(options={})
|
27
|
+
headers, columns = [], table.exportable_columns
|
28
|
+
for column in columns
|
29
|
+
datum = column.header_code
|
30
|
+
headers << (options[:encoding] ? datum+".to_s.encode('#{options[:encoding]}')" : datum)
|
31
|
+
end
|
32
|
+
return headers
|
33
|
+
end
|
34
|
+
|
35
|
+
def columns_to_array(nature, options={})
|
36
|
+
columns = table.exportable_columns
|
37
|
+
|
38
|
+
array = []
|
39
|
+
record = options[:record] || 'record_of_the_death'
|
40
|
+
for column in columns
|
41
|
+
if column.is_a?(ActiveList::Definition::AbstractColumn)
|
42
|
+
if nature == :header
|
43
|
+
datum = column.header_code
|
44
|
+
else
|
45
|
+
datum = column.exporting_datum_code(record)
|
46
|
+
end
|
47
|
+
array << (options[:encoding] ? datum+".to_s.encode('#{options[:encoding]}')" : datum)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return array
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActiveList
|
2
|
+
|
3
|
+
module Exporters
|
4
|
+
|
5
|
+
class CsvExporter < AbstractExporter
|
6
|
+
|
7
|
+
def file_extension
|
8
|
+
"csv"
|
9
|
+
end
|
10
|
+
|
11
|
+
def mime_type
|
12
|
+
Mime::CSV
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_data_code
|
16
|
+
record = "r"
|
17
|
+
code = generator.select_data_code(paginate: false)
|
18
|
+
code << "data = ActiveList::CSV.generate do |csv|\n"
|
19
|
+
code << " csv << [#{columns_to_array(:header).join(', ')}]\n"
|
20
|
+
code << " for #{record} in #{generator.records_variable_name}\n"
|
21
|
+
code << " csv << [#{columns_to_array(:body, record: record).join(', ')}]\n"
|
22
|
+
code << " end\n"
|
23
|
+
code << "end\n"
|
24
|
+
code << "send_data(data, type: #{self.mime_type.to_s.inspect}, disposition: 'inline', filename: #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_') + '.#{self.file_extension}')\n"
|
25
|
+
return code.c
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Register XCSV format unless is already set
|
4
|
+
Mime::Type.register("text/csv", :xcsv) unless defined? Mime::XCSV
|
5
|
+
|
6
|
+
module ActiveList
|
7
|
+
|
8
|
+
module Exporters
|
9
|
+
|
10
|
+
class ExcelCsvExporter < CsvExporter
|
11
|
+
|
12
|
+
def file_extension
|
13
|
+
"csv"
|
14
|
+
end
|
15
|
+
|
16
|
+
def mime_type
|
17
|
+
Mime::XCSV
|
18
|
+
end
|
19
|
+
|
20
|
+
def send_data_code
|
21
|
+
record = "r"
|
22
|
+
code = generator.select_data_code(paginate: false)
|
23
|
+
encoding = "CP1252"
|
24
|
+
code << "data = ActiveList::CSV.generate(:col_sep => ';') do |csv|\n"
|
25
|
+
code << " csv << [#{columns_to_array(:header, encoding: encoding).join(', ')}]\n"
|
26
|
+
code << " for #{record} in #{generator.records_variable_name}\n"
|
27
|
+
code << " csv << [#{columns_to_array(:body, record: record, encoding: encoding).join(', ')}]\n"
|
28
|
+
code << " end\n"
|
29
|
+
code << "end\n"
|
30
|
+
code << "send_data(data, type: #{self.mime_type.to_s.inspect}, disposition: 'inline', filename: #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_')+'.#{self.file_extension}')\n"
|
31
|
+
return code.c
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'zip'
|
3
|
+
|
4
|
+
# Register ODS format unless is already set
|
5
|
+
Mime::Type.register("application/vnd.oasis.opendocument.spreadsheet", :ods) unless defined? Mime::ODS
|
6
|
+
|
7
|
+
module ActiveList
|
8
|
+
|
9
|
+
module Exporters
|
10
|
+
|
11
|
+
class OpenDocumentSpreadsheetExporter < AbstractExporter
|
12
|
+
|
13
|
+
DATE_ELEMENTS = {
|
14
|
+
"m" => "<number:month number:style=\"long\"/>",
|
15
|
+
"d" => "<number:day number:style=\"long\"/>",
|
16
|
+
"Y" => "<number:year/>"
|
17
|
+
}
|
18
|
+
|
19
|
+
def file_extension
|
20
|
+
"ods"
|
21
|
+
end
|
22
|
+
|
23
|
+
def mime_type
|
24
|
+
Mime::ODS
|
25
|
+
end
|
26
|
+
|
27
|
+
def send_data_code
|
28
|
+
xml_escape = "to_s.gsub('&', '&').gsub('\\'', ''').gsub('<', '<').gsub('>', '>')"
|
29
|
+
xml_escape << ".force_encoding('US-ASCII')" if xml_escape.respond_to?(:force_encoding)
|
30
|
+
record = "r"
|
31
|
+
code = generator.select_data_code(paginate: false)
|
32
|
+
code << "name = #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i, '_')\n"
|
33
|
+
code << "file = ::Rails.root.join('tmp', 'export', 'active_list', name + rand.to_s+'.#{self.file_extension}')\n"
|
34
|
+
code << "FileUtils.mkdir_p(file.dirname)\n"
|
35
|
+
code << "Zip::OutputStream.open(file) do |zile|\n"
|
36
|
+
# MimeType in first place
|
37
|
+
code << " zile.put_next_entry('mimetype', nil, nil, Zip::Entry::STORED)\n"
|
38
|
+
code << " zile << '#{self.mime_type}'\n"
|
39
|
+
|
40
|
+
# Manifest
|
41
|
+
code << " zile.put_next_entry('META-INF/manifest.xml')\n"
|
42
|
+
code << " zile << ('<?xml version=\"1.0\" encoding=\"UTF-8\"?><manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"><manifest:file-entry manifest:media-type=\"#{self.mime_type}\" manifest:full-path=\"/\"/><manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/></manifest:manifest>')\n"
|
43
|
+
code << " zile.put_next_entry('content.xml')\n"
|
44
|
+
|
45
|
+
code << " zile << ('<?xml version=\"1.0\" encoding=\"UTF-8\"?><office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" xmlns:ooow=\"http://openoffice.org/2004/writer\" xmlns:oooc=\"http://openoffice.org/2004/calc\" xmlns:dom=\"http://www.w3.org/2001/xml-events\" xmlns:xforms=\"http://www.w3.org/2002/xforms\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:field=\"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0\" office:version=\"1.1\"><office:scripts/>')\n"
|
46
|
+
# Styles
|
47
|
+
code << " zile << ('<office:automatic-styles>"+
|
48
|
+
"<style:style style:name=\"co1\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:use-optimal-column-width=\"true\"/></style:style>"+
|
49
|
+
"<style:style style:name=\"header\" style:family=\"table-cell\"><style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\" style:font-weight-complex=\"bold\"/></style:style>"+
|
50
|
+
"<number:date-style style:name=\"K4D\" number:automatic-order=\"true\"><number:text>"+::I18n.translate("date.formats.default").gsub(/\%./){|x| "</number:text>"+DATE_ELEMENTS[x[1..1]]+"<number:text>"} +"</number:text></number:date-style><style:style style:name=\"ce1\" style:family=\"table-cell\" style:data-style-name=\"K4D\"/>"+
|
51
|
+
"</office:automatic-styles>')\n"
|
52
|
+
|
53
|
+
# Tables
|
54
|
+
code << " zile << ('<office:body><office:spreadsheet><table:table table:name=\"'+#{table.model.name}.model_name.human.#{xml_escape}+'\">')\n"
|
55
|
+
code << " zile << ('<table:table-column table:number-columns-repeated=\"#{table.exportable_columns.size}\"/>')\n"
|
56
|
+
code << " zile << ('<table:table-header-rows><table:table-row>"+columns_headers.collect{|h| "<table:table-cell table:style-name=\"header\" office:value-type=\"string\"><text:p>'+(#{h}).#{xml_escape}+'</text:p></table:table-cell>"}.join+"</table:table-row></table:table-header-rows>')\n"
|
57
|
+
code << " for #{record} in #{generator.records_variable_name}\n"
|
58
|
+
code << " zile << ('<table:table-row>"+table.exportable_columns.collect do |column|
|
59
|
+
"<table:table-cell"+(if column.numeric? or column.datatype==:decimal
|
60
|
+
" office:value-type=\"float\" office:value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
|
61
|
+
elsif column.datatype==:boolean
|
62
|
+
" office:value-type=\"boolean\" office:boolean-value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
|
63
|
+
elsif column.datatype==:date
|
64
|
+
" office:value-type=\"date\" table:style-name=\"ce1\" office:date-value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
|
65
|
+
else
|
66
|
+
" office:value-type=\"string\""
|
67
|
+
end)+"><text:p>'+("+column.exporting_datum_code(record, true)+").#{xml_escape}+'</text:p></table:table-cell>"
|
68
|
+
end.join+"</table:table-row>')\n"
|
69
|
+
code << " end\n"
|
70
|
+
code << " zile << ('</table:table></office:spreadsheet></office:body></office:document-content>')\n"
|
71
|
+
code << "end\n"
|
72
|
+
code << "send_file(file, stream: false, type: #{self.mime_type.to_s.inspect}, disposition: 'inline', filename: name+'.#{self.file_extension}')\n"
|
73
|
+
code << "File.delete(file)\n" # Removes tmp files before they explode the disk
|
74
|
+
# raise code
|
75
|
+
return code
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ActiveList
|
3
|
+
|
4
|
+
class Generator
|
5
|
+
|
6
|
+
attr_accessor :table, :controller, :controller_method_name, :view_method_name, :records_variable_name
|
7
|
+
|
8
|
+
def initialize(*args, &block)
|
9
|
+
options = args.extract_options!
|
10
|
+
@controller = options[:controller]
|
11
|
+
name = args.shift || @controller.controller_name.to_sym
|
12
|
+
model = (options[:model]||name).to_s.classify.constantize
|
13
|
+
@collection = !!(model.name == @controller.controller_name.to_s.classify)
|
14
|
+
@controller_method_name = "list#{'_'+name.to_s if name != @controller.controller_name.to_sym}"
|
15
|
+
@view_method_name = "_#{@controller.controller_name}_list_#{name}_tag"
|
16
|
+
@records_variable_name = "@#{name}"
|
17
|
+
@table = ActiveList::Definition::Table.new(name, model, options)
|
18
|
+
if block_given?
|
19
|
+
yield @table
|
20
|
+
else
|
21
|
+
@table.load_default_columns
|
22
|
+
end
|
23
|
+
@parameters = {:sort => :to_s, :dir => :to_s}
|
24
|
+
@parameters.merge!(:page => :to_i, :per_page => :to_i) if @table.paginate?
|
25
|
+
end
|
26
|
+
|
27
|
+
def collection?
|
28
|
+
@collection
|
29
|
+
end
|
30
|
+
|
31
|
+
def var_name(name)
|
32
|
+
"_#{name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def renderer
|
36
|
+
ActiveList::Renderers[@table.options[:renderer]].new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def controller_method_code
|
40
|
+
code = "# encoding: utf-8\n"
|
41
|
+
code << "def #{self.controller_method_name}\n"
|
42
|
+
code << self.session_initialization_code.dig
|
43
|
+
code << " respond_to do |format|\n"
|
44
|
+
code << " format.html do\n"
|
45
|
+
code << " if request.xhr?\n"
|
46
|
+
code << self.renderer.remote_update_code.dig(4)
|
47
|
+
code << " else\n"
|
48
|
+
code << " render(inline: '<%=#{self.view_method_name}-%>')\n" # , layout: action_has_layout?
|
49
|
+
code << " end\n"
|
50
|
+
code << " end\n"
|
51
|
+
for format, exporter in ActiveList::Exporters.hash
|
52
|
+
code << " format.#{format} do\n"
|
53
|
+
code << exporter.new(self).send_data_code.dig(3)
|
54
|
+
code << " end\n"
|
55
|
+
end
|
56
|
+
code << " end\n"
|
57
|
+
# Save preferences of user
|
58
|
+
if defined? User and User.instance_methods.include? :pref
|
59
|
+
code << " p = current_user.pref('list.#{self.view_method_name}', YAML::dump({}))\n"
|
60
|
+
code << " p.set! YAML::dump(#{var_name(:params)}.stringify_keys)\n"
|
61
|
+
end
|
62
|
+
code << "end\n"
|
63
|
+
# code.split("\n").each_with_index{|l, x| puts((x+1).to_s.rjust(4)+": "+l)}
|
64
|
+
unless ::Rails.env.production?
|
65
|
+
file = ::Rails.root.join("tmp", "code", "active_list", "controllers", self.controller.controller_path, self.controller_method_name + ".rb")
|
66
|
+
FileUtils.mkdir_p(file.dirname)
|
67
|
+
File.write(file, code)
|
68
|
+
end
|
69
|
+
return code
|
70
|
+
end
|
71
|
+
|
72
|
+
def view_method_code
|
73
|
+
code = "# encoding: utf-8\n"
|
74
|
+
code << "def #{self.view_method_name}(options={}, &block)\n"
|
75
|
+
code << self.session_initialization_code.dig
|
76
|
+
code << self.renderer.build_table_code.dig
|
77
|
+
code << "end\n"
|
78
|
+
# code.split("\n").each_with_index{|l, x| puts((x+1).to_s.rjust(4)+": "+l)}
|
79
|
+
unless ::Rails.env.production?
|
80
|
+
file = ::Rails.root.join("tmp", "code", "active_list", "views", self.controller.controller_path, self.view_method_name + ".rb")
|
81
|
+
FileUtils.mkdir_p(file.dirname)
|
82
|
+
File.write(file, code)
|
83
|
+
end
|
84
|
+
return code
|
85
|
+
end
|
86
|
+
|
87
|
+
def session_initialization_code
|
88
|
+
code = "options = {} unless options.is_a? Hash\n"
|
89
|
+
code << "options.update(params)\n"
|
90
|
+
if defined? User and User.instance_methods.include? :pref
|
91
|
+
code << "#{var_name(:params)} = YAML::load(current_user.pref('list.#{self.view_method_name}', YAML::dump({})).value).symbolize_keys\n"
|
92
|
+
code << "#{var_name(:params)} = {} unless #{var_name(:params)}.is_a?(Hash)\n"
|
93
|
+
else
|
94
|
+
code << "#{var_name(:params)} = {}\n"
|
95
|
+
end
|
96
|
+
code << "#{var_name(:params)}.update(options.symbolize_keys)\n"
|
97
|
+
code << "unless #{var_name(:params)}[:hidden_columns].is_a? Array\n"
|
98
|
+
code << " #{var_name(:params)}[:hidden_columns] = #{@table.hidden_columns.map(&:name).map(&:to_sym).inspect}\n"
|
99
|
+
code << "end\n"
|
100
|
+
for parameter, convertor in @parameters.sort{|a,b| a[0].to_s <=> b[0].to_s}
|
101
|
+
# expr = "options.delete('#{@table.name}_#{parameter}') || options.delete('#{parameter}') || #{var_name(:params)}[:#{parameter}]"
|
102
|
+
# expr += " || #{@table.options[parameter]}" unless @table.options[parameter].blank?
|
103
|
+
# code << "#{var_name(:params)}[:#{parameter}] = (#{expr}).#{convertor}\n"
|
104
|
+
expr = "#{var_name(:params)}[:#{parameter}]"
|
105
|
+
expr = "(#{expr} || #{@table.options[parameter]})" unless @table.options[parameter].blank?
|
106
|
+
code << "#{var_name(:params)}[:#{parameter}] = #{expr}.#{convertor}\n"
|
107
|
+
end
|
108
|
+
# Order
|
109
|
+
code << "#{var_name(:order)} = #{@table.options[:order] ? @table.options[:order].inspect : 'nil'}\n"
|
110
|
+
code << "if #{var_name(:col)} = {" + @table.sortable_columns.collect{|c| "'#{c.sort_id}' => '#{c.sort_expression}'"}.join(', ') + "}[#{var_name(:params)}[:sort]]\n"
|
111
|
+
code << " #{var_name(:params)}[:dir] = 'asc' unless #{var_name(:params)}[:dir] == 'asc' or #{var_name(:params)}[:dir] == 'desc'\n"
|
112
|
+
code << " #{var_name(:order)} = #{var_name(:col)} + ' ' + #{var_name(:params)}[:dir]\n"
|
113
|
+
code << "end\n"
|
114
|
+
|
115
|
+
return code
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
require "active_list/generator/finder"
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module ActiveList
|
2
|
+
|
3
|
+
# Manage data query
|
4
|
+
class Generator
|
5
|
+
|
6
|
+
# Generate select code for the table taking all parameters in account
|
7
|
+
def select_data_code(options = {})
|
8
|
+
paginate = (options.has_key?(:paginate) ? options[:paginate] : @table.paginate?)
|
9
|
+
# Check order
|
10
|
+
unless @table.options.keys.include?(:order)
|
11
|
+
columns = @table.table_columns
|
12
|
+
@table.options[:order] = (columns.size > 0 ? columns.first.name.to_sym : {id: :desc}) # "#{@table.model.table_name}.id DESC"
|
13
|
+
end
|
14
|
+
|
15
|
+
class_name = @table.model.name
|
16
|
+
class_name = "(controller_name != '#{class_name.tableize}' ? controller_name.to_s.classify.constantize : #{class_name})" if self.collection?
|
17
|
+
|
18
|
+
# Find data
|
19
|
+
query_code = "#{class_name}"
|
20
|
+
query_code << self.scope_code if self.scope_code
|
21
|
+
query_code << ".select(#{self.select_code})" if self.select_code
|
22
|
+
query_code << ".where(#{self.conditions_code})" unless @table.options[:conditions].blank?
|
23
|
+
query_code << ".joins(#{@table.options[:joins].inspect})" unless @table.options[:joins].blank?
|
24
|
+
unless self.includes_reflections.empty?
|
25
|
+
expr = self.includes_reflections.inspect[1..-2]
|
26
|
+
query_code << ".includes(#{expr})"
|
27
|
+
query_code << ".references(#{expr})"
|
28
|
+
end
|
29
|
+
|
30
|
+
code = ""
|
31
|
+
code << "#{var_name(:count)} = #{query_code}.count\n"
|
32
|
+
if paginate
|
33
|
+
code << "#{var_name(:limit)} = (#{var_name(:params)}[:per_page] || 25).to_i\n"
|
34
|
+
code << "#{var_name(:page)} = (#{var_name(:params)}[:page] || 1).to_i\n"
|
35
|
+
code << "#{var_name(:page)} = 1 if #{var_name(:page)} < 1\n"
|
36
|
+
code << "#{var_name(:offset)} = (#{var_name(:page)} - 1) * #{var_name(:limit)}\n"
|
37
|
+
code << "#{var_name(:last)} = (#{var_name(:count)}.to_f / #{var_name(:limit)}).ceil.to_i\n"
|
38
|
+
code << "#{var_name(:last)} = 1 if #{var_name(:last)} < 1\n"
|
39
|
+
code << "return #{self.view_method_name}(options.merge(page: 1)) if 1 > #{var_name(:page)}\n"
|
40
|
+
code << "return #{self.view_method_name}(options.merge(page: #{var_name(:last)})) if #{var_name(:page)} > #{var_name(:last)}\n"
|
41
|
+
end
|
42
|
+
code << "#{self.records_variable_name} = #{query_code}"
|
43
|
+
code << ".reorder(#{var_name(:order)})"
|
44
|
+
if paginate
|
45
|
+
code << ".offset(#{var_name(:offset)})"
|
46
|
+
code << ".limit(#{var_name(:limit)})"
|
47
|
+
end
|
48
|
+
code << " || {}\n"
|
49
|
+
return code
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
# Compute includes Hash
|
55
|
+
def includes_reflections
|
56
|
+
hash = []
|
57
|
+
for column in @table.columns
|
58
|
+
if column.respond_to?(:reflection)
|
59
|
+
hash << column.reflection.name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
return hash
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def scope_code
|
67
|
+
return nil unless scopes = @table.options[:scope]
|
68
|
+
scopes = [scopes].flatten
|
69
|
+
code = ""
|
70
|
+
for scope in scopes
|
71
|
+
code << ".#{scope}"
|
72
|
+
end
|
73
|
+
return code
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# Generate the code from a conditions option
|
78
|
+
def conditions_code
|
79
|
+
conditions = @table.options[:conditions]
|
80
|
+
code = ''
|
81
|
+
case conditions
|
82
|
+
when Array
|
83
|
+
case conditions[0]
|
84
|
+
when String # SQL
|
85
|
+
code << '[' + conditions.first.inspect
|
86
|
+
code << conditions[1..-1].collect{|p| ", " + sanitize_condition(p)}.join if conditions.size > 1
|
87
|
+
code << ']'
|
88
|
+
when Symbol # Method
|
89
|
+
raise "What?"
|
90
|
+
code << conditions.first.to_s + '('
|
91
|
+
code << conditions[1..-1].collect{|p| sanitize_condition(p)}.join(', ') if conditions.size > 1
|
92
|
+
code << ')'
|
93
|
+
else
|
94
|
+
raise ArgumentError.new("First element of an Array can only be String or Symbol.")
|
95
|
+
end
|
96
|
+
when Hash # SQL
|
97
|
+
code << '{' + conditions.collect{|key, value| key.to_s + ': ' + sanitize_condition(value)}.join(',') + '}'
|
98
|
+
when Symbol # Method
|
99
|
+
code << conditions.to_s + "(options)"
|
100
|
+
when Code
|
101
|
+
code << "(" + conditions.gsub(/\s*\n\s*/, ';') + ")"
|
102
|
+
when String
|
103
|
+
code << conditions.inspect
|
104
|
+
else
|
105
|
+
raise ArgumentError.new("Unsupported type for conditions: #{conditions.inspect}")
|
106
|
+
end
|
107
|
+
return code
|
108
|
+
end
|
109
|
+
|
110
|
+
def select_code
|
111
|
+
return nil unless @table.options[:distinct] or @table.options[:select]
|
112
|
+
code = ""
|
113
|
+
code << "DISTINCT " if @table.options[:distinct]
|
114
|
+
code << "#{@table.model.table_name}.*"
|
115
|
+
if @table.options[:select]
|
116
|
+
code << @table.options[:select].collect{|k, v| ", #{k[0].to_s+'.'+k[1].to_s} AS #{v}" }.join
|
117
|
+
end
|
118
|
+
return ("'" + code + "'").c
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
def sanitize_condition(value)
|
123
|
+
# if value.is_a? Array
|
124
|
+
# # if value.size==1 and value[0].is_a? String
|
125
|
+
# # value[0].to_s
|
126
|
+
# # else
|
127
|
+
# value.inspect
|
128
|
+
# # end
|
129
|
+
# elsif value.is_a? Code
|
130
|
+
# value.inspect
|
131
|
+
# elsif value.is_a? String
|
132
|
+
# '"' + value.gsub('"', '\"') + '"'
|
133
|
+
# els
|
134
|
+
if [Date, DateTime].include? value.class
|
135
|
+
'"' + value.to_formatted_s(:db) + '"'
|
136
|
+
elsif value.is_a? NilClass
|
137
|
+
'nil'
|
138
|
+
else
|
139
|
+
value.inspect
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
|