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,187 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# template.rb provides templating support for Ruby Reports.
|
4
|
+
#
|
5
|
+
# Copyright August 2007, Gregory Brown / Michael Milner. All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
+
|
9
|
+
|
10
|
+
class Ruport::Formatter::TemplateNotDefined < StandardError; end
|
11
|
+
|
12
|
+
# This class provides templating functionality for Ruport.
|
13
|
+
# New templates are created using the Template.create method.
|
14
|
+
#
|
15
|
+
# Example:
|
16
|
+
#
|
17
|
+
# Ruport::Formatter::Template.create(:simple) do |t|
|
18
|
+
# t.page_layout = :landscape
|
19
|
+
# t.grouping_style = :offset
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# You can then determine how the template should be used by defining
|
23
|
+
# an <tt>apply_template</tt> method in your formatter.
|
24
|
+
#
|
25
|
+
# Example:
|
26
|
+
#
|
27
|
+
# class Ruport::Formatter::PDF
|
28
|
+
# def apply_template
|
29
|
+
# options.paper_orientation = template.page_layout
|
30
|
+
# options.style = template.grouping_style
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# When you're ready to render the output, you can set the :template as an
|
35
|
+
# option for the formatter. Using the template remains optional and you can
|
36
|
+
# still render the report without it.
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
#
|
40
|
+
# puts g.to_pdf(:template => :simple) #=> uses the template
|
41
|
+
# puts g.to_pdf #=> doesn't use the template
|
42
|
+
#
|
43
|
+
# The built-in formatters all have <tt>apply_template</tt> methods defined that
|
44
|
+
# accept a standard set of options. Each option can be set by supplying a hash
|
45
|
+
# with the keys/values listed in the tables below.
|
46
|
+
#
|
47
|
+
# Example:
|
48
|
+
#
|
49
|
+
# Ruport::Formatter::Template.create(:simple) do |format|
|
50
|
+
# format.page = {
|
51
|
+
# :size => "LETTER",
|
52
|
+
# :layout => :landscape
|
53
|
+
# }
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# If you define a template with the name :default, then it will be used by
|
57
|
+
# all formatters unless they either specify a template or explicitly turn off
|
58
|
+
# the templating functionality by using :template => false.
|
59
|
+
#
|
60
|
+
# Example:
|
61
|
+
#
|
62
|
+
# Ruport::Formatter::Template.create(:simple)
|
63
|
+
# Ruport::Formatter::Template.create(:default)
|
64
|
+
#
|
65
|
+
# puts g.to_pdf #=> uses the :default template
|
66
|
+
# puts g.to_pdf(:template => :simple) #=> uses the :simple template
|
67
|
+
# puts g.to_pdf(:template => false) #=> doesn't use a template
|
68
|
+
#
|
69
|
+
# ==== PDF Formatter Options
|
70
|
+
#
|
71
|
+
# Option Key Value
|
72
|
+
#
|
73
|
+
# page :size Any size supported by the :paper
|
74
|
+
# option to PDF::Writer.new
|
75
|
+
#
|
76
|
+
# :layout :portrait, :landscape
|
77
|
+
#
|
78
|
+
# text Any available to Corresponding values
|
79
|
+
# PDF::Writer#text
|
80
|
+
#
|
81
|
+
# table All attributes of Corresponding values
|
82
|
+
# PDF::SimpleTable
|
83
|
+
#
|
84
|
+
# :column_options - All attributes of
|
85
|
+
# PDF::SimpleTable::Column
|
86
|
+
# except :heading
|
87
|
+
# - Hash keyed by a column name, whose
|
88
|
+
# value is a hash containing any of
|
89
|
+
# the other:column_options (sets values
|
90
|
+
# for specific columns)
|
91
|
+
# - :heading => { All attributes of
|
92
|
+
# PDF::SimpleTable::Column::Heading }
|
93
|
+
#
|
94
|
+
# column :alignment :left, :right, :center, :full
|
95
|
+
#
|
96
|
+
# :width column width
|
97
|
+
#
|
98
|
+
# heading :alignment :left, :right, :center, :full
|
99
|
+
#
|
100
|
+
# :bold true or false
|
101
|
+
#
|
102
|
+
# :title heading title (if not set,
|
103
|
+
# defaults to column name)
|
104
|
+
#
|
105
|
+
# grouping :style :inline, :justified, :separated, :offset
|
106
|
+
#
|
107
|
+
#
|
108
|
+
# ==== Text Formatter Options
|
109
|
+
#
|
110
|
+
# Option Key Value
|
111
|
+
#
|
112
|
+
# table :show_headings true or false
|
113
|
+
# :width Table width
|
114
|
+
# :ignore_width true or false
|
115
|
+
#
|
116
|
+
# column :alignment :center
|
117
|
+
# :maximum_width Max column width
|
118
|
+
#
|
119
|
+
# grouping :show_headings true or false
|
120
|
+
#
|
121
|
+
#
|
122
|
+
# ==== HTML Formatter Options
|
123
|
+
#
|
124
|
+
# Option Key Value
|
125
|
+
#
|
126
|
+
# table :show_headings true or false
|
127
|
+
#
|
128
|
+
# grouping :style :inline, :justified
|
129
|
+
# :show_headings true or false
|
130
|
+
#
|
131
|
+
#
|
132
|
+
# ==== CSV Formatter Options
|
133
|
+
#
|
134
|
+
# Option Key Value
|
135
|
+
#
|
136
|
+
# table :show_headings true or false
|
137
|
+
#
|
138
|
+
# grouping :style :inline, :justified, :raw
|
139
|
+
# :show_headings true or false
|
140
|
+
#
|
141
|
+
# format_options All options Corresponding values
|
142
|
+
# available to
|
143
|
+
# FasterCSV.new
|
144
|
+
#
|
145
|
+
class Ruport::Formatter::Template < Ruport::Controller::Options
|
146
|
+
|
147
|
+
# Returns all existing templates in a hash keyed by the template names.
|
148
|
+
def self.templates
|
149
|
+
@templates ||= Hash.new
|
150
|
+
end
|
151
|
+
|
152
|
+
# Creates a new template with a name given by <tt>label</tt>.
|
153
|
+
#
|
154
|
+
# Example:
|
155
|
+
#
|
156
|
+
# Ruport::Formatter::Template.create(:simple) do |t|
|
157
|
+
# t.page_layout = :landscape
|
158
|
+
# t.grouping_style = :offset
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# You can inherit all the options set in a template by using the :base option
|
162
|
+
# and providing an existing template name to use as the base.
|
163
|
+
#
|
164
|
+
# Example:
|
165
|
+
#
|
166
|
+
# Ruport::Formatter::Template.create(:derived, :base => :simple)
|
167
|
+
#
|
168
|
+
def self.create(label,opts={})
|
169
|
+
if opts[:base]
|
170
|
+
obj = Marshal.load(Marshal.dump(self[opts[:base]]))
|
171
|
+
else
|
172
|
+
obj = new
|
173
|
+
end
|
174
|
+
yield(obj) if block_given?
|
175
|
+
templates[label] = obj
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns an existing template with the provided name (label).
|
179
|
+
def self.[](label)
|
180
|
+
templates[label] or raise Ruport::Formatter::TemplateNotDefined
|
181
|
+
end
|
182
|
+
|
183
|
+
# Returns the default template.
|
184
|
+
def self.default
|
185
|
+
templates[:default]
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# formatter/text.rb provides text formatting for Ruport.
|
4
|
+
#
|
5
|
+
# Created by Gregory Brown, some time around Spring 2006.
|
6
|
+
# Copyright (C) 2006-2007, All Rights Reserved.
|
7
|
+
#
|
8
|
+
# Mathijs Mohlmann and Marshall T. Vandegrift have provided some patches for
|
9
|
+
# this class, see AUTHORS file for details.
|
10
|
+
#
|
11
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
12
|
+
# See LICENSE and COPYING for details.
|
13
|
+
module Ruport
|
14
|
+
|
15
|
+
# This class provides text output for Ruport's Row, Table, Group, and
|
16
|
+
# Grouping controllers
|
17
|
+
#
|
18
|
+
# It handles things like automatically truncating tables that go off the
|
19
|
+
# edge of the screen in the console, proper column alignment, and pretty
|
20
|
+
# output that looks something like this:
|
21
|
+
#
|
22
|
+
# +------------------------------+
|
23
|
+
# | apple | banana | strawberry |
|
24
|
+
# +------------------------------+
|
25
|
+
# | yes | no | yes |
|
26
|
+
# | yes | yes | red snapper |
|
27
|
+
# | what | the | red snapper |
|
28
|
+
# +------------------------------+
|
29
|
+
#
|
30
|
+
# === Supported Options
|
31
|
+
#
|
32
|
+
# <tt>:max_col_width:</tt> Ordinal array of column widths. Set automatically
|
33
|
+
# but can be overridden.
|
34
|
+
#
|
35
|
+
# <tt>:alignment:</tt> Defaults to left justify text and right justify
|
36
|
+
# numbers. Centers all fields when set to :center.
|
37
|
+
#
|
38
|
+
# <tt>:table_width:</tt> Will truncate rows at this limit.
|
39
|
+
#
|
40
|
+
# <tt>:show_table_headers:</tt> Defaults to true
|
41
|
+
#
|
42
|
+
# <tt>:show_group_headers:</tt> Defaults to true
|
43
|
+
#
|
44
|
+
# <tt>:ignore_table_width:</tt> When set to true, outputs full table without
|
45
|
+
# truncating it. Useful for file output.
|
46
|
+
class Formatter::Text < Formatter
|
47
|
+
|
48
|
+
renders [:txt, :text], :for => [ Controller::Row, Controller::Table,
|
49
|
+
Controller::Group, Controller::Grouping ]
|
50
|
+
|
51
|
+
# Hook for setting available options using a template. See the template
|
52
|
+
# documentation for the available options and their format.
|
53
|
+
def apply_template
|
54
|
+
apply_table_format_template(template.table)
|
55
|
+
apply_column_format_template(template.column)
|
56
|
+
apply_grouping_format_template(template.grouping)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Checks to ensure the table is not empty and then calls
|
60
|
+
# calculate_max_col_widths.
|
61
|
+
#
|
62
|
+
def prepare_table
|
63
|
+
raise Ruport::FormatterError, "Can't output table without " +
|
64
|
+
"data or column names." if data.empty? && data.column_names.empty?
|
65
|
+
calculate_max_col_widths
|
66
|
+
end
|
67
|
+
|
68
|
+
# Uses the column names from the given Data::Table to generate a table
|
69
|
+
# header.
|
70
|
+
#
|
71
|
+
# Calls fit_to_width to truncate the table heading if necessary.
|
72
|
+
#
|
73
|
+
def build_table_header
|
74
|
+
return unless should_render_column_names?
|
75
|
+
|
76
|
+
c = data.column_names.enum_for(:each_with_index).map { |f,i|
|
77
|
+
f.to_s.center(options.max_col_width[i])
|
78
|
+
}
|
79
|
+
|
80
|
+
output << fit_to_width("#{hr}| #{c.join(' | ')} |\n")
|
81
|
+
end
|
82
|
+
|
83
|
+
# Generates the body of the text table.
|
84
|
+
#
|
85
|
+
# Defaults to numeric values being right justified, and other values being
|
86
|
+
# left justified. Can be changed to support centering of output by
|
87
|
+
# setting options.alignment to :center
|
88
|
+
#
|
89
|
+
# Uses fit_to_width to truncate the table if necessary.
|
90
|
+
#
|
91
|
+
def build_table_body
|
92
|
+
output << fit_to_width(hr)
|
93
|
+
return if data.empty?
|
94
|
+
|
95
|
+
calculate_max_col_widths unless options.max_col_width
|
96
|
+
|
97
|
+
data.each { |row| build_row(row) }
|
98
|
+
|
99
|
+
output << fit_to_width(hr)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Generates a formatted text row.
|
103
|
+
#
|
104
|
+
# Defaults to numeric values being right justified, and other values being
|
105
|
+
# left justified. Can be changed to support centering of output by
|
106
|
+
# setting options.alignment to :center
|
107
|
+
#
|
108
|
+
# Uses fit_to_width to truncate the row if necessary.
|
109
|
+
#
|
110
|
+
def build_row(data = self.data)
|
111
|
+
max_col_widths_for_row(data) unless options.max_col_width
|
112
|
+
|
113
|
+
data.enum_for(:each_with_index).inject(line=[]) { |s,e|
|
114
|
+
field,index = e
|
115
|
+
if options.alignment.eql? :center
|
116
|
+
line << field.to_s.center(options.max_col_width[index])
|
117
|
+
else
|
118
|
+
align = field.is_a?(Numeric) ? :rjust : :ljust
|
119
|
+
line << field.to_s.send(align, options.max_col_width[index])
|
120
|
+
end
|
121
|
+
}
|
122
|
+
output << fit_to_width("| #{line.join(' | ')} |\n")
|
123
|
+
end
|
124
|
+
|
125
|
+
# Renders the header for a group using the group name.
|
126
|
+
#
|
127
|
+
def build_group_header
|
128
|
+
output << "#{data.name}:\n\n"
|
129
|
+
end
|
130
|
+
|
131
|
+
# Creates the group body. Since group data is a table, just uses the
|
132
|
+
# Table controller.
|
133
|
+
#
|
134
|
+
def build_group_body
|
135
|
+
render_table data, options
|
136
|
+
end
|
137
|
+
|
138
|
+
# Generates the body for a grouping. Iterates through the groups and
|
139
|
+
# renders them using the group controller.
|
140
|
+
#
|
141
|
+
def build_grouping_body
|
142
|
+
render_inline_grouping(options)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns false if column_names are empty or options.show_table_headers
|
146
|
+
# is false/nil. Returns true otherwise.
|
147
|
+
#
|
148
|
+
def should_render_column_names?
|
149
|
+
not data.column_names.empty? || !options.show_table_headers
|
150
|
+
end
|
151
|
+
|
152
|
+
# Generates the horizontal rule by calculating the total table width and
|
153
|
+
# then generating a bar that looks like this:
|
154
|
+
#
|
155
|
+
# "+------------------+"
|
156
|
+
def hr
|
157
|
+
ref = data.column_names.empty? ? data[0].to_a : data.column_names
|
158
|
+
len = options.max_col_width.inject(ref.length * 3) {|s,e|s+e}
|
159
|
+
"+" + "-"*(len-1) + "+\n"
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns options.table_width if specified.
|
163
|
+
#
|
164
|
+
# Otherwise, uses SystemExtensions to determine terminal width.
|
165
|
+
def width
|
166
|
+
options.table_width ||= SystemExtensions.terminal_width
|
167
|
+
end
|
168
|
+
|
169
|
+
# Truncates a string so that it does not exceed Text#width
|
170
|
+
def fit_to_width(s)
|
171
|
+
return s if options.ignore_table_width
|
172
|
+
# workaround for Rails setting terminal_width to 1
|
173
|
+
max_width = width < 2 ? 80 : width
|
174
|
+
|
175
|
+
s.split("\n").each { |r|
|
176
|
+
r.gsub!(/\A.{#{max_width+1},}/) { |m| m[0,max_width-2] + ">>" }
|
177
|
+
}.join("\n") + "\n"
|
178
|
+
end
|
179
|
+
|
180
|
+
# Determines the text widths for each column.
|
181
|
+
def calculate_max_col_widths
|
182
|
+
# allow override
|
183
|
+
return if options.max_col_width
|
184
|
+
|
185
|
+
options.max_col_width = []
|
186
|
+
|
187
|
+
unless data.column_names.empty?
|
188
|
+
data.column_names.each_index do |i|
|
189
|
+
options.max_col_width[i] = data.column_names[i].to_s.length
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
data.each { |r| max_col_widths_for_row(r) }
|
194
|
+
end
|
195
|
+
|
196
|
+
# Used to calculate the <tt>max_col_widths</tt> array.
|
197
|
+
# Override this to tweak the automatic column size adjustments.
|
198
|
+
def max_col_widths_for_row(row)
|
199
|
+
options.max_col_width ||= []
|
200
|
+
row.each_with_index do |f,i|
|
201
|
+
if !options.max_col_width[i] || f.to_s.length > options.max_col_width[i]
|
202
|
+
options.max_col_width[i] = f.to_s.length
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def apply_table_format_template(t)
|
210
|
+
t = (t || {}).merge(options.table_format || {})
|
211
|
+
options.show_table_headers = t[:show_headings] if
|
212
|
+
options.show_table_headers.nil?
|
213
|
+
options.table_width ||= t[:width]
|
214
|
+
options.ignore_table_width = t[:ignore_width] if
|
215
|
+
options.ignore_table_width.nil?
|
216
|
+
end
|
217
|
+
|
218
|
+
def apply_column_format_template(t)
|
219
|
+
t = (t || {}).merge(options.column_format || {})
|
220
|
+
options.max_col_width ||= t[:maximum_width]
|
221
|
+
options.alignment ||= t[:alignment]
|
222
|
+
end
|
223
|
+
|
224
|
+
def apply_grouping_format_template(t)
|
225
|
+
t = (t || {}).merge(options.grouping_format || {})
|
226
|
+
options.show_group_headers = t[:show_headings] if
|
227
|
+
options.show_group_headers.nil?
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|
data/lib/uport.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "ruport"
|
@@ -0,0 +1,743 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "helpers")
|
3
|
+
|
4
|
+
###########################################################################
|
5
|
+
#
|
6
|
+
# NOTE:
|
7
|
+
#
|
8
|
+
# As it stands, we haven't found a more clever way to test the formatting
|
9
|
+
# system than to just create a bunch of renderers and basic formatters for
|
10
|
+
# different concepts we're trying to test. Patches and ideas welcome:
|
11
|
+
#
|
12
|
+
# list.rubyreports.org
|
13
|
+
############################################################################
|
14
|
+
|
15
|
+
#============================================================================
|
16
|
+
# These two renderers represent the two styles that can be used when defining
|
17
|
+
# renderers in Ruport. The OldSchoolController approach has largely been
|
18
|
+
# deprecated, but still has uses in edge cases that we need to support.
|
19
|
+
#============================================================================
|
20
|
+
|
21
|
+
class OldSchoolController < Ruport::Controller
|
22
|
+
|
23
|
+
def run
|
24
|
+
formatter do
|
25
|
+
build_header
|
26
|
+
build_body
|
27
|
+
build_footer
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class VanillaController < Ruport::Controller
|
34
|
+
stage :header,:body,:footer
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# This formatter implements some junk output so we can be sure
|
39
|
+
# that the hooks are being set up right. Perhaps these could
|
40
|
+
# be replaced by mock objects in the future.
|
41
|
+
class DummyText < Ruport::Formatter
|
42
|
+
|
43
|
+
renders :text, :for => OldSchoolController
|
44
|
+
|
45
|
+
def prepare_document
|
46
|
+
output << "p"
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_header
|
50
|
+
output << "header\n"
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_body
|
54
|
+
output << "body\n"
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_footer
|
58
|
+
output << "footer\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
def finalize_document
|
62
|
+
output << "f"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# This formatter modifies the (String) data object passed to it
|
67
|
+
class Destructive < Ruport::Formatter
|
68
|
+
|
69
|
+
def prepare_document; end
|
70
|
+
|
71
|
+
def build_header; end
|
72
|
+
|
73
|
+
def build_body
|
74
|
+
output << "You sent #{data}"
|
75
|
+
data.replace("RUBBISH")
|
76
|
+
end
|
77
|
+
|
78
|
+
def build_footer; end
|
79
|
+
|
80
|
+
def finalize_document; end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
class VanillaBinary < Ruport::Formatter
|
85
|
+
renders :bin, :for => VanillaController
|
86
|
+
save_as_binary_file
|
87
|
+
end
|
88
|
+
|
89
|
+
class SpecialFinalize < Ruport::Formatter
|
90
|
+
renders :with_finalize, :for => VanillaController
|
91
|
+
|
92
|
+
def finalize
|
93
|
+
output << "I has been finalized"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class TestController < Test::Unit::TestCase
|
98
|
+
|
99
|
+
def teardown
|
100
|
+
Ruport::Formatter::Template.instance_variable_set(:@templates, nil)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_trivial
|
104
|
+
actual = OldSchoolController.render(:text)
|
105
|
+
assert_equal "header\nbody\nfooter\n", actual
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when running a formatter with custom a finalize method" do
|
109
|
+
def specify_finalize_method_should_be_called
|
110
|
+
assert_equal "I has been finalized",
|
111
|
+
VanillaController.render_with_finalize
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "when using templates" do
|
116
|
+
def specify_apply_template_should_be_called
|
117
|
+
Ruport::Formatter::Template.create(:stub)
|
118
|
+
Table(%w[a b c]).to_csv(:template => :stub) do |r|
|
119
|
+
r.formatter.expects(:apply_template)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def specify_undefined_template_should_throw_sensible_error
|
124
|
+
assert_raises(Ruport::Formatter::TemplateNotDefined) do
|
125
|
+
Table(%w[a b c]).to_csv(:template => :sub)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when using default templates" do
|
131
|
+
def specify_default_template_should_be_called
|
132
|
+
Ruport::Formatter::Template.create(:default)
|
133
|
+
Table(%w[a b c]).to_csv do |r|
|
134
|
+
r.formatter.expects(:apply_template)
|
135
|
+
assert r.formatter.template == Ruport::Formatter::Template[:default]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def specify_specific_should_override_default
|
140
|
+
Ruport::Formatter::Template.create(:default)
|
141
|
+
Ruport::Formatter::Template.create(:stub)
|
142
|
+
Table(%w[a b c]).to_csv(:template => :stub) do |r|
|
143
|
+
r.formatter.expects(:apply_template)
|
144
|
+
assert r.formatter.template == Ruport::Formatter::Template[:stub]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def specify_should_be_able_to_disable_templates
|
149
|
+
Ruport::Formatter::Template.create(:default)
|
150
|
+
Table(%w[a b c]).to_csv(:template => false) do |r|
|
151
|
+
r.formatter.expects(:apply_template).never
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_using_io
|
157
|
+
require "stringio"
|
158
|
+
out = StringIO.new
|
159
|
+
a = OldSchoolController.render(:text) { |r| r.io = out }
|
160
|
+
out.rewind
|
161
|
+
assert_equal "header\nbody\nfooter\n", out.read
|
162
|
+
assert_equal "", out.read
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_using_file
|
166
|
+
f = []
|
167
|
+
File.expects(:open).yields(f)
|
168
|
+
a = OldSchoolController.render(:text, :file => "foo.text")
|
169
|
+
assert_equal "header\nbody\nfooter\n", f[0]
|
170
|
+
|
171
|
+
f = []
|
172
|
+
File.expects(:open).with("blah","wb").yields(f)
|
173
|
+
VanillaController.render(:bin, :file => "blah")
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_using_file_via_rendering_tools
|
177
|
+
f = []
|
178
|
+
File.expects(:open).yields(f)
|
179
|
+
Table(%w[a b c], :data => [[1,2,3],[4,5,6]]).save_as("foo.csv")
|
180
|
+
assert_equal "a,b,c\n1,2,3\n4,5,6\n", f[0]
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
def test_formats
|
185
|
+
assert_equal( {}, Ruport::Controller.formats )
|
186
|
+
assert_equal( { :text => DummyText },OldSchoolController.formats )
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_method_missing
|
190
|
+
actual = OldSchoolController.render_text
|
191
|
+
assert_equal "header\nbody\nfooter\n", actual
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_formatter
|
195
|
+
# normal instance mode
|
196
|
+
rend = OldSchoolController.new
|
197
|
+
rend.send(:use_formatter,:text)
|
198
|
+
|
199
|
+
assert_kind_of Ruport::Formatter, rend.formatter
|
200
|
+
assert_kind_of DummyText, rend.formatter
|
201
|
+
|
202
|
+
# render mode
|
203
|
+
OldSchoolController.render_text do |r|
|
204
|
+
assert_kind_of Ruport::Formatter, r.formatter
|
205
|
+
assert_kind_of DummyText, r.formatter
|
206
|
+
end
|
207
|
+
|
208
|
+
assert_equal "body\n", rend.formatter { build_body }.output
|
209
|
+
|
210
|
+
rend.formatter.clear_output
|
211
|
+
assert_equal "", rend.formatter.output
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_options_act_like_indifferent_hash
|
215
|
+
opts = Ruport::Controller::Options.new
|
216
|
+
opts.foo = "bar"
|
217
|
+
assert_equal "bar", opts[:foo]
|
218
|
+
assert_equal "bar", opts["foo"]
|
219
|
+
|
220
|
+
opts["f"] = "bar"
|
221
|
+
assert_equal "bar", opts[:f]
|
222
|
+
assert_equal "bar", opts.f
|
223
|
+
assert_equal "bar", opts["f"]
|
224
|
+
|
225
|
+
opts[:apple] = "banana"
|
226
|
+
assert_equal "banana", opts.apple
|
227
|
+
assert_equal "banana", opts["apple"]
|
228
|
+
assert_equal "banana", opts[:apple]
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
class TestFormatterUsingBuild < Test::Unit::TestCase
|
235
|
+
# This formatter uses the build syntax
|
236
|
+
class UsesBuild < Ruport::Formatter
|
237
|
+
renders :text_using_build, :for => VanillaController
|
238
|
+
|
239
|
+
build :header do
|
240
|
+
output << "header\n"
|
241
|
+
end
|
242
|
+
|
243
|
+
build :body do
|
244
|
+
output << "body\n"
|
245
|
+
end
|
246
|
+
|
247
|
+
build :footer do
|
248
|
+
output << "footer\n"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_should_render_using_build_syntax
|
253
|
+
assert_equal "header\nbody\nfooter\n",
|
254
|
+
VanillaController.render_text_using_build
|
255
|
+
VanillaController.render_text_using_build do |rend|
|
256
|
+
assert rend.formatter.respond_to?(:build_header)
|
257
|
+
assert rend.formatter.respond_to?(:build_body)
|
258
|
+
assert rend.formatter.respond_to?(:build_footer)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
class TestFormatterWithLayout < Test::Unit::TestCase
|
265
|
+
# This formatter is meant to check out a special case in Ruport's renderer,
|
266
|
+
# in which a layout method is called and yielded to when defined
|
267
|
+
class WithLayout < DummyText
|
268
|
+
renders :text_with_layout, :for => VanillaController
|
269
|
+
|
270
|
+
def layout
|
271
|
+
output << "---\n"
|
272
|
+
yield
|
273
|
+
output << "---\n"
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_layout
|
279
|
+
assert_equal "---\nheader\nbody\nfooter\n---\n",
|
280
|
+
VanillaController.render_text_with_layout
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_layout_disabled
|
284
|
+
assert_equal "header\nbody\nfooter\n",
|
285
|
+
VanillaController.render_text_with_layout(:layout => false)
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
class TestControllerWithManyHooks < Test::Unit::TestCase
|
292
|
+
# This provides a way to check several hooks that controllers supports
|
293
|
+
class ControllerWithManyHooks < Ruport::Controller
|
294
|
+
add_format DummyText, :text
|
295
|
+
add_format Destructive, :destructive
|
296
|
+
|
297
|
+
prepare :document
|
298
|
+
|
299
|
+
stage :header
|
300
|
+
stage :body
|
301
|
+
stage :footer
|
302
|
+
|
303
|
+
finalize :document
|
304
|
+
|
305
|
+
def setup
|
306
|
+
options.apple = true
|
307
|
+
end
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
def test_hash_options_setters
|
312
|
+
a = ControllerWithManyHooks.render(:text, :subtitle => "foo",
|
313
|
+
:subsubtitle => "bar") { |r|
|
314
|
+
assert_equal "foo", r.options.subtitle
|
315
|
+
assert_equal "bar", r.options.subsubtitle
|
316
|
+
}
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_data_accessors
|
320
|
+
a = ControllerWithManyHooks.render(:text, :data => [1,2,4]) { |r|
|
321
|
+
assert_equal [1,2,4], r.data
|
322
|
+
}
|
323
|
+
|
324
|
+
b = ControllerWithManyHooks.render_text(%w[a b c]) { |r|
|
325
|
+
assert_equal %w[a b c], r.data
|
326
|
+
}
|
327
|
+
|
328
|
+
c = ControllerWithManyHooks.render_text(%w[a b f],:snapper => :red) { |r|
|
329
|
+
assert_equal %w[a b f], r.data
|
330
|
+
assert_equal :red, r.options.snapper
|
331
|
+
}
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_formatter_data_dup
|
335
|
+
source = "some text"
|
336
|
+
result = ControllerWithManyHooks.render(:destructive, :data => source)
|
337
|
+
assert_equal("You sent some text", result)
|
338
|
+
assert_equal("some text", source)
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_stage_helper
|
342
|
+
assert ControllerWithManyHooks.stages.include?('body')
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_finalize_helper
|
346
|
+
assert_equal :document, ControllerWithManyHooks.final_stage
|
347
|
+
end
|
348
|
+
|
349
|
+
def test_prepare_helper
|
350
|
+
assert_equal :document, ControllerWithManyHooks.first_stage
|
351
|
+
end
|
352
|
+
|
353
|
+
def test_finalize_again
|
354
|
+
assert_raise(Ruport::Controller::StageAlreadyDefinedError) {
|
355
|
+
ControllerWithManyHooks.finalize :report
|
356
|
+
}
|
357
|
+
end
|
358
|
+
|
359
|
+
def test_prepare_again
|
360
|
+
assert_raise(Ruport::Controller::StageAlreadyDefinedError) {
|
361
|
+
ControllerWithManyHooks.prepare :foo
|
362
|
+
}
|
363
|
+
end
|
364
|
+
|
365
|
+
def test_renderer_using_helpers
|
366
|
+
actual = ControllerWithManyHooks.render(:text)
|
367
|
+
assert_equal "pheader\nbody\nfooter\nf", actual
|
368
|
+
|
369
|
+
actual = ControllerWithManyHooks.render_text
|
370
|
+
assert_equal "pheader\nbody\nfooter\nf", actual
|
371
|
+
end
|
372
|
+
|
373
|
+
def test_required_option_helper
|
374
|
+
a = ControllerWithManyHooks.dup
|
375
|
+
a.required_option :title
|
376
|
+
|
377
|
+
a.render_text do |r|
|
378
|
+
r.title = "Test Report"
|
379
|
+
assert_equal "Test Report", r.options.title
|
380
|
+
end
|
381
|
+
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_without_required_option
|
385
|
+
a = ControllerWithManyHooks.dup
|
386
|
+
a.required_option :title
|
387
|
+
|
388
|
+
assert_raise(Ruport::Controller::RequiredOptionNotSet) { a.render(:text) }
|
389
|
+
end
|
390
|
+
|
391
|
+
end
|
392
|
+
|
393
|
+
|
394
|
+
class TestControllerWithRunHook < Test::Unit::TestCase
|
395
|
+
|
396
|
+
class ControllerWithRunHook < Ruport::Controller
|
397
|
+
add_format DummyText, :text
|
398
|
+
|
399
|
+
required_option :foo,:bar
|
400
|
+
stage :header
|
401
|
+
stage :body
|
402
|
+
stage :footer
|
403
|
+
|
404
|
+
def run
|
405
|
+
formatter.output << "|"
|
406
|
+
super
|
407
|
+
end
|
408
|
+
|
409
|
+
end
|
410
|
+
|
411
|
+
def test_renderer_with_run_hooks
|
412
|
+
assert_equal "|header\nbody\nfooter\n",
|
413
|
+
ControllerWithRunHook.render_text(:foo => "bar",:bar => "baz")
|
414
|
+
end
|
415
|
+
|
416
|
+
end
|
417
|
+
|
418
|
+
|
419
|
+
class TestControllerWithHelperModule < Test::Unit::TestCase
|
420
|
+
|
421
|
+
class ControllerWithHelperModule < VanillaController
|
422
|
+
|
423
|
+
add_format DummyText, :stub
|
424
|
+
|
425
|
+
module Helpers
|
426
|
+
def say_hello
|
427
|
+
"Hello Dolly"
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_renderer_helper_module
|
433
|
+
ControllerWithHelperModule.render_stub do |r|
|
434
|
+
assert_equal "Hello Dolly", r.formatter.say_hello
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
|
440
|
+
class TestMultiPurposeFormatter < Test::Unit::TestCase
|
441
|
+
# This provides a way to check the multi-format hooks for the Controller
|
442
|
+
class MultiPurposeFormatter < Ruport::Formatter
|
443
|
+
|
444
|
+
renders [:html,:text], :for => VanillaController
|
445
|
+
|
446
|
+
def build_header
|
447
|
+
a = 10
|
448
|
+
|
449
|
+
text { output << "Foo: #{a}\n" }
|
450
|
+
html { output << "<b>Foo: #{a}</b>\n" }
|
451
|
+
end
|
452
|
+
|
453
|
+
def build_body
|
454
|
+
html { output << "<pre>\n" }
|
455
|
+
output << options.body_text
|
456
|
+
html { output << "\n</pre>\n" }
|
457
|
+
end
|
458
|
+
|
459
|
+
end
|
460
|
+
|
461
|
+
def test_multi_purpose
|
462
|
+
text = VanillaController.render_text(:body_text => "foo")
|
463
|
+
assert_equal "Foo: 10\nfoo", text
|
464
|
+
html = VanillaController.render_html(:body_text => "bar")
|
465
|
+
assert_equal "<b>Foo: 10</b>\n<pre>\nbar\n</pre>\n",html
|
466
|
+
end
|
467
|
+
|
468
|
+
|
469
|
+
def test_method_missing_hack_formatter
|
470
|
+
assert_equal [:html,:text], MultiPurposeFormatter.formats
|
471
|
+
|
472
|
+
a = MultiPurposeFormatter.new
|
473
|
+
a.format = :html
|
474
|
+
|
475
|
+
visited = false
|
476
|
+
a.html { visited = true }
|
477
|
+
|
478
|
+
assert visited
|
479
|
+
|
480
|
+
visited = false
|
481
|
+
a.text { visited = true }
|
482
|
+
assert !visited
|
483
|
+
|
484
|
+
assert_raises(NoMethodError) do
|
485
|
+
a.pdf { 'do nothing' }
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
end
|
490
|
+
|
491
|
+
|
492
|
+
class TestFormatterErbHelper < Test::Unit::TestCase
|
493
|
+
class ErbFormatter < Ruport::Formatter
|
494
|
+
|
495
|
+
renders :terb, :for => VanillaController
|
496
|
+
|
497
|
+
def build_body
|
498
|
+
# demonstrate local binding
|
499
|
+
@foo = "bar"
|
500
|
+
if options.binding
|
501
|
+
output << erb("Binding Override: <%= reverse %>",
|
502
|
+
:binding => options.binding)
|
503
|
+
else
|
504
|
+
output << erb("Default Binding: <%= @foo %>")
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
end
|
509
|
+
|
510
|
+
#FIXME: need to test file
|
511
|
+
|
512
|
+
def test_self_bound
|
513
|
+
assert_equal "Default Binding: bar", VanillaController.render_terb
|
514
|
+
end
|
515
|
+
|
516
|
+
def test_custom_bound
|
517
|
+
a = [1,2,3]
|
518
|
+
arr_binding = a.instance_eval { binding }
|
519
|
+
assert_equal "Binding Override: 321",
|
520
|
+
VanillaController.render_terb(:binding => arr_binding)
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
|
525
|
+
class TestOptionReaders < Test::Unit::TestCase
|
526
|
+
|
527
|
+
class ControllerForCheckingOptionReaders < Ruport::Controller
|
528
|
+
required_option :foo
|
529
|
+
end
|
530
|
+
|
531
|
+
class ControllerForCheckingPassivity < Ruport::Controller
|
532
|
+
def foo
|
533
|
+
"apples"
|
534
|
+
end
|
535
|
+
required_option :foo
|
536
|
+
end
|
537
|
+
|
538
|
+
def setup
|
539
|
+
@renderer = ControllerForCheckingOptionReaders.new
|
540
|
+
@renderer.formatter = Ruport::Formatter.new
|
541
|
+
|
542
|
+
@passive = ControllerForCheckingPassivity.new
|
543
|
+
@passive.formatter = Ruport::Formatter.new
|
544
|
+
end
|
545
|
+
|
546
|
+
def test_options_are_readable
|
547
|
+
@renderer.foo = 5
|
548
|
+
assert_equal 5, @renderer.foo
|
549
|
+
end
|
550
|
+
|
551
|
+
def test_methods_are_not_overridden
|
552
|
+
@passive.foo = 5
|
553
|
+
assert_equal "apples", @passive.foo
|
554
|
+
assert_equal 5, @passive.options.foo
|
555
|
+
assert_equal 5, @passive.formatter.options.foo
|
556
|
+
end
|
557
|
+
|
558
|
+
end
|
559
|
+
|
560
|
+
class TestSetupOrdering < Test::Unit::TestCase
|
561
|
+
|
562
|
+
class ControllerWithSetup < Ruport::Controller
|
563
|
+
stage :bar
|
564
|
+
def setup
|
565
|
+
options.foo.capitalize!
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
class BasicFormatter < Ruport::Formatter
|
570
|
+
renders :text, :for => ControllerWithSetup
|
571
|
+
|
572
|
+
def build_bar
|
573
|
+
output << options.foo
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
def test_render_hash_options_should_be_called_before_setup
|
578
|
+
assert_equal "Hello", ControllerWithSetup.render_text(:foo => "hello")
|
579
|
+
end
|
580
|
+
|
581
|
+
def test_render_block_should_be_called_before_setup
|
582
|
+
assert_equal "Hello",
|
583
|
+
ControllerWithSetup.render_text { |r| r.options.foo = "hello" }
|
584
|
+
end
|
585
|
+
|
586
|
+
end
|
587
|
+
|
588
|
+
class CustomFormatter < Ruport::Formatter
|
589
|
+
def custom_helper
|
590
|
+
output << "Custom!"
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
class ControllerWithAnonymousFormatters < Ruport::Controller
|
595
|
+
|
596
|
+
stage :report
|
597
|
+
|
598
|
+
formatter :html do
|
599
|
+
build :report do
|
600
|
+
output << textile("h1. Hi there")
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
formatter :csv do
|
605
|
+
build :report do
|
606
|
+
build_row([1,2,3])
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
formatter :pdf do
|
611
|
+
build :report do
|
612
|
+
add_text "hello world"
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
formatter :text do
|
617
|
+
build :report do
|
618
|
+
output << "Hello world"
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
formatter :custom => CustomFormatter do
|
623
|
+
|
624
|
+
build :report do
|
625
|
+
output << "This is "
|
626
|
+
custom_helper
|
627
|
+
end
|
628
|
+
|
629
|
+
end
|
630
|
+
|
631
|
+
end
|
632
|
+
|
633
|
+
class TestAnonymousFormatter < Test::Unit::TestCase
|
634
|
+
context "When using built in Ruport formatters" do
|
635
|
+
|
636
|
+
def specify_text_formatter_shortcut_is_accessible
|
637
|
+
assert_equal "Hello world", ControllerWithAnonymousFormatters.render_text
|
638
|
+
assert_equal "1,2,3\n", ControllerWithAnonymousFormatters.render_csv
|
639
|
+
assert_equal "<h1>Hi there</h1>", ControllerWithAnonymousFormatters.render_html
|
640
|
+
assert_not_nil ControllerWithAnonymousFormatters.render_pdf
|
641
|
+
end
|
642
|
+
|
643
|
+
end
|
644
|
+
|
645
|
+
context "When using custom formatters" do
|
646
|
+
def specify_custom_formatter_shortcut_is_accessible
|
647
|
+
assert_equal "This is Custom!", ControllerWithAnonymousFormatters.render_custom
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
end
|
652
|
+
|
653
|
+
class TestControllerHooks < Test::Unit::TestCase
|
654
|
+
|
655
|
+
context "when renderable_data omitted" do
|
656
|
+
|
657
|
+
require "mocha"
|
658
|
+
|
659
|
+
class DummyObject
|
660
|
+
include Ruport::Controller::Hooks
|
661
|
+
renders_as_table
|
662
|
+
end
|
663
|
+
|
664
|
+
def specify_should_return_self
|
665
|
+
a = DummyObject.new
|
666
|
+
rend = mock("renderer")
|
667
|
+
rend.expects(:data=).with(a)
|
668
|
+
Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
|
669
|
+
a.as(:csv)
|
670
|
+
end
|
671
|
+
|
672
|
+
end
|
673
|
+
|
674
|
+
context "when using renderable_data" do
|
675
|
+
|
676
|
+
class DummyObject2
|
677
|
+
include Ruport::Controller::Hooks
|
678
|
+
renders_as_table
|
679
|
+
|
680
|
+
def renderable_data(format)
|
681
|
+
1
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
def specify_should_return_results_of_renderable_data
|
686
|
+
a = DummyObject2.new
|
687
|
+
rend = mock("renderer")
|
688
|
+
rend.expects(:data=).with(1)
|
689
|
+
Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
|
690
|
+
a.as(:csv)
|
691
|
+
end
|
692
|
+
|
693
|
+
class DummyObject3
|
694
|
+
include Ruport::Controller::Hooks
|
695
|
+
renders_as_table
|
696
|
+
|
697
|
+
def renderable_data
|
698
|
+
raise ArgumentError
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
def specify_should_not_mask_errors
|
703
|
+
assert_raises(ArgumentError) { DummyObject3.new.as(:csv) }
|
704
|
+
end
|
705
|
+
|
706
|
+
class DummyObject4
|
707
|
+
include Ruport::Controller::Hooks
|
708
|
+
renders_as_table
|
709
|
+
|
710
|
+
def renderable_data(format)
|
711
|
+
case format
|
712
|
+
when :html
|
713
|
+
1
|
714
|
+
when :csv
|
715
|
+
2
|
716
|
+
end
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
def specify_should_return_results_of_renderable_data_using_format
|
721
|
+
a = DummyObject4.new
|
722
|
+
rend = mock("renderer")
|
723
|
+
rend.expects(:data=).with(2)
|
724
|
+
Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
|
725
|
+
a.as(:csv)
|
726
|
+
end
|
727
|
+
|
728
|
+
end
|
729
|
+
|
730
|
+
context "when attempting to render a format that doesn't exist" do
|
731
|
+
|
732
|
+
def specify_an_unknown_format_error_should_be_raised
|
733
|
+
|
734
|
+
assert_raises(Ruport::Controller::UnknownFormatError) do
|
735
|
+
Ruport::Controller.render_foo
|
736
|
+
end
|
737
|
+
|
738
|
+
end
|
739
|
+
end
|
740
|
+
|
741
|
+
|
742
|
+
|
743
|
+
end
|