reportbuilder 1.1.1 → 1.2.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 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