report 0.0.1 → 0.0.2

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.
@@ -0,0 +1,16 @@
1
+ 0.0.2 / 2012-07-04
2
+
3
+ * Bug fixes
4
+
5
+ * Properly handle true and false values in pdf and xlsx
6
+
7
+ * Enhancements
8
+
9
+ * More sensible default spacing, font size, and page margins for pdf output
10
+ * If a column is named "Did you really see it?", try #Did_you_really_see_it? and #did_you_really_see_it? (previously we lost ? and ! characters)
11
+ * If a "body.rows" method yields instead of just returning an enumerable, re-yield it
12
+ * If a column block takes 2 args (arity = 2), pass it report and row obj. This is useful when each row is calculated using (1) the row object and (2) something defined only on the report instance itself.
13
+
14
+ 0.0.1 / 2012-07-04
15
+
16
+ Initial release!
@@ -20,7 +20,9 @@ class Report
20
20
  attr_accessor :xlsx_format
21
21
 
22
22
  def table(table_name, &blk)
23
- tables << Table.new(table_name, &blk)
23
+ t = Table.new table_name
24
+ t.instance_eval(&blk)
25
+ tables << t
24
26
  end
25
27
 
26
28
  def format_pdf(hsh)
@@ -1,31 +1,43 @@
1
1
  require 'report/body/column'
2
2
  require 'report/body/row'
3
- require 'report/body/rows'
4
3
 
5
4
  class Report
6
5
  class Body
7
6
  attr_reader :table
8
7
  attr_reader :columns
9
- def initialize(table, &blk)
8
+ attr_reader :method_id
9
+ attr_reader :method_args
10
+ def initialize(table)
10
11
  @table = table
11
12
  @columns = []
12
- instance_eval(&blk)
13
13
  end
14
14
  def rows(*args)
15
- @rows = Rows.new(*([self]+args))
15
+ @method_id = args.shift
16
+ if args.last.is_a?(Array)
17
+ @method_args = args.last
18
+ end
16
19
  end
17
20
  def column(*args, &blk)
18
21
  @columns << Column.new(*([self]+args), &blk)
19
22
  end
20
23
  def each(report)
21
- @rows.each(report) do |obj|
22
- yield Row.new(self, obj)
24
+ block_taken = false
25
+ if method_args
26
+ enum = report.send(method_id, *method_args) do |obj|
27
+ block_taken = true
28
+ yield Row.new(self, report, obj)
29
+ end
30
+ else
31
+ enum = report.send(method_id) do |obj|
32
+ block_taken = true
33
+ yield Row.new(self, report, obj)
34
+ end
35
+ end
36
+ unless block_taken
37
+ enum.each do |obj|
38
+ yield Row.new(self, report, obj)
39
+ end
23
40
  end
24
- end
25
- def to_a(report)
26
- a = []
27
- each(report) { |row| a << row.to_a }
28
- a
29
41
  end
30
42
  end
31
43
  end
@@ -4,12 +4,12 @@ class Report
4
4
  attr_reader :body
5
5
  attr_reader :name
6
6
  attr_reader :method_id
7
- attr_reader :proc
7
+ attr_reader :blk
8
8
  attr_reader :faded
9
9
  attr_reader :row_options
10
- def initialize(*args, &proc)
10
+ def initialize(*args, &blk)
11
11
  if block_given?
12
- @proc = proc
12
+ @blk = blk
13
13
  end
14
14
  @body = args.shift
15
15
  @name = args.shift
@@ -18,9 +18,16 @@ class Report
18
18
  @faded = options.delete(:faded)
19
19
  @row_options = options
20
20
  end
21
- def read(obj)
22
- if @proc
23
- obj.instance_eval(&@proc)
21
+ def read(report, obj)
22
+ if blk
23
+ case blk.arity
24
+ when 0
25
+ obj.instance_eval(&blk)
26
+ when 2
27
+ blk.call report, obj
28
+ else
29
+ raise "column block should have 0 or 2 arguments"
30
+ end
24
31
  elsif method_id
25
32
  obj.send method_id
26
33
  elsif from_name = guesses.detect { |m| obj.respond_to?(m) }
@@ -29,8 +36,8 @@ class Report
29
36
  raise "#{obj.inspect} does not respond to any of #{guesses.inspect}"
30
37
  end
31
38
  end
32
- def read_with_options(obj)
33
- v = read obj
39
+ def read_with_options(report, obj)
40
+ v = read report, obj
34
41
  f = case faded
35
42
  when Symbol
36
43
  obj.send faded
@@ -41,7 +48,10 @@ class Report
41
48
  end
42
49
  private
43
50
  def guesses
44
- [ name, name.underscore.gsub(/\W/, '_') ]
51
+ [
52
+ name.gsub(' ', '_'),
53
+ name.underscore.gsub(/[^\w\!\?]/, '_')
54
+ ]
45
55
  end
46
56
  end
47
57
  end
@@ -3,16 +3,18 @@ class Report
3
3
  class Row
4
4
  attr_reader :body
5
5
  attr_reader :obj
6
- def initialize(body, obj)
6
+ attr_reader :report
7
+ def initialize(body, report, obj)
7
8
  @body = body
9
+ @report = report
8
10
  @obj = obj
9
11
  end
10
12
  def to_a
11
- body.columns.map { |column| column.read(obj) }
13
+ body.columns.map { |column| column.read(report, obj) }
12
14
  end
13
15
  def to_hash
14
16
  body.columns.map do |column|
15
- column.read_with_options obj
17
+ column.read_with_options report, obj
16
18
  end
17
19
  end
18
20
  end
@@ -1,25 +1,30 @@
1
- require 'report/head/row'
2
-
3
1
  class Report
4
2
  class Head
5
3
  attr_reader :table
6
- def initialize(table, &blk)
4
+ def initialize(table)
7
5
  @table = table
8
6
  @rows = []
9
- instance_eval(&blk)
10
7
  end
11
8
  def row(*cells)
12
- @rows << Row.new(self, cells)
9
+ @rows << cells
13
10
  end
14
11
  def each(report)
15
12
  @rows.each do |row|
16
- yield row.read(report)
13
+ actual = row.map do |cell|
14
+ case cell
15
+ when String
16
+ cell
17
+ when Symbol
18
+ unless report.respond_to?(cell)
19
+ raise "#{report.inspect} doesn't respond to #{cell.inspect}"
20
+ end
21
+ report.send cell
22
+ else
23
+ raise "must pass String or Symbol to head row"
24
+ end
25
+ end
26
+ yield actual
17
27
  end
18
28
  end
19
- def to_a(report)
20
- a = []
21
- each(report) { |row| a << row.to_a }
22
- a
23
- end
24
29
  end
25
30
  end
@@ -9,7 +9,7 @@ class Report
9
9
  :bold_italic => File.expand_path('../pdf/DejaVuSansMono-BoldOblique.ttf', __FILE__),
10
10
  }
11
11
  DEFAULT_DOCUMENT = {
12
- :top_margin => 118,
12
+ :top_margin => 72,
13
13
  :right_margin => 36,
14
14
  :bottom_margin => 72,
15
15
  :left_margin => 36,
@@ -40,19 +40,23 @@ class Report
40
40
  Prawn::Document.generate(tmp_path, document) do |pdf|
41
41
 
42
42
  pdf.font_families.update(font_name => font)
43
- pdf.font font_name
43
+ pdf.font font_name, :size => 10
44
44
 
45
+ first = true
45
46
  report.class.tables.each do |table|
46
- if table._head and (t = table._head.to_a(report)).length > 0
47
- pdf.table(t, head)
47
+ if first
48
+ first = false
49
+ else
50
+ pdf.move_down 20
51
+ end
52
+ if t = make(table._head)
53
+ pdf.table t, head
54
+ pdf.move_down 20
48
55
  end
49
-
50
- pdf.move_down 20
51
56
  pdf.text table.name, :style => :bold
52
- pdf.move_down 10
53
-
54
- if table._body and (t = table._body.to_a(report)).length > 0
55
- pdf.table(t, body)
57
+ if t = make(table._body)
58
+ pdf.move_down 10
59
+ pdf.table t, body
56
60
  end
57
61
  end
58
62
 
@@ -71,6 +75,23 @@ class Report
71
75
 
72
76
  private
73
77
 
78
+ def make(src)
79
+ return unless src
80
+ memo = []
81
+ src.each(report) do |row|
82
+ converted = row.to_a.map do |cell|
83
+ case cell
84
+ when TrueClass, FalseClass
85
+ cell.to_s
86
+ else
87
+ cell
88
+ end
89
+ end
90
+ memo << converted
91
+ end
92
+ memo if memo.length > 0
93
+ end
94
+
74
95
  def font_name
75
96
  'MainFont'
76
97
  end
@@ -1,15 +1,18 @@
1
1
  class Report
2
2
  class Table
3
3
  attr_reader :name
4
- def initialize(name, &blk)
4
+ def initialize(name)
5
5
  @name = name
6
- instance_eval(&blk)
7
6
  end
8
7
  def body(&blk)
9
- @body = Body.new(self, &blk)
8
+ b = Body.new self
9
+ b.instance_eval(&blk)
10
+ @body = b
10
11
  end
11
12
  def head(&blk)
12
- @head = Head.new(self, &blk)
13
+ h = Head.new self
14
+ h.instance_eval(&blk)
15
+ @head = h
13
16
  end
14
17
  def _head
15
18
  @head
@@ -1,3 +1,3 @@
1
1
  class Report
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.version = Report::VERSION
18
18
 
19
19
  gem.add_runtime_dependency 'activesupport'
20
- gem.add_runtime_dependency 'xlsx_writer'
20
+ gem.add_runtime_dependency 'xlsx_writer', '>=0.2.2'
21
21
  gem.add_runtime_dependency 'prawn'
22
22
  gem.add_runtime_dependency 'posix-spawn'
23
23
 
@@ -6,14 +6,14 @@ require 'remote_table'
6
6
  require 'unix_utils'
7
7
  require 'posix/spawn'
8
8
 
9
- class Translation < Struct.new(:language, :translation)
9
+ class Translation < Struct.new(:language, :content)
10
10
  class << self
11
11
  def all
12
12
  [ new('English', 'Hello'), new('Russian', 'Здравствуйте') ]
13
13
  end
14
14
  end
15
15
  def backward
16
- translation.reverse
16
+ content.reverse
17
17
  end
18
18
  end
19
19
 
@@ -29,7 +29,7 @@ class A2 < Report
29
29
  body do
30
30
  rows :translations
31
31
  column 'Language'
32
- column 'Translation'
32
+ column 'Content'
33
33
  end
34
34
  end
35
35
  def translations
@@ -44,7 +44,7 @@ class A3 < Report
44
44
  body do
45
45
  rows :translations
46
46
  column 'Language'
47
- column 'Translation'
47
+ column 'Content'
48
48
  end
49
49
  end
50
50
  def description
@@ -59,7 +59,7 @@ class A4 < Report
59
59
  body do
60
60
  rows :translations
61
61
  column 'Language'
62
- column 'Forward', :translation
62
+ column 'Forward', :content
63
63
  column 'Backward'
64
64
  end
65
65
  end
@@ -72,14 +72,14 @@ class A5 < Report
72
72
  body do
73
73
  rows :translations, ['English']
74
74
  column 'Language'
75
- column 'Translation'
75
+ column 'Content'
76
76
  end
77
77
  end
78
78
  table 'InRussian' do
79
79
  body do
80
80
  rows :translations, ['Russian']
81
81
  column 'Language'
82
- column 'Translation'
82
+ column 'Content'
83
83
  end
84
84
  end
85
85
  def translations(language)
@@ -91,8 +91,8 @@ class A6 < Report
91
91
  body do
92
92
  rows :translations
93
93
  column 'Language'
94
- column('Forward') { translation }
95
- column('Backward') { translation.reverse }
94
+ column('Forward') { content }
95
+ column('Backward') { content.reverse }
96
96
  end
97
97
  end
98
98
  def translations
@@ -112,6 +112,33 @@ class A7 < Report
112
112
  end
113
113
  end
114
114
  end
115
+ class A8 < Report
116
+ table 'A8' do
117
+ body do
118
+ rows :translations
119
+ column 'Language'
120
+ column('ClassForward') { |report, translation| [report.class.name, translation.content].join }
121
+ column('ClassBackward') { |report, translation| [report.class.name.reverse, translation.content.reverse].join }
122
+ end
123
+ end
124
+ def translations
125
+ Translation.all
126
+ end
127
+ end
128
+ class A9 < Report
129
+ table 'MemorySafe' do
130
+ body do
131
+ rows :translations
132
+ column 'Language'
133
+ column 'Content'
134
+ end
135
+ end
136
+ def translations
137
+ Translation.all.each do |translation|
138
+ yield translation
139
+ end
140
+ end
141
+ end
115
142
  class Numero < Struct.new(:d_e_c_i_m_a_l, :m_o_n_e_y)
116
143
  class << self
117
144
  def all
@@ -159,6 +186,27 @@ class B2 < Report
159
186
  Numero.all
160
187
  end
161
188
  end
189
+ class Witness < Struct.new(:really_saw_it)
190
+ class << self
191
+ def all
192
+ [ new(true), new(false) ]
193
+ end
194
+ end
195
+ def did_you_really_see_it?
196
+ !!really_saw_it
197
+ end
198
+ end
199
+ class C1 < Report
200
+ table 'C1' do
201
+ body do
202
+ rows :witnesses
203
+ column 'Did you really see it?'
204
+ end
205
+ end
206
+ def witnesses
207
+ Witness.all
208
+ end
209
+ end
162
210
 
163
211
  describe Report do
164
212
  describe '#csv' do
@@ -169,9 +217,9 @@ describe Report do
169
217
  it "constructs a body out of rows and columns" do
170
218
  how_to_say_hello = ::CSV.read A2.new.csv.paths.first, :headers => :first_row
171
219
  how_to_say_hello[0]['Language'].should == 'English'
172
- how_to_say_hello[0]['Translation'].should == 'Hello'
220
+ how_to_say_hello[0]['Content'].should == 'Hello'
173
221
  how_to_say_hello[1]['Language'].should == 'Russian'
174
- how_to_say_hello[1]['Translation'].should == 'Здравствуйте'
222
+ how_to_say_hello[1]['Content'].should == 'Здравствуйте'
175
223
  end
176
224
  it "puts a blank row between head and body" do
177
225
  transl_with_head = ::CSV.read A3.new.csv.paths.first, :headers => false
@@ -196,13 +244,13 @@ describe Report do
196
244
  en = ::CSV.read en_path, :headers => :first_row
197
245
  en.length.should == 1
198
246
  en[0]['Language'].should == 'English'
199
- en[0]['Translation'].should == 'Hello'
247
+ en[0]['Content'].should == 'Hello'
200
248
  ru = ::CSV.read ru_path, :headers => :first_row
201
249
  ru.length.should == 1
202
250
  ru[0]['Language'].should == 'Russian'
203
- ru[0]['Translation'].should == 'Здравствуйте'
251
+ ru[0]['Content'].should == 'Здравствуйте'
204
252
  end
205
- it "instance-evals column blocks against row objects" do
253
+ it "instance-evals column blocks against row objects if arity is 0" do
206
254
  t = ::CSV.read A6.new.csv.paths.first, :headers => :first_row
207
255
  en = t[0]
208
256
  ru = t[1]
@@ -213,6 +261,29 @@ describe Report do
213
261
  ru['Forward'].should == 'Здравствуйте'
214
262
  ru['Backward'].should == 'Здравствуйте'.reverse
215
263
  end
264
+ it "calls column blocks with |report, row_obj| if arity == 2" do
265
+ t = ::CSV.read A8.new.csv.paths.first, :headers => :first_row
266
+ en = t[0]
267
+ ru = t[1]
268
+ en['Language'].should == 'English'
269
+ en['ClassForward'].should == 'A8Hello'
270
+ en['ClassBackward'].should == ['A8'.reverse, 'Hello'.reverse].join
271
+ ru['Language'].should == 'Russian'
272
+ ru['ClassForward'].should == 'A8Здравствуйте'
273
+ ru['ClassBackward'].should == ['A8'.reverse, 'Здравствуйте'.reverse].join
274
+ end
275
+ it "can have row objects yield to it one by one" do
276
+ how_to_say_hello = ::CSV.read A9.new.csv.paths.first, :headers => :first_row
277
+ how_to_say_hello[0]['Language'].should == 'English'
278
+ how_to_say_hello[0]['Content'].should == 'Hello'
279
+ how_to_say_hello[1]['Language'].should == 'Russian'
280
+ how_to_say_hello[1]['Content'].should == 'Здравствуйте'
281
+ end
282
+ it "treats ? and ! as valid method characters" do
283
+ t = ::CSV.read C1.new.csv.paths.first, :headers => :first_row
284
+ t[0]['Did you really see it?'].should == 'true'
285
+ t[1]['Did you really see it?'].should == 'false'
286
+ end
216
287
  end
217
288
 
218
289
  describe '#xlsx' do
@@ -223,9 +294,9 @@ describe Report do
223
294
  it "constructs a body out of rows and columns" do
224
295
  how_to_say_hello = RemoteTable.new A2.new.xlsx.path, :headers => :first_row
225
296
  how_to_say_hello[0]['Language'].should == 'English'
226
- how_to_say_hello[0]['Translation'].should == 'Hello'
297
+ how_to_say_hello[0]['Content'].should == 'Hello'
227
298
  how_to_say_hello[1]['Language'].should == 'Russian'
228
- how_to_say_hello[1]['Translation'].should == 'Здравствуйте'
299
+ how_to_say_hello[1]['Content'].should == 'Здравствуйте'
229
300
  end
230
301
  it "puts a blank row between head and body" do
231
302
  transl_with_head = RemoteTable.new A3.new.xlsx.path, :headers => false, :keep_blank_rows => true
@@ -250,11 +321,11 @@ describe Report do
250
321
  en = RemoteTable.new(path, :headers => :first_row, :sheet => 'InEnglish').to_a
251
322
  en.length.should == 1
252
323
  en[0]['Language'].should == 'English'
253
- en[0]['Translation'].should == 'Hello'
324
+ en[0]['Content'].should == 'Hello'
254
325
  ru = RemoteTable.new(path, :headers => :first_row, :sheet => 'InRussian').to_a
255
326
  ru.length.should == 1
256
327
  ru[0]['Language'].should == 'Russian'
257
- ru[0]['Translation'].should == 'Здравствуйте'
328
+ ru[0]['Content'].should == 'Здравствуйте'
258
329
  end
259
330
  it "instance-evals column blocks against row objects" do
260
331
  t = RemoteTable.new A6.new.xlsx.path, :headers => :first_row
@@ -267,6 +338,13 @@ describe Report do
267
338
  ru['Forward'].should == 'Здравствуйте'
268
339
  ru['Backward'].should == 'Здравствуйте'.reverse
269
340
  end
341
+ it "can have row objects yield to it one by one" do
342
+ how_to_say_hello = RemoteTable.new A9.new.xlsx.path, :headers => :first_row
343
+ how_to_say_hello[0]['Language'].should == 'English'
344
+ how_to_say_hello[0]['Content'].should == 'Hello'
345
+ how_to_say_hello[1]['Language'].should == 'Russian'
346
+ how_to_say_hello[1]['Content'].should == 'Здравствуйте'
347
+ end
270
348
  it "accepts a formatter that works on the raw XlsxWriter::Document" do
271
349
  path = A7.new.xlsx.path
272
350
  dir = UnixUtils.unzip path
@@ -290,6 +368,12 @@ describe Report do
290
368
  FileUtils.rm_f path
291
369
  FileUtils.rm_rf dir
292
370
  end
371
+ it "treats ? and ! as valid method characters" do
372
+ path = C1.new.xlsx.path
373
+ t = RemoteTable.new path, :headers => :first_row
374
+ t[0]['Did you really see it?'].should == 'TRUE'
375
+ t[1]['Did you really see it?'].should == 'FALSE'
376
+ end
293
377
  end
294
378
 
295
379
  describe '#pdf' do
@@ -350,11 +434,27 @@ describe Report do
350
434
  stdout_utf8.should include('Здравствуйте')
351
435
  stdout_utf8.should include('Здравствуйте'.reverse)
352
436
  end
437
+ it "can have row objects yield to it one by one" do
438
+ t = A9.new.pdf.path
439
+ child = POSIX::Spawn::Child.new('pdftotext', t, '-')
440
+ stdout_utf8 = child.out.force_encoding('UTF-8')
441
+ stdout_utf8.should include('English')
442
+ stdout_utf8.should include('Hello')
443
+ stdout_utf8.should include('Russian')
444
+ stdout_utf8.should include('Здравствуйте')
445
+ end
353
446
  it "accepts pdf formatting options, including the ability to stamp with pdftk" do
354
447
  path = B2.new.pdf.path
355
448
  child = POSIX::Spawn::Child.new('pdftotext', path, '-')
356
449
  stdout_utf8 = child.out.force_encoding('UTF-8')
357
450
  stdout_utf8.should include('Firefox')
358
451
  end
452
+ it "treats ? and ! as valid method characters" do
453
+ t = C1.new.pdf.path
454
+ child = POSIX::Spawn::Child.new('pdftotext', t, '-')
455
+ stdout_utf8 = child.out.force_encoding('UTF-8')
456
+ stdout_utf8.should include('true')
457
+ stdout_utf8.should include('false')
458
+ end
359
459
  end
360
460
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: report
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-04 00:00:00.000000000 Z
12
+ date: 2012-07-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ! '>='
36
36
  - !ruby/object:Gem::Version
37
- version: '0'
37
+ version: 0.2.2
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
- version: '0'
45
+ version: 0.2.2
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: prawn
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +149,7 @@ extra_rdoc_files: []
149
149
  files:
150
150
  - .gitignore
151
151
  - .yardopts
152
+ - CHANGELOG
152
153
  - Gemfile
153
154
  - LICENSE
154
155
  - README.md
@@ -158,13 +159,11 @@ files:
158
159
  - lib/report/body.rb
159
160
  - lib/report/body/column.rb
160
161
  - lib/report/body/row.rb
161
- - lib/report/body/rows.rb
162
162
  - lib/report/csv.rb
163
163
  - lib/report/csv/table.rb
164
164
  - lib/report/filename.rb
165
165
  - lib/report/formatter.rb
166
166
  - lib/report/head.rb
167
- - lib/report/head/row.rb
168
167
  - lib/report/pdf.rb
169
168
  - lib/report/pdf/DejaVuSansMono-Bold.ttf
170
169
  - lib/report/pdf/DejaVuSansMono-BoldOblique.ttf
@@ -1,21 +0,0 @@
1
- class Report
2
- class Body
3
- class Rows
4
- attr_reader :body
5
- attr_accessor :method_id
6
- attr_accessor :args
7
- def initialize(*args)
8
- @body = args.shift
9
- @method_id = args.shift
10
- if args.last.is_a?(Array)
11
- @args = args.last
12
- end
13
- end
14
- def each(report, &blk)
15
- (args ? report.send(method_id, *args) : report.send(method_id)).each do |obj|
16
- blk.call obj
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,27 +0,0 @@
1
- class Report
2
- class Head
3
- class Row
4
- attr_reader :head
5
- attr_reader :cells
6
- def initialize(head, cells)
7
- @head = head
8
- @cells = cells
9
- end
10
- def read(report)
11
- cells.map do |cell|
12
- case cell
13
- when String
14
- cell
15
- when Symbol
16
- unless report.respond_to?(cell)
17
- raise "#{report.inspect} doesn't respond to #{cell.inspect}"
18
- end
19
- report.send cell
20
- else
21
- raise "must pass String or Symbol to head row"
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end