ruport 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,10 @@
1
- Tnghe current version of Ruby Reports is 0.5.0
1
+ Tnghe current version of Ruby Reports is 0.5.1
2
+
3
+ changes since 0.5.0
4
+
5
+ - Broke plugins and engines out into their own files
6
+
7
+ - Fixed a bug which prevented TextPlugin from working right in Windows
2
8
 
3
9
  changes since 0.4.99
4
10
 
data/Rakefile CHANGED
@@ -23,7 +23,7 @@ end
23
23
 
24
24
  spec = Gem::Specification.new do |spec|
25
25
  spec.name = LEAN ? "lean-ruport" : "ruport"
26
- spec.version = "0.5.0"
26
+ spec.version = "0.5.1"
27
27
  spec.platform = Gem::Platform::RUBY
28
28
  spec.summary = "A generalized Ruby report generation and templating engine."
29
29
  spec.files = Dir.glob("{examples,lib,test,bin}/**/**/*") +
@@ -12,7 +12,7 @@
12
12
 
13
13
  module Ruport
14
14
 
15
- VERSION = "0.5.0"
15
+ VERSION = "0.5.1"
16
16
 
17
17
  # Ruports logging and error interface.
18
18
  # Can generate warnings or raise fatal errors
@@ -101,114 +101,7 @@ module Ruport
101
101
  end
102
102
 
103
103
  private_class_method :new
104
+ engines = %w[graph invoice table document]
105
+ engines.each { |e| require "lib/ruport/format/engine/#{e}" }
104
106
  end
105
-
106
- class Format::Engine::Graph < Ruport::Format::Engine
107
-
108
- attributes [:width, :height, :style, :title]
109
-
110
- renderer do
111
- super
112
- active_plugin.render_graph
113
- end
114
-
115
- alias_engine Graph, :graph_engine
116
- Ruport::Format.build_interface_for Graph, :graph
117
-
118
- end
119
-
120
- class Format::Engine::Invoice < Ruport::Format::Engine
121
-
122
- # order meta data
123
- attributes [ :customer_info, :company_info,
124
- :comments, :order_info, :title]
125
-
126
- renderer do
127
- super
128
- build_headers
129
- build_body
130
- build_footer
131
- active_plugin.render_invoice
132
- end
133
-
134
- alias_engine Invoice, :invoice_engine
135
- Ruport::Format.build_interface_for Invoice, :invoice
136
-
137
- end
138
-
139
- class Format::Engine::Table < Format::Engine
140
-
141
- renderer do
142
- super
143
- active_plugin.rendered_field_names = ""
144
- build_field_names if (data.respond_to?(:column_names) &&
145
- data.column_names && show_field_names)
146
- a = active_plugin.render_table
147
- end
148
-
149
- class << self
150
-
151
- def rewrite_column(key,&block)
152
- data.each { |r| r[key] = block[r] }
153
- end
154
-
155
- def num_cols
156
- data[0].to_a.length
157
- end
158
-
159
- def prune(limit=data[0].length)
160
- limit.times do |field|
161
- last = ""
162
- data.each_cons(2) { |l,e|
163
- next if field.nonzero? && e[field-1]
164
- last = l[field] if l[field]
165
- e[field] = nil if e[field] == last
166
- }
167
- end
168
- end
169
-
170
- attr_accessor :show_field_names
171
-
172
- private
173
-
174
- def build_field_names
175
- if active_plugin.respond_to?(:build_field_names)
176
- active_plugin.rendered_field_names =
177
- active_plugin.build_field_names
178
- end
179
- end
180
-
181
- end
182
-
183
- alias_engine Table, :table_engine
184
- Format.build_interface_for Table, :table
185
- self.show_field_names = true
186
- end
187
-
188
- class Format::Engine::Document < Format::Engine
189
-
190
- renderer do
191
- super
192
- apply_erb if erb_enabled
193
- apply_red_cloth if red_cloth_enabled
194
- active_plugin.render_document
195
- end
196
-
197
- class << self
198
-
199
- attr_accessor :red_cloth_enabled
200
- attr_accessor :erb_enabled
201
-
202
- def apply_red_cloth
203
- require "redcloth"
204
- active_plugin.data = RedCloth.new(active_plugin.data).to_html
205
- end
206
-
207
- end
208
-
209
- alias_engine Document, :document_engine
210
- Format.build_interface_for Document, :document
211
- end
212
-
213
-
214
107
  end
@@ -0,0 +1,28 @@
1
+ module Ruport
2
+ class Format::Engine
3
+ class Document < Format::Engine
4
+ renderer do
5
+ super
6
+ apply_erb if erb_enabled
7
+ apply_red_cloth if red_cloth_enabled
8
+ active_plugin.render_document
9
+ end
10
+
11
+ class << self
12
+
13
+ attr_accessor :red_cloth_enabled
14
+ attr_accessor :erb_enabled
15
+
16
+ def apply_red_cloth
17
+ require "redcloth"
18
+ active_plugin.data = RedCloth.new(active_plugin.data).to_html
19
+ end
20
+
21
+ end
22
+
23
+ alias_engine Document, :document_engine
24
+ Format.build_interface_for Document, :document
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,18 @@
1
+ module Ruport
2
+ class Format::Engine
3
+ class Graph < Format::Engine
4
+
5
+ attributes [:width, :height, :style, :title]
6
+
7
+ renderer do
8
+ super
9
+ active_plugin.render_graph
10
+ end
11
+
12
+ alias_engine Graph, :graph_engine
13
+ Ruport::Format.build_interface_for Graph, :graph
14
+
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,23 @@
1
+ module Ruport
2
+ class Format::Engine
3
+ class Format::Engine::Invoice < Ruport::Format::Engine
4
+
5
+ # order meta data
6
+ attributes [ :customer_info, :company_info,
7
+ :comments, :order_info, :title]
8
+
9
+ renderer do
10
+ super
11
+ build_headers
12
+ build_body
13
+ build_footer
14
+ active_plugin.render_invoice
15
+ end
16
+
17
+ alias_engine Invoice, :invoice_engine
18
+ Ruport::Format.build_interface_for Invoice, :invoice
19
+
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,53 @@
1
+ module Ruport
2
+ class Format::Engine
3
+ class Table < Format::Engine
4
+
5
+ renderer do
6
+ super
7
+ active_plugin.rendered_field_names = ""
8
+ build_field_names if (data.respond_to?(:column_names) &&
9
+ data.column_names && show_field_names)
10
+ a = active_plugin.render_table
11
+ end
12
+
13
+ class << self
14
+
15
+ def rewrite_column(key,&block)
16
+ data.each { |r| r[key] = block[r] }
17
+ end
18
+
19
+ def num_cols
20
+ data[0].to_a.length
21
+ end
22
+
23
+ def prune(limit=data[0].length)
24
+ limit.times do |field|
25
+ last = ""
26
+ data.each_cons(2) { |l,e|
27
+ next if field.nonzero? && e[field-1]
28
+ last = l[field] if l[field]
29
+ e[field] = nil if e[field] == last
30
+ }
31
+ end
32
+ end
33
+
34
+ attr_accessor :show_field_names
35
+
36
+ private
37
+
38
+ def build_field_names
39
+ if active_plugin.respond_to?(:build_field_names)
40
+ active_plugin.rendered_field_names =
41
+ active_plugin.build_field_names
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ alias_engine Table, :table_engine
48
+ Format.build_interface_for Table, :table
49
+ self.show_field_names = true
50
+ end
51
+ end
52
+ end
53
+
@@ -2,10 +2,13 @@ class InvalidGraphDataError < RuntimeError; end
2
2
  class InvalidGraphOptionError < RuntimeError; end
3
3
 
4
4
  require 'bigdecimal'
5
+ require 'tempfile'
6
+
7
+ class RenderingError < RuntimeError; end
5
8
 
6
9
  module Ruport
7
10
  class Format::Plugin
8
-
11
+
9
12
  class << self
10
13
 
11
14
  attr_accessor :data
@@ -62,292 +65,9 @@ module Ruport
62
65
  attr_accessor :rendered_field_names
63
66
  attr_accessor :pre, :post
64
67
  attr_accessor :header, :footer
65
- end
66
-
67
-
68
- class CSVPlugin < Format::Plugin
69
-
70
- helper(:init_plugin) { |eng| require "fastercsv" }
71
-
72
- format_field_names do
73
- FasterCSV.generate { |csv| csv << data.column_names }
74
- end
75
-
76
- renderer :table do
77
- rendered_field_names +
78
- FasterCSV.generate { |csv| data.each { |r| csv << r } }
79
- end
80
-
81
- plugin_name :csv
82
- register_on :table_engine
83
- end
84
-
85
- class SVGPlugin < Format::Plugin
86
-
87
- helper(:init_plugin) { |eng|
88
- # check the supplied data can be used for graphing
89
- data.each { |r|
90
- if data.column_names.size != r.data.size
91
- raise InvalidGraphDataError, "Column names and data do not match"
92
- end
93
- r.data.each { |c|
94
- begin
95
- c = BigDecimal.new(c) unless c.kind_of?(Float) ||
96
- c.kind_of?(Fixnum) || c.kind_of?(BigDecimal)
97
- rescue
98
- raise InvalidGraphDataError, "Unable to convert #{c.to_s} into a number"
99
- end
100
- }
101
- }
102
-
103
- raise InvalidGraphOptionError, 'You must provide a width before rendering a graph' if eng.width.nil?
104
- raise InvalidGraphOptionError, 'You must provide a height before rendering a graph' if eng.height.nil?
105
- raise InvalidGraphOptionError, 'You must provide a style before rendering a graph' if eng.style.nil?
106
- if eng.style != :area && eng.style != :bar &&
107
- eng.style != :line &&
108
- eng.style != :smiles &&
109
- eng.style != :stacked
110
- raise InvalidGraphOptionError, 'Invalid graph style'
111
- end
112
-
113
- require 'scruffy'
114
- @graph = Scruffy::Graph.new
115
- @graph.title = eng.title unless eng.title.nil?
116
- @graph.theme = Scruffy::Themes::Mephisto.new
117
- @graph.point_markers = @data.column_names
118
- @graph_style = eng.style
119
- @graph_width = eng.width
120
- @graph_height = eng.height
121
- }
122
-
123
- renderer :graph do
124
-
125
- data.each_with_index { |r,i|
126
- @graph.add(@graph_style,
127
- r.tags[0] || 'series ' + (i+1).to_s,
128
- r.data)
129
- }
130
-
131
- # return the rendered graph
132
- @graph.render(:size => [@graph_width, @graph_height])
133
- end
134
-
135
- plugin_name :svg
136
- register_on :graph_engine
137
- end
138
-
139
- class TextPlugin < Format::Plugin
140
- rendering_options :erb_enabled => true, :red_cloth_enabled => false
141
-
142
- renderer :document
143
-
144
- renderer :table do
145
- require "ruport/system_extensions"
146
-
147
- th = "#{rendered_field_names}#{hr}"
148
-
149
- data.each { |r|
150
- r.each_with_index { |f,i|
151
- r[i] = f.to_s.center(max_col_width(i))
152
- }
153
- }
154
-
155
- a = data.inject(th){ |s,r|
156
- s + "| #{r.to_a.join(' | ')} |\n"
157
- } << hr
158
-
159
- width = self.right_margin || SystemExtensions.terminal_width
160
-
161
- a.to_a.each { |r|
162
- r.gsub!(/\A.{#{width+1},}/) { |m| m[0,width-2] + ">>" }
163
- }.join
164
- end
165
-
166
- format_field_names do
167
- data.column_names.each_with_index { |f,i|
168
- data.column_names[i] = f.to_s.center(max_col_width(i))
169
- }
170
- "#{hr}| #{data.column_names.to_a.join(' | ')} |\n"
171
- end
172
-
173
- action :max_col_width do |index|
174
- f = data.column_names if data.respond_to? :column_names
175
- d = Data::Table.new :column_names => f, :data => data
176
-
177
- cw = d.map { |r| r[index].to_s.length }.max
178
-
179
- return cw unless d.column_names
180
-
181
- nw = (index.kind_of?(Integer) ? d.column_names[index] : index ).to_s.length
182
-
183
- [cw,nw].max
184
- end
185
-
186
- action :table_width do
187
- f = data.column_names if data.respond_to? :column_names
188
- d = Data::Table.new:column_names => f, :data => data
189
-
190
- f = d[0].attributes || (0...d[0].length)
191
-
192
- f.inject(0) { |s,e| s + max_col_width(e) }
193
- end
194
-
195
- action :hr do
196
- len = data[0].to_a.length * 3 + table_width + 1
197
- "+" + "-"*(len-2) + "+\n"
198
- end
199
-
200
- attribute :right_margin
201
- plugin_name :text
202
- register_on :table_engine
203
- register_on :document_engine
204
- end
205
-
206
- class PDFPlugin < Format::Plugin
207
- attribute :pdf
208
- attribute :paper
209
-
210
- helper(:init_plugin) {
211
- require "pdf/writer"
212
- require "pdf/simpletable"
213
- self.pdf = PDF::Writer.new( :paper => paper || "LETTER" )
214
- }
215
-
216
- renderer :table do
217
- pre[pdf] if pre
218
- PDF::SimpleTable.new do |table|
219
- table.maximum_width = 500
220
- table.orientation = :center
221
- table.data = data
222
- m = "Sorry, cant build PDFs from array like things (yet)"
223
- raise m if self.rendered_field_names.empty?
224
- table.column_order = self.rendered_field_names
225
- table.render_on(pdf)
226
- end
227
- post[pdf] if post
228
- pdf.render
229
- end
230
-
231
- format_field_names { data.column_names }
232
-
233
- renderer(:invoice) { pdf.render }
234
-
235
- # Company Information in top lefthand corner
236
- helper(:build_company_header, :engine => :invoice_engine) { |eng|
237
- @tod = pdf.y
238
- text_box(eng.company_info)
239
- }
240
-
241
- helper(:build_headers, :engine => :invoice_engine) { |eng|
242
- build_company_header_helper(eng)
243
- build_customer_header_helper(eng)
244
- build_title_helper(eng)
245
- build_order_header_helper(eng)
246
- }
247
-
248
- helper(:build_order_header, :engine => :invoice_engine) { |eng|
249
- if eng.order_info
250
- text_box(eng.order_info, :position => 350)
251
- end
252
- }
253
-
254
- helper(:build_title, :engine => :invoice_engine) { |eng|
255
- pdf.y = @tod
256
- if eng.title
257
- pdf.text eng.title, :left => 350, :font_size => 14
258
- pdf.y -= 10
259
- end
260
- }
261
-
262
- helper(:build_footer, :engine => :invoice_engine) { |eng|
263
- # footer
264
- pdf.open_object do |footer|
265
- pdf.save_state
266
- pdf.stroke_color! Color::RGB::Black
267
- pdf.stroke_style! PDF::Writer::StrokeStyle::DEFAULT
268
- if eng.comments
269
- pdf.y -= 20
270
- text_box eng.comments, :position => 110, :width => 400,
271
- :font_size => 14
272
- end
273
- pdf.add_text_wrap( 50, 20, 200, "Printed at " +
274
- Time.now.strftime("%H:%M %d/%m/%Y"), 8)
275
-
276
- pdf.restore_state
277
- pdf.close_object
278
- pdf.add_object(footer, :all_pages)
279
- end
280
- pdf.stop_page_numbering(true, :current)
281
- }
282
-
283
- helper(:build_body, :engine => :invoice_engine) do
284
- pdf.start_page_numbering(500, 20, 8, :right)
285
-
286
- # order contents
287
- pdf.y = 620
288
-
289
- PDF::SimpleTable.new do |table|
290
- table.width = 450
291
- table.orientation = :center
292
- table.data = data
293
- table.show_lines = :outer
294
- table.column_order = data.column_names
295
- table.render_on(pdf)
296
- table.font_size = 12
297
- end
298
- end
299
-
300
- # Order details
301
- helper(:build_customer_header, :engine => :invoice_engine) { |eng|
302
- pdf.y -= 10
303
- text_box(eng.customer_info)
304
- }
305
-
306
- def self.text_box(content,options={})
307
- PDF::SimpleTable.new do |table|
308
- table.data = content.to_a.inject([]) do |s,line|
309
- s << { "value" => line }
310
- end
311
- table.column_order = "value"
312
- table.show_headings = false
313
- table.show_lines = :outer
314
- table.shade_rows = :none
315
- table.width = options[:width] || 200
316
- table.orientation = options[:orientation] || :right
317
- table.position = options[:position] || :left
318
- table.font_size = options[:font_size] || 10
319
- table.render_on(pdf)
320
- end
321
- end
322
-
323
- plugin_name :pdf
324
- register_on :table_engine
325
- register_on :invoice_engine
326
- end
327
-
328
- class HTMLPlugin < Format::Plugin
329
-
330
- rendering_options :red_cloth_enabled => true, :erb_enabled => true
331
-
332
- renderer :document
333
-
334
- renderer :table do
335
- rc = data.inject(rendered_field_names) { |s,r|
336
- row = r.map { |e| e.to_s.empty? ? "&nbsp;" : e }
337
- s + "|#{row.to_a.join('|')}|\n"
338
- }
339
- Format.document :data => rc, :plugin => :html
340
- end
341
-
342
- format_field_names do
343
- s = "|_." + data.column_names.join(" |_.") + "|\n"
344
- end
345
-
346
- plugin_name :html
347
- register_on :table_engine
348
- register_on :document_engine
349
68
 
69
+ plugins = %w[text csv pdf svg html]
70
+ plugins.each { |p| require "ruport/format/plugin/#{p}_plugin" }
350
71
  end
351
-
352
- end
72
+ end
353
73
  end
@@ -0,0 +1,22 @@
1
+ module Ruport
2
+ class Format::Plugin
3
+ class CSVPlugin < Format::Plugin
4
+
5
+ helper(:init_plugin) { |eng| require "fastercsv" }
6
+
7
+ format_field_names do
8
+ FasterCSV.generate { |csv| csv << data.column_names }
9
+ end
10
+
11
+ renderer :table do
12
+ rendered_field_names +
13
+ FasterCSV.generate { |csv| data.each { |r| csv << r } }
14
+ end
15
+
16
+ plugin_name :csv
17
+ register_on :table_engine
18
+ end
19
+ end
20
+ end
21
+
22
+
@@ -0,0 +1,27 @@
1
+ module Ruport
2
+ class Format::Plugin
3
+ class HTMLPlugin < Format::Plugin
4
+
5
+ rendering_options :red_cloth_enabled => true, :erb_enabled => true
6
+
7
+ renderer :document
8
+
9
+ renderer :table do
10
+ rc = data.inject(rendered_field_names) { |s,r|
11
+ row = r.map { |e| e.to_s.empty? ? "&nbsp;" : e }
12
+ s + "|#{row.to_a.join('|')}|\n"
13
+ }
14
+ Format.document :data => rc, :plugin => :html
15
+ end
16
+
17
+ format_field_names do
18
+ s = "|_." + data.column_names.join(" |_.") + "|\n"
19
+ end
20
+
21
+ plugin_name :html
22
+ register_on :table_engine
23
+ register_on :document_engine
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,126 @@
1
+ module Ruport
2
+ class Format::Plugin
3
+ class PDFPlugin < Format::Plugin
4
+ attribute :pdf
5
+ attribute :paper
6
+
7
+ helper(:init_plugin) {
8
+ require "pdf/writer"
9
+ require "pdf/simpletable"
10
+ self.pdf = PDF::Writer.new( :paper => paper || "LETTER" )
11
+ }
12
+
13
+ renderer :table do
14
+ pre[pdf] if pre
15
+ PDF::SimpleTable.new do |table|
16
+ table.maximum_width = 500
17
+ table.orientation = :center
18
+ table.data = data
19
+ m = "Sorry, cant build PDFs from array like things (yet)"
20
+ raise m if self.rendered_field_names.empty?
21
+ table.column_order = self.rendered_field_names
22
+ table.render_on(pdf)
23
+ end
24
+ post[pdf] if post
25
+ pdf.render
26
+ end
27
+
28
+ format_field_names { data.column_names }
29
+
30
+ renderer(:invoice) { pdf.render }
31
+
32
+ # Company Information in top lefthand corner
33
+ helper(:build_company_header, :engine => :invoice_engine) { |eng|
34
+ @tod = pdf.y
35
+ text_box(eng.company_info)
36
+ }
37
+
38
+ helper(:build_headers, :engine => :invoice_engine) { |eng|
39
+ build_company_header_helper(eng)
40
+ build_customer_header_helper(eng)
41
+ build_title_helper(eng)
42
+ build_order_header_helper(eng)
43
+ }
44
+
45
+ helper(:build_order_header, :engine => :invoice_engine) { |eng|
46
+ if eng.order_info
47
+ text_box(eng.order_info, :position => 350)
48
+ end
49
+ }
50
+
51
+ helper(:build_title, :engine => :invoice_engine) { |eng|
52
+ pdf.y = @tod
53
+ if eng.title
54
+ pdf.text eng.title, :left => 350, :font_size => 14
55
+ pdf.y -= 10
56
+ end
57
+ }
58
+
59
+ helper(:build_footer, :engine => :invoice_engine) { |eng|
60
+ # footer
61
+ pdf.open_object do |footer|
62
+ pdf.save_state
63
+ pdf.stroke_color! Color::RGB::Black
64
+ pdf.stroke_style! PDF::Writer::StrokeStyle::DEFAULT
65
+ if eng.comments
66
+ pdf.y -= 20
67
+ text_box eng.comments, :position => 110, :width => 400,
68
+ :font_size => 14
69
+ end
70
+ pdf.add_text_wrap( 50, 20, 200, "Printed at " +
71
+ Time.now.strftime("%H:%M %d/%m/%Y"), 8)
72
+
73
+ pdf.restore_state
74
+ pdf.close_object
75
+ pdf.add_object(footer, :all_pages)
76
+ end
77
+ pdf.stop_page_numbering(true, :current)
78
+ }
79
+
80
+ helper(:build_body, :engine => :invoice_engine) do
81
+ pdf.start_page_numbering(500, 20, 8, :right)
82
+
83
+ # order contents
84
+ pdf.y = 620
85
+
86
+ PDF::SimpleTable.new do |table|
87
+ table.width = 450
88
+ table.orientation = :center
89
+ table.data = data
90
+ table.show_lines = :outer
91
+ table.column_order = data.column_names
92
+ table.render_on(pdf)
93
+ table.font_size = 12
94
+ end
95
+ end
96
+
97
+ # Order details
98
+ helper(:build_customer_header, :engine => :invoice_engine) { |eng|
99
+ pdf.y -= 10
100
+ text_box(eng.customer_info)
101
+ }
102
+
103
+ def self.text_box(content,options={})
104
+ PDF::SimpleTable.new do |table|
105
+ table.data = content.to_a.inject([]) do |s,line|
106
+ s << { "value" => line }
107
+ end
108
+ table.column_order = "value"
109
+ table.show_headings = false
110
+ table.show_lines = :outer
111
+ table.shade_rows = :none
112
+ table.width = options[:width] || 200
113
+ table.orientation = options[:orientation] || :right
114
+ table.position = options[:position] || :left
115
+ table.font_size = options[:font_size] || 10
116
+ table.render_on(pdf)
117
+ end
118
+ end
119
+
120
+ plugin_name :pdf
121
+ register_on :table_engine
122
+ register_on :invoice_engine
123
+ end
124
+ end
125
+ end
126
+
@@ -0,0 +1,61 @@
1
+ module Ruport
2
+ class Format::Plugin
3
+ class SVGPlugin < Format::Plugin
4
+ helper(:init_plugin) { |eng|
5
+ # check the supplied data can be used for graphing
6
+ data.each { |r|
7
+ if data.column_names.size != r.data.size
8
+ raise InvalidGraphDataError,
9
+ "Column names and data do not match"
10
+ end
11
+ r.data.each { |c|
12
+ begin
13
+ c = BigDecimal.new(c) unless c.kind_of?(Float) ||
14
+ c.kind_of?(Fixnum) || c.kind_of?(BigDecimal)
15
+ rescue
16
+ raise InvalidGraphDataError,
17
+ "Unable to convert #{c.to_s} into a number"
18
+ end
19
+ }
20
+ }
21
+
22
+ raise InvalidGraphOptionError,
23
+ 'You must provide a width before rendering a graph' if eng.width.nil?
24
+ raise InvalidGraphOptionError,
25
+ 'You must provide a height before rendering a graph' if eng.height.nil?
26
+ raise InvalidGraphOptionError,
27
+ 'You must provide a style before rendering a graph' if eng.style.nil?
28
+ if eng.style != :area && eng.style != :bar &&
29
+ eng.style != :line &&
30
+ eng.style != :smiles &&
31
+ eng.style != :stacked
32
+ raise InvalidGraphOptionError, 'Invalid graph style'
33
+ end
34
+
35
+ require 'scruffy'
36
+ @graph = Scruffy::Graph.new
37
+ @graph.title = eng.title unless eng.title.nil?
38
+ @graph.theme = Scruffy::Themes::Mephisto.new
39
+ @graph.point_markers = @data.column_names
40
+ @graph_style = eng.style
41
+ @graph_width = eng.width
42
+ @graph_height = eng.height
43
+ }
44
+
45
+ renderer :graph do
46
+
47
+ data.each_with_index { |r,i|
48
+ @graph.add(@graph_style,
49
+ r.tags[0] || 'series ' + (i+1).to_s,
50
+ r.data)
51
+ }
52
+
53
+ # return the rendered graph
54
+ @graph.render(:size => [@graph_width, @graph_height])
55
+ end
56
+
57
+ plugin_name :svg
58
+ register_on :graph_engine
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,71 @@
1
+ module Ruport
2
+ class Format::Plugin
3
+ class TextPlugin < Format::Plugin
4
+ rendering_options :erb_enabled => true, :red_cloth_enabled => false
5
+
6
+ renderer :document
7
+
8
+ renderer :table do
9
+ require "ruport/system_extensions"
10
+
11
+ th = "#{rendered_field_names}#{hr}"
12
+
13
+ data.each { |r|
14
+ r.each_with_index { |f,i|
15
+ r[i] = f.to_s.center(max_col_width(i))
16
+ }
17
+ }
18
+
19
+ a = data.inject(th){ |s,r|
20
+ s + "| #{r.to_a.join(' | ')} |\n"
21
+ } << hr
22
+
23
+ width = self.right_margin || SystemExtensions.terminal_width
24
+
25
+ a.to_a.each { |r|
26
+ r.gsub!(/\A.{#{width+1},}/) { |m| m[0,width-2] + ">>" }
27
+ }.join
28
+ end
29
+
30
+ format_field_names do
31
+ data.column_names.each_with_index { |f,i|
32
+ data.column_names[i] = f.to_s.center(max_col_width(i))
33
+ }
34
+ "#{hr}| #{data.column_names.to_a.join(' | ')} |\n"
35
+ end
36
+
37
+ action :max_col_width do |index|
38
+ f = data.column_names if data.respond_to? :column_names
39
+ d = Data::Table.new :column_names => f, :data => data
40
+
41
+ cw = d.map { |r| r[index].to_s.length }.max
42
+
43
+ return cw unless d.column_names
44
+
45
+ nw = (index.kind_of?(Integer) ? d.column_names[index] : index ).to_s.length
46
+
47
+ [cw,nw].max
48
+ end
49
+
50
+ action :table_width do
51
+ f = data.column_names if data.respond_to? :column_names
52
+ d = Data::Table.new:column_names => f, :data => data
53
+
54
+ f = d[0].attributes || (0...d[0].length)
55
+
56
+ f.inject(0) { |s,e| s + max_col_width(e) }
57
+ end
58
+
59
+ action :hr do
60
+ len = data[0].to_a.length * 3 + table_width + 1
61
+ "+" + "-"*(len-2) + "+\n"
62
+ end
63
+
64
+ attribute :right_margin
65
+ plugin_name :text
66
+ register_on :table_engine
67
+ register_on :document_engine
68
+ end
69
+ end
70
+ end
71
+
@@ -58,16 +58,16 @@ module Ruport
58
58
  # A Unix savvy method to fetch the console columns, and rows.
59
59
  def terminal_size
60
60
  `stty size`.split.map { |x| x.to_i }.reverse
61
- end
61
+ end
62
+ end
62
63
 
63
- def terminal_width
64
- terminal_size.first
65
- end
64
+ def terminal_width
65
+ terminal_size.first
66
+ end
66
67
 
67
- def terminal_height
68
- terminal_size.last
69
- end
70
-
68
+ def terminal_height
69
+ terminal_size.last
71
70
  end
71
+
72
72
  end
73
73
  end
@@ -0,0 +1,32 @@
1
+ ***************
2
+ *** 60,74 ****
3
+ `stty size`.split.map { |x| x.to_i }.reverse
4
+ end
5
+
6
+ - end
7
+ -
8
+ - def terminal_width
9
+ - terminal_size.first
10
+ - end
11
+ -
12
+ - def terminal_height
13
+ - terminal_size.last
14
+ - end
15
+
16
+ end
17
+ end
18
+ --- 60,73 ----
19
+ `stty size`.split.map { |x| x.to_i }.reverse
20
+ end
21
+
22
+ + def terminal_width
23
+ + terminal_size.first
24
+ + end
25
+
26
+ + def terminal_height
27
+ + terminal_size.last
28
+ + end
29
+ +
30
+ + end
31
+ end
32
+ end
@@ -36,4 +36,9 @@ class TestCollection < Test::Unit::TestCase
36
36
  assert_equal @ghost_collection.to_csv, @ghost_collection.as(:csv)
37
37
  end
38
38
 
39
+ def test_invalid_plugin_throws_an_error
40
+ assert_raise(InvalidPluginError) { @ghost_collection.to_papyrus_scroll }
41
+ assert_raise(InvalidPluginError) { @ghost_collection.as(:stone_tablet)}
42
+ end
43
+
39
44
  end
@@ -4718,3 +4718,15 @@ F, [2006-08-28T14:56:51.239122 #2797] FATAL -- : no block given!
4718
4718
  F, [2006-08-28T15:03:28.339719 #2839] FATAL -- : Missing host for mailer bar
4719
4719
  F, [2006-08-28T15:03:28.340989 #2839] FATAL -- : Missing DSN for source foo!
4720
4720
  F, [2006-08-28T15:03:29.731996 #2839] FATAL -- : no block given!
4721
+ F, [2006-08-30T16:45:01.507510 #2290] FATAL -- : Missing host for mailer bar
4722
+ F, [2006-08-30T16:45:01.509091 #2290] FATAL -- : Missing DSN for source foo!
4723
+ F, [2006-08-30T16:45:02.931966 #2290] FATAL -- : no block given!
4724
+ F, [2006-08-31T18:50:43.741551 #2594] FATAL -- : Missing host for mailer bar
4725
+ F, [2006-08-31T18:50:43.823591 #2594] FATAL -- : Missing DSN for source foo!
4726
+ F, [2006-08-31T18:50:45.287417 #2594] FATAL -- : no block given!
4727
+ F, [2006-09-02T14:35:05.490338 #2499] FATAL -- : Missing host for mailer bar
4728
+ F, [2006-09-02T14:35:05.524813 #2499] FATAL -- : Missing DSN for source foo!
4729
+ F, [2006-09-02T14:35:07.162616 #2499] FATAL -- : no block given!
4730
+ F, [2006-09-02T14:41:36.925689 #2530] FATAL -- : Missing host for mailer bar
4731
+ F, [2006-09-02T14:41:36.927265 #2530] FATAL -- : Missing DSN for source foo!
4732
+ F, [2006-09-02T14:41:38.446094 #2530] FATAL -- : no block given!
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: ruport
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.5.0
7
- date: 2006-08-28 00:00:00 -04:00
6
+ version: 0.5.1
7
+ date: 2006-09-02 00:00:00 -04:00
8
8
  summary: A generalized Ruby report generation and templating engine.
9
9
  require_paths:
10
10
  - lib
@@ -47,6 +47,7 @@ files:
47
47
  - lib/ruport/rails
48
48
  - lib/ruport/data
49
49
  - lib/ruport/report
50
+ - lib/ruport/system_extensions.rb.rej
50
51
  - lib/ruport/system_extensions.rb
51
52
  - lib/ruport/config.rb
52
53
  - lib/ruport/query.rb
@@ -59,6 +60,17 @@ files:
59
60
  - lib/ruport/query/sql_split.rb
60
61
  - lib/ruport/format/plugin.rb
61
62
  - lib/ruport/format/engine.rb
63
+ - lib/ruport/format/engine
64
+ - lib/ruport/format/plugin
65
+ - lib/ruport/format/engine/document.rb
66
+ - lib/ruport/format/engine/graph.rb
67
+ - lib/ruport/format/engine/invoice.rb
68
+ - lib/ruport/format/engine/table.rb
69
+ - lib/ruport/format/plugin/csv_plugin.rb
70
+ - lib/ruport/format/plugin/html_plugin.rb
71
+ - lib/ruport/format/plugin/pdf_plugin.rb
72
+ - lib/ruport/format/plugin/svg_plugin.rb
73
+ - lib/ruport/format/plugin/text_plugin.rb
62
74
  - lib/ruport/rails/reportable.rb
63
75
  - lib/ruport/data/taggable.rb
64
76
  - lib/ruport/data/table.rb