ruport 0.4.19 → 0.4.21

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,6 +1,23 @@
1
- The current version of Ruby Reports is 0.4.19
1
+ The current version of Ruby Reports is 0.4.21
2
2
 
3
- changes since 0.4.1
3
+ changes since 0.4.19
4
+ - Added a rake task to run rcov
5
+
6
+ - Removed DataSet / DataRow. Farewell good friends
7
+
8
+ - Added Array#to_table, dropped Array#to_ds
9
+
10
+ - You can now convert Sets to Tables and vice-versa
11
+
12
+ - acts_as_reportable converted to use Data::Table
13
+
14
+ - Data::Record's constructor can now take a hash
15
+
16
+ - Added initial Data::Set implementation
17
+
18
+ - Added smart Data::Table.to_format method_missing functionality
19
+
20
+ changes since 0.4.17
4
21
 
5
22
  - Made method_missing a lot more friendly all around.
6
23
 
data/Rakefile CHANGED
@@ -12,8 +12,7 @@ end
12
12
  LEAN=false
13
13
  dir = File.dirname(__FILE__)
14
14
  lib = File.join(dir, "lib", "ruport.rb")
15
- version = File.read(lib)[/^\s*VERSION\s*=\s*(['"])(\d+\.\d+\.d+)\1/,2]
16
-
15
+ version = File.read(lib)[/^\s*VERSION\s*=\s*(['"])(\d+\.\d+\.d+)['"]/,1]
17
16
  task :default => [:test]
18
17
 
19
18
  Rake::TestTask.new do |test|
@@ -24,7 +23,7 @@ end
24
23
 
25
24
  spec = Gem::Specification.new do |spec|
26
25
  spec.name = LEAN ? "lean-ruport" : "ruport"
27
- spec.version = "0.4.19"
26
+ spec.version = "0.4.21"
28
27
  spec.platform = Gem::Platform::RUBY
29
28
  spec.summary = "A generalized Ruby report generation and templating engine."
30
29
  spec.files = Dir.glob("{examples,lib,test}/**/**/*") +
@@ -66,10 +65,16 @@ Rake::RDocTask.new do |rdoc|
66
65
  rdoc.title = "Ruport Documentation"
67
66
  end
68
67
 
69
-
70
68
  Rake::GemPackageTask.new(spec) do |pkg|
71
69
  pkg.need_zip = true
72
70
  pkg.need_tar = true
73
71
  end
74
72
 
75
-
73
+ begin
74
+ require 'rcov/rcovtask'
75
+ Rcov::RcovTask.new do |t|
76
+ t.test_files = [ "test/ts_all.rb" ]
77
+ end
78
+ rescue LoadError
79
+ nil
80
+ end
@@ -11,11 +11,11 @@ class Format::Plugin::Text < Ruport::Format::Plugin
11
11
  end
12
12
 
13
13
  format_field_names do
14
- data.fields.join("---") << "\n"
14
+ data.column_names.join("---") << "\n"
15
15
  end
16
16
 
17
17
  register_on :table_engine
18
18
  end
19
19
 
20
- puts Format.table({ :data => [[1,2],[3,4]].to_ds(%w[a b]),
20
+ puts Format.table({ :data => [[1,2],[3,4]].to_table(:column_names =>%w[a b]),
21
21
  :plugin => :text })
data/lib/ruport.rb CHANGED
@@ -14,7 +14,7 @@ module Ruport
14
14
 
15
15
  #begin; require 'rubygems'; rescue LoadError; nil end
16
16
 
17
- VERSION = "0.4.19"
17
+ VERSION = "0.4.21"
18
18
 
19
19
  # Ruports logging and error interface.
20
20
  # Can generate warnings or raise fatal errors
@@ -67,6 +67,6 @@ module Ruport
67
67
  end
68
68
 
69
69
 
70
- %w[config meta_tools report format query data_row data_set data].each { |lib|
70
+ %w[config meta_tools report format query data].each { |lib|
71
71
  require "ruport/#{lib}"
72
72
  }
data/lib/ruport/data.rb CHANGED
@@ -1 +1 @@
1
- %w[taggable record collection table].each { |l| require "ruport/data/#{l}" }
1
+ %w[taggable record collection table set].each { |l| require "ruport/data/#{l}" }
@@ -12,7 +12,15 @@ module Ruport::Data
12
12
  def as(type)
13
13
  Ruport::Format.table :data => self, :plugin => type
14
14
  end
15
+
16
+ def to_set
17
+ Set.new :data => data
18
+ end
15
19
 
20
+ def to_table(options={})
21
+ Table.new({:data => data.map { |r| r.to_a }}.merge(options))
22
+ end
23
+
16
24
  attr_reader :data
17
25
  def_delegators :@data, :each, :length, :[], :empty?
18
26
  end
@@ -6,8 +6,17 @@ module Ruport::Data
6
6
  include Taggable
7
7
 
8
8
  def initialize(data,options={})
9
- @data = data.dup
10
- @attributes = options[:attributes]
9
+ if data.kind_of?(Hash)
10
+ if options[:attributes]
11
+ @attributes = options[:attributes]
12
+ @data = options[:attributes].map { |k| data[k] }
13
+ else
14
+ @attributes, @data = data.to_a.transpose
15
+ end
16
+ else
17
+ @data = data.dup
18
+ @attributes = options[:attributes]
19
+ end
11
20
  end
12
21
 
13
22
  attr_reader :data
@@ -67,6 +76,10 @@ module Ruport::Data
67
76
  #FIXME: This does not take into account frozen / tainted state
68
77
  alias_method :clone, :dup
69
78
 
79
+ def hash
80
+ (attributes.to_a + data.to_a).hash
81
+ end
82
+
70
83
  def method_missing(id,*args)
71
84
  id = id.to_s.gsub(/=$/,"")
72
85
  if @attributes.include?(id)
@@ -0,0 +1,42 @@
1
+ require 'set'
2
+
3
+ module Ruport::Data
4
+ class Set < Collection
5
+
6
+ def initialize(options={})
7
+ @data = ::Set.new
8
+ options[:data].each {|e| self << e} if options[:data]
9
+ end
10
+
11
+ def <<(other)
12
+ case other
13
+ when Record
14
+ @data << other
15
+ when Array
16
+ @data << Record.new(other)
17
+ end
18
+ end
19
+
20
+ def ==(other)
21
+ @data == other.data
22
+ end
23
+
24
+ def |(other)
25
+ Set.new :data => (@data | other.data)
26
+ end
27
+ alias_method :union, :|
28
+
29
+ def &(other)
30
+ Set.new :data => (@data & other.data)
31
+ end
32
+ alias_method :intersection, :&
33
+
34
+ # Set difference
35
+ def -(other)
36
+ Set.new :data => (@data - other.data)
37
+ end
38
+ alias_method :difference, :-
39
+
40
+ def_delegators :@data, :each
41
+ end
42
+ end
@@ -1,3 +1,9 @@
1
+ class Array
2
+ def to_table(options={})
3
+ Ruport::Data::Table.new({:data => self}.merge(options))
4
+ end
5
+ end
6
+
1
7
  module Ruport::Data
2
8
  class Table < Collection
3
9
  def initialize(options={})
@@ -12,6 +18,15 @@ module Ruport::Data
12
18
  @column_names = other.dup
13
19
  end
14
20
 
21
+ def eql?(other)
22
+ data.eql?(other.data) && column_names.eql?(other.column_names)
23
+ end
24
+ alias_method :==, :eql?
25
+
26
+ def to_s
27
+ as(:text)
28
+ end
29
+
15
30
  def <<(other)
16
31
  case other
17
32
  when Array
@@ -86,6 +101,11 @@ module Ruport::Data
86
101
  Ruport::Data::Record.new data, :attributes => group
87
102
  end
88
103
  end
104
+
105
+ def method_missing(id,*args)
106
+ return as($1.to_sym) if id.to_s =~ /^to_(.*)/
107
+ super
108
+ end
89
109
 
90
110
  end
91
111
  end
data/lib/ruport/format.rb CHANGED
@@ -19,17 +19,11 @@ module Ruport
19
19
  # There are three main sets of functionality the Ruport::Format model provides.
20
20
  # * Structured printable document support ( Format::Document and friends)
21
21
  # * Text filter support ( Report#render and the Format class)
22
- # * Support for DataSet Formatting ( Format::Builder)
23
22
  #
24
23
  # The support for structured printable documents is currently geared towards PDF
25
24
  # support and needs some additional work to be truly useful. Suggestions would
26
25
  # be much appreciated.
27
26
  #
28
- # Format::Builder lets you define functions that will be used via DataSet#as
29
- # This is primary geared towards tabular data output, but there is no reason why
30
- # DataSet#as and the <tt>render_foo</tt> methods of Format::Builder cannot be
31
- # adapted to fit whatever needs you may need.
32
- #
33
27
  # The filters implemented in the Format class are meant to process strings or
34
28
  # entire templates. The Format class will soon automatically build a
35
29
  # Ruport::Parser for any string input. By default, filters are provided to
@@ -94,6 +94,23 @@ module Ruport
94
94
  private_class_method :new
95
95
  end
96
96
 
97
+ class Format::Engine::Invoice < Ruport::Format::Engine
98
+
99
+ # order meta data
100
+ attributes [:customer_info, :company_info]
101
+
102
+ renderer do
103
+ super
104
+ build_company_header
105
+ build_customer_header
106
+ active_plugin.render_invoice
107
+ end
108
+
109
+ alias_engine Invoice, :invoice_engine
110
+ Ruport::Format.build_interface_for Invoice, :invoice
111
+
112
+ end
113
+
97
114
  class Format::Engine::Table < Format::Engine
98
115
 
99
116
  renderer do
@@ -109,7 +126,7 @@ module Ruport
109
126
  def rewrite_column(key,&block)
110
127
  data.each { |r| r[key] = block[r] }
111
128
  end
112
-
129
+
113
130
  def num_cols
114
131
  data[0].to_a.length
115
132
  end
@@ -106,7 +106,7 @@ module Ruport
106
106
 
107
107
  action :max_col_width do |index|
108
108
  f = data.column_names if data.respond_to? :column_names
109
- d = DataSet.new f, :data => data
109
+ d = Data::Table.new :column_names => f, :data => data
110
110
 
111
111
  cw = d.map { |r| r[index].to_s.length }.max
112
112
 
@@ -119,9 +119,11 @@ module Ruport
119
119
 
120
120
  action :table_width do
121
121
  f = data.column_names if data.respond_to? :column_names
122
- d = DataSet.new f, :data => data
122
+ d = Data::Table.new:column_names => f, :data => data
123
123
 
124
- d[0].attributes.inject(0) { |s,e| s + max_col_width(e) }
124
+ f = d[0].attributes || (0...d[0].length)
125
+
126
+ f.inject(0) { |s,e| s + max_col_width(e) }
125
127
  end
126
128
 
127
129
  action :hr do
@@ -136,10 +138,16 @@ module Ruport
136
138
  end
137
139
 
138
140
  class PDFPlugin < Format::Plugin
139
-
141
+ attribute :pdf
142
+ attribute :paper
143
+
144
+ helper(:init_plugin) {
145
+ require "pdf/writer"
146
+ require "pdf/simpletable"
147
+ self.pdf = PDF::Writer.new( :paper => paper || "LETTER" )
148
+ }
149
+
140
150
  renderer :table do
141
- require "pdf/writer"; require "pdf/simpletable";
142
- pdf = PDF::Writer.new
143
151
  pre[pdf] if pre
144
152
  PDF::SimpleTable.new do |table|
145
153
  table.maximum_width = 500
@@ -156,8 +164,78 @@ module Ruport
156
164
 
157
165
  format_field_names { data.column_names }
158
166
 
167
+ renderer :invoice do
168
+ return unless defined? PDF::Writer
169
+
170
+ pdf.start_page_numbering(500, 20, 8, :right)
171
+
172
+ # order contents
173
+ pdf.y = 620
174
+
175
+ PDF::SimpleTable.new do |table|
176
+ table.width = 450
177
+ table.orientation = :center
178
+ table.data = data
179
+ table.show_lines = :outer
180
+ table.column_order = data.column_names
181
+ table.render_on(pdf)
182
+ table.font_size = 12
183
+ end
184
+
185
+
186
+ # footer
187
+ pdf.open_object do |footer|
188
+ pdf.save_state
189
+ pdf.stroke_color! Color::Black
190
+ pdf.stroke_style! PDF::Writer::StrokeStyle::DEFAULT
191
+
192
+ pdf.add_text_wrap( 50, 20, 200, "Printed at " +
193
+ Time.now.strftime("%H:%M %d/%m/%Y"), 8)
194
+
195
+ pdf.restore_state
196
+ pdf.close_object
197
+ pdf.add_object(footer, :all_pages)
198
+ end
199
+
200
+ pdf.stop_page_numbering(true, :current)
201
+ pdf.render
202
+ end
203
+
204
+ # Company Information in top lefthand corner
205
+ helper(:build_company_header) { |eng|
206
+ text_box(eng.company_info)
207
+ }
208
+
209
+
210
+
211
+ helper(:build_order_helper) { }
212
+
213
+ # Order details
214
+ helper(:build_customer_header) { |eng|
215
+ pdf.y -= 10
216
+ text_box(eng.customer_info)
217
+ }
218
+
219
+ def self.text_box(content,options={})
220
+ PDF::SimpleTable.new do |table|
221
+ table.data = content.to_a.inject([]) do |s,line|
222
+ s << { "value" => line }
223
+ end
224
+ table.column_order = "value"
225
+ table.show_headings = false
226
+ table.show_lines = :outer
227
+ table.shade_rows = :none
228
+ table.width = options[:width] || 200
229
+ table.orientation = options[:orientation] || :right
230
+ table.position = options[:position] || :left
231
+ table.font_size = options[:font_size] || 10
232
+ table.render_on(pdf)
233
+ end
234
+ end
235
+
159
236
  plugin_name :pdf
160
237
  register_on :table_engine
238
+ register_on :invoice_engine
161
239
  end
162
240
 
163
241
  class HTMLPlugin < Format::Plugin
data/lib/ruport/query.rb CHANGED
@@ -4,7 +4,7 @@ require "ruport/query/sql_split"
4
4
  module Ruport
5
5
 
6
6
  # Query offers a way to interact with databases via DBI. It supports
7
- # returning result sets in either Ruport's native DataSets, or in their raw
7
+ # returning result sets in either Ruport's native Data::Table, or in their raw
8
8
  # form as DBI::Rows.
9
9
  #
10
10
  # It offers basic caching support, the ability to instantiate a generator for
@@ -25,7 +25,7 @@ module Ruport
25
25
  # This kind of laziness is supposed to be A Good Thing, and
26
26
  # as long as you keep it in mind, it should not cause any problems.
27
27
  #
28
- # The SQL can be single or multistatement, but the resulting DataSet will
28
+ # The SQL can be single or multistatement, but the resulting Data::Table will
29
29
  # consist only of the result of the last statement which returns something.
30
30
  #
31
31
  # Options:
@@ -106,7 +106,7 @@ module Ruport
106
106
  fetch &action
107
107
  end
108
108
 
109
- # Grabs the result set as a DataSet or if in raw_data mode, an array of
109
+ # Grabs the result set as a Data::Table or if in raw_data mode, an array of
110
110
  # DBI:Row objects
111
111
  def result; fetch; end
112
112
 
@@ -137,7 +137,7 @@ module Ruport
137
137
  @cache_enabled = false
138
138
  end
139
139
 
140
- # Returns a DataSet, even if in raw_data mode
140
+ # Returns a Data::Table, even if in raw_data mode
141
141
  # Does not work with raw data if cache is enabled and filled
142
142
  def to_dataset
143
143
  data_flag, @raw_data = @raw_data, false
@@ -160,7 +160,7 @@ module Ruport
160
160
 
161
161
  require "dbi"
162
162
 
163
- data = @raw_data ? [] : DataSet.new
163
+ data = @raw_data ? [] : Data::Table.new
164
164
  DBI.connect(@dsn, @user, @password) do |dbh|
165
165
  dbh.execute(query_text) do |sth|
166
166
  return unless sth.fetchable?