reportbuilder 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,10 @@
1
+ === 1.2.0 / 2010-03-28
2
+ *ReporBuilder::Table
3
+ * Colspans works as expected on Html and Text. On Rtf the cells doesn't merge, because ruby-rtf doesn't support it.
4
+ * Better tests for Html and Text.
5
+ * Classes related to Generator renamed to Builder, because these correspond to Builder pattern
6
+ * Flexible codes for formats. You could use :text or :txt as :format for ReportBuilder#generate. See ReportBuilder::Builder.code for more information
7
+
1
8
  === 1.1.1 / 2010-03-24
2
9
  * Test suite replaces Test::Unit for Test::MiniUnit and Hpricot for Nokogiri
3
10
  * Bug fix: rtf generator doesn't accept a ReportBuilder::Image object
data/Manifest.txt CHANGED
@@ -12,16 +12,16 @@ examples/images.rb
12
12
  examples/test.rtf
13
13
  examples/using_a_block.rb
14
14
  lib/reportbuilder.rb
15
- lib/reportbuilder/generator.rb
16
- lib/reportbuilder/generator/html.rb
17
- lib/reportbuilder/generator/rtf.rb
18
- lib/reportbuilder/generator/text.rb
15
+ lib/reportbuilder/builder.rb
16
+ lib/reportbuilder/builder/html.rb
17
+ lib/reportbuilder/builder/rtf.rb
18
+ lib/reportbuilder/builder/text.rb
19
19
  lib/reportbuilder/image.rb
20
20
  lib/reportbuilder/section.rb
21
21
  lib/reportbuilder/table.rb
22
- lib/reportbuilder/table/htmlgenerator.rb
23
- lib/reportbuilder/table/rtfgenerator.rb
24
- lib/reportbuilder/table/textgenerator.rb
22
+ lib/reportbuilder/table/htmlbuilder.rb
23
+ lib/reportbuilder/table/rtfbuilder.rb
24
+ lib/reportbuilder/table/textbuilder.rb
25
25
  test/test_html.rb
26
26
  test/test_image.rb
27
27
  test/test_reportbuilder.rb
data/Rakefile CHANGED
@@ -12,8 +12,15 @@ Hoe.spec 'reportbuilder' do
12
12
  self.rubyforge_name = 'ruby-statsample'
13
13
  self.developer('Claudio Bustos', 'clbustos_at_gmail.com')
14
14
  self.url = "http://ruby-statsample.rubyforge.org/reportbuilder/"
15
- self.extra_deps << ["clbustos-rtf","~>0.2.1"]
16
- self.extra_dev_deps << ["hpricot", "~>0.8"]
15
+ self.extra_deps << ["clbustos-rtf","~>0.2.1"] << ['text-table', "~>1.2"]
16
+ self.extra_dev_deps << ["nokogiri", "~>1.4"]
17
+ end
18
+
19
+ task :release => [:tag] do
20
+ end
21
+
22
+ task :tag do
23
+ sh %(svn cp https://ruby-statsample.googlecode.com/svn/reportbuilder/trunk https://ruby-statsample.googlecode.com/svn/reportbuilder/tags/v#{ReportBuilder::VERSION} -m "ReportBuilder #{ReportBuilder::VERSION} tagged")
17
24
  end
18
25
 
19
26
  # vim: syntax=ruby
data/lib/reportbuilder.rb CHANGED
@@ -1,9 +1,11 @@
1
+ require 'reportbuilder/builder'
1
2
  require 'reportbuilder/table'
2
3
  require 'reportbuilder/section'
3
- require 'reportbuilder/generator'
4
4
  require 'reportbuilder/image'
5
+
5
6
  # = Report Abstract Interface.
6
- # Creates text and html output, based on a common framework.
7
+ # Creates text, html and rtf output, based on a common framework.
8
+ #
7
9
  # == Use
8
10
  #
9
11
  #
@@ -26,7 +28,7 @@ require 'reportbuilder/image'
26
28
  # rb.name="Html output"
27
29
  # puts rb.to_html
28
30
  #
29
- # * Using a block, you can control directly the generator
31
+ # * Using a block, you can control directly the builder
30
32
  #
31
33
  # require "reportbuilder"
32
34
  # rb=ReportBuilder.new do
@@ -50,7 +52,15 @@ class ReportBuilder
50
52
  attr_accessor :name
51
53
  # Doesn't print a title if set to true
52
54
  attr_accessor :no_title
53
- VERSION = '1.1.1'
55
+ # ReportBuilder version
56
+ VERSION = '1.2.0'
57
+
58
+ FormatNotFound=Class.new(Exception)
59
+ # Available formats
60
+ def self.builder_for(format)
61
+ format=format.to_s.downcase
62
+ Builder.inherited_classes.find {|m| m.code.include? format}
63
+ end
54
64
  # Generates and optionally save the report on one function
55
65
  def self.generate(options=Hash.new, &block)
56
66
  options[:filename]||=nil
@@ -58,18 +68,18 @@ class ReportBuilder
58
68
 
59
69
  if options[:filename] and options[:filename]=~/\.(\w+?)$/
60
70
  options[:format]=$1
61
- options[:format]="text" if options[:format]=="txt"
62
71
  end
63
72
  file=options.delete(:filename)
64
- format=options.delete(:format).to_s
65
- format[0]=format[0,1].upcase
73
+ format=options.delete(:format)
66
74
  rb=ReportBuilder.new(options)
67
-
68
75
  rb.add(block)
69
-
70
- generator=Generator.const_get(format.to_sym).new(rb, options)
71
- generator.parse
72
- out=generator.out
76
+ begin
77
+ builder=builder_for(format).new(rb, options)
78
+ rescue NameError => e
79
+ raise FormatNotFound.new(e)
80
+ end
81
+ builder.parse
82
+ out=builder.out
73
83
  unless file.nil?
74
84
  File.open(file,"wb") do |fp|
75
85
  fp.write out
@@ -96,19 +106,19 @@ class ReportBuilder
96
106
  end
97
107
  # Returns an Html output
98
108
  def to_html()
99
- gen = Generator::Html.new(self,@options)
109
+ gen = Builder::Html.new(self,@options)
100
110
  gen.parse
101
111
  gen.out
102
112
  end
103
113
  # Returns a RTF output
104
114
  def to_rtf()
105
- gen = Generator::Rtf.new(self, @options)
115
+ gen = Builder::Rtf.new(self, @options)
106
116
  gen.parse
107
117
  gen.out
108
118
  end
109
119
  # Save a rtf file
110
120
  def save_rtf(filename)
111
- gen = Generator::Rtf.new(self,@options)
121
+ gen = Builder::Rtf.new(self,@options)
112
122
  gen.parse
113
123
  gen.save(filename)
114
124
  end
@@ -116,13 +126,13 @@ class ReportBuilder
116
126
  def save_html(file)
117
127
  options=@options.dup
118
128
  options[:directory]=File.dirname(file)
119
- gen=Generator::Html.new(self, options)
129
+ gen=Builder::Html.new(self, options)
120
130
  gen.parse
121
131
  gen.save(file)
122
132
  end
123
133
  # Returns a Text output
124
134
  def to_text()
125
- gen=Generator::Text.new(self, @options)
135
+ gen=Builder::Text.new(self, @options)
126
136
  gen.parse
127
137
  gen.out
128
138
  end
@@ -1,15 +1,27 @@
1
1
  class ReportBuilder
2
- # Abstract class for generators.
3
- # A generator is a class which control the output for a ReportBuilder object
2
+ # Abstract Builder.
3
+ # A builder is a class which control the output for a ReportBuilder object
4
4
  # Every object which have a #report_building() method could be
5
5
  # parsed with #parse_element method.
6
- class Generator
6
+ class Builder
7
7
  # Level of heading. See ReportBuilder::Section for using it.
8
8
  attr_reader :parse_level
9
- # Options for Generator. Passed by ReportBuilder class on creation
9
+ # Options for Builder. Passed by ReportBuilder class on creation
10
10
  attr_reader :options
11
11
  # Entries for Table of Contents
12
12
  attr_reader :toc
13
+ # Array of string with format names for the Builder.
14
+ # For example, Html builder returns %w{html htm} and
15
+ # Text builde returns %w{text txt}
16
+ def self.code
17
+ # raise "Implement this"
18
+ end
19
+ def self.inherited_classes
20
+ @@inherited_classes||=Array.new
21
+ end
22
+ def self.inherited(subclass)
23
+ inherited_classes << subclass
24
+ end
13
25
  def initialize(builder, options)
14
26
  @builder=builder
15
27
  @parse_level=0
@@ -24,7 +36,7 @@ class ReportBuilder
24
36
  def parse
25
37
  parse_cycle(@builder)
26
38
  end
27
- # Save the output of generator to a file
39
+ # Save the output of builder to a file
28
40
  def save(filename)
29
41
  File.open(filename, "wb") do |fp|
30
42
  fp.write(out)
@@ -35,7 +47,7 @@ class ReportBuilder
35
47
  Hash.new
36
48
  end
37
49
 
38
- # Parse each element of the container
50
+ # Parse each #elements of the container
39
51
  def parse_cycle(container)
40
52
  @parse_level+=1
41
53
  container.elements.each do |element|
@@ -46,14 +58,15 @@ class ReportBuilder
46
58
 
47
59
  # Parse one object, using this workflow
48
60
  # * If is a block, evaluate it
49
- # * Use #report_building_FORMAT
61
+ # * Use #report_building_CODE, where CODE is one of the codes defined by #code
50
62
  # * Use #report_building
51
63
  # * Use #to_s
52
64
  def parse_element(element)
53
- method=("report_building_" + self.class::PREFIX).intern
65
+ methods=self.class.code.map {|m| ("report_building_"+m).intern}
66
+
54
67
  if element.is_a? Proc
55
68
  element.arity<1 ? instance_eval(&element) : element.call(self)
56
- elsif element.respond_to? method
69
+ elsif method=methods.find {|m| element.respond_to? m}
57
70
  element.send(method, self)
58
71
  elsif element.respond_to? :report_building
59
72
  element.send(:report_building, self)
@@ -78,7 +91,7 @@ class ReportBuilder
78
91
  def text(t)
79
92
  raise "Implement this"
80
93
  end
81
- # Add html code. Only parsed with generator which understand html
94
+ # Add html code. Only parsed with builder which understand html
82
95
  def html(t)
83
96
  raise "Implement this"
84
97
  end
@@ -105,15 +118,15 @@ class ReportBuilder
105
118
  end
106
119
  end
107
120
 
108
- class ElementGenerator
109
- def initialize(generator,element)
121
+ class ElementBuilder
122
+ def initialize(builder,element)
110
123
  @element=element
111
- @generator=generator
124
+ @builder=builder
112
125
  end
113
126
  end
114
127
  end
115
128
 
116
- require 'reportbuilder/generator/text'
117
- require 'reportbuilder/generator/html'
118
- require 'reportbuilder/generator/rtf'
129
+ require 'reportbuilder/builder/text'
130
+ require 'reportbuilder/builder/html'
131
+ require 'reportbuilder/builder/rtf'
119
132
 
@@ -1,8 +1,7 @@
1
1
  require 'fileutils'
2
2
  class ReportBuilder
3
- class Generator
4
- class Html < Generator
5
- PREFIX="html"
3
+ class Builder
4
+ class Html < Builder
6
5
  attr_reader :directory
7
6
  def initialize(builder, options)
8
7
  super
@@ -11,6 +10,11 @@ class ReportBuilder
11
10
  @headers=[]
12
11
  @footers=[]
13
12
  end
13
+
14
+ def self.code
15
+ %w{html htm}
16
+ end
17
+
14
18
  def default_options
15
19
  {:directory => Dir.pwd}
16
20
  end
@@ -1,13 +1,11 @@
1
- gem 'clbustos-rtf'
2
1
  require 'rtf'
3
-
2
+ require 'pp'
4
3
  class ReportBuilder
5
- class Generator
6
- # Rtf Generator.
4
+ class Builder
5
+ # Rtf Builder.
7
6
  # Based on ruby-rtf (http://ruby-rtf.rubyforge.org/)
8
7
  #
9
- class Rtf < Generator
10
- PREFIX="rtf"
8
+ class Rtf < Builder
11
9
  # RTF::Document object.
12
10
  # See http://ruby-rtf.rubyforge.org/ for documentation
13
11
  attr_accessor :rtf
@@ -34,6 +32,12 @@ class ReportBuilder
34
32
  h[k]={:cs=>cs, :ps=>ps}
35
33
  }
36
34
  end
35
+
36
+ def self.code
37
+ %w{rtf}
38
+ end
39
+
40
+
37
41
  def default_options
38
42
 
39
43
  {
@@ -1,13 +1,17 @@
1
1
  class ReportBuilder
2
- class Generator
3
- class Text < Generator
4
- PREFIX="text"
2
+ class Builder
3
+ class Text < Builder
5
4
  attr_reader :toc
6
5
  attr_reader :out
7
6
  def initialize(builder, options)
8
7
  super
9
8
  @out=""
10
9
  end
10
+
11
+ def self.code
12
+ %w{text txt}
13
+ end
14
+
11
15
  def parse
12
16
  @out="#{@builder.name}\n" unless @builder.no_title
13
17
  parse_cycle(@builder)
@@ -21,7 +21,7 @@ class ReportBuilder::Image
21
21
  @filename=filename
22
22
  end
23
23
  # Based on http://rubyquiz.com/quiz50.html
24
- def report_building_text(generator)
24
+ def report_building_text(builder)
25
25
  require 'RMagick'
26
26
 
27
27
 
@@ -69,14 +69,14 @@ class ReportBuilder::Image
69
69
  end
70
70
  end
71
71
  out+= border
72
- generator.preformatted(out)
72
+ builder.preformatted(out)
73
73
  end
74
- def report_building_rtf(generator)
75
- raise "Not implemented on RTF::Document. Use gem install thecrisoshow-ruby-rtf for support" unless generator.rtf.respond_to? :image
76
- generator.rtf.image(@filename)
74
+ def report_building_rtf(builder)
75
+ raise "Not implemented on RTF::Document. Use gem install thecrisoshow-ruby-rtf for support" unless builder.rtf.respond_to? :image
76
+ builder.rtf.image(@filename)
77
77
  end
78
- def report_building_html(generator)
79
- basedir=generator.directory+"/images"
78
+ def report_building_html(builder)
79
+ basedir=builder.directory+"/images"
80
80
  out=basedir+"/"+File.basename(@filename)
81
81
  if(File.exists? @filename)
82
82
  if !File.exists? out
@@ -84,6 +84,6 @@ class ReportBuilder::Image
84
84
  FileUtils.cp @filename, out
85
85
  end
86
86
  end
87
- generator.html("<img src='images/#{File.basename(@filename)}' alt='#{@options[:alt]}' />")
87
+ builder.html("<img src='images/#{File.basename(@filename)}' alt='#{@options[:alt]}' />")
88
88
  end
89
89
  end
@@ -26,9 +26,9 @@ class ReportBuilder::Section
26
26
  end
27
27
  end
28
28
 
29
- def report_building_text(generator)
30
- generator.text(("="*generator.parse_level)+" "+name)
31
- generator.parse_cycle(self)
29
+ def report_building_text(builder)
30
+ builder.text(("="*builder.parse_level)+" "+name)
31
+ builder.parse_cycle(self)
32
32
  end
33
33
 
34
34
  def report_building_html(g)
@@ -1,3 +1,4 @@
1
+
1
2
  class ReportBuilder
2
3
  # Creates a table.
3
4
  # Use:
@@ -52,6 +53,7 @@ class ReportBuilder
52
53
  end
53
54
  end
54
55
  # Adds a row
56
+ # <b>Usage:</b>
55
57
  # table.add_row(%w{1 2})
56
58
  def row(row)
57
59
  @rows.push(row)
@@ -105,20 +107,20 @@ class ReportBuilder
105
107
  }
106
108
  @max_cols
107
109
  end
108
- def report_building_text(generator)
109
- require 'reportbuilder/table/textgenerator'
110
- table_generator=ReportBuilder::Table::TextGenerator.new( generator, self)
111
- table_generator.generate
110
+ def report_building_text(builder)
111
+ require 'reportbuilder/table/textbuilder'
112
+ table_builder=ReportBuilder::Table::TextBuilder.new( builder, self)
113
+ table_builder.generate
112
114
  end
113
- def report_building_html(generator)
114
- require 'reportbuilder/table/htmlgenerator'
115
- table_generator=ReportBuilder::Table::HtmlGenerator.new(generator, self)
116
- table_generator.generate
115
+ def report_building_html(builder)
116
+ require 'reportbuilder/table/htmlbuilder'
117
+ table_builder=ReportBuilder::Table::HtmlBuilder.new(builder, self)
118
+ table_builder.generate
117
119
  end
118
- def report_building_rtf(generator)
119
- require 'reportbuilder/table/rtfgenerator'
120
- table_generator=ReportBuilder::Table::RtfGenerator.new(generator, self)
121
- table_generator.generate
120
+ def report_building_rtf(builder)
121
+ require 'reportbuilder/table/rtfbuilder'
122
+ table_builder=ReportBuilder::Table::RtfBuilder.new(builder, self)
123
+ table_builder.generate
122
124
  end
123
125
  def total_width # :nodoc:
124
126
  if @max_cols.size>0
@@ -127,6 +129,9 @@ class ReportBuilder
127
129
  0
128
130
  end
129
131
  end
132
+
133
+
134
+
130
135
  ######################
131
136
  # INTERNAL CLASSES #
132
137
  ######################
@@ -154,4 +159,7 @@ class ReportBuilder
154
159
  end
155
160
  end
156
161
  end
162
+ require 'reportbuilder/table/htmlbuilder'
163
+ require 'reportbuilder/table/textbuilder'
164
+ require 'reportbuilder/table/rtfbuilder'
157
165
 
@@ -1,9 +1,9 @@
1
1
  class ReportBuilder
2
2
  class Table
3
- class HtmlGenerator < ElementGenerator
3
+ class HtmlBuilder < ElementBuilder
4
4
  def generate()
5
5
  t=@element
6
- anchor=@generator.table_entry(t.name)
6
+ anchor=@builder.table_entry(t.name)
7
7
  out="<a name='#{anchor}'></a><table><caption>#{t.name}</caption>"
8
8
  @rowspans=[]
9
9
  if t.header.size>0
@@ -21,27 +21,31 @@ class ReportBuilder
21
21
  end
22
22
  }
23
23
  out+="</tbody>\n</table>\n"
24
- @generator.html(out)
24
+ @builder.html(out)
25
25
  end
26
26
  def parse_row(t,row,tag="td")
27
27
  row_ary=[]
28
- colspan_i=0
28
+ real_i=0
29
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
30
+ extra=1
31
+ while !@rowspans[real_i].nil? and @rowspans[real_i]>0
32
+ @rowspans[real_i]-=1
33
+ row_ary << ""
34
+ real_i+=1
35
+ end
36
+
37
+ if row[i].is_a? Table::Colspan
35
38
  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
39
  elsif row[i].nil?
38
40
  row_ary.push("<#{tag}></#{tag}>")
39
41
  elsif row[i].is_a? Table::Rowspan
40
42
  row_ary.push(sprintf("<%s rowspan=\"%d\">%s</%s>", tag, row[i].rows, row[i].data, tag))
41
- @rowspans[i]=row[i].rows-1
43
+ @rowspans[real_i]=row[i].rows-1
42
44
  else
43
45
  row_ary.push("<#{tag}>#{row[i]}</#{tag}>")
44
46
  end
47
+ real_i+=extra
48
+
45
49
  end
46
50
  row_ary.join("")
47
51
  end
@@ -1,20 +1,20 @@
1
1
  class ReportBuilder
2
2
  class Table
3
- class RtfGenerator < ElementGenerator
3
+ class RtfBuilder < ElementBuilder
4
4
  include RTF
5
5
  def generate()
6
6
  @t=@element
7
- @rtf=@generator.rtf
7
+ @rtf=@builder.rtf
8
8
 
9
9
  # Title
10
10
 
11
- @generator.header(6,@t.name)
11
+ @builder.header(6,@t.name)
12
12
 
13
13
  max_cols=@t.calculate_widths
14
14
  n_rows=@t.n_rows_no_hr+(@t.header.size>0 ? 1: 0)
15
- args=[n_rows, @t.n_columns]+max_cols.map{|m| m*@generator.options[:font_size]*10}
15
+ args=[n_rows, @t.n_columns]+max_cols.map{|m| m*@builder.options[:font_size]*10}
16
16
  @table=@rtf.table(*args)
17
- @table.border_width=@generator.options[:table_border_width]
17
+ @table.border_width=@builder.options[:table_border_width]
18
18
  @rowspans=[]
19
19
  if @t.header.size>0
20
20
  @t.header.each_with_index do |th,i|
@@ -40,30 +40,34 @@ class ReportBuilder
40
40
  end
41
41
  def create_hr(row_i)
42
42
  (0...@t.n_columns).each {|i|
43
- @table[row_i][i].top_border_width=@generator.options[:table_hr_width]
43
+ @table[row_i][i].top_border_width=@builder.options[:table_hr_width]
44
44
  }
45
45
  end
46
46
 
47
47
  def parse_row(row,row_i)
48
48
  t=@element
49
49
  row_ary=[]
50
+ real_i=0
50
51
  colspan_i=0
51
52
  row.each_index do |i|
52
- if !@rowspans[i].nil? and @rowspans[i]>0
53
- @rowspans[i]-=1
54
- elsif colspan_i>0
55
- colspan_i-=1
56
- elsif row[i].is_a? Table::Colspan
57
- @table[row_i][i] << row[i].data
53
+ extra=1
54
+ while !@rowspans[real_i].nil? and @rowspans[real_i]>0
55
+ @rowspans[real_i]-=1
56
+ real_i+=1
57
+ end
58
+ if row[i].is_a? Table::Colspan
59
+ @table[row_i][real_i] << row[i].data
58
60
  colspan_i=row[i].cols-1
61
+ extra=row[i].cols
59
62
  elsif row[i].nil?
60
63
  @table[row_i][i] << ""
61
64
  elsif row[i].is_a? Table::Rowspan
62
- @table[row_i][i] << row[i].data
63
- @rowspans[i]=row[i].rows-1
65
+ @table[row_i][real_i] << row[i].data
66
+ @rowspans[real_i]=row[i].rows-1
64
67
  else
65
- @table[row_i][i] << row[i].to_s
68
+ @table[row_i][real_i] << row[i].to_s
66
69
  end
70
+ real_i+=extra
67
71
  end
68
72
  end
69
73
  end
@@ -0,0 +1,52 @@
1
+ require 'text-table'
2
+ class ReportBuilder
3
+ class Table
4
+ class TextBuilder < ElementBuilder
5
+ def generate()
6
+
7
+ t=@element
8
+ @rowspans=[]
9
+ @builder.text(t.name)
10
+ return if t.header.size+t.rows.size==0
11
+ table = Text::Table.new do |tt|
12
+ tt.head=t.header if t.header.size>0
13
+ tt.rows=t.rows.map {|row| parse_row(row)}
14
+ end
15
+ #pp table.rows
16
+ @builder.text(table.to_s)
17
+ end
18
+ # Parse a row
19
+ def parse_row(row)
20
+ return :separator if row==:hr
21
+ t=@element
22
+ row_ary=[]
23
+ real_i=0
24
+ row.each_index do |i|
25
+ extra=1
26
+
27
+ while !@rowspans[real_i].nil? and @rowspans[real_i]>0
28
+ @rowspans[real_i]-=1
29
+ row_ary << ""
30
+ real_i+=1
31
+ end
32
+
33
+ if row[i].is_a? ReportBuilder::Table::Rowspan
34
+ @rowspans[real_i]=row[i].rows-1
35
+ row_ary << row[i].to_s
36
+ elsif row[i].is_a? ReportBuilder::Table::Colspan
37
+ row_ary.push({:value=>row[i].to_s, :colspan=>row[i].cols})
38
+ extra=row[i].cols
39
+ elsif row[i].nil?
40
+ row_ary.push("")
41
+ else
42
+ #size=row[i].to_s.size
43
+ #puts sprintf("%i : %s (%d-%d)",i,row[i].to_s,@max_cols[i], size)
44
+ row_ary.push(row[i].to_s)
45
+ end
46
+ real_i+=extra
47
+ end
48
+ row_ary
49
+ end
50
+ end
51
+ end
52
+ end
data/test/test_image.rb CHANGED
@@ -41,6 +41,6 @@ Test
41
41
  assert_match(/img src='images\/sheep.jpg'/, @rp.to_html)
42
42
  end
43
43
  def test_image_rtf
44
- assert_match(/\\pict\\picw128\\pich112\\bliptag2403101\\jpegblip/, @rp.to_rtf)
44
+ assert_match(/\\pict\\picw128\\pich112\\bliptag\d+\\jpegblip/, @rp.to_rtf)
45
45
  end
46
46
  end
@@ -64,6 +64,8 @@ class TestReportbuilder < MiniTest::Unit::TestCase
64
64
  ["para","pre","th1","th2"].each do |t|
65
65
  assert_match(/#{t}/,out)
66
66
  end
67
+
68
+
67
69
  end
68
70
  def test_empty
69
71
  rp=ReportBuilder.new
@@ -73,11 +75,32 @@ class TestReportbuilder < MiniTest::Unit::TestCase
73
75
  rp.add("hola")
74
76
  assert_equal("hola\n",rp.to_s)
75
77
  end
78
+ def test_incorrect_format
79
+ assert_raises ReportBuilder::FormatNotFound do
80
+ ReportBuilder::generate(:format=>:fish) do
81
+ text "This is silly"
82
+ end
83
+ end
84
+ end
85
+ def test_formats
86
+ require 'pp'
87
+ assert_equal(ReportBuilder.builder_for(:txt), ReportBuilder::Builder::Text)
88
+ assert_equal(ReportBuilder.builder_for("txt"), ReportBuilder::Builder::Text)
89
+ assert_equal(ReportBuilder.builder_for("html"), ReportBuilder::Builder::Html)
90
+
91
+ end
92
+
76
93
  def test_generate
77
- res=ReportBuilder.generate(:format=>:text,:name=>"Test") do
94
+ txt_file=Tempfile.new("test.txt")
95
+ ReportBuilder.generate(:name=>"Test", :filename=>txt_file.path) do
96
+ text("hola")
97
+ end
98
+
99
+ text=ReportBuilder.generate(:format=>:text,:name=>"Test") do
78
100
  text("hola")
79
101
  end
80
- assert_match(/^Test\nhola$/,res)
102
+ assert_match(/^Test\nhola$/,text)
103
+ assert_equal(text, File.read(txt_file.path))
81
104
  html_file=Tempfile.new("test.html")
82
105
  html=ReportBuilder.generate(:name=>"Test", :format=>:html) do
83
106
  text("hola")
data/test/test_table.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  require "minitest/unit"
2
2
  $:.unshift(File.dirname(__FILE__)+"/../lib")
3
3
  require "reportbuilder"
4
- require 'reportbuilder/table/htmlgenerator'
5
- require 'reportbuilder/table/textgenerator'
6
4
  require 'nokogiri'
7
5
 
8
6
  MiniTest::Unit.autorun
@@ -11,13 +9,13 @@ class TestReportbuilderTable < MiniTest::Unit::TestCase
11
9
  super
12
10
  @name="Table Test"
13
11
  @header=%w{a bb ccc dddd eeee fff gggg hh i}
14
- table=ReportBuilder::Table.new(:name=>"Table Test", :header=>@header) do
12
+ table=ReportBuilder::Table.new(:name=>@name, :header=>@header) do
15
13
  row(["a","b","c","d","e","f","g","h","i"])
16
- row([colspan("a",2),nil,"c",rowspan("d",2),"e","f","g","h","i"])
17
- row([colspan("a",3),nil,nil,nil,"e","f","g","h","i"])
18
- row([colspan("a",4),nil,nil,nil,"e","f","g","h","i"])
19
- row([colspan("a",5),nil,nil,nil,nil,colspan("f",3),nil,nil,"i"])
20
- row([colspan("a",6),nil,nil,nil,nil,nil,"g","h","i"])
14
+ row([colspan("a",2),"c",'d',rowspan("e",2),rowspan("f",2),"g",rowspan("h",3),"i"])
15
+ row([colspan("a",3),'d', "g","i"])
16
+ row([colspan("a",4),"e","f","g","i"])
17
+ row([colspan("a",5),colspan("f",3),"i"])
18
+ row([colspan("a",6),"g","h","i"])
21
19
  end
22
20
 
23
21
  @table=table
@@ -25,16 +23,25 @@ class TestReportbuilderTable < MiniTest::Unit::TestCase
25
23
  @mock_generator = ""
26
24
  class << @mock_generator
27
25
  def preformatted(t)
28
- replace(t)
26
+ @first_pre||=true
27
+ self << "\n" unless @first_pre
28
+ self << t
29
+ @first=false
29
30
  end
30
31
  def text(t)
31
- replace(t)
32
+ @first_text||=:true
33
+ self << "\n" unless @first_text==:true
34
+ self << t
35
+ @first_text=:false
32
36
  end
33
37
  def table_entry(t)
34
38
  "MOCK"
35
39
  end
36
40
  def html(t)
37
- replace(t)
41
+ @first_html||=true
42
+ self << "\n" unless @first_html
43
+ self << t
44
+ @first=false
38
45
  end
39
46
  end
40
47
 
@@ -45,75 +52,69 @@ class TestReportbuilderTable < MiniTest::Unit::TestCase
45
52
  end
46
53
  assert_match(/^Table\s+$/ , text)
47
54
  end
55
+
56
+ def test_rtf
57
+ rb=ReportBuilder.new
58
+ rb.add(@table)
59
+ rb.save_rtf("test.rtf")
60
+
61
+
62
+ end
48
63
  def test_table_text
49
-
50
- tg=ReportBuilder::Table::TextGenerator.new(@mock_generator,@table)
64
+ tg=ReportBuilder::Table::TextBuilder.new(@mock_generator, @table)
51
65
  tg.generate
52
- expected= <<-HEREDOC
66
+ expected= <<-HEREDOC
53
67
  Table Test
54
- ----------------------------------------------------
68
+ +---+----+-----+------+------+-----+------+----+---+
55
69
  | a | bb | ccc | dddd | eeee | fff | gggg | hh | i |
56
- ----------------------------------------------------
70
+ +---+----+-----+------+------+-----+------+----+---+
57
71
  | a | b | c | d | e | f | g | h | i |
58
72
  | a | c | d | e | f | g | h | i |
59
- | a | | e | f | g | h | i |
60
- | a | e | f | g | h | i |
73
+ | a | d | | | g | | i |
74
+ | a | e | f | g | | i |
61
75
  | a | f | i |
62
76
  | a | g | h | i |
63
- ----------------------------------------------------
77
+ +---+----+-----+------+------+-----+------+----+---+
64
78
  HEREDOC
65
-
66
- assert_equal(expected,@mock_generator)
67
-
79
+ #puts expected
80
+ #puts @mock_generator
81
+ assert_equal(expected, @mock_generator)
68
82
  end
69
83
  def test_table_html
70
84
 
71
- tg=ReportBuilder::Table::HtmlGenerator.new(@mock_generator,@table)
85
+ tg=ReportBuilder::Table::HtmlBuilder.new(@mock_generator,@table)
72
86
  tg.generate
73
-
74
- expected= <<HEREDOC
75
- <a name='MOCK'> </a>
76
- <table>
77
- <thead>
78
- <th>a</th><th>bb</th><th>ccc</th>
79
- <th>dddd</th><th>eeee</th>
80
- <th>fff</th><th>gggg</th><th>hh</th><th>i</th>
81
- </thead>
82
- <tbody>
83
- <tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td>
84
- <td>f</td><td>g</td><td>h</td><td>i</td></tr>
85
-
86
- <tr><td colspan="2">a</td><td>c</td><td rowspan="2">d</td><td>e</td>
87
- <td>f</td><td>g</td><td>h</td><td>i</td></tr>
88
-
89
- <tr><td colspan="3">a</td><td>e</td>
90
- <td>f</td><td>g</td><td>h</td><td>i</td></tr>
91
-
92
- <tr><td colspan="4">a</td><td>e</td>
93
- <td>f</td><td>g</td><td>h</td><td>i</td></tr>
94
-
95
- <tr><td colspan="5">a</td><td colspan="3">f</td><td>i</td></tr>
96
-
97
- <tr><td colspan="6">a</td><td>g</td><td>h</td><td>i</td></tr>
98
- </tbody>
99
- </table>
100
- HEREDOC
101
-
102
87
  doc=Nokogiri::HTML(@mock_generator).at_xpath("/html")
103
88
 
104
89
  assert(doc.at_xpath("a[@name='MOCK']")!="")
105
90
  assert(doc.at_xpath("table")!="")
106
91
 
107
92
  assert_equal(@header, doc.xpath("//table/thead/th").map {|m| m.content} )
108
- [[2,%w{a}],
109
- [3,%w{a f}],
110
- [4,%w{a}],
111
- [5,%w{a}],
112
- [6,%w{a}],
93
+ expected_contents=[
94
+ %w{a b c d e f g h i},
95
+ %w{a c d e f g h i},
96
+ %w{a d g i},
97
+ %w{a e f g i},
98
+ %w{a f i},
99
+ %w{a g h i}
100
+ ]
101
+ real_contents=doc.xpath("//table/tbody/tr").map do |tr|
102
+ tds=tr.xpath("td").map {|m| m.content}
103
+
104
+ end
105
+ assert_equal(expected_contents, real_contents)
113
106
 
114
- ].each do |m,exp|
115
- real=doc.xpath("//table/tbody/tr/td[@colspan='#{m}']").map {|x| x.inner_html}
116
- assert_equal(exp, real, "On table/tbody/tr/td[@colspan='#{m}']"
107
+ [
108
+ ['colspan',2,%w{a}],
109
+ ['colspan',3,%w{a f}],
110
+ ['colspan',4,%w{a}],
111
+ ['colspan',5,%w{a}],
112
+ ['colspan',6,%w{a}],
113
+ ['rowspan',2,%w{e f}],
114
+ ['rowspan',3,%w{h}],
115
+ ].each do |attr,m,exp|
116
+ real=doc.xpath("//table/tbody/tr/td[@#{attr}='#{m}']").map {|x| x.content}.sort
117
+ assert_equal(exp, real, "On table/tbody/tr/td[@#{attr}='#{m}']"
117
118
  )
118
119
  end
119
120
 
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reportbuilder
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 2
8
+ - 0
9
+ version: 1.2.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Claudio Bustos
@@ -9,59 +14,91 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-03-24 00:00:00 -03:00
17
+ date: 2010-03-28 00:00:00 -03:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: clbustos-rtf
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ~>
22
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 2
30
+ - 1
23
31
  version: 0.2.1
24
- version:
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: text-table
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 2
44
+ version: "1.2"
45
+ type: :runtime
46
+ version_requirements: *id002
25
47
  - !ruby/object:Gem::Dependency
26
48
  name: rubyforge
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
30
51
  requirements:
31
52
  - - ">="
32
53
  - !ruby/object:Gem::Version
54
+ segments:
55
+ - 2
56
+ - 0
57
+ - 4
33
58
  version: 2.0.4
34
- version:
59
+ type: :development
60
+ version_requirements: *id003
35
61
  - !ruby/object:Gem::Dependency
36
62
  name: gemcutter
37
- type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
63
+ prerelease: false
64
+ requirement: &id004 !ruby/object:Gem::Requirement
40
65
  requirements:
41
66
  - - ">="
42
67
  - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ - 5
71
+ - 0
43
72
  version: 0.5.0
44
- version:
45
- - !ruby/object:Gem::Dependency
46
- name: hpricot
47
73
  type: :development
48
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Requirement
74
+ version_requirements: *id004
75
+ - !ruby/object:Gem::Dependency
76
+ name: nokogiri
77
+ prerelease: false
78
+ requirement: &id005 !ruby/object:Gem::Requirement
50
79
  requirements:
51
80
  - - ~>
52
81
  - !ruby/object:Gem::Version
53
- version: "0.8"
54
- version:
82
+ segments:
83
+ - 1
84
+ - 4
85
+ version: "1.4"
86
+ type: :development
87
+ version_requirements: *id005
55
88
  - !ruby/object:Gem::Dependency
56
89
  name: hoe
57
- type: :development
58
- version_requirement:
59
- version_requirements: !ruby/object:Gem::Requirement
90
+ prerelease: false
91
+ requirement: &id006 !ruby/object:Gem::Requirement
60
92
  requirements:
61
93
  - - ">="
62
94
  - !ruby/object:Gem::Version
95
+ segments:
96
+ - 2
97
+ - 5
98
+ - 1
63
99
  version: 2.5.1
64
- version:
100
+ type: :development
101
+ version_requirements: *id006
65
102
  description: Report Abstract Interface. Creates text, html and rtf output, based on a common framework.
66
103
  email:
67
104
  - clbustos_at_gmail.com
@@ -88,16 +125,16 @@ files:
88
125
  - examples/test.rtf
89
126
  - examples/using_a_block.rb
90
127
  - lib/reportbuilder.rb
91
- - lib/reportbuilder/generator.rb
92
- - lib/reportbuilder/generator/html.rb
93
- - lib/reportbuilder/generator/rtf.rb
94
- - lib/reportbuilder/generator/text.rb
128
+ - lib/reportbuilder/builder.rb
129
+ - lib/reportbuilder/builder/html.rb
130
+ - lib/reportbuilder/builder/rtf.rb
131
+ - lib/reportbuilder/builder/text.rb
95
132
  - lib/reportbuilder/image.rb
96
133
  - lib/reportbuilder/section.rb
97
134
  - lib/reportbuilder/table.rb
98
- - lib/reportbuilder/table/htmlgenerator.rb
99
- - lib/reportbuilder/table/rtfgenerator.rb
100
- - lib/reportbuilder/table/textgenerator.rb
135
+ - lib/reportbuilder/table/htmlbuilder.rb
136
+ - lib/reportbuilder/table/rtfbuilder.rb
137
+ - lib/reportbuilder/table/textbuilder.rb
101
138
  - test/test_html.rb
102
139
  - test/test_image.rb
103
140
  - test/test_reportbuilder.rb
@@ -117,18 +154,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
117
154
  requirements:
118
155
  - - ">="
119
156
  - !ruby/object:Gem::Version
157
+ segments:
158
+ - 0
120
159
  version: "0"
121
- version:
122
160
  required_rubygems_version: !ruby/object:Gem::Requirement
123
161
  requirements:
124
162
  - - ">="
125
163
  - !ruby/object:Gem::Version
164
+ segments:
165
+ - 0
126
166
  version: "0"
127
- version:
128
167
  requirements: []
129
168
 
130
169
  rubyforge_project: ruby-statsample
131
- rubygems_version: 1.3.5
170
+ rubygems_version: 1.3.6
132
171
  signing_key:
133
172
  specification_version: 3
134
173
  summary: Report Abstract Interface
@@ -1,55 +0,0 @@
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="#{t.name}\n"
10
- if total_width>0
11
- if t.header.size>0
12
- out+=parse_hr(total_width)+"\n"
13
- out+=parse_row(t,t.header)+"\n"
14
- out+=parse_hr(total_width)+"\n"
15
- end
16
- t.rows.each do |row|
17
- if row==:hr
18
- out+=parse_hr(total_width)+"\n"
19
- else
20
- out+=parse_row(t,row)+"\n"
21
- end
22
- end
23
- out+=parse_hr(total_width)+"\n"
24
- end
25
- @generator.text(out)
26
- end
27
- # Parse a row
28
- def parse_row(t,row)
29
- row_ary=[]
30
- colspan_i=0
31
- row.each_index do |i|
32
- if colspan_i>0
33
- colspan_i-=1
34
- elsif row[i].is_a? ReportBuilder::Table::Colspan
35
- size = (i...(i+row[i].cols)).inject(0) {|a,v| a+t.max_cols[v]+3}
36
- size-=3
37
- row_ary.push(row[i].data.to_s+" "*(size - row[i].data.size))
38
- colspan_i=row[i].cols-1
39
- elsif row[i].nil?
40
- row_ary.push(" "*t.max_cols[i])
41
- else
42
- size=row[i].to_s.size
43
- #puts sprintf("%i : %s (%d-%d)",i,row[i].to_s,@max_cols[i], size)
44
- row_ary.push(row[i].to_s+" "*(t.max_cols[i] - size))
45
- end
46
- end
47
- "| "+row_ary.join(" | ")+" |"
48
- end
49
- # Parse a horizontal rule
50
- def parse_hr(l)
51
- "-"*l
52
- end
53
- end
54
- end
55
- end