jsanders-ruport 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +48 -0
- data/LICENSE +59 -0
- data/README +114 -0
- data/Rakefile +93 -0
- data/examples/RWEmerson.jpg +0 -0
- data/examples/anon.rb +43 -0
- data/examples/btree/commaleon/commaleon.rb +263 -0
- data/examples/btree/commaleon/sample_data/ticket_count.csv +124 -0
- data/examples/btree/commaleon/sample_data/ticket_count2.csv +119 -0
- data/examples/centered_pdf_text_box.rb +83 -0
- data/examples/data/tattle.dump +82 -0
- data/examples/example.csv +3 -0
- data/examples/line_plotter.rb +61 -0
- data/examples/pdf_report_with_common_base.rb +72 -0
- data/examples/png_embed.rb +54 -0
- data/examples/roadmap.png +0 -0
- data/examples/row_renderer.rb +39 -0
- data/examples/simple_pdf_lines.rb +25 -0
- data/examples/simple_templating_example.rb +34 -0
- data/examples/tattle_ruby_version.rb +39 -0
- data/examples/tattle_rubygems_version.rb +37 -0
- data/examples/trac_ticket_status.rb +59 -0
- data/lib/ruport.rb +127 -0
- data/lib/ruport/controller.rb +616 -0
- data/lib/ruport/controller/grouping.rb +71 -0
- data/lib/ruport/controller/table.rb +54 -0
- data/lib/ruport/data.rb +4 -0
- data/lib/ruport/data/feeder.rb +111 -0
- data/lib/ruport/data/grouping.rb +399 -0
- data/lib/ruport/data/record.rb +297 -0
- data/lib/ruport/data/table.rb +950 -0
- data/lib/ruport/extensions.rb +4 -0
- data/lib/ruport/formatter.rb +254 -0
- data/lib/ruport/formatter/csv.rb +149 -0
- data/lib/ruport/formatter/html.rb +161 -0
- data/lib/ruport/formatter/pdf.rb +591 -0
- data/lib/ruport/formatter/template.rb +187 -0
- data/lib/ruport/formatter/text.rb +231 -0
- data/lib/uport.rb +1 -0
- data/test/controller_test.rb +743 -0
- data/test/csv_formatter_test.rb +164 -0
- data/test/data_feeder_test.rb +88 -0
- data/test/grouping_test.rb +410 -0
- data/test/helpers.rb +11 -0
- data/test/html_formatter_test.rb +201 -0
- data/test/pdf_formatter_test.rb +354 -0
- data/test/record_test.rb +332 -0
- data/test/samples/addressbook.csv +6 -0
- data/test/samples/data.csv +3 -0
- data/test/samples/data.tsv +3 -0
- data/test/samples/dates.csv +1409 -0
- data/test/samples/erb_test.sql +1 -0
- data/test/samples/query_test.sql +1 -0
- data/test/samples/ruport_test.sql +8 -0
- data/test/samples/test.sql +2 -0
- data/test/samples/test.yaml +3 -0
- data/test/samples/ticket_count.csv +124 -0
- data/test/table_pivot_test.rb +134 -0
- data/test/table_test.rb +838 -0
- data/test/template_test.rb +48 -0
- data/test/text_formatter_test.rb +258 -0
- data/util/bench/data/record/bench_as_vs_to.rb +18 -0
- data/util/bench/data/record/bench_constructor.rb +46 -0
- data/util/bench/data/record/bench_indexing.rb +65 -0
- data/util/bench/data/record/bench_reorder.rb +35 -0
- data/util/bench/data/record/bench_to_a.rb +19 -0
- data/util/bench/data/table/bench_column_manip.rb +103 -0
- data/util/bench/data/table/bench_dup.rb +24 -0
- data/util/bench/data/table/bench_init.rb +67 -0
- data/util/bench/data/table/bench_manip.rb +125 -0
- data/util/bench/formatter/bench_csv.rb +14 -0
- data/util/bench/formatter/bench_html.rb +14 -0
- data/util/bench/formatter/bench_pdf.rb +14 -0
- data/util/bench/formatter/bench_text.rb +14 -0
- data/util/bench/samples/tattle.csv +1237 -0
- metadata +176 -0
@@ -0,0 +1,254 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# formatter.rb provides a generalized base class for creating ruport formatters.
|
4
|
+
#
|
5
|
+
# Created By Gregory Brown
|
6
|
+
# Copyright (C) December 2006, All Rights Reserved.
|
7
|
+
#
|
8
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
9
|
+
# See LICENSE and COPYING for details.
|
10
|
+
module Ruport
|
11
|
+
# Formatter is the base class for Ruport's format implementations.
|
12
|
+
#
|
13
|
+
# Typically, a Formatter will implement one or more output types,
|
14
|
+
# and be registered with one or more Controller classes.
|
15
|
+
#
|
16
|
+
# This class provides all the necessary base functionality to make
|
17
|
+
# use of Ruport's rendering system, including option handling, data
|
18
|
+
# access, and basic output wrapping.
|
19
|
+
#
|
20
|
+
# The following example should provide a general idea of how formatters
|
21
|
+
# work, but see the built in formatters for reference implementations.
|
22
|
+
#
|
23
|
+
# A simple Controller definition is included to help show the example in
|
24
|
+
# context, but you can also build your own custom interface to formatter
|
25
|
+
# if you wish.
|
26
|
+
#
|
27
|
+
# class ReverseController < Ruport::Controller
|
28
|
+
# stage :reversed_header, :reversed_body
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# class ReversedText < Ruport::Formatter
|
32
|
+
#
|
33
|
+
# # Hooks formatter up to controller
|
34
|
+
# renders :txt, :for => ReverseController
|
35
|
+
#
|
36
|
+
# # Implements ReverseController's :reversed_header hook
|
37
|
+
# # but can be used by any controller
|
38
|
+
# def build_reversed_header
|
39
|
+
# output << "#{options.header_text}\n"
|
40
|
+
# output << "The reversed text will follow\n"
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# # Implements ReverseController's :reversed_body hook
|
44
|
+
# # but can be used by any controller
|
45
|
+
# def build_reversed_body
|
46
|
+
# output << data.reverse << "\n"
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# puts ReverseController.render_txt(:data => "apple",
|
52
|
+
# :header_text => "Hello Mike, Hello Joe!")
|
53
|
+
#
|
54
|
+
# -----
|
55
|
+
# OUTPUT:
|
56
|
+
#
|
57
|
+
# Hello Mike, Hello Joe!
|
58
|
+
# The reversed text will follow
|
59
|
+
# elppa
|
60
|
+
#
|
61
|
+
class Formatter
|
62
|
+
|
63
|
+
# Provides shortcuts so that you can use Ruport's default rendering
|
64
|
+
# capabilities within your custom formatters
|
65
|
+
#
|
66
|
+
module RenderingTools
|
67
|
+
# Uses Controller::Row to render the Row object with the
|
68
|
+
# given options.
|
69
|
+
#
|
70
|
+
# Sets the <tt>:io</tt> attribute by default to the existing
|
71
|
+
# formatter's <tt>output</tt> object.
|
72
|
+
def render_row(row,options={},&block)
|
73
|
+
render_helper(Controller::Row,row,options,&block)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Uses Controller::Table to render the Table object with the
|
77
|
+
# given options.
|
78
|
+
#
|
79
|
+
# Sets the :io attribute by default to the existing formatter's
|
80
|
+
# output object.
|
81
|
+
def render_table(table,options={},&block)
|
82
|
+
render_helper(Controller::Table,table,options,&block)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Uses Controller::Group to render the Group object with the
|
86
|
+
# given options.
|
87
|
+
#
|
88
|
+
# Sets the :io attribute by default to the existing formatter's
|
89
|
+
# output object.
|
90
|
+
def render_group(group,options={},&block)
|
91
|
+
render_helper(Controller::Group,group,options,&block)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Uses Controller::Grouping to render the Grouping object with the
|
95
|
+
# given options.
|
96
|
+
#
|
97
|
+
# Sets the :io attribute by default to the existing formatter's
|
98
|
+
# output object.
|
99
|
+
def render_grouping(grouping,options={},&block)
|
100
|
+
render_helper(Controller::Grouping,grouping,options,&block)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Iterates through the data in the grouping and renders each group
|
104
|
+
# followed by a newline.
|
105
|
+
#
|
106
|
+
def render_inline_grouping(options={},&block)
|
107
|
+
data.each do |_,group|
|
108
|
+
render_group(group, options, &block)
|
109
|
+
output << "\n"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def render_helper(rend_klass, source_data,options={},&block)
|
116
|
+
options = {:data => source_data,
|
117
|
+
:io => output,
|
118
|
+
:layout => false }.merge(options)
|
119
|
+
|
120
|
+
options[:io] = "" if self.class.kind_of?(Ruport::Formatter::PDF)
|
121
|
+
rend_klass.render(format,options) do |rend|
|
122
|
+
block[rend] if block
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
include RenderingTools
|
129
|
+
|
130
|
+
# Set by the <tt>:data</tt> attribute from Controller#render
|
131
|
+
attr_reader :data
|
132
|
+
|
133
|
+
# Set automatically by Controller#render(format) or Controller#render_format
|
134
|
+
attr_accessor :format
|
135
|
+
|
136
|
+
# Set automatically by Controller#render as a Controller::Options object built
|
137
|
+
# by the hash provided.
|
138
|
+
attr_writer :options
|
139
|
+
|
140
|
+
# Registers the formatter with one or more Controllers.
|
141
|
+
#
|
142
|
+
# renders :pdf, :for => MyController
|
143
|
+
# render :text, :for => [MyController,YourController]
|
144
|
+
# renders [:csv,:html], :for => YourController
|
145
|
+
#
|
146
|
+
def self.renders(fmts,options={})
|
147
|
+
Array(fmts).each do |format|
|
148
|
+
Array(options[:for]).each do |o|
|
149
|
+
o.send(:add_format,self,format)
|
150
|
+
formats << format unless formats.include?(format)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Allows you to implement stages in your formatter using the
|
156
|
+
# following syntax:
|
157
|
+
#
|
158
|
+
# class ReversedText < Ruport::Formatter
|
159
|
+
# renders :txt, :for => ReverseController
|
160
|
+
#
|
161
|
+
# build :reversed_header do
|
162
|
+
# output << "#{options.header_text}\n"
|
163
|
+
# output << "The reversed text will follow\n"
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# build :reversed_body do
|
167
|
+
# output << data.reverse << "\n"
|
168
|
+
# end
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
def self.build(stage,&block)
|
172
|
+
define_method "build_#{stage}", &block
|
173
|
+
end
|
174
|
+
|
175
|
+
# Gives a list of formats registered for this formatter.
|
176
|
+
def self.formats
|
177
|
+
@formats ||= []
|
178
|
+
end
|
179
|
+
|
180
|
+
# Returns the template currently set for this formatter.
|
181
|
+
def template
|
182
|
+
Template[options.template] rescue nil || Template[:default]
|
183
|
+
end
|
184
|
+
|
185
|
+
# Stores a string used for outputting formatted data.
|
186
|
+
def output
|
187
|
+
return options.io if options.io
|
188
|
+
@output ||= ""
|
189
|
+
end
|
190
|
+
|
191
|
+
# Provides a Controller::Options object for storing formatting options.
|
192
|
+
def options
|
193
|
+
@options ||= Controller::Options.new
|
194
|
+
end
|
195
|
+
|
196
|
+
# Sets the data object, making a local copy using #dup. This may have
|
197
|
+
# a significant overhead for large tables, so formatters which don't
|
198
|
+
# modify the data object may wish to override this.
|
199
|
+
def data=(val)
|
200
|
+
@data = val.dup
|
201
|
+
end
|
202
|
+
|
203
|
+
# Clears the output.
|
204
|
+
def clear_output
|
205
|
+
@output.replace("")
|
206
|
+
end
|
207
|
+
|
208
|
+
# Saves the output to a file.
|
209
|
+
def save_output(filename)
|
210
|
+
File.open(filename,"w") {|f| f << output }
|
211
|
+
end
|
212
|
+
|
213
|
+
# Use to define that your formatter should save in binary format
|
214
|
+
def self.save_as_binary_file
|
215
|
+
define_method :save_output do |filename|
|
216
|
+
File.open(filename,"wb") {|f| f << output }
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Evaluates the string using ERB and returns the results.
|
221
|
+
#
|
222
|
+
# If <tt>:binding</tt> is specified, it will evaluate the template
|
223
|
+
# in that context.
|
224
|
+
def erb(string,options={})
|
225
|
+
require "erb"
|
226
|
+
if string =~ /(\.r\w+)|(\.erb)$/
|
227
|
+
ERB.new(File.read(string)).result(options[:binding]||binding)
|
228
|
+
else
|
229
|
+
ERB.new(string).result(options[:binding]||binding)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Provides a shortcut for per-format handlers.
|
234
|
+
#
|
235
|
+
# Example:
|
236
|
+
#
|
237
|
+
# # will only be called if formatter is called for html output
|
238
|
+
# html { output << "Look, I'm handling html" }
|
239
|
+
#
|
240
|
+
def method_missing(id,*args)
|
241
|
+
if self.class.formats.include?(id)
|
242
|
+
yield() if format == id
|
243
|
+
else
|
244
|
+
super
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
require "ruport/formatter/template"
|
251
|
+
require "ruport/formatter/csv"
|
252
|
+
require "ruport/formatter/html"
|
253
|
+
require "ruport/formatter/text"
|
254
|
+
require "ruport/formatter/pdf"
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# formatter/csv.rb provides csv formatting for Ruport.
|
4
|
+
#
|
5
|
+
# Original code dates back to the earliest versions of Ruport in August 2005
|
6
|
+
# Extended over time, with much of the existing code being added around
|
7
|
+
# December 2006.
|
8
|
+
#
|
9
|
+
# Copyright (C) 2005-2007 Gregory Brown, All Rights Reserved.
|
10
|
+
#
|
11
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
12
|
+
# See LICENSE and COPYING for details.
|
13
|
+
#
|
14
|
+
module Ruport
|
15
|
+
|
16
|
+
# This formatter implements the CSV format for Ruport's Row, Table, Group
|
17
|
+
# and Grouping controllers. It is a light wrapper around
|
18
|
+
# James Edward Gray II's FasterCSV.
|
19
|
+
#
|
20
|
+
# === Rendering Options
|
21
|
+
#
|
22
|
+
# <tt>:style</tt> Used for grouping (:inline,:justified,:raw)
|
23
|
+
#
|
24
|
+
# <tt>:format_options</tt> A hash of FasterCSV options
|
25
|
+
#
|
26
|
+
# <tt>:formatter</tt> An existing FasterCSV object to write to
|
27
|
+
#
|
28
|
+
# <tt>:show_table_headers</tt> True by default
|
29
|
+
#
|
30
|
+
# <tt>:show_group_headers</tt> True by default
|
31
|
+
#
|
32
|
+
class Formatter::CSV < Formatter
|
33
|
+
|
34
|
+
renders :csv, :for => [ Controller::Row, Controller::Table,
|
35
|
+
Controller::Group, Controller::Grouping ]
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
require "fastercsv" unless RUBY_VERSION > "1.9"
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_writer :csv_writer
|
42
|
+
|
43
|
+
# Hook for setting available options using a template. See the template
|
44
|
+
# documentation for the available options and their format.
|
45
|
+
def apply_template
|
46
|
+
apply_table_format_template(template.table)
|
47
|
+
apply_grouping_format_template(template.grouping)
|
48
|
+
|
49
|
+
options.format_options ||= template.format_options
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the current FCSV object or creates a new one if it has not
|
53
|
+
# been set yet. Note that FCSV(sig) has a cache and returns the *same*
|
54
|
+
# FCSV object if writing to the same underlying output with the same
|
55
|
+
# options.
|
56
|
+
#
|
57
|
+
def csv_writer
|
58
|
+
@csv_writer ||= options.formatter ||
|
59
|
+
FCSV(output, options.format_options || {})
|
60
|
+
end
|
61
|
+
|
62
|
+
# Generates table header by turning column_names into a CSV row.
|
63
|
+
# Uses the row controller to generate the actual formatted output
|
64
|
+
#
|
65
|
+
# This method does not do anything if options.show_table_headers is false
|
66
|
+
# or the Data::Table has no column names.
|
67
|
+
def build_table_header
|
68
|
+
unless data.column_names.empty? || !options.show_table_headers
|
69
|
+
render_row data.column_names, :format_options => options.format_options,
|
70
|
+
:formatter => csv_writer
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Calls the row controller for each row in the Data::Table
|
75
|
+
def build_table_body
|
76
|
+
fcsv = csv_writer
|
77
|
+
data.each { |row| fcsv << row }
|
78
|
+
end
|
79
|
+
|
80
|
+
# Produces CSV output for a data row.
|
81
|
+
def build_row(data = self.data)
|
82
|
+
csv_writer << data
|
83
|
+
end
|
84
|
+
|
85
|
+
# Renders the header for a group using the group name.
|
86
|
+
#
|
87
|
+
def build_group_header
|
88
|
+
csv_writer << [data.name.to_s] << []
|
89
|
+
end
|
90
|
+
|
91
|
+
# Renders the group body - uses the table controller to generate the output.
|
92
|
+
#
|
93
|
+
def build_group_body
|
94
|
+
render_table data, options.to_hash
|
95
|
+
end
|
96
|
+
|
97
|
+
# Generates a header for the grouping using the grouped_by column and the
|
98
|
+
# column names.
|
99
|
+
#
|
100
|
+
def build_grouping_header
|
101
|
+
unless options.style == :inline
|
102
|
+
csv_writer << [data.grouped_by] + grouping_columns
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Determines the proper style to use and renders the Grouping.
|
107
|
+
def build_grouping_body
|
108
|
+
case options.style
|
109
|
+
when :inline
|
110
|
+
render_inline_grouping(options)
|
111
|
+
when :justified, :raw
|
112
|
+
render_justified_or_raw_grouping
|
113
|
+
else
|
114
|
+
raise NotImplementedError, "Unknown style"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def grouping_columns
|
121
|
+
data.data.to_a[0][1].column_names
|
122
|
+
end
|
123
|
+
|
124
|
+
def render_justified_or_raw_grouping
|
125
|
+
data.each do |_,group|
|
126
|
+
prefix = [group.name.to_s]
|
127
|
+
group.each do |row|
|
128
|
+
csv_writer << prefix + row.to_a
|
129
|
+
prefix = [nil] if options.style == :justified
|
130
|
+
end
|
131
|
+
csv_writer << []
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def apply_table_format_template(t)
|
136
|
+
t = (t || {}).merge(options.table_format || {})
|
137
|
+
options.show_table_headers = t[:show_headings] if
|
138
|
+
options.show_table_headers.nil?
|
139
|
+
end
|
140
|
+
|
141
|
+
def apply_grouping_format_template(t)
|
142
|
+
t = (t || {}).merge(options.grouping_format || {})
|
143
|
+
options.style ||= t[:style]
|
144
|
+
options.show_group_headers = t[:show_headings] if
|
145
|
+
options.show_group_headers.nil?
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# formatter/html.rb provides html formatting for Ruport.
|
4
|
+
#
|
5
|
+
# Created by Gregory Brown, late 2005. Updated numerous times as needed to
|
6
|
+
# fit new formatting systems.
|
7
|
+
#
|
8
|
+
# Copyright (C) 2005-2007 Gregory Brown, All Rights Reserved.
|
9
|
+
#
|
10
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
11
|
+
# See LICENSE and COPYING for details.
|
12
|
+
#
|
13
|
+
module Ruport
|
14
|
+
# This class produces HTML output for Ruport's Row, Table, Group, and
|
15
|
+
# Grouping controllers. It can be subclassed, as it has some helper methods
|
16
|
+
# that might be useful for custom output.
|
17
|
+
#
|
18
|
+
# === Rendering Options
|
19
|
+
#
|
20
|
+
# <tt>:show_table_headers</tt> True by default
|
21
|
+
#
|
22
|
+
# <tt>:show_group_headers</tt> True by default
|
23
|
+
#
|
24
|
+
# <tt>:style</tt> Used for grouping (:inline, :justified)
|
25
|
+
#
|
26
|
+
class Formatter::HTML < Formatter
|
27
|
+
|
28
|
+
renders :html, :for => [ Controller::Row, Controller::Table,
|
29
|
+
Controller::Group, Controller::Grouping ]
|
30
|
+
|
31
|
+
# Hook for setting available options using a template. See the template
|
32
|
+
# documentation for the available options and their format.
|
33
|
+
def apply_template
|
34
|
+
apply_table_format_template(template.table)
|
35
|
+
apply_grouping_format_template(template.grouping)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Generates table headers based on the column names of your Data::Table.
|
39
|
+
#
|
40
|
+
# This method does not do anything if options.show_table_headers is false
|
41
|
+
# or the Data::Table has no column names.
|
42
|
+
def build_table_header
|
43
|
+
output << "\t<table>\n"
|
44
|
+
unless data.column_names.empty? || !options.show_table_headers
|
45
|
+
output << "\t\t<tr>\n\t\t\t<th>" +
|
46
|
+
data.column_names.join("</th>\n\t\t\t<th>") +
|
47
|
+
"</th>\n\t\t</tr>\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Uses the Row controller to build up the table body.
|
52
|
+
# Replaces nil and empty strings with " "
|
53
|
+
def build_table_body
|
54
|
+
data.each do |row|
|
55
|
+
build_row(row.map { |e| e.to_s.empty? ? " " : e })
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Simply closes the table tag.
|
60
|
+
def build_table_footer
|
61
|
+
output << "\t</table>\n"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Renders individual rows for the table.
|
65
|
+
def build_row(data = self.data)
|
66
|
+
output <<
|
67
|
+
"\t\t<tr>\n\t\t\t<td>" +
|
68
|
+
data.to_a.join("</td>\n\t\t\t<td>") +
|
69
|
+
"</td>\n\t\t</tr>\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
# Renders the header for a group using the group name.
|
73
|
+
#
|
74
|
+
def build_group_header
|
75
|
+
output << "\t<p>#{data.name}</p>\n"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates the group body. Since group data is a table, just uses the
|
79
|
+
# Table controller.
|
80
|
+
#
|
81
|
+
def build_group_body
|
82
|
+
render_table data, options.to_hash
|
83
|
+
end
|
84
|
+
|
85
|
+
# Generates the body for a grouping. Iterates through the groups and
|
86
|
+
# renders them using the group controller.
|
87
|
+
#
|
88
|
+
def build_grouping_body
|
89
|
+
case options.style
|
90
|
+
when :inline
|
91
|
+
render_inline_grouping(options)
|
92
|
+
when :justified
|
93
|
+
render_justified_grouping
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Generates <table> tags enclosing the yielded content.
|
98
|
+
#
|
99
|
+
# Example:
|
100
|
+
#
|
101
|
+
# output << html_table { "<tr><td>1</td><td>2</td></tr>\n" }
|
102
|
+
# #=> "<table>\n<tr><td>1</td><td>2</td></tr>\n</table>\n"
|
103
|
+
#
|
104
|
+
def html_table
|
105
|
+
"<table>\n" << yield << "</table>\n"
|
106
|
+
end
|
107
|
+
|
108
|
+
# Uses RedCloth to turn a string containing textile markup into HTML.
|
109
|
+
#
|
110
|
+
# Example:
|
111
|
+
#
|
112
|
+
# textile "*bar*" #=> "<p><strong>foo</strong></p>"
|
113
|
+
#
|
114
|
+
def textile(s)
|
115
|
+
require "redcloth"
|
116
|
+
RedCloth.new(s).to_html
|
117
|
+
rescue LoadError
|
118
|
+
raise RuntimeError, "You need RedCloth!\n gem install RedCloth -v 3.0.3"
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def render_justified_grouping
|
124
|
+
output << "\t<table>\n\t\t<tr>\n\t\t\t<th>" +
|
125
|
+
"#{data.grouped_by}</th>\n\t\t\t<th>" +
|
126
|
+
grouping_columns.join("</th>\n\t\t\t<th>") +
|
127
|
+
"</th>\n\t\t</tr>\n"
|
128
|
+
data.each do |name, group|
|
129
|
+
group.each_with_index do |row, i|
|
130
|
+
output << "\t\t<tr>\n\t\t\t"
|
131
|
+
if i == 0
|
132
|
+
output << "<td class=\"groupName\">#{name}</td>\n\t\t\t<td>"
|
133
|
+
else
|
134
|
+
output << "<td> </td>\n\t\t\t<td>"
|
135
|
+
end
|
136
|
+
output << row.to_a.join("</td>\n\t\t\t<td>") +
|
137
|
+
"</td>\n\t\t</tr>\n"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
output << "\t</table>\n"
|
141
|
+
end
|
142
|
+
|
143
|
+
def grouping_columns
|
144
|
+
data.data.to_a[0][1].column_names
|
145
|
+
end
|
146
|
+
|
147
|
+
def apply_table_format_template(t)
|
148
|
+
t = (t || {}).merge(options.table_format || {})
|
149
|
+
options.show_table_headers = t[:show_headings] if
|
150
|
+
options.show_table_headers.nil?
|
151
|
+
end
|
152
|
+
|
153
|
+
def apply_grouping_format_template(t)
|
154
|
+
t = (t || {}).merge(options.grouping_format || {})
|
155
|
+
options.style ||= t[:style]
|
156
|
+
options.show_group_headers = t[:show_headings] if
|
157
|
+
options.show_group_headers.nil?
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|