ruport 0.4.11 → 0.4.13

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.
@@ -72,7 +72,7 @@ module Ruport
72
72
  def plugins
73
73
  format_plugins.values
74
74
  end
75
-
75
+
76
76
  end
77
77
  end
78
78
 
@@ -42,6 +42,7 @@ module Ruport
42
42
 
43
43
  attr_accessor :rendered_field_names
44
44
  attr_accessor :pre, :post
45
+ attr_accessor :header, :footer
45
46
  end
46
47
 
47
48
 
@@ -78,7 +79,7 @@ module Ruport
78
79
  }
79
80
 
80
81
  a = data.inject(th){ |s,r|
81
- s << "| #{r.to_a.join(' | ')} |\n"
82
+ s + "| #{r.to_a.join(' | ')} |\n"
82
83
  } << hr
83
84
 
84
85
  width = self.right_margin || SystemExtensions.terminal_width
@@ -111,7 +112,7 @@ module Ruport
111
112
  f = data.fields if data.respond_to? :fields
112
113
  d = DataSet.new f, :data => data
113
114
 
114
- d[0].fields.inject(0) { |s,e| s+=max_col_width(e) }
115
+ d[0].fields.inject(0) { |s,e| s + max_col_width(e) }
115
116
  end
116
117
 
117
118
  def self.hr
@@ -158,7 +159,7 @@ module Ruport
158
159
  renderer :table do
159
160
  rc = data.inject(rendered_field_names) { |s,r|
160
161
  row = r.map { |e| e.to_s.empty? ? "&nbsp;" : e }
161
- s << "|#{row.to_a.join('|')}|\n"
162
+ s + "|#{row.to_a.join('|')}|\n"
162
163
  }
163
164
  Format.document :data => rc, :plugin => :html
164
165
  end
data/lib/ruport/mailer.rb CHANGED
@@ -11,7 +11,8 @@ module Ruport
11
11
  extend Forwardable
12
12
 
13
13
  def initialize( mailer_label=:default )
14
- select_mailer(mailer_label); mail_object
14
+ select_mailer(mailer_label);
15
+ mail_object.from = @mailer.address if mail_object.from.to_s.empty?
15
16
  rescue
16
17
  raise "you need to specify a mailer to use"
17
18
  end
@@ -29,14 +30,14 @@ module Ruport
29
30
  end
30
31
 
31
32
  def select_mailer(label)
32
- mailer = Ruport::Config.mailers[label]
33
- @host = mailer.host
34
- @user = mailer.user
35
- @password = mailer.password
36
- @address = mailer.address
37
- @port = mailer.port || 25
38
- @auth = mailer.auth_type || :plain
39
- @mail_klass = mailer.mail_klass
33
+ @mailer = Ruport::Config.mailers[label]
34
+ @host = @mailer.host
35
+ @user = @mailer.user
36
+ @password = @mailer.password
37
+ @address = @mailer.address
38
+ @port = @mailer.port || 25
39
+ @auth = @mailer.auth_type || :plain
40
+ @mail_klass = @mailer.mail_klass
40
41
  end
41
42
 
42
43
  def mail_object
data/lib/ruport/query.rb CHANGED
@@ -61,8 +61,7 @@ module Ruport
61
61
  # # uses a SQL file stored on disk
62
62
  # Ruport::Query.new("my_query.sql",:origin => :file)
63
63
  def initialize(sql, options={})
64
- options[:source] ||= :default
65
- options[:origin] ||= :string
64
+ options = { :source => :default, :origin => :string }.merge(options)
66
65
  @sql = sql
67
66
  @statements = SqlSplit.new(get_query(options[:origin],sql))
68
67
 
@@ -116,15 +115,14 @@ module Ruport
116
115
 
117
116
  # clears the contents of the cache
118
117
  def clear_cache
119
- @cached_data = nil
118
+ @CAched_data = nil
120
119
  end
121
120
 
122
121
  # clears the contents of the cache and then runs the query, filling the
123
122
  # cache with the new result
124
123
  def update_cache
125
- clear_cache
126
- caching_flag,@cache_enabled = @cache_enabled, true
127
- fetch; @cache_enabled = caching_flag
124
+ return unless @cache_enabled
125
+ clear_cache; fetch
128
126
  end
129
127
 
130
128
  # Turns on caching. New data will not be loaded until cache is clear or
@@ -135,7 +133,7 @@ module Ruport
135
133
 
136
134
  # Turns off caching and flushes the cached data
137
135
  def disable_caching
138
- @cached_data = nil
136
+ clear_cache
139
137
  @cache_enabled = false
140
138
  end
141
139
 
@@ -148,7 +146,7 @@ module Ruport
148
146
 
149
147
  # Returns a csv dump of the query
150
148
  def to_csv
151
- to_dataset.to_csv
149
+ Format.table :plugin => :csv, :data => fetch
152
150
  end
153
151
 
154
152
  # Returns a Generator object of the result set
@@ -176,12 +174,7 @@ module Ruport
176
174
  end
177
175
 
178
176
  def get_query(type,query)
179
- case (type)
180
- when :string
181
- query
182
- when :file
183
- load_file( query )
184
- end
177
+ type.eql?(:file) ? load_file( query ) : query
185
178
  end
186
179
 
187
180
  def load_file( query_file )
data/lib/ruport/report.rb CHANGED
@@ -1,27 +1,140 @@
1
- # fixME: Copyright notice here.
1
+ # report.rb : High Level Interface to Ruport
2
+ #
3
+ # Author: Gregory Brown
4
+ # Copyright 2006, All Rights Reserved
5
+ #
6
+ # This is Free Software. See LICENSE and COPYING files for details.
2
7
 
3
8
  #load the needed standard libraries.
4
9
  %w[erb yaml date logger fileutils].each { |lib| require lib }
5
10
 
6
11
  require "ruport/mailer"
12
+ require "forwardable"
7
13
 
8
14
  module Ruport
15
+ # === Overview
16
+ #
17
+ # The Ruport::Report class povides a high level interface to most of Ruport's
18
+ # functionality. It is designed to allow you to build and run reports easily.
19
+ # If your needs are complicated, you will probably need to take a look at the
20
+ # individual classes of the library, but if they are fairly simple, you may be
21
+ # able to get away using this class alone.
22
+ #
23
+ # === Example
24
+ #
25
+ # Here is a simple example of using the Report class to run a simple query and
26
+ # then email the results as a CSV file, deleting the file from the local
27
+ # machine after it has been emailed:
28
+ #
29
+ # require "ruport"
30
+ # require "fileutils"
31
+ # class MyReport < Ruport::Report
32
+ # prepare do
33
+ # log_file "f.log"
34
+ # log "preparing report", :status => :info
35
+ # source :default,
36
+ # :dsn => "dbi:mysql:foo",
37
+ # :user => "root"
38
+ # mailer :default,
39
+ # :host => "mail.adelphia.net",
40
+ # :address => "gregory.t.brown@gmail.com"
41
+ # end
42
+ #
43
+ # generate do
44
+ # log "generated csv from query", :status => :info
45
+ # query "select * from bar", :as => :csv
46
+ # end
47
+ #
48
+ # cleanup do
49
+ # log "removing foo.csv", :status => :info
50
+ # FileUtils.rm("foo.csv")
51
+ # end
52
+ # end
53
+ #
54
+ # MyReport.run { |res|
55
+ # res.write "foo.csv";
56
+ # res.send_to("greg7224@gmail.com") do |mail|
57
+ # mail.subject = "Sample report"
58
+ # mail.attach "foo.csv"
59
+ # mail.text = <<-EOS
60
+ # this is a sample of sending an emailed report from within Ruport.
61
+ # EOS
62
+ # end
63
+ # }
64
+ #
65
+ #
66
+ # This class can also be used to run templates and process text filters
67
+ #
68
+ # See the examples in the documentation below to see how to use these
69
+ # features. (Namely Report#process_text , Report#text_processor, and
70
+ # Report#eval_template )
71
+ #
9
72
  class Report
73
+ extend Forwardable
74
+
75
+ # When initializing a report, you can provide a default mailer and source by
76
+ # giving a name of a valid source or mailer you've defined via
77
+ # Ruport::Config
78
+ #
79
+ # If your report does not need any sort of specialized information, you can
80
+ # simply use Report.run (Or MyReportName.run if you've inherited)
81
+ #
82
+ # This will auto-initialize a report.
10
83
  def initialize( source_name=:default, mailer_name=:default )
11
- @source = source_name
12
- @report_name = @report = ""
84
+ use_source source_name
85
+ use_mailer mailer_name
86
+ @report_name = @results = ""
13
87
  @file = nil
14
88
  end
15
89
 
16
- attr_accessor :file,:report
17
-
18
- # High level interface to Ruport::Query
19
- # - Can read SQL statements from file or string
20
- # - Can use multistatement SQL
21
- # - Can iterate by row or return entire set
22
- # - Can return raw DBI:Row objects or Ruport constructs.
90
+ #by default, this file will be used by Report#write
91
+ attr_accessor :file
92
+
93
+ #this attribute will get the results of Report#generate when the report is
94
+ #run.
95
+ attr_accessor :results
96
+
97
+ # Preserved for backwards compatability, please do not use this.
98
+ alias_method :report, :results
99
+
100
+ # Preserved for backwards compabilitity, please do not use this.
101
+ alias_method :report=, :results=
102
+
103
+
104
+ # Simplified interface to Ruport::Query
105
+ #
106
+ # === Can read SQL statements from file or string
107
+ #
108
+ # #from string
109
+ # result = query "select * from foo"
110
+ #
111
+ # #from file
112
+ # result = query "my_query.sql", :origin => :file
113
+ #
114
+ # === Can use multistatement SQL
115
+ #
116
+ # # will return the value of the last statement, "select * from foo"
117
+ # result = query "insert into foo values(1,2); select * from foo"
118
+ #
119
+ # === Can iterate by row or return entire set
120
+ #
121
+ # query("select * from foo", :yield_type => :by_row) { |r|
122
+ # #do something with the rows here
123
+ # }
124
+ #
125
+ # === Can return raw DBI:Row objects or Ruport's data structures.
126
+ #
127
+ # # will return a DataSet
128
+ # result = query "select * from foo"
23
129
  #
24
- # Defaults to returning entire sets of Ruport constructs.
130
+ # # will return an Array of DBI::Row objects
131
+ # result = query "select * from foo", :raw_data => true
132
+ #
133
+ # === Can quickly output in a number of formats
134
+ #
135
+ # result = query "select * from foo", :as => :csv
136
+ # result = query "select * from foo", :as => :html
137
+ # result = query "select * from foo", :as => :pdf
25
138
  #
26
139
  # See source of this function and methods of Ruport::Query for details.
27
140
  def query(sql, options={}, &action)
@@ -31,6 +144,8 @@ module Ruport
31
144
  q = Query.new(sql, options)
32
145
  if options[:yield_type].eql?(:by_row)
33
146
  q.each { |r| action.call(r) }
147
+ elsif options[:as]
148
+ Format.table :data => q.result, :plugin => options[:as]
34
149
  else
35
150
  block_given? ? action.call(q.result) : q.result
36
151
  end
@@ -38,41 +153,32 @@ module Ruport
38
153
 
39
154
  # Evaluates _code_ from _filename_ as pure ruby code for files ending in
40
155
  # .rb, and as ERb templates for anything else.
41
- def eval_template( filename, code )
42
- filename =~ /\.rb/ ? eval(code) : ERB.new(code, 0, "%").run(binding)
43
- end
44
-
45
-
46
- # Generates the report. If @pre or @post are defined with lambdas,
47
- # they will be called before and after the main code.
48
- #
49
- # If @file != nil, ruport will print to the
50
- # file with the specified name. Otherwise, it will print to STDOUT by
51
- # default.
52
156
  #
53
- # The source for this function is probably easier to read than this
54
- # explanation, so you may want to start there.
55
- def generate_report
56
- @pre.call if @pre
57
- @file ? File.open(@file,"w") { |f| f.puts @report } : puts(@report)
58
- @post.call if @post
157
+ # This code will be evaluated in the context of the instance on which it is
158
+ # called.
159
+ def eval_template( code, filename=nil )
160
+ filename =~ /\.rb/ ? eval(code) : ERB.new(code, 0, "%").run(binding)
59
161
  end
60
-
162
+
61
163
  # sets the active source to the Ruport::Config source requested by label.
62
164
  def use_source(label)
63
165
  @source = label
64
166
  end
167
+
168
+ # sets the active mailer to the Ruport::Config source requested by label.
169
+ def use_mailer(label)
170
+ @mailer = label
171
+ end
65
172
 
66
173
  # Provides a nice way to execute templates and filters.
67
174
  #
68
175
  # Example:
69
176
  #
70
- # my_report.render( "_<%= @some_internal_var %>_",
71
- # :filters => [:erb,:red_cloth] )
177
+ # process_text "_<%= @some_internal_var %>_", :filters => [:erb,:red_cloth]
72
178
  #
73
179
  # This method automatically passes a binding into the filters, so you are
74
180
  # free to access data from your Report instance in your templates.
75
- def render(string, options)
181
+ def process_text(string, options)
76
182
  options[:filters].each do |f|
77
183
  format = Format.new(binding)
78
184
  format.content = string
@@ -80,9 +186,104 @@ module Ruport
80
186
  end
81
187
  string
82
188
  end
189
+
190
+ # preserved for backwards compatibility. please do not use.
191
+ alias_method :render, :process_text
83
192
 
193
+ # This allows you to create filters to be used by process_text
194
+ #
195
+ # The block is evaluated in the context of the instance.
196
+ #
197
+ # E.g
198
+ #
199
+ # text_processor(:unix_newlines) { results.gsub!(/\r\n/,"\n") }
200
+ def text_processor(label,&block)
201
+ Format.register_filter(label, &block)
202
+ end
203
+
204
+
205
+ # Writes the contents of <tt>results</tt> to file. If a filename is
206
+ # specified, it will use it. Otherwise, it will try to write to the file
207
+ # specified by the <tt>file</tt> attribute.
208
+ def write(my_file=file)
209
+ File.open(my_file,"w") { |f| f << results }
210
+ end
211
+
212
+ # Like Report#write, but will append to a file rather than overwrite it if
213
+ # the file already exists
214
+ def append(my_file=file)
215
+ File.open(my_file,"a") { |f| f << results }
216
+ end
217
+
218
+ class << self
219
+
220
+ # Defines an instance method which will be run before the
221
+ # <tt>generate</tt> method when Ruport.run is executed
222
+ #
223
+ # Good for setting config info and perhaps files and/or loggers
224
+ #
225
+ def prepare(&block); define_method(:prepare,&block) end
226
+
227
+ # Defines an instance method which will be executed by Report.run
228
+ #
229
+ # The return value of this method is assigned to the <tt>results</tt>
230
+ # attribute
231
+ #
232
+ def generate(&block); define_method(:generate,&block) end
233
+
234
+ # Defines an instance method which will be executed after the object is
235
+ # yielded in Report.run
236
+ #
237
+ def cleanup(&block); define_method(:cleanup,&block) end
238
+
239
+ # Runs the reports specified. If no reports are specified, then it
240
+ # creates a new instance via <tt>self.new</tt>
241
+ #
242
+ # Tries to execute the prepare instance method, then runs generate.
243
+ # It then yields the object so that you may do something with it
244
+ # (print something out, write to file, email, etc)
245
+ #
246
+ # Finally, it tries to call cleanup.
247
+ def run(*reports)
248
+ reports[0] ||= self.new
249
+ reports.each { |rep|
250
+ rep.prepare if rep.respond_to? :prepare;
251
+ rep.results = rep.generate;
252
+ yield(rep) if block_given?
253
+ rep.cleanup if rep.respond_to? :cleanup;
254
+ }
255
+ end
256
+ end
257
+
258
+ # this method passes <tt>self</tt> to Report.run
259
+ #
260
+ # Please see the class method for details.
261
+ def run(&block)
262
+ self.class.run(self,&block)
263
+ end
264
+
265
+ # Preserved for backwards compatibility, please do not use this.
266
+ alias_method :generate_report, :run
84
267
 
268
+ # Allows logging and other fun stuff. See Ruport.log
269
+ def log(*args); Ruport.log(*args) end
270
+
271
+ # Creates a new Mailer and sets the <tt>to</tt> attribute to the addresses
272
+ # specified. Yields a Mailer object, which can be modified before delivery.
273
+ #
274
+ # By default, this will
275
+ def send_to(adds)
276
+ m = Mailer.new
277
+ m.to = adds
278
+ yield(m)
279
+ m.select_mailer @mailer
280
+ m.deliver :from => m.from, :to => m.to
281
+ end
282
+
283
+ def_delegators Ruport::Config, :source, :mailer, :log_file, :log_file=
284
+
85
285
  end
286
+
86
287
  end
87
288
 
88
289