reportbuilder 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/Manifest.txt +20 -0
- data/README.txt +34 -0
- data/Rakefile +16 -0
- data/bin/reportbuilder +3 -0
- data/data/reportbuilder.css +0 -0
- data/data/reportbuilder.js +0 -0
- data/lib/reportbuilder/generator/html.rb +99 -0
- data/lib/reportbuilder/generator/text.rb +25 -0
- data/lib/reportbuilder/generator.rb +40 -0
- data/lib/reportbuilder/section.rb +48 -0
- data/lib/reportbuilder/table/htmlgenerator.rb +50 -0
- data/lib/reportbuilder/table/textgenerator.rb +53 -0
- data/lib/reportbuilder/table.rb +137 -0
- data/lib/reportbuilder.rb +58 -0
- data/test/test_html.rb +47 -0
- data/test/test_reportbuilder.rb +22 -0
- data/test/test_section.rb +56 -0
- data/test/test_table.rb +87 -0
- metadata +89 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/reportbuilder
|
6
|
+
data/reportbuilder.css
|
7
|
+
data/reportbuilder.js
|
8
|
+
lib/reportbuilder/generator.rb
|
9
|
+
lib/reportbuilder/generator/html.rb
|
10
|
+
lib/reportbuilder/generator/text.rb
|
11
|
+
lib/reportbuilder.rb
|
12
|
+
lib/reportbuilder/section.rb
|
13
|
+
lib/reportbuilder/table.rb
|
14
|
+
lib/reportbuilder/table/htmlgenerator.rb
|
15
|
+
lib/reportbuilder/table/textgenerator.rb
|
16
|
+
test/test_html.rb
|
17
|
+
test/test_reportbuilder.rb
|
18
|
+
test/test_section.rb
|
19
|
+
test/test_table.rb
|
20
|
+
|
data/README.txt
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
= reportbuilder
|
2
|
+
|
3
|
+
* http://ruby-statsample.rubyforge.org/reportbuilder
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Report Abstract Interface. Creates text, html and pdf output, based on a common framework
|
8
|
+
|
9
|
+
== FEATURES
|
10
|
+
|
11
|
+
* One interface, multiple outputs
|
12
|
+
|
13
|
+
== SYNOPSIS:
|
14
|
+
|
15
|
+
rb=ReportBuilder.new
|
16
|
+
rb.add("This is a text")
|
17
|
+
table=rb.table(%w{id name})
|
18
|
+
table.add_row([1,"Nombre"])
|
19
|
+
table.add_hr
|
20
|
+
rb.add(table)
|
21
|
+
puts rb.to_text
|
22
|
+
puts rb.to_html
|
23
|
+
puts rb.to_pdf
|
24
|
+
|
25
|
+
== REQUIREMENTS:
|
26
|
+
|
27
|
+
|
28
|
+
== INSTALL:
|
29
|
+
|
30
|
+
sudo gem install reportbuilder
|
31
|
+
|
32
|
+
== LICENSE:
|
33
|
+
|
34
|
+
GPL-2
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
$:.unshift(File.dirname(__FILE__)+"/lib")
|
4
|
+
require 'rubygems'
|
5
|
+
require 'hoe'
|
6
|
+
require 'reportbuilder'
|
7
|
+
|
8
|
+
Hoe.spec 'reportbuilder' do
|
9
|
+
self.version=ReportBuilder::VERSION
|
10
|
+
self.rubyforge_name = 'ruby-statsample'
|
11
|
+
self.developer('Claudio Bustos', 'clbustos_at_gmail.com')
|
12
|
+
self.url = "http://rubyforge.org/projects/ruby-statsample/"
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
# vim: syntax=ruby
|
data/bin/reportbuilder
ADDED
File without changes
|
File without changes
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
class ReportBuilder
|
3
|
+
class Generator
|
4
|
+
|
5
|
+
class Html < Generator
|
6
|
+
PREFIX="html"
|
7
|
+
attr_reader :toc
|
8
|
+
def initialize(builder)
|
9
|
+
super
|
10
|
+
@body=""
|
11
|
+
@toc=[]
|
12
|
+
@table_n=1
|
13
|
+
@entry_n=1
|
14
|
+
@list_tables=[]
|
15
|
+
@headers=[]
|
16
|
+
@footers=[]
|
17
|
+
end
|
18
|
+
def parse
|
19
|
+
parse_cycle(@builder)
|
20
|
+
end
|
21
|
+
def out
|
22
|
+
out="<html><head><title>#{@builder.name}</title>"
|
23
|
+
out << @headers.join("\n")
|
24
|
+
out << "</head><body>\n"
|
25
|
+
out << "<h1>#{@builder.name}</h1>"
|
26
|
+
if (@list_tables.size>0)
|
27
|
+
out << "<div class='tot'><div class='title'>List of tables</div><ul>"
|
28
|
+
@list_tables.each {|anchor,name|
|
29
|
+
out << "<li><a href='#"+anchor+"'>#{name}</a></li>"
|
30
|
+
}
|
31
|
+
out << "</ul></div>\n"
|
32
|
+
end
|
33
|
+
if(@toc.size>0)
|
34
|
+
out << "<div class='toc'><div class='title'>List of contents</div></div>"
|
35
|
+
actual_level=0
|
36
|
+
@toc.each do |anchor,name,level|
|
37
|
+
if actual_level!=level
|
38
|
+
if actual_level > level
|
39
|
+
(actual_level-level).times { out << "</ul>\n"}
|
40
|
+
else
|
41
|
+
(level-actual_level).times { out << "<ul>\n"}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
out << "<li><a href='##{anchor}'>#{name}</a></li>\n"
|
45
|
+
actual_level=level
|
46
|
+
end
|
47
|
+
actual_level.times { out << "</ul>\n"}
|
48
|
+
out << "</div>\n"
|
49
|
+
end
|
50
|
+
out << @body
|
51
|
+
out << @footers.join("\n")
|
52
|
+
out << "</body></html>"
|
53
|
+
end
|
54
|
+
def add_js(js)
|
55
|
+
if(File.exists? js)
|
56
|
+
if(!File.exists? @builder.dir+"/js/"+File.basename(js))
|
57
|
+
FileUtils.mkdir @builder.dir+"/js"
|
58
|
+
FileUtils.cp js,@builder.dir+"/js/"+File.basename(js)
|
59
|
+
end
|
60
|
+
@headers.push("<script type='text/javascript' src='js/#{File.basename(js)}'></script>")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_css(css)
|
65
|
+
if(File.exists? css)
|
66
|
+
if(!File.exists? @builder.dir+"/css/"+File.basename(css))
|
67
|
+
FileUtils.mkdir @builder.dir+"/css"
|
68
|
+
FileUtils.cp css,@builder.dir+"/css/"+File.basename(css)
|
69
|
+
end
|
70
|
+
@headers.push("<link rel='stylesheet' type='text/css' href='css/#{File.basename(css)}' />")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def add_text(t)
|
76
|
+
ws=(" "*parse_level*2)
|
77
|
+
@body << ws << "<pre>#{t}</pre>\n"
|
78
|
+
end
|
79
|
+
def add_raw(t)
|
80
|
+
ws=(" "*parse_level*2)
|
81
|
+
@body << ws << t << "\n"
|
82
|
+
end
|
83
|
+
def add_toc_entry(name)
|
84
|
+
anchor="toc_#{@entry_n}"
|
85
|
+
@entry_n+=1
|
86
|
+
@toc.push([anchor, name, parse_level])
|
87
|
+
anchor
|
88
|
+
end
|
89
|
+
# Add an entry for a table
|
90
|
+
# Returns the name of the anchor
|
91
|
+
def add_table_entry(name)
|
92
|
+
anchor="table_#{@table_n}"
|
93
|
+
@table_n+=1
|
94
|
+
@list_tables.push([anchor,name])
|
95
|
+
anchor
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class ReportBuilder
|
2
|
+
class Generator
|
3
|
+
class Text < Generator
|
4
|
+
PREFIX="text"
|
5
|
+
attr_reader :toc
|
6
|
+
attr_reader :out
|
7
|
+
def initialize(builder)
|
8
|
+
super
|
9
|
+
@out=""
|
10
|
+
end
|
11
|
+
def parse
|
12
|
+
@out="Report: #{@builder.name}\n"
|
13
|
+
parse_cycle(@builder)
|
14
|
+
@out << "\n"
|
15
|
+
end
|
16
|
+
def add_text(t)
|
17
|
+
ws=" "*parse_level*2
|
18
|
+
@out << ws << t << "\n"
|
19
|
+
end
|
20
|
+
def add_text_raw(t)
|
21
|
+
@out << t
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class ReportBuilder
|
2
|
+
# Abstract class for generators.
|
3
|
+
# A generator is a class which control the output for a builder.
|
4
|
+
# On parse_cycle()....
|
5
|
+
#
|
6
|
+
class Generator
|
7
|
+
#PREFIX="none"
|
8
|
+
attr_reader :parse_level
|
9
|
+
# builder is a ReportBuilder object
|
10
|
+
def initialize(builder)
|
11
|
+
@builder=builder
|
12
|
+
@parse_level=0
|
13
|
+
end
|
14
|
+
# parse each element of the parameters
|
15
|
+
def parse_cycle(container)
|
16
|
+
@parse_level+=1
|
17
|
+
container.elements.each do |element|
|
18
|
+
method=("to_rb_"+self.class::PREFIX).intern
|
19
|
+
if element.respond_to? method
|
20
|
+
element.send(method, self)
|
21
|
+
else
|
22
|
+
add_text(element.to_s)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@parse_level-=1
|
26
|
+
end
|
27
|
+
def add_text(t)
|
28
|
+
raise "Implement this"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
class ElementGenerator
|
32
|
+
def initialize(generator,element)
|
33
|
+
@element=element
|
34
|
+
@generator=generator
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'reportbuilder/generator/text'
|
40
|
+
require 'reportbuilder/generator/html'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Creates a Section
|
2
|
+
class ReportBuilder::Section
|
3
|
+
@@n=1
|
4
|
+
attr_reader :parent, :elements, :name
|
5
|
+
def initialize(name=nil)
|
6
|
+
if name.nil?
|
7
|
+
@name="Section #{@nn}"
|
8
|
+
@nn+=1
|
9
|
+
else
|
10
|
+
@name=name
|
11
|
+
end
|
12
|
+
@parent = nil
|
13
|
+
@elements = []
|
14
|
+
end
|
15
|
+
def parent=(sect)
|
16
|
+
if sect.is_a? ReportBuilder::Section
|
17
|
+
@parent=sect
|
18
|
+
else
|
19
|
+
raise ArgumentError("Parent should be a Section")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_rb_text(generator)
|
24
|
+
generator.add_text(("="*generator.parse_level)+" "+name)
|
25
|
+
generator.parse_cycle(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_rb_html(generator)
|
29
|
+
htag="h#{generator.parse_level+1}"
|
30
|
+
anchor=generator.add_toc_entry(name)
|
31
|
+
generator.add_raw "<div class='section'><#{htag}>#{name}</#{htag}><a name='#{anchor}'></a>"
|
32
|
+
generator.parse_cycle(self)
|
33
|
+
generator.add_raw "</div>"
|
34
|
+
end
|
35
|
+
|
36
|
+
def add(*elements)
|
37
|
+
elements.each do |element|
|
38
|
+
if element.is_a? ReportBuilder::Section
|
39
|
+
element.parent=self
|
40
|
+
end
|
41
|
+
if element.respond_to?(:to_reportbuilder)
|
42
|
+
@elements.push(element.to_reportbuilder)
|
43
|
+
else
|
44
|
+
@elements.push(element)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class ReportBuilder
|
2
|
+
class Table
|
3
|
+
class HtmlGenerator < ElementGenerator
|
4
|
+
def generate()
|
5
|
+
t=@element
|
6
|
+
anchor=@generator.add_table_entry(t.name)
|
7
|
+
out="<a name='#{anchor}'></a><table>"
|
8
|
+
@rowspans=[]
|
9
|
+
if t.header.size>0
|
10
|
+
out+="<thead>"+parse_row(t,t.header,"th")+"</thead>\n"
|
11
|
+
end
|
12
|
+
out+="<tbody>\n"
|
13
|
+
next_class=""
|
14
|
+
t.rows.each{|row|
|
15
|
+
if row==:hr
|
16
|
+
next_class="top"
|
17
|
+
else
|
18
|
+
class_tag=(next_class=="")?"":" class ='#{next_class}' "
|
19
|
+
out+="<tr#{class_tag}>"+parse_row(t,row)+"</tr>\n"
|
20
|
+
next_class=""
|
21
|
+
end
|
22
|
+
}
|
23
|
+
out+="</tbody>\n</table>\n"
|
24
|
+
@generator.add_raw(out)
|
25
|
+
end
|
26
|
+
def parse_row(t,row,tag="td")
|
27
|
+
row_ary=[]
|
28
|
+
colspan_i=0
|
29
|
+
row.each_index do |i|
|
30
|
+
if !@rowspans[i].nil? and @rowspans[i]>0
|
31
|
+
@rowspans[i]-=1
|
32
|
+
elsif colspan_i>0
|
33
|
+
colspan_i-=1
|
34
|
+
elsif row[i].is_a? Table::Colspan
|
35
|
+
row_ary.push(sprintf("<%s colspan=\"%d\">%s</%s>",tag, row[i].cols, row[i].data,tag))
|
36
|
+
colspan_i=row[i].cols-1
|
37
|
+
elsif row[i].nil?
|
38
|
+
row_ary.push("<#{tag}></#{tag}>")
|
39
|
+
elsif row[i].is_a? Table::Rowspan
|
40
|
+
row_ary.push(sprintf("<%s rowspan=\"%d\">%s</%s>", tag, row[i].rows, row[i].data, tag))
|
41
|
+
@rowspans[i]=row[i].rows-1
|
42
|
+
else
|
43
|
+
row_ary.push("<#{tag}>#{row[i]}</#{tag}>")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
row_ary.join("")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class ReportBuilder
|
2
|
+
class Table
|
3
|
+
class TextGenerator < ElementGenerator
|
4
|
+
|
5
|
+
def generate()
|
6
|
+
t=@element
|
7
|
+
t.calculate_widths
|
8
|
+
total_width=t.total_width
|
9
|
+
out=""
|
10
|
+
if t.header.size>0
|
11
|
+
out+=parse_hr(total_width)+"\n"
|
12
|
+
out+=parse_row(t,t.header)+"\n"
|
13
|
+
out+=parse_hr(total_width)+"\n"
|
14
|
+
end
|
15
|
+
t.rows.each do |row|
|
16
|
+
if row==:hr
|
17
|
+
out+=parse_hr(total_width)+"\n"
|
18
|
+
else
|
19
|
+
out+=parse_row(t,row)+"\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
out+=parse_hr(total_width)+"\n"
|
23
|
+
@generator.add_text(out)
|
24
|
+
end
|
25
|
+
# Parse a row
|
26
|
+
def parse_row(t,row)
|
27
|
+
row_ary=[]
|
28
|
+
colspan_i=0
|
29
|
+
row.each_index do |i|
|
30
|
+
if colspan_i>0
|
31
|
+
colspan_i-=1
|
32
|
+
elsif row[i].is_a? ReportBuilder::Table::Colspan
|
33
|
+
size = (i...(i+row[i].cols)).inject(0) {|a,v| a+t.max_cols[v]+3}
|
34
|
+
size-=3
|
35
|
+
row_ary.push(row[i].data.to_s+" "*(size - row[i].data.size))
|
36
|
+
colspan_i=row[i].cols-1
|
37
|
+
elsif row[i].nil?
|
38
|
+
row_ary.push(" "*t.max_cols[i])
|
39
|
+
else
|
40
|
+
size=row[i].to_s.size
|
41
|
+
#puts sprintf("%i : %s (%d-%d)",i,row[i].to_s,@max_cols[i], size)
|
42
|
+
row_ary.push(row[i].to_s+" "*(t.max_cols[i] - size))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
"| "+row_ary.join(" | ")+" |"
|
46
|
+
end
|
47
|
+
# Parse a horizontal rule
|
48
|
+
def parse_hr(l)
|
49
|
+
"-"*l
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
class ReportBuilder
|
2
|
+
# Creates a table.
|
3
|
+
# Use:
|
4
|
+
# table=ReportBuilder::Table.new(:header =>["id","city","name","code1","code2"])
|
5
|
+
# table.add_row([1, Table.rowspan("New York",3), "Ringo", Table.colspan("no code",2),nil])
|
6
|
+
# table.add_row([2, nil,"John", "ab-1","ab-2"])
|
7
|
+
# table.add_row([3, nil,"Paul", "ab-3"])
|
8
|
+
# table.add_hr
|
9
|
+
# table.add_row([4, "London","George", Table.colspan("ab-4",2),nil])
|
10
|
+
# puts table
|
11
|
+
# ==>
|
12
|
+
# -----------------------------------------
|
13
|
+
# | id | city | name | code1 | code2 |
|
14
|
+
# -----------------------------------------
|
15
|
+
# | 1 | New York | Ringo | no code |
|
16
|
+
# | 2 | | John | ab-1 | ab-2 |
|
17
|
+
# | 3 | | Paul | ab-3 | |
|
18
|
+
# -----------------------------------------
|
19
|
+
# | 4 | London |George | ab-4 |
|
20
|
+
# -----------------------------------------
|
21
|
+
class Table
|
22
|
+
@@n=1
|
23
|
+
# :nodoc:
|
24
|
+
DEFAULT_OPTIONS={
|
25
|
+
:header => [],
|
26
|
+
:name => nil
|
27
|
+
}
|
28
|
+
# Array of headers
|
29
|
+
attr_accessor :header, :name
|
30
|
+
# Size for each column
|
31
|
+
attr_reader :max_cols
|
32
|
+
# Array of rows
|
33
|
+
attr_reader :rows
|
34
|
+
# Create a new table.
|
35
|
+
# Options: :name, :header
|
36
|
+
# Use:
|
37
|
+
# table=ReportBuilder::Table.new(:header =>["var1","var2"])
|
38
|
+
def initialize(opts=Hash.new)
|
39
|
+
opts=DEFAULT_OPTIONS.merge opts
|
40
|
+
if opts[:name].nil?
|
41
|
+
@name= "Table #{@@n}"
|
42
|
+
@@n+=1
|
43
|
+
else
|
44
|
+
@name=opts[:name]
|
45
|
+
end
|
46
|
+
@header=opts[:header]
|
47
|
+
@rows=[]
|
48
|
+
@max_cols=[]
|
49
|
+
end
|
50
|
+
# Adds a row
|
51
|
+
# table.add_row(%w{1 2})
|
52
|
+
def add_row(row)
|
53
|
+
@rows.push(row)
|
54
|
+
end
|
55
|
+
# Adds a horizontal rule
|
56
|
+
# table.add_hr
|
57
|
+
def add_hr
|
58
|
+
@rows.push(:hr)
|
59
|
+
end
|
60
|
+
# Adds a rowspan on a cell
|
61
|
+
# table.add_row(["a",table.rowspan("b",2)])
|
62
|
+
def rowspan(data,n)
|
63
|
+
Rowspan.new(data,n)
|
64
|
+
end
|
65
|
+
# Adds a colspan on a cell
|
66
|
+
# table.add_row(["a",table.colspan("b",2)])
|
67
|
+
|
68
|
+
def colspan(data,n)
|
69
|
+
Colspan.new(data,n)
|
70
|
+
end
|
71
|
+
def calculate_widths # :nodoc:
|
72
|
+
@max_cols=[]
|
73
|
+
rows_cal=[header]+@rows
|
74
|
+
rows_cal.each{|row|
|
75
|
+
next if row==:hr
|
76
|
+
row.each_index{|i|
|
77
|
+
if row[i].nil?
|
78
|
+
next
|
79
|
+
elsif row[i].is_a? Colspan
|
80
|
+
size_total=row[i].data.to_s.size
|
81
|
+
size_per_column=(size_total / row[i].cols)+1
|
82
|
+
for mi in i...i+row[i].cols
|
83
|
+
@max_cols[mi] = size_per_column if @max_cols[mi].nil? or @max_cols[mi]<size_per_column
|
84
|
+
end
|
85
|
+
elsif row[i].is_a? Rowspan
|
86
|
+
size=row[i].data.to_s.size
|
87
|
+
@max_cols[i]= size if @max_cols[i].nil? or @max_cols[i] < size
|
88
|
+
else
|
89
|
+
|
90
|
+
size=row[i].to_s.size
|
91
|
+
@max_cols[i]= size if @max_cols[i].nil? or @max_cols[i] < size
|
92
|
+
end
|
93
|
+
}
|
94
|
+
}
|
95
|
+
end
|
96
|
+
def to_rb_text(generator)
|
97
|
+
require 'reportbuilder/table/textgenerator'
|
98
|
+
table_generator=ReportBuilder::Table::TextGenerator.new( generator, self)
|
99
|
+
table_generator.generate
|
100
|
+
end
|
101
|
+
def to_rb_html(generator)
|
102
|
+
require 'reportbuilder/table/htmlgenerator'
|
103
|
+
table_generator=ReportBuilder::Table::HtmlGenerator.new(generator, self)
|
104
|
+
table_generator.generate
|
105
|
+
end
|
106
|
+
|
107
|
+
def total_width # :nodoc:
|
108
|
+
@max_cols.inject(0){|a,v| a+(v+3)}+1
|
109
|
+
end
|
110
|
+
######################
|
111
|
+
# INTERNAL CLASSES #
|
112
|
+
######################
|
113
|
+
|
114
|
+
class Rowspan # :nodoc:
|
115
|
+
attr_accessor :data, :rows
|
116
|
+
def initialize(data,rows)
|
117
|
+
@data=data
|
118
|
+
@rows=rows
|
119
|
+
end
|
120
|
+
def to_s
|
121
|
+
@data.to_s
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class Colspan # :nodoc:
|
126
|
+
attr_accessor :data, :cols
|
127
|
+
def initialize(data,cols)
|
128
|
+
@data=data
|
129
|
+
@cols=cols
|
130
|
+
end
|
131
|
+
def to_s
|
132
|
+
@data.to_s
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'reportbuilder/table'
|
2
|
+
require 'reportbuilder/section'
|
3
|
+
require 'reportbuilder/generator'
|
4
|
+
|
5
|
+
class ReportBuilder
|
6
|
+
attr_reader :elements
|
7
|
+
attr_reader :name
|
8
|
+
attr_reader :dir
|
9
|
+
VERSION = '0.1.0'
|
10
|
+
# Create a new Report
|
11
|
+
def initialize(name=nil,dir=nil)
|
12
|
+
name||="Report "+Time.new.to_s
|
13
|
+
dir||=Dir.pwd
|
14
|
+
@dir=dir
|
15
|
+
@name=name
|
16
|
+
@elements=Array.new
|
17
|
+
end
|
18
|
+
# Add an element to the report.
|
19
|
+
# If parameters is an object which respond to :to_reportbuilder,
|
20
|
+
# this method will called.
|
21
|
+
# Otherwise, the element itself will be added
|
22
|
+
def add(*elements)
|
23
|
+
elements.each do |element|
|
24
|
+
if element.respond_to?(:to_reportbuilder)
|
25
|
+
@elements.push(element.to_reportbuilder)
|
26
|
+
else
|
27
|
+
@elements.push(element)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
# Returns a Section
|
32
|
+
def section(name)
|
33
|
+
Section.new(name)
|
34
|
+
end
|
35
|
+
# Returns a Table
|
36
|
+
def table(h=[])
|
37
|
+
Table.new(h)
|
38
|
+
end
|
39
|
+
# Returns an Html output
|
40
|
+
def to_html
|
41
|
+
gen=Generator::Html.new(self)
|
42
|
+
gen.parse
|
43
|
+
gen.out
|
44
|
+
end
|
45
|
+
def save_html(file)
|
46
|
+
gen=Generator::Html.new(self)
|
47
|
+
gen.parse
|
48
|
+
File.open(@dir+"/"+file,"wb") {|fp|
|
49
|
+
fp.write(gen.out)
|
50
|
+
}
|
51
|
+
end
|
52
|
+
# Returns a Text output
|
53
|
+
def to_s
|
54
|
+
gen=Generator::Text.new(self)
|
55
|
+
gen.parse
|
56
|
+
gen.out
|
57
|
+
end
|
58
|
+
end
|
data/test/test_html.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
3
|
+
require "reportbuilder"
|
4
|
+
require 'fileutils'
|
5
|
+
require 'tmpdir'
|
6
|
+
class TestReportbuilderHtml < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@tmpdir=Dir::mktmpdir
|
9
|
+
@rp=ReportBuilder.new("Test Html", @tmpdir)
|
10
|
+
@datadir=File.dirname(__FILE__)+"/../data"
|
11
|
+
end
|
12
|
+
def teardown
|
13
|
+
FileUtils.remove_entry_secure @tmpdir
|
14
|
+
end
|
15
|
+
def test_include_js
|
16
|
+
mock_element = ""
|
17
|
+
eval(" class << mock_element
|
18
|
+
def to_rb_html(generator)
|
19
|
+
generator.add_js('"+@datadir+"/reportbuilder.js')
|
20
|
+
end
|
21
|
+
end ")
|
22
|
+
@rp.add(mock_element)
|
23
|
+
assert_match(/script.+js\/reportbuilder.js/, @rp.to_html)
|
24
|
+
assert(File.exists? @tmpdir+"/js/reportbuilder.js")
|
25
|
+
end
|
26
|
+
def test_save_html
|
27
|
+
exp=@rp.to_html
|
28
|
+
@rp.save_html("test.html")
|
29
|
+
obt=""
|
30
|
+
File.open(@tmpdir+"/test.html","r") {|fp|
|
31
|
+
obt=fp.readlines(nil)[0]
|
32
|
+
}
|
33
|
+
assert_equal(exp,obt)
|
34
|
+
end
|
35
|
+
def test_include_css
|
36
|
+
mock_element = ""
|
37
|
+
eval(" class << mock_element
|
38
|
+
def to_rb_html(generator)
|
39
|
+
generator.add_css('"+@datadir+"/reportbuilder.css')
|
40
|
+
end
|
41
|
+
end ")
|
42
|
+
@rp.add(mock_element)
|
43
|
+
assert_match(/link rel='stylesheet'.+css\/reportbuilder.css/, @rp.to_html)
|
44
|
+
assert(File.exists? @tmpdir+"/css/reportbuilder.css")
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
3
|
+
require "reportbuilder"
|
4
|
+
|
5
|
+
class TestReportbuilder < Test::Unit::TestCase
|
6
|
+
# adding basic object
|
7
|
+
def test_basic_generators
|
8
|
+
# basic_classes = Array,String,Integer, Float,Time,Hash
|
9
|
+
ary=[1,2,3]
|
10
|
+
str="1,2,3"
|
11
|
+
int=1
|
12
|
+
flt=1.0
|
13
|
+
rat=1.quo(2)
|
14
|
+
tim=Time.new
|
15
|
+
has={'a'=>1,'b'=>2}
|
16
|
+
rb=ReportBuilder.new
|
17
|
+
rb.add(ary,str,int,flt,rat,tim,has)
|
18
|
+
assert_nothing_raised do
|
19
|
+
rb.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
3
|
+
require "reportbuilder"
|
4
|
+
|
5
|
+
class TestReportbuilderSection < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@rp=ReportBuilder.new("Test Report")
|
8
|
+
s1=@rp.section("Section 1")
|
9
|
+
@rp.add s1
|
10
|
+
s1.add("Texto 1")
|
11
|
+
s1.add(2)
|
12
|
+
s11=@rp.section("Section 1.1")
|
13
|
+
s1.add s11
|
14
|
+
s1.add("Texto 1.1")
|
15
|
+
s2=@rp.section("Section 2")
|
16
|
+
@rp.add s2
|
17
|
+
end
|
18
|
+
def test_section_text
|
19
|
+
expected= <<-HERE
|
20
|
+
Report: Test Report
|
21
|
+
= Section 1
|
22
|
+
Texto 1
|
23
|
+
2
|
24
|
+
== Section 1.1
|
25
|
+
Texto 1.1
|
26
|
+
= Section 2
|
27
|
+
|
28
|
+
HERE
|
29
|
+
assert_equal(expected, @rp.to_s)
|
30
|
+
end
|
31
|
+
def test_section_html
|
32
|
+
expected= <<-HERE
|
33
|
+
<html><head><title>Test Report</title></head><body>
|
34
|
+
<h1>Test Report</h1><div class='toc'><div class='title'>List of contents</div></div><ul>
|
35
|
+
<li><a href='#toc_1'>Section 1</a></li>
|
36
|
+
<ul>
|
37
|
+
<li><a href='#toc_2'>Section 1.1</a></li>
|
38
|
+
</ul>
|
39
|
+
<li><a href='#toc_3'>Section 2</a></li>
|
40
|
+
</ul>
|
41
|
+
</div>
|
42
|
+
<div class='section'><h2>Section 1</h2><a name='toc_1'></a>
|
43
|
+
<pre>Texto 1</pre>
|
44
|
+
<pre>2</pre>
|
45
|
+
<div class='section'><h3>Section 1.1</h3><a name='toc_2'></a>
|
46
|
+
</div>
|
47
|
+
<pre>Texto 1.1</pre>
|
48
|
+
</div>
|
49
|
+
<div class='section'><h2>Section 2</h2><a name='toc_3'></a>
|
50
|
+
</div>
|
51
|
+
</body></html>
|
52
|
+
HERE
|
53
|
+
assert_equal(expected.gsub(/\s/,""), @rp.to_html.gsub(/\s/,""))
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/test/test_table.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
3
|
+
require "reportbuilder"
|
4
|
+
require "reportbuilder/table/htmlgenerator"
|
5
|
+
require "reportbuilder/table/textgenerator"
|
6
|
+
|
7
|
+
class TestReportbuilderTable < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
table=ReportBuilder::Table.new(:header=>%w{a bb ccc dddd eeee fff gggg hh i})
|
11
|
+
table.add_row(["a","b","c","d","e","f","g","h","i"])
|
12
|
+
table.add_row([table.colspan("a",2),nil,"c",table.rowspan("d",2),"e","f","g","h","i"])
|
13
|
+
table.add_row([table.colspan("a",3),nil,nil,nil,"e","f","g","h","i"])
|
14
|
+
table.add_row([table.colspan("a",4),nil,nil,nil,"e","f","g","h","i"])
|
15
|
+
table.add_row([table.colspan("a",5),nil,nil,nil,nil,table.colspan("f",3),nil,nil,"i"])
|
16
|
+
table.add_row([table.colspan("a",6),nil,nil,nil,nil,nil,"g","h","i"])
|
17
|
+
@table=table
|
18
|
+
|
19
|
+
@mock_generator = ""
|
20
|
+
class << @mock_generator
|
21
|
+
def add_raw(t)
|
22
|
+
replace(t)
|
23
|
+
end
|
24
|
+
def add_text(t)
|
25
|
+
replace(t)
|
26
|
+
end
|
27
|
+
def add_table_entry(t)
|
28
|
+
"MOCK"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
def test_table_text
|
34
|
+
|
35
|
+
tg=ReportBuilder::Table::TextGenerator.new(@mock_generator,@table)
|
36
|
+
tg.generate
|
37
|
+
expected= <<HEREDOC
|
38
|
+
----------------------------------------------------
|
39
|
+
| a | bb | ccc | dddd | eeee | fff | gggg | hh | i |
|
40
|
+
----------------------------------------------------
|
41
|
+
| a | b | c | d | e | f | g | h | i |
|
42
|
+
| a | c | d | e | f | g | h | i |
|
43
|
+
| a | | e | f | g | h | i |
|
44
|
+
| a | e | f | g | h | i |
|
45
|
+
| a | f | i |
|
46
|
+
| a | g | h | i |
|
47
|
+
----------------------------------------------------
|
48
|
+
HEREDOC
|
49
|
+
|
50
|
+
assert_equal(expected,@mock_generator)
|
51
|
+
|
52
|
+
end
|
53
|
+
def test_table_html
|
54
|
+
|
55
|
+
tg=ReportBuilder::Table::HtmlGenerator.new(@mock_generator,@table)
|
56
|
+
tg.generate
|
57
|
+
expected= <<HEREDOC
|
58
|
+
<a name='MOCK'> </a>
|
59
|
+
<table>
|
60
|
+
<thead>
|
61
|
+
<th>a</th><th>bb</th><th>ccc</th>
|
62
|
+
<th>dddd</th><th>eeee</th>
|
63
|
+
<th>fff</th><th>gggg</th><th>hh</th><th>i</th>
|
64
|
+
</thead>
|
65
|
+
<tbody>
|
66
|
+
<tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td>
|
67
|
+
<td>f</td><td>g</td><td>h</td><td>i</td></tr>
|
68
|
+
|
69
|
+
<tr><td colspan="2">a</td><td>c</td><td rowspan="2">d</td><td>e</td>
|
70
|
+
<td>f</td><td>g</td><td>h</td><td>i</td></tr>
|
71
|
+
|
72
|
+
<tr><td colspan="3">a</td><td>e</td>
|
73
|
+
<td>f</td><td>g</td><td>h</td><td>i</td></tr>
|
74
|
+
|
75
|
+
<tr><td colspan="4">a</td><td>e</td>
|
76
|
+
<td>f</td><td>g</td><td>h</td><td>i</td></tr>
|
77
|
+
|
78
|
+
<tr><td colspan="5">a</td><td colspan="3">f</td><td>i</td></tr>
|
79
|
+
|
80
|
+
<tr><td colspan="6">a</td><td>g</td><td>h</td><td>i</td></tr>
|
81
|
+
</tbody>
|
82
|
+
</table>
|
83
|
+
HEREDOC
|
84
|
+
|
85
|
+
assert_equal(expected.gsub(/\s/m,""), @mock_generator.gsub(/\s/m,""))
|
86
|
+
end
|
87
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: reportbuilder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Claudio Bustos
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-08 00:00:00 -03:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.3.3
|
24
|
+
version:
|
25
|
+
description: Report Abstract Interface. Creates text, html and pdf output, based on a common framework
|
26
|
+
email:
|
27
|
+
- clbustos_at_gmail.com
|
28
|
+
executables:
|
29
|
+
- reportbuilder
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- History.txt
|
34
|
+
- Manifest.txt
|
35
|
+
- README.txt
|
36
|
+
files:
|
37
|
+
- History.txt
|
38
|
+
- Manifest.txt
|
39
|
+
- README.txt
|
40
|
+
- Rakefile
|
41
|
+
- bin/reportbuilder
|
42
|
+
- data/reportbuilder.css
|
43
|
+
- data/reportbuilder.js
|
44
|
+
- lib/reportbuilder/generator.rb
|
45
|
+
- lib/reportbuilder/generator/html.rb
|
46
|
+
- lib/reportbuilder/generator/text.rb
|
47
|
+
- lib/reportbuilder.rb
|
48
|
+
- lib/reportbuilder/section.rb
|
49
|
+
- lib/reportbuilder/table.rb
|
50
|
+
- lib/reportbuilder/table/htmlgenerator.rb
|
51
|
+
- lib/reportbuilder/table/textgenerator.rb
|
52
|
+
- test/test_html.rb
|
53
|
+
- test/test_reportbuilder.rb
|
54
|
+
- test/test_section.rb
|
55
|
+
- test/test_table.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://rubyforge.org/projects/ruby-statsample/
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options:
|
62
|
+
- --main
|
63
|
+
- README.txt
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project: ruby-statsample
|
81
|
+
rubygems_version: 1.3.5
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: Report Abstract Interface
|
85
|
+
test_files:
|
86
|
+
- test/test_section.rb
|
87
|
+
- test/test_table.rb
|
88
|
+
- test/test_html.rb
|
89
|
+
- test/test_reportbuilder.rb
|