ruport 0.4.9 → 0.4.11
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 +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
|