ruport 0.4.9 → 0.4.11
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +7 -9
- data/CHANGELOG +36 -2
- data/Rakefile +14 -1
- data/TODO +0 -7
- data/examples/create.sql +2 -0
- data/examples/sql_query.rb +19 -0
- data/lib/ruport.rb +1 -1
- data/lib/ruport/data_row.rb +2 -1
- data/lib/ruport/data_set.rb +28 -6
- data/lib/ruport/format.rb +3 -3
- data/lib/ruport/format/engine.rb +42 -46
- data/lib/ruport/format/plugin.rb +57 -9
- data/lib/ruport/query.rb +1 -1
- data/lib/ruport/rails/reportable.rb +5 -5
- data/lib/ruport/report.rb +3 -16
- data/lib/ruport/system_extensions.rb +125 -0
- data/test/tc_data_set.rb +47 -10
- data/test/tc_format_engine.rb +46 -53
- data/test/tc_plugin.rb +147 -2
- data/test/ts_all.rb +0 -1
- data/test/ts_format.rb +0 -1
- data/test/unit.log +2506 -288
- metadata +14 -21
- data/lib/ruport/format/builder.rb +0 -123
- data/lib/ruport/parser.rb +0 -202
- data/test/samples/car_ads.txt +0 -505
- data/test/samples/five_lines.txt +0 -5
- data/test/samples/five_paragraphs.txt +0 -9
- data/test/samples/ross_report.txt +0 -58530
- data/test/tc_builder.rb +0 -135
- data/test/tc_data_set.rb~ +0 -326
- data/test/tc_state.rb +0 -142
- data/test/ts_parser.rb +0 -10
data/AUTHORS
CHANGED
@@ -2,22 +2,20 @@ Developers:
|
|
2
2
|
---------------------------------------------------
|
3
3
|
|
4
4
|
{Gregory Brown}[mailto:gregory.t.brown@gmail.com]
|
5
|
+
{Dudley Flanders}[mailto:dudley@misnomer.us]
|
5
6
|
|
6
|
-
Contributors / People we've (legally)
|
7
|
+
Contributors / People we've (legally) stolen from:
|
7
8
|
---------------------------------------------------
|
8
9
|
|
9
10
|
James Edward Gray II:
|
10
|
-
Original inspiration via query.rb
|
11
|
-
|
11
|
+
- Original inspiration via query.rb
|
12
|
+
- system_extensions.rb
|
12
13
|
|
13
14
|
Francis Hwang:
|
14
|
-
SQLSplit
|
15
|
+
- SQLSplit
|
15
16
|
|
16
17
|
Simon Claret:
|
17
|
-
PDF table support
|
18
|
-
|
19
|
-
Dudley Flanders:
|
20
|
-
DataSet improvements
|
18
|
+
- PDF table support
|
21
19
|
|
22
20
|
Dinko Mehinovic:
|
23
|
-
util/release/raa.rb
|
21
|
+
- util/release/raa.rb
|
data/CHANGELOG
CHANGED
@@ -1,4 +1,39 @@
|
|
1
|
-
The current version of Ruby Reports is 0.4.
|
1
|
+
The current version of Ruby Reports is 0.4.11
|
2
|
+
|
3
|
+
changes since 0.4.9
|
4
|
+
|
5
|
+
- DataSet#column_names and DataRow#column_names have been added as alias to
|
6
|
+
fields.
|
7
|
+
|
8
|
+
- Plugins are now safely copied when used via DataSet#as or the generated
|
9
|
+
Format::simple_interface(Format.table,Format.document,etc)
|
10
|
+
|
11
|
+
- Dropped insert_row / insert_column from Format::Engine::Table.
|
12
|
+
These are no longer needed.
|
13
|
+
|
14
|
+
- Reworked format engine unit tests to decouple from specific plugins.
|
15
|
+
|
16
|
+
- vendored SystemExtensions from HighLine to get terminal_width /
|
17
|
+
terminal_height functions
|
18
|
+
|
19
|
+
- DataSet#add_columns and DataSet#add_columns! has been added
|
20
|
+
|
21
|
+
- Added pre and post hooks for Plugins. Individual plugins choose if and
|
22
|
+
how to implement them.
|
23
|
+
|
24
|
+
- Parser is gone
|
25
|
+
|
26
|
+
- Format::Builder is gone
|
27
|
+
|
28
|
+
- fixed a bug in rails support. :columns now works properly.
|
29
|
+
|
30
|
+
- fieldnames can now be disabled in CSV loading
|
31
|
+
|
32
|
+
- DataSet.load now loads empty cells as nil instead "" by default
|
33
|
+
|
34
|
+
- fixed HTML table output in HTMLPlugin
|
35
|
+
|
36
|
+
- Select / Remove columns now accepts ordinal indexes
|
2
37
|
|
3
38
|
changes since 0.4.5:
|
4
39
|
|
@@ -72,7 +107,6 @@ changes since 0.4.0:
|
|
72
107
|
|
73
108
|
changes since 0.3.8:
|
74
109
|
|
75
|
-
|
76
110
|
- added DataRow#to_h
|
77
111
|
|
78
112
|
- Ruport::Format.register_filter now passes the content it will modify via a
|
data/Rakefile
CHANGED
@@ -21,7 +21,7 @@ end
|
|
21
21
|
|
22
22
|
spec = Gem::Specification.new do |spec|
|
23
23
|
spec.name = LEAN ? "lean-ruport" : "ruport"
|
24
|
-
spec.version = "0.4.
|
24
|
+
spec.version = "0.4.11"
|
25
25
|
spec.platform = Gem::Platform::RUBY
|
26
26
|
spec.summary = "A generalized Ruby report generation and templating engine."
|
27
27
|
spec.files = Dir.glob("{examples,lib,test}/**/**/*") +
|
@@ -52,7 +52,20 @@ quickly and cleanly.
|
|
52
52
|
END_DESC
|
53
53
|
end
|
54
54
|
|
55
|
+
Rake::RDocTask.new do |rdoc|
|
56
|
+
rdoc.rdoc_files.include( "README",
|
57
|
+
"TODO", "CHANGELOG",
|
58
|
+
"AUTHORS", "COPYING",
|
59
|
+
"LICENSE", "lib/" )
|
60
|
+
rdoc.main = "README"
|
61
|
+
rdoc.rdoc_dir = "doc/html"
|
62
|
+
rdoc.title = "Ruport Documentation"
|
63
|
+
end
|
64
|
+
|
65
|
+
|
55
66
|
Rake::GemPackageTask.new(spec) do |pkg|
|
56
67
|
pkg.need_zip = true
|
57
68
|
pkg.need_tar = true
|
58
69
|
end
|
70
|
+
|
71
|
+
|
data/TODO
CHANGED
@@ -2,13 +2,6 @@ TODO: (Wiped clean for a fresh start as of 2006.02.20)
|
|
2
2
|
|
3
3
|
Immediate Goals:
|
4
4
|
|
5
|
-
Bugs:
|
6
|
-
|
7
|
-
- DataSet deep cloning is broken thanks to activerecord.
|
8
|
-
|
9
|
-
- The format engine doesn't have a good way to give you cloned copies
|
10
|
-
of the Plugins meaningfully
|
11
|
-
|
12
5
|
Features:
|
13
6
|
|
14
7
|
- event system
|
data/examples/create.sql
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "ruport"
|
3
|
+
Ruport.configure { |c|
|
4
|
+
c.source :default, :dsn => "dbi:mysql:ruport", :user => "root"
|
5
|
+
}
|
6
|
+
|
7
|
+
SQL = <<-EOS
|
8
|
+
drop table if exists people;
|
9
|
+
create table people(
|
10
|
+
id int not null auto_increment,
|
11
|
+
name text,
|
12
|
+
email varchar(50),
|
13
|
+
primary key (id)
|
14
|
+
);
|
15
|
+
insert into people VALUES(NULL, 'gregory', 'g@g.com')
|
16
|
+
EOS
|
17
|
+
|
18
|
+
Ruport::Query.new(SQL).execute
|
19
|
+
p Ruport::Query.new("select * from people").result
|
data/lib/ruport.rb
CHANGED
data/lib/ruport/data_row.rb
CHANGED
data/lib/ruport/data_set.rb
CHANGED
@@ -47,6 +47,7 @@ module Ruport
|
|
47
47
|
|
48
48
|
#an array which contains column names
|
49
49
|
attr_accessor :fields
|
50
|
+
alias_method :column_names, :fields
|
50
51
|
|
51
52
|
#the default value to fill empty cells with
|
52
53
|
attr_accessor :default
|
@@ -167,7 +168,8 @@ module Ruport
|
|
167
168
|
# my_data = Ruport::DataSet.load("foo.csv")
|
168
169
|
# my_data = Ruport::DataSet.load("foo.yaml")
|
169
170
|
# my_data = Ruport::DataSet.load("foo.yml")
|
170
|
-
def self.load ( source,
|
171
|
+
def self.load ( source, options={}, &block)
|
172
|
+
options = {:has_names => true}.merge(options)
|
171
173
|
case source
|
172
174
|
when /\.(yaml|yml)/
|
173
175
|
return YAML.load(File.open(source))
|
@@ -181,10 +183,12 @@ module Ruport
|
|
181
183
|
else
|
182
184
|
lambda { |r| loaded_data << r }
|
183
185
|
end
|
186
|
+
|
187
|
+
loaded_data.fields = input[0] if options[:has_names]
|
188
|
+
input = input[1..-1] if options[:has_names]
|
184
189
|
|
185
|
-
loaded_data.
|
186
|
-
|
187
|
-
input[1..-1].each { |row| action[row] }
|
190
|
+
loaded_data.default = options[:default]
|
191
|
+
input.each { |row| action[row] }
|
188
192
|
return loaded_data
|
189
193
|
else
|
190
194
|
raise "Invalid file type"
|
@@ -194,6 +198,7 @@ module Ruport
|
|
194
198
|
|
195
199
|
# Returns a new DataSet composed of the fields specified.
|
196
200
|
def select_columns(*fields)
|
201
|
+
fields = get_field_names(fields)
|
197
202
|
rows = fields.inject([]) { |s,e| s << map { |row| row[e] } }.transpose
|
198
203
|
my_data = DataSet.new(fields, :data => rows)
|
199
204
|
end
|
@@ -204,16 +209,26 @@ module Ruport
|
|
204
209
|
@fields = a.fields; @data = a.data
|
205
210
|
end
|
206
211
|
|
212
|
+
#Creates a new dataset with additional columns appending to it
|
213
|
+
def add_columns(*fields)
|
214
|
+
select_columns *(@fields + fields)
|
215
|
+
end
|
216
|
+
|
217
|
+
def add_columns!(*fields)
|
218
|
+
select_columns! *(@fields + fields)
|
219
|
+
end
|
207
220
|
|
208
221
|
# Returns a new DataSet with the specified fields removed
|
209
222
|
def remove_columns(*fields)
|
223
|
+
fields = get_field_names(fields)
|
210
224
|
select_columns(*(@fields-fields))
|
211
225
|
end
|
212
226
|
|
213
227
|
# removes the specified fields from this DataSet (DESTRUCTIVE!)
|
214
228
|
def remove_columns!(*fields)
|
215
|
-
|
216
|
-
@data
|
229
|
+
d = remove_columns(*fields)
|
230
|
+
@data = d.data
|
231
|
+
@fields = d.fields
|
217
232
|
end
|
218
233
|
|
219
234
|
# uses Format::Builder to render DataSets in various ready to output
|
@@ -262,6 +277,13 @@ module Ruport
|
|
262
277
|
# Readable string representation of the DataSet
|
263
278
|
def to_s; as(:text) end
|
264
279
|
|
280
|
+
private
|
281
|
+
|
282
|
+
def get_field_names(f)
|
283
|
+
f.all? { |e| e.kind_of? Integer } &&
|
284
|
+
f.inject([]) { |s,e| s << @fields[e] } || f
|
285
|
+
end
|
286
|
+
|
265
287
|
end
|
266
288
|
end
|
267
289
|
|
data/lib/ruport/format.rb
CHANGED
@@ -68,7 +68,7 @@ module Ruport
|
|
68
68
|
options[:auto_render] = false; simple_interface(engine,options) })
|
69
69
|
end
|
70
70
|
|
71
|
-
%w[
|
71
|
+
%w[open_node document engine plugin].each { |lib|
|
72
72
|
require "ruport/format/#{lib}"
|
73
73
|
}
|
74
74
|
|
@@ -83,13 +83,13 @@ module Ruport
|
|
83
83
|
options[:auto_render] = true unless options.has_key? :auto_render
|
84
84
|
|
85
85
|
|
86
|
-
options[:data]
|
86
|
+
options[:data] = options[:data].dup
|
87
87
|
|
88
88
|
options.each do |k,v|
|
89
89
|
my_engine.send("#{k}=",v) if my_engine.respond_to? k
|
90
90
|
end
|
91
91
|
|
92
|
-
options[:auto_render] ? my_engine.render : my_engine
|
92
|
+
options[:auto_render] ? my_engine.render : my_engine.dup
|
93
93
|
end
|
94
94
|
|
95
95
|
end
|
data/lib/ruport/format/engine.rb
CHANGED
@@ -2,7 +2,6 @@ module Ruport
|
|
2
2
|
class Format::Engine
|
3
3
|
require "forwardable"
|
4
4
|
|
5
|
-
|
6
5
|
class << self
|
7
6
|
|
8
7
|
include Enumerable
|
@@ -16,32 +15,36 @@ module Ruport
|
|
16
15
|
end
|
17
16
|
|
18
17
|
attr_accessor :engine_klasses
|
18
|
+
attr_reader :plugin
|
19
|
+
attr_reader :data
|
20
|
+
attr_accessor :klass_binding
|
19
21
|
|
20
22
|
def alias_engine(klass,name)
|
21
23
|
Format::Engine.engine_klasses ||= {}
|
22
24
|
Format::Engine.engine_klasses[name] = klass
|
23
25
|
end
|
24
26
|
|
25
|
-
def
|
26
|
-
@
|
27
|
+
def data=(data)
|
28
|
+
@data = data
|
29
|
+
active_plugin.data = data.dup if active_plugin
|
27
30
|
end
|
28
31
|
|
29
|
-
def
|
30
|
-
format_plugins[
|
32
|
+
def active_plugin
|
33
|
+
@format_plugins[:current]
|
34
|
+
#plugin && @format_plugins[plugin]
|
31
35
|
end
|
32
36
|
|
33
|
-
def
|
34
|
-
|
37
|
+
def plugin=(p)
|
38
|
+
@plugin = p
|
39
|
+
@format_plugins[:current] = @format_plugins[p].dup
|
40
|
+
@format_plugins[:current].data = self.data.dup if self.data
|
35
41
|
end
|
36
|
-
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
def active_plugin
|
42
|
-
plugin && @format_plugins[plugin]
|
42
|
+
|
43
|
+
def apply_erb
|
44
|
+
active_plugin.data =
|
45
|
+
ERB.new(active_plugin.data).result(klass_binding || binding)
|
43
46
|
end
|
44
|
-
|
47
|
+
|
45
48
|
def render
|
46
49
|
raise "No plugin specified" unless plugin
|
47
50
|
raise "No data provided" unless data
|
@@ -52,53 +55,47 @@ module Ruport
|
|
52
55
|
self.data = nil
|
53
56
|
end
|
54
57
|
|
55
|
-
def
|
56
|
-
|
57
|
-
ERB.new(active_plugin.data).result(klass_binding || binding)
|
58
|
+
def accept_format_plugin(klass)
|
59
|
+
format_plugins[klass.format_name] = klass
|
58
60
|
end
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
private
|
63
|
+
|
64
|
+
def format_plugins
|
65
|
+
@format_plugins ||= {}
|
66
|
+
end
|
67
|
+
|
68
|
+
def plugin_names
|
69
|
+
format_plugins.keys
|
70
|
+
end
|
71
|
+
|
72
|
+
def plugins
|
73
|
+
format_plugins.values
|
74
|
+
end
|
75
|
+
|
64
76
|
end
|
65
77
|
end
|
66
78
|
|
67
79
|
class Format::Engine::Table < Format::Engine
|
68
80
|
|
69
81
|
renderer do
|
70
|
-
super
|
82
|
+
super
|
71
83
|
active_plugin.rendered_field_names = ""
|
72
|
-
build_field_names if (data.respond_to?(:fields) &&
|
73
|
-
|
84
|
+
build_field_names if (data.respond_to?(:fields) &&
|
85
|
+
data.fields && show_field_names)
|
86
|
+
a = active_plugin.render_table
|
74
87
|
end
|
75
88
|
|
76
89
|
class << self
|
77
|
-
def insert_column(options)
|
78
|
-
filler = options[:filler].to_s
|
79
|
-
nr_action = if (index = options[:left_of])
|
80
|
-
lambda { |e| e.to_a[0..index-1] + [filler] + e.to_a[index..-1] }
|
81
|
-
elsif (index = options[:right_of])
|
82
|
-
lambda { |e| e.to_a[0..index] + [filler] + e.to_a[index+1..-1] }
|
83
|
-
end
|
84
|
-
self.data = self.data.inject([]) { |a,r|
|
85
|
-
a << nr_action[r]
|
86
|
-
}
|
87
|
-
end
|
88
|
-
|
89
|
-
def insert_row(options)
|
90
|
-
filler = options[:filler].to_s
|
91
|
-
self.data = if (index = options[:above])
|
92
|
-
data.to_a[0..index-1] + [filler] + data.to_a[index..-1]
|
93
|
-
elsif (index = options[:below])
|
94
|
-
data.to_a[0..index] + [filler] + data.to_a[index+1..-1]
|
95
|
-
end
|
96
|
-
end
|
97
90
|
|
98
91
|
def rewrite_column(key,&block)
|
99
92
|
data.each { |r| r[key] = block[r] }
|
100
93
|
end
|
101
94
|
|
95
|
+
def num_cols
|
96
|
+
data[0].to_a.length
|
97
|
+
end
|
98
|
+
|
102
99
|
attr_accessor :show_field_names
|
103
100
|
|
104
101
|
private
|
@@ -134,7 +131,6 @@ module Ruport
|
|
134
131
|
require "redcloth"
|
135
132
|
active_plugin.data = RedCloth.new(active_plugin.data).to_html
|
136
133
|
end
|
137
|
-
|
138
134
|
|
139
135
|
end
|
140
136
|
|
data/lib/ruport/format/plugin.rb
CHANGED
@@ -41,6 +41,7 @@ module Ruport
|
|
41
41
|
end
|
42
42
|
|
43
43
|
attr_accessor :rendered_field_names
|
44
|
+
attr_accessor :pre, :post
|
44
45
|
end
|
45
46
|
|
46
47
|
|
@@ -48,7 +49,7 @@ module Ruport
|
|
48
49
|
|
49
50
|
format_field_names do
|
50
51
|
require "fastercsv"
|
51
|
-
FasterCSV.generate { |csv| csv << data.fields }
|
52
|
+
FasterCSV.generate { |csv| csv << data.fields }
|
52
53
|
end
|
53
54
|
|
54
55
|
renderer :table do
|
@@ -61,30 +62,75 @@ module Ruport
|
|
61
62
|
end
|
62
63
|
|
63
64
|
class TextPlugin < Format::Plugin
|
64
|
-
|
65
65
|
rendering_options :erb_enabled => true, :red_cloth_enabled => false
|
66
66
|
|
67
67
|
renderer :document
|
68
68
|
|
69
|
-
renderer :table do
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
renderer :table do
|
70
|
+
require "ruport/system_extensions"
|
71
|
+
|
72
|
+
th = "#{rendered_field_names}#{hr}"
|
73
|
+
|
74
|
+
data.each { |r|
|
75
|
+
r.each_with_index { |f,i|
|
76
|
+
r[i] = f.to_s.center(max_col_width(i))
|
77
|
+
}
|
73
78
|
}
|
79
|
+
|
80
|
+
a = data.inject(th){ |s,r|
|
81
|
+
s << "| #{r.to_a.join(' | ')} |\n"
|
82
|
+
} << hr
|
83
|
+
|
84
|
+
width = self.right_margin || SystemExtensions.terminal_width
|
85
|
+
|
86
|
+
a.split("\n").each { |r|
|
87
|
+
r.gsub!(/\A.{#{width},}/) { |m| m[0,width-2] += ">>" }
|
88
|
+
}.join("\n") << "\n"
|
74
89
|
end
|
75
90
|
format_field_names do
|
76
|
-
|
91
|
+
data.fields.each_with_index { |f,i|
|
92
|
+
data.fields[i] = f.to_s.center(max_col_width(i))
|
93
|
+
}
|
94
|
+
"#{hr}| #{data.fields.to_a.join(' | ')} |\n"
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.max_col_width(index)
|
98
|
+
f = data.fields if data.respond_to? :fields
|
99
|
+
d = DataSet.new f, :data => data
|
100
|
+
|
101
|
+
cw = d.map { |r| r[index].to_s.length }.max
|
102
|
+
|
103
|
+
return cw unless d.fields
|
104
|
+
|
105
|
+
nw = (index.kind_of?(Integer) ? d.fields[index] : index ).to_s.length
|
106
|
+
|
107
|
+
[cw,nw].max
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.table_width
|
111
|
+
f = data.fields if data.respond_to? :fields
|
112
|
+
d = DataSet.new f, :data => data
|
113
|
+
|
114
|
+
d[0].fields.inject(0) { |s,e| s+=max_col_width(e) }
|
77
115
|
end
|
78
116
|
|
117
|
+
def self.hr
|
118
|
+
len = data[0].to_a.length * 3 + table_width + 1
|
119
|
+
"+" + "-"*(len-2) + "+\n"
|
120
|
+
end
|
121
|
+
|
122
|
+
class << self; attr_accessor :right_margin; end
|
123
|
+
|
79
124
|
register_on :table_engine
|
80
125
|
register_on :document_engine
|
81
126
|
end
|
82
127
|
|
83
128
|
class PDFPlugin < Format::Plugin
|
129
|
+
|
84
130
|
renderer :table do
|
85
131
|
require "pdf/writer"; require "pdf/simpletable";
|
86
|
-
return unless defined? PDF::Writer
|
87
132
|
pdf = PDF::Writer.new
|
133
|
+
pre[pdf] if pre
|
88
134
|
PDF::SimpleTable.new do |table|
|
89
135
|
table.maximum_width = 500
|
90
136
|
table.orientation = :center
|
@@ -94,6 +140,7 @@ module Ruport
|
|
94
140
|
table.column_order = self.rendered_field_names
|
95
141
|
table.render_on(pdf)
|
96
142
|
end
|
143
|
+
post[pdf] if post
|
97
144
|
pdf.render
|
98
145
|
end
|
99
146
|
|
@@ -110,7 +157,8 @@ module Ruport
|
|
110
157
|
|
111
158
|
renderer :table do
|
112
159
|
rc = data.inject(rendered_field_names) { |s,r|
|
113
|
-
|
160
|
+
row = r.map { |e| e.to_s.empty? ? " " : e }
|
161
|
+
s << "|#{row.to_a.join('|')}|\n"
|
114
162
|
}
|
115
163
|
Format.document :data => rc, :plugin => :html
|
116
164
|
end
|