ruport 0.12.0 → 1.0.0
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/Rakefile +1 -1
- data/examples/btree/commaleon/commaleon.rb +264 -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 +43 -16
- data/examples/data/tattle.dump +82 -0
- data/examples/line_plotter.rb +9 -14
- data/examples/pdf_report_with_common_base.rb +46 -43
- data/examples/{ruport_list/png_embed.rb → png_embed.rb} +3 -4
- data/examples/{ruport_list/roadmap.png → roadmap.png} +0 -0
- data/examples/simple_pdf_lines.rb +2 -0
- data/examples/tattle_ruby_version.rb +39 -0
- data/examples/tattle_rubygems_version.rb +39 -0
- data/examples/trac_ticket_status.rb +59 -0
- data/lib/ruport.rb +2 -2
- data/lib/ruport/data/grouping.rb +13 -8
- data/lib/ruport/formatter.rb +1 -1
- data/lib/ruport/formatter/html.rb +35 -2
- data/lib/ruport/formatter/pdf.rb +6 -4
- data/lib/ruport/formatter/text.rb +7 -7
- data/lib/ruport/renderer.rb +12 -8
- data/lib/ruport/renderer/grouping.rb +10 -0
- data/test/acts_as_reportable_test.rb +2 -2
- data/test/grouping_test.rb +18 -2
- data/test/html_formatter_test.rb +16 -0
- data/test/pdf_formatter_test.rb +16 -0
- data/test/renderer_test.rb +64 -9
- data/test/table_test.rb +2 -2
- data/util/bench/data/record/bench_as_vs_to.rb +4 -3
- metadata +15 -11
- data/examples/pdf_complex_report.rb +0 -39
- data/examples/pdf_styles.rb +0 -16
- data/examples/pdf_table_with_title.rb +0 -42
- data/test/database_test_.rb +0 -25
- data/test/samples/document.xml +0 -22
- data/test/samples/stonecodeblog.sql +0 -279
@@ -0,0 +1,59 @@
|
|
1
|
+
%w[ruport hpricot open-uri].each { |lib| require lib }
|
2
|
+
|
3
|
+
class TracSummaryReport
|
4
|
+
|
5
|
+
include Ruport::Renderer::Hooks
|
6
|
+
|
7
|
+
renders_as_table
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
@days = options[:days] || 7
|
11
|
+
@timeline_uri = options[:timeline_uri]
|
12
|
+
end
|
13
|
+
|
14
|
+
class TicketStatus < Ruport::Data::Record
|
15
|
+
|
16
|
+
def closed
|
17
|
+
title =~ /Ticket.+(\w+ closed)/ ? 1 : 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def opened
|
21
|
+
title =~ /Ticket.+(\w+ created)|(\w+ reopened)/ ? 1 : 0
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def feed_data
|
27
|
+
uri = @timeline_uri + "?wiki=on&milestone=on&ticket=on&changeset=on"+
|
28
|
+
"&max=10000&daysback=#{@days-1}&format=rss"
|
29
|
+
|
30
|
+
feed = Hpricot(open(uri))
|
31
|
+
|
32
|
+
table = Table([:title, :date], :record_class => TicketStatus) do |table|
|
33
|
+
(feed/"item").each do |r|
|
34
|
+
title = (r/"title").innerHTML
|
35
|
+
next unless title =~ /Ticket.*(created|closed|reopene)/
|
36
|
+
table << { :title => title,
|
37
|
+
:date => Date.parse((r/"pubdate").innerHTML) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Grouping(table,:by => :date)
|
42
|
+
end
|
43
|
+
|
44
|
+
def renderable_data
|
45
|
+
summary = feed_data.summary :date,
|
46
|
+
:opened => lambda { |g| g.sigma { |r| r.opened } },
|
47
|
+
:closed => lambda { |g| g.sigma { |r| r.closed } },
|
48
|
+
:order => [:date,:opened,:closed]
|
49
|
+
|
50
|
+
summary.sort_rows_by! { |r| r.date }
|
51
|
+
return summary
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
timeline = "http://stonecode.svnrepository.com/ruport/trac.cgi/timeline"
|
56
|
+
|
57
|
+
report = TracSummaryReport.new(:timeline_uri => timeline, :days => 14)
|
58
|
+
puts report.as(:text)
|
59
|
+
|
data/lib/ruport.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# Author: Gregory T. Brown (gregory.t.brown at gmail dot com)
|
4
4
|
#
|
5
|
-
# Copyright (c)
|
5
|
+
# Copyright (c) 2005-2007, All Rights Reserved.
|
6
6
|
#
|
7
7
|
# This is free software. You may modify and redistribute this freely under
|
8
8
|
# your choice of the GNU General Public License or the Ruby License.
|
@@ -12,7 +12,7 @@
|
|
12
12
|
|
13
13
|
module Ruport #:nodoc:#
|
14
14
|
|
15
|
-
VERSION = "0.
|
15
|
+
VERSION = "1.0.0"
|
16
16
|
|
17
17
|
class FormatterError < RuntimeError #:nodoc:
|
18
18
|
end
|
data/lib/ruport/data/grouping.rb
CHANGED
@@ -156,14 +156,19 @@ module Ruport::Data
|
|
156
156
|
#
|
157
157
|
# grouping = Grouping.new(table, :by => "a")
|
158
158
|
#
|
159
|
-
def initialize(data,options={})
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
@
|
165
|
-
|
166
|
-
|
159
|
+
def initialize(data={},options={})
|
160
|
+
if data.kind_of?(Hash)
|
161
|
+
@grouped_by = data[:by]
|
162
|
+
@data = {}
|
163
|
+
else
|
164
|
+
@grouped_by = options[:by]
|
165
|
+
cols = Array(options[:by]).dup
|
166
|
+
@data = data.to_group.send(:grouped_data, cols.shift)
|
167
|
+
cols.each do |col|
|
168
|
+
@data.each do |name,group|
|
169
|
+
group.create_subgroups(col)
|
170
|
+
end
|
171
|
+
end
|
167
172
|
end
|
168
173
|
end
|
169
174
|
|
data/lib/ruport/formatter.rb
CHANGED
@@ -21,12 +21,14 @@ module Ruport
|
|
21
21
|
#
|
22
22
|
# <tt>:show_group_headers</tt> True by default
|
23
23
|
#
|
24
|
+
# <tt>:style</tt> Used for grouping (:inline, :justified)
|
25
|
+
#
|
24
26
|
class Formatter::HTML < Formatter
|
25
27
|
|
26
28
|
renders :html, :for => [ Renderer::Row, Renderer::Table,
|
27
29
|
Renderer::Group, Renderer::Grouping ]
|
28
30
|
|
29
|
-
opt_reader :show_table_headers, :show_group_headers
|
31
|
+
opt_reader :show_table_headers, :show_group_headers, :style
|
30
32
|
|
31
33
|
# Generates table headers based on the column names of your Data::Table.
|
32
34
|
#
|
@@ -80,7 +82,12 @@ module Ruport
|
|
80
82
|
# renders them using the group renderer.
|
81
83
|
#
|
82
84
|
def build_grouping_body
|
83
|
-
|
85
|
+
case style
|
86
|
+
when :inline
|
87
|
+
render_inline_grouping(options)
|
88
|
+
when :justified
|
89
|
+
render_justified_grouping
|
90
|
+
end
|
84
91
|
end
|
85
92
|
|
86
93
|
# Generates <table> tags enclosing the yielded content.
|
@@ -106,6 +113,32 @@ module Ruport
|
|
106
113
|
rescue LoadError
|
107
114
|
raise RuntimeError, "You need RedCloth!\n gem install RedCloth -v 3.0.3"
|
108
115
|
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def render_justified_grouping
|
120
|
+
output << "\t<table>\n\t\t<tr>\n\t\t\t<th>" +
|
121
|
+
"#{data.grouped_by}</th>\n\t\t\t<th>" +
|
122
|
+
grouping_columns.join("</th>\n\t\t\t<th>") +
|
123
|
+
"</th>\n\t\t</tr>\n"
|
124
|
+
data.each do |name, group|
|
125
|
+
group.each_with_index do |row, i|
|
126
|
+
output << "\t\t<tr>\n\t\t\t"
|
127
|
+
if i == 0
|
128
|
+
output << "<td class=\"groupName\">#{name}</td>\n\t\t\t<td>"
|
129
|
+
else
|
130
|
+
output << "<td> </td>\n\t\t\t<td>"
|
131
|
+
end
|
132
|
+
output << row.to_a.join("</td>\n\t\t\t<td>") +
|
133
|
+
"</td>\n\t\t</tr>\n"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
output << "\t</table>"
|
137
|
+
end
|
138
|
+
|
139
|
+
def grouping_columns
|
140
|
+
data.data.to_a[0][1].column_names
|
141
|
+
end
|
109
142
|
|
110
143
|
end
|
111
144
|
end
|
data/lib/ruport/formatter/pdf.rb
CHANGED
@@ -41,8 +41,6 @@ module Ruport
|
|
41
41
|
#
|
42
42
|
class Formatter::PDF < Formatter
|
43
43
|
|
44
|
-
## THESE ARE WHY YOU SHOULD NEVER USE PDF::Writer
|
45
|
-
|
46
44
|
module PDFWriterMemoryPatch #:nodoc:
|
47
45
|
unless self.class.instance_methods.include?("_post_transaction_rewind")
|
48
46
|
def _post_transaction_rewind
|
@@ -133,7 +131,7 @@ module Ruport
|
|
133
131
|
|
134
132
|
# Determines which style to use and renders the main body for
|
135
133
|
# Renderer::Grouping
|
136
|
-
def build_grouping_body
|
134
|
+
def build_grouping_body
|
137
135
|
case style
|
138
136
|
when :inline
|
139
137
|
render_inline_grouping(options.to_hash.merge(:formatter => pdf_writer,
|
@@ -311,6 +309,8 @@ module Ruport
|
|
311
309
|
table_data.rename_columns { |c| c.to_s }
|
312
310
|
|
313
311
|
format_opts = table_format.merge(format_opts) if table_format
|
312
|
+
|
313
|
+
old = pdf_writer.font_size
|
314
314
|
|
315
315
|
::PDF::SimpleTable.new do |table|
|
316
316
|
table.extend(PDFSimpleTableOrderingPatch)
|
@@ -322,7 +322,9 @@ module Ruport
|
|
322
322
|
|
323
323
|
format_opts.each {|k,v| table.send("#{k}=", v) }
|
324
324
|
table.render_on(pdf_writer)
|
325
|
-
end
|
325
|
+
end
|
326
|
+
|
327
|
+
pdf_writer.font_size = old
|
326
328
|
end
|
327
329
|
|
328
330
|
# This module provides tools to simplify some common drawing operations
|
@@ -18,13 +18,13 @@ module Ruport
|
|
18
18
|
# edge of the screen in the console, proper column alignment, and pretty
|
19
19
|
# output that looks something like this:
|
20
20
|
#
|
21
|
-
#
|
22
|
-
# | apple | banana | strawberry
|
23
|
-
#
|
24
|
-
# | yes | no | yes
|
25
|
-
# | yes | yes |
|
26
|
-
# | what | the |
|
27
|
-
#
|
21
|
+
# +------------------------------+
|
22
|
+
# | apple | banana | strawberry |
|
23
|
+
# +------------------------------+
|
24
|
+
# | yes | no | yes |
|
25
|
+
# | yes | yes | red snapper |
|
26
|
+
# | what | the | red snapper |
|
27
|
+
# +------------------------------+
|
28
28
|
#
|
29
29
|
# === Supported Options
|
30
30
|
#
|
data/lib/ruport/renderer.rb
CHANGED
@@ -10,8 +10,6 @@
|
|
10
10
|
# for different kinds of tasks. See Renderer::Table for a tabular data
|
11
11
|
# renderer.
|
12
12
|
#
|
13
|
-
# This class can easily be extended to build custom formatting systems, but if
|
14
|
-
# you do not need that, it may not be relevant to study for your use of Ruport.
|
15
13
|
class Ruport::Renderer
|
16
14
|
|
17
15
|
class RequiredOptionNotSet < RuntimeError #:nodoc:
|
@@ -318,10 +316,16 @@ class Ruport::Renderer
|
|
318
316
|
# option :font_size, :font_style
|
319
317
|
# # other details omitted
|
320
318
|
# end
|
321
|
-
def option(*opts)
|
322
|
-
opts.each do |opt|
|
319
|
+
def option(*opts)
|
320
|
+
opts.each do |opt|
|
321
|
+
o = opt
|
322
|
+
unless instance_methods(false).include?(o.to_s)
|
323
|
+
define_method(o) {
|
324
|
+
options.send(o.to_s)
|
325
|
+
}
|
326
|
+
end
|
323
327
|
opt = "#{opt}="
|
324
|
-
define_method(opt) {|t| options.send(opt, t) }
|
328
|
+
define_method(opt) {|t| options.send(opt, t) }
|
325
329
|
end
|
326
330
|
end
|
327
331
|
|
@@ -362,8 +366,8 @@ class Ruport::Renderer
|
|
362
366
|
# sets the data and options, and then does the following process:
|
363
367
|
#
|
364
368
|
# * If the renderer contains a module Helpers, mix it in to the instance.
|
369
|
+
# * If a block is given, yield the Renderer instance
|
365
370
|
# * If a setup() method is defined on the Renderer, call it
|
366
|
-
# * If a block is given, yield the Renderer instance
|
367
371
|
# * If the renderer has defined a run() method, call it, otherwise,
|
368
372
|
# include Renderer::AutoRunner. (you usually won't need a run() method )
|
369
373
|
# * call _run_ if it exists (This is provided by default, by AutoRunner)
|
@@ -375,9 +379,9 @@ class Ruport::Renderer
|
|
375
379
|
# Please see the examples/ directory for custom renderer examples, because
|
376
380
|
# this is not nearly as complicated as it sounds in most cases.
|
377
381
|
def render(*args)
|
378
|
-
rend = build(*args) { |r|
|
382
|
+
rend = build(*args) { |r|
|
383
|
+
yield(r) if block_given?
|
379
384
|
r.setup if r.respond_to? :setup
|
380
|
-
yield(r) if block_given?
|
381
385
|
}
|
382
386
|
if rend.respond_to? :run
|
383
387
|
rend.run
|
@@ -1,3 +1,13 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# renderer/grouping.rb : Group data renderer for Ruby Reports
|
4
|
+
#
|
5
|
+
# Written by Michael Milner, 2007.
|
6
|
+
# Copyright (C) 2007, 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
|
+
#
|
1
11
|
module Ruport
|
2
12
|
|
3
13
|
# This class implements the basic renderer for a single group of data.
|
@@ -11,10 +11,10 @@ rescue LoadError
|
|
11
11
|
nil
|
12
12
|
end
|
13
13
|
|
14
|
-
require "ruport/acts_as_reportable"
|
15
|
-
|
16
14
|
if Object.const_defined?(:ActiveRecord) && Object.const_defined?(:Mocha)
|
17
15
|
|
16
|
+
require "ruport/acts_as_reportable"
|
17
|
+
|
18
18
|
class Team < ActiveRecord::Base
|
19
19
|
acts_as_reportable :except => 'id', :include => :players
|
20
20
|
has_many :players
|
data/test/grouping_test.rb
CHANGED
@@ -86,7 +86,7 @@ class TestGroupRendering < Test::Unit::TestCase
|
|
86
86
|
@group = Ruport::Data::Group.new(:name => 'test',
|
87
87
|
:data => [[1,2,3]],
|
88
88
|
:column_names => %w[a b c])
|
89
|
-
end
|
89
|
+
end
|
90
90
|
|
91
91
|
def test_group_as
|
92
92
|
assert_equal(7, @group.to_text.to_a.length)
|
@@ -129,7 +129,23 @@ class TestGrouping < Test::Unit::TestCase
|
|
129
129
|
:column_names => %w[b c],
|
130
130
|
:name => 4 ) }
|
131
131
|
assert_equal c, b.data
|
132
|
-
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_empty_grouping
|
135
|
+
a = Ruport::Data::Grouping.new()
|
136
|
+
a << Group("foo",:data => [[1,2,3],[4,5,6]],
|
137
|
+
:column_names => %w[a b c] )
|
138
|
+
assert_equal "foo", a["foo"].name
|
139
|
+
assert_nil a.grouped_by
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_empty_grouping_with_grouped_by
|
143
|
+
a = Ruport::Data::Grouping.new(:by => "nada")
|
144
|
+
a << Group("foo",:data => [[1,2,3],[4,5,6]],
|
145
|
+
:column_names => %w[a b c] )
|
146
|
+
assert_equal "foo", a["foo"].name
|
147
|
+
assert_equal "nada", a.grouped_by
|
148
|
+
end
|
133
149
|
|
134
150
|
def test_grouping_indexing
|
135
151
|
a = [Ruport::Data::Group.new( :data => [[2,3]],
|
data/test/html_formatter_test.rb
CHANGED
@@ -101,6 +101,22 @@ class TestRenderHTMLGrouping < Test::Unit::TestCase
|
|
101
101
|
"\t<th>c</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>7</td>\n"+
|
102
102
|
"\t\t\t<td>9</td>\n\t\t</tr>\n\t</table>\n", actual
|
103
103
|
end
|
104
|
+
|
105
|
+
def test_render_justified_html_grouping
|
106
|
+
table = Table(%w[a b c]) << [1,2,3] << [1,1,3] << [2,7,9]
|
107
|
+
g = Grouping(table,:by => "a")
|
108
|
+
actual = Ruport::Renderer::Grouping.render(:html, :data => g,
|
109
|
+
:style => :justified)
|
110
|
+
|
111
|
+
assert_equal "\t<table>\n\t\t<tr>\n\t\t\t<th>a</th>\n\t\t\t<th>b</th>\n"+
|
112
|
+
"\t\t\t<th>c</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t"+
|
113
|
+
"<td class=\"groupName\">1</td>\n\t\t\t<td>"+
|
114
|
+
"2</td>\n\t\t\t<td>3</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t"+
|
115
|
+
"<td> </td>\n\t\t\t<td>1</td>\n\t\t\t<td>3</td>"+
|
116
|
+
"\n\t\t</tr>\n\t\t<tr>\n\t\t\t"+
|
117
|
+
"<td class=\"groupName\">2</td>\n\t\t\t<td>7</td>\n"+
|
118
|
+
"\t\t\t<td>9</td>\n\t\t</tr>\n\t</table>", actual
|
119
|
+
end
|
104
120
|
end
|
105
121
|
|
106
122
|
|
data/test/pdf_formatter_test.rb
CHANGED
@@ -69,6 +69,22 @@ class TestRenderPDFGrouping < Test::Unit::TestCase
|
|
69
69
|
assert_raises(NotImplementedError) do
|
70
70
|
grouping.to_pdf(:style => :red_snapper)
|
71
71
|
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_grouping_should_have_consistent_font_size
|
75
|
+
a = Table(%w[a b c]) << %w[eye like chicken] << %w[eye like liver] <<
|
76
|
+
%w[meow mix meow ] << %w[mix please deliver ]
|
77
|
+
b = Grouping(a, :by => "a")
|
78
|
+
splat = b.to_pdf.split("\n")
|
79
|
+
splat.grep(/meow/).each do |m|
|
80
|
+
assert_equal '10.0', m.split[5]
|
81
|
+
end
|
82
|
+
splat.grep(/mix/).each do |m|
|
83
|
+
assert_equal '10.0', m.split[5]
|
84
|
+
end
|
85
|
+
splat.grep(/eye/).each do |m|
|
86
|
+
assert_equal '10.0', m.split[5]
|
87
|
+
end
|
72
88
|
end
|
73
89
|
|
74
90
|
end
|
data/test/renderer_test.rb
CHANGED
@@ -229,14 +229,6 @@ class TestRendererWithManyHooks < Test::Unit::TestCase
|
|
229
229
|
assert_equal "pheader\nbody\nfooter\nf", actual
|
230
230
|
end
|
231
231
|
|
232
|
-
def test_setup
|
233
|
-
actual = false
|
234
|
-
RendererWithManyHooks.render_text { |r|
|
235
|
-
actual = r.options.apple
|
236
|
-
}
|
237
|
-
assert actual
|
238
|
-
end
|
239
|
-
|
240
232
|
def test_option_helper
|
241
233
|
RendererWithManyHooks.render_text do |r|
|
242
234
|
r.subtitle = "Test Report"
|
@@ -395,6 +387,69 @@ class TestFormatterErbHelper < Test::Unit::TestCase
|
|
395
387
|
assert_equal "Binding Override: 321",
|
396
388
|
VanillaRenderer.render_terb(:binding => arr_binding)
|
397
389
|
end
|
398
|
-
end
|
390
|
+
end
|
399
391
|
|
400
392
|
|
393
|
+
class TestOptionReaders < Test::Unit::TestCase
|
394
|
+
|
395
|
+
class RendererForCheckingOptionReaders < Ruport::Renderer
|
396
|
+
option :foo
|
397
|
+
end
|
398
|
+
|
399
|
+
class RendererForCheckingPassivity < Ruport::Renderer
|
400
|
+
def foo
|
401
|
+
"apples"
|
402
|
+
end
|
403
|
+
option :foo
|
404
|
+
end
|
405
|
+
|
406
|
+
def setup
|
407
|
+
@renderer = RendererForCheckingOptionReaders.new
|
408
|
+
@renderer.formatter = Ruport::Formatter.new
|
409
|
+
|
410
|
+
@passive = RendererForCheckingPassivity.new
|
411
|
+
@passive.formatter = Ruport::Formatter.new
|
412
|
+
end
|
413
|
+
|
414
|
+
def test_options_are_readable
|
415
|
+
@renderer.foo = 5
|
416
|
+
assert_equal 5, @renderer.foo
|
417
|
+
end
|
418
|
+
|
419
|
+
def test_methods_are_not_overridden
|
420
|
+
@passive.foo = 5
|
421
|
+
assert_equal "apples", @passive.foo
|
422
|
+
assert_equal 5, @passive.options.foo
|
423
|
+
assert_equal 5, @passive.formatter.options.foo
|
424
|
+
end
|
425
|
+
|
426
|
+
end
|
427
|
+
|
428
|
+
class TestSetupOrdering < Test::Unit::TestCase
|
429
|
+
|
430
|
+
class RendererWithSetup < Ruport::Renderer
|
431
|
+
option :foo
|
432
|
+
stage :bar
|
433
|
+
def setup
|
434
|
+
foo.capitalize!
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
class BasicFormatter < Ruport::Formatter
|
439
|
+
renders :text, :for => RendererWithSetup
|
440
|
+
|
441
|
+
def build_bar
|
442
|
+
output << options.foo
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def test_render_hash_options_should_be_called_before_setup
|
447
|
+
assert_equal "Hello", RendererWithSetup.render_text(:foo => "hello")
|
448
|
+
end
|
449
|
+
|
450
|
+
def test_render_block_should_be_called_before_setup
|
451
|
+
assert_equal "Hello",
|
452
|
+
RendererWithSetup.render_text { |r| r.foo = "hello" }
|
453
|
+
end
|
454
|
+
|
455
|
+
end
|