reportbuilder 0.1.0
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/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
|